diff options
Diffstat (limited to 'src/pluto')
69 files changed, 5320 insertions, 8608 deletions
diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index c9cb6651f..b83e4be33 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -20,7 +20,6 @@ demux.c demux.h \ dnskey.c dnskey.h \ fetch.c fetch.h \ foodgroups.c foodgroups.h \ -id.c id.h \ ike_alg.c ike_alg.h \ ipsec_doi.c ipsec_doi.h \ kameipsec.h \ @@ -32,12 +31,11 @@ kernel_pfkey.c kernel_pfkey.h \ keys.c keys.h \ lex.c lex.h \ log.c log.h \ +myid.c myid.h \ modecfg.c modecfg.h \ nat_traversal.c nat_traversal.h \ ocsp.c ocsp.h \ packet.c packet.h \ -pem.c pem.h \ -pgpcert.c pgpcert.h \ pkcs7.c pkcs7.h \ plutomain.c \ rcv_whack.c rcv_whack.h \ @@ -50,6 +48,7 @@ vendor.c vendor.h \ virtual.c virtual.h \ xauth.c xauth.h \ x509.c x509.h \ +builder.c builder.h \ rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h _pluto_adns_SOURCES = adns.c adns.h @@ -58,26 +57,25 @@ LIBSTRONGSWANDIR=$(top_builddir)/src/libstrongswan LIBFREESWANDIR=$(top_builddir)/src/libfreeswan INCLUDES = \ --I${linuxdir} \ +-I${linux_headers} \ -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libfreeswan \ -I$(top_srcdir)/src/whack AM_CFLAGS = \ -DIPSEC_DIR=\"${ipsecdir}\" \ --DIPSEC_CONFDIR=\"${confdir}\" \ +-DIPSEC_CONFDIR=\"${sysconfdir}\" \ -DIPSEC_PIDDIR=\"${piddir}\" \ --DSHARED_SECRETS_FILE=\"${confdir}/ipsec.secrets\" \ --DIPSEC_PLUGINDIR=\"${plugindir}\" \ +-DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ -DPLUGINS=\""${pluto_plugins}\"" \ --DSTRONGSWAN_CONF=\"${strongswan_conf}\" \ +-DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" \ -DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES \ -DPLUTO -DKLIPS -DDEBUG pluto_LDADD = \ $(LIBSTRONGSWANDIR)/libstrongswan.la \ $(LIBFREESWANDIR)/libfreeswan.a \ --lresolv -lpthread $(DLLIB) +-lresolv $(PTHREADLIB) $(DLLIB) _pluto_adns_LDADD = \ $(LIBFREESWANDIR)/libfreeswan.a \ diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in index 871f0c905..c93756c44 100644 --- a/src/pluto/Makefile.in +++ b/src/pluto/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.10.2 from Makefile.am. +# Makefile.in generated by automake 1.11 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -20,8 +21,9 @@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c @@ -58,14 +60,21 @@ subdir = src/pluto DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(man8dir)" -ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(ipsec_PROGRAMS) am__pluto_adns_OBJECTS = adns.$(OBJEXT) _pluto_adns_OBJECTS = $(am__pluto_adns_OBJECTS) @@ -77,23 +86,24 @@ am_pluto_OBJECTS = ac.$(OBJEXT) alg_info.$(OBJEXT) ca.$(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) \ + 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) \ + lex.$(OBJEXT) log.$(OBJEXT) myid.$(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) + 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) \ + builder.$(OBJEXT) pluto_OBJECTS = $(am_pluto_OBJECTS) pluto_DEPENDENCIES = $(LIBSTRONGSWANDIR)/libstrongswan.la \ $(LIBFREESWANDIR)/libfreeswan.a $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles +am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -105,6 +115,27 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(_pluto_adns_SOURCES) $(pluto_SOURCES) DIST_SOURCES = $(_pluto_adns_SOURCES) $(pluto_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' man5dir = $(mandir)/man5 man8dir = $(mandir)/man8 NROFF = nroff @@ -145,25 +176,22 @@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ -IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ LD = @LD@ 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@ -LINUX_HEADERS = @LINUX_HEADERS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ @@ -175,11 +203,14 @@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ +PTHREADLIB = @PTHREADLIB@ RANLIB = @RANLIB@ +RTLIB = @RTLIB@ RUBY = @RUBY@ RUBYINCLUDE = @RUBYINCLUDE@ SED = @SED@ @@ -208,9 +239,9 @@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ -confdir = @confdir@ datadir = @datadir@ datarootdir = @datarootdir@ +default_pkcs11 = @default_pkcs11@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -233,7 +264,7 @@ ipsecuser = @ipsecuser@ libdir = @libdir@ libexecdir = @libexecdir@ libstrongswan_plugins = @libstrongswan_plugins@ -linuxdir = @linuxdir@ +linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ lt_ECHO = @lt_ECHO@ @@ -241,6 +272,7 @@ mandir = @mandir@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ piddir = @piddir@ @@ -249,10 +281,12 @@ pluto_plugins = @pluto_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +random_device = @random_device@ resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ -simreader = @simreader@ srcdir = @srcdir@ strongswan_conf = @strongswan_conf@ sysconfdir = @sysconfdir@ @@ -260,6 +294,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ pluto_SOURCES = \ @@ -278,7 +313,6 @@ demux.c demux.h \ dnskey.c dnskey.h \ fetch.c fetch.h \ foodgroups.c foodgroups.h \ -id.c id.h \ ike_alg.c ike_alg.h \ ipsec_doi.c ipsec_doi.h \ kameipsec.h \ @@ -290,12 +324,11 @@ kernel_pfkey.c kernel_pfkey.h \ keys.c keys.h \ lex.c lex.h \ log.c log.h \ +myid.c myid.h \ modecfg.c modecfg.h \ nat_traversal.c nat_traversal.h \ ocsp.c ocsp.h \ packet.c packet.h \ -pem.c pem.h \ -pgpcert.c pgpcert.h \ pkcs7.c pkcs7.h \ plutomain.c \ rcv_whack.c rcv_whack.h \ @@ -308,29 +341,29 @@ vendor.c vendor.h \ virtual.c virtual.h \ xauth.c xauth.h \ x509.c x509.h \ +builder.c builder.h \ rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h _pluto_adns_SOURCES = adns.c adns.h LIBSTRONGSWANDIR = $(top_builddir)/src/libstrongswan LIBFREESWANDIR = $(top_builddir)/src/libfreeswan INCLUDES = \ --I${linuxdir} \ +-I${linux_headers} \ -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libfreeswan \ -I$(top_srcdir)/src/whack -AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" \ - -DIPSEC_PIDDIR=\"${piddir}\" \ - -DSHARED_SECRETS_FILE=\"${confdir}/ipsec.secrets\" \ - -DIPSEC_PLUGINDIR=\"${plugindir}\" \ +AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" \ + -DIPSEC_CONFDIR=\"${sysconfdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \ + -DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ -DPLUGINS=\""${pluto_plugins}\"" \ - -DSTRONGSWAN_CONF=\"${strongswan_conf}\" -DKERNEL26_SUPPORT \ + -DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" -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_7) pluto_LDADD = $(LIBSTRONGSWANDIR)/libstrongswan.la \ - $(LIBFREESWANDIR)/libfreeswan.a -lresolv -lpthread $(DLLIB) \ - $(am__append_6) + $(LIBFREESWANDIR)/libfreeswan.a -lresolv $(PTHREADLIB) \ + $(DLLIB) $(am__append_6) _pluto_adns_LDADD = \ $(LIBFREESWANDIR)/libfreeswan.a \ -lresolv $(DLLIB) @@ -349,9 +382,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pluto/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/pluto/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pluto/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/pluto/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -369,34 +402,50 @@ $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): install-ipsecPROGRAMS: $(ipsec_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" - @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ - p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - if test -f $$p \ - || test -f $$p1 \ - ; then \ - f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \ - else :; fi; \ - done + @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(ipsecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(ipsecdir)$$dir" || exit $$?; \ + } \ + ; done uninstall-ipsecPROGRAMS: @$(NORMAL_UNINSTALL) - @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ - f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \ - rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \ - done + @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(ipsecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(ipsecdir)" && rm -f $$files clean-ipsecPROGRAMS: - @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ - f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f $$p $$f"; \ - rm -f $$p $$f ; \ - done + @list='$(ipsec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list _pluto_adns$(EXEEXT): $(_pluto_adns_OBJECTS) $(_pluto_adns_DEPENDENCIES) @rm -f _pluto_adns$(EXEEXT) $(LINK) $(_pluto_adns_OBJECTS) $(_pluto_adns_LDADD) $(LIBS) @@ -413,6 +462,7 @@ 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)/builder.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ca.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connections.Po@am__quote@ @@ -426,7 +476,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnskey.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)/id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_doi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel.Po@am__quote@ @@ -438,11 +487,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modecfg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/myid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_traversal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocsp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pem.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)/rcv_whack.Po@am__quote@ @@ -458,21 +506,21 @@ distclean-compile: .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< @@ -482,96 +530,82 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -install-man5: $(man5_MANS) $(man_MANS) +install-man5: $(dist_man_MANS) @$(NORMAL_INSTALL) test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)" - @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.5*) list="$$list $$i" ;; \ - esac; \ + @list=''; test -n "$(man5dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.5[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ + fi; \ done; \ - for i in $$list; do \ - if test -f $$i; then file=$$i; \ - else file=$(srcdir)/$$i; fi; \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 5*) ;; \ - *) ext='5' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \ - done + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ + done; } + uninstall-man5: @$(NORMAL_UNINSTALL) - @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.5*) list="$$list $$i" ;; \ - esac; \ - done; \ - for i in $$list; do \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 5*) ;; \ - *) ext='5' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \ - rm -f "$(DESTDIR)$(man5dir)/$$inst"; \ - done -install-man8: $(man8_MANS) $(man_MANS) + @list=''; test -n "$(man5dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.5[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man5dir)" && rm -f $$files; } +install-man8: $(dist_man_MANS) @$(NORMAL_INSTALL) test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" - @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.8*) list="$$list $$i" ;; \ - esac; \ + @list=''; test -n "$(man8dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.8[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ + fi; \ done; \ - for i in $$list; do \ - if test -f $$i; then file=$$i; \ - else file=$(srcdir)/$$i; fi; \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 8*) ;; \ - *) ext='8' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \ - done + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ + done; } + uninstall-man8: @$(NORMAL_UNINSTALL) - @list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \ - l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ - for i in $$l2; do \ - case "$$i" in \ - *.8*) list="$$list $$i" ;; \ - esac; \ - done; \ - for i in $$list; do \ - ext=`echo $$i | sed -e 's/^.*\\.//'`; \ - case "$$ext" in \ - 8*) ;; \ - *) ext='8' ;; \ - esac; \ - inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ - inst=`echo $$inst | sed -e 's/^.*\///'`; \ - inst=`echo $$inst | sed '$(transform)'`.$$ext; \ - echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \ - rm -f "$(DESTDIR)$(man8dir)/$$inst"; \ - done + @list=''; test -n "$(man8dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.8[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man8dir)" && rm -f $$files; } ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -585,7 +619,7 @@ tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ + set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -593,34 +627,52 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) - tags=; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ + test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique + $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ @@ -636,13 +688,17 @@ distdir: $(DISTFILES) if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @@ -673,6 +729,7 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -694,6 +751,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -702,18 +761,28 @@ install-data-am: install-ipsecPROGRAMS install-man install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-man5 install-man8 install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -756,6 +825,7 @@ uninstall-man: uninstall-man5 uninstall-man8 uninstall-ipsecPROGRAMS uninstall-man uninstall-man5 \ uninstall-man8 + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/pluto/ac.c b/src/pluto/ac.c index 3b5df9738..d8b16112f 100644 --- a/src/pluto/ac.c +++ b/src/pluto/ac.c @@ -1,6 +1,7 @@ /* Support of X.509 attribute certificates * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter + * Copyright (C) 2009 Andreas Steffen * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -13,971 +14,284 @@ * for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <dirent.h> +#include <sys/stat.h> #include <time.h> -#include <sys/types.h> -#include <freeswan.h> - -#include <utils.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <asn1/oid.h> +#include <debug.h> +#include <utils/enumerator.h> +#include <utils/linked_list.h> +#include <credentials/certificates/ac.h> #include "ac.h" -#include "x509.h" -#include "crl.h" #include "ca.h" #include "certs.h" -#include "log.h" -#include "whack.h" #include "fetch.h" +#include "log.h" /** * Chained list of X.509 attribute certificates */ -static x509acert_t *x509acerts = NULL; - -/** - * Chained list of ietfAttributes - */ -static ietfAttrList_t *ietfAttributes = NULL; - -/** - * 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, "exit", ASN1_EOC, ASN1_EXIT } -}; - -#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, "exit", ASN1_EOC, ASN1_EXIT } -}; - -/** - * 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, "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 - -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 */ -}; - +static linked_list_t *acerts = NULL; /** - * compare two ietfAttributes, returns zero if a equals b - * negative/positive if a is earlier/later in the alphabet than b + * Initialize the linked list of attribute certificates */ -static int cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b) +void ac_initialize(void) { - 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); - - return (cmp_value == 0)? cmp_len : cmp_value; + acerts = linked_list_create(); } /** - * add an ietfAttribute to the chained list + * Free the linked list of attribute certificates */ -static ietfAttr_t* add_ietfAttr(ietfAttr_t *attr) +void ac_finalize(void) { - 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 + if (acerts) { - 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; + acerts->destroy_offset(acerts, offsetof(certificate_t, destroy)); } } /** - * decodes a comma separated list of group attributes + * Get a X.509 attribute certificate for a given holder */ -void decode_groups(char *groups, ietfAttrList_t **listp) +certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial) { - if (groups == NULL) - return; + enumerator_t *enumerator; + certificate_t *cert, *found = NULL; - while (strlen(groups) > 0) + enumerator = acerts->create_enumerator(acerts); + while (enumerator->enumerate(enumerator, &cert)) { - char *end; - char *next = strchr(groups, ','); - - if (next == NULL) - end = next = groups + strlen(groups); - else - end = next++; - - /* eat preceeding whitespace */ - while (groups < end && *groups == ' ') - groups++; + ac_t *ac = (ac_t*)cert; - /* eat trailing whitespace */ - while (end > groups && *(end-1) == ' ') - end--; - - if (groups < end) + if (issuer->equals(issuer, ac->get_holderIssuer(ac)) && + chunk_equals(serial, ac->get_holderSerial(ac))) { - 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; - - el->attr = add_ietfAttr(attr); - el->next = *listp; - *listp = el; + found = cert; + break; } - - groups = next; } + enumerator->destroy(enumerator); + return found; } -static bool same_attribute(const ietfAttr_t *a, const ietfAttr_t *b) +/** + * Verifies a X.509 attribute certificate + */ +bool ac_verify_cert(certificate_t *cert, bool strict) { - return (a->kind == b->kind && a->value.len == b->value.len - && memeq(a->value.ptr, b->value.ptr, b->value.len)); -} + ac_t *ac = (ac_t*)cert; + identification_t *subject = cert->get_subject(cert); + identification_t *issuer = cert->get_issuer(cert); + chunk_t authKeyID = ac->get_authKeyIdentifier(ac); + cert_t *aacert; + time_t notBefore, valid_until; -bool group_membership(const ietfAttrList_t *peer_list - , const char *conn - , const ietfAttrList_t *conn_list) -{ - if (conn_list == NULL) - return TRUE; + DBG1("holder: '%Y'", subject); + DBG1("issuer: '%Y'", issuer); - while (peer_list != NULL) + if (!cert->get_validity(cert, NULL, NULL, &valid_until)) { - const ietfAttr_t *peer_attr = peer_list->attr; - const ietfAttrList_t *list = conn_list; - - 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; + DBG1("attribute certificate is invalid (valid from %T to %T)", + ¬Before, FALSE, &valid_until, FALSE); + return FALSE; } - DBG(DBG_CONTROL, - DBG_log("%s: peer doesn't match any group", conn) - ) - return FALSE; -} + DBG1("attribute certificate is valid until %T", &valid_until, FALSE); -void unshare_ietfAttrList(ietfAttrList_t **listp) -{ - ietfAttrList_t *list = *listp; + lock_authcert_list("verify_x509acert"); + aacert = get_authcert(issuer, authKeyID, X509_AA); + unlock_authcert_list("verify_x509acert"); - while (list != NULL) + if (aacert == 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; + DBG1("issuer aacert not found"); + return FALSE; } -} - -/** - * Parses ietfAttrSyntax - */ -static ietfAttrList_t* parse_ietfAttrSyntax(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; + DBG2("issuer aacert found"); - ietfAttrList_t *list = NULL; - - parser = asn1_parser_create(ietfAttrSyntaxObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) + if (!cert->issued_by(cert, aacert->cert)) { - 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; - } + DBG1("attribute certificate signature is invalid"); + return FALSE; } - parser->destroy(parser); - return list; -} - -/** - * Parses roleSyntax - */ -static void parse_roleSyntax(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; + DBG1("attribute certificate signature is valid"); - parser = asn1_parser_create(roleSyntaxObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - default: - break; - } - } - parser->destroy(parser); + return verify_x509cert(aacert, strict, &valid_until); } /** - * Parses an X.509 attribute certificate + * Add a X.509 attribute certificate to the chained list */ -bool parse_ac(chunk_t blob, x509acert_t *ac) +static void ac_add_cert(certificate_t *cert) { - asn1_parser_t *parser; - chunk_t object; - int objectID; - int type = OID_UNKNOWN; - int extn_oid = OID_UNKNOWN; - bool success = FALSE; - bool critical; + ac_t *ac = (ac_t*)cert; + identification_t *hIssuer = ac->get_holderIssuer(ac); + chunk_t hSerial = ac->get_holderSerial(ac); - parser = asn1_parser_create(acObjects, blob); + enumerator_t *enumerator; + certificate_t *cert_old; - while (parser->iterate(parser, &objectID, &object)) + enumerator = acerts->create_enumerator(acerts); + while (enumerator->enumerate(enumerator, &cert_old)) { - u_int level = parser->get_level(parser)+1; + ac_t *ac_old = (ac_t*)cert_old; - switch (objectID) + if (hIssuer->equals(hIssuer, ac_old->get_holderIssuer(ac_old)) && + chunk_equals(hSerial, ac_old->get_holderSerial(ac_old))) { - 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) + if (cert->is_newer(cert, cert_old)) { - plog("v%d attribute certificates are not supported" - , ac->version); - goto end; + acerts->remove_at(acerts, enumerator); + cert_old->destroy(cert_old); } - 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: + else { - 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; - } + cert->destroy(cert); + cert = NULL; } 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; - - default: - break; } } - success = parser->success(parser); - time(&ac->installed); - -end: - parser->destroy(parser); - return success; -} + enumerator->destroy(enumerator); -/** - * Release an ietfAttribute, free it if count reaches zero - */ -static void release_ietfAttr(ietfAttr_t* attr) -{ - if (--attr->count == 0) + if (cert) { - 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); + acerts->insert_last(acerts, cert); } } /** - * Free an ietfAttrList + * Check if at least one peer attribute matches a connection attribute */ -void free_ietfAttrList(ietfAttrList_t* list) +bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn, + ietf_attributes_t *conn_attributes) { - while (list != NULL) - { - ietfAttrList_t *el = list; - - release_ietfAttr(el->attr); - list = list->next; - free(el); - } -} + bool match; -/** - * Free a X.509 attribute certificate - */ -void free_acert(x509acert_t *ac) -{ - if (ac != NULL) + if (conn_attributes == 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 - */ -static void free_first_acert(void) -{ - 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(); -} - -/** - * Get a X.509 attribute certificate for a given holder - */ -x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial) -{ - x509acert_t *ac = x509acerts; - x509acert_t *prev_ac = NULL; - - while (ac != NULL) - { - 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; - } - return NULL; -} - -/** - * Add a X.509 attribute certificate to the chained list - */ -static void add_acert(x509acert_t *ac) -{ - 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 - { - DBG(DBG_CONTROL, - DBG_log("attribute cert is not newer - existing cert kept"); - ) - free_acert(ac); - return; - } + return TRUE; } - plog("attribute cert added"); - /* insert new attribute cert at the root of the chain */ - ac->next = x509acerts; - x509acerts = ac; -} + match = conn_attributes->matches(conn_attributes, peer_attributes); + DBG1("%s: peer with attributes '%s' is %sa member of the groups '%s'", + conn, peer_attributes->get_string(peer_attributes), + match ? "" : "not ", conn_attributes->get_string(conn_attributes)); -/** - * Verify the validity of an attribute certificate by - * checking the notBefore and notAfter dates - */ -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 : %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; + return match; } /** - * verifies a X.509 attribute certificate + * Loads X.509 attribute certificates */ -bool verify_x509acert(x509acert_t *ac, bool strict) +void ac_load_certs(void) { - 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") - ) + enumerator_t *enumerator; + struct stat st; + char *file; - 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") - ) + DBG1("loading attribute certificates from '%s'", A_CERT_PATH); - if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm, - aacert)) + enumerator = enumerator_create_directory(A_CERT_PATH); + if (!enumerator) { - plog("attribute certificate signature is invalid"); - return FALSE; + return; } - 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) -{ - u_char buf[BUF_LEN]; - - /* change directory to specified path */ - u_char *save_dir = getcwd(buf, BUF_LEN); - if (!chdir(A_CERT_PATH)) + while (enumerator->enumerate(enumerator, NULL, &file, &st)) { - struct dirent **filelist; - int n; + certificate_t *cert; - plog("Changing to directory '%s'",A_CERT_PATH); - n = scandir(A_CERT_PATH, &filelist, file_select, alphasort); - - if (n > 0) + if (!S_ISREG(st.st_mode)) { - 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); + /* skip special file */ + continue; } - } - /* 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) -{ - bool first_group = TRUE; - - while (list != NULL && len > 0) - { - ietfAttr_t *attr = list->attr; - - if (attr->kind == IETF_ATTRIBUTE_OCTETS - || attr->kind == IETF_ATTRIBUTE_STRING) + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, + BUILD_FROM_FILE, file, BUILD_END); + if (cert) { - 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; + DBG1(" loaded attribute certificate from '%s'", file); + ac_add_cert(cert); } - list = list->next; } + enumerator->destroy(enumerator); } /** - * list all X.509 attribute certificates in the chained list + * List all X.509 attribute certificates in the chained list */ -void list_acerts(bool utc) +void ac_list_certs(bool utc) { - x509acert_t *ac = x509acerts; + enumerator_t *enumerator; + certificate_t *cert; time_t now; /* determine the current time */ time(&now); - if (ac != NULL) + if (acerts->get_count(acerts) > 0) { whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); - whack_log(RC_COMMENT, " "); } - while (ac != NULL) + enumerator = acerts->create_enumerator(acerts); + while (enumerator->enumerate(enumerator, &cert)) { - u_char buf[BUF_LEN]; + ac_t *ac = (ac_t*)cert; + identification_t *entityName, *holderIssuer, *issuer; + chunk_t holderSerial, serial, authKeyID; + time_t notBefore, notAfter; + ietf_attributes_t *groups; - whack_log(RC_COMMENT, "%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) + whack_log(RC_COMMENT, " "); + + entityName = cert->get_subject(cert); + if (entityName) { - datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " hserial: %s", buf); + whack_log(RC_COMMENT, " holder: \"%Y\"", entityName); } - if (ac->groups != NULL) + + holderIssuer = ac->get_holderIssuer(ac); + if (holderIssuer) { - format_groups(ac->groups, buf, BUF_LEN); - whack_log(RC_COMMENT, " groups: %s", buf); + whack_log(RC_COMMENT, " hissuer: \"%Y\"", holderIssuer); } - 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) + + holderSerial = ac->get_holderSerial(ac); + if (holderSerial.ptr) { - datatot(ac->authKeyID.ptr, ac->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " hserial: %#B", &holderSerial); } - if (ac->authKeySerialNumber.ptr != NULL) + + groups = ac->get_groups(ac); + if (groups) { - datatot(ac->authKeySerialNumber.ptr, ac->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " groups: %s", groups->get_string(groups)); + groups->destroy(groups); } - ac = ac->next; - } -} + issuer = cert->get_issuer(cert); + whack_log(RC_COMMENT, " issuer: \"%Y\"", issuer); -/** - * list all group attributes in alphabetical order - */ -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, " "); - } + serial = ac->get_serial(ac); + whack_log(RC_COMMENT, " serial: %#B", &serial); - while (list != NULL) - { - ietfAttr_t *attr = list->attr; + cert->get_validity(cert, &now, ¬Before, ¬After); + whack_log(RC_COMMENT, " validity: not before %T %s", + ¬Before, utc, + (notBefore < now)?"ok":"fatal (not valid yet)"); + whack_log(RC_COMMENT, " not after %T %s", ¬After, utc, + check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE)); - whack_log(RC_COMMENT, "%T, count: %d", &attr->installed, utc, attr->count); - - switch (attr->kind) + authKeyID = ac->get_authKeyIdentifier(ac); + if (authKeyID.ptr) { - 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; + whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); } - - list = list->next; } + enumerator->destroy(enumerator); } + diff --git a/src/pluto/ac.h b/src/pluto/ac.h index bee016143..d4e0c1590 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 - + * Copyright (C) 2009 Andreas Steffen * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,85 +17,23 @@ #ifndef _AC_H #define _AC_H -/* definition of ietfAttribute kinds */ - -typedef enum { - IETF_ATTRIBUTE_OCTETS = 0, - IETF_ATTRIBUTE_OID = 1, - IETF_ATTRIBUTE_STRING = 2 -} ietfAttribute_t; - -/* access structure for an ietfAttribute */ - -typedef struct ietfAttr ietfAttr_t; - -struct ietfAttr { - time_t installed; - int count; - ietfAttribute_t kind; - chunk_t value; -}; - -typedef struct ietfAttrList ietfAttrList_t; - -struct ietfAttrList { - ietfAttrList_t *next; - ietfAttr_t *attr; -}; - +#include <utils/identification.h> +#include <credentials/certificates/certificate.h> +#include <credentials/ietf_attributes/ietf_attributes.h> /* access structure for an X.509 attribute certificate */ -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 */ - int sigAlg; - chunk_t serialNumber; - /* attrCertValidityPeriod */ - time_t notBefore; - time_t notAfter; - /* attributes */ - ietfAttrList_t *charging; - ietfAttrList_t *groups; - /* extensions */ - chunk_t authKeyID; - chunk_t authKeySerialNumber; - bool noRevAvail; - /* signatureAlgorithm */ - int algorithm; - chunk_t signature; -}; +extern void ac_initialize(void); +extern void ac_finalize(void); +extern void ac_load_certs(void); +extern void ac_list_certs(bool utc); -/* used for initialization */ -extern const x509acert_t empty_ac; +extern certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial); -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); -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); -extern void load_acerts(void); -extern void free_acert(x509acert_t *ac); -extern void free_acerts(void); -extern void list_acerts(bool utc); -extern void list_groups(bool utc); -extern void format_groups(const ietfAttrList_t *list, char *buf, int len); +extern bool ac_verify_cert(certificate_t *ac, bool strict); +extern bool match_group_membership(ietf_attributes_t *peer_attributes, + char *conn, + ietf_attributes_t *conn_attributes); -#endif /* _AH_H */ +#endif /* _AC_H */ diff --git a/src/pluto/alg_info.c b/src/pluto/alg_info.c index c25418fc1..edecf14c6 100644 --- a/src/pluto/alg_info.c +++ b/src/pluto/alg_info.c @@ -51,19 +51,13 @@ int alg_info_esp_aa2sadb(int auth) { int sadb_aalg = 0; - switch(auth) { + 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; @@ -73,20 +67,13 @@ int alg_info_esp_sadb2aa(int sadb_aalg) { int auth = 0; - switch(sadb_aalg) { + 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; @@ -133,7 +120,7 @@ static void __alg_info_esp_add(struct alg_info_esp *alg_info, int ealg_id, DBG(DBG_CRYPT, DBG_log("esp alg added: %s_%d/%s, cnt=%d", - enum_show(&esp_transformid_names, ealg_id), ek_bits, + enum_show(&esp_transform_names, ealg_id), ek_bits, enum_show(&auth_alg_names, aalg_id), alg_info->alg_info_cnt) ) @@ -238,12 +225,12 @@ static void __alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, * merging alg_info (ike_info) contents */ -static int default_ike_groups[] = { +static int default_ike_groups[] = { MODP_1536_BIT, MODP_1024_BIT }; -/* +/* * Add IKE alg info _with_ logic (policy): */ static void alg_info_ike_add (struct alg_info *alg_info, int ealg_id, @@ -258,7 +245,7 @@ static void alg_info_ike_add (struct alg_info *alg_info, int ealg_id, n_groups=0; goto in_loop; } - + for (; n_groups--; i++) { modp_id = default_ike_groups[i]; @@ -372,7 +359,7 @@ static status_t alg_info_parse_str(struct alg_info *alg_info, char *alg_str) eat_whitespace(&string); - if (string.len > 0) + if (string.len > 0) { chunk_t alg; @@ -397,7 +384,7 @@ static status_t alg_info_parse_str(struct alg_info *alg_info, char *alg_str) { case PROTO_IPSEC_ESP: alg_info_esp_add(alg_info, ealg, ealg_keysize, - aalg, aalg_keysize); + aalg, aalg_keysize); break; case PROTO_ISAKMP: alg_info_ike_add(alg_info, ealg, ealg_keysize, @@ -461,12 +448,16 @@ struct alg_info_esp *alg_info_esp_create_from_str(char *alg_str) status = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str); out: - if (status != SUCCESS) + if (status == SUCCESS) + { + alg_info_esp->ref_cnt = 1; + return alg_info_esp; + } + else { free(alg_info_esp); - alg_info_esp = NULL; + return NULL; } - return alg_info_esp; } struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str) @@ -481,12 +472,16 @@ struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str) 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) + if (alg_info_parse_str((struct alg_info *)alg_info_ike, alg_str) == SUCCESS) + { + alg_info_ike->ref_cnt = 1; + return alg_info_ike; + } + else { free(alg_info_ike); return NULL; } - return alg_info_ike; } /* @@ -494,7 +489,7 @@ struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str) * several connections instances, * handle free() with ref_cnts */ -void +void alg_info_addref(struct alg_info *alg_info) { if (alg_info != NULL) @@ -529,7 +524,7 @@ alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info) struct esp_info *esp_info; struct ike_info *ike_info; int cnt; - + switch (alg_info->alg_info_protoid) { case PROTO_IPSEC_ESP: { @@ -538,7 +533,7 @@ alg_info_snprint(char *buf, int buflen, struct alg_info *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)); + enum_show(&esp_transform_names, esp_info->esp_ealg_id)); ptr += np; buflen -= np; if (esp_info->esp_ealg_keylen) @@ -608,7 +603,7 @@ out: , "buffer space exhausted in alg_info_snprint_ike(), buflen=%d" , buflen); } - + return ptr - buf; } diff --git a/src/pluto/alg_info.h b/src/pluto/alg_info.h index fcf7efca0..85b88ddff 100644 --- a/src/pluto/alg_info.h +++ b/src/pluto/alg_info.h @@ -74,7 +74,7 @@ extern int alg_info_snprint_esp(char *buf, int buflen extern int alg_info_snprint_ike(char *buf, int buflen , struct alg_info_ike *alg_info); #define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \ - for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++) + 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/builder.c b/src/pluto/builder.c new file mode 100644 index 000000000..0cba32bcf --- /dev/null +++ b/src/pluto/builder.c @@ -0,0 +1,150 @@ +/* Pluto certificate/CRL/AC builder hooks. + * Copyright (C) 2002-2009 Andreas Steffen + * Copyright (C) 2009 Martin Willi + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "builder.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <time.h> + +#include <freeswan.h> + +#include <library.h> +#include <credentials/certificates/certificate.h> + +#include "constants.h" +#include "defs.h" +#include "log.h" +#include "certs.h" +#include "crl.h" + +/** + * Load a certificate + */ +static cert_t *builder_load_cert(certificate_type_t type, va_list args) +{ + x509_flag_t flags = 0; + chunk_t blob = chunk_empty; + bool pgp = FALSE; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_PGP: + pgp = TRUE; + /* FALL */ + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_X509_FLAG: + flags |= va_arg(args, x509_flag_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + if (blob.ptr) + { + cert_t *cert = malloc_thing(cert_t); + + *cert = cert_empty; + + if (pgp) + { + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_GPG, + BUILD_BLOB_PGP, blob, + BUILD_END); + } + else + { + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_X509_FLAG, flags, + BUILD_END); + } + if (cert->cert) + { + return cert; + } + plog(" error in X.509 certificate"); + cert_free(cert); + } + return NULL; +} + +/** + * Load a CRL + */ +static x509crl_t *builder_load_crl(certificate_type_t type, va_list args) +{ + chunk_t blob = chunk_empty; + x509crl_t *crl; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + if (blob.ptr) + { + crl = malloc_thing(x509crl_t); + crl->next = NULL; + crl->distributionPoints = linked_list_create(); + crl->crl = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509_CRL, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); + if (crl->crl) + { + return crl; + } + plog(" error in X.509 crl"); + free_crl(crl); + } + return NULL; +} + +void init_builder(void) +{ + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, + (builder_function_t)builder_load_cert); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, + (builder_function_t)builder_load_crl); +} + +void free_builder(void) +{ + lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_cert); + lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_crl); +} + diff --git a/src/pluto/pem.h b/src/pluto/builder.h index 5e97b99ed..784751b7c 100644 --- a/src/pluto/pem.h +++ b/src/pluto/builder.h @@ -1,7 +1,6 @@ -/* Loading of PEM encoded files with optional encryption - * Copyright (C) 2001-2009 Andreas Steffen - * - * Hochschule fuer Technik Rapperswil +/* Pluto certificate/CRL/AC builder hooks. + * Copyright (C) 2009 Martin Willi + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -14,5 +13,12 @@ * for more details. */ -extern err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, - bool *pgp); +#ifndef _BUILDER_H +#define _BUILDER_H + +/* register credential builder hooks */ +extern void init_builder(); +/* unregister credential builder hooks */ +extern void free_builder(); + +#endif /* _BUILDER_H */ diff --git a/src/pluto/ca.c b/src/pluto/ca.c index 4fdb8cfe7..e25e7f6f5 100644 --- a/src/pluto/ca.c +++ b/src/pluto/ca.c @@ -15,11 +15,14 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <unistd.h> -#include <dirent.h> #include <time.h> +#include <sys/stat.h> #include <sys/types.h> +#include <debug.h> +#include <utils/enumerator.h> +#include <credentials/certificates/x509.h> + #include <freeswan.h> #include "constants.h" @@ -34,21 +37,7 @@ /* chained list of X.509 authority certificates (ca, aa, and ocsp) */ -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 */ -}; +static cert_t *x509authcerts = NULL; /* chained list of X.509 certification authority information records */ @@ -57,53 +46,71 @@ static ca_info_t *ca_infos = NULL; /* * Checks if CA a is trusted by CA b */ -bool -trusted_ca(chunk_t a, chunk_t b, int *pathlen) +bool trusted_ca(identification_t *a, identification_t *b, int *pathlen) { bool match = FALSE; /* no CA b specified -> any CA a is accepted */ - if (b.ptr == NULL) + if (b == NULL) { - *pathlen = (a.ptr == NULL)? 0 : MAX_CA_PATH_LEN; + *pathlen = (a == NULL) ? 0 : X509_MAX_PATH_LEN; return TRUE; } /* no CA a specified -> trust cannot be established */ - if (a.ptr == NULL) + if (a == NULL) { - *pathlen = MAX_CA_PATH_LEN; + *pathlen = X509_MAX_PATH_LEN; return FALSE; } *pathlen = 0; /* CA a equals CA b -> we have a match */ - if (same_dn(a, b)) + if (a->equals(a, b)) + { return TRUE; + } /* CA a might be a subordinate CA of b */ lock_authcert_list("trusted_ca"); - while ((*pathlen)++ < MAX_CA_PATH_LEN) + while ((*pathlen)++ < X509_MAX_PATH_LEN) { - x509cert_t *cacert = get_authcert(a, chunk_empty, chunk_empty, AUTH_CA); + certificate_t *certificate; + identification_t *issuer; + cert_t *cacert; - /* cacert not found or self-signed root cacert-> exit */ - if (cacert == NULL || same_dn(cacert->issuer, a)) + cacert = get_authcert(a, chunk_empty, X509_CA); + if (cacert == NULL) + { break; + } + certificate = cacert->cert; + + /* is the certificate self-signed? */ + { + x509_t *x509 = (x509_t*)certificate; + + if (x509->get_flags(x509) & X509_SELF_SIGNED) + { + break; + } + } /* does the issuer of CA a match CA b? */ - match = same_dn(cacert->issuer, b); + issuer = certificate->get_issuer(certificate); + match = b->equals(b, issuer); /* we have a match and exit the loop */ if (match) + { break; - + } /* go one level up in the CA chain */ - a = cacert->issuer; + a = issuer; } - + unlock_authcert_list("trusted_ca"); return match; } @@ -111,33 +118,36 @@ trusted_ca(chunk_t a, chunk_t b, int *pathlen) /* * does our CA match one of the requested CAs? */ -bool -match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen) +bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca, + int *our_pathlen) { + identification_t *ca; + enumerator_t *enumerator; + /* if no ca is requested than any ca will match */ - if (requested_ca == NULL) + if (requested_ca == NULL || requested_ca->get_count(requested_ca) == 0) { *our_pathlen = 0; return TRUE; } - *our_pathlen = MAX_CA_PATH_LEN + 1; + *our_pathlen = X509_MAX_PATH_LEN + 1; - while (requested_ca != NULL) + enumerator = requested_ca->create_enumerator(requested_ca); + while (enumerator->enumerate(enumerator, &ca)) { int pathlen; - if (trusted_ca(our_ca, requested_ca->name, &pathlen) - && pathlen < *our_pathlen) + if (trusted_ca(our_ca, ca, &pathlen) && pathlen < *our_pathlen) { *our_pathlen = pathlen; } - requested_ca = requested_ca->next; } + enumerator->destroy(enumerator); - if (*our_pathlen > MAX_CA_PATH_LEN) + if (*our_pathlen > X509_MAX_PATH_LEN) { - *our_pathlen = MAX_CA_PATH_LEN; + *our_pathlen = X509_MAX_PATH_LEN; return FALSE; } else @@ -149,55 +159,80 @@ match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen /* * free the first authority certificate in the chain */ -static void -free_first_authcert(void) +static void free_first_authcert(void) { - x509cert_t *first = x509authcerts; + cert_t *first = x509authcerts; + x509authcerts = first->next; - free_x509cert(first); + cert_free(first); } /* * free all CA certificates */ -void -free_authcerts(void) +void free_authcerts(void) { lock_authcert_list("free_authcerts"); while (x509authcerts != NULL) + { free_first_authcert(); - + } unlock_authcert_list("free_authcerts"); } /* * get a X.509 authority certificate with a given subject or keyid */ -x509cert_t* -get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags) +cert_t* get_authcert(identification_t *subject, chunk_t keyid, + x509_flag_t auth_flags) { - x509cert_t *cert = x509authcerts; - x509cert_t *prev_cert = NULL; + cert_t *cert, *prev_cert = NULL; + + /* the authority certificate list is empty */ + if (x509authcerts == NULL) + { + return NULL; + } - while (cert != NULL) + for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next) { - if (cert->authority_flags & auth_flags - && ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) - : (same_dn(subject, cert->subject) - && same_serial(serial, cert->serialNumber)))) + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + + /* skip non-matching types of authority certificates */ + if (!(x509->get_flags(x509) & auth_flags)) + { + continue; + } + + /* compare the keyid with the certificate's subjectKeyIdentifier */ + if (keyid.ptr) { - if (cert != x509authcerts) + chunk_t subjectKeyId; + + subjectKeyId = x509->get_subjectKeyIdentifier(x509); + if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) { - /* bring the certificate up front */ - prev_cert->next = cert->next; - cert->next = x509authcerts; - x509authcerts = cert; + continue; } - return cert; } - prev_cert = cert; - cert = cert->next; + + /* compare the subjectDistinguishedNames */ + if (!certificate->has_subject(certificate, subject)) + { + continue; + } + + /* found the authcert */ + if (cert != x509authcerts) + { + /* bring the certificate up front */ + prev_cert->next = cert->next; + cert->next = x509authcerts; + x509authcerts = cert; + } + return cert; } return NULL; } @@ -205,31 +240,27 @@ get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags) /* * add an authority certificate to the chained list */ -x509cert_t* -add_authcert(x509cert_t *cert, u_char auth_flags) +cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags) { - x509cert_t *old_cert; - - /* set authority flags */ - cert->authority_flags |= auth_flags; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + cert_t *old_cert; lock_authcert_list("add_authcert"); - old_cert = get_authcert(cert->subject, cert->serialNumber - , cert->subjectKeyID, auth_flags); - - if (old_cert != NULL) + old_cert = get_authcert(certificate->get_subject(certificate), + x509->get_subjectKeyIdentifier(x509), + auth_flags); + if (old_cert) { - if (same_x509cert(cert, old_cert)) + if (certificate->equals(certificate, old_cert->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); + cert_free(cert); return old_cert; } else @@ -245,7 +276,7 @@ add_authcert(x509cert_t *cert, u_char auth_flags) /* add new authcert to chained list */ cert->next = x509authcerts; x509authcerts = cert; - share_x509cert(cert); /* set count to one */ + cert_share(cert); /* set count to one */ DBG(DBG_CONTROL | DBG_PARSING, DBG_log(" authcert inserted") ) @@ -256,51 +287,43 @@ add_authcert(x509cert_t *cert, u_char auth_flags) /* * Loads authority certificates */ -void -load_authcerts(const char *type, const char *path, u_char auth_flags) +void load_authcerts(char *type, char *path, x509_flag_t auth_flags) { - struct dirent **filelist; - u_char buf[BUF_LEN]; - u_char *save_dir; - int n; + enumerator_t *enumerator; + struct stat st; + char *file; - /* change directory to specified path */ - save_dir = getcwd(buf, BUF_LEN); + DBG1("loading %s certificates from '%s'", type, path); - if (chdir(path)) + enumerator = enumerator_create_directory(path); + if (!enumerator) { - plog("Could not change to directory '%s'", path); + DBG1(" reading directory '%s' failed"); + return; } - else + + while (enumerator->enumerate(enumerator, NULL, &file, &st)) { - plog("Changing to directory '%s'", path); - n = scandir(path, &filelist, file_select, alphasort); + cert_t *cert; - if (n < 0) - plog(" scandir() error"); - else + if (!S_ISREG(st.st_mode)) { - 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); + /* skip special file */ + continue; + } + cert = load_cert(file, type, auth_flags); + if (cert) + { + add_authcert(cert, auth_flags); } } - /* restore directory path */ - ignore_result(chdir(save_dir)); + enumerator->destroy(enumerator); } /* * list all X.509 authcerts with given auth flags in a chained list */ -void -list_authcerts(const char *caption, u_char auth_flags, bool utc) +void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc) { lock_authcert_list("list_authcerts"); list_x509cert_chain(caption, x509authcerts, auth_flags, utc); @@ -310,19 +333,38 @@ list_authcerts(const char *caption, u_char auth_flags, bool utc) /* * get a cacert with a given subject or keyid from an alternative list */ -static const x509cert_t* -get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid - , const x509cert_t *cert) +static const cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid, + const cert_t *cert) { - while (cert != NULL) + if (cert == NULL) { - if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) - : (same_dn(subject, cert->subject) - && same_serial(serial, cert->serialNumber))) + return NULL; + } + for (; cert != NULL; cert = cert->next) + { + certificate_t *certificate = cert->cert; + + /* compare the keyid with the certificate's subjectKeyIdentifier */ + if (keyid.ptr) + { + x509_t *x509 = (x509_t*)certificate; + chunk_t subjectKeyId; + + subjectKeyId = x509->get_subjectKeyIdentifier(x509); + if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) + { + continue; + } + } + + /* compare the subjectDistinguishedNames */ + if (!certificate->has_subject(certificate, subject)) { - return cert; + continue; } - cert = cert->next; + + /* we found the cacert */ + return cert; } return NULL; } @@ -330,34 +372,32 @@ get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid /* establish trust into a candidate authcert by going up the trust chain. * validity and revocation status are not checked. */ -bool -trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) +bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain) { int pathlen; lock_authcert_list("trust_authcert_candidate"); - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) + for (pathlen = 0; pathlen < X509_MAX_PATH_LEN; pathlen++) { - const x509cert_t *authcert = NULL; - u_char buf[BUF_LEN]; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); + const cert_t *authcert = NULL; DBG(DBG_CONTROL, - 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) + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr != NULL) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } ) /* search in alternative chain first */ - authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, alt_chain); + authcert = get_alt_cacert(issuer, authKeyID, alt_chain); if (authcert != NULL) { @@ -368,8 +408,7 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) else { /* search in trusted chain */ - authcert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); + authcert = get_authcert(issuer, authKeyID, X509_CA); if (authcert != NULL) { @@ -385,8 +424,7 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) } } - if (!x509_check_signature(cert->tbsCertificate, cert->signature, - cert->algorithm, authcert)) + if (!certificate->issued_by(certificate, authcert->cert)) { plog("certificate signature is invalid"); unlock_authcert_list("trust_authcert_candidate"); @@ -397,7 +435,7 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) ) /* check if cert is a self-signed root ca */ - if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) + if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) { DBG(DBG_CONTROL, DBG_log("reached self-signed root ca") @@ -409,7 +447,7 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) /* go up one step in the trust chain */ cert = authcert; } - plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + plog("maximum ca path length of %d levels exceeded", X509_MAX_PATH_LEN); unlock_authcert_list("trust_authcert_candidate"); return FALSE; } @@ -417,16 +455,14 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) /* * get a CA info record with a given authName or authKeyID */ -ca_info_t* -get_ca_info(chunk_t authname, chunk_t serial, chunk_t keyid) +ca_info_t* get_ca_info(identification_t *name, chunk_t keyid) { ca_info_t *ca= ca_infos; - while (ca!= NULL) + while (ca != NULL) { - if ((keyid.ptr != NULL) ? same_keyid(keyid, ca->authKeyID) - : (same_dn(authname, ca->authName) - && same_serial(serial, ca->authKeySerialNumber))) + if ((keyid.ptr) ? same_keyid(keyid, ca->authKeyID) + : name->equals(name, ca->authName)) { return ca; } @@ -443,24 +479,23 @@ static void free_ca_info(ca_info_t* ca_info) { if (ca_info == NULL) + { return; - + } + ca_info->crluris->destroy_function(ca_info->crluris, free); + DESTROY_IF(ca_info->authName); free(ca_info->name); free(ca_info->ldaphost); free(ca_info->ldapbase); free(ca_info->ocspuri); - free(ca_info->authName.ptr); free(ca_info->authKeyID.ptr); - free(ca_info->authKeySerialNumber.ptr); - free_generalNames(ca_info->crluri, TRUE); free(ca_info); } /* * free all CA certificates */ -void -free_ca_infos(void) +void free_ca_infos(void) { while (ca_infos != NULL) { @@ -474,8 +509,7 @@ free_ca_infos(void) /* * find a CA information record by name and optionally delete it */ -bool -find_ca_info_by_name(const char *name, bool delete) +bool find_ca_info_by_name(const char *name, bool delete) { ca_info_t **ca_p = &ca_infos; ca_info_t *ca = *ca_p; @@ -501,16 +535,26 @@ find_ca_info_by_name(const char *name, bool delete) return FALSE; } +/* + * Create an empty ca_info_t record + */ +ca_info_t* create_ca_info(void) +{ + ca_info_t *ca_info = malloc_thing(ca_info_t); + + memset(ca_info, 0, sizeof(ca_info_t)); + ca_info->crluris = linked_list_create(); - /* - * adds a CA description to a chained list + return ca_info; +} + +/** + * Adds a CA description to a chained list */ -void -add_ca_info(const whack_message_t *msg) +void add_ca_info(const whack_message_t *msg) { smartcard_t *sc = NULL; - cert_t cert; - bool valid_cert = FALSE; + cert_t *cert = NULL; bool cached_cert = FALSE; if (find_ca_info_by_name(msg->name, FALSE)) @@ -522,60 +566,54 @@ add_ca_info(const whack_message_t *msg) if (scx_on_smartcard(msg->cacert)) { /* load CA cert from smartcard */ - valid_cert = scx_load_cert(msg->cacert, &sc, &cert, &cached_cert); + cert = scx_load_cert(msg->cacert, &sc, &cached_cert); } else { /* load CA cert from file */ - valid_cert = load_ca_cert(msg->cacert, &cert); + cert = load_ca_cert(msg->cacert); } - if (valid_cert) + if (cert) { - char buf[BUF_LEN]; - x509cert_t *cacert = cert.u.x509; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509); ca_info_t *ca = NULL; /* does the authname already exist? */ - ca = get_ca_info(cacert->subject, cacert->serialNumber - , cacert->subjectKeyID); - + ca = get_ca_info(subject, subjectKeyID); + if (ca != NULL) { /* ca_info is already present */ loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found," "ignoring \"%s\"", ca->name, msg->name); - free_x509cert(cacert); + cert_free(cert); 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; + ca = create_ca_info(); /* name */ ca->name = clone_str(msg->name); - + /* authName */ - ca->authName = chunk_clone(cacert->subject); - dntoa(buf, BUF_LEN, ca->authName); + ca->authName = subject->clone(subject); DBG(DBG_CONTROL, - DBG_log("authname: '%s'", buf) + DBG_log("authname: '%Y'", subject) ) - /* authSerialNumber */ - ca->authKeySerialNumber = chunk_clone(cacert->serialNumber); - /* authKeyID */ - if (cacert->subjectKeyID.ptr != NULL) + if (subjectKeyID.ptr) { - ca->authKeyID = chunk_clone(cacert->subjectKeyID); - datatot(cacert->subjectKeyID.ptr, cacert->subjectKeyID.len, ':' - , buf, BUF_LEN); + ca->authKeyID = chunk_clone(subjectKeyID); DBG(DBG_CONTROL | DBG_PARSING , - DBG_log("authkey: %s", buf) + DBG_log("authkey: %#B", &subjectKeyID) ) } @@ -594,23 +632,9 @@ add_ca_info(const whack_message_t *msg) 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); - } + /* add crl uris */ + add_distribution_point(ca->crluris, msg->crluri); + add_distribution_point(ca->crluris, msg->crluri2); /* strictrlpolicy */ ca->strictcrlpolicy = msg->whack_strict; @@ -620,17 +644,19 @@ add_ca_info(const whack_message_t *msg) ca->next = ca_infos; ca_infos = ca; - ca->installed = time(NULL); - + unlock_ca_info_list("add_ca_info"); /* add cacert to list of authcerts */ + cert = add_authcert(cert, X509_CA); if (!cached_cert && sc != NULL) { - if (sc->last_cert.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->last_cert != NULL) + { + sc->last_cert->count--; + } + sc->last_cert = cert; + cert_share(sc->last_cert); } if (sc != NULL) time(&sc->last_load); @@ -640,54 +666,46 @@ add_ca_info(const whack_message_t *msg) /* * list all ca_info records in the chained list */ -void -list_ca_infos(bool utc) +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, "%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) + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, " authname: \"%Y\"", ca->authName); + if (ca->ldaphost) + { + whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost); + } + if (ca->ldapbase) { - datatot(ca->authKeyID.ptr, ca->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase); } - if (ca->authKeySerialNumber.ptr != NULL) + if (ca->ocspuri) { - datatot(ca->authKeySerialNumber.ptr, ca->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri); + } + + list_distribution_points(ca->crluris); + + if (ca->authKeyID.ptr) + { + whack_log(RC_COMMENT, " authkey: %#B", &ca->authKeyID); } ca = ca->next; } } - diff --git a/src/pluto/ca.h b/src/pluto/ca.h index 44d079b4c..d964a694a 100644 --- a/src/pluto/ca.h +++ b/src/pluto/ca.h @@ -15,49 +15,39 @@ #ifndef _CA_H #define _CA_H -#include "x509.h" -#include "whack.h" - -#define MAX_CA_PATH_LEN 7 +#include <utils/linked_list.h> +#include <utils/identification.h> -/* 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 */ +#include "certs.h" +#include "whack.h" /* CA info structures */ typedef struct ca_info ca_info_t; struct ca_info { - ca_info_t *next; - char *name; - 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; + identification_t *authName; + chunk_t authKeyID; + char *ldaphost; + char *ldapbase; + char *ocspuri; + linked_list_t *crluris; + 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); -extern x509cert_t* get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid - , u_char auth_flags); -extern void load_authcerts(const char *type, const char *path - , u_char auth_flags); -extern x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags); +extern bool trusted_ca(identification_t *a, identification_t *b, int *pathlen); +extern bool match_requested_ca(linked_list_t *requested_ca, + identification_t *our_ca, int *our_pathlen); +extern cert_t* get_authcert(identification_t *subject, chunk_t keyid, + x509_flag_t auth_flags); +extern void load_authcerts(char *type, char *path, x509_flag_t auth_flags); +extern cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags); extern void free_authcerts(void); -extern void list_authcerts(const char *caption, u_char auth_flags, bool utc); -extern bool trust_authcert_candidate(const x509cert_t *cert - , const x509cert_t *alt_chain); -extern ca_info_t* get_ca_info(chunk_t name, chunk_t serial, chunk_t keyid); +extern void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc); +extern bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain); +extern ca_info_t* get_ca_info(identification_t *name, chunk_t keyid); extern bool find_ca_info_by_name(const char *name, bool delete); extern void add_ca_info(const whack_message_t *msg); extern void delete_ca_info(const char *name); diff --git a/src/pluto/certs.c b/src/pluto/certs.c index ca3019b9b..8bce4c5c2 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -17,153 +17,166 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <unistd.h> +#include <time.h> #include <freeswan.h> -#include "library.h" -#include "asn1/asn1.h" +#include <library.h> +#include <asn1/asn1.h> +#include <credentials/certificates/certificate.h> +#include <credentials/certificates/pgp_certificate.h> #include "constants.h" #include "defs.h" #include "log.h" -#include "id.h" -#include "pem.h" #include "certs.h" +#include "whack.h" +#include "fetch.h" +#include "keys.h" +#include "builder.h" /** - * used for initializatin of certs + * Initialization */ -const cert_t cert_empty = {CERT_NONE, {NULL}}; +const cert_t cert_empty = { + NULL , /* cert */ + NULL , /* *next */ + 0 , /* count */ + FALSE /* smartcard */ +}; /** - * extracts the certificate to be sent to the peer + * Chained lists of X.509 and PGP end entity certificates */ -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 chunk_empty; - } -} +static cert_t *certs = NULL; -public_key_t* cert_get_public_key(const cert_t cert) +/** + * Free a pluto certificate + */ +void cert_free(cert_t *cert) { - switch (cert.type) + if (cert) { - case CERT_PGP: - return cert.u.pgp->public_key; - break; - case CERT_X509_SIGNATURE: - return cert.u.x509->public_key; - break; - default: - return NULL; + certificate_t *certificate = cert->cert; + + if (certificate) + { + certificate->destroy(certificate); + } + free(cert); } } -/* load a coded key or certificate file with autodetection - * of binary DER or base64 PEM ASN.1 formats and armored PGP format +/** + * Add a pluto end entity certificate to the chained list */ -bool load_coded_file(char *filename, prompt_pass_t *pass, const char *type, - chunk_t *blob, bool *pgp) +cert_t* cert_add(cert_t *cert) { - err_t ugh = NULL; - - FILE *fd = fopen(filename, "r"); + certificate_t *certificate = cert->cert; + cert_t *c = certs; - if (fd) + while (c != NULL) { - 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); - - *pgp = FALSE; - - /* try DER format */ - if (is_asn1(*blob)) + if (certificate->equals(certificate, c->cert)) /* already in chain, free cert */ { - DBG(DBG_PARSING, - DBG_log(" file coded in DER format"); - ) - return TRUE; + cert_free(cert); + return c; } + c = c->next; + } - /* try PEM format */ - ugh = pemtobin(blob, pass, filename, pgp); + /* insert new cert at the root of the chain */ + lock_certs_and_keys("cert_add"); + cert->next = certs; + certs = cert; + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log(" cert inserted") + ) + unlock_certs_and_keys("cert_add"); + return cert; +} - 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"; - } +/** + * Passphrase callback to read from whack fd + */ +chunk_t whack_pass_cb(prompt_pass_t *pass, int try) +{ + int n; - /* a conversion error has occured */ - plog(" %s", ugh); - free(blob->ptr); - *blob = chunk_empty; + if (try > MAX_PROMPT_PASS_TRIALS) + { + whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials"); + return chunk_empty; + } + if (try == 1) + { + whack_log(RC_ENTERSECRET, "need passphrase for 'private key'"); } else { - plog(" could not open %s file '%s'", type, filename); + whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); + } + + n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); + + if (n == -1) + { + whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); + return chunk_empty; } - return FALSE; + + pass->secret[n-1] = '\0'; + + if (strlen(pass->secret) == 0) + { + whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted"); + return chunk_empty; + } + return chunk_create(pass->secret, strlen(pass->secret)); } /** - * Loads a PKCS#1 or PGP privatekey file + * Loads a PKCS#1 or PGP private key file */ private_key_t* load_private_key(char* filename, prompt_pass_t *pass, key_type_t type) { private_key_t *key = NULL; - chunk_t blob = chunk_empty; - bool pgp = FALSE; - - char *path = concatenate_paths(PRIVATE_KEY_PATH, filename); + char *path; - if (load_coded_file(path, pass, "private key", &blob, &pgp)) - { - if (pgp) - { - parse_pgp(blob, NULL, &key); - } - else + path = concatenate_paths(PRIVATE_KEY_PATH, filename); + if (pass && pass->prompt && pass->fd != NULL_FD) + { /* use passphrase callback */ + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_FROM_FILE, path, + BUILD_PASSPHRASE_CALLBACK, whack_pass_cb, pass, + BUILD_END); + if (key) { - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_BLOB_ASN1_DER, blob, BUILD_END); + whack_log(RC_SUCCESS, "valid passphrase"); } - if (key == NULL) - { - plog(" syntax error in %s private key file", pgp ? "PGP":"PKCS#"); - } - free(blob.ptr); + } + else if (pass) + { /* use a given passphrase */ + chunk_t password = chunk_create(pass->secret, strlen(pass->secret)); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_FROM_FILE, path, + BUILD_PASSPHRASE, password, BUILD_END); + } + else + { /* no passphrase */ + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_FROM_FILE, path, BUILD_END); + + } + if (key) + { + plog(" loaded private key from '%s'", filename); } else { - plog(" error loading private key file"); + plog(" syntax error in private key file"); } return key; } @@ -171,125 +184,166 @@ private_key_t* load_private_key(char* filename, prompt_pass_t *pass, /** * Loads a X.509 or OpenPGP certificate */ -bool load_cert(char *filename, const char *label, cert_t *cert) +cert_t* load_cert(char *filename, const char *label, x509_flag_t flags) { - bool pgp = FALSE; - chunk_t blob = chunk_empty; - - /* initialize cert struct */ - cert->type = CERT_NONE; - cert->u.x509 = NULL; + cert_t *cert; - if (load_coded_file(filename, NULL, label, &blob, &pgp)) + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, + BUILD_FROM_FILE, filename, + BUILD_X509_FLAG, flags, + BUILD_END); + if (cert) { - 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; - } - } + plog(" loaded %s certificate from '%s'", label, filename); } - return FALSE; + return cert; } /** * Loads a host certificate */ -bool load_host_cert(char *filename, cert_t *cert) +cert_t* load_host_cert(char *filename) { char *path = concatenate_paths(HOST_CERT_PATH, filename); - return load_cert(path, "host cert", cert); + return load_cert(path, "host", X509_NONE); } /** * Loads a CA certificate */ -bool load_ca_cert(char *filename, cert_t *cert) +cert_t* load_ca_cert(char *filename) { char *path = concatenate_paths(CA_CERT_PATH, filename); - return load_cert(path, "CA cert", cert); + return load_cert(path, "CA", X509_NONE); } /** - * establish equality of two certificates + * for each link pointing to the certificate increase the count by one */ -bool same_cert(const cert_t *a, const cert_t *b) +void cert_share(cert_t *cert) { - return a->type == b->type && a->u.x509 == b->u.x509; + if (cert != NULL) + { + cert->count++; + } +} + +/* release of a certificate decreases the count by one + * the certificate is freed when the counter reaches zero + */ +void cert_release(cert_t *cert) +{ + if (cert && --cert->count == 0) + { + cert_t **pp = &certs; + while (*pp != cert) + { + pp = &(*pp)->next; + } + *pp = cert->next; + cert_free(cert); + } } /** - * for each link pointing to the certificate increase the count by one + * Get a X.509 certificate with a given issuer found at a certain position */ -void share_cert(cert_t cert) +cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t *chain) { - switch (cert.type) + cert_t *cert = chain ? chain->next : certs; + + while (cert) { - case CERT_PGP: - share_pgpcert(cert.u.pgp); - break; - case CERT_X509_SIGNATURE: - share_x509cert(cert.u.x509); - break; - default: - break; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); + + if (keyid.ptr ? same_keyid(keyid, authKeyID) : + certificate->has_issuer(certificate, issuer)) + { + return cert; + } + cert = cert->next; } + return NULL; } -/* release of a certificate decreases the count by one - " the certificate is freed when the counter reaches zero +/** + * List all PGP end certificates in a chained list */ -void -release_cert(cert_t cert) +void list_pgp_end_certs(bool utc) { - switch (cert.type) + cert_t *cert = certs; + time_t now = time(NULL); + bool first = TRUE; + + + while (cert != NULL) { - case CERT_PGP: - release_pgpcert(cert.u.pgp); - break; - case CERT_X509_SIGNATURE: - release_x509cert(cert.u.x509); - break; - default: - break; + certificate_t *certificate = cert->cert; + + if (certificate->get_type(certificate) == CERT_GPG) + { + time_t created, until; + public_key_t *key; + identification_t *userid = certificate->get_subject(certificate); + pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; + chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); + + if (first) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of PGP End Entity Certificates:"); + first = false; + } + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, " userid: '%Y'", userid); + whack_log(RC_COMMENT, " digest: %#B", &fingerprint); + + /* list validity */ + certificate->get_validity(certificate, &now, &created, &until); + whack_log(RC_COMMENT, " created: %T", &created, utc); + whack_log(RC_COMMENT, " until: %T %s%s", &until, utc, + check_expiry(until, CA_CERT_WARNING_INTERVAL, TRUE), + (until == TIME_32_BIT_SIGNED_MAX) ? " (expires never)":""); + + key = certificate->get_public_key(certificate); + if (key) + { + chunk_t keyid; + + whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", + key_type_names, key->get_type(key), + key->get_keysize(key) * BITS_PER_BYTE, + has_private_key(cert)? ", has private key" : ""); + if (key->get_fingerprint(key, KEY_ID_PUBKEY_INFO_SHA1, &keyid)) + { + whack_log(RC_COMMENT, " keyid: %#B", &keyid); + } + if (key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &keyid)) + { + whack_log(RC_COMMENT, " subjkey: %#B", &keyid); + } + } + } + cert = cert->next; } } -/* +/** + * List all X.509 end certificates in a chained list + */ +void list_x509_end_certs(bool utc) +{ + list_x509cert_chain("End Entity", certs, X509_NONE, utc); +} + +/** * list all X.509 and OpenPGP end certificates */ -void -list_certs(bool utc) +void cert_list(bool utc) { list_x509_end_certs(utc); list_pgp_end_certs(utc); diff --git a/src/pluto/certs.h b/src/pluto/certs.h index 0810c52fa..21e856a3c 100644 --- a/src/pluto/certs.h +++ b/src/pluto/certs.h @@ -18,9 +18,12 @@ #define _CERTS_H #include <credentials/keys/private_key.h> +#include <credentials/certificates/certificate.h> +#include <credentials/certificates/x509.h> -#include "x509.h" -#include "pgpcert.h" +#include <freeswan.h> + +#include "defs.h" /* path definitions for private keys, end certs, * cacerts, attribute certs and crls @@ -43,16 +46,16 @@ #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; -} cert_t; +/* access structure for a pluto certificate */ + +typedef struct cert_t cert_t; + +struct cert_t { + certificate_t *cert; + cert_t *next; + int count; + bool smartcard; +}; /* used for initialization */ extern const cert_t cert_empty; @@ -62,19 +65,17 @@ extern const cert_t cert_empty; */ extern bool no_cr_send; -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); -extern void list_certs(bool utc); +extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags); +extern cert_t* load_host_cert(char *filename); +extern cert_t* load_ca_cert(char *filename); +extern cert_t* cert_add(cert_t *cert); +extern void cert_free(cert_t *cert); +extern void cert_share(cert_t *cert); +extern void cert_release(cert_t *cert); +extern void cert_list(bool utc); +extern cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t* chain); #endif /* _CERTS_H */ diff --git a/src/pluto/connections.c b/src/pluto/connections.c index b800b1665..fece34eec 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -30,15 +30,15 @@ #include <freeswan.h> #include "kameipsec.h" +#include <credentials/certificates/ac.h> #include <credentials/keys/private_key.h> #include "constants.h" #include "defs.h" -#include "id.h" +#include "myid.h" #include "x509.h" #include "ca.h" #include "crl.h" -#include "pgpcert.h" #include "certs.h" #include "ac.h" #include "smartcard.h" @@ -62,9 +62,9 @@ #include "nat_traversal.h" #include "virtual.h" -static void flush_pending_by_connection(struct connection *c); /* forward */ +static void flush_pending_by_connection(connection_t *c); /* forward */ -static struct connection *connections = NULL; +static connection_t *connections = NULL; /* struct host_pair: a nexus of information about a pair of hosts. * A host is an IP address, UDP port pair. This is a debatable choice: @@ -82,34 +82,62 @@ struct host_pair { u_int16_t port; /* host order */ } me, him; bool initial_connection_sent; - struct connection *connections; /* connections with this pair */ + connection_t *connections; /* connections with this pair */ struct pending *pending; /* awaiting Keying Channel */ struct host_pair *next; }; static struct host_pair *host_pairs = NULL; -static struct connection *unoriented_connections = NULL; +static connection_t *unoriented_connections = NULL; -/* check to see that Ids of peers match */ -bool -same_peer_ids(const struct connection *c, const struct connection *d -, const struct id *his_id) +/** + * Check if an id was instantiated by assigning to it the current IP address + */ +bool his_id_was_instantiated(const connection_t *c) { - 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); + if (c->kind != CK_INSTANCE) + { + return FALSE; + } + if (id_is_ipaddr(c->spd.that.id)) + { + identification_t *host; + bool equal; + + host = identification_create_from_sockaddr((sockaddr_t*)&c->spd.that.host_addr); + equal = host->equals(host, c->spd.that.id); + host->destroy(host); + return equal; + } + else + { + return TRUE; + } } -static struct host_pair * -find_host_pair(const ip_address *myaddr, u_int16_t myport -, const ip_address *hisaddr, u_int16_t hisport) +/** + * Check to see that IDs of peers match + */ +bool same_peer_ids(const connection_t *c, const connection_t *d, + identification_t *his_id) +{ + return d->spd.this.id->equals(d->spd.this.id, c->spd.this.id) && + d->spd.that.id->equals(d->spd.that.id, + his_id ? his_id : c->spd.that.id); +} + +static struct host_pair *find_host_pair(const ip_address *myaddr, + u_int16_t myport, + const ip_address *hisaddr, + u_int16_t hisport) { struct host_pair *p, *prev; /* default hisaddr to an appropriate any */ if (hisaddr == NULL) hisaddr = aftoinfo(addrtypeof(myaddr))->any; - + if (nat_traversal_enabled) { /** @@ -125,7 +153,7 @@ find_host_pair(const ip_address *myaddr, u_int16_t myport if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport) { - if (prev != NULL) + if (prev) { prev->next = p->next; /* remove p from list */ p->next = host_pairs; /* and stick it on front */ @@ -138,15 +166,16 @@ find_host_pair(const ip_address *myaddr, u_int16_t myport } /* find head of list of connections with this pair of hosts */ -static struct connection * -find_host_pair_connections(const ip_address *myaddr, u_int16_t myport -, const ip_address *hisaddr, u_int16_t hisport) +static connection_t *find_host_pair_connections(const ip_address *myaddr, + u_int16_t myport, + const ip_address *hisaddr, + u_int16_t hisport) { struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport); if (nat_traversal_enabled && hp && hisaddr) { - struct connection *c; + connection_t *c; for (c = hp->connections; c != NULL; c = c->hp_next) { @@ -158,8 +187,7 @@ find_host_pair_connections(const ip_address *myaddr, u_int16_t myport return hp == NULL? NULL : hp->connections; } -static void -connect_to_host_pair(struct connection *c) +static void connect_to_host_pair(connection_t *c) { if (oriented(*c)) { @@ -206,10 +234,9 @@ connect_to_host_pair(struct connection *c) * Move the winner (if any) to the front. * If none is found, and strict, a diagnostic is logged to whack. */ -struct connection * -con_by_name(const char *nm, bool strict) +connection_t *con_by_name(const char *nm, bool strict) { - struct connection *p, *prev; + connection_t *p, *prev; for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) { @@ -223,7 +250,7 @@ con_by_name(const char *nm, bool strict) if (streq(p->name, nm) && (!strict || p->kind != CK_INSTANCE)) { - if (prev != NULL) + if (prev) { prev->ac_next = p->ac_next; /* remove p from list */ p->ac_next = connections; /* and stick it on front */ @@ -235,8 +262,7 @@ con_by_name(const char *nm, bool strict) return p; } -void -release_connection(struct connection *c, bool relations) +void release_connection(connection_t *c, bool relations) { if (c->kind == CK_INSTANCE) { @@ -264,10 +290,9 @@ release_connection(struct connection *c, bool relations) } -void -delete_connection(struct connection *c, bool relations) +void delete_connection(connection_t *c, bool relations) { - struct connection *old_cur_connection + connection_t *old_cur_connection = cur_connection == c? NULL : cur_connection; #ifdef DEBUG lset_t old_cur_debugging = cur_debugging; @@ -294,26 +319,30 @@ delete_connection(struct connection *c, bool relations) 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); + list_rm(connection_t, ac_next, c, connections); cur_connection = old_cur_connection; /* find and delete c from the host pair list */ if (c->host_pair == NULL) { if (c->ikev1) - list_rm(struct connection, hp_next, c, unoriented_connections); + { + list_rm(connection_t, hp_next, c, unoriented_connections); + } } else { struct host_pair *hp = c->host_pair; - list_rm(struct connection, hp_next, c, hp->connections); + list_rm(connection_t, hp_next, c, hp->connections); c->host_pair = NULL; /* redundant, but safe */ /* if there are no more connections with this host_pair @@ -332,25 +361,45 @@ delete_connection(struct connection *c, bool relations) { free(c->spd.that.virt); } + + /* release virtual IP address lease if any */ + if (c->spd.that.modecfg && c->spd.that.pool && + !isanyaddr(&c->spd.that.host_srcip)) + { + host_t *vip; + + vip = host_create_from_sockaddr((sockaddr_t*)&c->spd.that.host_srcip); + lib->attributes->release_address(lib->attributes, c->spd.that.pool, + vip, c->spd.that.id); + vip->destroy(vip); + } + + /* free internal data */ #ifdef DEBUG cur_debugging = old_cur_debugging; #endif free(c->name); - free_id_content(&c->spd.this.id); + DESTROY_IF(c->spd.this.id); + DESTROY_IF(c->spd.this.ca); + DESTROY_IF(c->spd.this.groups); 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.this.pool); + DESTROY_IF(c->spd.that.id); + DESTROY_IF(c->spd.that.ca); + DESTROY_IF(c->spd.that.groups); free(c->spd.that.updown); - free(c->spd.that.ca.ptr); - free_ietfAttrList(c->spd.that.groups); - free_generalNames(c->requested_ca, TRUE); + free(c->spd.that.pool); + if (c->requested_ca) + { + c->requested_ca->destroy_offset(c->requested_ca, + offsetof(identification_t, destroy)); + } gw_delref(&c->gw_info); lock_certs_and_keys("delete_connection"); - release_cert(c->spd.this.cert); + cert_release(c->spd.this.cert); scx_release(c->spd.this.sc); - release_cert(c->spd.that.cert); + cert_release(c->spd.that.cert); scx_release(c->spd.that.sc); unlock_certs_and_keys("delete_connection"); @@ -361,30 +410,29 @@ delete_connection(struct connection *c, bool relations) } /* Delete connections with the specified name */ -void -delete_connections_by_name(const char *name, bool strict) +void delete_connections_by_name(const char *name, bool strict) { - struct connection *c = con_by_name(name, strict); + connection_t *c = con_by_name(name, strict); for (; c != NULL; c = con_by_name(name, FALSE)) delete_connection(c, FALSE); } -void -delete_every_connection(void) +void delete_every_connection(void) { - while (connections != NULL) + while (connections) + { delete_connection(connections, TRUE); + } } -void -release_dead_interfaces(void) +void release_dead_interfaces(void) { struct host_pair *hp; for (hp = host_pairs; hp != NULL; hp = hp->next) { - struct connection **pp + connection_t **pp , *p; for (pp = &hp->connections; (p = *pp) != NULL; ) @@ -427,18 +475,17 @@ release_dead_interfaces(void) } /* adjust orientations of connections to reflect newly added interfaces */ -void -check_orientations(void) +void check_orientations(void) { /* try to orient all the unoriented connections */ { - struct connection *c = unoriented_connections; + connection_t *c = unoriented_connections; unoriented_connections = NULL; - while (c != NULL) + while (c) { - struct connection *nxt = c->hp_next; + connection_t *nxt = c->hp_next; (void)orient(c); connect_to_host_pair(c); @@ -472,12 +519,12 @@ check_orientations(void) * cost of leaving it is slight and cannot * be induced by a foe). */ - struct connection *c = hp->connections; + connection_t *c = hp->connections; hp->connections = NULL; - while (c != NULL) + while (c) { - struct connection *nxt = c->hp_next; + connection_t *nxt = c->hp_next; c->interface = NULL; (void)orient(c); @@ -491,34 +538,38 @@ check_orientations(void) } } -static err_t -default_end(struct end *e, ip_address *dflt_nexthop) +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)); + int af = addrtypeof(&e->host_addr); - if (afi == NULL) + if (af != AF_INET && af != AF_INET6) + { return "unknown address family in default_end"; + } /* default ID to IP (but only if not NO_IP -- WildCard) */ - if (e->id.kind == ID_ANY && !isanyaddr(&e->host_addr)) + if (e->id->get_type(e->id) == ID_ANY && !isanyaddr(&e->host_addr)) { - e->id.kind = afi->id_addr; - e->id.ip_addr = e->host_addr; + e->id->destroy(e->id); + e->id = identification_create_from_sockaddr((sockaddr_t*)&e->host_addr); e->has_id_wildcards = FALSE; } /* default nexthop to other side */ if (isanyaddr(&e->host_nexthop)) + { e->host_nexthop = *dflt_nexthop; + } /* default client to subnet containing only self * XXX This may mean that the client's address family doesn't match * tunnel_addr_family. */ if (!e->has_client) + { ugh = addrtosubnet(&e->host_addr, &e->client); - + } return ugh; } @@ -527,15 +578,10 @@ default_end(struct end *e, ip_address *dflt_nexthop) * Note: if that==NULL, skip nexthop * Returns strlen of formated result (length excludes NUL at end). */ -size_t -format_end(char *buf -, size_t buf_len -, const struct end *this -, const struct end *that -, bool is_left -, lset_t policy) +size_t format_end(char *buf, size_t buf_len, const struct end *this, + const struct end *that, bool is_left, lset_t policy) { - char client[SUBNETTOT_BUF]; + char client[BUF_LEN]; const char *client_sep = ""; char protoport[sizeof(":255/65535")]; const char *host = NULL; @@ -591,17 +637,24 @@ format_end(char *buf 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 */ + /* we are mode config client, or a server with a pool */ client_sep = "==="; - strcpy(client, "%modecfg"); + client[0] = '%'; + strcpy(client+1, this->pool ? this->pool : "modecfg"); } /* host */ @@ -613,53 +666,50 @@ format_end(char *buf host_port[0] = '\0'; if (this->host_port != IKE_UDP_PORT) - snprintf(host_port, sizeof(host_port), ":%u" - , this->host_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], "]"); - } + /* id */ + snprintf(host_id, sizeof(host_id), "[%Y]", this->id); /* [---hop] */ hop[0] = '\0'; hop_sep = ""; - if (that != NULL && !sameaddr(&this->host_nexthop, &that->host_addr)) + if (that && !sameaddr(&this->host_nexthop, &that->host_addr)) { addrtot(&this->host_nexthop, 0, hop, sizeof(hop)); hop_sep = "---"; } if (is_left) + { snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" , open_brackets, client, close_brackets, client_sep , this->allow_any? "%":"" , host, host_port, host_id, protoport , hop_sep, hop); + } else + { snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" , hop, hop_sep , this->allow_any? "%":"" , host, host_port, host_id, protoport, client_sep , open_brackets, client, close_brackets); + } return strlen(buf); } @@ -668,10 +718,9 @@ format_end(char *buf */ #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) +static size_t format_connection(char *buf, size_t buf_len, + const connection_t *c, + struct spd_route *sr) { size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY); @@ -679,22 +728,35 @@ format_connection(char *buf, size_t buf_len return w + format_end(buf + w, buf_len - w, &sr->that, &sr->this, FALSE, c->policy); } -static void -unshare_connection_strings(struct connection *c) +static void unshare_connection_strings(connection_t *c) { c->name = clone_str(c->name); - - unshare_id_content(&c->spd.this.id); + c->spd.this.id = c->spd.this.id->clone(c->spd.this.id); + c->spd.this.pool = clone_str(c->spd.this.pool); c->spd.this.updown = clone_str(c->spd.this.updown); 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); + cert_share(c->spd.this.cert); + if (c->spd.this.ca) + { + c->spd.this.ca = c->spd.this.ca->clone(c->spd.this.ca); + } + if (c->spd.this.groups) + { + c->spd.this.groups = c->spd.this.groups->get_ref(c->spd.this.groups); + } + c->spd.that.id = c->spd.that.id->clone(c->spd.that.id); + c->spd.that.pool = clone_str(c->spd.that.pool); c->spd.that.updown = clone_str(c->spd.that.updown); scx_share(c->spd.that.sc); - share_cert(c->spd.that.cert); - c->spd.that.ca = chunk_clone(c->spd.that.ca); + cert_share(c->spd.that.cert); + if (c->spd.that.ca) + { + c->spd.that.ca = c->spd.that.ca->clone(c->spd.that.ca); + } + if (c->spd.that.groups) + { + c->spd.that.groups = c->spd.that.groups->get_ref(c->spd.that.groups); + } /* increment references to algo's */ alg_info_addref((struct alg_info *)c->alg_info_esp); @@ -703,137 +765,116 @@ unshare_connection_strings(struct connection *c) static void load_end_certificate(char *filename, struct end *dst) { - time_t valid_until; - cert_t cert; - bool valid_cert = FALSE; + time_t notBefore, notAfter; + cert_t *cert = NULL; + certificate_t *certificate; bool cached_cert = FALSE; - + /* initialize end certificate */ - dst->cert.type = CERT_NONE; - dst->cert.u.x509 = NULL; + dst->cert = NULL; /* initialize smartcard info record */ dst->sc = NULL; - if (filename != NULL) + if (filename) { if (scx_on_smartcard(filename)) { /* load cert from smartcard */ - valid_cert = scx_load_cert(filename, &dst->sc, &cert, &cached_cert); + cert = scx_load_cert(filename, &dst->sc, &cached_cert); } else { /* load cert from file */ - valid_cert = load_host_cert(filename, &cert); + cert = load_host_cert(filename); } } - if (valid_cert) + if (cert) { - err_t ugh = NULL; + certificate = cert->cert; - switch (cert.type) + if (dst->id->get_type(dst->id) == ID_ANY || + !certificate->has_subject(certificate, dst->id)) { - case CERT_PGP: - select_pgpcert_id(cert.u.pgp, &dst->id); + plog( " id '%Y' not confirmed by certificate, defaulting to '%Y'", + dst->id, certificate->get_subject(certificate)); + dst->id->destroy(dst->id); + dst->id = certificate->get_subject(certificate); + dst->id = dst->id->clone(dst->id); + } - if (cached_cert) - dst->cert = cert; - else + if (cached_cert) + { + dst->cert = cert; + } + else + { + if (!certificate->get_validity(certificate, NULL, ¬Before, ¬After)) { - 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); + plog("certificate is invalid (valid from %T to %T)", + ¬Before, FALSE, ¬After, FALSE); + cert_free(cert); + return; } - break; - case CERT_X509_SIGNATURE: - select_x509cert_id(cert.u.x509, &dst->id); + DBG(DBG_CONTROL, + DBG_log("certificate is valid") + ) + add_public_key_from_cert(cert, notAfter, DAL_LOCAL); + dst->cert = cert_add(cert); + } + certificate = dst->cert->cert; - if (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; - } + /* if no CA is defined, use issuer as default */ + if (dst->ca == NULL && certificate->get_type(certificate) == CERT_X509) + { + identification_t *issuer; - 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; + issuer = certificate->get_issuer(certificate); + dst->ca = issuer->clone(issuer); } /* cache the certificate that was last retrieved from the smartcard */ - if (dst->sc != NULL) + if (dst->sc) { - if (!same_cert(&dst->sc->last_cert, &dst->cert)) + if (!certificate->equals(certificate, dst->sc->last_cert->cert)) { lock_certs_and_keys("load_end_certificates"); - release_cert(dst->sc->last_cert); + cert_release(dst->sc->last_cert); dst->sc->last_cert = dst->cert; - share_cert(dst->cert); + cert_share(dst->cert); unlock_certs_and_keys("load_end_certificates"); } time(&dst->sc->last_load); } } + scx_share(dst->sc); + cert_share(dst->cert); } -static bool -extract_end(struct end *dst, const whack_end_t *src, const char *which) +static bool extract_end(struct end *dst, const whack_end_t *src, + const char *which) { bool same_ca = FALSE; - /* decode id, if any */ - if (src->id == NULL) - { - dst->id.kind = ID_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 = chunk_empty; + dst->id = identification_create_from_string(src->id); + dst->ca = NULL; /* decode CA distinguished name, if any */ - if (src->ca != NULL) + if (src->ca) { 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) + dst->ca = identification_create_from_string(src->ca); + if (dst->ca->get_type(dst->ca) != ID_DER_ASN1_DN) { - plog("bad CA string '%s': %s (ignored)", src->ca, ugh); - dst->ca = chunk_empty; + plog("bad CA string '%s', ignored", src->ca); + dst->ca->destroy(dst->ca); + dst->ca = NULL; } } } @@ -842,10 +883,13 @@ extract_end(struct end *dst, const whack_end_t *src, const char *which) load_end_certificate(src->cert, dst); /* does id has wildcards? */ - dst->has_id_wildcards = id_count_wildcards(&dst->id) > 0; + dst->has_id_wildcards = dst->id->contains_wildcards(dst->id); /* decode group attributes, if any */ - decode_groups(src->groups, &dst->groups); + if (src->groups) + { + dst->groups = ietf_attributes_create_from_string(src->groups); + } /* the rest is simple copying of corresponding fields */ dst->host_addr = src->host_addr; @@ -863,30 +907,38 @@ extract_end(struct end *dst, const whack_end_t *src, const char *which) dst->hostaccess = src->hostaccess; dst->allow_any = src->allow_any; dst->sendcert = src->sendcert; - dst->updown = src->updown; + dst->updown = clone_str(src->updown); dst->host_port = src->host_port; + /* if the sourceip netmask is zero a named pool exists */ + if (src->sourceip_mask == 0) + { + dst->pool = clone_str(src->sourceip); + } + /* if host sourceip is defined but no client is present * behind the host then set client to sourceip/32 */ - if (addrbytesptr(&dst->host_srcip, NULL) - && !isanyaddr(&dst->host_srcip) - && !dst->has_natip - && !dst->has_client) + 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) + if (ugh) + { plog("could not assign host sourceip to client subnet"); + } else + { dst->has_client = TRUE; + } } return same_ca; } -static bool -check_connection_end(const whack_end_t *this, const whack_end_t *that -, const whack_message_t *wm) +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) @@ -921,23 +973,23 @@ check_connection_end(const whack_end_t *this, const whack_end_t *that return TRUE; /* happy */ } -struct connection * -find_connection_by_reqid(uint32_t reqid) +connection_t *find_connection_by_reqid(uint32_t reqid) { - struct connection *c; + connection_t *c; reqid &= ~3; for (c = connections; c != NULL; c = c->ac_next) { if (c->spd.reqid == reqid) + { return c; + } } return NULL; } -static uint32_t -gen_reqid(void) +static uint32_t gen_reqid(void) { uint32_t start; static uint32_t reqid = IPSEC_MANUAL_REQID_MAX & ~3; @@ -946,17 +998,20 @@ gen_reqid(void) 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) +void add_connection(const whack_message_t *wm) { if (con_by_name(wm->name, FALSE) != NULL) { @@ -973,45 +1028,50 @@ add_connection(const whack_message_t *wm) && check_connection_end(&wm->left, &wm->right, wm)) { bool same_rightca, same_leftca; - struct connection *c = malloc_thing(struct connection); + connection_t *c = malloc_thing(connection_t); zero(c); - c->name = wm->name; + c->name = clone_str(wm->name); c->ikev1 = wm->ikev1; c->policy = wm->policy; if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp) + { loglog(RC_COMMENT , "ignoring --compress in \"%s\" because KLIPS is not configured to do IPCOMP" , c->name); + } if (wm->esp) { DBG(DBG_CONTROL, DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp: "NULL") ) - c->alg_info_esp= alg_info_esp_create_from_str(wm->esp? wm->esp : ""); + c->alg_info_esp = alg_info_esp_create_from_str(wm->esp? wm->esp : ""); DBG(DBG_CRYPT|DBG_CONTROL, static char buf[BUF_LEN]="<NULL>"; if (c->alg_info_esp) + { alg_info_snprint(buf, sizeof(buf) ,(struct alg_info *)c->alg_info_esp); + } DBG_log("esp proposal: %s", buf); ) if (c->alg_info_esp) { - if (c->alg_info_esp->alg_info_cnt==0) - loglog(RC_LOG_SERIOUS - , "got 0 transforms for esp=\"%s\"", wm->esp); + if (c->alg_info_esp->alg_info_cnt == 0) + { + loglog(RC_LOG_SERIOUS, "got 0 esp transforms"); + } } else { - loglog(RC_LOG_SERIOUS, "esp string error"); + loglog(RC_LOG_SERIOUS, "syntax error in esp string"); } } - + if (wm->ike) { DBG(DBG_CONTROL, @@ -1023,22 +1083,25 @@ add_connection(const whack_message_t *wm) static char buf[BUF_LEN]="<NULL>"; if (c->alg_info_ike) + { alg_info_snprint(buf, sizeof(buf) , (struct alg_info *)c->alg_info_ike); + } DBG_log("ike proposal: %s", buf); ) if (c->alg_info_ike) { - if (c->alg_info_ike->alg_info_cnt==0) - loglog(RC_LOG_SERIOUS - , "got 0 transforms for ike=\"%s\"", wm->ike); + if (c->alg_info_ike->alg_info_cnt == 0) + { + loglog(RC_LOG_SERIOUS, "got 0 ike transforms"); + } } else { - loglog(RC_LOG_SERIOUS, "ike string error:"); + loglog(RC_LOG_SERIOUS, "syntax error in ike string"); } } - + 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; @@ -1059,9 +1122,13 @@ add_connection(const whack_message_t *wm) same_rightca = extract_end(&c->spd.that, &wm->right, "right"); if (same_rightca) - c->spd.that.ca = c->spd.this.ca; + { + c->spd.that.ca = c->spd.this.ca->clone(c->spd.this.ca); + } else if (same_leftca) - c->spd.this.ca = c->spd.that.ca; + { + c->spd.this.ca = c->spd.that.ca->clone(c->spd.that.ca); + } default_end(&c->spd.this, &c->spd.that.host_addr); default_end(&c->spd.that, &c->spd.this.host_addr); @@ -1127,16 +1194,17 @@ add_connection(const whack_message_t *wm) c->spd.that.has_client = TRUE; } - unshare_connection_strings(c); (void)orient(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]; + char topo[BUF_LEN]; (void) format_connection(topo, sizeof(topo), c, &c->spd); @@ -1172,12 +1240,10 @@ add_connection(const whack_message_t *wm) * Returns name of new connection. May be NULL. * Caller is responsible for freeing. */ -char * -add_group_instance(struct connection *group, const ip_subnet *target) +char *add_group_instance(connection_t *group, const ip_subnet *target) { - char namebuf[100] - , targetbuf[SUBNETTOT_BUF]; - struct connection *t; + char namebuf[100], targetbuf[SUBNETTOT_BUF]; + connection_t *t; char *name = NULL; passert(group->kind == CK_GROUP); @@ -1213,7 +1279,7 @@ add_group_instance(struct connection *group, const ip_subnet *target) if (t->spd.that.virt) { DBG_log("virtual_ip not supported in group instance"); - t->spd.that.virt = NULL; + t->spd.that.virt = NULL; } /* add to connections list */ @@ -1234,9 +1300,8 @@ add_group_instance(struct connection *group, const ip_subnet *target) } /* an old target has disappeared for a group: delete instance */ -void -remove_group_instance(const struct connection *group USED_BY_DEBUG -, const char *name) +void remove_group_instance(const connection_t *group USED_BY_DEBUG, + const char *name) { passert(group->kind == CK_GROUP); passert(oriented(*group)); @@ -1254,13 +1319,10 @@ remove_group_instance(const struct connection *group USED_BY_DEBUG * * Note that instantiate can only deal with a single SPD/eroute. */ -static struct connection * -instantiate(struct connection *c, const ip_address *him -, u_int16_t his_port -, const struct id *his_id) +static connection_t *instantiate(connection_t *c, const ip_address *him, + u_int16_t his_port, identification_t *his_id) { - struct connection *d; - int wildcards; + connection_t *d; passert(c->kind == CK_TEMPLATE); passert(c->spd.next == NULL); @@ -1269,15 +1331,20 @@ instantiate(struct connection *c, const ip_address *him d = clone_thing(*c); d->spd.that.allow_any = FALSE; - if (his_id != NULL) + if (his_id) { - passert(match_id(his_id, &d->spd.that.id, &wildcards)); - d->spd.that.id = *his_id; + 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); + if (d->spd.this.groups) + { + d->spd.this.groups = d->spd.this.groups->get_ref(d->spd.this.groups); + } + if (d->spd.that.groups) + { + d->spd.that.groups = d->spd.that.groups->get_ref(d->spd.that.groups); + } d->kind = CK_INSTANCE; passert(oriented(*d)); @@ -1318,11 +1385,11 @@ instantiate(struct connection *c, const ip_address *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) +connection_t *rw_instantiate(connection_t *c, const ip_address *him, + u_int16_t his_port, const ip_subnet *his_net, + identification_t *his_id) { - struct connection *d = instantiate(c, him, his_port, his_id); + connection_t *d = instantiate(c, him, his_port, his_id); if (d && his_net && is_virtual_connection(c)) { @@ -1345,15 +1412,12 @@ rw_instantiate(struct connection *c, const ip_address *him, u_int16_t his_port return d; } -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 USED_BY_DEBUG -, const ip_address *peer_client) +connection_t *oppo_instantiate(connection_t *c, const ip_address *him, + identification_t *his_id, struct gw_info *gw, + const ip_address *our_client USED_BY_DEBUG, + const ip_address *peer_client) { - struct connection *d = instantiate(c, him, 0, his_id); + connection_t *d = instantiate(c, him, 0, his_id); passert(d->spd.next == NULL); @@ -1407,7 +1471,7 @@ oppo_instantiate(struct connection *c d->instance_initiation_ok = TRUE; DBG(DBG_CONTROL, - char topo[CONNECTION_BUF]; + char topo[BUF_LEN]; (void) format_connection(topo, sizeof(topo), d, &d->spd); DBG_log("instantiated \"%s\": %s", d->name, topo); @@ -1416,14 +1480,17 @@ oppo_instantiate(struct connection *c } /* priority formatting */ -void -fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) +void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) { if (pp == BOTTOM_PRIO) + { snprintf(buf, POLICY_PRIO_BUF, "0"); + } else + { snprintf(buf, POLICY_PRIO_BUF, "%lu,%lu" , pp>>16, (pp & ~(~(policy_prio_t)0 << 16)) >> 8); + } } /* Format any information needed to identify an instance of a connection. @@ -1431,8 +1498,8 @@ fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) * Road Warrior: peer's IP address * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0' */ -static size_t -fmt_client(const ip_subnet *client, const ip_address *gw, const char *prefix, char buf[ADDRTOT_BUF]) +static size_t fmt_client(const ip_subnet *client, const ip_address *gw, + const char *prefix, char buf[ADDRTOT_BUF]) { if (subnetisaddr(client, gw)) { @@ -1452,8 +1519,7 @@ fmt_client(const ip_subnet *client, const ip_address *gw, const char *prefix, ch return strlen(buf); } -void -fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF]) +void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]) { char *p = buf; @@ -1510,13 +1576,12 @@ fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF]) * * See also build_outgoing_opportunistic_connection. */ -struct connection * -find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto) +connection_t *find_connection_for_clients(struct spd_route **srp, + const ip_address *our_client, + const ip_address *peer_client, + int transport_proto) { - struct connection *c = connections, *best = NULL; + connection_t *c = connections, *best = NULL; policy_prio_t best_prio = BOTTOM_PRIO; struct spd_route *sr; struct spd_route *best_sr = NULL; @@ -1540,7 +1605,9 @@ find_connection_for_clients(struct spd_route **srp, 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) { @@ -1605,11 +1672,14 @@ find_connection_for_clients(struct spd_route **srp, } } - if (best!= NULL && NEVER_NEGOTIATE(best->policy)) + if (best && NEVER_NEGOTIATE(best->policy)) + { best = NULL; - - if (srp != NULL && best != NULL) + } + if (srp && best) + { *srp = best_sr; + } #ifdef DEBUG if (DBGP(DBG_CONTROL)) @@ -1654,25 +1724,18 @@ find_connection_for_clients(struct spd_route **srp, * find_connection_for_clients. In this case, we know the gateways * that we need to instantiate an opportunistic connection. */ -struct connection * -build_outgoing_opportunistic_connection(struct gw_info *gw - ,const ip_address *our_client - ,const ip_address *peer_client) +connection_t *build_outgoing_opportunistic_connection(struct gw_info *gw, + const ip_address *our_client, + const ip_address *peer_client) { struct iface *p; - struct connection *best = NULL; + connection_t *best = NULL; struct spd_route *sr, *bestsr; char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; addrtot(our_client, 0, ocb, sizeof(ocb)); addrtot(peer_client, 0, pcb, sizeof(pcb)); - 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) { @@ -1680,8 +1743,8 @@ build_outgoing_opportunistic_connection(struct gw_info *gw * 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); + connection_t *c = find_host_pair_connections(&p->addr, pluto_port, + (ip_address *)NULL, pluto_port); for (; c != NULL; c = c->hp_next) { @@ -1723,18 +1786,25 @@ build_outgoing_opportunistic_connection(struct gw_info *gw } } - if (best == NULL - || NEVER_NEGOTIATE(best->policy) - || (best->policy & POLICY_OPPO) == LEMPTY - || best->kind != CK_TEMPLATE) + 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); + { + chunk_t encoding = gw->gw_id->get_encoding(gw->gw_id); + id_type_t type = gw->gw_id->get_type(gw->gw_id); + ip_address ip_addr; + + initaddr(encoding.ptr, encoding.len, + (type == ID_IPV4_ADDR) ? AF_INET : AF_INET6, &ip_addr); + + return oppo_instantiate(best, &ip_addr, NULL, gw, our_client, peer_client); + } } -bool -orient(struct connection *c) +bool orient(connection_t *c) { struct spd_route *sr; @@ -1750,7 +1820,9 @@ orient(struct connection *c) for (p = interfaces; p != NULL; p = p->next) { if (p->ike_float) + { continue; + } for (;;) { @@ -1796,12 +1868,11 @@ orient(struct connection *c) return oriented(*c); } -void -initiate_connection(const char *name, int whackfd) +void initiate_connection(const char *name, int whackfd) { - struct connection *c = con_by_name(name, TRUE); + connection_t *c = con_by_name(name, TRUE); - if (c != NULL && c->ikev1) + if (c && c->ikev1) { set_cur_connection(c); if (!oriented(*c)) @@ -1823,11 +1894,11 @@ initiate_connection(const char *name, int whackfd) else { /* do we have to prompt for a PIN code? */ - if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD) + if (c->spd.this.sc && !c->spd.this.sc->valid && whackfd != NULL_FD) { scx_get_pin(c->spd.this.sc, whackfd); } - if (c->spd.this.sc != NULL && !c->spd.this.sc->valid) + if (c->spd.this.sc && !c->spd.this.sc->valid) { loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); } @@ -1836,8 +1907,8 @@ initiate_connection(const char *name, int whackfd) if (c->spd.that.allow_any) { - c = instantiate(c, &c->spd.that.host_addr, c->spd.that.host_port - , &c->spd.that.id); + 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 @@ -1928,10 +1999,7 @@ struct find_oppo_continuation { struct find_oppo_bundle b; }; -static void -cannot_oppo(struct connection *c - , struct find_oppo_bundle *b - , err_t ugh) +static void cannot_oppo(connection_t *c, struct find_oppo_bundle *b, err_t ugh) { char pcb[ADDRTOT_BUF]; char ocb[ADDRTOT_BUF]; @@ -1946,11 +2014,11 @@ cannot_oppo(struct connection *c , "Can't Opportunistically initiate for %s to %s: %s" , ocb, pcb, ugh); - if (c != NULL && c->policy_next != NULL) + if (c && c->policy_next) { /* there is some policy that comes afterwards */ struct spd_route *shunt_spd; - struct connection *nc = c->policy_next; + connection_t *nc = c->policy_next; struct state *st; passert(c->kind == CK_TEMPLATE); @@ -2048,12 +2116,9 @@ cannot_oppo(struct connection *c static void initiate_opportunistic_body(struct find_oppo_bundle *b , struct adns_continuation *ac, err_t ac_ugh); /* forward */ -void -initiate_opportunistic(const ip_address *our_client -, const ip_address *peer_client -, int transport_proto -, bool held -, int whackfd) +void initiate_opportunistic(const ip_address *our_client, + const ip_address *peer_client, int transport_proto, + bool held, int whackfd) { struct find_oppo_bundle b; @@ -2070,11 +2135,10 @@ initiate_opportunistic(const ip_address *our_client initiate_opportunistic_body(&b, NULL, NULL); } -static void -continue_oppo(struct adns_continuation *acr, err_t ugh) +static void continue_oppo(struct adns_continuation *acr, err_t ugh) { struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ - struct connection *c; + connection_t *c; bool was_held = cr->b.held; int whackfd = cr->b.whackfd; @@ -2095,7 +2159,7 @@ continue_oppo(struct adns_continuation *acr, err_t ugh) #ifdef DEBUG /* if we're going to ignore the error, at least note it in debugging log */ - if (cr->b.failure_ok && ugh != NULL) + if (cr->b.failure_ok && ugh) { DBG(DBG_CONTROL | DBG_DNS, { @@ -2110,7 +2174,7 @@ continue_oppo(struct adns_continuation *acr, err_t ugh) } #endif - if (!cr->b.failure_ok && ugh != NULL) + if (!cr->b.failure_ok && ugh) { c = find_connection_for_clients(NULL, &cr->b.our_client, &cr->b.peer_client , cr->b.transport_proto); @@ -2145,10 +2209,8 @@ continue_oppo(struct adns_continuation *acr, err_t ugh) } #ifdef USE_KEYRR -static err_t -check_key_recs(enum myid_state try_state -, const struct connection *c -, struct adns_continuation *ac) +static err_t check_key_recs(enum myid_state try_state, const connection_t *c, + struct adns_continuation *ac) { /* Check if KEY lookup yielded good results. * Looking up based on our ID. Used if @@ -2194,14 +2256,15 @@ check_key_recs(enum myid_state try_state } } } - if (ugh != NULL) + if (ugh) + { 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, +static err_t check_txt_recs(enum myid_state try_state, const connection_t *c, struct adns_continuation *ac) { /* Check if TXT lookup yielded good results. @@ -2226,7 +2289,7 @@ static err_t check_txt_recs(enum myid_state try_state, { ugh = "we don't know our own RSA key"; } - else if (!same_id(&ac->id, &c->spd.this.id)) + else if (!ac->id->equals(ac->id, c->spd.this.id)) { ugh = "our ID changed underfoot"; } @@ -2251,7 +2314,7 @@ static err_t check_txt_recs(enum myid_state try_state, } } } - if (ugh != NULL) + if (ugh) { myid_state = old_myid_state; } @@ -2260,12 +2323,11 @@ static err_t check_txt_recs(enum myid_state try_state, /* note: gateways_from_dns must be NULL iff this is the first call */ -static void -initiate_opportunistic_body(struct find_oppo_bundle *b -, struct adns_continuation *ac -, err_t ac_ugh) +static void initiate_opportunistic_body(struct find_oppo_bundle *b, + struct adns_continuation *ac, + err_t ac_ugh) { - struct connection *c; + connection_t *c; struct spd_route *sr; /* What connection shall we use? @@ -2353,17 +2415,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b 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 */ + DBG(DBG_CONTROL, DBG_log("creating new instance from \"%s\"%s", + c->name, (fmt_conn_instance(c, cib), cib))); + snprintf(mycredentialstr, BUF_LEN, "%Y", sr->this.id); /* handle any DNS answer; select next step */ - switch (b->step) { case fos_start: @@ -2373,18 +2429,17 @@ initiate_opportunistic_body(struct find_oppo_bundle *b case fos_myid_ip_txt: /* TXT for our default IP address as %myid */ ugh = check_txt_recs(MYID_IP, c, ac); - if (ugh != NULL) + if (ugh) { /* 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)); + DBG(DBG_OPPO, + DBG_log("can not use our IP (%Y:TXT) as identity: %s", + myids[MYID_IP], ugh)); if (!logged_myid_ip_txt_warning) { - loglog(RC_LOG_SERIOUS - , "can not use our IP (%s:TXT) as identity: %s" - , myid_str[MYID_IP] - , ugh); + loglog(RC_LOG_SERIOUS, + "can not use our IP (%Y:TXT) as identity: %s", + myids[MYID_IP], ugh); logged_myid_ip_txt_warning = TRUE; } @@ -2396,9 +2451,9 @@ initiate_opportunistic_body(struct find_oppo_bundle *b /* 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]); + loglog(RC_LOG_SERIOUS, + "using our IP (%Y:TXT) as identity!", + myids[MYID_IP]); logged_myid_ip_txt_warning = TRUE; } @@ -2408,18 +2463,17 @@ initiate_opportunistic_body(struct find_oppo_bundle *b case fos_myid_hostname_txt: /* TXT for our hostname as %myid */ ugh = check_txt_recs(MYID_HOSTNAME, c, ac); - if (ugh != NULL) + if (ugh) { /* 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)); + DBG(DBG_OPPO, + DBG_log("can not use our hostname (%Y:TXT) as identity: %s", + myids[MYID_HOSTNAME], ugh)); if (!logged_myid_fqdn_txt_warning) { - loglog(RC_LOG_SERIOUS - , "can not use our hostname (%s:TXT) as identity: %s" - , myid_str[MYID_HOSTNAME] - , ugh); + loglog(RC_LOG_SERIOUS, + "can not use our hostname (%Y:TXT) as identity: %s", + myids[MYID_HOSTNAME], ugh); logged_myid_fqdn_txt_warning = TRUE; } #ifdef USE_KEYRR @@ -2432,9 +2486,9 @@ initiate_opportunistic_body(struct find_oppo_bundle *b /* 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]); + loglog(RC_LOG_SERIOUS, + "using our hostname (%Y:TXT) as identity!", + myids[MYID_HOSTNAME]); logged_myid_fqdn_txt_warning = TRUE; } next_step = fos_our_client; @@ -2444,18 +2498,17 @@ initiate_opportunistic_body(struct find_oppo_bundle *b #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) + if (ugh) { /* 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)); + DBG(DBG_OPPO, + DBG_log("can not use our IP (%Y:KEY) as identity: %s", + myids[MYID_IP], ugh)); if (!logged_myid_ip_key_warning) { - loglog(RC_LOG_SERIOUS - , "can not use our IP (%s:KEY) as identity: %s" - , myid_str[MYID_IP] - , ugh); + loglog(RC_LOG_SERIOUS, + "can not use our IP (%Y:KEY) as identity: %s", + myids[MYID_IP], ugh); logged_myid_ip_key_warning = TRUE; } @@ -2467,9 +2520,9 @@ initiate_opportunistic_body(struct find_oppo_bundle *b /* 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]); + loglog(RC_LOG_SERIOUS, + "using our IP (%Y:KEY) as identity!", + myids[MYID_IP]); logged_myid_ip_key_warning = TRUE; } next_step = fos_our_client; @@ -2478,21 +2531,19 @@ initiate_opportunistic_body(struct find_oppo_bundle *b case fos_myid_hostname_key: /* KEY for our hostname as %myid */ ugh = check_key_recs(MYID_HOSTNAME, c, ac); - if (ugh != NULL) + if (ugh) { /* 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)); + DBG(DBG_OPPO, + DBG_log("can not use our hostname (%Y:KEY) as identity: %s", + myids[MYID_HOSTNAME], ugh)); if (!logged_myid_fqdn_key_warning) { - loglog(RC_LOG_SERIOUS - , "can not use our hostname (%s:KEY) as identity: %s" - , myid_str[MYID_HOSTNAME] - , ugh); + loglog(RC_LOG_SERIOUS, + "can not use our hostname (%Y:KEY) as identity: %s", + myids[MYID_HOSTNAME], ugh); logged_myid_fqdn_key_warning = TRUE; } - next_step = fos_myid_hostname_key; ugh = NULL; /* failure can be recovered from */ } @@ -2501,9 +2552,9 @@ initiate_opportunistic_body(struct find_oppo_bundle *b /* 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]); + loglog(RC_LOG_SERIOUS, + "using our hostname (%Y:KEY) as identity!", + myids[MYID_HOSTNAME]); logged_myid_fqdn_key_warning = TRUE; } next_step = fos_our_client; @@ -2522,8 +2573,6 @@ initiate_opportunistic_body(struct find_oppo_bundle *b next_step = fos_his_client; /* normal situation */ - passert(sr != NULL); - if (private == NULL) { ugh = "we don't know our own RSA key"; @@ -2533,7 +2582,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b /* this wasn't true when we started -- bail */ ugh = "our IP address changed underfoot"; } - else if (!same_id(&ac->sgw_id, &sr->this.id)) + else if (!ac->sgw_id->equals(ac->sgw_id, sr->this.id)) { /* this wasn't true when we started -- bail */ ugh = "our ID changed underfoot"; @@ -2548,8 +2597,6 @@ initiate_opportunistic_body(struct find_oppo_bundle *b 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. @@ -2592,7 +2639,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b { ugh = "we don't know our own RSA key"; } - else if (!same_id(&ac->id, &c->spd.this.id)) + else if (!ac->id->equals(ac->id, c->spd.this.id)) { ugh = "our ID changed underfoot"; } @@ -2606,8 +2653,6 @@ initiate_opportunistic_body(struct find_oppo_bundle *b 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)) @@ -2620,7 +2665,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b } } #ifdef USE_KEYRR - if (ugh != NULL) + if (ugh) { /* if no TXT with right key, try KEY */ DBG(DBG_CONTROL, @@ -2707,18 +2752,14 @@ initiate_opportunistic_body(struct find_oppo_bundle *b /* We cannot seem to instantiate a suitable connection: * complain clearly. */ - char ocb[ADDRTOT_BUF] - , pcb[ADDRTOT_BUF] - , pb[ADDRTOT_BUF]; + char ocb[ADDRTOT_BUF], pcb[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); + loglog(RC_OPPOFAILURE, + "no suitable connection for opportunism " + "between %s and %s with %Y as peer", + ocb, pcb, ac->gateways_from_dns->gw_id); #ifdef KLIPS if (b->held) @@ -2774,7 +2815,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b , ours, his, oppo_step_name[b->step], ugh ? ugh : "ok"); }); - if (ugh != NULL) + if (ugh) { b->policy_prio = c->prio; b->failure_shunt = shunt_policy_spi(c, FALSE); @@ -2788,7 +2829,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b { /* set up the next query */ struct find_oppo_continuation *cr = malloc_thing(struct find_oppo_continuation); - struct id id; + identification_t *id; b->policy_prio = c->prio; b->failure_shunt = shunt_policy_spi(c, FALSE); @@ -2829,23 +2870,20 @@ initiate_opportunistic_body(struct find_oppo_bundle *b switch (next_step) { case fos_myid_ip_txt: - if (c->spd.this.id.kind == ID_MYID + if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID && myid_state != MYID_SPECIFIED) { cr->b.failure_ok = TRUE; cr->b.want = b->want = "TXT record for IP address as %myid"; - ugh = start_adns_query(&myids[MYID_IP] - , &myids[MYID_IP] - , T_TXT - , continue_oppo - , &cr->ac); + 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 + if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID && myid_state != MYID_SPECIFIED) { #ifdef USE_KEYRR @@ -2854,11 +2892,9 @@ initiate_opportunistic_body(struct find_oppo_bundle *b 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); + ugh = start_adns_query(myids[MYID_HOSTNAME], + myids[MYID_HOSTNAME], + T_TXT, continue_oppo, &cr->ac); break; } @@ -2872,11 +2908,8 @@ initiate_opportunistic_body(struct find_oppo_bundle *b { 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); + ugh = start_adns_query(myids[MYID_IP], NULL, /* security gateway meaningless */ + T_KEY, continue_oppo, &cr->ac); break; } cr->b.step = fos_myid_hostname_key; @@ -2888,11 +2921,8 @@ initiate_opportunistic_body(struct find_oppo_bundle *b { 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); + ugh = start_adns_query(myids[MYID_HOSTNAME], NULL, /* security gateway meaningless */ + T_KEY, continue_oppo, &cr->ac); break; } #endif @@ -2906,12 +2936,10 @@ initiate_opportunistic_body(struct find_oppo_bundle *b * 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); + id = identification_create_from_sockaddr((sockaddr_t*)&b->our_client); + ugh = start_adns_query(id, c->spd.this.id, /* we are the security gateway */ + T_TXT, continue_oppo, &cr->ac); + id->destroy(id); break; } cr->b.step = fos_our_txt; @@ -2920,22 +2948,16 @@ initiate_opportunistic_body(struct find_oppo_bundle *b 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); + ugh = start_adns_query(sr->this.id, sr->this.id, /* we are the security gateway */ + T_TXT, continue_oppo, &cr->ac); break; #ifdef USE_KEYRR case fos_our_key: /* KEY for us */ cr->b.want = b->want = "our KEY record"; cr->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(&sr->this.id - , (const struct id *) NULL /* security gateway meaningless */ - , T_KEY - , continue_oppo - , &cr->ac); + ugh = start_adns_query(sr->this.id, NULL, /* security gateway meaningless */ + T_KEY, continue_oppo, &cr->ac); break; #endif /* USE_KEYRR */ @@ -2943,12 +2965,10 @@ initiate_opportunistic_body(struct find_oppo_bundle *b /* 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); + id = identification_create_from_sockaddr((sockaddr_t*)&b->peer_client); + ugh = start_adns_query(id, NULL, /* security gateway unconstrained */ + T_TXT, continue_oppo, &cr->ac); + id->destroy(id); break; default: @@ -2964,20 +2984,19 @@ initiate_opportunistic_body(struct find_oppo_bundle *b close_any(b->whackfd); } -void -terminate_connection(const char *nm) +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); + connection_t *c = con_by_name(nm, TRUE); if (c == NULL || !c->ikev1) return; do { - struct connection *n = c->ac_next; /* grab this before c might disappear */ + connection_t *n = c->ac_next; /* grab this before c might disappear */ if (streq(c->name, nm) && c->kind >= CK_PERMANENT @@ -2993,7 +3012,7 @@ terminate_connection(const char *nm) reset_cur_connection(); } c = n; - } while (c != NULL); + } while (c); } /* an ISAKMP SA has been established. @@ -3002,8 +3021,7 @@ terminate_connection(const char *nm) */ bool uniqueIDs = FALSE; /* --uniqueids? */ -void -ISAKMP_SA_established(struct connection *c, so_serial_t serial) +void ISAKMP_SA_established(connection_t *c, so_serial_t serial) { c->newest_isakmp_sa = serial; @@ -3011,23 +3029,25 @@ ISAKMP_SA_established(struct connection *c, so_serial_t serial) * 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; + connection_t *d; for (d = connections; d != NULL; ) { - struct connection *next = d->ac_next; /* might move underneath us */ + connection_t *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)) + if (d->kind >= CK_PERMANENT && + c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && + c->spd.that.id->equals(c->spd.that.id, d->spd.that.id) && + !sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr)) { release_connection(d, FALSE); } @@ -3047,13 +3067,10 @@ ISAKMP_SA_established(struct connection *c, so_serial_t serial) * The return value is used to find other connections sharing a route. * *erop is used to find other connections sharing an eroute. */ -struct connection * -route_owner(struct connection *c - , struct spd_route **srp - , struct connection **erop - , struct spd_route **esrp) +connection_t *route_owner(connection_t *c, struct spd_route **srp, + connection_t **erop, struct spd_route **esrp) { - struct connection *d + connection_t *d , *best_ro = c , *best_ero = c; struct spd_route *srd, *src; @@ -3076,11 +3093,17 @@ route_owner(struct connection *c 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) { @@ -3090,11 +3113,17 @@ route_owner(struct connection *c } 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; @@ -3123,7 +3152,7 @@ route_owner(struct connection *c , (fmt_conn_instance(best_ro, cib), cib) , enum_name(&routing_story, best_ro->spd.routing)); - if (erop != NULL) + if (erop) { m = builddiag("%s; eroute owner:", m); if (!erouted(best_ero->spd.routing)) @@ -3140,14 +3169,17 @@ route_owner(struct connection *c DBG_log("%s", m); }); - if (erop != NULL) + if (erop) + { *erop = erouted(best_erouting)? best_ero : NULL; - - if (srp != NULL ) + } + if (srp) { *srp = best_sr; - if (esrp != NULL ) + if (esrp) + { *esrp = best_esr; + } } return routed(best_routing)? best_ro : NULL; @@ -3157,10 +3189,9 @@ route_owner(struct connection *c * There ought to be only one. * This might get to be a bottleneck -- try hashing if it does. */ -struct connection * -shunt_owner(const ip_subnet *ours, const ip_subnet *his) +connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his) { - struct connection *c; + connection_t *c; struct spd_route *sr; for (c = connections; c != NULL; c = c->ac_next) @@ -3180,11 +3211,11 @@ shunt_owner(const ip_subnet *ours, const ip_subnet *his) * We don't know enough to chose amongst those available. * ??? no longer usefully different from find_host_pair_connections */ -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) +connection_t *find_host_connection(const ip_address *me, u_int16_t my_port, + const ip_address *him, u_int16_t his_port, + lset_t policy) { - struct connection *c = find_host_pair_connections(me, my_port, him, his_port); + connection_t *c = find_host_pair_connections(me, my_port, him, his_port); if (policy != LEMPTY) { @@ -3193,7 +3224,7 @@ find_host_connection(const ip_address *me, u_int16_t my_port /* if we have requirements for the policy, * choose the first matching connection. */ - while (c != NULL) + while (c) { if (c->policy & auth_requested) { @@ -3266,25 +3297,25 @@ find_host_connection(const ip_address *me, u_int16_t my_port */ #define PRIO_NO_MATCH_FOUND 2048 -struct connection * -refine_host_connection(const struct state *st, const struct id *peer_id -, chunk_t peer_ca) +connection_t *refine_host_connection(const struct state *st, + identification_t *peer_id, + identification_t *peer_ca) { - struct connection *c = st->st_connection; - struct connection *d; - struct connection *best_found = NULL; + connection_t *c = st->st_connection; + connection_t *d; + connection_t *best_found = NULL; u_int16_t auth = st->st_oakley.auth; lset_t auth_policy = POLICY_PSK; const chunk_t *psk = NULL; bool wcpip; /* wildcard Peer IP? */ int best_prio = PRIO_NO_MATCH_FOUND; - int wildcards, our_pathlen, peer_pathlen; + int 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) + if (c->spd.that.id->equals(c->spd.that.id, peer_id) && + trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen) && + peer_pathlen == 0 && + match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen) && + our_pathlen == 0) { DBG(DBG_CONTROL, DBG_log("current connection is a full match" @@ -3345,8 +3376,10 @@ refine_host_connection(const struct state *st, const struct id *peer_id { const char *match_name[] = {"no", "ok"}; - bool matching_id = match_id(peer_id - , &d->spd.that.id, &wildcards); + id_match_t match_level = peer_id->matches(peer_id, d->spd.that.id); + + bool matching_id = match_level > ID_MATCH_NONE; + bool matching_auth = (d->policy & auth_policy) != LEMPTY; bool matching_trust = trusted_ca(peer_ca @@ -3355,10 +3388,11 @@ refine_host_connection(const struct state *st, const struct id *peer_id , d->spd.this.ca, &our_pathlen); bool match = matching_id && matching_auth && matching_trust; - int prio = (MAX_WILDCARDS + 1) * !matching_request + wildcards; + int prio = (ID_MATCH_PERFECT) * !matching_request + + ID_MATCH_PERFECT - match_level; - prio = (MAX_CA_PATH_LEN + 1) * prio + peer_pathlen; - prio = (MAX_CA_PATH_LEN + 1) * prio + our_pathlen; + prio = (X509_MAX_PATH_LEN + 1) * prio + peer_pathlen; + prio = (X509_MAX_PATH_LEN + 1) * prio + our_pathlen; DBG(DBG_CONTROLMORE, DBG_log("%s: %s match (id: %s, auth: %s, trust: %s, request: %s, prio: %4d)" @@ -3373,11 +3407,15 @@ refine_host_connection(const struct state *st, const struct id *peer_id /* 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) @@ -3395,12 +3433,17 @@ refine_host_connection(const struct state *st, const struct id *peer_id 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; @@ -3415,7 +3458,9 @@ refine_host_connection(const struct state *st, const struct id *peer_id .*/ if (d->spd.this.sc == NULL /* no smartcard */ && get_private_key(d) == NULL) /* no private key */ + { continue; + } break; default: @@ -3456,10 +3501,10 @@ refine_host_connection(const struct state *st, const struct id *peer_id * With virtual addressing, we must not allow someone to use an already * used (by another id) addr/net. */ -static bool -is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id) +static bool is_virtual_net_used(const ip_subnet *peer_net, + identification_t *peer_id) { - struct connection *d; + connection_t *d; for (d = connections; d != NULL; d = d->ac_next) { @@ -3469,16 +3514,15 @@ is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id) 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)) + && !d->spd.that.id->equals(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); + plog("Virtual IP %s is already used by '%Y'", + client, d->spd.that.id); + plog("Your ID is '%Y'", peer_id); + return TRUE; /* already used by another one */ } break; @@ -3516,27 +3560,27 @@ is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id) */ #define PATH_WEIGHT 1 -#define WILD_WEIGHT (MAX_CA_PATH_LEN+1) -#define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT +#define WILD_WEIGHT (X509_MAX_PATH_LEN+1) +#define PRIO_WEIGHT (ID_MATCH_PERFECT+1) * WILD_WEIGHT /* fc_try: a helper function for find_client_connection */ -static struct connection * -fc_try(const struct connection *c -, struct host_pair *hp -, const struct id *peer_id -, const ip_subnet *our_net -, const ip_subnet *peer_net -, const u_int8_t our_protocol -, const u_int16_t our_port -, const u_int8_t peer_protocol -, const u_int16_t peer_port -, chunk_t peer_ca -, const ietfAttrList_t *peer_list) +static connection_t *fc_try(const connection_t *c, struct host_pair *hp, + identification_t *peer_id, + const ip_subnet *our_net, + const ip_subnet *peer_net, + const u_int8_t our_protocol, + const u_int16_t our_port, + const u_int8_t peer_protocol, + const u_int16_t peer_port, + identification_t *peer_ca, + ietf_attributes_t *peer_attributes) { - struct connection *d; - struct connection *best = NULL; + connection_t *d; + connection_t *best = NULL; policy_prio_t best_prio = BOTTOM_PRIO; - int wildcards, pathlen; + id_match_t match_level; + int pathlen; + const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr); @@ -3545,20 +3589,28 @@ fc_try(const struct connection *c struct spd_route *sr; 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))) + match_level = c->spd.that.id->matches(c->spd.that.id, d->spd.that.id); + + if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && + (match_level > ID_MATCH_NONE) && + trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && + match_group_membership(peer_attributes, d->name, d->spd.that.groups))) + { continue; + } /* compare protocol and ports */ if (d->spd.this.protocol != our_protocol || d->spd.this.port != our_port || d->spd.that.protocol != peer_protocol || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) + { continue; + } /* non-Opportunistic case: * our_client must match. @@ -3595,29 +3647,38 @@ fc_try(const struct connection *c #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; + || 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: @@ -3629,8 +3690,8 @@ fc_try(const struct connection *c * - 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) + + WILD_WEIGHT * match_level + + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen) + 1; if (prio > best_prio) { @@ -3640,9 +3701,10 @@ fc_try(const struct connection *c } } - if (best != NULL && NEVER_NEGOTIATE(best->policy)) + if (best && NEVER_NEGOTIATE(best->policy)) + { best = NULL; - + } DBG(DBG_CONTROLMORE, DBG_log(" fc_try concluding with %s [%ld]" , (best ? best->name : "none"), best_prio) @@ -3650,22 +3712,22 @@ fc_try(const struct connection *c return best; } -static struct connection * -fc_try_oppo(const struct connection *c -, struct host_pair *hp -, const ip_subnet *our_net -, const ip_subnet *peer_net -, const u_int8_t our_protocol -, const u_int16_t our_port -, const u_int8_t peer_protocol -, const u_int16_t peer_port -, chunk_t peer_ca -, const ietfAttrList_t *peer_list) +static connection_t *fc_try_oppo(const connection_t *c, + struct host_pair *hp, + const ip_subnet *our_net, + const ip_subnet *peer_net, + const u_int8_t our_protocol, + const u_int16_t our_port, + const u_int8_t peer_protocol, + const u_int16_t peer_port, + identification_t *peer_ca, + ietf_attributes_t *peer_attributes) { - struct connection *d; - struct connection *best = NULL; + connection_t *d; + connection_t *best = NULL; policy_prio_t best_prio = BOTTOM_PRIO; - int wildcards, pathlen; + id_match_t match_level; + int pathlen; for (d = hp->connections; d != NULL; d = d->hp_next) { @@ -3673,20 +3735,27 @@ fc_try_oppo(const struct connection *c policy_prio_t prio; if (d->policy & POLICY_GROUP) + { continue; + } + match_level = c->spd.that.id->matches(c->spd.that.id, c->spd.that.id); - if (!(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))) + if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && + (match_level > ID_MATCH_NONE) && + trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && + match_group_membership(peer_attributes, d->name, d->spd.that.groups))) + { continue; + } /* compare protocol and ports */ if (d->spd.this.protocol != our_protocol || d->spd.this.port != our_port || d->spd.that.protocol != peer_protocol || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) + { continue; + } /* Opportunistic case: * our_net must be inside d->spd.this.client @@ -3714,7 +3783,9 @@ fc_try_oppo(const struct connection *c 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. @@ -3725,8 +3796,8 @@ fc_try_oppo(const struct connection *c * - 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); + + WILD_WEIGHT * match_level + + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen); if (prio > best_prio) { best = d; @@ -3736,9 +3807,8 @@ fc_try_oppo(const struct connection *c } /* 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)) + if (best && (NEVER_NEGOTIATE(best->policy) || + (best->policy & POLICY_OPPO) == LEMPTY)) { best = NULL; } @@ -3754,44 +3824,52 @@ fc_try_oppo(const struct connection *c /* * get the peer's CA and group attributes */ -chunk_t -get_peer_ca_and_groups(struct connection *c, const ietfAttrList_t **peer_list) +void get_peer_ca_and_groups(connection_t *c, + identification_t **peer_ca, + ietf_attributes_t **peer_attributes) { - struct state *p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); + struct state *p1st; - *peer_list = NULL; + *peer_ca = NULL; + *peer_attributes = NULL; - if (p1st != NULL - && p1st->st_peer_pubkey != NULL - && p1st->st_peer_pubkey->issuer.ptr != NULL) + p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); + if (p1st && p1st->st_peer_pubkey && p1st->st_peer_pubkey->issuer) { - x509acert_t *ac = get_x509acert(p1st->st_peer_pubkey->issuer - , p1st->st_peer_pubkey->serial);; + certificate_t *cert; - if (ac != NULL && verify_x509acert(ac, strict_crl_policy)) - *peer_list = ac->groups; + cert = ac_get_cert(p1st->st_peer_pubkey->issuer, + p1st->st_peer_pubkey->serial); + if (cert && ac_verify_cert(cert, strict_crl_policy)) + { + ac_t *ac = (ac_t*)cert; + + *peer_attributes = ac->get_groups(ac); + } else { DBG(DBG_CONTROL, DBG_log("no valid attribute cert found") ) } - return p1st->st_peer_pubkey->issuer; + *peer_ca = p1st->st_peer_pubkey->issuer; } - return chunk_empty; } -struct connection * -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 our_port -, const u_int8_t peer_protocol, const u_int16_t peer_port) +connection_t *find_client_connection(connection_t *c, + const ip_subnet *our_net, + const ip_subnet *peer_net, + const u_int8_t our_protocol, + const u_int16_t our_port, + const u_int8_t peer_protocol, + const u_int16_t peer_port) { - struct connection *d; + connection_t *d; struct spd_route *sr; + ietf_attributes_t *peer_attributes = NULL; + identification_t *peer_ca; - const ietfAttrList_t *peer_list = NULL; - chunk_t peer_ca = get_peer_ca_and_groups(c, &peer_list); + get_peer_ca_and_groups(c, &peer_ca, &peer_attributes); #ifdef DEBUG if (DBGP(DBG_CONTROLMORE)) @@ -3813,7 +3891,7 @@ find_client_connection(struct connection *c * but even greater priority to a routed concrete connection */ { - struct connection *unrouted = NULL; + connection_t *unrouted = NULL; int srnum = -1; for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next) @@ -3838,12 +3916,14 @@ find_client_connection(struct connection *c && sr->this.port == our_port && sr->that.protocol == peer_protocol && sr->that.port == peer_port - && group_membership(peer_list, c->name, sr->that.groups)) + && match_group_membership(peer_attributes, c->name, sr->that.groups)) { passert(oriented(*c)); if (routed(sr->routing)) + { + DESTROY_IF(peer_attributes); return c; - + } unrouted = c; } } @@ -3851,7 +3931,7 @@ find_client_connection(struct connection *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); + , peer_ca, peer_attributes); DBG(DBG_CONTROLMORE, DBG_log(" fc_try %s gives %s" @@ -3860,7 +3940,9 @@ find_client_connection(struct connection *c ) if (d == NULL) + { d = unrouted; + } } if (d == NULL) @@ -3890,12 +3972,12 @@ find_client_connection(struct connection *c #endif /* DEBUG */ } - if (hp != NULL) + if (hp) { /* RW match with actual peer_id or abstract peer_id? */ d = fc_try(c, hp, NULL, our_net, peer_net , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_list); + , peer_ca, peer_attributes); if (d == NULL && subnetishost(our_net) @@ -3907,7 +3989,7 @@ find_client_connection(struct connection *c */ d = fc_try_oppo(c, hp, our_net, peer_net , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_list); + , peer_ca, peer_attributes); } } } @@ -3916,24 +3998,27 @@ find_client_connection(struct connection *c DBG_log(" concluding with d = %s" , (d ? d->name : "none")) ) + DESTROY_IF(peer_attributes); return d; } -int -connection_compare(const struct connection *ca -, const struct connection *cb) +int connection_compare(const connection_t *ca, const connection_t *cb) { int ret; /* DBG_log("comparing %s to %s", ca->name, cb->name); */ ret = strcasecmp(ca->name, cb->name); - if (ret != 0) + if (ret) + { return ret; + } ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */ - if (ret != 0) + if (ret) + { return ret; + } /* same name, and same type */ switch (ca->kind) @@ -3950,19 +4035,17 @@ connection_compare(const struct connection *ca } } -static int -connection_compare_qsort(const void *a, const void *b) +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 connection_t *const *)a + , *(const connection_t *const *)b); } -void -show_connections_status(bool all, const char *name) +void show_connections_status(bool all, const char *name) { - struct connection *c; + connection_t *c; int count, i; - struct connection **array; + connection_t **array; /* make an array of connections, and sort it */ count = 0; @@ -3971,7 +4054,7 @@ show_connections_status(bool all, const char *name) if (c->ikev1 && (name == NULL || streq(c->name, name))) count++; } - array = malloc(sizeof(struct connection *)*count); + array = malloc(sizeof(connection_t *)*count); count=0; for (c = connections; c != NULL; c = c->ac_next) @@ -3981,7 +4064,7 @@ show_connections_status(bool all, const char *name) } /* sort it! */ - qsort(array, count, sizeof(struct connection *), connection_compare_qsort); + qsort(array, count, sizeof(connection_t *), connection_compare_qsort); for (i = 0; i < count; i++) { @@ -3999,11 +4082,11 @@ show_connections_status(bool all, const char *name) /* show topology */ { - char topo[CONNECTION_BUF]; + char topo[BUF_LEN]; struct spd_route *sr = &c->spd; int num=0; - while (sr != NULL) + while (sr) { (void) format_connection(topo, sizeof(topo), c, sr); whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu" @@ -4018,32 +4101,30 @@ show_connections_status(bool all, const char *name) if (all) { /* show CAs if defined */ - if (c->spd.this.ca.ptr != NULL || c->spd.that.ca.ptr != NULL) + if (c->spd.this.ca && c->spd.that.ca) { - 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: \"%Y\"...\"%Y\"", + c->name, instance, c->spd.this.ca, c->spd.that.ca); + } + else if (c->spd.this.ca) + { + whack_log(RC_COMMENT, "\"%s\"%s: CAs: \"%Y\"...%%any", + c->name, instance, c->spd.this.ca); - whack_log(RC_COMMENT - , "\"%s\"%s: CAs: '%s'...'%s'" - , c->name - , instance - , this_ca - , that_ca); + } + else if (c->spd.that.ca) + { + whack_log(RC_COMMENT, "\"%s\"%s: CAs: %%any...\"%Y\"", + c->name, instance, c->spd.that.ca); } /* show group attributes if defined */ - if (c->spd.that.groups != NULL) + if (c->spd.that.groups) { - char buf[BUF_LEN]; - - format_groups(c->spd.that.groups, buf, BUF_LEN); - whack_log(RC_COMMENT - , "\"%s\"%s: groups: %s" + whack_log(RC_COMMENT, "\"%s\"%s: groups: %s" , c->name , instance - , buf); + , c->spd.that.groups->get_string(c->spd.that.groups)); } whack_log(RC_COMMENT @@ -4058,7 +4139,7 @@ show_connections_status(bool all, const char *name) , (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;" @@ -4095,7 +4176,7 @@ show_connections_status(bool all, const char *name) , instance , c->newest_isakmp_sa , c->newest_ipsec_sa); - + if (all) { ike_alg_show_connection(c, instance); @@ -4116,7 +4197,7 @@ show_connections_status(bool all, const char *name) struct pending { int whack_sock; struct state *isakmp_sa; - struct connection *connection; + connection_t *connection; lset_t policy; unsigned long try; so_serial_t replacing; @@ -4125,18 +4206,13 @@ struct pending { }; /* queue a Quick Mode negotiation pending completion of a suitable Main Mode */ -void -add_pending(int whack_sock -, struct state *isakmp_sa -, struct connection *c -, lset_t policy -, unsigned long try -, so_serial_t replacing) +void add_pending(int whack_sock, struct state *isakmp_sa, connection_t *c, + lset_t policy, unsigned long try, so_serial_t replacing) { bool already_queued = FALSE; struct pending *p = c->host_pair->pending; - while (p != NULL) + while (p) { if (streq(c->name, p->connection->name)) { @@ -4169,8 +4245,7 @@ add_pending(int whack_sock * This is accomplished by closing all the whack socket file descriptors. * We go to a lot of trouble to tell each whack, but to not tell it twice. */ -void -release_pending_whacks(struct state *st, err_t story) +void release_pending_whacks(struct state *st, err_t story) { struct pending *p; struct stat stst; @@ -4202,20 +4277,20 @@ release_pending_whacks(struct state *st, err_t story) } } -static void -delete_pending(struct pending **pp) +static void delete_pending(struct pending **pp) { struct pending *p = *pp; *pp = p->next; - if (p->connection != NULL) + if (p->connection) + { connection_discard(p->connection); + } close_any(p->whack_sock); free(p); } -void -unpend(struct state *st) +void unpend(struct state *st) { struct pending **pp , *p; @@ -4241,8 +4316,7 @@ unpend(struct state *st) } /* a Main Mode negotiation has been replaced; update any pending */ -void -update_pending(struct state *os, struct state *ns) +void update_pending(struct state *os, struct state *ns) { struct pending *p; @@ -4259,12 +4333,11 @@ update_pending(struct state *os, struct state *ns) } /* a Main Mode negotiation has failed; discard any pending */ -void -flush_pending_by_state(struct state *st) +void flush_pending_by_state(struct state *st) { struct host_pair *hp = st->st_connection->host_pair; - if (hp != NULL) + if (hp) { struct pending **pp , *p; @@ -4280,10 +4353,9 @@ flush_pending_by_state(struct state *st) } /* a connection has been deleted; discard any related pending */ -static void -flush_pending_by_connection(struct connection *c) +static void flush_pending_by_connection(connection_t *c) { - if (c->host_pair != NULL) + if (c->host_pair) { struct pending **pp , *p; @@ -4303,8 +4375,7 @@ flush_pending_by_connection(struct connection *c) } } -void -show_pending_phase2(const struct host_pair *hp, const struct state *st) +void show_pending_phase2(const struct host_pair *hp, const struct state *st) { const struct pending *p; @@ -4329,8 +4400,7 @@ show_pending_phase2(const struct host_pair *hp, const struct state *st) * We must be careful to avoid circularity: * we don't touch it if it is CK_GOING_AWAY. */ -void -connection_discard(struct connection *c) +void connection_discard(connection_t *c) { if (c->kind == CK_INSTANCE) { @@ -4354,28 +4424,26 @@ connection_discard(struct connection *c) long eclipse_count = 0; -struct connection * -eclipsed(struct connection *c, struct spd_route **esrp) +connection_t *eclipsed(connection_t *c, struct spd_route **esrp) { - struct connection *ue; + connection_t *ue; struct spd_route *sr1 = &c->spd; ue = NULL; - while (sr1 != NULL && ue != NULL) + while (sr1 && ue) { for (ue = connections; ue != NULL; ue = ue->ac_next) { struct spd_route *srue = &ue->spd; - while (srue != NULL - && srue->routing == RT_ROUTED_ECLIPSED + while (srue && srue->routing == RT_ROUTED_ECLIPSED && !(samesubnet(&sr1->this.client, &srue->this.client) && samesubnet(&sr1->that.client, &srue->that.client))) { srue = srue->next; } - if (srue != NULL && srue->routing==RT_ROUTED_ECLIPSED) + if (srue && srue->routing == RT_ROUTED_ECLIPSED) { *esrp = srue; break; diff --git a/src/pluto/connections.h b/src/pluto/connections.h index 16cbbfd72..ee2e00da6 100644 --- a/src/pluto/connections.h +++ b/src/pluto/connections.h @@ -1,5 +1,6 @@ /* information about connections between hosts and clients * 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 @@ -17,9 +18,11 @@ #include <sys/queue.h> -#include "id.h" +#include <utils/linked_list.h> +#include <utils/identification.h> +#include <credentials/ietf_attributes/ietf_attributes.h> + #include "certs.h" -#include "ac.h" #include "smartcard.h" #include "whack.h" @@ -127,7 +130,7 @@ extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]); struct virtual_t; struct end { - struct id id; + identification_t *id; ip_address host_addr, host_nexthop, @@ -144,13 +147,14 @@ struct end { 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 */ + cert_t *cert; /* end certificate */ + identification_t *ca; /* CA distinguished name */ + ietf_attributes_t *groups; /* access control groups */ smartcard_t *sc; /* smartcard reader and key info */ struct virtual_t *virt; bool modecfg; /* this end: request local address from server */ /* that end: give local addresses to clients */ + char *pool; /* name of an associated virtual IP address pool */ bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */ /* rules if client behind host is a subnet */ bool allow_any; /* IP address is subject to change */ @@ -166,6 +170,8 @@ struct spd_route { uint32_t reqid; }; +typedef struct connection connection_t; + struct connection { char *name; bool ikev1; @@ -182,10 +188,10 @@ struct connection { time_t dpd_timeout; dpd_action_t dpd_action; - char *log_file_name; /* name of log file */ - FILE *log_file; /* possibly open FILE */ + 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 */ + bool log_file_err; /* only bitch once */ struct spd_route spd; @@ -210,119 +216,110 @@ struct connection { sa_family_t addr_family; /* between gateways */ sa_family_t tunnel_addr_family; /* between clients */ - struct connection *policy_next; /* if multiple policies, + connection_t *policy_next; /* if multiple policies, next one to apply */ - struct gw_info *gw_info; struct alg_info_esp *alg_info_esp; struct alg_info_ike *alg_info_ike; - struct host_pair *host_pair; - struct connection *hp_next; /* host pair list link */ - - struct connection *ac_next; /* all connections list link */ - - generalName_t *requested_ca; /* collected certificate requests */ + connection_t *hp_next; /* host pair list link */ + connection_t *ac_next; /* all connections list link */ + linked_list_t *requested_ca; /* collected certificate requests */ bool got_certrequest; }; #define oriented(c) ((c).interface != NULL) -extern bool orient(struct connection *c); +extern bool orient(connection_t *c); -extern bool same_peer_ids(const struct connection *c - , const struct connection *d, const struct id *his_id); +extern bool same_peer_ids(const connection_t *c, const connection_t *d, + identification_t *his_id); /* Format the topology of a connection end, leaving out defaults. * Largest left end looks like: client === host : port [ host_id ] --- hop * Note: if that==NULL, skip nexthop */ #define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10) -extern size_t format_end(char *buf, size_t buf_len - , const struct end *this, const struct end *that - , bool is_left, lset_t policy); +extern size_t format_end(char *buf, size_t buf_len, const struct end *this, + const struct end *that, bool is_left, lset_t policy); extern void add_connection(const whack_message_t *wm); extern void initiate_connection(const char *name, int whackfd); -extern void initiate_opportunistic(const ip_address *our_client - , const ip_address *peer_client, int transport_proto, bool held, int whackfd); +extern void initiate_opportunistic(const ip_address *our_client, + const ip_address *peer_client, + int transport_proto, bool held, int whackfd); extern void terminate_connection(const char *nm); -extern void release_connection(struct connection *c, bool relations); -extern void delete_connection(struct connection *c, bool relations); +extern void release_connection(connection_t *c, bool relations); +extern void delete_connection(connection_t *c, bool relations); extern void delete_connections_by_name(const char *name, bool strict); extern void delete_every_connection(void); -extern char *add_group_instance(struct connection *group, const ip_subnet *target); -extern void remove_group_instance(const struct connection *group, const char *name); +extern char *add_group_instance(connection_t *group, const ip_subnet *target); +extern void remove_group_instance(const connection_t *group, const char *name); extern void release_dead_interfaces(void); extern void check_orientations(void); -extern struct connection *route_owner(struct connection *c - , struct spd_route **srp - , struct connection **erop - , struct spd_route **esrp); -extern struct connection *shunt_owner(const ip_subnet *ours - , const ip_subnet *his); +extern connection_t *route_owner(connection_t *c, struct spd_route **srp, + connection_t **erop, struct spd_route **esrp); +extern connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his); extern bool uniqueIDs; /* --uniqueids? */ -extern void ISAKMP_SA_established(struct connection *c, so_serial_t serial); +extern void ISAKMP_SA_established(connection_t *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)) +#define id_is_ipaddr(id) ((id)->get_type(id) == ID_IPV4_ADDR || \ + (id)->get_type(id) == ID_IPV6_ADDR) +extern bool his_id_was_instantiated(const connection_t *c); struct state; /* forward declaration of tag (defined in state.h) */ -extern 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); - -extern struct connection * -find_connection_for_clients(struct spd_route **srp - , 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); - + +extern connection_t* con_by_name(const char *nm, bool strict); +extern connection_t* find_host_connection(const ip_address *me, + u_int16_t my_port, + const ip_address *him, + u_int16_t his_port, lset_t policy); +extern connection_t* refine_host_connection(const struct state *st, + identification_t *id, + identification_t *peer_ca); +extern connection_t* find_client_connection(connection_t *c, + const ip_subnet *our_net, + const ip_subnet *peer_net, + const u_int8_t our_protocol, + const u_int16_t out_port, + const u_int8_t peer_protocol, + const u_int16_t peer_port); +extern connection_t* find_connection_by_reqid(uint32_t reqid); +extern connection_t* find_connection_for_clients(struct spd_route **srp, + const ip_address *our_client, + const ip_address *peer_client, + int transport_proto); +extern void get_peer_ca_and_groups(connection_t *c, + identification_t **peer_ca, + ietf_attributes_t **peer_attributes); + /* instantiating routines * Note: connection_discard() is in state.h because all its work * is looking through state objects. */ struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ struct alg_info; /* forward declaration of tag (defined in alg_info.h) */ -extern 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); - -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); - -extern struct connection - *build_outgoing_opportunistic_connection(struct gw_info *gw - , 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) - -extern void fmt_conn_instance(const struct connection *c - , char buf[CONN_INST_BUF]); +extern connection_t *rw_instantiate(connection_t *c, + const ip_address *him, + u_int16_t his_port, + const ip_subnet *his_net, + identification_t *his_id); + +extern connection_t *oppo_instantiate(connection_t *c, + const ip_address *him, + identification_t *his_id, + struct gw_info *gw, + const ip_address *our_client, + const ip_address *peer_client); + +extern connection_t + *build_outgoing_opportunistic_connection(struct gw_info *gw, + const ip_address *our_client, + const ip_address *peer_client); + +#define CONN_INST_BUF BUF_LEN + +extern void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]); /* operations on "pending", the structure representing Quick Mode * negotiations delayed until a Keying Channel has been negotiated. @@ -330,12 +327,9 @@ extern void fmt_conn_instance(const struct connection *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); +extern void add_pending(int whack_sock, struct state *isakmp_sa, + connection_t *c, lset_t policy, unsigned long try, + so_serial_t replacing); extern void release_pending_whacks(struct state *st, err_t story); extern void unpend(struct state *st); @@ -343,7 +337,7 @@ extern void update_pending(struct state *os, struct state *ns); extern void flush_pending_by_state(struct state *st); extern void show_pending_phase2(const struct host_pair *hp, const struct state *st); -extern void connection_discard(struct connection *c); +extern void connection_discard(connection_t *c); /* A template connection's eroute can be eclipsed by * either a %hold or an eroute for an instance iff @@ -351,15 +345,15 @@ extern void connection_discard(struct connection *c); */ #define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client)) extern long eclipse_count; -extern struct connection *eclipsed(struct connection *c, struct spd_route **); +extern connection_t *eclipsed(connection_t *c, struct spd_route **); /* print connection status */ extern void show_connections_status(bool all, const char *name); -extern int connection_compare(const struct connection *ca - , const struct connection *cb); -extern void update_host_pair(const char *why, struct connection *c +extern int connection_compare(const connection_t *ca + , const connection_t *cb); +extern void update_host_pair(const char *why, connection_t *c , const ip_address *myaddr, u_int16_t myport , const ip_address *hisaddr, u_int16_t hisport); diff --git a/src/pluto/constants.c b/src/pluto/constants.c index e46728d84..6f991fd69 100644 --- a/src/pluto/constants.c +++ b/src/pluto/constants.c @@ -25,6 +25,8 @@ #include <freeswan.h> +#include <attributes/attributes.h> + #include "constants.h" #include "defs.h" #include "log.h" @@ -61,20 +63,6 @@ enum_names version_names = ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, version_name, NULL }; -/* RFC 2459 CRL reason codes */ - -ENUM(crl_reason_names, REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, - "unspecified", - "key compromise", - "ca compromise", - "affiliation changed", - "superseded", - "cessation of operation", - "certificate hold", - "reason #7", - "remove from crl" -); - /* RFC 3706 Dead Peer Detection */ ENUM(dpd_action_names, DPD_ACTION_NONE, DPD_ACTION_RESTART, @@ -82,8 +70,8 @@ ENUM(dpd_action_names, DPD_ACTION_NONE, DPD_ACTION_RESTART, "clear", "hold", "restart" -); - +); + /* Timer events */ ENUM(timer_event_names, EVENT_NULL, EVENT_LOG_DAILY, @@ -288,7 +276,7 @@ const char *const payload_name_nat_d[] = { static enum_names payload_names_nat_d = { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL }; - + enum_names payload_names = { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d }; @@ -364,11 +352,21 @@ static const char *const ah_transform_name[] = { "HMAC_SHA2_512", "HMAC_RIPEMD", "AES_XCBC_96", - "SIG_RSA" + "SIG_RSA", + "AES_128_GMAC", + "AES_192_GMAC", + "AES_256_GMAC" +}; + +static const char *const ah_transform_name_high[] = { + "HMAC_SHA2_256_96" }; -enum_names ah_transformid_names = - { AH_MD5, AH_RSA, ah_transform_name, NULL }; +enum_names ah_transform_names_high = + { AH_SHA2_256_96, AH_SHA2_256_96, ah_transform_name_high, NULL }; + +enum_names ah_transform_names = + { AH_MD5, AH_AES_256_GMAC, ah_transform_name, &ah_transform_names_high }; /* IPsec ESP transform values */ @@ -402,11 +400,11 @@ static const char *const esp_transform_name_high[] = { "TWOFISH_CBC" }; -enum_names esp_transformid_names_high = +enum_names esp_transform_names_high = { 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 }; +enum_names esp_transform_names = + { ESP_DES_IV64, ESP_CAMELLIA, esp_transform_name, &esp_transform_names_high }; /* IPCOMP transform values */ @@ -677,15 +675,17 @@ static const char *const auth_alg_name[] = { }; static const char *const extended_auth_alg_name[] = { - "NULL" - }; + "NULL", + "HMAC_SHA2_256_96" +}; enum_names extended_auth_alg_names = - { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_NULL, extended_auth_alg_name, NULL }; + { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_HMAC_SHA2_256_96, + extended_auth_alg_name, NULL }; enum_names auth_alg_names = - { AUTH_ALGORITHM_NONE, AUTH_ALGORITHM_SIG_RSA, auth_alg_name - , &extended_auth_alg_names }; + { AUTH_ALGORITHM_NONE, AUTH_ALGORITHM_SIG_RSA, + auth_alg_name, &extended_auth_alg_names }; /* From draft-beaulieu-ike-xauth */ static const char *const xauth_type_name[] = { @@ -859,7 +859,7 @@ static const char *const oakley_auth_name1[] = { "ECDSA signature", "ECDSA-256 signature", "ECDSA-384 signature", - "ECDSA-521-signature", + "ECDSA-521-signature", }; static const char *const oakley_auth_name2[] = { @@ -936,7 +936,7 @@ enum_names oakley_group_names_rfc3526 = oakley_group_name_rfc3526, &oakley_group_names_rfc4753 }; enum_names oakley_group_names = - { MODP_768_BIT, MODP_1536_BIT, + { MODP_768_BIT, MODP_1536_BIT, oakley_group_name, &oakley_group_names_rfc3526 }; /* Oakley Group Type attribute */ @@ -1000,20 +1000,28 @@ static const char *const notification_dpd_name[] = { "R_U_THERE_ACK", }; +static const char *const notification_juniper_name[] = { + "NS_NHTB_INFORM", +}; + +enum_names notification_juniper_names = + { NS_NHTB_INFORM, NS_NHTB_INFORM, + notification_juniper_name, NULL }; + enum_names notification_dpd_names = { R_U_THERE, R_U_THERE_ACK, - notification_dpd_name, NULL }; + notification_dpd_name, ¬ification_juniper_names }; enum_names ipsec_notification_names = { IPSEC_RESPONDER_LIFETIME, IPSEC_INITIAL_CONTACT, ipsec_notification_name, ¬ification_dpd_names }; enum_names notification_status_names = - { CONNECTED, CONNECTED, + { ISAKMP_CONNECTED, ISAKMP_CONNECTED, notification_status_name, &ipsec_notification_names }; enum_names notification_names = - { INVALID_PAYLOAD_TYPE, UNEQUAL_PAYLOAD_LENGTHS, + { ISAKMP_INVALID_PAYLOAD_TYPE, ISAKMP_UNEQUAL_PAYLOAD_LENGTHS, notification_name, ¬ification_status_names }; /* MODECFG @@ -1167,7 +1175,7 @@ const char *const natt_type_bitnames[] = { "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", + "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", @@ -1210,8 +1218,8 @@ enum_show(enum_names *ed, unsigned long val) static char bitnamesbuf[200]; /* only one! I hope that it is big enough! */ -int -enum_search(enum_names *ed, const char *str) +int +enum_search(enum_names *ed, const char *str) { enum_names *p; const char *ptr; diff --git a/src/pluto/constants.h b/src/pluto/constants.h index 5fe936e08..8c574ebc5 100644 --- a/src/pluto/constants.h +++ b/src/pluto/constants.h @@ -16,6 +16,8 @@ #ifndef _CONSTANTS_H #define _CONSTANTS_H +#include <freeswan.h> + #include <utils.h> #include <utils/identification.h> #include <crypto/hashers/hasher.h> @@ -135,19 +137,23 @@ extern const char sparse_end[]; * and in http://www.iana.org/assignments/isakmp-registry */ enum ipsec_authentication_algo { - AH_NONE = 0, - AH_MD5 = 2, - AH_SHA = 3, - AH_DES = 4, - AH_SHA2_256 = 5, - AH_SHA2_384 = 6, - AH_SHA2_512 = 7, - AH_RIPEMD = 8, - AH_AES_XCBC_MAC = 9, - AH_RSA = 10 + AH_NONE = 0, + AH_MD5 = 2, + AH_SHA = 3, + AH_DES = 4, + AH_SHA2_256 = 5, + AH_SHA2_384 = 6, + AH_SHA2_512 = 7, + AH_RIPEMD = 8, + AH_AES_XCBC_MAC = 9, + AH_RSA = 10, + AH_AES_128_GMAC = 11, + AH_AES_192_GMAC = 12, + AH_AES_256_GMAC = 13, + AH_SHA2_256_96 = 252 }; -extern enum_names ah_transformid_names; +extern enum_names ah_transform_names; /* IPsec ESP transform values * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4 @@ -155,45 +161,45 @@ extern enum_names ah_transformid_names; */ 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 + 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; +extern enum_names esp_transform_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 + IPSCOMP_NONE = 0, + IPCOMP_OUI = 1, + IPCOMP_DEFLATE = 2, + IPCOMP_LZS = 3, + IPCOMP_LZJH = 4 }; extern enum_names ipcomp_transformid_names; @@ -202,18 +208,18 @@ extern enum_names ipcomp_transformid_names; * 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 + 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 */ @@ -225,21 +231,6 @@ typedef enum { CERT_UNDEFINED = 3 } cert_status_t; -/* RFC 2459 CRL reason codes */ - -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 -} crl_reason_t; - /* RFC 3706 Dead Peer Detection */ extern enum_name_t *dpd_action_names; @@ -549,24 +540,6 @@ extern const char *const payload_name[]; extern enum_names attr_msg_type_names; -/* Mode Config attribute values */ -#define INTERNAL_IP4_ADDRESS 1 -#define INTERNAL_IP4_NETMASK 2 -#define INTERNAL_IP4_DNS 3 -#define INTERNAL_IP4_NBNS 4 -#define INTERNAL_ADDRESS_EXPIRY 5 -#define INTERNAL_IP4_DHCP 6 -#define APPLICATION_VERSION 7 -#define INTERNAL_IP6_ADDRESS 8 -#define INTERNAL_IP6_NETMASK 9 -#define INTERNAL_IP6_DNS 10 -#define INTERNAL_IP6_NBNS 11 -#define INTERNAL_IP6_DHCP 12 -#define INTERNAL_IP4_SUBNET 13 -#define SUPPORTED_ATTRIBUTES 14 -#define INTERNAL_IP6_SUBNET 15 - - extern enum_names modecfg_attr_names; /* XAUTH attribute values */ @@ -704,10 +677,10 @@ extern enum_name_t *cert_policy_names; typedef enum certpolicy { CERT_ALWAYS_SEND = 0, - CERT_SEND_IF_ASKED = 1, + CERT_SEND_IF_ASKED = 1, CERT_NEVER_SEND = 2, - CERT_YES_SEND = 3, /* synonym for CERT_ALWAYS_SEND */ + CERT_YES_SEND = 3, /* synonym for CERT_ALWAYS_SEND */ CERT_NO_SEND = 4 /* synonym for CERT_NEVER_SEND */ } certpolicy_t; @@ -883,18 +856,22 @@ 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_AES_128_GMAC 11 +#define AUTH_ALGORITHM_AES_192_GMAC 12 +#define AUTH_ALGORITHM_AES_256_GMAC 13 +#define AUTH_ALGORITHM_NULL 251 +#define AUTH_ALGORITHM_HMAC_SHA2_256_96 252 /* Oakley Lifetime Type attribute * draft-ietf-ipsec-ike-01.txt appendix A @@ -1026,52 +1003,55 @@ 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_NOTHING_WRONG = 0, /* unofficial! */ + + ISAKMP_INVALID_PAYLOAD_TYPE = 1, + ISAKMP_DOI_NOT_SUPPORTED = 2, + ISAKMP_SITUATION_NOT_SUPPORTED = 3, + ISAKMP_INVALID_COOKIE = 4, + ISAKMP_INVALID_MAJOR_VERSION = 5, + ISAKMP_INVALID_MINOR_VERSION = 6, + ISAKMP_INVALID_EXCHANGE_TYPE = 7, + ISAKMP_INVALID_FLAGS = 8, + ISAKMP_INVALID_MESSAGE_ID = 9, + ISAKMP_INVALID_PROTOCOL_ID = 10, + ISAKMP_INVALID_SPI = 11, + ISAKMP_INVALID_TRANSFORM_ID = 12, + ISAKMP_ATTRIBUTES_NOT_SUPPORTED = 13, + ISAKMP_NO_PROPOSAL_CHOSEN = 14, + ISAKMP_BAD_PROPOSAL_SYNTAX = 15, + ISAKMP_PAYLOAD_MALFORMED = 16, + ISAKMP_INVALID_KEY_INFORMATION = 17, + ISAKMP_INVALID_ID_INFORMATION = 18, + ISAKMP_INVALID_CERT_ENCODING = 19, + ISAKMP_INVALID_CERTIFICATE = 20, + ISAKMP_CERT_TYPE_UNSUPPORTED = 21, + ISAKMP_INVALID_CERT_AUTHORITY = 22, + ISAKMP_INVALID_HASH_INFORMATION = 23, + ISAKMP_AUTHENTICATION_FAILED = 24, + ISAKMP_INVALID_SIGNATURE = 25, + ISAKMP_ADDRESS_NOTIFICATION = 26, + ISAKMP_NOTIFY_SA_LIFETIME = 27, + ISAKMP_CERTIFICATE_UNAVAILABLE = 28, + ISAKMP_UNSUPPORTED_EXCHANGE_TYPE = 29, + ISAKMP_UNEQUAL_PAYLOAD_LENGTHS = 30, /* ISAKMP status type */ - CONNECTED = 16384, + ISAKMP_CONNECTED = 16384, /* IPSEC DOI additions; status types (RFC2407 IPSEC DOI 4.6.3) * These must be sent under the protection of an ISAKMP SA. */ - IPSEC_RESPONDER_LIFETIME = 24576, - IPSEC_REPLAY_STATUS = 24577, - IPSEC_INITIAL_CONTACT = 24578, + IPSEC_RESPONDER_LIFETIME = 24576, + IPSEC_REPLAY_STATUS = 24577, + IPSEC_INITIAL_CONTACT = 24578, /* RFC 3706 DPD */ - R_U_THERE = 36136, - R_U_THERE_ACK = 36137 + R_U_THERE = 36136, + R_U_THERE_ACK = 36137, + + /* Juniper SRX private use */ + NS_NHTB_INFORM = 40001 } notification_t; diff --git a/src/pluto/crl.c b/src/pluto/crl.c index c800f2acc..84fe77554 100644 --- a/src/pluto/crl.c +++ b/src/pluto/crl.c @@ -24,11 +24,6 @@ #include <freeswan.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <asn1/oid.h> -#include <crypto/hashers/hasher.h> - #include "constants.h" #include "defs.h" #include "log.h" @@ -39,145 +34,53 @@ #include "keys.h" #include "whack.h" #include "fetch.h" +#include "builder.h" /* chained lists of X.509 crls */ -static x509crl_t *x509crls = NULL; - -/** - * 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 */ - { 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_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 - -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 */ -}; +static x509crl_t *x509crls = NULL; /** * 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(identification_t *issuer, chunk_t keyid) { - x509crl_t *crl = x509crls; + x509crl_t *x509crl = x509crls; x509crl_t *prev_crl = NULL; - while (crl != NULL) + while (x509crl != NULL) { - if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL) - ? same_keyid(keyid, crl->authKeyID) - : (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber))) + certificate_t *cert_crl = x509crl->crl; + crl_t *crl = (crl_t*)cert_crl; + identification_t *crl_issuer = cert_crl->get_issuer(cert_crl); + chunk_t authKeyID = crl->get_authKeyIdentifier(crl); + + if ((keyid.ptr && authKeyID.ptr)? same_keyid(keyid, authKeyID) : + issuer->equals(issuer, crl_issuer)) { - if (crl != x509crls) + if (x509crl != x509crls) { /* bring the CRL up front */ - prev_crl->next = crl->next; - crl->next = x509crls; - x509crls = crl; + prev_crl->next = x509crl->next; + x509crl->next = x509crls; + x509crls = x509crl; } - return crl; + return x509crl; } - prev_crl = crl; - crl = crl->next; + prev_crl = x509crl; + x509crl = x509crl->next; } return NULL; } /** - * Free the dynamic memory used to store revoked certificates - */ -static void free_revoked_certs(revokedCert_t* revokedCerts) -{ - while (revokedCerts != NULL) - { - revokedCert_t * revokedCert = revokedCerts; - revokedCerts = revokedCert->next; - free(revokedCert); - } -} - -/** * Free the dynamic memory used to store CRLs */ void free_crl(x509crl_t *crl) { - free_revoked_certs(crl->revokedCertificates); - free_generalNames(crl->distributionPoints, TRUE); - free(crl->certificateList.ptr); + DESTROY_IF(crl->crl); + crl->distributionPoints->destroy_function(crl->distributionPoints, free); free(crl); } @@ -194,7 +97,9 @@ void free_crls(void) lock_crl_list("free_crls"); while (x509crls != NULL) + { free_first_crl(); + } unlock_crl_list("free_crls"); } @@ -202,127 +107,109 @@ void free_crls(void) /** * Insert X.509 CRL into chained list */ -bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl) +bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl) { - x509crl_t *crl = malloc_thing(x509crl_t); + certificate_t *cert_crl = x509crl->crl; + crl_t *crl = (crl_t*)cert_crl; + identification_t *issuer = cert_crl->get_issuer(cert_crl); + chunk_t authKeyID = crl->get_authKeyIdentifier(crl); + cert_t *issuer_cert; + x509crl_t *oldcrl; + time_t now, nextUpdate; + bool valid_sig; + + /* add distribution point */ + add_distribution_point(x509crl->distributionPoints, crl_uri); + + lock_authcert_list("insert_crl"); + + /* get the issuer cacert */ + issuer_cert = get_authcert(issuer, authKeyID, X509_CA); + if (issuer_cert == NULL) + { + plog("crl issuer cacert not found"); + free_crl(x509crl); + unlock_authcert_list("insert_crl"); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("crl issuer cacert found") + ) - *crl = empty_x509crl; + /* check the issuer's signature of the crl */ + valid_sig = cert_crl->issued_by(cert_crl, issuer_cert->cert); + unlock_authcert_list("insert_crl"); - if (parse_x509crl(blob, 0, crl)) + if (!valid_sig) { - 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("crl issuer cacert found") - ) + free_crl(x509crl); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("crl signature is valid") + ) - /* 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"); + /* note the current time */ + time(&now); - 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(issuer, authKeyID); - lock_crl_list("insert_crl"); - oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber - , crl->authKeyID); + if (oldcrl != NULL) + { + certificate_t *old_cert_crl = oldcrl->crl; - if (oldcrl != NULL) + if (cert_crl->is_newer(cert_crl, old_cert_crl)) { - if (crl->thisUpdate > oldcrl->thisUpdate) - { - /* keep any known CRL distribution points */ - add_distribution_points(oldcrl->distributionPoints - , &crl->distributionPoints); + /* keep any known CRL distribution points */ + add_distribution_points(x509crl->distributionPoints, + oldcrl->distributionPoints); - /* now delete the old CRL */ - free_first_crl(); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is newer - existing crl deleted") - ) - } - else - { - unlock_crl_list("insert_crls"); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is not newer - existing crl not replaced"); - ) - free_crl(crl); - return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval; - } + /* now delete the old CRL */ + free_first_crl(); + DBG(DBG_CONTROL, + DBG_log("thisUpdate is newer - existing crl deleted") + ) } - - /* 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) + else { - 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); - } + unlock_crl_list("insert_crls"); + DBG(DBG_CONTROL, + DBG_log("thisUpdate is not newer - existing crl not replaced"); + ) + free_crl(x509crl); + old_cert_crl->get_validity(old_cert_crl, &now, NULL, &nextUpdate); + return nextUpdate - now > 2*crl_check_interval; } - - /* is the fetched crl valid? */ - return crl->nextUpdate - time(NULL) > 2*crl_check_interval; } - else + + /* insert new CRL */ + x509crl->next = x509crls; + x509crls = x509crl; + + unlock_crl_list("insert_crl"); + + /* If crl caching is enabled then the crl is saved locally. + * Only http or ldap URIs are cached but not local file URIs. + * The CRL's authorityKeyIdentifier is used as a unique filename + */ + if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0) { - plog(" error in X.509 crl"); - free_crl(crl); - return FALSE; + char buf[BUF_LEN]; + chunk_t hex, encoding; + + hex = chunk_to_hex(crl->get_authKeyIdentifier(crl), NULL, FALSE); + snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_PATH, hex); + free(hex.ptr); + + encoding = cert_crl->get_encoding(cert_crl); + chunk_write(encoding, buf, "crl", 022, TRUE); + free(encoding.ptr); } + + /* is the fetched crl valid? */ + cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); + return nextUpdate - now > 2*crl_check_interval; } /** @@ -352,22 +239,19 @@ void load_crls(void) { while (n--) { - bool pgp = FALSE; - chunk_t blob = chunk_empty; char *filename = filelist[n]->d_name; + x509crl_t *x509crl; - if (load_coded_file(filename, NULL, "crl", &blob, &pgp)) + x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_PLUTO_CRL, + BUILD_FROM_FILE, filename, BUILD_END); + if (x509crl) { - chunk_t crl_uri; - - crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename); - crl_uri.ptr = malloc(crl_uri.len + 1); + char crl_uri[BUF_LEN]; - /* build CRL file URI */ - snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s" - , CRL_PATH, filename); - - insert_crl(blob, crl_uri, FALSE); + plog(" loaded crl from '%s'", filename); + snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename); + insert_crl(x509crl, crl_uri, FALSE); } free(filelist[n]); } @@ -378,212 +262,77 @@ void load_crls(void) ignore_result(chdir(save_dir)); } -/** - * Parses a CRL revocation reason code - */ -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(" '%N'", crl_reason_names, reason) - ) - return reason; -} - -/* - * Parses an X.509 CRL - */ -bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl) -{ - 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; - } - } - success = parser->success(parser); - time(&crl->installed); - -end: - parser->destroy(parser); - return success; -} /* Checks if the current certificate is revoked. It goes through the * list of revoked certificates of the corresponding crl. Either the * status CERT_GOOD or CERT_REVOKED is returned */ -static cert_status_t -check_revocation(const x509crl_t *crl, chunk_t serial -, time_t *revocationDate, crl_reason_t * revocationReason) +static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial, + time_t *revocationDate, + crl_reason_t *revocationReason) { - revokedCert_t *revokedCert = crl->revokedCertificates; + enumerator_t *enumerator; + cert_status_t status; + chunk_t serial; - *revocationDate = UNDEFINED_TIME; - *revocationReason = REASON_UNSPECIFIED; - DBG(DBG_CONTROL, - DBG_dump_chunk("serial number:", serial) + DBG_log("serial number: %#B", &cert_serial) ) + *revocationDate = UNDEFINED_TIME; + *revocationReason = CRL_REASON_UNSPECIFIED; + status = CERT_GOOD; - while(revokedCert != NULL) + enumerator = crl->create_enumerator(crl); + while (enumerator->enumerate(enumerator, &serial, + revocationDate, revocationReason)) { - /* compare serial numbers */ - if (revokedCert->userCertificate.len == serial.len && - memeq(revokedCert->userCertificate.ptr, serial.ptr, serial.len)) + if (chunk_equals(serial, cert_serial)) { - *revocationDate = revokedCert->revocationDate; - *revocationReason = revokedCert->revocationReason; - return CERT_REVOKED; + status = CERT_REVOKED; + break; } - revokedCert = revokedCert->next; } - return CERT_GOOD; + enumerator->destroy(enumerator); + return status; } /* * check if any crls are about to expire */ -void -check_crls(void) +void check_crls(void) { - x509crl_t *crl; + x509crl_t *x509crl; + time_t now, nextUpdate, time_left; lock_crl_list("check_crls"); - crl = x509crls; + time(&now); + x509crl = x509crls; - while (crl != NULL) + while (x509crl != NULL) { - time_t time_left = crl->nextUpdate - time(NULL); - u_char buf[BUF_LEN]; + certificate_t *cert_crl = x509crl->crl; + crl_t *crl = (crl_t*)cert_crl; + identification_t *issuer = cert_crl->get_issuer(cert_crl); + chunk_t authKeyID = crl->get_authKeyIdentifier(crl); + + cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); + time_left = nextUpdate - now; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, crl->issuer); - DBG_log("issuer: '%s'",buf); - if (crl->authKeyID.ptr != NULL) + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr) { - datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } DBG_log("%ld seconds left", time_left) ) if (time_left < 2*crl_check_interval) { - fetch_req_t *req = build_crl_fetch_request(crl->issuer - , crl->authKeySerialNumber - , crl->authKeyID, crl->distributionPoints); + fetch_req_t *req = build_crl_fetch_request(issuer, authKeyID, + x509crl->distributionPoints); add_crl_fetch_request(req); } - crl = crl->next; + x509crl = x509crl->next; } unlock_crl_list("check_crls"); } @@ -591,112 +340,131 @@ check_crls(void) /* * verify if a cert hasn't been revoked by a crl */ -cert_status_t -verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate -, crl_reason_t *revocationReason) +cert_status_t verify_by_crl(cert_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); - - generalName_t *crluri = (ca == NULL)? NULL : ca->crluri; - + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *issuer = certificate->get_issuer(certificate); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); + x509crl_t *x509crl; + ca_info_t *ca; + enumerator_t *enumerator; + char *point; + + ca = get_ca_info(issuer, authKeyID); + *revocationDate = UNDEFINED_TIME; - *revocationReason = REASON_UNSPECIFIED; + *revocationReason = CRL_REASON_UNSPECIFIED; lock_crl_list("verify_by_crl"); - crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID); + x509crl = get_x509crl(issuer, authKeyID); - if (crl == NULL) + if (x509crl == NULL) { + linked_list_t *crluris; + unlock_crl_list("verify_by_crl"); plog("crl not found"); - if (cert->crlDistributionPoints != NULL) + crluris = linked_list_create(); + if (ca) { - fetch_req_t *req = build_crl_fetch_request(cert->issuer - , cert->authKeySerialNumber - , cert->authKeyID, cert->crlDistributionPoints); - add_crl_fetch_request(req); + add_distribution_points(crluris, ca->crluris); } - if (crluri != NULL) + enumerator = x509->create_crl_uri_enumerator(x509); + while (enumerator->enumerate(enumerator, &point)) { - fetch_req_t *req = build_crl_fetch_request(cert->issuer - , cert->authKeySerialNumber - , cert->authKeyID, crluri); - add_crl_fetch_request(req); + add_distribution_point(crluris, point); } + enumerator->destroy(enumerator); - if (cert->crlDistributionPoints != 0 || crluri != NULL) + if (crluris->get_count(crluris) > 0) { + fetch_req_t *req; + + req = build_crl_fetch_request(issuer, authKeyID, crluris); + crluris->destroy_function(crluris, free); + add_crl_fetch_request(req); wake_fetch_thread("verify_by_crl"); return CERT_UNKNOWN; } else + { + crluris->destroy(crluris); return CERT_UNDEFINED; + } } else { - x509cert_t *issuer_cert; - bool valid; + certificate_t *cert_crl = x509crl->crl; + crl_t *crl = (crl_t*)cert_crl; + chunk_t authKeyID = crl->get_authKeyIdentifier(crl); + cert_t *issuer_cert; + bool trusted, valid; DBG(DBG_CONTROL, DBG_log("crl found") ) - add_distribution_points(cert->crlDistributionPoints - , &crl->distributionPoints); + if (ca) + { + add_distribution_points(x509crl->distributionPoints, ca->crluris); + } - add_distribution_points(crluri - , &crl->distributionPoints); + enumerator = x509->create_crl_uri_enumerator(x509); + while (enumerator->enumerate(enumerator, &point)) + { + add_distribution_point(x509crl->distributionPoints, point); + } + enumerator->destroy(enumerator); lock_authcert_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); - + issuer_cert = get_authcert(issuer, authKeyID, X509_CA); + trusted = cert_crl->issued_by(cert_crl, issuer_cert->cert); + unlock_authcert_list("verify_by_crl"); - if (valid) + if (trusted) { cert_status_t status; DBG(DBG_CONTROL, DBG_log("crl signature is valid") ) - /* return the expiration date */ - *until = crl->nextUpdate; + + /* return the expiration date */ + valid = cert_crl->get_validity(cert_crl, NULL, NULL, until); /* has the certificate been revoked? */ - status = check_revocation(crl, cert->serialNumber, revocationDate + status = check_revocation(crl, x509->get_serial(x509), revocationDate , revocationReason); - if (*until < time(NULL)) + if (valid) + { + unlock_crl_list("verify_by_crl"); + DBG(DBG_CONTROL, + DBG_log("crl is valid: until %T", until, FALSE) + ) + } + else { fetch_req_t *req; - plog("crl update is overdue since %T", until, TRUE); + DBG(DBG_CONTROL, + DBG_log("crl is stale: since %T", until, FALSE) + ) /* try to fetch a crl update */ - req = build_crl_fetch_request(crl->issuer - , crl->authKeySerialNumber - , crl->authKeyID, crl->distributionPoints); + req = build_crl_fetch_request(issuer, authKeyID, + x509crl->distributionPoints); unlock_crl_list("verify_by_crl"); add_crl_fetch_request(req); wake_fetch_thread("verify_by_crl"); } - else - { - unlock_crl_list("verify_by_crl"); - DBG(DBG_CONTROL, - DBG_log("crl is valid") - ) - } return status; } else @@ -711,65 +479,59 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate /* * list all X.509 crls in the chained list */ -void -list_crls(bool utc, bool strict) +void list_crls(bool utc, bool strict) { - x509crl_t *crl; + x509crl_t *x509crl; lock_crl_list("list_crls"); - crl = x509crls; + x509crl = x509crls; - if (crl != NULL) + if (x509crl) { whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, "List of X.509 CRLs:"); - whack_log(RC_COMMENT, " "); } - while (crl != NULL) + while (x509crl) { - u_char buf[BUF_LEN]; + certificate_t *cert_crl = x509crl->crl; + crl_t *crl = (crl_t*)cert_crl; + chunk_t serial, authKeyID; + time_t thisUpdate, nextUpdate; u_int revoked = 0; - revokedCert_t *revokedCert = crl->revokedCertificates; + enumerator_t *enumerator; - /* count number of revoked certificates in CRL */ - while (revokedCert != NULL) + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, " issuer: \"%Y\"", + cert_crl->get_issuer(cert_crl)); + serial = crl->get_serial(crl); + if (serial.ptr) { - revoked++; - revokedCert = revokedCert->next; + whack_log(RC_COMMENT, " serial: %#B", &serial); } - 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) + /* count number of revoked certificates in CRL */ + enumerator = crl->create_enumerator(crl); + while (enumerator->enumerate(enumerator, NULL, NULL, NULL)) { - datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + revoked++; } - if (crl->authKeySerialNumber.ptr != NULL) + enumerator->destroy(enumerator); + whack_log(RC_COMMENT, " revoked: %d certificates", revoked); + + list_distribution_points(x509crl->distributionPoints); + + cert_crl->get_validity(cert_crl, NULL, &thisUpdate, &nextUpdate); + whack_log(RC_COMMENT, " updates: this %T", &thisUpdate, utc); + whack_log(RC_COMMENT, " next %T %s", &nextUpdate, utc, + check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict)); + authKeyID = crl->get_authKeyIdentifier(crl); + if (authKeyID.ptr) { - datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); } - crl = crl->next; + x509crl = x509crl->next; } unlock_crl_list("list_crls"); } diff --git a/src/pluto/crl.h b/src/pluto/crl.h index 7c110ad5a..43bafe145 100644 --- a/src/pluto/crl.h +++ b/src/pluto/crl.h @@ -14,47 +14,18 @@ #include "constants.h" -/* access structure for a revoked serial number */ - -typedef struct revokedCert revokedCert_t; - -struct revokedCert{ - revokedCert_t *next; - chunk_t userCertificate; - time_t revocationDate; - crl_reason_t revocationReason; -}; +#include <utils/linked_list.h> +#include <credentials/certificates/certificate.h> +#include <credentials/certificates/crl.h> /* storage structure for an X.509 CRL */ typedef struct x509crl x509crl_t; struct x509crl { - x509crl_t *next; - time_t installed; - generalName_t *distributionPoints; - chunk_t certificateList; - chunk_t tbsCertList; - u_int version; - /* 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; - - /* signatureAlgorithm */ - int algorithm; - chunk_t signature; + certificate_t *crl; + x509crl_t *next; + linked_list_t *distributionPoints; }; /* apply a strict CRL policy @@ -69,18 +40,14 @@ extern bool cache_crls; /* * check periodically for expired crls - */ + */ extern long crl_check_interval; - -/* used for initialization */ -extern const x509crl_t empty_x509crl; - -extern bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl); 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); +extern bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl); +extern cert_status_t verify_by_crl(cert_t *cert, time_t *until, + time_t *revocationDate, + crl_reason_t *revocationReason); extern void list_crls(bool utc, bool strict); extern void free_crls(void); extern void free_crl(x509crl_t *crl); diff --git a/src/pluto/crypto.c b/src/pluto/crypto.c index f47ad1eeb..2113cecbc 100644 --- a/src/pluto/crypto.c +++ b/src/pluto/crypto.c @@ -21,12 +21,12 @@ #include "log.h" static struct encrypt_desc encrypt_desc_3des = -{ +{ algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_3DES_CBC, + algo_id: OAKLEY_3DES_CBC, algo_next: NULL, - enc_blocksize: DES_BLOCK_SIZE, + 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, @@ -40,7 +40,7 @@ static struct encrypt_desc encrypt_desc_aes = { algo_type: IKE_ALG_ENCRYPT, algo_id: OAKLEY_AES_CBC, - algo_next: NULL, + algo_next: NULL, enc_blocksize: AES_BLOCK_SIZE, keyminlen: AES_KEY_MIN_LEN, @@ -48,6 +48,22 @@ static struct encrypt_desc encrypt_desc_aes = keymaxlen: AES_KEY_MAX_LEN, }; +#define CAMELLIA_KEY_MIN_LEN 128 +#define CAMELLIA_KEY_DEF_LEN 128 +#define CAMELLIA_KEY_MAX_LEN 256 + +static struct encrypt_desc encrypt_desc_camellia = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_CAMELLIA_CBC, + algo_next: NULL, + + enc_blocksize: CAMELLIA_BLOCK_SIZE, + keyminlen: CAMELLIA_KEY_MIN_LEN, + keydeflen: CAMELLIA_KEY_DEF_LEN, + keymaxlen: CAMELLIA_KEY_MAX_LEN, +}; + #define BLOWFISH_KEY_MIN_LEN 128 #define BLOWFISH_KEY_MAX_LEN 448 @@ -55,7 +71,7 @@ static struct encrypt_desc encrypt_desc_blowfish = { algo_type: IKE_ALG_ENCRYPT, algo_id: OAKLEY_BLOWFISH_CBC, - algo_next: NULL, + algo_next: NULL, enc_blocksize: BLOWFISH_BLOCK_SIZE, keyminlen: BLOWFISH_KEY_MIN_LEN, @@ -83,7 +99,7 @@ static struct encrypt_desc encrypt_desc_serpent = #define TWOFISH_KEY_DEF_LEN 128 #define TWOFISH_KEY_MAX_LEN 256 -static struct encrypt_desc encrypt_desc_twofish = +static struct encrypt_desc encrypt_desc_twofish = { algo_type: IKE_ALG_ENCRYPT, algo_id: OAKLEY_TWOFISH_CBC, @@ -108,18 +124,18 @@ static struct encrypt_desc encrypt_desc_twofish_ssh = }; static struct hash_desc hash_desc_md5 = -{ +{ algo_type: IKE_ALG_HASH, algo_id: OAKLEY_MD5, - algo_next: NULL, + algo_next: NULL, hash_digest_size: HASH_SIZE_MD5, }; static struct hash_desc hash_desc_sha1 = -{ +{ algo_type: IKE_ALG_HASH, algo_id: OAKLEY_SHA, - algo_next: NULL, + algo_next: NULL, hash_digest_size: HASH_SIZE_SHA1, }; @@ -146,91 +162,91 @@ static struct hash_desc hash_desc_sha2_512 = { const struct dh_desc unset_group = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_NONE, + algo_id: MODP_NONE, algo_next: NULL, ke_size: 0 }; -static struct dh_desc dh_desc_modp_1024 = { +static struct dh_desc dh_desc_modp_1024 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1024_BIT, + algo_id: MODP_1024_BIT, algo_next: NULL, ke_size: 1024 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_modp_1536 = { +static struct dh_desc dh_desc_modp_1536 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1536_BIT, + algo_id: MODP_1536_BIT, algo_next: NULL, ke_size: 1536 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_modp_2048 = { +static struct dh_desc dh_desc_modp_2048 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_BIT, + algo_id: MODP_2048_BIT, algo_next: NULL, ke_size: 2048 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_modp_3072 = { +static struct dh_desc dh_desc_modp_3072 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_3072_BIT, + algo_id: MODP_3072_BIT, algo_next: NULL, ke_size: 3072 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_modp_4096 = { +static struct dh_desc dh_desc_modp_4096 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_4096_BIT, + algo_id: MODP_4096_BIT, algo_next: NULL, ke_size: 4096 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_modp_6144 = { +static struct dh_desc dh_desc_modp_6144 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_6144_BIT, + algo_id: MODP_6144_BIT, algo_next: NULL, ke_size: 6144 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_modp_8192 = { +static struct dh_desc dh_desc_modp_8192 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_8192_BIT, + algo_id: MODP_8192_BIT, algo_next: NULL, ke_size: 8192 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_ecp_256 = { +static struct dh_desc dh_desc_ecp_256 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_256_BIT, + algo_id: ECP_256_BIT, algo_next: NULL, ke_size: 2*256 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_ecp_384 = { +static struct dh_desc dh_desc_ecp_384 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_384_BIT, + algo_id: ECP_384_BIT, algo_next: NULL, ke_size: 2*384 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_ecp_521 = { +static struct dh_desc dh_desc_ecp_521 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_521_BIT, + algo_id: ECP_521_BIT, algo_next: NULL, ke_size: 2*528 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_ecp_192 = { +static struct dh_desc dh_desc_ecp_192 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_192_BIT, + algo_id: ECP_192_BIT, algo_next: NULL, ke_size: 2*192 / BITS_PER_BYTE }; -static struct dh_desc dh_desc_ecp_224 = { +static struct dh_desc dh_desc_ecp_224 = { algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_224_BIT, + algo_id: ECP_224_BIT, algo_next: NULL, ke_size: 2*224 / BITS_PER_BYTE }; @@ -283,12 +299,12 @@ bool init_crypto(void) (no_md5) ? "MD5" : ""); return FALSE; } - + 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: @@ -300,6 +316,9 @@ bool init_crypto(void) case ENCR_AES_CBC: desc = &encrypt_desc_aes; break; + case ENCR_CAMELLIA_CBC: + desc = &encrypt_desc_camellia; + break; case ENCR_TWOFISH_CBC: desc = &encrypt_desc_twofish; ike_alg_add((struct ike_alg *)&encrypt_desc_twofish_ssh); @@ -308,7 +327,7 @@ bool init_crypto(void) desc = &encrypt_desc_serpent; break; default: - continue; + continue; } ike_alg_add((struct ike_alg *)desc); } @@ -381,7 +400,7 @@ encryption_algorithm_t oakley_to_encryption_algorithm(int alg) case OAKLEY_DES_CBC: return ENCR_DES; case OAKLEY_IDEA_CBC: - return ENCR_IDEA; + return ENCR_IDEA; case OAKLEY_BLOWFISH_CBC: return ENCR_BLOWFISH; case OAKLEY_RC5_R16_B64_CBC: @@ -392,6 +411,8 @@ encryption_algorithm_t oakley_to_encryption_algorithm(int alg) return ENCR_CAST; case OAKLEY_AES_CBC: return ENCR_AES_CBC; + case OAKLEY_CAMELLIA_CBC: + return ENCR_CAMELLIA_CBC; case OAKLEY_SERPENT_CBC: return ENCR_SERPENT_CBC; case OAKLEY_TWOFISH_CBC: @@ -491,7 +512,7 @@ int oakley_from_encryption_algorithm(encryption_algorithm_t alg) return OAKLEY_CAMELLIA_CBC; case ENCR_SERPENT_CBC: return OAKLEY_SERPENT_CBC; - case ENCR_TWOFISH_CBC: + case ENCR_TWOFISH_CBC: return OAKLEY_TWOFISH_CBC; default: return 0; @@ -561,7 +582,7 @@ int esp_from_encryption_algorithm(encryption_algorithm_t alg) return ESP_CAMELLIA; case ENCR_SERPENT_CBC: return ESP_SERPENT; - case ENCR_TWOFISH_CBC: + case ENCR_TWOFISH_CBC: return ESP_TWOFISH; default: return 0; @@ -581,12 +602,20 @@ int esp_from_integrity_algorithm(integrity_algorithm_t alg) return AUTH_ALGORITHM_HMAC_SHA1; case AUTH_AES_XCBC_96: return AUTH_ALGORITHM_AES_XCBC_MAC; + case AUTH_HMAC_SHA2_256_96: + return AUTH_ALGORITHM_HMAC_SHA2_256_96; 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; + case AUTH_AES_128_GMAC: + return AUTH_ALGORITHM_AES_128_GMAC; + case AUTH_AES_192_GMAC: + return AUTH_ALGORITHM_AES_192_GMAC; + case AUTH_AES_256_GMAC: + return AUTH_ALGORITHM_AES_256_GMAC; default: return 0; } diff --git a/src/pluto/db_ops.c b/src/pluto/db_ops.c index 4ba4fa324..547ea5f22 100644 --- a/src/pluto/db_ops.c +++ b/src/pluto/db_ops.c @@ -1,6 +1,6 @@ /* Dynamic db (proposal, transforms, attributes) handling. * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -12,11 +12,11 @@ * for more details. */ -/* +/* * The stratedy is to have (full contained) struct db_prop in db_context * pointing to ONE dynamically sizable transform vector (trans0). * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0) - * in a "serialized" way (attributes storage is used in linear sequence for + * in a "serialized" way (attributes storage is used in linear sequence for * subsecuent transforms). * * Resizing for both trans0 and attrs0 is supported: @@ -24,7 +24,7 @@ * also update trans_cur (by offset) * - For attrs0: after allocating and copying attrs, I must rewrite each * trans->attrs present in trans0; to achieve this, calculate - * attrs pointer offset (new minus old) and iterate over + * attrs pointer offset (new minus old) and iterate over * each transform "adding" this difference. * also update attrs_cur (by offset) * @@ -70,7 +70,7 @@ #ifdef NOT_YET /* * Allocator cache: - * Because of the single-threaded nature of pluto/spdb.c, + * 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 @@ -84,9 +84,9 @@ struct db_ops_alloc_cache { #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 */ @@ -100,7 +100,7 @@ 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 *malloc_bytes_st(size_t size, struct db_ops_stats *st) +static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st) { void *ptr = malloc(size); if (ptr) @@ -108,7 +108,7 @@ static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st) st->st_curr_cnt++; st->st_total_cnt++; if (size > st->st_maxsz) st->st_maxsz=size; - } + } return ptr; } #define ALLOC_BYTES_ST(z,st) malloc_bytes_st(z, &st); @@ -125,13 +125,13 @@ static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st) * as a result of "add" operations */ int -db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs) +db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs) { ctx->trans0 = NULL; ctx->attrs0 = NULL; if (max_trans > 0) { /* quite silly if not */ - ctx->trans0 = ALLOC_BYTES_ST ( sizeof(struct db_trans) * max_trans, + ctx->trans0 = ALLOC_BYTES_ST ( sizeof(struct db_trans) * max_trans, db_trans_st); memset(ctx->trans0, '\0', sizeof(struct db_trans) * max_trans); } @@ -162,12 +162,12 @@ db_trans_expand(struct db_context *ctx, int delta_trans) int offset; old_trans = ctx->trans0; - new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, + 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) */ @@ -175,7 +175,7 @@ db_trans_expand(struct db_context *ctx, int delta_trans) { char *cctx = (char *)(ctx->trans_cur); - + cctx += offset; ctx->trans_cur = (struct db_trans *)cctx; } @@ -186,7 +186,7 @@ db_trans_expand(struct db_context *ctx, int delta_trans) out: return ret; } -/* +/* * Expand storage for attributes by delta_attrs number AND * rewrite trans->attr pointers */ @@ -201,22 +201,22 @@ db_attrs_expand(struct db_context *ctx, int delta_attrs) int offset; old_attrs = ctx->attrs0; - new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, + new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, db_attrs_st); if (!new_attrs) goto out; memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr)); - + /* update attrs0 and attrs_cur (obviously) */ offset = (char *)(new_attrs) - (char *)(old_attrs); - + { char *actx = (char *)(ctx->attrs0); - + actx += offset; ctx->attrs0 = (struct db_attr *)actx; - + actx = (char *)ctx->attrs_cur; actx += offset; ctx->attrs_cur = (struct db_attr *)actx; @@ -237,13 +237,13 @@ out: return ret; } /* Allocate a new db object */ -struct db_context * -db_prop_new(u_int8_t protoid, int max_trans, int max_attrs) +struct db_context * +db_prop_new(u_int8_t protoid, int max_trans, int max_attrs) { struct db_context *ctx; ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), db_context_st); if (!ctx) goto out; - + if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) { PFREE_ST(ctx, db_context_st); ctx=NULL; @@ -266,8 +266,8 @@ 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 + /* + * Strategy: if more space is needed, expand by * <current_size>/2 + 1 * * This happens to produce a "reasonable" sequence @@ -287,10 +287,10 @@ db_trans_add(struct db_context *ctx, u_int8_t transid) } /* Add attr copy to current transform, expanding attrs0 if needed */ int -db_attr_add(struct db_context *ctx, const struct db_attr *a) +db_attr_add(struct db_context *ctx, const struct db_attr *a) { - /* - * Strategy: if more space is needed, expand by + /* + * Strategy: if more space is needed, expand by * <current_size>/2 + 1 */ if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) { @@ -302,7 +302,7 @@ db_attr_add(struct db_context *ctx, const struct db_attr *a) ctx->trans_cur->attr_cnt++; return 0; } -/* Add attr copy (by value) to current transform, +/* Add attr copy (by value) to current transform, * expanding attrs0 if needed, just calls db_attr_add(). */ int @@ -317,7 +317,7 @@ db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val) int db_ops_show_status(void) { - whack_log(RC_COMMENT, "stats " __FILE__ ": " + whack_log(RC_COMMENT, "stats " __FILE__ ": " DB_OPS_STATS_DESC " :" DB_OPS_STATS_STR("context") DB_OPS_STATS_STR("trans") @@ -329,7 +329,7 @@ db_ops_show_status(void) return 0; } #endif /* NO_DB_OPS_STATS */ -/* +/* * From below to end just testing stuff .... */ #ifdef TEST @@ -349,7 +349,7 @@ static void db_prop_print(struct db_prop *p) default: continue; } - printf(" transid=\"%s\"\n", + printf(" transid=\"%s\"\n", enum_name(n, t->transid)); for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) { int i; @@ -367,16 +367,16 @@ static void db_prop_print(struct db_prop *p) default: continue; } - printf(" type=\"%s\" value=\"%s\"\n", + 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) +static void db_print(struct db_context *ctx) { - printf("trans_cur diff=%d, attrs_cur diff=%d\n", + 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); diff --git a/src/pluto/demux.c b/src/pluto/demux.c index 3cfc909af..fad1450cd 100644 --- a/src/pluto/demux.c +++ b/src/pluto/demux.c @@ -819,7 +819,7 @@ check_msg_errqueue(const struct iface *ifp, short interest) bool send_packet(struct state *st, const char *where) { - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; int port_buf; bool err; u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE]; @@ -1258,16 +1258,16 @@ process_packet(struct msg_digest **mdp) 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); + SEND_NOTIFICATION(ISAKMP_INVALID_MAJOR_VERSION); return; } else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION) { - SEND_NOTIFICATION(INVALID_MINOR_VERSION); + SEND_NOTIFICATION(ISAKMP_INVALID_MINOR_VERSION); return; } } - SEND_NOTIFICATION(PAYLOAD_MALFORMED); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } @@ -1295,14 +1295,14 @@ process_packet(struct msg_digest **mdp) { plog("Message ID was 0x%08lx but should be zero in Main Mode", (unsigned long) md->hdr.isa_msgid); - SEND_NOTIFICATION(INVALID_MESSAGE_ID); + SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); return; } if (is_zero_cookie(md->hdr.isa_icookie)) { plog("Initiator Cookie must not be zero in Main Mode message"); - SEND_NOTIFICATION(INVALID_COOKIE); + SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); return; } @@ -1315,7 +1315,7 @@ process_packet(struct msg_digest **mdp) { plog("initial Main Mode message is invalid:" " its Encrypted Flag is on"); - SEND_NOTIFICATION(INVALID_FLAGS); + SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); return; } @@ -1399,7 +1399,7 @@ process_packet(struct msg_digest **mdp) { 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) @@ -1429,7 +1429,7 @@ process_packet(struct msg_digest **mdp) { plog("Quick Mode message is invalid because" " it has an Initiator Cookie of 0"); - SEND_NOTIFICATION(INVALID_COOKIE); + SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); return; } @@ -1437,7 +1437,7 @@ process_packet(struct msg_digest **mdp) { plog("Quick Mode message is invalid because" " it has a Responder Cookie of 0"); - SEND_NOTIFICATION(INVALID_COOKIE); + SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); return; } @@ -1445,7 +1445,7 @@ process_packet(struct msg_digest **mdp) { plog("Quick Mode message is invalid because" " it has a Message ID of 0"); - SEND_NOTIFICATION(INVALID_MESSAGE_ID); + SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); return; } @@ -1475,7 +1475,7 @@ process_packet(struct msg_digest **mdp) { loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because" " it is for an incomplete ISAKMP SA"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); return; } @@ -1486,7 +1486,7 @@ process_packet(struct msg_digest **mdp) " 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); + SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); return; } @@ -1498,7 +1498,7 @@ process_packet(struct msg_digest **mdp) } else { - set_cur_state(st); + set_cur_state(st); from_state = st->st_state; } @@ -1635,7 +1635,7 @@ process_packet(struct msg_digest **mdp) default: plog("unsupported exchange type %s in message" , enum_show(&exchange_names, md->hdr.isa_xchg)); - SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE); + SEND_NOTIFICATION(ISAKMP_UNSUPPORTED_EXCHANGE_TYPE); return; } @@ -1681,7 +1681,7 @@ process_packet(struct msg_digest **mdp) default: auth = st->st_oakley.auth; } - + while (!LHAS(smc->flags, auth)) { smc++; @@ -1748,14 +1748,14 @@ process_packet(struct msg_digest **mdp) if (st == NULL) { plog("discarding encrypted message for an unknown ISAKMP SA"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); return; } if (st->st_skeyid_e.ptr == (u_char *) NULL) { loglog(RC_LOG_SERIOUS, "discarding encrypted message" " because we haven't yet negotiated keying materiel"); - SEND_NOTIFICATION(INVALID_FLAGS); + SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); return; } @@ -1795,7 +1795,7 @@ process_packet(struct msg_digest **mdp) 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); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } @@ -1823,11 +1823,11 @@ process_packet(struct msg_digest **mdp) memcpy(new_iv, data.ptr + data.len - crypter_block_size, crypter_block_size); - crypter->set_key(crypter, st->st_enc_key); + 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); + memcpy(st->st_new_iv, new_iv, crypter_block_size); if (restore_iv) { memcpy(st->st_new_iv, new_iv, new_iv_len); @@ -1848,7 +1848,7 @@ process_packet(struct msg_digest **mdp) if (smc->flags & SMF_INPUT_ENCRYPTED) { loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); - SEND_NOTIFICATION(INVALID_FLAGS); + SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); return; } } @@ -1875,7 +1875,7 @@ process_packet(struct msg_digest **mdp) if (pd == &md->digest[PAYLIMIT]) { loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } @@ -1915,7 +1915,7 @@ process_packet(struct msg_digest **mdp) 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); + SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); return; } } @@ -1929,7 +1929,7 @@ process_packet(struct msg_digest **mdp) 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); + SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); return; } needed &= ~s; @@ -1939,7 +1939,7 @@ process_packet(struct msg_digest **mdp) { loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse); if (md->hdr.isa_xchg != ISAKMP_XCHG_INFO) - SEND_NOTIFICATION(PAYLOAD_MALFORMED); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } @@ -1979,7 +1979,7 @@ process_packet(struct msg_digest **mdp) 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); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } } @@ -1995,7 +1995,7 @@ process_packet(struct msg_digest **mdp) && 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); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } } @@ -2019,7 +2019,7 @@ process_packet(struct msg_digest **mdp) 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); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } @@ -2033,7 +2033,7 @@ process_packet(struct msg_digest **mdp) if (p != &md->digest[i]) { loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } } @@ -2054,14 +2054,14 @@ process_packet(struct msg_digest **mdp) loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" " if any ID payload is present," " there must be exactly two"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } if (id+1 != id->next) { loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" " the ID payloads are not adjacent"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); + SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); return; } } @@ -2192,7 +2192,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) time_t delay = UNDEFINED_TIME; enum event_type kind = smc->timeout_event; bool agreed_time = FALSE; - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; switch (kind) { @@ -2310,7 +2310,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) 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)) diff --git a/src/pluto/dnskey.c b/src/pluto/dnskey.c index ed901ade5..ec56b8530 100644 --- a/src/pluto/dnskey.c +++ b/src/pluto/dnskey.c @@ -36,7 +36,7 @@ #include "adns.h" /* needs <resolv.h> */ #include "defs.h" #include "log.h" -#include "id.h" +#include "myid.h" #include "connections.h" #include "keys.h" /* needs connections.h */ #include "dnskey.h" @@ -238,62 +238,30 @@ stop_adns(void) #define our_TXT_attr_string "X-IPsec-Server" static const char our_TXT_attr[] = our_TXT_attr_string; -static err_t -decode_iii(u_char **pp, struct id *gw_id) +identification_t* decode_iii(u_char **pp) { + identification_t *gw_id; u_char *p = *pp + strspn(*pp, " \t"); u_char *e = p + strcspn(p, " \t"); u_char under = *e; if (p == e) { - return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; + return NULL; } *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); - } - + gw_id = identification_create_from_string(p); *e = under; *pp = e + strspn(e, " \t"); - return NULL; + return gw_id; } -static err_t -process_txt_rr_body(u_char *str -, bool doit /* should we capture information? */ -, enum dns_auth_level dns_auth_level -, struct adns_continuation *const cr) +static err_t process_txt_rr_body(u_char *str, bool doit, + enum dns_auth_level dns_auth_level, + struct adns_continuation *const cr) { - const struct id *client_id = &cr->id; /* subject of query */ + identification_t *client_id = cr->id; /* subject of query */ u_char *p = str; unsigned long pref = 0; struct gw_info gi; @@ -349,10 +317,13 @@ process_txt_rr_body(u_char *str p += strspn(p, " \t"); /* Decode iii (Security Gateway ID). */ - zero(&gi); /* before first use */ - TRY(decode_iii(&p, &gi.gw_id)); /* will need to unshare_id_content */ + gi.gw_id = decode_iii(&p); + if (gi.gw_id == NULL) + { + return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; + } if (!cr->sgw_specified) { @@ -360,19 +331,14 @@ process_txt_rr_body(u_char *str * 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 (gi.gw_id->get_type(gi.gw_id) != ID_IPV4_ADDR && + gi.gw_id->get_type(gi.gw_id) != ID_IPV6_ADDR) { DBG(DBG_DNS, - { - 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); - }); + DBG_log("TXT %s record for '%Y': security gateway '%Y';" + " ignored because gateway's IP is unspecified", + our_TXT_attr, client_id, gi.gw_id); + ) return NULL; /* we cannot use this record, but it isn't wrong */ } } @@ -381,23 +347,15 @@ process_txt_rr_body(u_char *str /* 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; + identification_t *peer_id = cr->sgw_id; - if (!same_id(peer_id, &gi.gw_id)) + if (!peer_id->equals(peer_id, gi.gw_id)) { 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); - }); + DBG_log("TXT %s record for '%Y': security gateway '%Y';" + " ignored -- looking to confirm '%Y' as gateway", + our_TXT_attr, client_id, gi.gw_id, peer_id); + ) return NULL; /* we cannot use this record, but it isn't wrong */ } } @@ -407,7 +365,7 @@ process_txt_rr_body(u_char *str /* really accept gateway */ struct gw_info **gwip; /* gateway insertion point */ - gi.client_id = *client_id; /* will need to unshare_id_content */ + gi.client_id = client_id; /* will need to unshare_id_content */ /* decode optional kkk: base 64 encoding of key */ @@ -436,7 +394,7 @@ process_txt_rr_body(u_char *str } rfc3110_chunk = chunk_create(buf, sz); key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_BLOB_RFC_3110, rfc3110_chunk, + BUILD_BLOB_DNSKEY, rfc3110_chunk, BUILD_END); if (key == NULL) { @@ -462,32 +420,26 @@ process_txt_rr_body(u_char *str 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); + chunk_t keyid; + public_key_t *key = gi.key->public_key; - if (gi.gw_key_present) + if (gi.gw_key_present && + key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &keyid)) { - DBG_log("gateway for %s is %s with key %Y" - , cidb, gwidb, keyid); + DBG_log("gateway for %s is %s with key %#B", + client_id, gi.gw_id, &keyid); } else { - DBG_log("gateway for %s is %s; no key specified" - , cidb, gwidb); + DBG_log("gateway for '%Y' is '%Y'; no key specified", + client_id, gi.gw_id); } }); gi.next = *gwip; *gwip = clone_thing(gi); - unshare_id_content(&(*gwip)->gw_id); - unshare_id_content(&(*gwip)->client_id); + (*gwip)->gw_id = (*gwip)->gw_id->clone((*gwip)->gw_id); + (*gwip)->client_id = (*gwip)->client_id->clone((*gwip)->client_id); } return NULL; @@ -1271,75 +1223,62 @@ process_dns_answer(struct adns_continuation *const cr /****************************************************************/ -static err_t -build_dns_name(u_char name_buf[NS_MAXDNAME + 2] -, unsigned long serial USED_BY_DEBUG -, const struct id *id -, const char *typename USED_BY_DEBUG -, const char *gwname USED_BY_DEBUG) +static err_t build_dns_name(u_char name_buf[NS_MAXDNAME + 2], + unsigned long serial USED_BY_DEBUG, + identification_t *id, + const char *typename USED_BY_DEBUG, + identification_t *gw USED_BY_DEBUG) { /* note: all end in "." to suppress relative searches */ id = resolve_myid(id); - switch (id->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: + switch (id->get_type(id)) { - /* ??? 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; ) + 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); - } - strcpy(op, suffix); - break; - } + chunk_t b = id->get_encoding(id); - case ID_FQDN: - /* strip trailing "." characters, then add one */ + snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa.", + b.ptr[3], b.ptr[2], b.ptr[1], b.ptr[0]); + break; + } + case ID_IPV6_ADDR: { - size_t il = id->name.len; + chunk_t b = id->get_encoding(id); + size_t bl; + u_char *op = name_buf; + static const char suffix[] = "IP6.INT."; - while (il > 0 && id->name.ptr[il - 1] == '.') - il--; - if (il > NS_MAXDNAME) + for (bl = b.len; bl-- != 0; ) + { + if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1) + { + return "IPv6 reverse name too long"; + } + op += sprintf(op, "%x.%x.", b.ptr[bl] & 0xF, b.ptr[bl] >> 4); + } + strcpy(op, suffix); + break; + } + case ID_FQDN: + { + if (snprintf(name_buf, NS_MAXDNAME + 2, "%Y.", id) > NS_MAXDNAME + 1) + { return "FQDN too long for domain name"; - - memcpy(name_buf, id->name.ptr, il); - strcpy(name_buf + il, "."); + } + break; } - break; - - default: - return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR"; + 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)); + DBG(DBG_CONTROL | DBG_DNS, + DBG_log("DNS query %lu for %s for %s (gw: %Y)", serial, typename, name_buf, gw) + ) return NULL; } -void -gw_addref(struct gw_info *gw) +void gw_addref(struct gw_info *gw) { if (gw != NULL) { @@ -1348,8 +1287,7 @@ gw_addref(struct gw_info *gw) } } -void -gw_delref(struct gw_info **gwp) +void gw_delref(struct gw_info **gwp) { struct gw_info *gw = *gwp; @@ -1361,10 +1299,12 @@ gw_delref(struct gw_info **gwp) gw->refcnt--; if (gw->refcnt == 0) { - free_id_content(&gw->client_id); - free_id_content(&gw->gw_id); + DESTROY_IF(gw->client_id); + DESTROY_IF(gw->gw_id); if (gw->gw_key_present) + { unreference_key(&gw->key); + } gw_delref(&gw->next); free(gw); /* trickery could make this a tail-call */ } @@ -1414,68 +1354,61 @@ static int adns_in_flight = 0; /* queries outstanding */ 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) +static struct adns_continuation *continuation_for_qtid(unsigned long qtid) { struct adns_continuation *cr = NULL; if (qtid != 0) + { for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous) ; + } return cr; } -static void -release_adns_continuation(struct adns_continuation *cr) +static void release_adns_continuation(struct adns_continuation *cr) { passert(cr != next_query); gw_delref(&cr->gateways_from_dns); #ifdef USE_KEYRR free_public_keys(&cr->keys_from_dns); #endif /* USE_KEYRR */ - unshare_id_content(&cr->id); - unshare_id_content(&cr->sgw_id); + cr->id = cr->id->clone(cr->id); + cr->sgw_id = cr->sgw_id->clone(cr->sgw_id); /* unlink from doubly-linked list */ if (cr->next == NULL) { - 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 */ -, cont_fn_t cont_fn -, struct adns_continuation *cr) +err_t start_adns_query(identification_t *id, /* domain to query */ + identification_t *sgw_id, /* if non-null, any accepted gw_info must match */ + int type, /* T_TXT or T_KEY, selecting rr type of interest */ + cont_fn_t cont_fn, + struct adns_continuation *cr) { static unsigned long qtid = 1; /* query transaction id; NOTE: static */ const char *typename = rr_typename(type); - char gwidb[BUF_LEN]; - if(adns_pid == 0 - && adns_restart_count < ADNS_RESTART_MAX) + 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(). */ @@ -1483,7 +1416,6 @@ start_adns_query(const struct id *id /* domain to query */ cr->previous = continuations; if (continuations != NULL) { - passert(continuations->next == NULL); continuations->next = cr; } continuations = cr; @@ -1491,11 +1423,11 @@ start_adns_query(const struct id *id /* domain to query */ 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->id = id->clone(id); + cr->sgw_specified = (sgw_id != NULL); + cr->sgw_id = cr->sgw_specified ? + sgw_id->clone(sgw_id) : + identification_create_from_string("%any"); cr->gateways_from_dns = NULL; #ifdef USE_KEYRR cr->keys_from_dns = NULL; @@ -1507,15 +1439,12 @@ start_adns_query(const struct id *id /* domain to query */ cr->debugging = LEMPTY; #endif - idtoa(&cr->sgw_id, gwidb, sizeof(gwidb)); - zero(&cr->query); - { - err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid - , id, typename, gwidb); + err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid, id, + typename, cr->sgw_id); - if (ugh != NULL) + if (ugh) { release_adns_continuation(cr); return ugh; @@ -1620,8 +1549,7 @@ send_unsent_ADNS_queries(void) * Returns with error message iff lwdnsq result is malformed. * Most errors will be in DNS data and will be handled by cr->cont_fn. */ -static err_t -process_lwdnsq_answer(char *ts) +static err_t process_lwdnsq_answer(char *ts) { err_t ugh = NULL; char *rest; @@ -1813,11 +1741,10 @@ process_lwdnsq_answer(char *ts) } #endif /* USE_LWRES */ -static void -recover_adns_die(void) +static void recover_adns_die(void) { struct adns_continuation *cr = NULL; - + adns_pid = 0; if(adns_restart_count < ADNS_RESTART_MAX) { adns_restart_count++; @@ -1834,7 +1761,7 @@ recover_adns_die(void) if(continuations != NULL) { for (; cr->previous != NULL; cr = cr->previous); } - + next_query = cr; if(next_query != NULL) { @@ -1848,8 +1775,7 @@ void reset_adns_restart_count(void) adns_restart_count=0; } -void -handle_adns_answer(void) +void handle_adns_answer(void) { /* These are retained across calls to handle_adns_answer. */ static size_t buflen = 0; /* bytes in answer buffer */ diff --git a/src/pluto/dnskey.h b/src/pluto/dnskey.h index 976c715bf..d26a0e64f 100644 --- a/src/pluto/dnskey.h +++ b/src/pluto/dnskey.h @@ -12,9 +12,10 @@ * for more details. */ -extern int - adns_qfd, /* file descriptor for sending queries to adns */ - adns_afd; /* file descriptor for receiving answers from adns */ +#include <utils/identification.h> + +extern int adns_qfd; /* file descriptor for sending queries to adns */ +extern int adns_afd; /* file descriptor for receiving answers from adns */ extern const char *pluto_adns_option; /* path from --pluto_adns */ extern void init_adns(void); extern void stop_adns(void); @@ -33,13 +34,13 @@ 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 */ + unsigned long qtid; /* query transaction id number */ + int type; /* T_TXT or T_KEY, selecting rr type of interest */ + cont_fn_t cont_fn; /* function to carry on suspended work */ + identification_t *id; /* subject of query */ bool sgw_specified; - struct id sgw_id; /* peer, if constrained */ - lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ + identification_t *sgw_id; /* peer, if constrained */ + lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */ #ifdef USE_KEYRR struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */ @@ -47,7 +48,7 @@ struct adns_continuation { 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? */ + bool used; /* have we called the cont_fn yet? */ struct { u_char name_buf[NS_MAXDNAME + 2]; } query; @@ -56,8 +57,8 @@ struct adns_continuation { #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 */ +extern err_t start_adns_query(identification_t *id /* domain to query */ + , identification_t *sgw_id /* if non-null, any accepted gw_info must match */ , int type /* T_TXT or T_KEY, selecting rr type of interest */ , cont_fn_t cont_fn /* continuation function */ , struct adns_continuation *cr); @@ -65,18 +66,17 @@ extern err_t start_adns_query(const struct id *id /* domain to query */ /* 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) */ + unsigned refcnt; /* reference counted! */ + unsigned pref; /* preference: lower is better */ +#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */ + identification_t* client_id; /* id of client of peer */ + identification_t* gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */ bool gw_key_present; struct pubkey *key; struct gw_info *next; }; -extern void gw_addref(struct gw_info *gw) - , gw_delref(struct gw_info **gwp); - +extern void gw_addref(struct gw_info *gw); +extern void gw_delref(struct gw_info **gwp); extern void reset_adns_restart_count(void); diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c index 6f7f1215f..6172165bd 100644 --- a/src/pluto/fetch.c +++ b/src/pluto/fetch.c @@ -28,27 +28,27 @@ #include <library.h> #include <debug.h> #include <asn1/asn1.h> -#include <asn1/pem.h> +#include <credentials/certificates/certificate.h> +#ifdef THREADS +#include <threading/thread.h> +#endif #include "constants.h" #include "defs.h" #include "log.h" -#include "id.h" -#include "pem.h" #include "x509.h" #include "ca.h" #include "whack.h" #include "ocsp.h" #include "crl.h" #include "fetch.h" +#include "builder.h" fetch_req_t empty_fetch_req = { NULL , /* next */ - 0 , /* installed */ 0 , /* trials */ - { NULL, 0}, /* issuer */ + NULL , /* issuer */ { NULL, 0}, /* authKeyID */ - { NULL, 0}, /* authKeySerialNumber */ NULL /* distributionPoints */ }; @@ -59,7 +59,7 @@ static fetch_req_t *crl_fetch_reqs = NULL; static ocsp_location_t *ocsp_fetch_reqs = NULL; #ifdef THREADS -static pthread_t thread; +static thread_t *thread; static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -251,10 +251,9 @@ void wake_fetch_thread(const char *who) */ static void free_fetch_request(fetch_req_t *req) { - free(req->issuer.ptr); - free(req->authKeySerialNumber.ptr); + req->distributionPoints->destroy_function(req->distributionPoints, free); + DESTROY_IF(req->issuer); free(req->authKeyID.ptr); - free_generalNames(req->distributionPoints, TRUE); free(req); } @@ -262,86 +261,63 @@ static void free_fetch_request(fetch_req_t *req) /** * Fetch an ASN.1 blob coded in PEM or DER format from a URL */ -bool fetch_asn1_blob(char *url, chunk_t *blob) +x509crl_t* fetch_crl(char *url) { + x509crl_t *crl; + chunk_t blob; + DBG1(" fetching crl from '%s' ...", url); - if (lib->fetcher->fetch(lib->fetcher, url, blob, FETCH_END) != SUCCESS) + if (lib->fetcher->fetch(lib->fetcher, url, &blob, FETCH_END) != SUCCESS) { DBG1("crl fetching failed"); return FALSE; } - - if (is_asn1(*blob)) + crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, + BUILD_BLOB_PEM, blob, BUILD_END); + free(blob.ptr); + if (!crl) { - DBG2(" fetched blob coded in DER format"); + DBG1("crl fetched successfully but data coded in unknown format"); } - else - { - bool pgp = FALSE; - - if (pem_to_bin(blob, chunk_empty, &pgp) != SUCCESS) - { - free(blob->ptr); - return FALSE; - } - if (is_asn1(*blob)) - { - DBG2(" fetched blob coded in PEM format"); - } - else - { - DBG1("crl fetched successfully but data coded in unknown format"); - free(blob->ptr); - return FALSE; - } - } - return TRUE; + return crl; } /** * Complete a distributionPoint URI with ca information */ -static char* complete_uri(chunk_t distPoint, const char *ldaphost) +static char* complete_uri(char *distPoint, const char *ldaphost) { - char *uri; - char *ptr = distPoint.ptr; - size_t len = distPoint.len; + char *symbol = strchr(distPoint, ':'); - char *symbol = memchr(ptr, ':', len); - - if (symbol != NULL) + if (symbol) { - size_t type_len = symbol - ptr; - - if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0) + int type_len = symbol - distPoint; + + if (type_len >= 4 && strncasecmp(distPoint, "ldap", 4) == 0) { - ptr = symbol + 1; - len -= (type_len + 1); + char *ptr = symbol + 1; + int len = strlen(distPoint) - (type_len + 1); if (len > 2 && *ptr++ == '/' && *ptr++ == '/') { len -= 2; - symbol = memchr(ptr, '/', len); - - if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL) + symbol = strchr(ptr, '/'); + + if (symbol && symbol - ptr == 0 && ldaphost) { - uri = malloc(distPoint.len + strlen(ldaphost) + 1); + char uri[BUF_LEN]; /* insert the ldaphost into the uri */ - sprintf(uri, "%.*s%s%.*s" - , (int)(distPoint.len - len), distPoint.ptr - , ldaphost - , (int)len, symbol); - return uri; + snprintf(uri, BUF_LEN, "%.*s%s%.*s", strlen(distPoint)-len, + distPoint, ldaphost, len, symbol); + return strdup(uri); } } } } - + /* default action: copy distributionPoint without change */ - uri = malloc(distPoint.len + 1); - sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr); - return uri; + return strdup(distPoint); } /** @@ -358,39 +334,40 @@ static void fetch_crls(bool cache_crls) while (req != NULL) { + enumerator_t *enumerator; + char *point; bool valid_crl = FALSE; - chunk_t blob = chunk_empty; - generalName_t *gn = req->distributionPoints; const char *ldaphost; ca_info_t *ca; lock_ca_info_list("fetch_crls"); - ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID); + ca = get_ca_info(req->issuer, req->authKeyID); ldaphost = (ca == NULL)? NULL : ca->ldaphost; - while (gn != NULL) + enumerator = req->distributionPoints->create_enumerator(req->distributionPoints); + while (enumerator->enumerate(enumerator, &point)) { - char *uri = complete_uri(gn->name, ldaphost); + x509crl_t *crl; + char *uri; - if (fetch_asn1_blob(uri, &blob)) - { - chunk_t crl_uri = chunk_clone(gn->name); + uri = complete_uri(point, ldaphost); + crl = fetch_crl(uri); + free(uri); - if (insert_crl(blob, crl_uri, cache_crls)) + if (crl) + { + if (insert_crl(crl, point, cache_crls)) { DBG(DBG_CONTROL, DBG_log("we have a valid crl") ) valid_crl = TRUE; - free(uri); break; } } - free(uri); - gn = gn->next; } - + enumerator->destroy(enumerator); unlock_ca_info_list("fetch_crls"); if (valid_crl) @@ -415,19 +392,11 @@ static void fetch_crls(bool cache_crls) static void fetch_ocsp_status(ocsp_location_t* location) { - chunk_t request, response; - char *uri; + chunk_t request = build_ocsp_request(location); + chunk_t response = chunk_empty; - 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'; - - DBG1(" requesting ocsp status from '%s' ...", uri); - if (lib->fetcher->fetch(lib->fetcher, uri, &response, + DBG1(" requesting ocsp status from '%s' ...", location->uri); + if (lib->fetcher->fetch(lib->fetcher, location->uri, &response, FETCH_REQUEST_DATA, request, FETCH_REQUEST_TYPE, "application/ocsp-request", FETCH_END) == SUCCESS) @@ -436,17 +405,16 @@ static void fetch_ocsp_status(ocsp_location_t* location) } else { - DBG1("ocsp request to %s failed", uri); + DBG1("ocsp request to %s failed", location->uri); } - free(uri); free(request.ptr); chunk_free(&location->nonce); /* increment the trial counter of the unresolved fetch requests */ { ocsp_certinfo_t *certinfo = location->certinfo; - + while (certinfo != NULL) { certinfo->trials++; @@ -482,6 +450,9 @@ static void* fetch_thread(void *arg) { struct timespec wait_interval; + /* the fetching thread is only cancellable while waiting for new events */ + thread_cancelability(FALSE); + DBG(DBG_CONTROL, DBG_log("fetch thread started") ) @@ -498,8 +469,11 @@ static void* fetch_thread(void *arg) DBG(DBG_CONTROL, DBG_log("next regular crl check in %ld seconds", crl_check_interval) ) + + thread_cancelability(TRUE); status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex , &wait_interval); + thread_cancelability(FALSE); if (status == ETIMEDOUT) { @@ -519,22 +493,22 @@ static void* fetch_thread(void *arg) fetch_ocsp(); fetch_crls(cache_crls); } + return NULL; } #endif /* THREADS*/ /** * Initializes curl and starts the fetching thread */ -void init_fetch(void) +void fetch_initialize(void) { if (crl_check_interval > 0) { #ifdef THREADS - int status = pthread_create( &thread, NULL, fetch_thread, NULL); - - if (status != 0) + thread = thread_create((thread_main_t)fetch_thread, NULL); + if (thread == NULL) { - plog("fetching thread could not be started, status = %d", status); + plog("fetching thread could not be started"); } #else /* !THREADS */ plog("warning: not compiled with pthread support"); @@ -542,6 +516,23 @@ void init_fetch(void) } } +/** + * Terminates the fetching thread + */ +void fetch_finalize(void) +{ + if (crl_check_interval > 0) + { +#ifdef THREADS + if (thread) + { + thread->cancel(thread); + thread->join(thread); + } +#endif + } +} + void free_crl_fetch(void) { lock_crl_fetch_list("free_crl_fetch"); @@ -568,62 +559,93 @@ void free_ocsp_fetch(void) /** + * Add an additional distribution point + */ +void add_distribution_point(linked_list_t *points, char *new_point) +{ + char *point; + bool add = TRUE; + enumerator_t *enumerator; + + if (new_point == NULL || *new_point == '\0') + { + return; + } + + enumerator = points->create_enumerator(points); + while (enumerator->enumerate(enumerator, &point)) + { + if (streq(point, new_point)) + { + add = FALSE; + break; + } + } + enumerator->destroy(enumerator); + + if (add) + { + points->insert_last(points, strdup(new_point)); + } +} + +/** * Add additional distribution points */ -void add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints) +void add_distribution_points(linked_list_t *points, linked_list_t *new_points) { - while (newPoints != NULL) + char *new_point; + enumerator_t *enumerator; + + enumerator = new_points->create_enumerator(new_points); + while (enumerator->enumerate(enumerator, &new_point)) { - /* skip empty distribution point */ - if (newPoints->name.len > 0) - { - bool add = TRUE; - generalName_t *gn = *distributionPoints; + bool add = TRUE; + char *point; + enumerator_t *enumerator; - while (gn != NULL) + enumerator = points->create_enumerator(points); + while (enumerator->enumerate(enumerator, &point)) + { + if (streq(point, new_point)) { - 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; + add = FALSE; + break; } + } + enumerator->destroy(enumerator); - 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; - } + if (add) + { + points->insert_last(points, strdup(new_point)); } - newPoints = newPoints->next; } + enumerator->destroy(enumerator); } -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(identification_t *issuer, + chunk_t authKeyID, + linked_list_t *distributionPoints) { + char *point; + enumerator_t *enumerator; fetch_req_t *req = malloc_thing(fetch_req_t); - *req = empty_fetch_req; - /* note current time */ - req->installed = time(NULL); + memset(req, 0, sizeof(fetch_req_t)); + req->distributionPoints = linked_list_create(); /* clone fields */ - req->issuer = chunk_clone(issuer); - req->authKeySerialNumber = chunk_clone(authKeySerialNumber); + req->issuer = issuer->clone(issuer); req->authKeyID = chunk_clone(authKeyID); /* copy distribution points */ - add_distribution_points(gn, &req->distributionPoints); + enumerator = distributionPoints->create_enumerator(distributionPoints); + while (enumerator->enumerate(enumerator, &point)) + { + req->distributionPoints->insert_last(req->distributionPoints, + strdup(point)); + } + enumerator->destroy(enumerator); return req; } @@ -640,9 +662,8 @@ void add_crl_fetch_request(fetch_req_t *req) 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))) + if (req->authKeyID.ptr ? same_keyid(req->authKeyID, r->authKeyID) : + req->issuer->equals(req->issuer, r->issuer)) { /* there is already a fetch request */ DBG(DBG_CONTROL, @@ -650,7 +671,8 @@ void add_crl_fetch_request(fetch_req_t *req) ) /* there might be new distribution points */ - add_distribution_points(req->distributionPoints, &r->distributionPoints); + add_distribution_points(r->distributionPoints, + req->distributionPoints); unlock_crl_fetch_list("add_crl_fetch_request"); free_fetch_request(req); @@ -686,17 +708,20 @@ void add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) /** * List all distribution points */ -void list_distribution_points(const generalName_t *gn) +void list_distribution_points(linked_list_t *distributionPoints) { - bool first_gn = TRUE; + char *point; + bool first_point = TRUE; + enumerator_t *enumerator; - while (gn != NULL) + enumerator = distributionPoints->create_enumerator(distributionPoints); + while (enumerator->enumerate(enumerator, &point)) { - whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: " - :" ", (int)gn->name.len, gn->name.ptr); - first_gn = FALSE; - gn = gn->next; + whack_log(RC_COMMENT, " %s '%s'", + (first_point)? "distPts: " : " ", point); + first_point = FALSE; } + enumerator->destroy(enumerator); } /** @@ -712,29 +737,17 @@ void list_crl_fetch_requests(bool utc) if (req != NULL) { whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of CRL fetch requests:"); - whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of CRL Fetch Requests:"); } while (req != NULL) { - 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) + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, " trials: %d", req->trials); + whack_log(RC_COMMENT, " issuer: \"%Y\"", req->issuer); + if (req->authKeyID.ptr) { - datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " authkey: %#B", &req->authKeyID); } list_distribution_points(req->distributionPoints); req = req->next; diff --git a/src/pluto/fetch.h b/src/pluto/fetch.h index f7b4eb074..265dc5fe7 100644 --- a/src/pluto/fetch.h +++ b/src/pluto/fetch.h @@ -13,6 +13,9 @@ * for more details. */ +#include <utils/linked_list.h> +#include <utils/identification.h> + #include "x509.h" #define FETCH_CMD_TIMEOUT 10 /* seconds */ @@ -27,13 +30,11 @@ typedef enum { 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; + int trials; + identification_t *issuer; + chunk_t authKeyID; + linked_list_t *distributionPoints; }; #ifdef THREADS @@ -61,16 +62,20 @@ extern void wake_fetch_thread(const char *who); #define unlock_certs_and_keys(who) /* do nothing */ #define wake_fetch_thread(who) /* do nothing */ #endif -extern void init_fetch(void); +extern void fetch_initialize(void); +extern void fetch_finalize(void); extern void free_crl_fetch(void); extern void free_ocsp_fetch(void); -extern void add_distribution_points(const generalName_t *newPoints - , generalName_t **distributionPoints); -extern fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber - , chunk_t authKeyID, const generalName_t *gn); +extern void add_distribution_point(linked_list_t *points, char* new_point); +extern void add_distribution_points(linked_list_t *points, + linked_list_t *new_points); +extern fetch_req_t* build_crl_fetch_request(identification_t *issuer, + chunk_t authKeyID, + linked_list_t *distributionPoints); extern void add_crl_fetch_request(fetch_req_t *req); -extern void add_ocsp_fetch_request(struct ocsp_location *location, chunk_t serialNumber); -extern void list_distribution_points(const generalName_t *gn); +extern void add_ocsp_fetch_request(struct ocsp_location *location, + chunk_t serialNumber); +extern void list_distribution_points(linked_list_t *distributionPoints); extern void list_crl_fetch_requests(bool utc); extern void list_ocsp_fetch_requests(bool utc); extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data); diff --git a/src/pluto/foodgroups.c b/src/pluto/foodgroups.c index ed9853fc4..e4f9a1d01 100644 --- a/src/pluto/foodgroups.c +++ b/src/pluto/foodgroups.c @@ -48,7 +48,7 @@ static size_t fg_path_space = 0; struct fg_groups { struct fg_groups *next; - struct connection *connection; + connection_t *connection; }; static struct fg_groups *groups = NULL; @@ -78,8 +78,7 @@ struct fg_targets *new_targets; * It returns -1, 0, or +1 if a is, respectively, * less than, equal to, or greater than b. */ -static int -ipcmp(ip_address *a, ip_address *b) +static int ipcmp(ip_address *a, ip_address *b) { if (addrtypeof(a) != addrtypeof(b)) { @@ -105,8 +104,7 @@ ipcmp(ip_address *a, ip_address *b) * It returns -1, 0, or +1 if a is, respectively, * less than, equal to, or greater than b. */ -static int -subnetcmp(const ip_subnet *a, const ip_subnet *b) +static int subnetcmp(const ip_subnet *a, const ip_subnet *b) { ip_address neta, maska, netb, maskb; int r; @@ -121,8 +119,7 @@ subnetcmp(const ip_subnet *a, const ip_subnet *b) return r; } -static void -read_foodgroup(struct fg_groups *g) +static void read_foodgroup(struct fg_groups *g) { const char *fgn = g->connection->name; const ip_subnet *lsn = &g->connection->spd.this.client; @@ -244,8 +241,7 @@ read_foodgroup(struct fg_groups *g) } } -static void -free_targets(void) +static void free_targets(void) { while (targets != NULL) { @@ -257,8 +253,7 @@ free_targets(void) } } -void -load_groups(void) +void load_groups(void) { passert(new_targets == NULL); @@ -341,8 +336,7 @@ load_groups(void) } -void -add_group(struct connection *c) +void add_group(connection_t *c) { struct fg_groups *g = malloc_thing(struct fg_groups); @@ -352,8 +346,7 @@ add_group(struct connection *c) g->connection = c; } -static struct fg_groups * -find_group(const struct connection *c) +static struct fg_groups *find_group(const connection_t *c) { struct fg_groups *g; @@ -362,8 +355,7 @@ find_group(const struct connection *c) return g; } -void -route_group(struct connection *c) +void route_group(connection_t *c) { /* it makes no sense to route a connection that is ISAKMP-only */ if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) @@ -381,7 +373,7 @@ route_group(struct connection *c) { if (t->group == g) { - struct connection *ci = con_by_name(t->name, FALSE); + connection_t *ci = con_by_name(t->name, FALSE); if (ci != NULL) { @@ -395,8 +387,7 @@ route_group(struct connection *c) } } -void -unroute_group(struct connection *c) +void unroute_group(connection_t *c) { struct fg_groups *g = find_group(c); struct fg_targets *t; @@ -407,7 +398,7 @@ unroute_group(struct connection *c) { if (t->group == g) { - struct connection *ci = con_by_name(t->name, FALSE); + connection_t *ci = con_by_name(t->name, FALSE); if (ci != NULL) { @@ -419,8 +410,7 @@ unroute_group(struct connection *c) } } -void -delete_group(const struct connection *c) +void delete_group(const connection_t *c) { struct fg_groups *g; diff --git a/src/pluto/id.c b/src/pluto/id.c deleted file mode 100644 index f34775e68..000000000 --- a/src/pluto/id.c +++ /dev/null @@ -1,523 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> -#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */ -# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */ -#endif -#include <sys/queue.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "id.h" -#include "log.h" -#include "connections.h" -#include "packet.h" -#include "whack.h" - -const struct id empty_id; /* ID_ANY */ - -enum myid_state myid_state = MYID_UNKNOWN; -struct id myids[MYID_SPECIFIED+1]; /* %myid */ -char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */ - -/* initialize id module - * Fills in myid from environment variable IPSECmyid or defaultrouteaddr - */ -void -init_id(void) -{ - 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++) - { - free_id_content(&myids[s]); - free(myid_str[s]); - } -} - -static void -calc_myid_str(enum myid_state s) -{ - /* preformat the ID name */ - char buf[BUF_LEN]; - - 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 - { - 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 */ - - { - 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]; - - (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. - * Note that if the id is to be kept, unshare_id_content will be necessary. - */ -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")) - { - /* 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 - { - 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; -} - - -/* - * Converts a binary key ID into hexadecimal format - */ -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; -} - -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; -} - -int -idtoa(const struct id *id, char *dst, size_t dstlen) -{ - 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 - * by escape sequences consisting of their octal values - */ -void -escape_metachar(const char *src, char *dst, size_t dstlen) -{ - while (*src != '\0' && dstlen > 4) - { - switch (*src) - { - case '\'': - case '\\': - case '"': - case '`': - case '$': - sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src); - dst += 4; - dstlen -= 4; - break; - default: - *dst++ = *src; - dstlen--; - } - src++; - } - *dst = '\0'; -} - - -/* Make private copy of string in struct id. - * This is needed if the result of atoid is to be kept. - */ -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 = 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: - 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_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_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; -} - -/* 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_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_ANY: - return MAX_WILDCARDS; - case ID_DER_ASN1_DN: - return dn_count_wildcards(id->name); - default: - return 0; - } -} - -/* build an ID payload - * Note: no memory is allocated for the body of the payload (tl->ptr). - * We assume it will end up being a pointer into a sufficiently - * stable datastructure. It only needs to last a short time. - */ -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_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); - } -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/id.h b/src/pluto/id.h deleted file mode 100644 index dc2dcdfa6..000000000 --- a/src/pluto/id.h +++ /dev/null @@ -1,65 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _ID_H -#define _ID_H - -#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 */ -}; - -extern void init_id(void); -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 */ -}; - -extern enum myid_state myid_state; -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); -#define resolve_myid(id) ((id)->kind == ID_MYID? &myids[myid_state] : (id)) -extern void set_myFQDN(void); - -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 -extern void escape_metachar(const char *src, char *dst, size_t dstlen); -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 -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) */ -extern void - 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 f833f85b5..7521dd33b 100644 --- a/src/pluto/ike_alg.c +++ b/src/pluto/ike_alg.c @@ -23,6 +23,8 @@ #include <library.h> #include <debug.h> +#include <credentials/keys/public_key.h> +#include <credentials/keys/private_key.h> #include <crypto/hashers/hasher.h> #include <crypto/crypters/crypter.h> #include <crypto/prfs/prf.h> @@ -126,7 +128,7 @@ struct dh_desc *ike_alg_get_dh_group(u_int alg) /** * Get pfsgroup for this connection */ -const struct dh_desc *ike_alg_pfsgroup(struct connection *c, lset_t policy) +const struct dh_desc *ike_alg_pfsgroup(connection_t *c, lset_t policy) { const struct dh_desc *ret = NULL; @@ -141,7 +143,7 @@ const struct dh_desc *ike_alg_pfsgroup(struct connection *c, lset_t policy) /** * Create an OAKLEY proposal based on alg_info and policy */ -struct db_context *ike_alg_db_new(struct connection *c, lset_t policy) +struct db_context *ike_alg_db_new(connection_t *c, lset_t policy) { struct alg_info_ike *ai = c->alg_info_ike; struct db_context *db_ctx = NULL; @@ -176,13 +178,13 @@ struct db_context *ike_alg_db_new(struct connection *c, lset_t policy) enum_show(&oakley_enc_names, ealg)); continue; } - if (!ike_alg_get_hasher(halg)) + 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)) + if (!ike_alg_get_dh_group(modp)) { plog("ike alg: dh group %s not present", enum_show(&oakley_group_names, modp)); @@ -193,20 +195,43 @@ struct db_context *ike_alg_db_new(struct connection *c, lset_t policy) if (policy & POLICY_PUBKEY) { int auth_method = 0; - private_key_t *key = get_private_key(c); + size_t key_size = 0; + key_type_t key_type = KEY_ANY; - if (key == NULL) + + if (c->spd.this.cert) + { + certificate_t *certificate = c->spd.this.cert->cert; + public_key_t *key = certificate->get_public_key(certificate); + + if (key == NULL) + { + plog("ike alg: unable to retrieve my public key"); + continue; + } + key_type = key->get_type(key); + key_size = key->get_keysize(key); + key->destroy(key); + } + else { - plog("ike alg: unable to locate my private key"); - continue; + private_key_t *key = get_private_key(c); + + if (key == NULL) + { + plog("ike alg: unable to retrieve my private key"); + continue; + } + key_type = key->get_type(key); + key_size = key->get_keysize(key); } - switch (key->get_type(key)) + switch (key_type) { case KEY_RSA: auth_method = OAKLEY_RSA_SIG; break; case KEY_ECDSA: - switch (key->get_keysize(key)) + switch (key_size) { case 32: auth_method = OAKLEY_ECDSA_256; @@ -344,7 +369,7 @@ void ike_alg_list(void) * Show IKE algorithms for this connection (result from ike= string) * and newest SA */ -void ike_alg_show_connection(struct connection *c, const char *instance) +void ike_alg_show_connection(connection_t *c, const char *instance) { struct state *st = state_with_serialno(c->newest_isakmp_sa); diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c index 57f4fb54b..1f8917d79 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -25,7 +25,6 @@ #include <resolv.h> #include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> -#include <sys/time.h> /* for gettimeofday */ #include <freeswan.h> @@ -36,12 +35,14 @@ #include <crypto/rngs/rng.h> #include <credentials/keys/private_key.h> #include <credentials/keys/public_key.h> +#include <utils/identification.h> #include "constants.h" #include "defs.h" +#include "myid.h" #include "state.h" -#include "id.h" #include "x509.h" +#include "ac.h" #include "crl.h" #include "ca.h" #include "certs.h" @@ -101,21 +102,24 @@ * 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 != ISAKMP_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) +void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np) { struct isakmp_hdr r_hdr = md->hdr; /* mostly same as incoming header */ r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */ if (enc) + { r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION; + } /* some day, we may have to set r_hdr.isa_version */ r_hdr.isa_np = np; if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) + { impossible(); /* surely must have room and be well-formed */ + } } /* Compute DH shared secret from our local secret and the peer's public value. @@ -172,13 +176,13 @@ static notification_t accept_KE(chunk_t *dest, const char *val_name, 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; + return ISAKMP_INVALID_KEY_INFORMATION; } free(dest->ptr); *dest = chunk_create(pbs->cur, pbs_left(pbs)); *dest = chunk_clone(*dest); DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest); - return NOTHING_WRONG; + return ISAKMP_NOTHING_WRONG; } /* accept_PFS_KE @@ -197,7 +201,7 @@ static notification_t accept_PFS_KE(struct msg_digest *md, chunk_t *dest, if (st->st_pfs_group != NULL) { loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name); - return INVALID_KEY_INFORMATION; + return ISAKMP_INVALID_KEY_INFORMATION; } } else @@ -206,16 +210,16 @@ static notification_t accept_PFS_KE(struct msg_digest *md, chunk_t *dest, { loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" , msg_name); - return INVALID_KEY_INFORMATION; + return ISAKMP_INVALID_KEY_INFORMATION; } if (ke_pd->next != NULL) { loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name); - return INVALID_KEY_INFORMATION; /* ??? */ + return ISAKMP_INVALID_KEY_INFORMATION; /* ??? */ } return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs); } - return NOTHING_WRONG; + return ISAKMP_NOTHING_WRONG; } static bool build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np, @@ -231,39 +235,42 @@ static bool build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np, 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 linked_list_t* collect_rw_ca_candidates(struct msg_digest *md) { - struct connection *d = find_host_connection(&md->iface->addr - , pluto_port, (ip_address*)NULL, md->sender_port, LEMPTY); + linked_list_t *list = linked_list_create(); + connection_t *d; + + d = find_host_connection(&md->iface->addr, pluto_port, (ip_address*)NULL, + md->sender_port, LEMPTY); for (; d != NULL; d = d->hp_next) { /* must be a road warrior connection */ - if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO) - && d->spd.that.ca.ptr != NULL) + if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO) && + d->spd.that.ca) { - generalName_t *gn; + enumerator_t *enumerator; + identification_t *ca; bool new_entry = TRUE; - for (gn = *top; gn != NULL; gn = gn->next) + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &ca)) { - if (same_dn(gn->name, d->spd.that.ca)) + if (ca->equals(ca, d->spd.that.ca)) { new_entry = FALSE; break; - } + } } + enumerator->destroy(enumerator); + if (new_entry) { - gn = malloc_thing(generalName_t); - gn->kind = GN_DIRECTORY_NAME; - gn->name = d->spd.that.ca; - gn->next = *top; - *top = gn; + list->insert_last(list, d->spd.that.ca->clone(d->spd.that.ca)); } } } - return *top != NULL; + return list; } static bool build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, @@ -276,8 +283,9 @@ static bool build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, /* 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 */ @@ -323,24 +331,33 @@ static void send_notification(struct state *sndst, u_int16_t type, 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)) + 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 */ } @@ -358,7 +375,9 @@ static void send_notification(struct state *sndst, u_int16_t type, if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, ¬_pbs) || !out_raw(spi, spisize, ¬_pbs, "spi")) + { impossible(); + } close_output_pbs(¬_pbs); } @@ -393,8 +412,9 @@ static void send_notification(struct state *sndst, u_int16_t type, 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); @@ -405,8 +425,10 @@ static void send_notification(struct state *sndst, u_int16_t type, } 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); @@ -475,7 +497,7 @@ void send_notification_from_md(struct msg_digest *md, u_int16_t type) * st_connection->interface */ struct state st; - struct connection cnx; + connection_t cnx; passert(md); @@ -569,10 +591,14 @@ void send_delete(struct state *st) 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) */ } @@ -595,7 +621,9 @@ void send_delete(struct state *st) 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 @@ -615,7 +643,9 @@ void send_delete(struct state *st) 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); } } @@ -656,8 +686,9 @@ void send_delete(struct state *st) 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; @@ -755,14 +786,15 @@ void accept_delete(struct state *st, struct msg_digest *md, } else { - struct connection *oldc; - + connection_t *oldc; + oldc = cur_connection; set_cur_connection(dst->st_connection); if (nat_traversal_enabled) + { nat_traversal_change_port_lookup(md, dst); - + } loglog(RC_LOG_SERIOUS, "received Delete SA payload: " "deleting ISAKMP State #%lu", dst->st_serialno); delete_state(dst); @@ -790,18 +822,19 @@ void accept_delete(struct state *st, struct msg_digest *md, } else { - struct connection *rc = dst->st_connection; - struct connection *oldc; - + connection_t *rc = dst->st_connection; + connection_t *oldc; + oldc = cur_connection; set_cur_connection(rc); if (nat_traversal_enabled) + { nat_traversal_change_port_lookup(md, dst); - + } if (rc->newest_ipsec_sa == dst->st_serialno && (rc->policy & POLICY_UP)) - { + { /* Last IPSec SA for a permanent connection that we * have initiated. Replace it in a few seconds. * @@ -855,7 +888,9 @@ void close_message(pb_stream *pbs) size_t padding = pad_up(pbs_offset(pbs), 4); if (padding != 0) + { (void) out_zero(padding, pbs, "message padding"); + } close_output_pbs(pbs); } @@ -864,15 +899,14 @@ void close_message(pb_stream *pbs) * Note: this is not called from demux.c */ static stf_status -main_outI1(int whack_sock, struct connection *c, struct state *predecessor +main_outI1(int whack_sock, connection_t *c, struct state *predecessor , lset_t policy, unsigned long try) { struct state *st = new_state(); pb_stream reply; /* not actually a reply, but you know what I mean */ pb_stream rbody; - int vids_to_send = 0; - + /* set up new state */ st->st_connection = c; set_cur_state(st); /* we must reset before exit */ @@ -883,30 +917,48 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor /* 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) + } + if (c->spd.this.cert && + c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) + { vids_to_send++; + } if (SEND_XAUTH_VID) + { vids_to_send++; + } + /* always send DPD Vendor ID */ - vids_to_send++; + vids_to_send++; + if (nat_traversal_enabled) + { vids_to_send++; + } get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr); insert_state(st); /* needs cookies, connection, and msgid (0) */ if (HAS_IPSEC_POLICY(policy)) + { add_pending(dup_any(whack_sock), st, c, policy, 1 , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno); - + } if (predecessor == NULL) + { plog("initiating Main Mode"); + } else + { plog("initiating Main Mode to replace #%lu", predecessor->st_serialno); + } /* set up reply */ init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); @@ -970,7 +1022,8 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor /* 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 (c->spd.this.cert && + c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) { if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE , &rbody, VID_OPENPGP)) @@ -1042,7 +1095,7 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor return STF_OK; } -void ipsecdoi_initiate(int whack_sock, struct connection *c, lset_t policy, +void ipsecdoi_initiate(int whack_sock, connection_t *c, lset_t policy, unsigned long try, so_serial_t replacing) { /* If there's already an ISAKMP SA established, use that and @@ -1155,7 +1208,7 @@ static bool skeyid_preshared(struct state *st) { loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", pseudo_random_function_names, prf_alg); - return FALSE; + return FALSE; } free(st->st_skeyid.ptr); prf->set_key(prf, *pss); @@ -1166,8 +1219,7 @@ static bool skeyid_preshared(struct state *st) } } -static bool -skeyid_digisig(struct state *st) +static bool skeyid_digisig(struct state *st) { chunk_t nir; pseudo_random_function_t prf_alg; @@ -1234,12 +1286,9 @@ static bool generate_skeyids_iv(struct state *st) /* 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 seed_skeyid_d = chunk_from_chars(0x00); + chunk_t seed_skeyid_a = chunk_from_chars(0x01); + chunk_t seed_skeyid_e = chunk_from_chars(0x02); chunk_t icookie = { st->st_icookie, COOKIE_SIZE }; chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE }; pseudo_random_function_t prf_alg; @@ -1254,7 +1303,7 @@ static bool generate_skeyids_iv(struct state *st) 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); + prf->allocate_bytes(prf, seed_skeyid_d, &st->st_skeyid_d); /* SKEYID_A */ free(st->st_skeyid_a.ptr); @@ -1262,7 +1311,7 @@ static bool generate_skeyids_iv(struct state *st) 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); + prf->allocate_bytes(prf, seed_skeyid_a, &st->st_skeyid_a); /* SKEYID_E */ free(st->st_skeyid_e.ptr); @@ -1270,7 +1319,7 @@ static bool generate_skeyids_iv(struct state *st) 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->allocate_bytes(prf, seed_skeyid_e, &st->st_skeyid_e); prf->destroy(prf); } @@ -1289,7 +1338,7 @@ static bool generate_skeyids_iv(struct state *st) 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); @@ -1302,15 +1351,14 @@ static bool generate_skeyids_iv(struct state *st) */ { 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); + chunk_t seed = chunk_from_chars(0x00); size_t prf_block_size, i; pseudo_random_function_t prf_alg; prf_t *prf; @@ -1319,7 +1367,7 @@ static bool generate_skeyids_iv(struct state *st) 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]); @@ -1336,7 +1384,7 @@ static bool generate_skeyids_iv(struct state *st) else { st->st_enc_key = chunk_create(st->st_skeyid_e.ptr, keysize); - } + } st->st_enc_key = chunk_clone(st->st_enc_key); } @@ -1421,7 +1469,7 @@ static bool generate_skeyids_iv(struct state *st) * Use PKCS#1 version 1.5 encryption of hash (called * RSAES-PKCS1-V1_5) in PKCS#2. */ -static size_t sign_hash(signature_scheme_t scheme, struct connection *c, +static size_t sign_hash(signature_scheme_t scheme, connection_t *c, u_char sig_val[RSA_MAX_OCTETS], chunk_t hash) { size_t sz = 0; @@ -1469,7 +1517,9 @@ static size_t sign_hash(signature_scheme_t scheme, struct connection *c, ) 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; @@ -1487,7 +1537,7 @@ static size_t sign_hash(signature_scheme_t scheme, struct connection *c, */ struct tac_state { struct state *st; - chunk_t hash; + chunk_t hash; chunk_t sig; int tried_cnt; /* number of keys tried */ }; @@ -1495,17 +1545,18 @@ struct tac_state { static bool take_a_crack(struct tac_state *s, pubkey_t *kr) { public_key_t *pub_key = kr->public_key; - identification_t *keyid = pub_key->get_id(pub_key, ID_PUBKEY_INFO_SHA1); + chunk_t keyid = chunk_empty; signature_scheme_t scheme; s->tried_cnt++; scheme = oakley_to_signature_scheme(s->st->st_oakley.auth); + pub_key->get_fingerprint(pub_key, KEY_ID_PUBKEY_INFO_SHA1, &keyid); if (pub_key->verify(pub_key, scheme, s->hash, s->sig)) { DBG(DBG_CRYPT | DBG_CONTROL, - DBG_log("%s check passed with keyid %Y", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), keyid) + DBG_log("%s check passed with keyid %#B", + enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) ) unreference_key(&s->st->st_peer_pubkey); s->st->st_peer_pubkey = reference_key(kr); @@ -1514,14 +1565,14 @@ static bool take_a_crack(struct tac_state *s, pubkey_t *kr) else { DBG(DBG_CRYPT, - DBG_log("%s check failed with keyid %Y", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), keyid) + DBG_log("%s check failed with keyid %#B", + enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) ) return FALSE; } } -static stf_status check_signature(key_type_t key_type, const struct id* peer, +static stf_status check_signature(key_type_t key_type, identification_t* peer, struct state *st, chunk_t hash, const pb_stream *sig_pbs, #ifdef USE_KEYRR @@ -1529,7 +1580,7 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer, #endif /* USE_KEYRR */ const struct gw_info *gateways_from_dns) { - const struct connection *c = st->st_connection; + const connection_t *c = st->st_connection; struct tac_state s; s.st = st; @@ -1545,7 +1596,8 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer, 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)&& + if (gw->gw_key_present && + gw->gw_id->equals(gw->gw_id, c->spd.that.id) && take_a_crack(&s, gw->key)) { return STF_OK; @@ -1564,7 +1616,7 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer, pubkey_t *key = p->key; key_type_t type = key->public_key->get_type(key->public_key); - if (type == key_type && same_id(peer, &key->id)) + if (type == key_type && peer->equals(peer, key->id)) { time_t now = time(NULL); @@ -1576,7 +1628,6 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer, *pp = free_public_keyentry(p); continue; /* continue with next public key */ } - if (take_a_crack(&s, key)) { return STF_OK; @@ -1628,34 +1679,30 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer, /* no acceptable key was found: diagnose */ { - char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */ - - idtoa(peer, id_buf, sizeof(id_buf)); - if (s.tried_cnt == 0) { - loglog(RC_LOG_SERIOUS, "no public key known for '%s'", id_buf); + loglog(RC_LOG_SERIOUS, "no public key known for '%Y'", peer); } else if (s.tried_cnt == 1) { - loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: " - " wrong key?; tried %d", id_buf, s.tried_cnt); + loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " + " wrong key?; tried %d", peer, s.tried_cnt); DBG(DBG_CONTROL, - DBG_log("public key for '%s' failed: " - "decrypted SIG payload into a malformed ECB", id_buf) + DBG_log("public key for '%Y' failed: " + "decrypted SIG payload into a malformed ECB", peer) ) } else { - loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: " - "tried %d keys but none worked.", id_buf, s.tried_cnt); + loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " + "tried %d keys but none worked.", peer, s.tried_cnt); DBG(DBG_CONTROL, - DBG_log("all %d public keys for '%s' failed: " + DBG_log("all %d public keys for '%Y' failed: " "best decrypted SIG payload into a malformed ECB", - s.tried_cnt, id_buf) + s.tried_cnt, peer) ) } - return STF_FAIL + INVALID_KEY_INFORMATION; + return STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; } } @@ -1669,12 +1716,12 @@ static notification_t accept_nonce(struct msg_digest *md, chunk_t *dest, { loglog(RC_LOG_SERIOUS, "%s length not between %d and %d" , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE); - return PAYLOAD_MALFORMED; /* ??? */ + return ISAKMP_PAYLOAD_MALFORMED; /* ??? */ } free(dest->ptr); *dest = chunk_create(nonce_pbs->cur, len); *dest = chunk_clone(*dest); - return NOTHING_WRONG; + return ISAKMP_NOTHING_WRONG; } /* encrypt message, sans fixed part of header @@ -1682,8 +1729,7 @@ static notification_t accept_nonce(struct msg_digest *md, chunk_t *dest, * The theory is that there will be no "backing out", so we commit to IV. * We also close the pbs. */ -bool -encrypt_message(pb_stream *pbs, struct state *st) +bool encrypt_message(pb_stream *pbs, struct state *st) { u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr); size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); @@ -1723,7 +1769,7 @@ encrypt_message(pb_stream *pbs, struct state *st) 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); @@ -1755,7 +1801,7 @@ static size_t quick_mode_hash12(u_char *dest, u_char *start, u_char *roof, 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); @@ -1775,13 +1821,12 @@ static size_t quick_mode_hash12(u_char *dest, u_char *start, u_char *roof, */ static size_t quick_mode_hash3(u_char *dest, struct state *st) { - char seed_buf[] = { 0x00 }; - chunk_t seed_chunk = chunk_from_buf(seed_buf); + chunk_t seed_chunk = chunk_from_chars(0x00); chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); pseudo_random_function_t prf_alg; prf_t *prf; size_t prf_block_size; - + prf_alg = oakley_to_prf(st->st_oakley.hash); prf = lib->crypto->create_prf(lib->crypto, prf_alg); prf->set_key(prf, st->st_skeyid_a); @@ -1814,7 +1859,7 @@ void init_phase2_iv(struct state *st, const msgid_t *msgid) 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); @@ -1846,27 +1891,30 @@ static bool emit_subnet_id(ip_subnet *net, u_int8_t np, u_int8_t protoid, id.isaiid_port = port; if (!out_struct(&id, &isakmp_ipsec_identification_desc, outs, &id_pbs)) + { return FALSE; - + } networkof(net, &ta); tal = addrbytesptr(&ta, &tbp); if (!out_raw(tbp, tal, &id_pbs, "client network")) + { return FALSE; - + } if (!subnetishost(net)) { maskof(net, &ta); tal = addrbytesptr(&ta, &tbp); if (!out_raw(tbp, tal, &id_pbs, "client mask")) + { return FALSE; + } } - close_output_pbs(&id_pbs); return TRUE; } stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, - struct connection *c, lset_t policy, unsigned long try, + connection_t *c, lset_t policy, unsigned long try, so_serial_t replacing) { struct state *st = duplicate_state(isakmp_sa); @@ -1878,10 +1926,27 @@ stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, 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; + if (c->spd.this.modecfg && !c->spd.this.has_client && + isanyaddr(&c->spd.this.host_srcip)) + { + connection_t *ph1_c = isakmp_sa->st_connection; + + if (ph1_c->spd.this.modecfg && !isanyaddr(&ph1_c->spd.this.host_srcip)) + { + char srcip[ADDRTOT_BUF]; + + c->spd.this.host_srcip = ph1_c->spd.this.host_srcip; + c->spd.this.client = ph1_c->spd.this.client; + c->spd.this.has_client = TRUE; + addrtot(&c->spd.this.host_srcip, 0, srcip, sizeof(srcip)); + plog("inheriting virtual IP source address %s from ModeCfg", srcip); + } + } + st->st_whack_sock = whack_sock; st->st_connection = c; set_cur_state(st); /* we must reset before exit */ @@ -1899,27 +1964,30 @@ stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, 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); + { + 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); - + { + 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) @@ -1957,13 +2025,15 @@ stf_status quick_outI1(int whack_sock, struct state *isakmp_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: @@ -1979,11 +2049,12 @@ stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, 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)) + } + 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; @@ -2063,14 +2134,18 @@ stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, 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; } @@ -2092,35 +2167,45 @@ static void decode_cert(struct msg_digest *md) blob.len = pbs_left(&p->pbs); if (cert->isacert_type == CERT_X509_SIGNATURE) { - x509cert_t cert = empty_x509cert; - if (parse_x509cert(blob, 0, &cert)) + cert_t x509cert = cert_empty; + + x509cert.cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); + if (x509cert.cert) { - if (verify_x509cert(&cert, strict_crl_policy, &valid_until)) + if (verify_x509cert(&x509cert, strict_crl_policy, &valid_until)) { DBG(DBG_PARSING, DBG_log("Public key validated") ) - add_x509_public_key(&cert, valid_until, DAL_SIGNED); + add_public_key_from_cert(&x509cert, 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); + x509cert.cert->destroy(x509cert.cert); } else + { plog("Syntax error in X.509 certificate"); + } } else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509) { - x509cert_t *cert = NULL; + linked_list_t *certs = linked_list_create(); - if (pkcs7_parse_signedData(blob, NULL, &cert, NULL, NULL)) - store_x509certs(&cert, strict_crl_policy); + if (pkcs7_parse_signedData(blob, NULL, certs, NULL, NULL)) + { + store_x509certs(certs, strict_crl_policy); + } else + { plog("Syntax error in PKCS#7 wrapped X.509 certificates"); + } + certs->destroy_offset(certs, offsetof(certificate_t, destroy)); } else { @@ -2134,7 +2219,7 @@ static void decode_cert(struct msg_digest *md) /* * Decode the CR payload of Phase 1. */ -static void decode_cr(struct msg_digest *md, struct connection *c) +static void decode_cr(struct msg_digest *md, connection_t *c) { struct payload_digest *p; @@ -2142,7 +2227,7 @@ static void decode_cr(struct msg_digest *md, struct connection *c) { 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; @@ -2150,32 +2235,37 @@ static void decode_cr(struct msg_digest *md, struct connection *c) if (cr->isacr_type == CERT_X509_SIGNATURE) { - char buf[BUF_LEN]; - if (ca_name.len > 0) { - generalName_t *gn; - + identification_t *ca; + 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; + } + if (c->requested_ca == NULL) + { + c->requested_ca = linked_list_create(); + } + ca = identification_create_from_encoding(ID_DER_ASN1_DN, ca_name); + c->requested_ca->insert_last(c->requested_ca, ca); + DBG(DBG_PARSING | DBG_CONTROL, + DBG_log("requested CA: \"%Y\"", ca) + ) + } + else + { + DBG(DBG_PARSING | DBG_CONTROL, + DBG_log("requested CA: %%any") + ) } c->got_certrequest = TRUE; - - 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)); + } } } @@ -2184,12 +2274,13 @@ static void decode_cr(struct msg_digest *md, struct connection *c) * 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) +static bool decode_peer_id(struct msg_digest *md, identification_t **peer) { struct state *const st = md->st; struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID]; const pb_stream *const id_pbs = &id_pld->pbs; struct isakmp_id *const id = &id_pld->payload.id; + chunk_t id_payload; /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused. * It talks about the protocol ID and Port fields of the ID @@ -2218,74 +2309,50 @@ static bool decode_peer_id(struct msg_digest *md, struct id *peer) return FALSE; } - peer->kind = id->isaid_idtype; + id_payload = chunk_create(id_pbs->cur, pbs_left(id_pbs)); - switch (peer->kind) + switch (id->isaid_idtype) { - 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) + case ID_IPV4_ADDR: + if (id_payload.len != 4) { - loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s" - , enum_show(&ident_names, peer->kind), ugh); - /* XXX Could send notification back */ + loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", + enum_show(&ident_names, id->isaid_idtype)); 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)); + break; + case ID_IPV6_ADDR: + if (id_payload.len != 16) + { + loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", + enum_show(&ident_names, id->isaid_idtype)); + return FALSE; + } + break; + case ID_USER_FQDN: + case ID_FQDN: + if (memchr(id_payload.ptr, '\0', id_payload.len) != NULL) + { + loglog(RC_LOG_SERIOUS, "%s Phase 1 ID payload contains " + "a NUL character", + enum_show(&ident_names, id->isaid_idtype)); + return FALSE; + } + break; + case ID_KEY_ID: + case ID_DER_ASN1_DN: + break; + default: + /* XXX Could send notification back */ + loglog(RC_LOG_SERIOUS, "unacceptable identity type (%s) " + "in Phase 1 ID payload", + enum_show(&ident_names, id->isaid_idtype)); return FALSE; - } - - /* ??? ought to do some more sanity check, but what? */ - - peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); - break; - - case ID_KEY_ID: - peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); - DBG(DBG_PARSING, - DBG_dump_chunk("KEY ID:", peer->name)); - break; - - case ID_DER_ASN1_DN: - peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); - DBG(DBG_PARSING, - DBG_dump_chunk("DER ASN1 DN:", peer->name)); - break; - - default: - /* XXX Could send notification back */ - loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload" - , enum_show(&ident_names, peer->kind)); - return FALSE; } + *peer = identification_create_from_encoding(id->isaid_idtype, id_payload); - { - char buf[BUF_LEN]; - - idtoa(peer, buf, sizeof(buf)); - plog("Peer ID is %s: '%s'", - enum_show(&ident_names, id->isaid_idtype), buf); - } + plog("Peer ID is %s: '%Y'", enum_show(&ident_names, id->isaid_idtype), + *peer); /* check for certificates */ decode_cert(md); @@ -2298,45 +2365,51 @@ static bool 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, +static bool switch_connection(struct msg_digest *md, identification_t *peer, bool initiator) { struct state *const st = md->st; - struct connection *c = st->st_connection; - - chunk_t peer_ca = (st->st_peer_pubkey != NULL) - ? st->st_peer_pubkey->issuer : chunk_empty; + connection_t *c = st->st_connection; + identification_t *peer_ca; - DBG(DBG_CONTROL, - char buf[BUF_LEN]; - - dntoa_or_null(buf, BUF_LEN, peer_ca, "%none"); - DBG_log("peer CA: '%s'", buf); - ) + peer_ca = st->st_peer_pubkey ? st->st_peer_pubkey->issuer : NULL; + if (peer_ca) + { + DBG(DBG_CONTROL, + DBG_log("peer CA: \"%Y\"", peer_ca) + ) + } + else + { + DBG(DBG_CONTROL, + DBG_log("peer CA: %%none") + ) + } if (initiator) { int pathlen; - if (!same_id(&c->spd.that.id, peer)) + if (!peer->equals(peer, c->spd.that.id)) { - 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); + loglog(RC_LOG_SERIOUS, + "we require peer to have ID '%Y', but peer declares '%Y'", + c->spd.that.id, peer); return FALSE; } - DBG(DBG_CONTROL, - char buf[BUF_LEN]; - - dntoa_or_null(buf, BUF_LEN, c->spd.that.ca, "%none"); - DBG_log("required CA: '%s'", buf); - ) + if (c->spd.that.ca) + { + DBG(DBG_CONTROL, + DBG_log("required CA: \"%s\"", c->spd.that.ca); + ) + } + else + { + DBG(DBG_CONTROL, + DBG_log("required CA: %%none"); + ) + } if (!trusted_ca(peer_ca, c->spd.that.ca, &pathlen)) { @@ -2347,7 +2420,7 @@ static bool switch_connection(struct msg_digest *md, struct id *peer, } else { - struct connection *r; + connection_t *r; /* check for certificate requests */ decode_cr(md, c); @@ -2355,24 +2428,31 @@ static bool switch_connection(struct msg_digest *md, struct id *peer, r = refine_host_connection(st, peer, peer_ca); /* delete the collected certificate requests */ - free_generalNames(c->requested_ca, TRUE); - c->requested_ca = NULL; + if (c->requested_ca) + { + c->requested_ca->destroy_offset(c->requested_ca, + offsetof(identification_t, destroy)); + c->requested_ca = NULL; + } if (r == NULL) { - char buf[BUF_LEN]; - - idtoa(peer, buf, sizeof(buf)); - loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf); + loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%Y'", peer); return FALSE; } - DBG(DBG_CONTROL, - char buf[BUF_LEN]; - - dntoa_or_null(buf, BUF_LEN, r->spd.this.ca, "%none"); - DBG_log("offered CA: '%s'", buf); - ) + if (r->spd.this.ca) + { + DBG(DBG_CONTROL, + DBG_log("offered CA: \"%Y\"", r->spd.this.ca) + ) + } + else + { + DBG(DBG_CONTROL, + DBG_log("offered CA: %%none") + ) + } if (r != c) { @@ -2396,10 +2476,9 @@ static bool switch_connection(struct msg_digest *md, struct id *peer, } else if (c->spd.that.has_id_wildcards) { - free_id_content(&c->spd.that.id); - c->spd.that.id = *peer; + c->spd.that.id->destroy(c->spd.that.id); + c->spd.that.id = peer->clone(peer); c->spd.that.has_id_wildcards = FALSE; - unshare_id_content(&c->spd.that.id); } } return TRUE; @@ -2489,13 +2568,19 @@ static bool decode_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, 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)" @@ -2528,8 +2613,10 @@ static bool decode_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, } 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" @@ -2540,7 +2627,9 @@ static bool decode_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, 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]; @@ -2582,8 +2671,9 @@ static bool check_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, ip_subnet net_temp; if (!decode_net_id(id, id_pbs, &net_temp, which)) + { return FALSE; - + } if (!samesubnet(net, &net_temp) || *protoid != id->isaiid_protoid || *port != id->isaiid_port) { @@ -2598,7 +2688,7 @@ static bool check_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, */ static bool has_preloaded_public_key(struct state *st) { - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; /* do not consider rw connections since * the peer's identity must be known @@ -2613,7 +2703,8 @@ static bool has_preloaded_public_key(struct state *st) 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) && + if (type == KEY_RSA && + c->spd.that.id->equals(c->spd.that.id, key->id) && key->until_time == UNDEFINED_TIME) { /* found a preloaded public key */ @@ -2646,7 +2737,7 @@ static void compute_proto_keymat(struct state *st, u_int8_t protoid, if (needed_len && pi->attrs.key_len) { needed_len = pi->attrs.key_len / BITS_PER_BYTE; - } + } switch (pi->attrs.transid) { @@ -2745,7 +2836,7 @@ static void compute_proto_keymat(struct state *st, u_int8_t protoid, 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 */ @@ -2785,9 +2876,13 @@ static void compute_proto_keymat(struct state *st, u_int8_t protoid, 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 bool uses_pubkey_auth(int auth) @@ -2807,6 +2902,38 @@ static bool uses_pubkey_auth(int auth) } } +/* build an ID payload + * Note: no memory is allocated for the body of the payload (tl->ptr). + * We assume it will end up being a pointer into a sufficiently + * stable datastructure. It only needs to last a short time. + */ +static void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) +{ + identification_t *id = resolve_myid(end->id); + + zero(hd); + hd->isaiid_idtype = id->get_type(id); + + switch (id->get_type(id)) + { + case ID_ANY: + hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr; + tl->len = addrbytesptr(&end->host_addr, + (const unsigned char **)&tl->ptr); /* sets tl->ptr too */ + break; + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + case ID_FQDN: + case ID_USER_FQDN: + case ID_DER_ASN1_DN: + case ID_KEY_ID: + *tl = id->get_encoding(id); + break; + default: + bad_case(id->get_type(id)); + } +} + /* State Transition Functions. * * The definition of state_microcode_table in demux.c is a good @@ -2833,7 +2960,7 @@ 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; + connection_t *c; struct isakmp_proposal proposal; pb_stream proposal_pbs; pb_stream r_sa_pbs; @@ -2877,7 +3004,7 @@ stf_status main_inI1_outR1(struct msg_digest *md) * but Food Groups kind of assumes one. */ { - struct connection *d; + connection_t *d; d = find_host_connection(&md->iface->addr , pluto_port, (ip_address*)NULL, md->sender_port, policy); @@ -2936,7 +3063,7 @@ stf_status main_inI1_outR1(struct msg_digest *md) /* 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); + c = rw_instantiate(c, &md->sender, md->sender_port, NULL, c->spd.that.id); } /* Set up state */ @@ -3126,7 +3253,7 @@ stf_status main_inR1_outI2(struct msg_digest *md) { 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(ISAKMP_BAD_PROPOSAL_SYNTAX); } RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit , &proposal_pbs, &proposal, NULL, st, TRUE)); @@ -3155,35 +3282,46 @@ stf_status main_inR1_outI2(struct msg_digest *md) /* KE out */ if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group , &md->rbody, ISAKMP_NEXT_NONCE)) + { return STF_INTERNAL_ERROR; + } #ifdef DEBUG /* Ni out */ if (!build_and_ship_nonce(&st->st_ni, &md->rbody , (cur_debugging & IMPAIR_BUST_MI2)? ISAKMP_NEXT_VID : np, "Ni")) + { return STF_INTERNAL_ERROR; - + } if (cur_debugging & IMPAIR_BUST_MI2) { /* generate a pointless large VID payload to push message over MTU */ pb_stream vid_pbs; if (!out_generic(np, &isakmp_vendor_id_desc, &md->rbody, &vid_pbs)) + { return STF_INTERNAL_ERROR; + } if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID")) + { return STF_INTERNAL_ERROR; + } close_output_pbs(&vid_pbs); } #else /* Ni out */ if (!build_and_ship_nonce(&st->st_ni, &md->rbody, np, "Ni")) + { return STF_INTERNAL_ERROR; + } #endif if (st->nat_traversal & NAT_T_WITH_NATD) { if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) + { return STF_INTERNAL_ERROR; + } } /* finish message */ @@ -3251,15 +3389,18 @@ stf_status main_inI2_outR2(struct msg_digest *md) /* 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 + 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 */ @@ -3267,9 +3408,13 @@ stf_status main_inI2_outR2(struct msg_digest *md) 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 @@ -3284,33 +3429,50 @@ stf_status main_inI2_outR2(struct msg_digest *md) { if (st->st_connection->kind == CK_PERMANENT) { - if (!build_and_ship_CR(CERT_X509_SIGNATURE - , st->st_connection->spd.that.ca - , &md->rbody, np)) + identification_t *ca = st->st_connection->spd.that.ca; + chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; + + if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, np)) + { return STF_INTERNAL_ERROR; + } } else { - generalName_t *ca = NULL; + linked_list_t *list = collect_rw_ca_candidates(md); + int count = list->get_count(list); + bool error = FALSE; - if (collect_rw_ca_candidates(md, &ca)) + if (count) { - generalName_t *gn; + enumerator_t *enumerator; + identification_t *ca; - for (gn = ca; gn != NULL; gn = gn->next) + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &ca)) { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, gn->name - , &md->rbody - , gn->next == NULL ? np : ISAKMP_NEXT_CR)) - return STF_INTERNAL_ERROR; + if (!build_and_ship_CR(CERT_X509_SIGNATURE, + ca->get_encoding(ca), &md->rbody, + --count ? ISAKMP_NEXT_CR : np)) + { + error = TRUE; + break; + } } - free_generalNames(ca, FALSE); + enumerator->destroy(enumerator); } else { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, chunk_empty - , &md->rbody, np)) - return STF_INTERNAL_ERROR; + if (!build_and_ship_CR(CERT_X509_SIGNATURE, chunk_empty, + &md->rbody, np)) + { + error = TRUE; + } + } + list->destroy_offset(list, offsetof(identification_t, destroy)); + if (error) + { + return STF_INTERNAL_ERROR; } } } @@ -3318,7 +3480,9 @@ stf_status main_inI2_outR2(struct msg_digest *md) 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 */ @@ -3329,7 +3493,9 @@ stf_status main_inI2_outR2(struct msg_digest *md) */ compute_dh_shared(st, st->st_gi); if (!generate_skeyids_iv(st)) - return STF_FAIL + AUTHENTICATION_FAILED; + { + return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; + } update_iv(st); return STF_OK; @@ -3350,9 +3516,10 @@ 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; + + connection_t *c = st->st_connection; + certpolicy_t cert_policy = c->spd.this.sendcert; + cert_t *mycert = c->spd.this.cert; bool requested, send_cert, send_cr; bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); @@ -3365,22 +3532,26 @@ stf_status main_inR2_outI3(struct msg_digest *md) 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); + c->got_certrequest = FALSE; + decode_cr(md, c); /* 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; + if (c->requested_ca) + { + c->requested_ca->destroy_offset(c->requested_ca, + offsetof(identification_t, destroy)); + c->requested_ca = NULL; + } /* send certificate if auth is RSA, we have one and we want * or are requested to send it */ - requested = cert_policy == CERT_SEND_IF_ASKED - && st->st_connection->got_certrequest; - send_cert = pubkey_auth && mycert.type != CERT_NONE - && (cert_policy == CERT_ALWAYS_SEND || requested); + requested = cert_policy == CERT_SEND_IF_ASKED && c->got_certrequest; + send_cert = pubkey_auth && mycert && + mycert->cert->get_type(mycert->cert) == CERT_X509 && + (cert_policy == CERT_ALWAYS_SEND || requested); /* send certificate request if we don't have a preloaded RSA public key */ send_cr = !no_cr_send && send_cert && !has_preloaded_public_key(st); @@ -3388,8 +3559,9 @@ stf_status main_inR2_outI3(struct msg_digest *md) /* done parsing; initialize crypto */ compute_dh_shared(st, st->st_gr); if (!generate_skeyids_iv(st)) - return STF_FAIL + AUTHENTICATION_FAILED; - + { + return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; + } if (st->nat_traversal & NAT_T_WITH_NATD) { nat_traversal_natd_lookup(md); @@ -3413,11 +3585,13 @@ stf_status main_inR2_outI3(struct msg_digest *md) struct isakmp_ipsec_id id_hd; chunk_t id_b; - build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this); + build_id_payload(&id_hd, &id_b, &c->spd.this); id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload; if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs) || !out_chunk(id_b, &id_pbs, "my identity")) + { return STF_INTERNAL_ERROR; + } close_output_pbs(&id_pbs); } @@ -3427,12 +3601,14 @@ stf_status main_inR2_outI3(struct msg_digest *md) DBG(DBG_CONTROL, DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) ) - if (mycert.type != CERT_NONE) + if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) { const char *request_text = ""; if (cert_policy == CERT_SEND_IF_ASKED) + { request_text = (send_cert)? "upon request":"without request"; + } plog("we have a cert %s sending it %s" , send_cert? "and are":"but are not", request_text); } @@ -3443,31 +3619,43 @@ stf_status main_inR2_outI3(struct msg_digest *md) } if (send_cert) { + bool success; + chunk_t cert_encoding; pb_stream cert_pbs; struct isakmp_cert cert_hd; cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG; - cert_hd.isacert_type = mycert.type; + cert_hd.isacert_type = CERT_X509_SIGNATURE; if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) + { return STF_INTERNAL_ERROR; - if (!out_chunk(cert_get_encoding(mycert), &cert_pbs, "CERT")) + } + cert_encoding = mycert->cert->get_encoding(mycert->cert); + success = out_chunk(cert_encoding, &cert_pbs, "CERT"); + free(cert_encoding.ptr); + if (!success) + { return STF_INTERNAL_ERROR; + } close_output_pbs(&cert_pbs); } /* CR out */ if (send_cr) { - if (!build_and_ship_CR(mycert.type, st->st_connection->spd.that.ca - , &md->rbody, ISAKMP_NEXT_SIG)) + identification_t *ca = st->st_connection->spd.that.ca; + chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; + + if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, ISAKMP_NEXT_SIG)) + { return STF_INTERNAL_ERROR; + } } /* HASH_I or SIG_I out */ { - u_char hash_buf[MAX_DIGEST_LEN]; - chunk_t hash = chunk_from_buf(hash_buf); + chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); main_mode_hash(st, &hash, TRUE, &id_pbs); @@ -3489,16 +3677,18 @@ stf_status main_inR2_outI3(struct msg_digest *md) scheme = oakley_to_signature_scheme(st->st_oakley.auth); - sig_len = sign_hash(scheme, st->st_connection, sig_val, hash); + sig_len = sign_hash(scheme, c, sig_val, hash); if (sig_len == 0) { loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + AUTHENTICATION_FAILED; + return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; } if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc , &md->rbody, sig_val, sig_len, "SIG_I")) + { return STF_INTERNAL_ERROR; + } } } @@ -3506,8 +3696,9 @@ stf_status main_inR2_outI3(struct msg_digest *md) /* 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; } @@ -3534,13 +3725,10 @@ struct key_continuation { 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) +static void report_key_dns_failure(identification_t *id, err_t ugh) { - 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); + loglog(RC_LOG_SERIOUS, "no RSA public key known for '%Y'" + "; DNS search for KEY failed (%s)", id, ugh); } @@ -3558,15 +3746,16 @@ main_id_and_auth(struct msg_digest *md , const struct key_continuation *kc /* current state, can be NULL */ ) { - u_char hash_buf[MAX_DIGEST_LEN]; - chunk_t hash = chunk_from_buf(hash_buf); + chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); struct state *st = md->st; - struct id peer; + identification_t *peer; stf_status r = STF_OK; /* ID Payload in */ if (!decode_peer_id(md, &peer)) - return STF_FAIL + INVALID_ID_INFORMATION; + { + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; + } /* Hash the ID Payload. * main_mode_hash requires idpl->cur to be at end of payload @@ -3596,7 +3785,7 @@ main_id_and_auth(struct msg_digest *md , 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; + r = STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; } } break; @@ -3604,14 +3793,14 @@ main_id_and_auth(struct msg_digest *md case OAKLEY_RSA_SIG: case XAUTHInitRSA: case XAUTHRespRSA: - r = check_signature(KEY_RSA, &peer, st, hash, - &md->chain[ISAKMP_NEXT_SIG]->pbs, + 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 + kc == NULL ? NULL : kc->ac.gateways_from_dns ); - + if (r == STF_SUSPEND) { /* initiate/resume asynchronous DNS lookup for key */ @@ -3634,22 +3823,14 @@ main_id_and_auth(struct msg_digest *md #ifdef USE_KEYRR nkc->failure_ok = TRUE; #endif - ugh = start_adns_query(&peer - , &peer /* SG itself */ - , T_TXT - , cont_fn - , &nkc->ac); + ugh = start_adns_query(peer, peer, T_TXT, cont_fn, &nkc->ac); break; #ifdef USE_KEYRR case kos_his_txt: /* second try: look for the KEY records */ nkc->step = kos_his_key; - ugh = start_adns_query(&peer - , NULL /* no sgw for KEY */ - , T_KEY - , cont_fn - , &nkc->ac); + ugh = start_adns_query(peer, NULL, T_KEY, cont_fn, &nkc->ac); break; #endif /* USE_KEYRR */ @@ -3659,9 +3840,9 @@ main_id_and_auth(struct msg_digest *md if (ugh != NULL) { - report_key_dns_failure(&peer, ugh); + report_key_dns_failure(peer, ugh); st->st_suspended_md = NULL; - r = STF_FAIL + INVALID_KEY_INFORMATION; + r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; } } break; @@ -3669,7 +3850,7 @@ main_id_and_auth(struct msg_digest *md case OAKLEY_ECDSA_256: case OAKLEY_ECDSA_384: case OAKLEY_ECDSA_521: - r = check_signature(KEY_ECDSA, &peer, st, hash, + r = check_signature(KEY_ECDSA, peer, st, hash, &md->chain[ISAKMP_NEXT_SIG]->pbs, #ifdef USE_KEYRR NULL, @@ -3681,16 +3862,20 @@ main_id_and_auth(struct msg_digest *md bad_case(st->st_oakley.auth); } if (r != STF_OK) + { + peer->destroy(peer); return r; - + } DBG(DBG_CRYPT, DBG_log("authentication succeeded")); /* * With the peer ID known, let's see if we need to switch connections. */ - if (!switch_connection(md, &peer, initiator)) - return STF_FAIL + INVALID_ID_INFORMATION; - + if (!switch_connection(md, peer, initiator)) + { + r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; + } + peer->destroy(peer); return r; } @@ -3715,7 +3900,7 @@ 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, +static void key_continue(struct adns_continuation *cr, err_t ugh, key_tail_fn *tail) { struct key_continuation *kc = (void *)cr; @@ -3734,8 +3919,8 @@ static void key_continue(struct adns_continuation *cr, err_t ugh, if (!kc->failure_ok && ugh != NULL) { - report_key_dns_failure(&st->st_connection->spd.that.id, ugh); - r = STF_FAIL + INVALID_KEY_INFORMATION; + report_key_dns_failure(st->st_connection->spd.that.id, ugh); + r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; } else { @@ -3751,7 +3936,9 @@ static void key_continue(struct adns_continuation *cr, err_t ugh, complete_state_transition(&kc->md, r); } if (kc->md != NULL) + { release_md(kc->md); + } cur_state = NULL; } @@ -3786,7 +3973,7 @@ main_inI3_outR3_tail(struct msg_digest *md u_int8_t auth_payload; pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */ certpolicy_t cert_policy; - cert_t mycert; + cert_t *mycert; bool pubkey_auth, send_cert, requested; /* ID and HASH_I or SIG_I in @@ -3798,7 +3985,9 @@ main_inI3_outR3_tail(struct msg_digest *md , kc); if (r != STF_OK) + { return r; + } } /* send certificate if pubkey authentication is used, we have one @@ -3809,7 +3998,8 @@ main_inI3_outR3_tail(struct msg_digest *md 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 && + send_cert = pubkey_auth && mycert && + mycert->cert->get_type(mycert->cert) == CERT_X509 && (cert_policy == CERT_ALWAYS_SEND || requested); /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/ @@ -3840,7 +4030,9 @@ main_inI3_outR3_tail(struct msg_digest *md 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); } @@ -3850,12 +4042,14 @@ main_inI3_outR3_tail(struct msg_digest *md DBG(DBG_CONTROL, DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) ) - if (mycert.type != CERT_NONE) + if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) { const char *request_text = ""; if (cert_policy == CERT_SEND_IF_ASKED) + { request_text = (send_cert)? "upon request":"without request"; + } plog("we have a cert %s sending it %s" , send_cert? "and are":"but are not", request_text); } @@ -3866,23 +4060,31 @@ main_inI3_outR3_tail(struct msg_digest *md } if (send_cert) { + bool success; + chunk_t cert_encoding; pb_stream cert_pbs; - struct isakmp_cert cert_hd; + cert_hd.isacert_np = ISAKMP_NEXT_SIG; - cert_hd.isacert_type = mycert.type; + cert_hd.isacert_type = CERT_X509_SIGNATURE; if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - return STF_INTERNAL_ERROR; - if (!out_chunk(cert_get_encoding(mycert), &cert_pbs, "CERT")) + { + return STF_INTERNAL_ERROR; + } + cert_encoding = mycert->cert->get_encoding(mycert->cert); + success = out_chunk(cert_encoding, &cert_pbs, "CERT"); + free(cert_encoding.ptr); + if (!success) + { return STF_INTERNAL_ERROR; + } close_output_pbs(&cert_pbs); } /* HASH_R or SIG_R out */ { - u_char hash_buf[MAX_DIGEST_LEN]; - chunk_t hash = chunk_from_buf(hash_buf); + chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); main_mode_hash(st, &hash, FALSE, &r_id_pbs); @@ -3908,19 +4110,23 @@ main_inI3_outR3_tail(struct msg_digest *md if (sig_len == 0) { loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + AUTHENTICATION_FAILED; + return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; } if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc , &md->rbody, sig_val, sig_len, "SIG_R")) + { return STF_INTERNAL_ERROR; + } } } /* encrypt message, sans fixed part of header */ if (!encrypt_message(&md->rbody, st)) + { return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ + } /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */ DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:" @@ -3969,7 +4175,9 @@ static stf_status main_inR3_tail(struct msg_digest *md, stf_status r = main_id_and_auth(md, TRUE, main_inR3_continue, kc); if (r != STF_OK) + { return r; + } } /**************** done input ****************/ @@ -4103,7 +4311,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b stf_status quick_inI1_outR1(struct msg_digest *md) { const struct state *const p1st = md->st; - struct connection *c = p1st->st_connection; + connection_t *c = p1st->st_connection; struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; struct verify_oppo_bundle b; @@ -4127,12 +4335,16 @@ stf_status quick_inI1_outR1(struct msg_digest *md) if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs , &b.his.net, "peer client")) - return STF_FAIL + INVALID_ID_INFORMATION; + { + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; + } /* Hack for MS 818043 NAT-T Update */ if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN) + { happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); + } /* End Hack for MS 818043 NAT-T Update */ @@ -4144,8 +4356,9 @@ stf_status quick_inI1_outR1(struct msg_digest *md) 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; - + { + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; + } b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid; b.my.port = id_pd->next->payload.ipsec_id.isaiid_port; b.my.net.addr.u.v4.sin_port = htons(b.my.port); @@ -4154,8 +4367,9 @@ stf_status quick_inI1_outR1(struct msg_digest *md) { /* 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; @@ -4224,7 +4438,7 @@ static void quick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh) if (!b->failure_ok && ugh != NULL) { report_verify_failure(b, ugh); - r = STF_FAIL + INVALID_ID_INFORMATION; + r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; } else { @@ -4233,7 +4447,9 @@ static void quick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh) complete_state_transition(&b->md, r); } if (b->md != NULL) + { release_md(b->md); + } cur_state = NULL; } @@ -4242,11 +4458,11 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b, { struct msg_digest *md = b->md; struct state *p1st = md->st; - struct connection *c = p1st->st_connection; + connection_t *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 */ + identification_t *id; /* subject of query */ + identification_t *our_id; /* needed for myid playing */ + identification_t *our_id_space; /* ephemeral: no need for unshare_id_content */ ip_address client; err_t ugh = NULL; @@ -4282,20 +4498,20 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b, * %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) + our_id = resolve_myid(c->spd.this.id); + if (our_id->get_type(our_id) == ID_ANY) { - iptoid(&c->spd.this.host_addr, &our_id_space); - our_id = &our_id_space; + our_id_space = identification_create_from_sockaddr((sockaddr_t*)&c->spd.this.host_addr); + our_id = our_id_space; } switch (next_step) { case vos_our_client: networkof(&b->my.net, &client); - iptoid(&client, &id); + id = identification_create_from_sockaddr((sockaddr_t*)&client); vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(&id + ugh = start_adns_query(id , our_id , T_TXT , quick_inI1_outR1_continue @@ -4324,10 +4540,10 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b, case vos_his_client: networkof(&b->his.net, &client); - iptoid(&client, &id); + id = identification_create_from_sockaddr((sockaddr_t*)&client); vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(&id - , &c->spd.that.id + ugh = start_adns_query(id + , c->spd.that.id , T_TXT , quick_inI1_outR1_continue , &vc->ac); @@ -4345,7 +4561,7 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b, */ report_verify_failure(b, ugh); p1st->st_suspended_md = NULL; - return STF_FAIL + INVALID_ID_INFORMATION; + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; } else { @@ -4358,7 +4574,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( struct adns_continuation *ac, struct state *p1st) { - struct connection *c = p1st->st_connection; + connection_t *c = p1st->st_connection; enum verify_oppo_step next_step = vos_our_client; err_t ugh = NULL; @@ -4491,14 +4707,12 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( next_step = vos_done; { 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) @@ -4510,10 +4724,8 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer( * 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)) - ) + if (!gwp->gw_key_present || + pub_key->equals(pub_key, gwp->key->public_key)) { ugh = NULL; /* good! */ break; @@ -4539,7 +4751,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, { struct msg_digest *md = b->md; struct state *const p1st = md->st; - struct connection *c = p1st->st_connection; + connection_t *c = p1st->st_connection; struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; ip_subnet *our_net = &b->my.net , *his_net = &b->his.net; @@ -4552,7 +4764,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, * a suitable connection (our current one only matches for hosts). */ { - struct connection *p = find_client_connection(c + connection_t *p = find_client_connection(c , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port); if (p == NULL) @@ -4582,7 +4794,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, plog("cannot respond to IPsec SA request" " because no connection is known for %s" , buf); - return STF_FAIL + INVALID_ID_INFORMATION; + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; } else if (p != c) { @@ -4609,14 +4821,18 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, next_step = quick_inI1_outR1_process_answer(b, ac, p1st); if (next_step == vos_fail) - return STF_FAIL + INVALID_ID_INFORMATION; + { + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; + } /* short circuit: if peer's client is self, * accept that we've verified delegation in Phase 1 */ if (next_step == vos_his_client && sameaddr(&c->spd.that.host_addr, &his_client)) + { next_step = vos_done; + } /* the second chunk: initiate the next DNS query (if any) */ DBG(DBG_CONTROL, @@ -4633,7 +4849,9 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, /* 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 @@ -4643,7 +4861,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, * 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 + p = oppo_instantiate(p, &c->spd.that.host_addr, c->spd.that.id , NULL, &our_client, &his_client); } else @@ -4652,7 +4870,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, * instantiate, carrying over authenticated peer ID */ p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port - , his_net, &c->spd.that.id); + , his_net, c->spd.that.id); } } #ifdef DEBUG @@ -4680,7 +4898,9 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, 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 */ @@ -4708,7 +4928,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, if (st->st_connection != c) { - struct connection *t = st->st_connection; + connection_t *t = st->st_connection; st->st_connection = c; set_cur_connection(c); @@ -4781,7 +5001,9 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, /* 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; @@ -4794,7 +5016,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, 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; /* ??? */ + return STF_FAIL + ISAKMP_NO_PROPOSAL_CHOSEN; } /* Ni in */ @@ -4811,7 +5033,9 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, 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) */ @@ -4819,7 +5043,9 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, { 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; + { + return STF_INTERNAL_ERROR; + } /* MPZ-Operations might be done after sending the packet... */ compute_dh_shared(st, st->st_gi); @@ -4831,13 +5057,17 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */ if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci")) + { return STF_INTERNAL_ERROR; + } p->isaiid_np = ISAKMP_NEXT_ID; p = (void *)md->rbody.cur; /* UGH! */ if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr")) + { return STF_INTERNAL_ERROR; + } p->isaiid_np = ISAKMP_NEXT_NONE; } @@ -4873,12 +5103,16 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, * 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 */ if (!encrypt_message(&md->rbody, st)) + { return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ + } return STF_OK; } @@ -4891,14 +5125,16 @@ 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); @@ -4914,7 +5150,7 @@ static void dpd_init(struct state *st) stf_status quick_inR1_outI2(struct msg_digest *md) { struct state *const st = md->st; - const struct connection *c = st->st_connection; + const connection_t *c = st->st_connection; /* HASH(2) in */ CHECK_QUICK_HASH(md @@ -4937,7 +5173,9 @@ stf_status quick_inR1_outI2(struct msg_digest *md) RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); if (st->st_pfs_group != NULL) + { compute_dh_shared(st, st->st_gr); + } /* [ IDci, IDcr ] in; these must match what we sent */ @@ -4954,7 +5192,9 @@ stf_status quick_inR1_outI2(struct msg_digest *md) , &st->st_myuserprotoid, &st->st_myuserport , &st->st_connection->spd.this.client , "our client")) - return STF_FAIL + INVALID_ID_INFORMATION; + { + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; + } /* IDcr (responder is peer) */ @@ -4962,7 +5202,9 @@ stf_status quick_inR1_outI2(struct msg_digest *md) , &st->st_peeruserprotoid, &st->st_peeruserport , &st->st_connection->spd.that.client , "peer client")) - return STF_FAIL + INVALID_ID_INFORMATION; + { + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; + } } else { @@ -4972,35 +5214,40 @@ stf_status quick_inR1_outI2(struct msg_digest *md) { loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message" " but default does not match proposal"); - return STF_FAIL + INVALID_ID_INFORMATION; + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; } } } /* check the peer's group attributes */ - { - const ietfAttrList_t *peer_list = NULL; - - get_peer_ca_and_groups(st->st_connection, &peer_list); + identification_t *peer_ca = NULL; + ietf_attributes_t *peer_attributes = NULL; + bool match; - if (!group_membership(peer_list, st->st_connection->name - , st->st_connection->spd.that.groups)) + get_peer_ca_and_groups(st->st_connection, &peer_ca, &peer_attributes); + match = match_group_membership(peer_attributes, + st->st_connection->name, + st->st_connection->spd.that.groups); + DESTROY_IF(peer_attributes); + + if (!match) { - char buf[BUF_LEN]; + ietf_attributes_t *groups = st->st_connection->spd.that.groups; - 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; + loglog(RC_LOG_SERIOUS, + "peer with attributes '%s' is not a member of the groups '%s'", + peer_attributes->get_string(peer_attributes), + groups->get_string(groups)); + return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; } } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } + 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). @@ -5029,32 +5276,37 @@ stf_status quick_inR1_outI2(struct msg_digest *md) * failure won't look like success. */ if (!install_ipsec_sa(st, TRUE)) + { return STF_INTERNAL_ERROR; + } /* encrypt message, except for fixed part of header */ if (!encrypt_message(&md->rbody, st)) - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - { - DBG(DBG_CONTROLMORE, DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" + 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->spd.eroute_owner) + ) st->st_connection->newest_ipsec_sa = st->st_serialno; /* note (presumed) success */ if (c->gw_info != NULL) + { c->gw_info->key->last_worked_time = now(); + } /* If we want DPD on this connection then initialize it */ if (st->st_connection->dpd_action != DPD_ACTION_NONE) + { dpd_init(st); - + } return STF_OK; } @@ -5078,17 +5330,17 @@ stf_status quick_inI2(struct msg_digest *md) * 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)" + 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->spd.eroute_owner) + ) st->st_connection->newest_ipsec_sa = st->st_serialno; update_iv(st); /* not actually used, but tidy */ @@ -5098,13 +5350,16 @@ stf_status quick_inI2(struct msg_digest *md) 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; } @@ -5117,9 +5372,9 @@ static stf_status send_isakmp_notification(struct state *st, u_int16_t type, 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* */ @@ -5134,7 +5389,9 @@ static stf_status send_isakmp_notification(struct state *st, u_int16_t type, 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); @@ -5147,22 +5404,32 @@ static stf_status send_isakmp_notification(struct state *st, u_int16_t type, 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_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; + { + return STF_INTERNAL_ERROR; + } if (!out_raw(st->st_rcookie, COOKIE_SIZE, ¬ify_pbs, "notify rcookie")) - return STF_INTERNAL_ERROR; + { + return STF_INTERNAL_ERROR; + } if (data != NULL && len > 0) + { if (!out_raw(data, len, ¬ify_pbs, "notify data")) - return STF_INTERNAL_ERROR; + { + return STF_INTERNAL_ERROR; + } + } close_output_pbs(¬ify_pbs); } - + { - /* finish computing HASH */ + /* 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; @@ -5197,8 +5464,10 @@ static stf_status send_isakmp_notification(struct state *st, u_int16_t type, 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); @@ -5241,7 +5510,9 @@ void dpd_outI(struct state *p2st) /* 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); @@ -5329,7 +5600,7 @@ dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *p 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; + return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; } if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) @@ -5338,7 +5609,7 @@ dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *p /* 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; + return STF_FAIL + ISAKMP_INVALID_COOKIE; #endif } pbs->cur += COOKIE_SIZE; @@ -5346,7 +5617,7 @@ dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *p 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; + return STF_FAIL + ISAKMP_INVALID_COOKIE; } pbs->cur += COOKIE_SIZE; @@ -5354,7 +5625,7 @@ dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *p { loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid data length (%d)" , (int) pbs_left(pbs)); - return STF_FAIL + PAYLOAD_MALFORMED; + return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; } seqno = ntohl(*(u_int32_t *)pbs->cur); @@ -5403,7 +5674,7 @@ stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, loglog(RC_LOG_SERIOUS , "DPD: R_U_THERE_ACK has invalid SPI length (%d)" , n->isan_spisize); - return STF_FAIL + PAYLOAD_MALFORMED; + return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; } if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) @@ -5412,7 +5683,7 @@ stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, /* Ignore it, cisco sends odd icookies */ #else loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie"); - return STF_FAIL + INVALID_COOKIE; + return STF_FAIL + ISAKMP_INVALID_COOKIE; #endif } pbs->cur += COOKIE_SIZE; @@ -5423,7 +5694,7 @@ stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, /* Ignore it, cisco sends odd icookies */ #else loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie"); - return STF_FAIL + INVALID_COOKIE; + return STF_FAIL + ISAKMP_INVALID_COOKIE; #endif } pbs->cur += COOKIE_SIZE; @@ -5433,7 +5704,7 @@ stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, loglog(RC_LOG_SERIOUS , " DPD: R_U_THERE_ACK has invalid data length (%d)" , (int) pbs_left(pbs)); - return STF_FAIL + PAYLOAD_MALFORMED; + return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; } seqno = ntohl(*(u_int32_t *)pbs->cur); @@ -5447,7 +5718,7 @@ stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, loglog(RC_LOG_SERIOUS , "DPD: R_U_THERE_ACK has unexpected sequence number %u (expected %u)" , seqno, st->st_dpd_expectseqno); - return STF_FAIL + PAYLOAD_MALFORMED; + return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; } st->st_dpd_expectseqno = 0; @@ -5466,7 +5737,7 @@ void dpd_timeout(struct state *st) { struct state *newest_phase1_st; - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; int action = st->st_connection->dpd_action; char cname[BUF_LEN]; @@ -5501,14 +5772,18 @@ dpd_timeout(struct state *st) */ 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, @@ -5521,7 +5796,9 @@ dpd_timeout(struct state *st) strncpy(cname, c->name, BUF_LEN); if (c->kind == CK_INSTANCE) + { delete_connection(c, TRUE); + } initiate_connection(cname, NULL_FD); break; default: diff --git a/src/pluto/ipsec_doi.h b/src/pluto/ipsec_doi.h index 2e242e903..c11edaa94 100644 --- a/src/pluto/ipsec_doi.h +++ b/src/pluto/ipsec_doi.h @@ -12,6 +12,11 @@ * for more details. */ +#ifndef _IPSEC_DOI_H +#define _IPSEC_DOI_H + +#include "defs.h" + extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np); extern void ipsecdoi_initiate(int whack_sock, struct connection *c @@ -95,8 +100,9 @@ extern void dpd_timeout(struct state *st); 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; \ + return STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; \ } \ } +#endif /* _IPSEC_DOI_H */ diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c index 46edac1cd..fe4655d3f 100644 --- a/src/pluto/kernel.c +++ b/src/pluto/kernel.c @@ -45,7 +45,6 @@ #include "constants.h" #include "defs.h" -#include "id.h" #include "connections.h" #include "state.h" #include "timer.h" @@ -151,7 +150,7 @@ static void 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, +static bool shunt_eroute(connection_t *c, struct spd_route *sr, enum routing_t rt_kind, unsigned int op, const char *opname); @@ -347,14 +346,43 @@ ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) latest_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; - + } return htonl((ipsec_spi_t)latest_cpi); } +/* Replace the shell metacharacters ', \, ", `, and $ in a character string + * by escape sequences consisting of their octal values + */ +static void escape_metachar(const char *src, char *dst, size_t dstlen) +{ + while (*src != '\0' && dstlen > 4) + { + switch (*src) + { + case '\'': + case '\\': + case '"': + case '`': + case '$': + sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src); + dst += 4; + dstlen -= 4; + break; + default: + *dst++ = *src; + dstlen--; + } + src++; + } + *dst = '\0'; +} + /* invoke the updown script to do the routing and firewall commands required * * The user-specified updown script is run. Parameters are fed to it in @@ -392,7 +420,7 @@ ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) # define DEFAULT_UPDOWN "ipsec _updown" #endif -static bool do_command(struct connection *c, struct spd_route *sr, +static bool do_command(connection_t *c, struct spd_route *sr, const char *verb) { char cmd[1536]; /* arbitrary limit on shell command length */ @@ -469,7 +497,7 @@ static bool do_command(struct connection *c, struct spd_route *sr, } addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); - idtoa(&sr->this.id, myid_str, sizeof(myid_str)); + snprintf(myid_str, sizeof(myid_str), "%Y", sr->this.id); escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str)); subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str)); networkof(&sr->this.client, &ta); @@ -478,7 +506,7 @@ static bool do_command(struct connection *c, struct spd_route *sr, 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)); + snprintf(peerid_str, sizeof(peerid_str), "%Y", sr->that.id); escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str)); subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str)); networkof(&sr->that.client, &ta); @@ -492,11 +520,19 @@ static bool do_command(struct connection *c, struct spd_route *sr, 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) && + if (type == KEY_RSA && + sr->that.id->equals(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)); + if (key->issuer) + { + snprintf(peerca_str, BUF_LEN, "%Y", key->issuer); + escape_metachar(peerca_str, secure_peerca_str, BUF_LEN); + } + else + { + secure_peerca_str[0] = '\0'; + } break; } } @@ -653,10 +689,10 @@ enum routability { route_farconflict = 3 }; -static enum routability could_route(struct connection *c) +static enum routability could_route(connection_t *c) { struct spd_route *esr, *rosr; - struct connection *ero /* who, if anyone, owns our eroute? */ + connection_t *ero /* who, if anyone, owns our eroute? */ , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */ /* it makes no sense to route a connection that is ISAKMP-only */ @@ -710,8 +746,8 @@ static enum routability could_route(struct connection *c) /* 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; + connection_t *ero2, *ero_top; + connection_t *inside, *outside; /* * note, wavesec (PERMANENT) goes *outside* and @@ -797,7 +833,7 @@ static enum routability could_route(struct connection *c) return route_easy; } -bool trap_connection(struct connection *c) +bool trap_connection(connection_t *c) { switch (could_route(c)) { @@ -825,7 +861,7 @@ bool trap_connection(struct connection *c) /** * Delete any eroute for a connection and unroute it if route isn't shared */ -void unroute_connection(struct connection *c) +void unroute_connection(connection_t *c) { struct spd_route *sr; enum routing_t cr; @@ -847,7 +883,9 @@ void unroute_connection(struct connection *c) /* only unroute if no other connection shares it */ if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) + { (void) do_command(c, sr, "unroute"); + } } } @@ -868,7 +906,7 @@ static void set_text_said(char *text_said, const ip_address *dst, * this allows the entry to be deleted. */ static struct bare_shunt** bare_shunt_ptr(const ip_subnet *ours, - const ip_subnet *his, + const ip_subnet *his, int transport_proto) { struct bare_shunt *p, **pp; @@ -942,8 +980,8 @@ 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, + ipsec_spi_t spi, + unsigned int proto, unsigned int satype, unsigned int transport_proto, const struct pfkey_proto_info *proto_info, @@ -1072,8 +1110,9 @@ static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, , "eroute_connection %s", opname); if (proto == SA_INT) + { peer = aftoinfo(addrtypeof(peer))->any; - + } return raw_eroute(&sr->this.host_addr, &sr->this.client , peer , &sr->that.client @@ -1083,7 +1122,7 @@ static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, /* assign a bare hold to a connection */ -bool assign_hold(struct connection *c USED_BY_DEBUG, struct spd_route *sr, +bool assign_hold(connection_t *c USED_BY_DEBUG, struct spd_route *sr, int transport_proto, const ip_address *src, const ip_address *dst) @@ -1225,7 +1264,7 @@ static bool sag_eroute(struct state *st, struct spd_route *sr, /* compute a (host-order!) SPI to implement the policy in connection c */ ipsec_spi_t -shunt_policy_spi(struct connection *c, bool prospective) +shunt_policy_spi(connection_t *c, bool prospective) { /* note: these are in host order :-( */ static const ipsec_spi_t shunt_spi[] = @@ -1256,7 +1295,7 @@ shunt_policy_spi(struct connection *c, bool prospective) * If negotiation has failed, the choice between %trap/%pass/%drop/%reject * is specified in the policy of connection c. */ -static bool shunt_eroute(struct connection *c, struct spd_route *sr, +static bool shunt_eroute(connection_t *c, struct spd_route *sr, enum routing_t rt_kind, unsigned int op, const char *opname) { @@ -1316,7 +1355,7 @@ static bool shunt_eroute(struct connection *c, struct spd_route *sr, { /* maybe we are uneclipsing something */ struct spd_route *esr; - struct connection *ue = eclipsed(c, &esr); + connection_t *ue = eclipsed(c, &esr); if (ue != NULL) { @@ -1359,15 +1398,20 @@ static const char *read_proto(const char * s, size_t * len, int * transport_prot l = *len; p = memchr(s, ':', l); - if (p == 0) { + 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; @@ -1429,7 +1473,9 @@ void scan_proc_shunts(void) f = fopen(procname, "r"); if (f == NULL) + { return; + } /* for each line... */ for (lino = 1; ; lino++) @@ -1445,7 +1491,9 @@ void scan_proc_shunts(void) cp = fgets(buf, sizeof(buf), f); if (cp == NULL) + { break; + } /* break out each field * Note: if there are too many fields, just stop; @@ -1461,7 +1509,9 @@ void scan_proc_shunts(void) field[fi] = chunk_create(cp, w); cp += w; if (w == 0) + { break; + } } /* This odd do-hickey is to share error reporting code. @@ -1473,9 +1523,13 @@ void scan_proc_shunts(void) * 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"; @@ -1501,7 +1555,9 @@ void scan_proc_shunts(void) context = "count field is malformed: "; ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count); if (ugh != NULL) + { break; + } } /* our client */ @@ -1509,21 +1565,27 @@ void scan_proc_shunts(void) 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); @@ -1666,7 +1728,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) { /* Build an inbound or outbound SA */ - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; ip_subnet src, dst; ip_subnet src_client, dst_client; ipsec_spi_t inner_spi = 0; @@ -1738,9 +1800,13 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) ipip_spi = htonl(++last_tunnel_spi); if (inbound) + { st->st_tunnel_in_spi = ipip_spi; + } else + { st->st_tunnel_out_spi = ipip_spi; + } } set_text_said(text_said @@ -1797,10 +1863,10 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) said_next->text_said = text_said; if (!kernel_ops->add_sa(said_next, replace)) + { goto fail; - + } said_next++; - encapsulation = ENCAPSULATION_MODE_TRANSPORT; } @@ -1861,7 +1927,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) if (ei == &esp_info[countof(esp_info)]) { /* Check for additional kernel alg */ - if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid, + if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid, st->st_esp.attrs.auth))!=NULL) { break; @@ -1873,7 +1939,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) * 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(&esp_transform_names, st->st_esp.attrs.transid) , enum_name(&auth_alg_names, st->st_esp.attrs.auth)); goto fail; } @@ -1892,7 +1958,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) 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), + enum_name(&esp_transform_names, st->st_esp.attrs.transid), (int)key_len, (int)ei->enckeylen); goto fail; } @@ -1906,7 +1972,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) { case ESP_3DES: /* 168 bits in kernel, need 192 bits for keymat_len */ - if (key_len == 21) + if (key_len == 21) { key_len = 24; } @@ -1914,7 +1980,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) case ESP_DES: /* 56 bits in kernel, need 64 bits for keymat_len */ if (key_len == 7) - { + { key_len = 8; } break; @@ -1930,7 +1996,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) key_len += 4; break; default: - break; + break; } /* divide up keying material */ @@ -2032,7 +2098,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) { struct pfkey_proto_info proto_info[4]; int i = 0; - + if (st->st_ipcomp.present) { proto_info[i].proto = IPPROTO_COMP; @@ -2040,7 +2106,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) proto_info[i].reqid = c->spd.reqid + 2; i++; } - + if (st->st_esp.present) { proto_info[i].proto = IPPROTO_ESP; @@ -2048,7 +2114,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) proto_info[i].reqid = c->spd.reqid + 1; i++; } - + if (st->st_ah.present) { proto_info[i].proto = IPPROTO_AH; @@ -2056,9 +2122,9 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) proto_info[i].reqid = c->spd.reqid; i++; } - + proto_info[i].proto = 0; - + if (kernel_ops->inbound_eroute && encapsulation == ENCAPSULATION_MODE_TUNNEL) { @@ -2068,7 +2134,7 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) 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 @@ -2079,11 +2145,11 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) } /* If there are multiple SPIs, group them. */ - + 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. @@ -2095,15 +2161,15 @@ static bool setup_half_ipsec_sa(struct state *st, bool inbound) 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; @@ -2135,7 +2201,7 @@ static bool teardown_half_ipsec_sa(struct state *st, bool inbound) * 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; + connection_t *c = st->st_connection; struct { unsigned proto; struct ipsec_proto_info *info; @@ -2227,7 +2293,7 @@ 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; + connection_t *c = st->st_connection; *use_time = UNDEFINED_TIME; @@ -2353,7 +2419,7 @@ void init_kernel(void) */ bool install_inbound_ipsec_sa(struct state *st) { - struct connection *const c = st->st_connection; + connection_t *const c = st->st_connection; /* If our peer has a fixed-address client, check if we already * have a route for that client that conflicts. We will take this @@ -2367,7 +2433,7 @@ bool install_inbound_ipsec_sa(struct state *st) for (;;) { struct spd_route *esr; - struct connection *o = route_owner(c, &esr, NULL, NULL); + connection_t *o = route_owner(c, &esr, NULL, NULL); if (o == NULL) { @@ -2417,20 +2483,20 @@ bool 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, +bool route_and_eroute(connection_t *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? */ + connection_t *ero /* who, if anyone, owns our eroute? */ , *ro = route_owner(c, &rosr, &ero, &esr); bool eroute_installed = FALSE , firewall_notified = FALSE , route_installed = FALSE; - struct connection *ero_top; + connection_t *ero_top; struct bare_shunt **bspp; DBG(DBG_CONTROLMORE, @@ -2438,7 +2504,7 @@ bool route_and_eroute(struct connection *c USED_BY_KLIPS, , c->name , (c->policy_next ? c->policy_next->name : "none") , ero ? ero->name : "null" - , esr + , esr , ro ? ro->name : "null" , rosr , st ? st->st_serialno : 0)); @@ -2472,11 +2538,14 @@ bool route_and_eroute(struct connection *c USED_BY_KLIPS, /* 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) @@ -2588,7 +2657,7 @@ bool route_and_eroute(struct connection *c USED_BY_KLIPS, else if (ero != NULL && ero != c) { /* check if ero is an ancestor of c. */ - struct connection *ero2; + connection_t *ero2; for (ero2 = c; ero2 != NULL && ero2 != c; ero2 = ero2->policy_next) ; @@ -2788,7 +2857,7 @@ void delete_ipsec_sa(struct state *st USED_BY_KLIPS, /* If the state is the eroute owner, we must adjust * the routing for the connection. */ - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; struct spd_route *sr; passert(st->st_connection); @@ -2837,9 +2906,9 @@ void delete_ipsec_sa(struct state *st USED_BY_KLIPS, #ifdef KLIPS static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound) { - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; char text_said[SATOT_BUF]; - struct kernel_sa sa; + 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; @@ -2924,7 +2993,7 @@ bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time) ret = *idle_time >= idle_max; } } - else + else { while (f != NULL) { diff --git a/src/pluto/kernel_alg.c b/src/pluto/kernel_alg.c index 7e7d25872..bf67315e6 100644 --- a/src/pluto/kernel_alg.c +++ b/src/pluto/kernel_alg.c @@ -90,7 +90,7 @@ static struct sadb_alg* sadb_alg_ptr (int satype, int exttype, int alg_id, default: return NULL; } - + return alg_p; } @@ -154,7 +154,7 @@ bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, if (!ret) goto out; alg_p = &esp_ealg[alg_id]; - + /* * test #2: if key_len specified, it must be in range */ @@ -195,8 +195,8 @@ out: return ret; } -/* - * ML: make F_STRICT logic consider enc,auth algorithms +/* + * ML: make F_STRICT logic consider enc,auth algorithms */ bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info) @@ -237,14 +237,14 @@ bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, { loglog(RC_LOG_SERIOUS , "You should NOT use insecure ESP algorithms [%s (%d)]!" - , enum_name(&esp_transformid_names, ealg), key_len); + , enum_name(&esp_transform_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(&esp_transform_names, ealg), key_len, enum_name(&auth_alg_names, aalg), ealg_insecure ? "insecure key_len and enc. alg. not listed in \"esp\" string" : "strict flag"); return FALSE; @@ -252,7 +252,7 @@ bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, return TRUE; } -/** +/** * Load kernel_alg arrays from /proc used in manual mode from klips/utils/spi.c */ int kernel_alg_proc_read(void) @@ -312,7 +312,7 @@ int kernel_alg_proc_read(void) return 0; } -/** +/** * 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) @@ -380,6 +380,7 @@ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) ) /* if AES_CBC is registered then also register AES_CCM and AES_GCM */ if (satype == SADB_SATYPE_ESP && + supp_exttype == SADB_EXT_SUPPORTED_ENCRYPT && sadb.alg->sadb_alg_id == SADB_X_EALG_AESCBC) { struct sadb_alg alg = *sadb.alg; @@ -395,6 +396,16 @@ void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) } } } + /* if SHA2_256 is registered then also register SHA2_256_96 */ + if (satype == SADB_SATYPE_ESP && + supp_exttype == SADB_EXT_SUPPORTED_AUTH && + sadb.alg->sadb_alg_id == SADB_X_AALG_SHA2_256HMAC) + { + struct sadb_alg alg = *sadb.alg; + + alg.sadb_alg_id = SADB_X_AALG_SHA2_256_96HMAC; + kernel_alg_add(satype, supp_exttype, &alg); + } } } } @@ -422,7 +433,7 @@ u_int kernel_alg_esp_enc_keylen(u_int alg_id) break; } -none: +none: DBG(DBG_KLIPS, DBG_log("kernel_alg_esp_enc_keylen(): alg_id=%d, keylen=%d", alg_id, keylen) @@ -461,7 +472,7 @@ void kernel_alg_list(void) if (ESP_EALG_PRESENT(sadb_id)) { n = snprintf(pos, len, " %s", - enum_name(&esp_transformid_names, sadb_id)); + enum_name(&esp_transform_names, sadb_id)); pos += n; len -= n; if (len <= 0) @@ -471,7 +482,7 @@ void kernel_alg_list(void) } } whack_log(RC_COMMENT, " encryption:%s", buf); - + pos = buf; *pos = '\0'; len = BUF_LEN; @@ -493,7 +504,7 @@ void kernel_alg_list(void) whack_log(RC_COMMENT, " integrity: %s", buf); } -void kernel_alg_show_connection(struct connection *c, const char *instance) +void kernel_alg_show_connection(connection_t *c, const char *instance) { struct state *st = state_with_serialno(c->newest_ipsec_sa); @@ -502,12 +513,12 @@ void kernel_alg_show_connection(struct connection *c, const char *instance) const char *aalg_name, *pfsgroup_name; aalg_name = (c->policy & POLICY_AUTHENTICATE) ? - enum_show(&ah_transformid_names, st->st_ah.attrs.transid): + enum_show(&ah_transform_names, st->st_ah.attrs.transid): enum_show(&auth_alg_names, st->st_esp.attrs.auth); pfsgroup_name = (c->policy & POLICY_PFS) ? - (c->alg_info_esp->esp_pfsgroup) ? - enum_show(&oakley_group_names, + (c->alg_info_esp && c->alg_info_esp->esp_pfsgroup) ? + enum_show(&oakley_group_names, c->alg_info_esp->esp_pfsgroup) : "<Phase1>" : "<N/A>"; @@ -516,7 +527,7 @@ void kernel_alg_show_connection(struct connection *c, const char *instance) 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), + enum_show(&esp_transform_names, st->st_esp.attrs.transid), st->st_esp.attrs.key_len, aalg_name, pfsgroup_name); } else @@ -524,7 +535,7 @@ void kernel_alg_show_connection(struct connection *c, const char *instance) 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), + enum_show(&esp_transform_names, st->st_esp.attrs.transid), aalg_name, pfsgroup_name); } } @@ -634,7 +645,7 @@ static bool kernel_alg_db_add(struct db_context *db_ctx, DBG_log("kernel_alg_db_add() kernel enc ealg_id=%d not present", ealg_id); return FALSE; } - + if (!(policy & POLICY_AUTHENTICATE) && /* skip ESP auth attrs for AH */ esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE) { @@ -666,11 +677,11 @@ static bool kernel_alg_db_add(struct db_context *db_ctx, { 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 * @@ -694,12 +705,6 @@ struct db_context* kernel_alg_db_new(struct alg_info_esp *alg_info, /* pass aprox. number of transforms and attributes */ ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2); - /* - * 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 ... - */ - if (alg_info) { int i; @@ -710,28 +715,6 @@ struct db_context* kernel_alg_db_new(struct alg_info_esp *alg_info, kernel_alg_db_add(ctx_new, &tmp_esp_info, policy); } } - else - { - u_int ealg_id; - - ESP_EALG_FOR_EACH_UPDOWN(ealg_id) - { - 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); return ctx_new; } diff --git a/src/pluto/kernel_netlink.c b/src/pluto/kernel_netlink.c index 0376e817b..289714b50 100644 --- a/src/pluto/kernel_netlink.c +++ b/src/pluto/kernel_netlink.c @@ -40,6 +40,11 @@ #include "whack.h" /* for RC_LOG_SERIOUS */ #include "kernel_alg.h" +/** required for Linux 2.6.26 kernel and later */ +#ifndef XFRM_STATE_AF_UNSPEC +#define XFRM_STATE_AF_UNSPEC 32 +#endif + /* Minimum priority number in SPD used by pluto. */ #define MIN_SPD_PRIORITY 1024 @@ -80,15 +85,15 @@ static sparse_names xfrm_type_names = { /* 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" }, + { SADB_X_AALG_NULL, "digest_null" }, + { SADB_AALG_MD5HMAC, "md5" }, + { SADB_AALG_SHA1HMAC, "sha1" }, + { SADB_X_AALG_SHA2_256_96HMAC, "sha256" }, + { SADB_X_AALG_SHA2_256HMAC, "hmac(sha256)" }, + { SADB_X_AALG_SHA2_384HMAC, "hmac(sha384)" }, + { SADB_X_AALG_SHA2_512HMAC, "hmac(sha512)" }, + { SADB_X_AALG_RIPEMD160HMAC, "ripemd160" }, + { SADB_X_AALG_AES_XCBC_MAC, "xcbc(aes)"}, { 0, sparse_end } }; @@ -183,7 +188,7 @@ static void init_netlink(void) * @param hdr - Data to be sent. * @param rbuf - Return Buffer - contains data returned from the send. * @param rbuf_len - Length of rbuf - * @param description - String - user friendly description of what is + * @param description - String - user friendly description of what is * being attempted. Used for diagnostics * @param text_said - String * @return bool True if the message was succesfully sent. @@ -343,6 +348,7 @@ static bool netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, struct { struct nlmsghdr n; struct nlmsgerr e; + char data[1024]; } rsp; int error; @@ -382,7 +388,7 @@ static bool netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, * @param proto int (Currently unused) Contains protocol (u=tcp, 17=udp, etc...) * @param transport_proto int (Currently unused) 0=tunnel, 1=transport * @param satype int - * @param proto_info + * @param proto_info * @param lifetime (Currently unused) * @param ip int * @return boolean True if successful @@ -518,9 +524,9 @@ static bool netlink_raw_eroute(const ip_address *this_host 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].family = that_host->u.v4.sin_family; tmpl[i].mode = proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - if (!tmpl[i].mode) { continue; @@ -590,7 +596,7 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) char data[1024]; } req; struct rtattr *attr; - u_int16_t icv_size = 64; + u_int16_t icv_size = 64; memset(&req, 0, sizeof(req)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; @@ -602,7 +608,15 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) 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); + if (sa->encapsulation == ENCAPSULATION_MODE_TUNNEL) + { + req.p.mode = XFRM_MODE_TUNNEL; + req.p.flags |= XFRM_STATE_AF_UNSPEC; + } + else + { + req.p.mode = XFRM_MODE_TRANSPORT; + } req.p.replay_window = sa->replay_window; req.p.reqid = sa->reqid; req.p.lft.soft_byte_limit = XFRM_INF; @@ -616,7 +630,6 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) if (sa->authalg) { - struct xfrm_algo algo; const char *name; name = sparse_name(aalg_list, sa->authalg); @@ -632,16 +645,37 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) sa->authkeylen * BITS_PER_BYTE) ) - strcpy(algo.alg_name, name); - algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; + if (sa->authalg == SADB_X_AALG_SHA2_256HMAC) + { + struct xfrm_algo_auth algo; - attr->rta_type = XFRMA_ALG_AUTH; - attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen); + /* the kernel uses SHA256 with 96 bit truncation by default, + * use specified truncation size supported by newer kernels */ + strcpy(algo.alg_name, name); + algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; + algo.alg_trunc_len = 128; - memcpy(RTA_DATA(attr), &algo, sizeof(algo)); - memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey - , sa->authkeylen); + attr->rta_type = XFRMA_ALG_AUTH_TRUNC; + 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); + } + else + { + struct xfrm_algo algo; + + 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); } @@ -674,19 +708,19 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) } DBG(DBG_CRYPT, DBG_log("configured esp encryption algorithm %s with key size %d", - enum_show(&esp_transformid_names, sa->encalg), + enum_show(&esp_transform_names, sa->encalg), sa->enckeylen * BITS_PER_BYTE) ) attr->rta_type = XFRMA_ALG_AEAD; attr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + sa->enckeylen); req.n.nlmsg_len += attr->rta_len; - + algo = (struct xfrm_algo_aead*)RTA_DATA(attr); algo->alg_key_len = sa->enckeylen * BITS_PER_BYTE; algo->alg_icv_len = icv_size; strcpy(algo->alg_name, name); memcpy(algo->alg_key, sa->enckey, sa->enckeylen); - + attr = (struct rtattr *)((char *)attr + attr->rta_len); break; } @@ -704,7 +738,7 @@ static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) } DBG(DBG_CRYPT, DBG_log("configured esp encryption algorithm %s with key size %d", - enum_show(&esp_transformid_names, sa->encalg), + enum_show(&esp_transform_names, sa->encalg), sa->enckeylen * BITS_PER_BYTE) ) attr->rta_type = XFRMA_ALG_CRYPT; @@ -962,7 +996,7 @@ static void linux_pfkey_register(void) /** Create ip_address out of xfrm_address_t. * - * @param family + * @param family * @param src xfrm formatted IP address * @param dst ip_address formatted destination * @return err_t NULL if okay, otherwise an error @@ -1001,7 +1035,7 @@ static err_t xfrm_sel_to_ip_pair(const struct xfrm_selector *sel, if ((ugh = xfrm_to_ip_address(family, &sel->saddr, src)) || (ugh = xfrm_to_ip_address(family, &sel->daddr, dst))) - { + { return ugh; } diff --git a/src/pluto/kernel_noklips.c b/src/pluto/kernel_noklips.c index 82a6ab648..e99efe062 100644 --- a/src/pluto/kernel_noklips.c +++ b/src/pluto/kernel_noklips.c @@ -107,7 +107,7 @@ 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, diff --git a/src/pluto/kernel_pfkey.c b/src/pluto/kernel_pfkey.c index 7ac405fd4..99ba4ff30 100644 --- a/src/pluto/kernel_pfkey.c +++ b/src/pluto/kernel_pfkey.c @@ -73,7 +73,7 @@ static sparse_names pfkey_type_names = { NE(SADB_X_DELFLOW), NE(SADB_X_DEBUG), NE(SADB_X_NAT_T_NEW_MAPPING), - NE(SADB_MAX), + NE(SADB_MAX), { 0, sparse_end } }; @@ -531,7 +531,7 @@ pfkeyext_protocol(int transport_proto , const char *text_said , struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { - return (transport_proto == 0)? TRUE + return (transport_proto == 0)? TRUE : pfkey_build( pfkey_x_protocol_build(extensions + SADB_X_EXT_PROTOCOL, transport_proto) , description, text_said, extensions); diff --git a/src/pluto/keys.c b/src/pluto/keys.c index 516872e8e..8cf28ace1 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -36,12 +36,11 @@ #include <library.h> #include <asn1/asn1.h> +#include <credentials/certificates/pgp_certificate.h> #include "constants.h" #include "defs.h" -#include "id.h" #include "x509.h" -#include "pgpcert.h" #include "certs.h" #include "smartcard.h" #include "connections.h" @@ -61,7 +60,7 @@ const char *shared_secrets_file = SHARED_SECRETS_FILE; typedef struct id_list id_list_t; struct id_list { - struct id id; + identification_t *id; id_list_t *next; }; @@ -84,9 +83,9 @@ struct secret { */ static void free_public_key(pubkey_t *pk) { + DESTROY_IF(pk->id); DESTROY_IF(pk->public_key); - free_id_content(&pk->id); - free(pk->issuer.ptr); + DESTROY_IF(pk->issuer); free(pk->serial.ptr); free(pk); } @@ -97,7 +96,7 @@ 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, +static const secret_t* get_secret(const connection_t *c, enum PrivateKeyKind kind, bool asym) { enum { /* bits */ @@ -109,14 +108,14 @@ static const secret_t* get_secret(const struct connection *c, 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; + identification_t *my_id, *his_id; /* is there a certificate assigned to this connection? */ - if (kind == PPK_PUBKEY && c->spd.this.cert.type != CERT_NONE) + if (kind == PPK_PUBKEY && c->spd.this.cert) { - public_key_t *pub_key = cert_get_public_key(c->spd.this.cert); + certificate_t *certificate = c->spd.this.cert->cert; + + public_key_t *pub_key = certificate->get_public_key(certificate); for (s = secrets; s != NULL; s = s->next) { @@ -127,26 +126,28 @@ static const secret_t* get_secret(const struct connection *c, break; /* we have found the private key - no sense in searching further */ } } + pub_key->destroy(pub_key); return best; } + my_id = c->spd.this.id; + 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; + his_id = identification_create_from_string("%any"); } - 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)))) + else if (kind == PPK_PSK && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) && + ((c->kind == CK_TEMPLATE && + c->spd.that.id->get_type(c->spd.that.id) == ID_ANY) || + (c->kind == CK_INSTANCE && id_is_ipaddr(c->spd.that.id)))) { /* roadwarrior: replace him with 0.0.0.0 */ - rw_id.kind = ID_IPV4_ADDR; - happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); - his_id = &rw_id; + his_id = identification_create_from_string("%any"); + } + else + { + his_id = c->spd.that.id->clone(c->spd.that.id); } for (s = secrets; s != NULL; s = s->next) @@ -169,11 +170,11 @@ static const secret_t* get_secret(const struct connection *c, for (i = s->ids; i != NULL; i = i->next) { - if (same_id(my_id, &i->id)) + if (my_id->equals(my_id, i->id)) { match |= match_me; } - if (same_id(his_id, &i->id)) + if (his_id->equals(his_id, i->id)) { match |= match_him; } @@ -239,6 +240,7 @@ static const secret_t* get_secret(const struct connection *c, } } } + his_id->destroy(his_id); return best; } @@ -246,7 +248,7 @@ static const secret_t* get_secret(const struct connection *c, * 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 connection_t *c) { const secret_t *s = get_secret(c, PPK_PSK, FALSE); @@ -262,11 +264,11 @@ const chunk_t* get_preshared_secret(const struct connection *c) /* 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; - public_key_t *pub_key = cert_get_public_key(cert); + public_key_t *pub_key = cert->cert->get_public_key(cert->cert); for (s = secrets; s != NULL; s = s->next) { @@ -277,31 +279,37 @@ bool has_private_key(cert_t cert) break; } } + pub_key->destroy(pub_key); return has_key; } /* * get the matching private key belonging to a given X.509 certificate */ -private_key_t* get_x509_private_key(const x509cert_t *cert) +private_key_t* get_x509_private_key(const cert_t *cert) { + public_key_t *public_key = cert->cert->get_public_key(cert->cert); + private_key_t *private_key = NULL; secret_t *s; for (s = secrets; s != NULL; s = s->next) { + if (s->kind == PPK_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, cert->public_key)) + s->u.private_key->belongs_to(s->u.private_key, public_key)) { - return s->u.private_key; + private_key = s->u.private_key; + break; } } - return NULL; + public_key->destroy(public_key); + return private_key; } /* find the appropriate private key (see get_secret). * Failure is indicated by a NULL pointer. */ -private_key_t* get_private_key(const struct connection *c) +private_key_t* get_private_key(const connection_t *c) { const secret_t *s = get_secret(c, PPK_PUBKEY, TRUE); @@ -392,7 +400,7 @@ enum rsa_private_key_part_t { RSA_PART_EXPONENT1 = 5, RSA_PART_EXPONENT2 = 6, RSA_PART_COEFFICIENT = 7 -}; +}; const char *rsa_private_key_part_names[] = { "Modulus", @@ -408,20 +416,17 @@ const char *rsa_private_key_part_names[] = { /** * 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(private_key_t **key) { - chunk_t asn1_chunk[countof(rsa_private_key_part_names)]; - chunk_t pkcs1_chunk; + chunk_t rsa_chunk[countof(rsa_private_key_part_names)]; u_char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ rsa_private_key_part_t part, p; - size_t sz, len = 0; + size_t sz; err_t ugh; for (part = RSA_PART_MODULUS; part <= RSA_PART_COEFFICIENT; part++) { - chunk_t rsa_private_key_part; const char *keyword = rsa_private_key_part_names[part]; if (!shift()) @@ -448,9 +453,8 @@ static err_t process_rsa_secret(private_key_t **key) 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; + rsa_chunk[part] = chunk_create(buf, sz); + rsa_chunk[part] = chunk_clone(rsa_chunk[part]); } /* We require an (indented) '}' and the end of the record. @@ -468,21 +472,17 @@ static err_t process_rsa_secret(private_key_t **key) goto end; } - 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); + BUILD_RSA_MODULUS, rsa_chunk[RSA_PART_MODULUS], + BUILD_RSA_PUB_EXP, rsa_chunk[RSA_PART_PUBLIC_EXPONENT], + BUILD_RSA_PRIV_EXP, rsa_chunk[RSA_PART_PRIVATE_EXPONENT], + BUILD_RSA_PRIME1, rsa_chunk[RSA_PART_PRIME1], + BUILD_RSA_PRIME2, rsa_chunk[RSA_PART_PRIME2], + BUILD_RSA_EXP1, rsa_chunk[RSA_PART_EXPONENT1], + BUILD_RSA_EXP2, rsa_chunk[RSA_PART_EXPONENT2], + BUILD_RSA_COEFF, rsa_chunk[RSA_PART_COEFFICIENT], + BUILD_END); + if (*key == NULL) { ugh = "parsing of RSA private key failed"; @@ -492,9 +492,9 @@ end: /* clean up and return */ for (p = RSA_PART_MODULUS ; p < part; p++) { - free(asn1_chunk[p].ptr); + chunk_clear(&rsa_chunk[p]); } - return ugh; + return ugh; } /** @@ -722,7 +722,7 @@ static err_t process_pin(secret_t *s, int whackfd) } } else - { + { /* we read the pin directly from ipsec.secrets */ err_t ugh = process_psk_secret(&sc->pin); if (ugh != NULL) @@ -762,16 +762,12 @@ static void log_psk(secret_t *s) { do { - n += idtoa(&id_list->id, buf + n, BUF_LEN - n); + n += snprintf(buf + n, BUF_LEN - n, "%Y ", id_list->id); 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); @@ -948,42 +944,12 @@ static void process_secret_records(int whackfd) /* an id * See RFC2407 IPsec Domain of Interpretation 4.6.2 */ - struct id id; - err_t ugh; + id_list_t *i = malloc_thing(id_list_t); - 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); - } + i->id = identification_create_from_string(tok); + i->next = s->ids; + s->ids = i; - 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 */ @@ -1071,11 +1037,11 @@ void free_preshared_secrets(void) { id_list_t *i, *ni; - ns = s->next; /* grab before freeing s */ + ns = s->next; for (i = s->ids; i != NULL; i = ni) { - ni = i->next; /* grab before freeing i */ - free_id_content(&i->id); + ni = i->next; + i->id->destroy(i->id); free(i); } switch (s->kind) @@ -1119,8 +1085,8 @@ pubkey_t* public_key_from_rsa(public_key_t *key) pubkey_t *p = malloc_thing(pubkey_t); zero(p); - p->id = empty_id; /* don't know, doesn't matter */ - p->issuer = chunk_empty; + p->id = identification_create_from_string("%any"); /* don't know, doesn't matter */ + p->issuer = NULL; p->serial = chunk_empty; p->public_key = key; @@ -1128,7 +1094,6 @@ pubkey_t* public_key_from_rsa(public_key_t *key) * invariant: recount > 0. */ p->refcnt = 1; - time(&p->installed_time); return p; } @@ -1207,25 +1172,14 @@ static void install_public_key(pubkey_t *pk, pubkey_list_t **head) { pubkey_list_t *p = malloc_thing(pubkey_list_t); - unshare_id_content(&pk->id); - - /* copy issuer dn */ - pk->issuer = chunk_clone(pk->issuer); - - /* copy serial number */ - pk->serial = chunk_clone(pk->serial); - - /* 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; } -void delete_public_keys(const struct id *id, key_type_t type, - chunk_t issuer, chunk_t serial) +void delete_public_keys(identification_t *id, key_type_t type, + identification_t *issuer, chunk_t serial) { pubkey_list_t **pp, *p; pubkey_t *pk; @@ -1236,10 +1190,10 @@ void delete_public_keys(const struct id *id, key_type_t type, 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)) + if (id->equals(id, pk->id) && pk_type == type + && (issuer == NULL || pk->issuer == NULL + || issuer->equals(issuer, pk->issuer)) + && (serial.ptr == NULL || chunk_equals(serial, pk->serial))) { *pp = free_public_keyentry(p); } @@ -1252,25 +1206,26 @@ void delete_public_keys(const struct id *id, key_type_t type, pubkey_t* reference_key(pubkey_t *pk) { + DBG(DBG_CONTROLMORE, + DBG_log(" ref key: %p %p cnt %d '%Y'", + pk, pk->public_key, pk->refcnt, pk->id) + ) pk->refcnt++; return pk; } -void -unreference_key(pubkey_t **pkp) +void unreference_key(pubkey_t **pkp) { pubkey_t *pk = *pkp; - char b[BUF_LEN]; 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) + DBG_log("unref key: %p %p cnt %d '%Y'", + pk, pk->public_key, pk->refcnt, pk->id) ) /* cancel out the pointer */ @@ -1284,7 +1239,7 @@ unreference_key(pubkey_t **pkp) } } -bool add_public_key(const struct id *id, enum dns_auth_level dns_auth_level, +bool add_public_key(identification_t *id, enum dns_auth_level dns_auth_level, enum pubkey_alg alg, chunk_t rfc3110_key, pubkey_list_t **head) { @@ -1296,7 +1251,7 @@ bool add_public_key(const struct id *id, enum dns_auth_level dns_auth_level, { case PUBKEY_ALG_RSA: key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, - BUILD_BLOB_RFC_3110, rfc3110_key, + BUILD_BLOB_DNSKEY, rfc3110_key, BUILD_END); if (key == NULL) { @@ -1310,90 +1265,97 @@ bool add_public_key(const struct id *id, enum dns_auth_level dns_auth_level, pk = malloc_thing(pubkey_t); zero(pk); pk->public_key = key; - pk->id = *id; + pk->id = id->clone(id); pk->dns_auth_level = dns_auth_level; pk->until_time = UNDEFINED_TIME; - pk->issuer = chunk_empty; + pk->issuer = NULL; 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 +/** + * Extract id and public key a 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_public_key_from_cert(cert_t *cert , time_t until, + enum dns_auth_level dns_auth_level) { - generalName_t *gn; + certificate_t *certificate = cert->cert; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = NULL; + identification_t *id; + chunk_t serialNumber = chunk_empty; pubkey_t *pk; key_type_t pk_type; /* ID type: ID_DER_ASN1_DN (X.509 subject field) */ pk = malloc_thing(pubkey_t); zero(pk); - pk->public_key = cert->public_key->get_ref(cert->public_key); - pk->id.kind = ID_DER_ASN1_DN; - pk->id.name = cert->subject; + pk->public_key = certificate->get_public_key(certificate); + pk_type = pk->public_key->get_type(pk->public_key); + pk->id = subject->clone(subject); pk->dns_auth_level = dns_auth_level; pk->until_time = until; - 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); + if (certificate->get_type(certificate) == CERT_X509) + { + x509_t *x509 = (x509_t*)certificate; - gn = cert->subjectAltName; + issuer = certificate->get_issuer(certificate); + serialNumber = x509->get_serial(x509); + pk->issuer = issuer->clone(issuer); + pk->serial = chunk_clone(serialNumber); + } + delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); + install_public_key(pk, &pubkeys); - while (gn != NULL) /* insert all subjectAltNames */ + if (certificate->get_type(certificate) == CERT_X509) { - struct id id = empty_id; + x509_t *x509 = (x509_t*)certificate; + enumerator_t *enumerator; - gntoid(&id, gn); - if (id.kind != ID_ANY) + /* insert all subjectAltNames from X.509 certificates */ + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, &id)) { - 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); + if (id->get_type(id) != ID_ANY) + { + pk = malloc_thing(pubkey_t); + zero(pk); + pk->id = id->clone(id); + pk->public_key = certificate->get_public_key(certificate); + pk->dns_auth_level = dns_auth_level; + pk->until_time = until; + pk->issuer = issuer->clone(issuer); + pk->serial = chunk_clone(serialNumber); + delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); + install_public_key(pk, &pubkeys); + } } - gn = gn->next; + enumerator->destroy(enumerator); + } + else + { + pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; + chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); + + /* add v3 or v4 PGP fingerprint */ + pk = malloc_thing(pubkey_t); + zero(pk); + pk->id = identification_create_from_encoding(ID_KEY_ID, fingerprint); + pk->public_key = certificate->get_public_key(certificate); + pk->dns_auth_level = dns_auth_level; + pk->until_time = until; + delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); + install_public_key(pk, &pubkeys); } -} - -/* 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) -{ - 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 cert_t *cert) { - public_key_t *revoked_key = cert->public_key; + public_key_t *revoked_key = cert->cert->get_public_key(cert->cert); pubkey_list_t *p, **pp; p = pubkeys; @@ -1413,6 +1375,7 @@ void remove_x509_public_key(const x509cert_t *cert) } p =*pp; } + revoked_key->destroy(revoked_key); } /* @@ -1426,34 +1389,32 @@ void list_public_keys(bool utc) { whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, "List of Public Keys:"); - whack_log(RC_COMMENT, " "); } while (p != NULL) { 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]; + chunk_t keyid; - 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", + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, " identity: '%Y'", key->id); + whack_log(RC_COMMENT, " pubkey: %N %4d bits, until %T %s", key_type_names, public->get_type(public), public->get_keysize(public) * 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) + if (public->get_fingerprint(public, KEY_ID_PUBKEY_INFO_SHA1, &keyid)) + { + whack_log(RC_COMMENT," keyid: %#B", &keyid); + } + if (key->issuer) { - dntoa(buf, BUF_LEN, key->issuer); - whack_log(RC_COMMENT," issuer: '%s'", buf); + whack_log(RC_COMMENT," issuer: \"%Y\"", key->issuer); } - if (key->serial.len > 0) + if (key->serial.len) { - datatot(key->serial.ptr, key->serial.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT," serial: %s", buf); + whack_log(RC_COMMENT," serial: %#B", &key->serial); } p = p->next; } diff --git a/src/pluto/keys.h b/src/pluto/keys.h index 8bc94d839..d856c0009 100644 --- a/src/pluto/keys.h +++ b/src/pluto/keys.h @@ -16,6 +16,7 @@ #ifndef _KEYS_H #define _KEYS_H +#include <utils/identification.h> #include <credentials/keys/private_key.h> #include <credentials/keys/public_key.h> @@ -44,22 +45,19 @@ struct connection; extern const chunk_t *get_preshared_secret(const struct connection *c); extern private_key_t *get_private_key(const struct connection *c); -extern private_key_t *get_x509_private_key(const x509cert_t *cert); +extern private_key_t *get_x509_private_key(const cert_t *cert); /* public key machinery */ typedef struct pubkey pubkey_t; struct pubkey { - struct id id; + identification_t *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; + time_t last_tried_time, last_worked_time, until_time; + identification_t *issuer; chunk_t serial; public_key_t *public_key; }; @@ -77,23 +75,19 @@ 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, key_type_t type, - chunk_t issuer, chunk_t serial); +extern void delete_public_keys(identification_t *id, key_type_t type, + identification_t *issuer, chunk_t serial); extern pubkey_t *reference_key(pubkey_t *pk); extern void unreference_key(pubkey_t **pkp); - -extern bool add_public_key(const struct id *id, +extern bool add_public_key(identification_t *id, enum dns_auth_level dns_auth_level, enum pubkey_alg alg, chunk_t rfc3110_key, pubkey_list_t **head); - -extern bool has_private_key(cert_t cert); -extern void add_x509_public_key(x509cert_t *cert, time_t until - , 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); -extern void remove_x509_public_key(const x509cert_t *cert); +extern bool has_private_key(cert_t *cert); +extern void add_public_key_from_cert(cert_t *cert, time_t until, + enum dns_auth_level dns_auth_level); +extern void remove_x509_public_key(const cert_t *cert); extern void list_public_keys(bool utc); struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ diff --git a/src/pluto/log.c b/src/pluto/log.c index e34409f1c..2f3536ff3 100644 --- a/src/pluto/log.c +++ b/src/pluto/log.c @@ -38,12 +38,13 @@ #include "server.h" #include "state.h" #include "connections.h" +#include "myid.h" #include "kernel.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(connection_t *c); /* forward */ bool @@ -77,7 +78,7 @@ static TAILQ_HEAD(perpeer, connection) perpeer_list; */ 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 */ +connection_t *cur_connection = NULL; /* current connection, for diagnostics */ const ip_address *cur_from = NULL; /* source of current current message */ u_int16_t cur_from_port; /* host order */ @@ -99,12 +100,12 @@ static void pluto_dbg(int level, char *fmt, ...) else if (cur_debugging & DBG_RAW) { debug_level = 3; - } + } else if (cur_debugging & DBG_PARSING) { debug_level = 2; } - else + else { debug_level = 1; } @@ -245,7 +246,7 @@ 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 + connection_t *c = cur_state != NULL ? cur_state->st_connection : cur_connection; buf[0] = '\0'; @@ -293,7 +294,7 @@ fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap) } static void -perpeer_logclose(struct connection *c) +perpeer_logclose(connection_t *c) { /* only free/close things if we had used them! */ if (c->log_file != NULL) @@ -308,7 +309,7 @@ perpeer_logclose(struct connection *c) } void -perpeer_logfree(struct connection *c) +perpeer_logfree(connection_t *c) { perpeer_logclose(c); if (c->log_file_name != NULL) @@ -321,7 +322,7 @@ perpeer_logfree(struct connection *c) /* open the per-peer log */ static void -open_peerlog(struct connection *c) +open_peerlog(connection_t *c) { syslog(LOG_INFO, "opening log file for conn %s", c->name); @@ -725,7 +726,7 @@ lset_t cur_debugging = DBG_NONE; void -extra_debugging(const struct connection *c) +extra_debugging(const connection_t *c) { if(c == NULL) { @@ -835,8 +836,8 @@ static void show_loaded_plugins() char buf[BUF_LEN], *plugin; int len = 0; enumerator_t *enumerator; - - buf[0] = '\0'; + + buf[0] = '\0'; enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin)) { diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c index 228827f2a..03ec7f41f 100644 --- a/src/pluto/modecfg.c +++ b/src/pluto/modecfg.c @@ -26,6 +26,7 @@ #include <freeswan.h> #include <library.h> +#include <attributes/attributes.h> #include <crypto/prfs/prf.h> #include "constants.h" @@ -81,11 +82,10 @@ struct internal_addr bool xauth_status; }; -/* +/** * Initialize an internal_addr struct */ -static void -init_internal_addr(internal_addr_t *ia) +static void init_internal_addr(internal_addr_t *ia) { int i; @@ -106,46 +106,65 @@ init_internal_addr(internal_addr_t *ia) anyaddr(AF_INET, &ia->dns[i]); } - /* initialize WINS server information */ + /* initialize NBNS server information */ for (i = 0; i < NBNS_SERVER_MAX; i++) { anyaddr(AF_INET, &ia->nbns[i]); } } -/* - * get internal IP address for a connection +/** + * Get internal IP address for a connection */ -static void -get_internal_addr(struct connection *c, internal_addr_t *ia) +static void get_internal_addr(connection_t *c, host_t *requested_vip, + internal_addr_t *ia) { int i, dns_idx = 0, nbns_idx = 0; + enumerator_t *enumerator; + configuration_attribute_type_t type; + chunk_t value; + host_t *vip = NULL; if (isanyaddr(&c->spd.that.host_srcip)) { - /* not defined in connection - fetch it from LDAP */ + if (c->spd.that.pool) + { + vip = lib->attributes->acquire_address(lib->attributes, + c->spd.that.pool, c->spd.that.id, + requested_vip); + if (vip) + { + chunk_t addr = vip->get_address(vip); + + plog("assigning virtual IP %H to peer", vip); + initaddr(addr.ptr, addr.len, vip->get_family(vip), &ia->ipaddr); + + } + } + else + { + plog("no virtual IP found"); + } } 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); + vip = host_create_from_sockaddr((sockaddr_t*)&ia->ipaddr); + plog("assigning virtual IP %H to peer", vip); } if (!isanyaddr(&ia->ipaddr)) /* We got an IP address, send it */ { + c->spd.that.host_srcip = ia->ipaddr; 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 */ + /* assign DNS servers from strongswan.conf */ for (i = 1; i <= DNS_SERVER_MAX; i++) { char dns_key[16], *dns_str; @@ -158,20 +177,20 @@ get_internal_addr(struct connection *c, internal_addr_t *ia) sa_family_t family = strchr(dns_str, ':') ? AF_INET6 : AF_INET; ugh = ttoaddr(dns_str, 0, family, &ia->dns[dns_idx]); - if (ugh != NULL) + if (ugh) { 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() */ + /* differentiate between IP4 and IP6 in modecfg_build_msg() */ ia->attr_set |= LELEM(INTERNAL_IP4_DNS); dns_idx++; } } - /* assign WINS servers */ + /* assign NBNS servers from strongswan.conf */ for (i = 1; i <= NBNS_SERVER_MAX; i++) { char nbns_key[16], *nbns_str; @@ -184,26 +203,93 @@ get_internal_addr(struct connection *c, internal_addr_t *ia) sa_family_t family = strchr(nbns_str, ':') ? AF_INET6 : AF_INET; ugh = ttoaddr(nbns_str, 0, family, &ia->nbns[nbns_idx]); - if (ugh != NULL) + if (ugh) { - plog("error in WINS server address: %s", ugh); + plog("error in NBNS server address: %s", ugh); continue; } plog("assigning NBNS server %s to peer", nbns_str); - /* differentiate between IP4 and IP6 in modecfg_build_msg() */ + /* differentiate between IP4 and IP6 in modecfg_build_msg() */ ia->attr_set |= LELEM(INTERNAL_IP4_NBNS); nbns_idx++; } } + + /* assign attributes from registered providers */ + enumerator = lib->attributes->create_responder_enumerator(lib->attributes, + c->spd.that.id, vip); + while (enumerator->enumerate(enumerator, &type, &value)) + { + err_t ugh; + host_t *server; + sa_family_t family = AF_INET; + + switch (type) + { + case INTERNAL_IP6_DNS: + family = AF_INET6; + /* fallthrough */ + case INTERNAL_IP4_DNS: + if (dns_idx >= DNS_SERVER_MAX) + { + plog("exceeded the maximum number of %d DNS servers", + DNS_SERVER_MAX); + break; + } + ugh = initaddr(value.ptr, value.len, family, &ia->dns[dns_idx]); + if (ugh) + { + plog("error in DNS server address: %s", ugh); + break; + } + server = host_create_from_chunk(family, value, 0); + plog("assigning DNS server %H to peer", server); + server->destroy(server); + + /* differentiate between IP4 and IP6 in modecfg_build_msg() */ + ia->attr_set |= LELEM(INTERNAL_IP4_DNS); + dns_idx++; + break; + + case INTERNAL_IP6_NBNS: + family = AF_INET6; + /* fallthrough */ + case INTERNAL_IP4_NBNS: + if (nbns_idx >= NBNS_SERVER_MAX) + { + plog("exceeded the maximum number of %d NBNS servers", + NBNS_SERVER_MAX); + break; + } + ugh = initaddr(value.ptr, value.len, family, &ia->nbns[nbns_idx]); + if (ugh) + { + plog("error in NBNS server address: %s", ugh); + break; + } + server = host_create_from_chunk(family, value, 0); + plog("assigning NBNS server %H to peer", server); + server->destroy(server); + + /* differentiate between IP4 and IP6 in modecfg_build_msg() */ + ia->attr_set |= LELEM(INTERNAL_IP4_NBNS); + nbns_idx++; + break; + + default: + break; + } + } + enumerator->destroy(enumerator); + DESTROY_IF(vip); } -/* +/** * Set srcip and client subnet to internal IP address */ -static bool -set_internal_addr(struct connection *c, internal_addr_t *ia) +static bool set_internal_addr(connection_t *c, internal_addr_t *ia) { if (ia->attr_set & LELEM(INTERNAL_IP4_ADDRESS) && !isanyaddr(&ia->ipaddr)) @@ -227,7 +313,7 @@ set_internal_addr(struct connection *c, internal_addr_t *ia) plog("replacing virtual IP source address %s by %s" , old_srcip, new_srcip); } - + /* setting srcip */ c->spd.this.host_srcip = ia->ipaddr; @@ -240,7 +326,7 @@ set_internal_addr(struct connection *c, internal_addr_t *ia) return FALSE; } -/* +/** * Compute HASH of Mode Config. */ static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, @@ -263,19 +349,18 @@ static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, DBG(DBG_CRYPT, DBG_log("ModeCfg HASH computed:"); DBG_dump("", dest, prf_block_size) - ) + ) return prf_block_size; } -/* +/** * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS) */ -static stf_status -modecfg_build_msg(struct state *st, pb_stream *rbody - , u_int16_t msg_type - , internal_addr_t *ia - , u_int16_t ap_id) +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_char *r_hash_start, *r_hashval; @@ -322,7 +407,7 @@ modecfg_build_msg(struct state *st, pb_stream *rbody is_unity_attr_set = FALSE; } } - + dont_advance = FALSE; if (attr_set & 1) @@ -384,7 +469,7 @@ modecfg_build_msg(struct state *st, pb_stream *rbody mask[t] = 0xff; m -= 8; } -#endif +#endif if (st->st_connection->spd.this.client.maskbits == 0) { mask = 0; @@ -491,11 +576,11 @@ modecfg_build_msg(struct state *st, pb_stream *rbody return STF_OK; } -/* +/** * Send ModeCfg message */ -static stf_status -modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia) +static stf_status modecfg_send_msg(struct state *st, int isama_type, + internal_addr_t *ia) { pb_stream msg; pb_stream rbody; @@ -549,11 +634,10 @@ modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia) return STF_OK; } -/* +/** * Parse a ModeCfg attribute payload */ -static stf_status -modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) +static stf_status modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) { struct isakmp_attribute attr; pb_stream strattr; @@ -610,12 +694,12 @@ modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) ugh = initaddr((char *)(strattr.cur), 4, AF_INET, &ia->nbns[nbns_idx]); if (ugh != NULL) { - plog("received invalid IPv4 WINS server address: %s", ugh); + plog("received invalid IPv4 NBNS server address: %s", ugh); } else { addrtot(&ia->nbns[nbns_idx], 0, buf, BUF_LEN); - plog("received IPv4 WINS server address %s", buf); + plog("received IPv4 NBNS server address %s", buf); nbns_idx++; } } @@ -644,12 +728,12 @@ modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) ugh = initaddr((char *)(strattr.cur), 16, AF_INET6, &ia->nbns[nbns_idx]); if (ugh != NULL) { - plog("received invalid IPv6 WINS server address: %s", ugh); + plog("received invalid IPv6 NBNS server address: %s", ugh); } else { addrtot(&ia->nbns[nbns_idx], 0, buf, BUF_LEN); - plog("received IPv6 WINS server address %s", buf); + plog("received IPv6 NBNS server address %s", buf); nbns_idx++; } } @@ -735,12 +819,11 @@ modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) return STF_OK; } -/* +/** * Parse a ModeCfg message */ -static stf_status -modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id - , 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) { struct state *const st = md->st; struct payload_digest *p; @@ -788,12 +871,12 @@ modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id return STF_IGNORE; } -/* +/** * Send ModeCfg request message from client to server in pull mode */ -stf_status -modecfg_send_request(struct state *st) +stf_status modecfg_send_request(struct state *st) { + connection_t *c = st->st_connection; stf_status stat; internal_addr_t ia; @@ -801,6 +884,7 @@ modecfg_send_request(struct state *st) ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS) | LELEM(INTERNAL_IP4_NETMASK); + ia.ipaddr = c->spd.this.host_srcip; plog("sending ModeCfg request"); st->st_state = STATE_MODE_CFG_I1; @@ -817,14 +901,14 @@ modecfg_send_request(struct state *st) * * used in ModeCfg pull mode, on the server (responder) */ -stf_status -modecfg_inR0(struct msg_digest *md) +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; + host_t *requested_vip; stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia); if (stat != STF_OK) @@ -832,9 +916,20 @@ modecfg_inR0(struct msg_digest *md) return stat; } + if (ia.attr_set & LELEM(INTERNAL_IP4_ADDRESS)) + { + requested_vip = host_create_from_sockaddr((sockaddr_t*)&ia.ipaddr); + } + else + { + requested_vip = host_create_any(AF_INET); + } + plog("peer requested virtual IP %H", requested_vip); + want_unity_banner = (ia.unity_attr_set & LELEM(UNITY_BANNER - UNITY_BASE)) != LEMPTY; init_internal_addr(&ia); - get_internal_addr(st->st_connection, &ia); + get_internal_addr(st->st_connection, requested_vip, &ia); + requested_vip->destroy(requested_vip); if (want_unity_banner) { @@ -859,10 +954,9 @@ modecfg_inR0(struct msg_digest *md) /* STATE_MODE_CFG_I1: * HDR*, HASH, ATTR(REPLY=IP) * - * used in ModeCfg pull mode, on the client (initiator) + * used in ModeCfg pull mode, on the client (initiator) */ -stf_status -modecfg_inI1(struct msg_digest *md) +stf_status modecfg_inI1(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; @@ -882,17 +976,19 @@ modecfg_inI1(struct msg_digest *md) } -/* +/** * Send ModeCfg set message from server to client in push mode */ -stf_status -modecfg_send_set(struct state *st) +stf_status modecfg_send_set(struct state *st) { stf_status stat; internal_addr_t ia; + host_t *vip; init_internal_addr(&ia); - get_internal_addr(st->st_connection, &ia); + vip = host_create_any(AF_INET); + get_internal_addr(st->st_connection, vip, &ia); + vip->destroy(vip); #ifdef CISCO_QUIRKS ia.unity_banner = UNITY_BANNER_STR; @@ -914,8 +1010,7 @@ modecfg_send_set(struct state *st) * * used in ModeCfg push mode, on the client (initiator). */ -stf_status -modecfg_inI0(struct msg_digest *md) +stf_status modecfg_inI0(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; @@ -958,8 +1053,7 @@ modecfg_inI0(struct msg_digest *md) * * used in ModeCfg push mode, on the server (responder) */ -stf_status -modecfg_inR3(struct msg_digest *md) +stf_status modecfg_inR3(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; @@ -977,11 +1071,10 @@ modecfg_inR3(struct msg_digest *md) return STF_OK; } -/* +/** * Send XAUTH credentials request (username + password) */ -stf_status -xauth_send_request(struct state *st) +stf_status xauth_send_request(struct state *st) { stf_status stat; internal_addr_t ia; @@ -1005,8 +1098,7 @@ xauth_send_request(struct state *st) * * used on the XAUTH client (initiator) */ -stf_status -xauth_inI0(struct msg_digest *md) +stf_status xauth_inI0(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; @@ -1111,8 +1203,7 @@ xauth_inI0(struct msg_digest *md) * * used on the XAUTH server (responder) */ -stf_status -xauth_inR1(struct msg_digest *md) +stf_status xauth_inR1(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; @@ -1148,13 +1239,14 @@ xauth_inR1(struct msg_digest *md) plog("user password attribute is missing in XAUTH reply"); st->st_xauth.status = FALSE; } - else + 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)); + snprintf(peer.id, sizeof(peer.id), "%Y", + md->st->st_connection->spd.that.id); DBG(DBG_CONTROL, DBG_log("peer xauth user name is '%.*s'" @@ -1191,8 +1283,7 @@ xauth_inR1(struct msg_digest *md) * * used on the XAUTH client (initiator) */ -stf_status -xauth_inI1(struct msg_digest *md) +stf_status xauth_inI1(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; @@ -1204,7 +1295,7 @@ xauth_inI1(struct msg_digest *md) if (stat != STF_OK) { /* notification payload - not exactly the right choice, but okay */ - md->note = ATTRIBUTES_NOT_SUPPORTED; + md->note = ISAKMP_ATTRIBUTES_NOT_SUPPORTED; return stat; } @@ -1243,8 +1334,7 @@ xauth_inI1(struct msg_digest *md) * * used on the XAUTH server (responder) */ -stf_status -xauth_inR2(struct msg_digest *md) +stf_status xauth_inR2(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; diff --git a/src/pluto/modecfg.h b/src/pluto/modecfg.h index 86bfc6ed2..bc1443012 100644 --- a/src/pluto/modecfg.h +++ b/src/pluto/modecfg.h @@ -1,7 +1,7 @@ /* Mode Config related functions * Copyright (C) 2001-2002 Colubris Networks * Copyright (C) 2003-2004 Xelerance Corporation - * + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your diff --git a/src/pluto/myid.c b/src/pluto/myid.c new file mode 100644 index 000000000..ad4eefd15 --- /dev/null +++ b/src/pluto/myid.c @@ -0,0 +1,121 @@ +/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) + * Copyright (C) 1999-2001 D. Hugh Redelmeier + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <errno.h> +#include <unistd.h> + +#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */ +# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */ +#endif + +#include <utils/identification.h> + +#include <freeswan.h> + +#include "myid.h" +#include "constants.h" +#include "defs.h" +#include "log.h" +#include "connections.h" +#include "packet.h" +#include "whack.h" + +enum myid_state myid_state = MYID_UNKNOWN; + +identification_t *myids[MYID_SPECIFIED+1]; /* %myid */ + +/** + * Fills in myid from environment variable IPSECmyid or defaultrouteaddr + */ +void init_myid(void) +{ + myid_state = MYID_UNKNOWN; + { + enum myid_state s; + + for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) + { + myids[s] = identification_create_from_string("%any"); + } + } + set_myid(MYID_SPECIFIED, getenv("IPSECmyid")); + set_myid(MYID_IP, getenv("defaultrouteaddr")); + set_myFQDN(); +} + +/** + * Free myid module + */ +void free_myid(void) +{ + enum myid_state s; + + for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) + { + DESTROY_IF(myids[s]); + } +} + +void set_myid(enum myid_state s, char *idstr) +{ + if (idstr) + { + myids[s]->destroy(myids[s]); + myids[s] = identification_create_from_string(idstr); + if (s == MYID_SPECIFIED) + { + myid_state = MYID_SPECIFIED; + } + } +} + +void set_myFQDN(void) +{ + char FQDN[HOST_NAME_MAX + 1]; + int r = gethostname(FQDN, sizeof(FQDN)); + size_t len; + + if (r != 0) + { + log_errno((e, "gethostname() failed in set_myFQDN")); + } + else + { + FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */ + len = strlen(FQDN); + + if (len > 0 && FQDN[len-1] == '.') + { + /* nuke trailing . */ + FQDN[len-1] = '\0'; + } + if (!strcaseeq(FQDN, "localhost.localdomain")) + { + myids[MYID_HOSTNAME]->destroy(myids[MYID_HOSTNAME]); + myids[MYID_HOSTNAME] = identification_create_from_string(FQDN); + } + } +} + +void show_myid_status(void) +{ + whack_log(RC_COMMENT, "%%myid = '%Y'", myids[myid_state]); +} + +/* + * Local Variables: + * c-basic-offset:4 + * c-style: pluto + * End: + */ diff --git a/src/pluto/myid.h b/src/pluto/myid.h new file mode 100644 index 000000000..012a34968 --- /dev/null +++ b/src/pluto/myid.h @@ -0,0 +1,38 @@ +/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) + * Copyright (C) 1999-2001 D. Hugh Redelmeier + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef _MYID_H +#define _MYID_H + +#include <utils/identification.h> + +extern void init_myid(void); +extern void free_myid(void); + +enum myid_state { + MYID_UNKNOWN, /* not yet figured out */ + MYID_HOSTNAME, /* our current hostname */ + MYID_IP, /* our default IP address */ + MYID_SPECIFIED /* as specified by ipsec.conf */ +}; + +extern enum myid_state myid_state; +extern identification_t* myids[MYID_SPECIFIED+1]; /* %myid */ +extern void set_myid(enum myid_state s, char *); +extern void show_myid_status(void); +extern void set_myFQDN(void); + +#define resolve_myid(id) ((id)->get_type(id) == ID_MYID? myids[myid_state] : (id)) + +#endif /* _MYID_H */ diff --git a/src/pluto/nat_traversal.c b/src/pluto/nat_traversal.c index de3972fe2..feedf2aad 100644 --- a/src/pluto/nat_traversal.c +++ b/src/pluto/nat_traversal.c @@ -147,7 +147,7 @@ static void _natd_hash(const struct hash_desc *oakley_hasher, char *hash, addr_chunk = chunk_from_thing(ip->u.v6.sin6_addr.s6_addr); break; default: - addr_chunk = chunk_empty; /* should never occur */ + addr_chunk = chunk_empty; /* should never occur */ } hasher->get_hash(hasher, addr_chunk, NULL); hasher->get_hash(hasher, port_chunk, hash); @@ -310,7 +310,7 @@ bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, DBG(DBG_EMITTING, DBG_log("sending NATD payloads") ) - + /* * First one with sender IP & port */ @@ -348,7 +348,7 @@ bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, /* * nat_traversal_natoa_lookup() - * + * * Look for NAT-OA in message */ void nat_traversal_natoa_lookup(struct msg_digest *md) @@ -435,7 +435,7 @@ void nat_traversal_natoa_lookup(struct msg_digest *md) { char ip_t[ADDRTOT_BUF]; addrtot(&ip, 0, ip_t, sizeof(ip_t)); - + DBG_log("received NAT-OA: %s", ip_t); } ) @@ -514,7 +514,7 @@ void nat_traversal_show_result (u_int32_t nt, u_int16_t sport) mth = natt_type_bitnames[2]; break; } - + switch (nt & NAT_T_DETECTED) { case 0: @@ -600,7 +600,7 @@ 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; + const connection_t *c = st->st_connection; if (!c) return; @@ -658,7 +658,7 @@ struct _new_mapp_nfo { static void nat_traversal_find_new_mapp_state (struct state *st, void *data) { - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data; if (c != NULL @@ -720,7 +720,7 @@ static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport, void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st) { - struct connection *c = st ? st->st_connection : NULL; + connection_t *c = st ? st->st_connection : NULL; struct iface *i = NULL; if ((st == NULL) || (c == NULL)) @@ -804,7 +804,7 @@ struct _new_klips_mapp_nfo { static void nat_t_new_klips_mapp (struct state *st, void *data) { - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data; if (c != NULL && st->st_esp.present diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c index 8e428a759..b1f558ebf 100644 --- a/src/pluto/ocsp.c +++ b/src/pluto/ocsp.c @@ -67,19 +67,19 @@ static const char *const response_status_names[] = { 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; + identification_t *responder_id_name; + chunk_t responder_id_key; + time_t produced_at; + chunk_t responses; + chunk_t nonce; + int algorithm; + chunk_t signature; }; const response_t empty_response = { { NULL, 0 } , /* tbs */ - { NULL, 0 } , /* responder_id_name */ + NULL , /* responder_id_name */ { NULL, 0 } , /* responder_id_key */ UNDEFINED_TIME, /* produced_at */ { NULL, 0 } , /* single_response */ @@ -105,16 +105,16 @@ struct single_response { }; 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 */ + CRL_REASON_UNSPECIFIED, /* revocationReason */ + UNDEFINED_TIME , /* this_update */ + UNDEFINED_TIME /* next_update */ }; @@ -126,26 +126,17 @@ struct request_list { }; /* some OCSP specific prefabricated ASN.1 constants */ - -static u_char ASN1_nonce_oid_str[] = { +static const chunk_t ASN1_nonce_oid = chunk_from_chars( 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 -}; - -static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); - -static u_char ASN1_response_oid_str[] = { +); +static const chunk_t ASN1_response_oid = chunk_from_chars( 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 -}; - -static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); - -static u_char ASN1_response_content_str[] = { +); +static const chunk_t ASN1_response_content = chunk_from_chars( 0x04, 0x0D, 0x30, 0x0B, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 -}; - -static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); +); /* default OCSP uri */ static chunk_t ocsp_default_uri; @@ -154,7 +145,7 @@ static chunk_t ocsp_default_uri; static ocsp_location_t *ocsp_cache = NULL; /* static temporary storage for ocsp requestor information */ -static x509cert_t *ocsp_requestor_cert = NULL; +static cert_t *ocsp_requestor_cert = NULL; static smartcard_t *ocsp_requestor_sc = NULL; @@ -290,27 +281,38 @@ static const asn1Object_t singleResponseObjects[] = { * 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 cert_t *cert, ocsp_location_t *location) { + certificate_t *certificate = cert->cert; + identification_t *issuer = certificate->get_issuer(certificate); + x509_t *x509 = (x509_t*)certificate; + chunk_t issuer_dn = issuer->get_encoding(issuer); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); hasher_t *hasher; static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */ - - location->uri = cert->accessLocation; - if (location->uri.ptr == NULL) + enumerator_t *enumerator = x509->create_ocsp_uri_enumerator(x509); + + location->uri = NULL; + while (enumerator->enumerate(enumerator, &location->uri)) + { + break; + } + enumerator->destroy(enumerator); + + if (location->uri == NULL) { - ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID); - if (ca != NULL && ca->ocspuri != NULL) + ca_info_t *ca = get_ca_info(issuer, authKeyID); + if (ca && ca->ocspuri) { - location->uri = chunk_create(ca->ocspuri, strlen(ca->ocspuri)); + location->uri = ca->ocspuri; } else { /* abort if no ocsp location uri is defined */ return FALSE; } } - + /* compute authNameID from as SHA-1 hash of issuer DN */ location->authNameID = chunk_create(digest, HASH_SIZE_SHA1); hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); @@ -318,23 +320,22 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio { return FALSE; } - hasher->get_hash(hasher, cert->issuer, digest); + hasher->get_hash(hasher, issuer_dn, digest); hasher->destroy(hasher); location->next = NULL; - location->issuer = cert->issuer; - location->authKeyID = cert->authKeyID; - location->authKeySerialNumber = cert->authKeySerialNumber; - - if (cert->authKeyID.ptr == NULL) + location->issuer = issuer; + location->authKeyID = authKeyID; + + if (authKeyID.ptr == NULL) { - x509cert_t *authcert = get_authcert(cert->issuer - , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA); + cert_t *authcert = get_authcert(issuer, authKeyID, X509_CA); - if (authcert != NULL) + if (authcert) { - location->authKeyID = authcert->subjectKeyID; - location->authKeySerialNumber = authcert->serialNumber; + x509_t *x509 = (x509_t*)authcert->cert; + + location->authKeyID = x509->get_subjectKeyIdentifier(x509); } } @@ -349,11 +350,10 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio */ static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b) { - return ((a->authKeyID.ptr != NULL) + return ((a->authKeyID.ptr) ? same_keyid(a->authKeyID, b->authKeyID) - : (same_dn(a->issuer, b->issuer) - && same_serial(a->authKeySerialNumber, b->authKeySerialNumber))) - && chunk_equals(a->uri, b->uri); + : a->issuer->equals(a->issuer, b->issuer)) + && streq(a->uri, b->uri); } /** @@ -362,7 +362,7 @@ static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t * ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain) { - while (chain != NULL) + while (chain) { if (same_ocsp_location(loc, chain)) return chain; @@ -393,7 +393,7 @@ static cert_status_t get_ocsp_status(const ocsp_location_t *loc, certinfop = &location->certinfo; certinfo = *certinfop; - while (certinfo != NULL) + while (certinfo) { cmp = chunk_compare(serialNumber, certinfo->serialNumber); if (cmp <= 0) @@ -416,30 +416,34 @@ static cert_status_t get_ocsp_status(const ocsp_location_t *loc, /** * Verify the ocsp status of a certificate */ -cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until, +cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until, time_t *revocationDate, crl_reason_t *revocationReason) { + x509_t *x509 = (x509_t*)cert->cert; + chunk_t serialNumber = x509->get_serial(x509); cert_status_t status; ocsp_location_t location; - time_t nextUpdate = 0; + time_t nextUpdate = UNDEFINED_TIME; *revocationDate = UNDEFINED_TIME; - *revocationReason = REASON_UNSPECIFIED; - + *revocationReason = CRL_REASON_UNSPECIFIED; + /* is an ocsp location defined? */ if (!build_ocsp_location(cert, &location)) + { return CERT_UNDEFINED; + } lock_ocsp_cache("verify_by_ocsp"); - status = get_ocsp_status(&location, cert->serialNumber, &nextUpdate + status = get_ocsp_status(&location, serialNumber, &nextUpdate , revocationDate, revocationReason); unlock_ocsp_cache("verify_by_ocsp"); if (status == CERT_UNDEFINED || nextUpdate < time(NULL)) { plog("ocsp status is stale or not in cache"); - add_ocsp_fetch_request(&location, cert->serialNumber); + add_ocsp_fetch_request(&location, serialNumber); /* inititate fetching of ocsp status */ wake_fetch_thread("verify_by_ocsp"); @@ -457,14 +461,14 @@ void check_ocsp(void) lock_ocsp_cache("check_ocsp"); location = ocsp_cache; - - while (location != NULL) + + while (location) { char buf[BUF_LEN]; bool first = TRUE; ocsp_certinfo_t *certinfo = location->certinfo; - while (certinfo != NULL) + while (certinfo) { if (!certinfo->once) { @@ -473,9 +477,8 @@ void check_ocsp(void) DBG(DBG_CONTROL, if (first) { - dntoa(buf, BUF_LEN, location->issuer); - DBG_log("issuer: '%s'", buf); - if (location->authKeyID.ptr != NULL) + DBG_log("issuer: \"%Y\"", location->issuer); + if (location->authKeyID.ptr) { datatot(location->authKeyID.ptr, location->authKeyID.len , ':', buf, BUF_LEN); @@ -514,7 +517,7 @@ static void free_certinfos(ocsp_certinfo_t *chain) { ocsp_certinfo_t *certinfo; - while (chain != NULL) + while (chain) { certinfo = chain; chain = chain->next; @@ -527,11 +530,10 @@ static void free_certinfos(ocsp_certinfo_t *chain) */ static void free_ocsp_location(ocsp_location_t* location) { - free(location->issuer.ptr); + DESTROY_IF(location->issuer); free(location->authNameID.ptr); free(location->authKeyID.ptr); - free(location->authKeySerialNumber.ptr); - free(location->uri.ptr); + free(location->uri); free_certinfos(location->certinfo); free(location); } @@ -541,7 +543,7 @@ static void free_ocsp_location(ocsp_location_t* location) */ void free_ocsp_locations(ocsp_location_t **chain) { - while (*chain != NULL) + while (*chain) { ocsp_location_t *location = *chain; *chain = location->next; @@ -576,73 +578,55 @@ void list_ocsp_locations(ocsp_location_t *location, bool requests, { bool first = TRUE; - while (location != NULL) + while (location) { ocsp_certinfo_t *certinfo = location->certinfo; - if (certinfo != NULL) + if (certinfo) { - u_char buf[BUF_LEN]; - if (first) { whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of OCSP %s:", requests? - "fetch requests":"responses"); + 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) + if (location->issuer) { - datatot(location->authNameID.ptr, location->authNameID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authname: %s", buf); + whack_log(RC_COMMENT, " issuer: \"%Y\"", location->issuer); } - if (location->authKeyID.ptr != NULL) + whack_log(RC_COMMENT, " uri: '%s'", location->uri); + if (location->authNameID.ptr) { - datatot(location->authKeyID.ptr, location->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " authname: %#B", &location->authNameID); } - if (location->authKeySerialNumber.ptr != NULL) + if (location->authKeyID.ptr) { - datatot(location->authKeySerialNumber.ptr - , location->authKeySerialNumber.len, ':', buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " authkey: %#B", &location->authKeyID); } - while (certinfo != NULL) + while (certinfo) { - char thisUpdate[BUF_LEN]; - - snprintf(thisUpdate, BUF_LEN, "%T", &certinfo->thisUpdate, utc); - if (requests) { - whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate - , certinfo->trials); + whack_log(RC_COMMENT, " serial: %#B, %d trials", + &certinfo->serialNumber, certinfo->trials); } else if (certinfo->once) { - whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate - , (certinfo->nextUpdate < time(NULL))? " (expired)": ""); + whack_log(RC_COMMENT, " serial: %#B, %s, once%s", + &certinfo->serialNumber, + cert_status_names[certinfo->status], + (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)); + whack_log(RC_COMMENT, " serial: %#B, %s, until %T %s", + &certinfo->serialNumber, + cert_status_names[certinfo->status], + &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; } } @@ -662,7 +646,7 @@ void list_ocsp_cache(bool utc, bool strict) static bool get_ocsp_requestor_cert(ocsp_location_t *location) { - x509cert_t *cert = NULL; + cert_t *cert = NULL; /* initialize temporary static storage */ ocsp_requestor_cert = NULL; @@ -671,17 +655,17 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) for (;;) { - char buf[BUF_LEN]; + certificate_t *certificate; /* looking for a certificate from the same issuer */ - cert = get_x509cert(location->issuer, location->authKeySerialNumber - ,location->authKeyID, cert); + cert = get_x509cert(location->issuer, location->authKeyID, cert); if (cert == NULL) + { break; - + } + certificate = cert->cert; DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("candidate: '%s'", buf); + DBG_log("candidate: '%Y'", certificate->get_subject(certificate)); ) if (cert->smartcard) @@ -689,7 +673,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) /* look for a matching private key on a smartcard */ smartcard_t *sc = scx_get(cert); - if (sc != NULL) + if (sc) { DBG(DBG_CONTROL, DBG_log("matching smartcard found") @@ -708,7 +692,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location) /* look for a matching private key in the chained list */ private_key_t *private = get_x509_private_key(cert); - if (private != NULL) + if (private) { DBG(DBG_CONTROL, DBG_log("matching private key found") @@ -726,8 +710,7 @@ static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) { hasher_t *hasher; u_char *pos; - u_char digest_buf[HASH_SIZE_SHA1]; - chunk_t digest = chunk_from_buf(digest_buf); + chunk_t digest; chunk_t digest_info, sigdata; size_t siglen = 0; @@ -756,15 +739,15 @@ static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) { return chunk_empty; } - hasher->get_hash(hasher, tbs, digest_buf); + hasher->allocate_hash(hasher, tbs, &digest); hasher->destroy(hasher); /* according to PKCS#1 v2.1 digest must be packaged into * an ASN.1 structure for encryption */ - digest_info = asn1_wrap(ASN1_SEQUENCE, "cm" + digest_info = asn1_wrap(ASN1_SEQUENCE, "mm" , asn1_algorithmIdentifier(OID_SHA1) - , asn1_simple_object(ASN1_OCTET_STRING, digest)); + , asn1_wrap(ASN1_OCTET_STRING, "m", digest)); pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); *pos++ = 0x00; @@ -784,9 +767,9 @@ static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) */ static chunk_t build_signature(chunk_t tbsRequest) { - chunk_t sigdata, certs; + chunk_t sigdata, cert, certs; - if (ocsp_requestor_sc != NULL) + if (ocsp_requestor_sc) { /* RSA signature is done on smartcard */ sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc); @@ -803,15 +786,13 @@ static chunk_t build_signature(chunk_t tbsRequest) } /* include our certificate */ - certs = asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_simple_object(ASN1_SEQUENCE - , ocsp_requestor_cert->certificate - ) - ); + cert = ocsp_requestor_cert->cert->get_encoding(ocsp_requestor_cert->cert); + certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_SEQUENCE, "m", cert)); /* build signature comprising algorithm, signature and cert */ return asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_wrap(ASN1_SEQUENCE, "cmm" + , asn1_wrap(ASN1_SEQUENCE, "mmm" , asn1_algorithmIdentifier(OID_SHA1_WITH_RSA) , sigdata , certs @@ -825,7 +806,7 @@ static chunk_t build_signature(chunk_t tbsRequest) */ static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo) { - chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm" + chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "mmmm" , asn1_algorithmIdentifier(OID_SHA1) , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID) , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID) @@ -847,7 +828,7 @@ static chunk_t build_request_list(ocsp_location_t *location) size_t datalen = 0; /* build content */ - while (certinfo != NULL) + while (certinfo) { /* build request for every certificate in list * and store them in a chained list @@ -865,7 +846,7 @@ static chunk_t build_request_list(ocsp_location_t *location) pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen); /* copy all in chained list, free list afterwards */ - while (reqs != NULL) + while (reqs) { request_list_t *req = reqs; @@ -882,9 +863,12 @@ static chunk_t build_request_list(ocsp_location_t *location) */ static chunk_t build_requestor_name(void) { + certificate_t *certificate = ocsp_requestor_cert->cert; + identification_t *subject = certificate->get_subject(certificate); + return asn1_wrap(ASN1_CONTEXT_C_1, "m" , asn1_simple_object(ASN1_CONTEXT_C_4 - , ocsp_requestor_cert->subject)); + , subject->get_encoding(subject))); } /** @@ -944,17 +928,13 @@ 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) + DBG_log("issuer: \"%Y\"", location->issuer); + if (location->authKeyID.ptr) { - datatot(location->authKeyID.ptr, location->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &location->authKeyID); } ) lock_certs_and_keys("build_ocsp_request"); @@ -981,14 +961,13 @@ chunk_t build_ocsp_request(ocsp_location_t *location) */ static bool valid_ocsp_response(response_t *res) { - int pathlen; - x509cert_t *authcert; + int pathlen, pathlen_constraint; + cert_t *authcert; lock_authcert_list("valid_ocsp_response"); - authcert = get_authcert(res->responder_id_name, chunk_empty - , res->responder_id_key, AUTH_OCSP | AUTH_CA); - + authcert = get_authcert(res->responder_id_name, res->responder_id_key, + X509_OCSP_SIGNER | X509_CA); if (authcert == NULL) { plog("no matching ocsp signer cert found"); @@ -999,7 +978,8 @@ static bool valid_ocsp_response(response_t *res) DBG_log("ocsp signer cert found") ) - if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert)) + if (!x509_check_signature(res->tbs, res->signature, res->algorithm, + authcert->cert)) { plog("signature of ocsp response is invalid"); unlock_authcert_list("valid_ocsp_response"); @@ -1010,43 +990,38 @@ static bool valid_ocsp_response(response_t *res) ) - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) + for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) { - u_char buf[BUF_LEN]; - err_t ugh = NULL; - time_t until; - - x509cert_t *cert = authcert; + cert_t *cert = authcert; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); + time_t not_before, not_after; DBG(DBG_CONTROL, - 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) + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } ) - ugh = check_validity(authcert, &until); - - if (ugh != NULL) + if (!certificate->get_validity(certificate, NULL, ¬_before, ¬_after)) { - plog("%s", ugh); + plog("certificate is invalid (valid from %T to %T)", + ¬_before, FALSE, ¬_after, FALSE); + unlock_authcert_list("valid_ocsp_response"); return FALSE; } - DBG(DBG_CONTROL, DBG_log("certificate is valid") ) - - authcert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); + authcert = get_authcert(issuer, authKeyID, X509_CA); if (authcert == NULL) { plog("issuer cacert not found"); @@ -1057,8 +1032,7 @@ static bool valid_ocsp_response(response_t *res) DBG_log("issuer cacert found") ) - if (!x509_check_signature(cert->tbsCertificate, cert->signature, - cert->algorithm, authcert)) + if (!certificate->issued_by(certificate, authcert->cert)) { plog("certificate signature is invalid"); unlock_authcert_list("valid_ocsp_response"); @@ -1068,17 +1042,28 @@ static bool valid_ocsp_response(response_t *res) DBG_log("certificate signature is valid") ) + /* check path length constraint */ + pathlen_constraint = x509->get_pathLenConstraint(x509); + if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT && + pathlen > pathlen_constraint) + { + plog("path length of %d violates constraint of %d", + pathlen, pathlen_constraint); + return FALSE; + } + /* check if cert is self-signed */ - if (same_dn(cert->issuer, cert->subject)) + if (x509->get_flags(x509) & X509_SELF_SIGNED) { DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") + DBG_log("reached self-signed root ca with a path length of %d", + pathlen) ) unlock_authcert_list("valid_ocsp_response"); return TRUE; } } - plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); unlock_authcert_list("valid_ocsp_response"); return FALSE; } @@ -1091,7 +1076,6 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) 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; @@ -1116,10 +1100,10 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) } break; case BASIC_RESPONSE_ID_BY_NAME: - res->responder_id_name = object; + res->responder_id_name = identification_create_from_encoding( + ID_DER_ASN1_DN, object); DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) + DBG_log(" '%Y'", res->responder_id_name) ) break; case BASIC_RESPONSE_ID_BY_KEY: @@ -1153,23 +1137,35 @@ static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) 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)) + cert_t *cert = malloc_thing(cert_t); + x509_t *x509; + + *cert = cert_empty; + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (cert->cert == NULL) + { + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log("parsing of embedded ocsp certificate failed") + ) + cert_free(cert); + break; + } + x509 = (x509_t*)cert->cert; + + if ((x509->get_flags(x509) & X509_OCSP_SIGNER) && + trust_authcert_candidate(cert, NULL)) { - add_authcert(cert, AUTH_OCSP); + add_authcert(cert, X509_OCSP_SIGNER); } else { DBG(DBG_CONTROL | DBG_PARSING, DBG_log("embedded ocsp certificate rejected") ) - free_x509cert(cert); + cert_free(cert); } } break; @@ -1292,7 +1288,7 @@ static bool parse_ocsp_single_response(chunk_t blob, int level0, break; case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: sres->revocationReason = (object.len == 1) - ? *object.ptr : REASON_UNSPECIFIED; + ? *object.ptr : CRL_REASON_UNSPECIFIED; break; case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: sres->status = CERT_UNKNOWN; @@ -1329,11 +1325,10 @@ ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t *location = malloc_thing(ocsp_location_t); /* unshare location fields */ - location->issuer = chunk_clone(loc->issuer); + location->issuer = loc->issuer->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->uri = strdup(loc->uri); location->certinfo = NULL; /* insert new ocsp location in front of chain */ @@ -1369,7 +1364,7 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, certinfop = &location->certinfo; certinfo = *certinfop; - while (certinfo != NULL) + while (certinfo) { cmp = chunk_compare(info->serialNumber, certinfo->serialNumber); if (cmp <= 0) @@ -1385,10 +1380,11 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, cnew->serialNumber = chunk_clone(info->serialNumber); cnew->next = certinfo; + cnew->trials = 0; *certinfop = cnew; certinfo = cnew; } - + DBG(DBG_CONTROL, datatot(info->serialNumber.ptr, info->serialNumber.len, ':' , buf, BUF_LEN); @@ -1403,7 +1399,7 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, if (request) { certinfo->status = CERT_UNDEFINED; - + if (cmp != 0) { certinfo->thisUpdate = now; @@ -1415,7 +1411,7 @@ void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, certinfo->status = info->status; certinfo->revocationTime = info->revocationTime; certinfo->revocationReason = info->revocationReason; - + certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)? info->thisUpdate : now; @@ -1446,12 +1442,12 @@ static void process_single_response(ocsp_location_t *location, plog("ocsp single response has wrong issuer"); return; } - + /* traverse list of certinfos in increasing order */ certinfop = &location->certinfo; certinfo = *certinfop; - while (certinfo != NULL) + while (certinfo) { cmp = chunk_compare(sres->serialNumber, certinfo->serialNumber); if (cmp <= 0) @@ -1468,14 +1464,14 @@ static void process_single_response(ocsp_location_t *location, /* 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); @@ -1486,6 +1482,14 @@ static void process_single_response(ocsp_location_t *location, } /** + * Destroy a response_t object + */ +static void free_response(response_t *res) +{ + DESTROY_IF(res->responder_id_name); +} + +/** * Parse and verify ocsp response and update the ocsp cache */ void parse_ocsp(ocsp_location_t *location, chunk_t blob) @@ -1498,24 +1502,24 @@ void parse_ocsp(ocsp_location_t *location, chunk_t blob) if (status != STATUS_SUCCESSFUL) { plog("error in ocsp response"); - return; + goto free; } /* check if there was a nonce in the request */ - if (location->nonce.ptr != NULL && res.nonce.ptr == NULL) + if (location->nonce.ptr && res.nonce.ptr == NULL) { plog("ocsp response contains no nonce, replay attack possible"); } /* check if the nonce is identical */ - if (res.nonce.ptr != NULL && !chunk_equals(res.nonce, location->nonce)) + if (res.nonce.ptr && !chunk_equals(res.nonce, location->nonce)) { plog("invalid nonce in ocsp response"); - return; + goto free; } /* check if the response is signed by a trusted key */ if (!valid_ocsp_response(&res)) { plog("invalid ocsp response"); - return; + goto free; } DBG(DBG_CONTROL, DBG_log("valid ocsp response") @@ -1536,7 +1540,7 @@ void parse_ocsp(ocsp_location_t *location, chunk_t blob) single_response_t sres = empty_single_response; if (!parse_ocsp_single_response(object, - parser->get_level(parser)+1, &sres)) + parser->get_level(parser)+1, &sres)) { goto end; } @@ -1546,4 +1550,7 @@ void parse_ocsp(ocsp_location_t *location, chunk_t blob) end: parser->destroy(parser); } + +free: + free_response(&res); } diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h index d8ee7bd8c..977cca3c8 100644 --- a/src/pluto/ocsp.h +++ b/src/pluto/ocsp.h @@ -15,6 +15,8 @@ #include "constants.h" +#include <credentials/certificates/crl.h> + /* constants */ #define OCSP_BASIC_RESPONSE_VERSION 1 @@ -52,12 +54,11 @@ 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; + identification_t *issuer; + chunk_t authNameID; + chunk_t authKeyID; + chunk_t nonce; + char *uri; ocsp_certinfo_t *certinfo; }; @@ -68,11 +69,11 @@ extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info , ocsp_location_t **chain, bool request); extern void check_ocsp(void); -extern cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until +extern cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until , time_t *revocationTime, crl_reason_t *revocationReason); extern bool ocsp_set_request_cert(char* path); extern void ocsp_set_default_uri(char* uri); -extern void ocsp_cache_add_cert(const x509cert_t* cert); +extern void ocsp_cache_add_cert(const cert_t* cert); extern chunk_t build_ocsp_request(ocsp_location_t* location); extern void parse_ocsp(ocsp_location_t* location, chunk_t blob); extern void list_ocsp_locations(ocsp_location_t *location, bool requests diff --git a/src/pluto/packet.c b/src/pluto/packet.c index 01967efed..35fc4afcc 100644 --- a/src/pluto/packet.c +++ b/src/pluto/packet.c @@ -227,7 +227,7 @@ static field_desc isat_fields_ah[] = { { 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_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transform_names }, { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, { ft_end, 0, NULL, NULL } }; @@ -242,7 +242,7 @@ static field_desc isat_fields_esp[] = { { 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_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transform_names }, { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, { ft_end, 0, NULL, NULL } }; @@ -535,7 +535,7 @@ struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, s +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Type ! RESERVED ! Identifier ! + ! Type ! RESERVED ! Identifier ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Attributes ~ diff --git a/src/pluto/pem.c b/src/pluto/pem.c deleted file mode 100644 index 1a4a99af7..000000000 --- a/src/pluto/pem.c +++ /dev/null @@ -1,127 +0,0 @@ -/* Loading of PEM encoded files with optional encryption - * 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 - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* decrypt a PEM encoded data block using DES-EDE3-CBC - * see RFC 1423 PEM: Algorithms, Modes and Identifiers - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <stddef.h> -#include <sys/types.h> - -#include <freeswan.h> - -#include <library.h> -#include <asn1/pem.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" -#include "pem.h" - -/** - * 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) -{ - chunk_t password = chunk_empty; - - /* do we prompt for the passphrase? */ - if (pass && pass->prompt && pass->fd != NULL_FD) - { - int i; - chunk_t blob_copy; - err_t ugh = "invalid passphrase, too many trials"; - status_t status; - - 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; - } - else - { - if (pass) - { - password = chunk_create(pass->secret, strlen(pass->secret)); - } - if (pem_to_bin(blob, password, pgp) == SUCCESS) - { - return NULL; - } - else - { - return "pem to bin conversion failed"; - } - } -} diff --git a/src/pluto/pgpcert.c b/src/pluto/pgpcert.c deleted file mode 100644 index 1d5b14b26..000000000 --- a/src/pluto/pgpcert.c +++ /dev/null @@ -1,514 +0,0 @@ -/* Support of OpenPGP certificates - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <freeswan.h> - -#include <library.h> -#include <pgp/pgp.h> -#include <crypto/hashers/hasher.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "id.h" -#include "pgpcert.h" -#include "certs.h" -#include "whack.h" -#include "keys.h" - -/** - * Chained list of OpenPGP end certificates - */ -static pgpcert_t *pgpcerts = NULL; - -/** - * Size of PGP Key ID - */ -#define PGP_KEYID_SIZE 8 - -const pgpcert_t pgpcert_empty = { - NULL , /* next */ - 0 , /* version */ - 0 , /* installed */ - 0 , /* count */ - { NULL, 0 }, /* certificate */ - 0 , /* created */ - 0 , /* until */ - NULL , /* public key */ - NULL /* fingerprint */ -}; - - -/** - * Extracts the length of a PGP packet - */ -static size_t pgp_old_packet_length(chunk_t *blob) -{ - /* bits 0 and 1 define the packet length type */ - int len_type = 0x03 & *blob->ptr++; - - blob->len--; - - /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ - return pgp_length(blob, (len_type == 0)? 1: len_type << 1); -} - -/** - * Extracts PGP packet version (V3 or V4) - */ -static u_char pgp_version(chunk_t *blob) -{ - u_char version = *blob->ptr++; - blob->len--; - DBG(DBG_PARSING, - DBG_log("L3 - version:"); - DBG_log(" V%d", version) - ) - return version; -} - -/** - * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 4880 - */ -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) -{ - chunk_t pubkey_packet = *packet; - pgp_pubkey_alg_t pubkey_alg; - - 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: - cert->public_key = lib->creds->create(lib->creds, - CRED_PUBLIC_KEY, KEY_RSA, - BUILD_BLOB_PGP, *packet, - BUILD_END); - if (cert->public_key == NULL) - { - return FALSE; - } - break; - default: - plog(" non RSA public keys not supported"); - return FALSE; - } - - /* compute V4 or V3 fingerprint according to section 12.2 of RFC 4880 */ - if (cert->version == 4) - { - char pubkey_packet_header_buf[] = { - 0x99, pubkey_packet.len / 256, pubkey_packet.len % 256 - }; - chunk_t pubkey_packet_header = chunk_from_buf(pubkey_packet_header_buf); - chunk_t hash; - hasher_t *hasher; - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - plog("no SHA-1 hasher available"); - return FALSE; - } - hasher->allocate_hash(hasher, pubkey_packet_header, NULL); - hasher->allocate_hash(hasher, pubkey_packet, &hash); - hasher->destroy(hasher); - cert->fingerprint = identification_create_from_encoding(ID_KEY_ID, hash); - free(hash.ptr); - } - else - { - /* V3 fingerprint is computed by public_key_t class */ - cert->fingerprint = cert->public_key->get_id(cert->public_key, ID_KEY_ID); - if (cert->fingerprint == NULL) - { - 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 deleted file mode 100644 index 727648391..000000000 --- a/src/pluto/pgpcert.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Support of OpenPGP certificates - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PGPCERT_H -#define _PGPCERT_H - -#include <crypto/hashers/hasher.h> -#include <credentials/keys/private_key.h> -#include <credentials/keys/public_key.h> - -/* - * 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/pkcs7.c b/src/pluto/pkcs7.c index 7248b042f..733dd2623 100644 --- a/src/pluto/pkcs7.c +++ b/src/pluto/pkcs7.c @@ -17,8 +17,7 @@ #include <stdlib.h> #include <string.h> - -#include <freeswan.h> +#include <time.h> #include <library.h> #include <debug.h> @@ -27,11 +26,8 @@ #include <asn1/oid.h> #include <crypto/rngs/rng.h> #include <crypto/crypters/crypter.h> +#include <credentials/certificates/x509.h> -#include "constants.h" -#include "defs.h" -#include "x509.h" -#include "certs.h" #include "pkcs7.h" const contentInfo_t empty_contentInfo = { @@ -84,10 +80,12 @@ static const asn1Object_t signedDataObjects[] = { { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ { 0, "exit", ASN1_EOC, ASN1_EXIT } }; +#define PKCS7_SIGNED_VERSION 1 #define PKCS7_DIGEST_ALG 3 #define PKCS7_SIGNED_CONTENT_INFO 5 #define PKCS7_SIGNED_CERT 7 #define PKCS7_SIGNER_INFO 13 +#define PKCS7_SIGNER_INFO_VERSION 14 #define PKCS7_SIGNED_ISSUER 16 #define PKCS7_SIGNED_SERIAL_NUMBER 17 #define PKCS7_DIGEST_ALGORITHM 18 @@ -128,81 +126,6 @@ static const asn1Object_t envelopedDataObjects[] = { #define PKCS7_ENVELOPED_ROOF 15 /** - * PKCS7 contentInfo OIDs - */ - -static u_char ASN1_pkcs7_data_oid_str[] = { - 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 -}; - -static u_char ASN1_pkcs7_enveloped_data_oid_str[] = { - 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 -}; - -static u_char ASN1_pkcs7_digested_data_oid_str[] = { - 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 -}; - -static const chunk_t ASN1_pkcs7_data_oid = - chunk_from_buf(ASN1_pkcs7_data_oid_str); -static const chunk_t ASN1_pkcs7_signed_data_oid = - chunk_from_buf(ASN1_pkcs7_signed_data_oid_str); -static const chunk_t ASN1_pkcs7_enveloped_data_oid = - chunk_from_buf(ASN1_pkcs7_enveloped_data_oid_str); -static const chunk_t ASN1_pkcs7_signed_enveloped_data_oid = - chunk_from_buf(ASN1_pkcs7_signed_enveloped_data_oid_str); -static const chunk_t ASN1_pkcs7_digested_data_oid = - chunk_from_buf(ASN1_pkcs7_digested_data_oid_str); -static const chunk_t ASN1_pkcs7_encrypted_data_oid = - chunk_from_buf(ASN1_pkcs7_encrypted_data_oid_str); - -/** - * 3DES and DES encryption OIDs - */ - -static u_char ASN1_3des_ede_cbc_oid_str[] = { - 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 -}; - -static const chunk_t ASN1_3des_ede_cbc_oid = - chunk_from_buf(ASN1_3des_ede_cbc_oid_str); -static const chunk_t ASN1_des_cbc_oid = - chunk_from_buf(ASN1_des_cbc_oid_str); - -/** - * PKCS#7 attribute type OIDs - */ - -static u_char ASN1_contentType_oid_str[] = { - 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 -}; - -static const chunk_t ASN1_contentType_oid = - chunk_from_buf(ASN1_contentType_oid_str); -static const chunk_t ASN1_messageDigest_oid = - 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) @@ -242,15 +165,16 @@ end: /** * 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, + linked_list_t *certs, + chunk_t *attributes, certificate_t *cacert) { - 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 version; int objectID; bool success = FALSE; @@ -267,7 +191,7 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert return FALSE; } - parser = asn1_parser_create(signedDataObjects, blob); + parser = asn1_parser_create(signedDataObjects, cInfo.content); parser->set_top_level(parser, 2); while (parser->iterate(parser, &objectID, &object)) @@ -276,6 +200,10 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert switch (objectID) { + case PKCS7_SIGNED_VERSION: + version = object.len ? (int)*object.ptr : 0; + DBG2(" v%d", version); + break; case PKCS7_DIGEST_ALG: digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; @@ -286,33 +214,36 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert } 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; + certificate_t *cert; DBG2(" parsing pkcs7-wrapped certificate"); - if (parse_x509cert(cert_blob, level+1, newcert)) - { - newcert->next = *cert; - *cert = newcert; - } - else + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (cert) { - free_x509cert(newcert); + certs->insert_last(certs, cert); } } 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_SIGNER_INFO_VERSION: + version = object.len ? (int)*object.ptr : 0; + DBG2(" v%d", version); + break; + case PKCS7_SIGNED_ISSUER: + { + identification_t *issuer = identification_create_from_encoding( + ID_DER_ASN1_DN, object); + DBG2(" \"%Y\"", issuer); + issuer->destroy(issuer); + break; + } case PKCS7_AUTH_ATTRIBUTES: if (attributes != NULL) { @@ -340,9 +271,15 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert /* check the signature only if a cacert is available */ if (cacert != NULL) { - public_key_t *key = cacert->public_key; - signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + public_key_t *key; + signature_scheme_t scheme; + scheme = signature_scheme_from_oid(digest_alg); + if (scheme == SIGN_UNKNOWN) + { + DBG1("unsupported signature scheme"); + return FALSE; + } if (signerInfos == 0) { DBG1("no signerInfo object found"); @@ -364,11 +301,11 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert return FALSE; } - /* determine signature scheme */ - scheme = signature_scheme_from_oid(digest_alg); - - if (scheme == SIGN_UNKNOWN) + /* verify the signature */ + key = cacert->get_public_key(cacert); + if (key == NULL) { + DBG1("no public key found in CA certificate"); return FALSE; } if (key->verify(key, scheme, *attributes, encrypted_digest)) @@ -378,10 +315,11 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert else { DBG1("invalid signature"); - return FALSE; + success = FALSE; } + key->destroy(key); } - return TRUE; + return success; } /** @@ -399,9 +337,9 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, crypter_t *crypter = NULL; - u_char buf[BUF_LEN]; int enc_alg = OID_UNKNOWN; int content_enc_alg = OID_UNKNOWN; + int version; int objectID; bool success = FALSE; @@ -428,37 +366,45 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, switch (objectID) { case PKCS7_ENVELOPED_VERSION: - if (*object.ptr != 0) - { - DBG1("envelopedData version is not 0"); - goto end; - } - break; + version = object.len ? (int)*object.ptr : 0; + DBG2(" v%d", version); + if (version != 0) + { + DBG1("envelopedData version is not 0"); + goto end; + } + break; case PKCS7_RECIPIENT_INFO_VERSION: - if (*object.ptr != 0) + version = object.len ? (int)*object.ptr : 0; + DBG2(" v%d", version); + if (version != 0) { DBG1("recipient info version is not 0"); goto end; } break; case PKCS7_ISSUER: - dntoa(buf, BUF_LEN, object); - DBG2(" '%s'", buf); - break; + { + identification_t *issuer = identification_create_from_encoding( + ID_DER_ASN1_DN, object); + DBG2(" \"%Y\"", issuer); + issuer->destroy(issuer); + break; + } case PKCS7_SERIAL_NUMBER: if (!chunk_equals(serialNumber, object)) { DBG1("serial numbers do not match"); goto end; - } - break; + } + 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)) @@ -477,7 +423,7 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, 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"); @@ -578,19 +524,20 @@ failed: */ 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, "mm", + asn1_build_known_oid(OID_PKCS9_CONTENT_TYPE), + asn1_wrap(ASN1_SET, "m", + asn1_build_known_oid(OID_PKCS7_DATA))); } /** * @brief Builds a messageDigest attribute - * - * + * + * * @param[in] blob content to create digest of * @param[in] digest_alg digest algorithm to be used * @return ASN.1 encoded messageDigest attribute - * + * */ chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) { @@ -603,12 +550,10 @@ chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_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) - ) - ); + return asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_PKCS9_MESSAGE_DIGEST), + asn1_wrap(ASN1_SET, "m", + asn1_wrap(ASN1_OCTET_STRING, "m", digest))); } /** @@ -616,83 +561,59 @@ chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) */ 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: - 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) - ); + return (cInfo->content.ptr) ? + asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(cInfo->type), + asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content)) : + asn1_build_known_oid(cInfo->type); } /** * build issuerAndSerialNumber object */ -chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert) +chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert) { - return asn1_wrap(ASN1_SEQUENCE, "cm" - , cert->issuer - , asn1_integer("c", cert->serialNumber)); + identification_t *issuer = cert->get_issuer(cert); + x509_t *x509 = (x509_t*)cert; + + return asn1_wrap(ASN1_SEQUENCE, "cm", + issuer->get_encoding(issuer), + asn1_integer("c", x509->get_serial(x509))); } /** * create a signed pkcs7 contentInfo object */ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - const x509cert_t *cert, int digest_alg, + certificate_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); + chunk_t authenticatedAttributes = chunk_empty; + chunk_t encryptedDigest = chunk_empty; + chunk_t signerInfo, cInfo, signature; + signature_scheme_t scheme = signature_scheme_from_oid(digest_alg); - if (attributes.ptr != NULL) + if (attributes.ptr) { - encryptedDigest = x509_build_signature(attributes, digest_alg, key, - FALSE); - authenticatedAttributes = chunk_clone(attributes); - *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; + if (key->sign(key, scheme, attributes, &signature)) + { + encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); + authenticatedAttributes = chunk_clone(attributes); + *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; + } } - else + else if (data.ptr) { - encryptedDigest = (data.ptr == NULL)? chunk_empty - : x509_build_signature(data, digest_alg, key, FALSE); - authenticatedAttributes = chunk_empty; + if (key->sign(key, scheme, data, &signature)) + { + encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); + } } - - signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmcmcm" + signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm" , ASN1_INTEGER_1 , pkcs7_build_issuerAndSerialNumber(cert) - , digestAlgorithm + , asn1_algorithmIdentifier(digest_alg) , authenticatedAttributes , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) , encryptedDigest); @@ -704,9 +625,9 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, signedData.type = OID_PKCS7_SIGNED_DATA; signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm" , ASN1_INTEGER_1 - , asn1_simple_object(ASN1_SET, digestAlgorithm) + , asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_alg)) , pkcs7_build_contentInfo(&pkcs7Data) - , asn1_simple_object(ASN1_CONTEXT_C_0, cert->certificate) + , asn1_wrap(ASN1_CONTEXT_C_0, "m", cert->get_encoding(cert)) , asn1_wrap(ASN1_SET, "m", signerInfo)); cInfo = pkcs7_build_contentInfo(&signedData); @@ -720,7 +641,7 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, /** * create a symmetrically encrypted pkcs7 contentInfo object */ -chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_alg) +chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg) { encryption_algorithm_t alg; size_t alg_key_size; @@ -739,7 +660,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ /* 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); @@ -760,7 +681,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ in.ptr = malloc(in.len); DBG2("padding %u bytes of data to multiple block size of %u bytes", - data.len, in.len); + data.len, in.len); /* copy data */ memcpy(in.ptr, data.ptr, data.len); @@ -773,26 +694,41 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ crypter->set_key(crypter, symmetricKey); crypter->encrypt(crypter, in, iv, &out); crypter->destroy(crypter); + chunk_clear(&in); DBG3("encrypted data %B", &out); - cert->public_key->encrypt(cert->public_key, symmetricKey, &protectedKey); + /* protect symmetric key by public key encryption */ + { + public_key_t *key = cert->get_public_key(cert); - /* build pkcs7 enveloped data object */ + if (key == NULL) + { + DBG1("public key not found in encryption certificate"); + chunk_clear(&symmetricKey); + chunk_free(&iv); + chunk_free(&out); + return chunk_empty; + } + key->encrypt(key, symmetricKey, &protectedKey); + key->destroy(key); + } + + /* build pkcs7 enveloped data object */ { - + chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm" , asn1_build_known_oid(enc_alg) , asn1_simple_object(ASN1_OCTET_STRING, iv)); - - chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "cmm" - , ASN1_pkcs7_data_oid + + chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm" + , asn1_build_known_oid(OID_PKCS7_DATA) , contentEncryptionAlgorithm , asn1_wrap(ASN1_CONTEXT_S_0, "m", out)); chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m" , protectedKey); - chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm" + chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm" , ASN1_INTEGER_0 , pkcs7_build_issuerAndSerialNumber(cert) , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) @@ -810,10 +746,9 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_ cInfo = pkcs7_build_contentInfo(&envelopedData); DBG3("envelopedData %B", &cInfo); - free(envelopedData.content.ptr); - free(symmetricKey.ptr); - free(in.ptr); - free(iv.ptr); + chunk_free(&envelopedData.content); + chunk_free(&iv); + chunk_clear(&symmetricKey); return cInfo; } } diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h index 028822dfe..1743ea9c4 100644 --- a/src/pluto/pkcs7.h +++ b/src/pluto/pkcs7.h @@ -18,10 +18,10 @@ #ifndef _PKCS7_H #define _PKCS7_H +#include <utils/linked_list.h> #include <crypto/crypters/crypter.h> #include <credentials/keys/private_key.h> -#include "defs.h" -#include "x509.h" +#include <credentials/certificates/certificate.h> /* Access structure for a PKCS#7 ContentInfo object */ @@ -35,17 +35,19 @@ struct contentInfo { extern const contentInfo_t empty_contentInfo; extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, - contentInfo_t *cInfo); + contentInfo_t *cInfo); extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert); + linked_list_t *cert, chunk_t *attributes, + certificate_t *cacert); extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, private_key_t *key); + 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_issuerAndSerialNumber(certificate_t *cert); 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); + certificate_t *cert, int digest_alg, + private_key_t *key); +extern chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, + int enc_alg); #endif /* _PKCS7_H */ diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c index 5d0e008f3..8b922df8c 100644 --- a/src/pluto/plutomain.c +++ b/src/pluto/plutomain.c @@ -48,7 +48,7 @@ #include "constants.h" #include "defs.h" -#include "id.h" +#include "myid.h" #include "ca.h" #include "certs.h" #include "ac.h" @@ -73,6 +73,7 @@ #include "virtual.h" #include "timer.h" #include "vendor.h" +#include "builder.h" static void usage(const char *mess) { @@ -128,7 +129,7 @@ static void usage(const char *mess) " [--debug-private]" " [--debug-natt]" #endif - " \\\n\t" + " \\\n\t" "[--nat_traversal] [--keep_alive <delay_sec>]" " \\\n\t" "[--force_keepalive] [--disable_port_floating]" @@ -233,8 +234,8 @@ static void print_plugins() char buf[BUF_LEN], *plugin; int len = 0; enumerator_t *enumerator; - - buf[0] = '\0'; + + buf[0] = '\0'; enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin)) { @@ -260,7 +261,7 @@ int main(int argc, char **argv) #endif /* CAPABILITIES */ /* initialize library and optionsfrom */ - if (!library_init(STRONGSWAN_CONF)) + if (!library_init(NULL)) { library_deinit(); exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); @@ -651,10 +652,14 @@ int main(int argc, char **argv) } /* load plugins, further infrastructure may need it */ - lib->plugins->load(lib->plugins, IPSEC_PLUGINDIR, - lib->settings->get_str(lib->settings, "pluto.load", PLUGINS)); + if (!lib->plugins->load(lib->plugins, NULL, + lib->settings->get_str(lib->settings, "pluto.load", PLUGINS))) + { + exit(SS_RC_INITIALIZATION_FAILED); + } print_plugins(); + init_builder(); if (!init_secret() || !init_crypto()) { plog("initialization failed - aborting pluto"); @@ -668,12 +673,13 @@ int main(int argc, char **argv) init_demux(); init_kernel(); init_adns(); - init_id(); - init_fetch(); + init_myid(); + fetch_initialize(); + ac_initialize(); /* drop unneeded capabilities and change UID/GID */ prctl(PR_SET_KEEPCAPS, 1); - + #ifdef IPSEC_GROUP { struct group group, *grp; @@ -715,15 +721,15 @@ int main(int argc, char **argv) #endif /* CAPABILITIES */ /* loading X.509 CA certificates */ - load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA); + load_authcerts("ca", CA_CERT_PATH, X509_CA); /* loading X.509 AA certificates */ - load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA); + load_authcerts("aa", AA_CERT_PATH, X509_AA); /* loading X.509 OCSP certificates */ - load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP); + load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER); /* loading X.509 CRLs */ load_crls(); /* loading attribute certificates (experimental) */ - load_acerts(); + ac_load_certs(); daily_log_event(); call_server(); @@ -744,22 +750,24 @@ void exit_pluto(int status) free_preshared_secrets(); free_remembered_public_keys(); delete_every_connection(); + fetch_finalize(); /* stop fetching thread */ free_crl_fetch(); /* free chain of crl fetch requests */ free_ocsp_fetch(); /* free chain of ocsp fetch requests */ free_authcerts(); /* free chain of X.509 authority certificates */ free_crls(); /* free chain of X.509 CRLs */ - free_acerts(); /* free chain of X.509 attribute certificates */ free_ca_infos(); /* free chain of X.509 CA information records */ free_ocsp(); /* free ocsp cache */ free_ifaces(); + ac_finalize(); /* free X.509 attribute certificates */ scx_finalize(); /* finalize and unload PKCS #11 module */ xauth_finalize(); /* finalize and unload XAUTH module */ stop_adns(); free_md_pool(); free_crypto(); - free_id(); /* free myids */ + free_myid(); /* free myids */ free_events(); /* free remaining events */ - free_vendorid(); /* free all vendor id records */ + free_vendorid(); /* free all vendor id records */ + free_builder(); delete_lock(); options->destroy(options); library_deinit(); diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c index 013deb446..826a1aa6e 100644 --- a/src/pluto/rcv_whack.c +++ b/src/pluto/rcv_whack.c @@ -33,7 +33,6 @@ #include "constants.h" #include "defs.h" -#include "id.h" #include "ca.h" #include "certs.h" #include "ac.h" @@ -55,16 +54,16 @@ #include "fetch.h" #include "ocsp.h" #include "crl.h" - +#include "myid.h" #include "kernel_alg.h" #include "ike_alg.h" + /* helper variables and function to decode strings from whack message */ static char *next_str , *str_roof; -static bool -unpack_str(char **p) +static bool unpack_str(char **p) { char *end = memchr(next_str, '\0', str_roof - next_str); @@ -103,19 +102,13 @@ struct key_add_continuation { enum key_add_attempt lookingfor; }; -static void -key_add_ugh(const struct id *keyid, err_t ugh) +static void key_add_ugh(identification_t *keyid, err_t ugh) { - char name[BUF_LEN]; /* longer IDs will be truncated in message */ - - (void)idtoa(keyid, name, sizeof(name)); - loglog(RC_NOKEY - , "failure to fetch key for %s from DNS: %s", name, ugh); + loglog(RC_NOKEY, "failure to fetch key for %'Y' from DNS: %s", keyid, ugh); } /* last one out: turn out the lights */ -static void -key_add_merge(struct key_add_common *oc, const struct id *keyid) +static void key_add_merge(struct key_add_common *oc, identification_t *keyid) { if (oc->refCount == 0) { @@ -123,9 +116,12 @@ key_add_merge(struct key_add_common *oc, const struct id *keyid) /* if no success, print all diagnostics */ if (!oc->success) + { for (kaa = ka_TXT; kaa != ka_roof; kaa++) + { key_add_ugh(keyid, oc->diag[kaa]); - + } + } for (kaa = ka_TXT; kaa != ka_roof; kaa++) { free(oc->diag[kaa]); @@ -135,8 +131,7 @@ key_add_merge(struct key_add_common *oc, const struct id *keyid) } } -static void -key_add_continue(struct adns_continuation *ac, err_t ugh) +static void key_add_continue(struct adns_continuation *ac, err_t ugh) { struct key_add_continuation *kc = (void *) ac; struct key_add_common *oc = kc->common; @@ -159,95 +154,87 @@ key_add_continue(struct adns_continuation *ac, err_t ugh) } oc->refCount--; - key_add_merge(oc, &ac->id); + key_add_merge(oc, ac->id); whack_log_fd = NULL_FD; } -static void -key_add_request(const whack_message_t *msg) +static void key_add_request(const whack_message_t *msg) { - struct id keyid; - err_t ugh = atoid(msg->keyid, &keyid, FALSE); + identification_t *key_id; - if (ugh != NULL) + key_id = identification_create_from_string(msg->keyid); + + if (!msg->whack_addkey) { - loglog(RC_BADID, "bad --keyid \"%s\": %s", msg->keyid, ugh); + delete_public_keys(key_id, msg->pubkey_alg, NULL, chunk_empty); } - else + if (msg->keyval.len == 0) { - if (!msg->whack_addkey) - delete_public_keys(&keyid, msg->pubkey_alg - , chunk_empty, chunk_empty); + struct key_add_common *oc = malloc_thing(struct key_add_common); + enum key_add_attempt kaa; + err_t ugh; - if (msg->keyval.len == 0) + /* initialize state shared by queries */ + oc->refCount = 0; + oc->whack_fd = dup_any(whack_log_fd); + oc->success = FALSE; + + for (kaa = ka_TXT; kaa != ka_roof; kaa++) { - struct key_add_common *oc = malloc_thing(struct key_add_common); - enum key_add_attempt kaa; + struct key_add_continuation *kc; - /* initialize state shared by queries */ - oc->refCount = 0; - oc->whack_fd = dup_any(whack_log_fd); - oc->success = FALSE; + oc->diag[kaa] = NULL; + oc->refCount++; + kc = malloc_thing(struct key_add_continuation); + kc->common = oc; + kc->lookingfor = kaa; - for (kaa = ka_TXT; kaa != ka_roof; kaa++) + switch (kaa) { - struct key_add_continuation *kc; - - oc->diag[kaa] = NULL; - oc->refCount++; - kc = malloc_thing(struct key_add_continuation); - kc->common = oc; - kc->lookingfor = kaa; - - switch (kaa) - { case ka_TXT: - ugh = start_adns_query(&keyid - , &keyid /* same */ - , T_TXT - , key_add_continue - , &kc->ac); + ugh = start_adns_query(key_id + , key_id /* same */ + , T_TXT + , key_add_continue + , &kc->ac); break; #ifdef USE_KEYRR case ka_KEY: - ugh = start_adns_query(&keyid - , NULL - , T_KEY - , key_add_continue - , &kc->ac); + ugh = start_adns_query(key_id + , NULL + , T_KEY + , key_add_continue + , &kc->ac); break; #endif /* USE_KEYRR */ default: bad_case(kaa); /* suppress gcc warning */ - } - if (ugh != NULL) - { - oc->diag[kaa] = clone_str(ugh); - oc->refCount--; - } } - - /* Done launching queries. - * Handle total failure case. - */ - key_add_merge(oc, &keyid); - } - else - { - if (!add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg, msg->keyval, - &pubkeys)) + if (ugh) { - loglog(RC_LOG_SERIOUS, "failed to add public key"); + oc->diag[kaa] = clone_str(ugh); + oc->refCount--; } } + + /* Done launching queries. Handle total failure case. */ + key_add_merge(oc, key_id); + } + else + { + if (!add_public_key(key_id, DAL_LOCAL, msg->pubkey_alg, msg->keyval, + &pubkeys)) + { + loglog(RC_LOG_SERIOUS, "failed to add public key"); + } } + key_id->destroy(key_id); } /* Handle a kernel request. Supposedly, there's a message in * the kernelsock socket. */ -void -whack_handle(int whackctlfd) +void whack_handle(int whackctlfd) { whack_message_t msg; struct sockaddr_un whackaddr; @@ -319,24 +306,26 @@ whack_handle(int whackctlfd) || !unpack_str(&msg.left.ca) /* string 4 */ || !unpack_str(&msg.left.groups) /* string 5 */ || !unpack_str(&msg.left.updown) /* string 6 */ - || !unpack_str(&msg.left.virt) /* string 7 */ - || !unpack_str(&msg.right.id) /* string 8 */ - || !unpack_str(&msg.right.cert) /* string 9 */ - || !unpack_str(&msg.right.ca) /* string 10 */ - || !unpack_str(&msg.right.groups) /* string 11 */ - || !unpack_str(&msg.right.updown) /* string 12 */ - || !unpack_str(&msg.right.virt) /* string 13 */ - || !unpack_str(&msg.keyid) /* string 14 */ - || !unpack_str(&msg.myid) /* string 15 */ - || !unpack_str(&msg.cacert) /* string 16 */ - || !unpack_str(&msg.ldaphost) /* string 17 */ - || !unpack_str(&msg.ldapbase) /* string 18 */ - || !unpack_str(&msg.crluri) /* string 19 */ - || !unpack_str(&msg.crluri2) /* string 20 */ - || !unpack_str(&msg.ocspuri) /* string 21 */ - || !unpack_str(&msg.ike) /* string 22 */ - || !unpack_str(&msg.esp) /* string 23 */ - || !unpack_str(&msg.sc_data) /* string 24 */ + || !unpack_str(&msg.left.sourceip) /* string 7 */ + || !unpack_str(&msg.left.virt) /* string 8 */ + || !unpack_str(&msg.right.id) /* string 9 */ + || !unpack_str(&msg.right.cert) /* string 10 */ + || !unpack_str(&msg.right.ca) /* string 11 */ + || !unpack_str(&msg.right.groups) /* string 12 */ + || !unpack_str(&msg.right.updown) /* string 13 */ + || !unpack_str(&msg.right.sourceip) /* string 14 */ + || !unpack_str(&msg.right.virt) /* string 15 */ + || !unpack_str(&msg.keyid) /* string 16 */ + || !unpack_str(&msg.myid) /* string 17 */ + || !unpack_str(&msg.cacert) /* string 18 */ + || !unpack_str(&msg.ldaphost) /* string 19 */ + || !unpack_str(&msg.ldapbase) /* string 20 */ + || !unpack_str(&msg.crluri) /* string 21 */ + || !unpack_str(&msg.crluri2) /* string 22 */ + || !unpack_str(&msg.ocspuri) /* string 23 */ + || !unpack_str(&msg.ike) /* string 24 */ + || !unpack_str(&msg.esp) /* string 25 */ + || !unpack_str(&msg.sc_data) /* string 26 */ || str_roof - next_str != (ptrdiff_t)msg.keyval.len) /* check chunk */ { ugh = "message from whack contains bad string"; @@ -372,7 +361,7 @@ whack_handle(int whackctlfd) } else if (!msg.whack_connection) { - struct connection *c = con_by_name(msg.name, TRUE); + connection_t *c = con_by_name(msg.name, TRUE); if (c != NULL) { @@ -424,7 +413,7 @@ whack_handle(int whackctlfd) if (msg.whack_ca && msg.cacert != NULL) add_ca_info(&msg); - + /* process "listen" before any operation that could require it */ if (msg.whack_listen) { @@ -451,22 +440,22 @@ whack_handle(int whackctlfd) if (msg.whack_reread & REREAD_CACERTS) { - load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA); + load_authcerts("ca", CA_CERT_PATH, X509_CA); } if (msg.whack_reread & REREAD_AACERTS) { - load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA); + load_authcerts("aa", AA_CERT_PATH, X509_AA); } if (msg.whack_reread & REREAD_OCSPCERTS) { - load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP); + load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER); } if (msg.whack_reread & REREAD_ACERTS) { - load_acerts(); + ac_load_certs(); } if (msg.whack_reread & REREAD_CRLS) @@ -487,32 +476,27 @@ whack_handle(int whackctlfd) if (msg.whack_list & LIST_CERTS) { - list_certs(msg.whack_utc); + cert_list(msg.whack_utc); } if (msg.whack_list & LIST_CACERTS) { - list_authcerts("CA", AUTH_CA, msg.whack_utc); + list_authcerts("CA", X509_CA, msg.whack_utc); } if (msg.whack_list & LIST_AACERTS) { - list_authcerts("AA", AUTH_AA, msg.whack_utc); + list_authcerts("AA", X509_AA, msg.whack_utc); } if (msg.whack_list & LIST_OCSPCERTS) { - list_authcerts("OCSP", AUTH_OCSP, msg.whack_utc); + list_authcerts("OCSP", X509_OCSP_SIGNER, msg.whack_utc); } if (msg.whack_list & LIST_ACERTS) { - list_acerts(msg.whack_utc); - } - - if (msg.whack_list & LIST_GROUPS) - { - list_groups(msg.whack_utc); + ac_list_certs(msg.whack_utc); } if (msg.whack_list & LIST_CAINFOS) @@ -562,7 +546,7 @@ whack_handle(int whackctlfd) } else { - struct connection *c = con_by_name(msg.name, TRUE); + connection_t *c = con_by_name(msg.name, TRUE); if (c != NULL && c->ikev1) { @@ -588,7 +572,7 @@ whack_handle(int whackctlfd) } else { - struct connection *c = con_by_name(msg.name, TRUE); + connection_t *c = con_by_name(msg.name, TRUE); if (c != NULL && c->ikev1) { diff --git a/src/pluto/rsaref/pkcs11.h b/src/pluto/rsaref/pkcs11.h index 9261e1e4c..3283bdc89 100644 --- a/src/pluto/rsaref/pkcs11.h +++ b/src/pluto/rsaref/pkcs11.h @@ -7,10 +7,10 @@ * License is also granted to make and use derivative works provided that * such works are identified as "derived from the RSA Security Inc. PKCS #11 - * Cryptographic Token Interface (Cryptoki)" in all material mentioning or + * Cryptographic Token Interface (Cryptoki)" in all material mentioning or * referencing the derived work. - * RSA Security Inc. makes no representations concerning either the + * RSA Security Inc. makes no representations concerning either the * merchantability of this software or the suitability of this software for * any particular purpose. It is provided "as is" without express or implied * warranty of any kind. @@ -275,7 +275,7 @@ extern "C" { #define CK_PKCS11_FUNCTION_INFO(name) \ __PASTE(CK_,name) name; - + struct CK_FUNCTION_LIST { CK_VERSION version; /* Cryptoki version */ diff --git a/src/pluto/rsaref/pkcs11f.h b/src/pluto/rsaref/pkcs11f.h index dec6315dd..54b884aed 100644 --- a/src/pluto/rsaref/pkcs11f.h +++ b/src/pluto/rsaref/pkcs11f.h @@ -7,10 +7,10 @@ * License is also granted to make and use derivative works provided that * such works are identified as "derived from the RSA Security Inc. PKCS #11 - * Cryptographic Token Interface (Cryptoki)" in all material mentioning or + * Cryptographic Token Interface (Cryptoki)" in all material mentioning or * referencing the derived work. - * RSA Security Inc. makes no representations concerning either the + * RSA Security Inc. makes no representations concerning either the * merchantability of this software or the suitability of this software for * any particular purpose. It is provided "as is" without express or implied * warranty of any kind. @@ -564,7 +564,7 @@ CK_PKCS11_FUNCTION_INFO(C_Sign) /* C_SignUpdate continues a multiple-part signature operation, - * where the signature is (will be) an appendix to the data, + * where the signature is (will be) an appendix to the data, * and plaintext cannot be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_SignUpdate) #ifdef CK_NEED_ARG_LIST @@ -576,7 +576,7 @@ CK_PKCS11_FUNCTION_INFO(C_SignUpdate) #endif -/* C_SignFinal finishes a multiple-part signature operation, +/* C_SignFinal finishes a multiple-part signature operation, * returning the signature. */ CK_PKCS11_FUNCTION_INFO(C_SignFinal) #ifdef CK_NEED_ARG_LIST @@ -625,12 +625,12 @@ CK_PKCS11_FUNCTION_INFO(C_VerifyInit) ( CK_SESSION_HANDLE hSession, /* the session's handle */ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ - CK_OBJECT_HANDLE hKey /* verification key */ + CK_OBJECT_HANDLE hKey /* verification key */ ); #endif -/* C_Verify verifies a signature in a single-part operation, +/* C_Verify verifies a signature in a single-part operation, * where the signature is an appendix to the data, and plaintext * cannot be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_Verify) @@ -646,7 +646,7 @@ CK_PKCS11_FUNCTION_INFO(C_Verify) /* C_VerifyUpdate continues a multiple-part verification - * operation, where the signature is an appendix to the data, + * operation, where the signature is an appendix to the data, * and plaintext cannot be recovered from the signature. */ CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate) #ifdef CK_NEED_ARG_LIST @@ -772,7 +772,7 @@ CK_PKCS11_FUNCTION_INFO(C_GenerateKey) #endif -/* C_GenerateKeyPair generates a public-key/private-key pair, +/* C_GenerateKeyPair generates a public-key/private-key pair, * creating new key objects. */ CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair) #ifdef CK_NEED_ARG_LIST diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c index 7e4452d89..f1a3932a6 100644 --- a/src/pluto/smartcard.c +++ b/src/pluto/smartcard.c @@ -31,6 +31,7 @@ #include <asn1/asn1.h> #include <credentials/keys/public_key.h> +#include <credentials/certificates/x509.h> #include "constants.h" @@ -58,21 +59,21 @@ static smartcard_t *smartcards = NULL; static int sc_number = 0; const smartcard_t empty_sc = { - NULL , /* next */ - 0 , /* last_load */ - { CERT_NONE, {NULL} }, /* last_cert */ - 0 , /* count */ - 0 , /* number */ - 999999 , /* slot */ - NULL , /* id */ - NULL , /* label */ - { NULL, 0 } , /* pin */ - FALSE , /* pinpad */ - FALSE , /* valid */ - FALSE , /* session_opened */ - FALSE , /* logged_in */ - TRUE , /* any_slot */ - 0L , /* session */ + NULL , /* next */ + 0 , /* last_load */ + NULL , /* last_cert */ + 0 , /* count */ + 0 , /* number */ + 999999 , /* slot */ + NULL , /* id */ + NULL , /* label */ + { NULL, 0 } , /* pin */ + FALSE , /* pinpad */ + FALSE , /* valid */ + FALSE , /* session_opened */ + FALSE , /* logged_in */ + TRUE , /* any_slot */ + 0L , /* session */ }; #ifdef SMARTCARD /* compile with smartcard support */ @@ -115,7 +116,7 @@ static const char *const pkcs11_return_name_10[] = { }; static const char *const pkcs11_return_name_20[] = { - "CKR_DATA_INVALID", + "CKR_DATA_INVALID", "CKR_DATA_LEN_RANGE" }; @@ -386,8 +387,7 @@ static enum_names pkcs11_return_names = * The calling application is responsible for cleaning up * and calling C_Finalize() */ -static CK_RV -scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) +static CK_RV scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) { if (!mod || mod->_magic != SCX_MAGIC) return CKR_ARGUMENTS_BAD; @@ -400,8 +400,8 @@ scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) return CKR_OK; } -static scx_pkcs11_module_t* -scx_load_pkcs11_module(const char *name, CK_FUNCTION_LIST_PTR_PTR funcs) +static scx_pkcs11_module_t* scx_load_pkcs11_module(const char *name, + CK_FUNCTION_LIST_PTR_PTR funcs) { CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR); scx_pkcs11_module_t *mod; @@ -437,14 +437,13 @@ failed: scx_unload_pkcs11_module(mod); /* * retrieve a certificate object */ -static bool -scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object -, smartcard_t *sc, cert_t *cert) +static cert_t* scx_find_cert_object(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, smartcard_t *sc) { size_t hex_len, label_len; u_char *hex_id = NULL; + cert_t *cert; chunk_t blob; - x509cert_t *x509cert; CK_ATTRIBUTE attr[] = { { CKA_ID, NULL_PTR, 0L }, @@ -452,16 +451,13 @@ scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object { CKA_VALUE, NULL_PTR, 0L } }; - /* initialize the return argument */ - *cert = cert_empty; - /* get the length of the attributes first */ CK_RV rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3); if (rv != CKR_OK) { plog("couldn't read the attribute sizes: %s" , enum_show(&pkcs11_return_names, rv)); - return FALSE; + return NULL; } free(sc->label); @@ -486,7 +482,7 @@ scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object free(hex_id); free(sc->label); free(blob.ptr); - return FALSE; + return NULL; } free(sc->id); @@ -500,26 +496,30 @@ scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object sc->label[label_len] = '\0'; /* parse the retrieved cert */ - x509cert = malloc_thing(x509cert_t); - *x509cert = empty_x509cert; - x509cert->smartcard = TRUE; - if (!parse_x509cert(blob, 0, x509cert)) + /* initialize the return argument */ + cert = malloc_thing(cert_t); + *cert = cert_empty; + cert->smartcard = TRUE; + cert->cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, blob, + BUILD_END); + if (cert->cert) { - plog("failed to load cert from smartcard, error in X.509 certificate"); - free_x509cert(x509cert); - return FALSE; + return cert; } - cert->type = CERT_X509_SIGNATURE; - cert->u.x509 = x509cert; - return TRUE; + + plog("failed to load cert from smartcard, error in X.509 certificate"); + cert_free(cert); + return NULL; } + /* * search a given slot for PKCS#11 certificate objects */ -static void -scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) +static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { CK_RV rv; CK_OBJECT_CLASS class = CKO_CERTIFICATE; @@ -537,10 +537,10 @@ scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) { CK_OBJECT_HANDLE object; CK_ULONG obj_count = 0; - err_t ugh; time_t valid_until; smartcard_t *sc; - x509cert_t *cert; + certificate_t *certificate; + x509_t *x509; rv = pkcs11_functions->C_FindObjects(session, &object, 1, &obj_count); if (rv != CKR_OK) @@ -559,8 +559,8 @@ scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) *sc = empty_sc; sc->any_slot = FALSE; sc->slot = slot; - - if (!scx_find_cert_object(session, object, sc, &sc->last_cert)) + sc->last_cert = scx_find_cert_object(session, object, sc); + if (sc->last_cert == NULL) { scx_free(sc); continue; @@ -571,37 +571,31 @@ scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) ) /* check validity of certificate */ - cert = sc->last_cert.u.x509; - valid_until = cert->notAfter; - ugh = check_validity(cert, &valid_until); - if (ugh != NULL) + certificate = sc->last_cert->cert; + if (!certificate->get_validity(certificate, NULL, NULL, &valid_until)) { - plog(" %s", ugh); - free_x509cert(cert); scx_free(sc); continue; } - else - { - DBG(DBG_CONTROL, - DBG_log(" certificate is valid") - ) - } + DBG(DBG_CONTROL, + DBG_log(" certificate is valid") + ) sc = scx_add(sc); + x509 = (x509_t*)certificate; /* put end entity and ca certificates into different chains */ - if (cert->isCA) + if (x509->get_flags(x509) & X509_CA) { - sc->last_cert.u.x509 = add_authcert(cert, AUTH_CA); + sc->last_cert = add_authcert(sc->last_cert, X509_CA); } else { - add_x509_public_key(cert, valid_until, DAL_LOCAL); - sc->last_cert.u.x509 = add_x509cert(cert); + add_public_key_from_cert(sc->last_cert, valid_until, DAL_LOCAL); + sc->last_cert = cert_add(sc->last_cert); } - share_cert(sc->last_cert); + cert_share(sc->last_cert); time(&sc->last_load); } @@ -616,8 +610,7 @@ scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) /* * search all slots for PKCS#11 certificate objects */ -static void -scx_find_all_cert_objects(void) +static void scx_find_all_cert_objects(void) { CK_RV rv; CK_SLOT_ID_PTR slots = NULL_PTR; @@ -659,7 +652,7 @@ scx_find_all_cert_objects(void) , enum_show(&pkcs11_return_names, rv)); continue; } - + if (!(info.flags & CKF_TOKEN_PRESENT)) { plog("no token present in slot %lu", slot); @@ -696,8 +689,7 @@ scx_find_all_cert_objects(void) * init_args should be unused when we have a PKCS#11 compliant module, * but NSS softoken breaks that API. */ -void -scx_init(const char* module, const char *init_args) +void scx_init(const char* module, const char *init_args) { #ifdef SMARTCARD CK_C_INITIALIZE_ARGS args = { .pReserved = (char *)init_args, }; @@ -750,10 +742,9 @@ scx_init(const char* module, const char *init_args) } /* - * finalize and unload PKCS#11 cryptoki module + * finalize and unload PKCS#11 cryptoki module */ -void -scx_finalize(void) +void scx_finalize(void) { #ifdef SMARTCARD while (smartcards != NULL) @@ -783,21 +774,18 @@ scx_finalize(void) /* * does a filename contain the token %smartcard? */ -bool -scx_on_smartcard(const char *filename) +bool scx_on_smartcard(const char *filename) { return strneq(filename, SCX_TOKEN, strlen(SCX_TOKEN)); } #ifdef SMARTCARD /* - * find a specific object on the smartcard + * find a specific object on the smartcard */ -static bool -scx_pkcs11_find_object( CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE_PTR object, - CK_OBJECT_CLASS class, - const char* id) +static bool scx_pkcs11_find_object(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE_PTR object, + CK_OBJECT_CLASS class, const char* id) { size_t len; char buf[BUF_LEN]; @@ -848,8 +836,7 @@ scx_pkcs11_find_object( CK_SESSION_HANDLE session, /* * check if a given certificate object id is found in a slot */ -static bool -scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) +static bool scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) { CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; @@ -863,7 +850,7 @@ scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) , enum_show(&pkcs11_return_names, rv)); return FALSE; } - + if (!(info.flags & CKF_TOKEN_PRESENT)) { plog("no token present in slot %lu", slot); @@ -891,7 +878,7 @@ scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) sc->session_opened = TRUE; return TRUE; } - + rv = pkcs11_functions->C_CloseSession(session); if (rv != CKR_OK) { @@ -905,8 +892,7 @@ scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) /* * Connect to the smart card in the reader and select the correct slot */ -bool -scx_establish_context(smartcard_t *sc) +bool scx_establish_context(smartcard_t *sc) { #ifdef SMARTCARD bool id_found = FALSE; @@ -983,8 +969,7 @@ scx_establish_context(smartcard_t *sc) /* * log in to a session */ -bool -scx_login(smartcard_t *sc) +bool scx_login(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; @@ -996,7 +981,7 @@ scx_login(smartcard_t *sc) ) return TRUE; } - + if (sc->pin.ptr == NULL) { plog("unable to log in without PIN!"); @@ -1009,7 +994,7 @@ scx_login(smartcard_t *sc) return FALSE; } - rv = pkcs11_functions->C_Login(sc->session, CKU_USER + rv = pkcs11_functions->C_Login(sc->session, CKU_USER , (CK_UTF8CHAR *) sc->pin.ptr, sc->pin.len); if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) { @@ -1031,11 +1016,10 @@ scx_login(smartcard_t *sc) /* * logout from a session */ -static void -scx_logout(smartcard_t *sc) +static void scx_logout(smartcard_t *sc) { CK_RV rv; - + rv = pkcs11_functions->C_Logout(sc->session); if (rv != CKR_OK) plog("error in C_Logout: %s" @@ -1052,8 +1036,7 @@ scx_logout(smartcard_t *sc) /* * Release context and disconnect from card */ -void -scx_release_context(smartcard_t *sc) +void scx_release_context(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; @@ -1067,7 +1050,7 @@ scx_release_context(smartcard_t *sc) scx_logout(sc); sc->session_opened = FALSE; - + rv = pkcs11_functions->C_CloseSession(sc->session); if (rv != CKR_OK) plog("error in C_CloseSession: %s" @@ -1083,68 +1066,66 @@ scx_release_context(smartcard_t *sc) /* * Load host certificate from smartcard */ -bool -scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert -, bool *cached) +cert_t* scx_load_cert(const char *filename, smartcard_t **scp, bool *cached) { #ifdef SMARTCARD /* compile with smartcard support */ - CK_OBJECT_HANDLE object; - const char *number_slot_id = filename + strlen(SCX_TOKEN); - - smartcard_t *sc = scx_add(scx_parse_number_slot_id(number_slot_id)); + CK_OBJECT_HANDLE object; + smartcard_t *sc; + cert_t *cert = NULL; /* return the smartcard object */ - *scp = sc; + *scp = sc = scx_add(scx_parse_number_slot_id(number_slot_id)); /* is there a cached smartcard certificate? */ - *cached = sc->last_cert.type != CERT_NONE - && (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; + *cached = sc->last_cert && + (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; if (*cached) { - *cert = sc->last_cert; plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')" , sc->number , scx_print_slot(sc, "") , sc->id , sc->label); - return TRUE; + return sc->last_cert; } if (!scx_establish_context(sc)) { scx_release_context(sc); - return FALSE; + return NULL; } /* find the certificate object */ if (!scx_pkcs11_find_object(sc->session, &object, CKO_CERTIFICATE, sc->id)) { scx_release_context(sc); - return FALSE; + return NULL; } /* retrieve the certificate object */ - if (!scx_find_cert_object(sc->session, object, sc, cert)) + cert = scx_find_cert_object(sc->session, object, sc); + if (cert == NULL) { scx_release_context(sc); - return FALSE; + return NULL; } if (!pkcs11_keep_state) + { scx_release_context(sc); - + } plog(" loaded cert from smartcard #%d (%s, id: %s, label: '%s')" , sc->number , scx_print_slot(sc, "") , sc->id , sc->label); - return TRUE; + return cert; #else plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); - return FALSE; + return NULL; #endif } @@ -1158,8 +1139,7 @@ scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert * %smartcard:45 - - 45 * %smartcard0:45 - 0 45 */ -smartcard_t* -scx_parse_number_slot_id(const char *number_slot_id) +smartcard_t* scx_parse_number_slot_id(const char *number_slot_id) { int len = strlen(number_slot_id); smartcard_t *sc = malloc_thing(smartcard_t); @@ -1169,7 +1149,7 @@ scx_parse_number_slot_id(const char *number_slot_id) if (len == 0) /* default: use certificate #1 */ { - sc->number = 1; + sc->number = 1; } else if (*number_slot_id == '#') /* #number scheme */ { @@ -1218,12 +1198,11 @@ scx_parse_number_slot_id(const char *number_slot_id) /* * Verify pin on card */ -bool -scx_verify_pin(smartcard_t *sc) +bool scx_verify_pin(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; - + if (!sc->pinpad) sc->valid = FALSE; @@ -1270,9 +1249,8 @@ scx_verify_pin(smartcard_t *sc) /* * Sign hash on smartcard */ -bool -scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen -, u_char *out, size_t outlen) +bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, + size_t outlen) { #ifdef SMARTCARD CK_RV rv; @@ -1377,12 +1355,11 @@ scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen #endif } -/* +/* * encrypt data block with an RSA public key */ -bool -scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen -, u_char *out, size_t *outlen) +bool scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, + size_t *outlen) { #ifdef SMARTCARD CK_RV rv; @@ -1423,7 +1400,7 @@ scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen scx_release_context(sc); return FALSE; } - + /* there must be enough space left for the PKCS#1 v1.5 padding */ if (inlen > attr[0].ulValueLen - 11) { @@ -1467,7 +1444,7 @@ scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen rsa_key = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_integer("m", rsa_modulus), asn1_integer("m", rsa_exponent)); - key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER, rsa_key, BUILD_END); free(rsa_key.ptr); if (key == NULL) @@ -1527,12 +1504,11 @@ scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen return FALSE; #endif } -/* +/* * decrypt a data block with an RSA private key */ -bool -scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen -, u_char *out, size_t *outlen) +bool scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, + size_t *outlen) { #ifdef SMARTCARD CK_RV rv; @@ -1570,7 +1546,7 @@ scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen scx_release_context(sc); return FALSE; } - + DBG(DBG_CONTROL, DBG_log("doing RSA decryption on smartcard") ) @@ -1606,9 +1582,8 @@ scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen * decrypt it using a private RSA key and * return the decrypted data block via whack */ -bool -scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op -, const char* keyid, int whackfd) +bool scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op, + const char* keyid, int whackfd) { char inbuf[RSA_MAX_OCTETS]; char outbuf[2*RSA_MAX_OCTETS + 1]; @@ -1680,7 +1655,7 @@ scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op DBG_dump("smartcard output data:\n", inbuf, outlen) ) - if (outbase == 0) /* use default base */ + if (outbase == 0) /* use default base */ outbase = DEFAULT_BASE; if (outbase == 256) /* ascii plain text */ @@ -1701,8 +1676,7 @@ scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op /* * get length of RSA key in bytes */ -size_t -scx_get_keylength(smartcard_t *sc) +size_t scx_get_keylength(smartcard_t *sc) { #ifdef SMARTCARD CK_RV rv; @@ -1737,8 +1711,7 @@ scx_get_keylength(smartcard_t *sc) /* * prompt for pin and verify it */ -bool -scx_get_pin(smartcard_t *sc, int whackfd) +bool scx_get_pin(smartcard_t *sc, int whackfd) { #ifdef SMARTCARD char pin[BUF_LEN]; @@ -1796,8 +1769,7 @@ scx_get_pin(smartcard_t *sc, int whackfd) /* * free the pin code */ -void -scx_free_pin(chunk_t *pin) +void scx_free_pin(chunk_t *pin) { if (pin->ptr != NULL) { @@ -1811,12 +1783,12 @@ scx_free_pin(chunk_t *pin) /* * frees a smartcard record */ -void -scx_free(smartcard_t *sc) +void scx_free(smartcard_t *sc) { if (sc != NULL) { scx_release_context(sc); + cert_release(sc->last_cert); free(sc->id); free(sc->label); scx_free_pin(&sc->pin); @@ -1827,8 +1799,7 @@ scx_free(smartcard_t *sc) /* release of a smartcard record decreases the count by one " the record is freed when the counter reaches zero */ -void -scx_release(smartcard_t *sc) +void scx_release(smartcard_t *sc) { if (sc != NULL && --sc->count == 0) { @@ -1836,7 +1807,6 @@ scx_release(smartcard_t *sc) while (*pp != sc) pp = &(*pp)->next; *pp = sc->next; - release_cert(sc->last_cert); scx_free(sc); } } @@ -1844,8 +1814,7 @@ scx_release(smartcard_t *sc) /* * compare two smartcard records by comparing their slots and ids */ -static bool -scx_same(smartcard_t *a, smartcard_t *b) +static bool scx_same(smartcard_t *a, smartcard_t *b) { if (a->number && b->number) { @@ -1863,8 +1832,7 @@ scx_same(smartcard_t *a, smartcard_t *b) /* for each link pointing to the smartcard record " increase the count by one */ -void -scx_share(smartcard_t *sc) +void scx_share(smartcard_t *sc) { if (sc != NULL) sc->count++; @@ -1873,8 +1841,7 @@ scx_share(smartcard_t *sc) /* * adds a smartcard record to the chained list */ -smartcard_t* -scx_add(smartcard_t *smartcard) +smartcard_t* scx_add(smartcard_t *smartcard) { smartcard_t *sc = smartcards; smartcard_t **psc = &smartcards; @@ -1903,15 +1870,16 @@ scx_add(smartcard_t *smartcard) /* * get the smartcard that belongs to an X.509 certificate */ -smartcard_t* -scx_get(x509cert_t *cert) +smartcard_t* scx_get(cert_t *cert) { smartcard_t *sc = smartcards; while (sc != NULL) { - if (sc->last_cert.u.x509 == cert) + if (sc->last_cert == cert) + { return sc; + } sc = sc->next; } return NULL; @@ -1920,8 +1888,7 @@ scx_get(x509cert_t *cert) /* * prints either the slot number or 'any slot' */ -char * -scx_print_slot(smartcard_t *sc, const char *whitespace) +char *scx_print_slot(smartcard_t *sc, const char *whitespace) { char *buf = temporary_cyclic_buffer(); @@ -1935,8 +1902,7 @@ scx_print_slot(smartcard_t *sc, const char *whitespace) /* * list all smartcard info records in a chained list */ -void -scx_list(bool utc) +void scx_list(bool utc) { smartcard_t *sc = smartcards; @@ -1944,32 +1910,28 @@ scx_list(bool utc) { whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, "List of Smartcard Objects:"); - whack_log(RC_COMMENT, " "); } while (sc != NULL) { - whack_log(RC_COMMENT, "%T, #%d, count: %d" - , &sc->last_load, utc - , sc->number - , sc->count); - whack_log(RC_COMMENT, " %s, session %s, logged %s, has %s" + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, " %s, session %s, logged %s, has %s" , scx_print_slot(sc, " ") , sc->session_opened? "opened" : "closed" , sc->logged_in? "in" : "out" - , sc->pinpad? "pin pad" + , sc->pinpad? "pin pad" : ((sc->pin.ptr == NULL)? "no pin" : sc->valid? "valid pin" : "invalid pin")); if (sc->id != NULL) - whack_log(RC_COMMENT, " id: %s", sc->id); + whack_log(RC_COMMENT, " id: %s", sc->id); if (sc->label != NULL) - whack_log(RC_COMMENT, " label: '%s'", sc->label); - if (sc->last_cert.type == CERT_X509_SIGNATURE) + whack_log(RC_COMMENT, " label: '%s'", sc->label); + if (sc->last_cert) { - char buf[BUF_LEN]; + certificate_t *certificate = sc->last_cert->cert; - dntoa(buf, BUF_LEN, sc->last_cert.u.x509->subject); - whack_log(RC_COMMENT, " subject: '%s'", buf); + whack_log(RC_COMMENT, " subject: '%Y'", + certificate->get_subject(certificate)); } sc = sc->next; } diff --git a/src/pluto/smartcard.h b/src/pluto/smartcard.h index 60a0fccfc..7a2229794 100644 --- a/src/pluto/smartcard.h +++ b/src/pluto/smartcard.h @@ -42,7 +42,7 @@ typedef struct smartcard smartcard_t; struct smartcard { smartcard_t *next; time_t last_load; - cert_t last_cert; + cert_t *last_cert; int count; int number; unsigned long slot; @@ -75,8 +75,7 @@ extern void scx_finalize(void); extern bool scx_establish_context(smartcard_t *sc); extern bool scx_login(smartcard_t *sc); extern bool scx_on_smartcard(const char *filename); -extern bool scx_load_cert(const char *filename, smartcard_t **scp - , cert_t *cert, bool *cached); +extern cert_t* scx_load_cert(const char *filename, smartcard_t **scp, bool *cached); extern bool scx_verify_pin(smartcard_t *sc); extern void scx_share(smartcard_t *sc); extern bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen @@ -90,7 +89,7 @@ extern bool scx_op_via_whack(const char* msg, int inbase, int outbase extern bool scx_get_pin(smartcard_t *sc, int whackfd); extern size_t scx_get_keylength(smartcard_t *sc); extern smartcard_t* scx_add(smartcard_t *sc); -extern smartcard_t* scx_get(x509cert_t *cert); +extern smartcard_t* scx_get(cert_t *cert); extern void scx_release(smartcard_t *sc); extern void scx_release_context(smartcard_t *sc); extern void scx_free_pin(chunk_t *pin); diff --git a/src/pluto/spdb.c b/src/pluto/spdb.c index a86c9f215..cdf2cb21b 100644 --- a/src/pluto/spdb.c +++ b/src/pluto/spdb.c @@ -24,7 +24,6 @@ #include "constants.h" #include "defs.h" -#include "id.h" #include "connections.h" #include "state.h" #include "packet.h" @@ -607,7 +606,7 @@ static u_int32_t decode_long_duration(pb_stream *pbs) } /* Preparse the body of an ISAKMP SA Payload and - * return body of ISAKMP Proposal Payload + * return body of ISAKMP Proposal Payload * * Only IPsec DOI is accepted (what is the ISAKMP DOI?). * Error response is rudimentary. @@ -624,20 +623,20 @@ preparse_isakmp_sa_body(const struct isakmp_sa *sa { loglog(RC_LOG_SERIOUS, "Unknown/unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); /* XXX Could send notification back */ - return DOI_NOT_SUPPORTED; + return ISAKMP_DOI_NOT_SUPPORTED; } /* Situation */ if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) { - return SITUATION_NOT_SUPPORTED; + return ISAKMP_SITUATION_NOT_SUPPORTED; } if (*ipsecdoisit != SIT_IDENTITY_ONLY) { loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" , bitnamesof(sit_bit_names, *ipsecdoisit)); /* XXX Could send notification back */ - return SITUATION_NOT_SUPPORTED; + return ISAKMP_SITUATION_NOT_SUPPORTED; } /* The rules for ISAKMP SAs are scattered. @@ -647,20 +646,20 @@ preparse_isakmp_sa_body(const struct isakmp_sa *sa */ if (!in_struct(proposal, &isakmp_proposal_desc, sa_pbs, proposal_pbs)) { - return PAYLOAD_MALFORMED; + return ISAKMP_PAYLOAD_MALFORMED; } if (proposal->isap_np != ISAKMP_NEXT_NONE) { loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal" , enum_show(&payload_names, proposal->isap_np)); - return PAYLOAD_MALFORMED; + return ISAKMP_PAYLOAD_MALFORMED; } if (proposal->isap_protoid != PROTO_ISAKMP) { loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) found in Oakley Proposal" , enum_show(&protocol_names, proposal->isap_protoid)); - return INVALID_PROTOCOL_ID; + return ISAKMP_INVALID_PROTOCOL_ID; } /* Just what should we accept for the SPI field? @@ -694,15 +693,15 @@ preparse_isakmp_sa_body(const struct isakmp_sa *sa u_char junk_spi[MAX_ISAKMP_SPI_SIZE]; if (!in_raw(junk_spi, proposal->isap_spisize, proposal_pbs, "Oakley SPI")) - return PAYLOAD_MALFORMED; + return ISAKMP_PAYLOAD_MALFORMED; } else { loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal" , (unsigned)proposal->isap_spisize); - return INVALID_SPI; + return ISAKMP_INVALID_SPI; } - return NOTHING_WRONG; + return ISAKMP_NOTHING_WRONG; } static struct { @@ -750,14 +749,14 @@ notification_t parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs)) { - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } if (trans.isat_transnum <= last_transnum) { /* picky, picky, picky */ loglog(RC_LOG_SERIOUS, "Transform Numbers are not monotonically increasing" " in Oakley Proposal"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } last_transnum = trans.isat_transnum; @@ -765,7 +764,7 @@ notification_t parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, { loglog(RC_LOG_SERIOUS, "expected KEY_IKE but found %s in Oakley Transform" , enum_show(&isakmp_transformid_names, trans.isat_transid)); - return INVALID_TRANSFORM_ID; + return ISAKMP_INVALID_TRANSFORM_ID; } attr_start = trans_pbs.cur; @@ -779,7 +778,7 @@ notification_t parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) { - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); @@ -822,7 +821,7 @@ notification_t parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, DBG_log("preparse_isakmp_policy: peer requests %s authentication" , prettypolicy(*policy)) ) - return NOTHING_WRONG; + return ISAKMP_NOTHING_WRONG; } /** @@ -831,23 +830,22 @@ notification_t parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, static err_t find_preshared_key(struct state* st) { err_t ugh = NULL; - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; if (get_preshared_secret(c) == NULL) { - char my_id[BUF_LEN], his_id[BUF_LEN]; + char his_id[BUF_LEN]; - idtoa(&c->spd.this.id, my_id, sizeof(my_id)); if (his_id_was_instantiated(c)) { strcpy(his_id, "%any"); } else { - idtoa(&c->spd.that.id, his_id, sizeof(his_id)); + snprintf(his_id, sizeof(his_id), "%Y", c->spd.that.id); } - ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" - , my_id, his_id); + ugh = builddiag("Can't authenticate: no preshared key found " + "for '%Y' and '%s'", c->spd.this.id, his_id); } return ugh; } @@ -868,7 +866,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, struct state *st, bool initiator) { - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; unsigned no_trans_left; /* for each transform payload... */ @@ -892,7 +890,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, if (no_trans_left == 0) { loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs); @@ -908,7 +906,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, u_int32_t val; /* room for larger values */ if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); @@ -917,7 +915,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, loglog(RC_LOG_SERIOUS, "repeated %s attribute in Oakley Transform %u" , enum_show(&oakley_attr_names, a.isaat_af_type) , trans.isat_transnum); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); @@ -1071,7 +1069,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, loglog(RC_LOG_SERIOUS , "attribute OAKLEY_LIFE_TYPE value %s repeated" , enum_show(&oakley_lifetime_names, val)); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } seen_durations |= LELEM(val); life_type = val; @@ -1114,7 +1112,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, , (long) val , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); #endif - } + } ta.life_seconds = val; break; case OAKLEY_LIFE_KILOBYTES: @@ -1210,7 +1208,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, loglog(RC_LOG_SERIOUS, "missing mandatory attribute(s) %s in Oakley Transform %u" , bitnamesof(oakley_attr_bit_names, missing) , trans.isat_transnum); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } } /* We must have liked this transform. @@ -1264,7 +1262,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, /* copy over the results */ st->st_oakley = ta; - return NOTHING_WRONG; + return ISAKMP_NOTHING_WRONG; } /* on to next transform */ @@ -1275,7 +1273,7 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, if (no_trans_left != 0) { loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } break; } @@ -1283,11 +1281,11 @@ notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, { loglog(RC_LOG_SERIOUS, "unexpected %s payload in Oakley Proposal" , enum_show(&payload_names, proposal->isap_np)); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } } loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform"); - return NO_PROPOSAL_CHOSEN; + return ISAKMP_NO_PROPOSAL_CHOSEN; } /* Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode). @@ -1712,7 +1710,7 @@ parse_ipsec_sa_body( bool selection, /* if this SA is a selection, only one transform may appear */ struct state *st) /* current state object */ { - const struct connection *c = st->st_connection; + const connection_t *c = st->st_connection; u_int32_t ipsecdoisit; pb_stream next_proposal_pbs; @@ -1726,19 +1724,19 @@ parse_ipsec_sa_body( { loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); /* XXX Could send notification back */ - return DOI_NOT_SUPPORTED; + return ISAKMP_DOI_NOT_SUPPORTED; } /* Situation */ if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) - return SITUATION_NOT_SUPPORTED; + return ISAKMP_SITUATION_NOT_SUPPORTED; if (ipsecdoisit != SIT_IDENTITY_ONLY) { loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" , bitnamesof(sit_bit_names, ipsecdoisit)); /* XXX Could send notification back */ - return SITUATION_NOT_SUPPORTED; + return ISAKMP_SITUATION_NOT_SUPPORTED; } /* The rules for IPsec SAs are scattered. @@ -1755,7 +1753,7 @@ parse_ipsec_sa_body( */ if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; /* for each conjunction of proposals... */ while (next_full) @@ -1797,13 +1795,13 @@ parse_ipsec_sa_body( if (!in_raw(filler, sizeof(filler) , &next_proposal_pbs, "CPI filler") || !all_zero(filler, sizeof(filler))) - return INVALID_SPI; + return ISAKMP_INVALID_SPI; } else if (next_proposal.isap_spisize != IPCOMP_CPI_SIZE) { loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper CPI size (%u)" , next_proposal.isap_spisize); - return INVALID_SPI; + return ISAKMP_INVALID_SPI; } /* We store CPI in the low order of a network order @@ -1813,7 +1811,7 @@ parse_ipsec_sa_body( if (!in_raw((u_char *)&next_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE , IPCOMP_CPI_SIZE, &next_proposal_pbs, "CPI")) - return INVALID_SPI; + return ISAKMP_INVALID_SPI; /* If sanity ruled, CPIs would have to be such that * the SAID (the triple (CPI, IPCOM, destination IP)) @@ -1832,7 +1830,7 @@ parse_ipsec_sa_body( { loglog(RC_LOG_SERIOUS , "IPsec Proposal contains well-known CPI that I cannot uniquify"); - return INVALID_SPI; + return ISAKMP_INVALID_SPI; } break; default: @@ -1841,7 +1839,7 @@ parse_ipsec_sa_body( { loglog(RC_LOG_SERIOUS, "IPsec Proposal contains CPI from non-negotiated range (0x%lx)" , (unsigned long) ntohl(next_spi)); - return INVALID_SPI; + return ISAKMP_INVALID_SPI; } break; } @@ -1853,11 +1851,11 @@ parse_ipsec_sa_body( { loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper SPI size (%u)" , next_proposal.isap_spisize); - return INVALID_SPI; + return ISAKMP_INVALID_SPI; } if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI")) - return INVALID_SPI; + return ISAKMP_INVALID_SPI; /* SPI value 0 is invalid and values 1-255 are reserved to IANA. * RFC 2402 (ESP) 2.4, RFC 2406 (AH) 2.1 @@ -1867,14 +1865,14 @@ parse_ipsec_sa_body( { loglog(RC_LOG_SERIOUS, "IPsec Proposal contains invalid SPI (0x%lx)" , (unsigned long) ntohl(next_spi)); - return INVALID_SPI; + return ISAKMP_INVALID_SPI; } } if (next_proposal.isap_notrans == 0) { loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } switch (next_proposal.isap_protoid) @@ -1883,7 +1881,7 @@ parse_ipsec_sa_body( if (ah_seen) { loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous AH Proposals"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } ah_seen = TRUE; ah_prop_pbs = next_proposal_pbs; @@ -1895,7 +1893,7 @@ parse_ipsec_sa_body( if (esp_seen) { loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous ESP Proposals"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } esp_seen = TRUE; esp_prop_pbs = next_proposal_pbs; @@ -1907,7 +1905,7 @@ parse_ipsec_sa_body( if (ipcomp_seen) { loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous IPCOMP Proposals"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } ipcomp_seen = TRUE; ipcomp_prop_pbs = next_proposal_pbs; @@ -1918,7 +1916,7 @@ parse_ipsec_sa_body( default: loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) in IPsec Proposal" , enum_show(&protocol_names, next_proposal.isap_protoid)); - return INVALID_PROTOCOL_ID; + return ISAKMP_INVALID_PROTOCOL_ID; } /* refill next_proposal */ @@ -1931,11 +1929,11 @@ parse_ipsec_sa_body( { loglog(RC_LOG_SERIOUS, "unexpected in Proposal: %s" , enum_show(&payload_names, next_proposal.isap_np)); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } while (next_proposal.isap_proposal == propno); /* Now that we have all conjuncts, we should try @@ -1968,7 +1966,7 @@ parse_ipsec_sa_body( , tn == ah_proposal.isap_notrans - 1 , FALSE , st)) - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; previous_transnum = ah_trans.isat_transnum; @@ -1988,7 +1986,7 @@ parse_ipsec_sa_body( { case AUTH_ALGORITHM_NONE: loglog(RC_LOG_SERIOUS, "AUTH_ALGORITHM attribute missing in AH Transform"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; case AUTH_ALGORITHM_HMAC_MD5: ok_auth = TRUE; @@ -2010,8 +2008,8 @@ parse_ipsec_sa_body( { loglog(RC_LOG_SERIOUS, "%s attribute inappropriate in %s Transform" , enum_name(&auth_alg_names, ah_attrs.auth) - , enum_show(&ah_transformid_names, ah_attrs.transid)); - return BAD_PROPOSAL_SYNTAX; + , enum_show(&ah_transform_names, ah_attrs.transid)); + return ISAKMP_BAD_PROPOSAL_SYNTAX; } if (!ok_auth) { @@ -2019,7 +2017,7 @@ parse_ipsec_sa_body( , DBG_log("%s attribute unsupported" " in %s Transform from %s" , enum_name(&auth_alg_names, ah_attrs.auth) - , enum_show(&ah_transformid_names, ah_attrs.transid) + , enum_show(&ah_transform_names, ah_attrs.transid) , ip_str(&c->spd.that.host_addr))); continue; /* try another */ } @@ -2050,7 +2048,7 @@ parse_ipsec_sa_body( , tn == esp_proposal.isap_notrans - 1 , FALSE , st)) - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; previous_transnum = esp_trans.isat_transnum; @@ -2087,7 +2085,7 @@ parse_ipsec_sa_body( default: DBG(DBG_CONTROL | DBG_CRYPT , DBG_log("unsupported ESP Transform %s from %s" - , enum_show(&esp_transformid_names, esp_attrs.transid) + , enum_show(&esp_transform_names, esp_attrs.transid) , ip_str(&c->spd.that.host_addr))); continue; /* try another */ } @@ -2138,7 +2136,7 @@ parse_ipsec_sa_body( } if (tn == esp_proposal.isap_notrans) continue; /* we didn't find a nice one */ - + esp_attrs.spi = esp_spi; inner_proto = IPPROTO_ESP; if (esp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) @@ -2186,7 +2184,7 @@ parse_ipsec_sa_body( if (well_known_cpi != 0 && !ah_seen && !esp_seen) { plog("illegal proposal: bare IPCOMP used with well-known CPI"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } for (tn = 0; tn != ipcomp_proposal.isap_notrans; tn++) @@ -2201,14 +2199,14 @@ parse_ipsec_sa_body( , tn == ipcomp_proposal.isap_notrans - 1 , TRUE , st)) - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; previous_transnum = ipcomp_trans.isat_transnum; if (well_known_cpi != 0 && ipcomp_attrs.transid != well_known_cpi) { plog("illegal proposal: IPCOMP well-known CPI disagrees with transform"); - return BAD_PROPOSAL_SYNTAX; + return ISAKMP_BAD_PROPOSAL_SYNTAX; } switch (ipcomp_attrs.transid) @@ -2309,9 +2307,9 @@ parse_ipsec_sa_body( if (ipcomp_seen) st->st_ipcomp.attrs = ipcomp_attrs; - return NOTHING_WRONG; + return ISAKMP_NOTHING_WRONG; } loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA"); - return NO_PROPOSAL_CHOSEN; + return ISAKMP_NO_PROPOSAL_CHOSEN; } diff --git a/src/pluto/state.c b/src/pluto/state.c index 5bef36c5c..29d78fb3d 100644 --- a/src/pluto/state.c +++ b/src/pluto/state.c @@ -277,7 +277,7 @@ void release_whack(struct state *st) */ void delete_state(struct state *st) { - struct connection *const c = st->st_connection; + connection_t *const c = st->st_connection; struct state *old_cur_state = cur_state == st? NULL : cur_state; set_cur_state(st); @@ -371,7 +371,7 @@ void delete_state(struct state *st) /** * Is a connection in use by some state? */ -bool states_use_connection(struct connection *c) +bool states_use_connection(connection_t *c) { /* are there any states still using it? */ struct state *st = NULL; @@ -390,7 +390,7 @@ bool states_use_connection(struct connection *c) * if relations == TRUE, then also delete states that share * the same phase 1 SA. */ -void delete_states_by_connection(struct connection *c, bool relations) +void delete_states_by_connection(connection_t *c, bool relations) { int pass; /* this kludge avoids an n^2 algorithm */ @@ -448,7 +448,7 @@ void delete_states_by_connection(struct connection *c, bool relations) } } } - + sr = &c->spd; while (sr != NULL) { @@ -480,7 +480,7 @@ void delete_states_by_peer(ip_address *peer) { struct state *this = st; struct spd_route *sr; - struct connection *c = this->st_connection; + connection_t *c = this->st_connection; st = st->st_hashchain_next; /* before this is deleted */ @@ -521,7 +521,7 @@ struct state *duplicate_state(struct state *st) memcpy(nst->st_icookie, st->st_icookie, COOKIE_SIZE); memcpy(nst->st_rcookie, st->st_rcookie, COOKIE_SIZE); - + nst->st_connection = st->st_connection; nst->st_doi = st->st_doi; nst->st_situation = st->st_situation; @@ -646,7 +646,7 @@ struct state *find_phase2_state_to_delete(const struct state *p1st, /** * Find newest Phase 1 negotiation state object for suitable for connection c */ -struct state *find_phase1_state(const struct connection *c, lset_t ok_states) +struct state *find_phase1_state(const connection_t *c, lset_t ok_states) { struct state *st, @@ -674,7 +674,7 @@ void state_eroute_usage(ip_subnet *ours, ip_subnet *his, unsigned long count, { for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { - struct connection *c = st->st_connection; + connection_t *c = st->st_connection; /* XXX spd-enum */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state) @@ -708,7 +708,7 @@ void fmt_state(bool all, struct state *st, time_t n, char *state_buf, size_t state_buf_len, char *state_buf2, size_t state_buf2_len) { /* what the heck is interesting about a state? */ - const struct connection *c = st->st_connection; + const connection_t *c = st->st_connection; long delta = st->st_event->ev_time >= n ? (long)(st->st_event->ev_time - n) @@ -724,7 +724,7 @@ void fmt_state(bool all, struct state *st, time_t n, char *state_buf, ? "; eroute owner" : ""; const char *dpd = (all && st->st_dpd && c->dpd_action != DPD_ACTION_NONE) ? "; DPD active" : ""; - + passert(st->st_event != 0); fmt_conn_instance(c, inst); @@ -824,9 +824,9 @@ void fmt_state(bool all, struct state *st, time_t n, char *state_buf, static int state_compare(const void *a, const void *b) { const struct state *sap = *(const struct state *const *)a; - struct connection *ca = sap->st_connection; + connection_t *ca = sap->st_connection; const struct state *sbp = *(const struct state *const *)b; - struct connection *cb = sbp->st_connection; + connection_t *cb = sbp->st_connection; /* DBG_log("comparing %s to %s", ca->name, cb->name); */ diff --git a/src/pluto/state.h b/src/pluto/state.h index a059c52b4..35ffe5a5b 100644 --- a/src/pluto/state.h +++ b/src/pluto/state.h @@ -21,6 +21,7 @@ #include <crypto/diffie_hellman.h> +#include "defs.h" #include "connections.h" /* Message ID mechanism. diff --git a/src/pluto/timer.c b/src/pluto/timer.c index 89082f88e..74806a40c 100644 --- a/src/pluto/timer.c +++ b/src/pluto/timer.c @@ -143,7 +143,7 @@ void event_schedule(enum event_type type, time_t tm, struct state *st) bool init_secret(void) { rng_t *rng; - + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); if (rng == NULL) @@ -166,7 +166,7 @@ void handle_timer_event(void) struct event *ev = evlist; int type; struct state *st; - struct connection *c = NULL; + connection_t *c = NULL; ip_address peer; if (ev == (struct event *) NULL) /* Just paranoid */ @@ -216,7 +216,7 @@ void handle_timer_event(void) passert(st->st_dpd_event == ev); st->st_dpd_event = NULL; } - else + else { passert(st->st_event == ev); st->st_event = NULL; diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c index a532e50f2..7d3c96c87 100644 --- a/src/pluto/vendor.c +++ b/src/pluto/vendor.c @@ -158,7 +158,7 @@ static struct vid_struct _vid_tab[] = { { VID_CISCO3K, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "Cisco VPN 3000 Series" , { "\x1f\x07\xf7\x0e\xaa\x65\x14\xd3\xb0\xfa\x96\x54\x2a\x50", 14 } }, - { VID_CISCO_IOS, VID_KEEP | VID_SUBSTRING_MATCH, + { VID_CISCO_IOS, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "Cisco IOS Device", { "\x3e\x98\x40\x48", 4 } }, /* @@ -197,7 +197,9 @@ static struct vid_struct _vid_tab[] = { /* * strongSwan */ - DEC_MD5_VID(STRONGSWAN, "strongSwan 4.3.4") + DEC_MD5_VID(STRONGSWAN, "strongSwan") + DEC_MD5_VID(STRONGSWAN_4_3_5, "strongSwan 4.3.5") + DEC_MD5_VID(STRONGSWAN_4_3_4, "strongSwan 4.3.4") DEC_MD5_VID(STRONGSWAN_4_3_3, "strongSwan 4.3.3") DEC_MD5_VID(STRONGSWAN_4_3_2, "strongSwan 4.3.2") DEC_MD5_VID(STRONGSWAN_4_3_1, "strongSwan 4.3.1") @@ -296,7 +298,7 @@ static struct vid_struct _vid_tab[] = { DEC_MD5_VID(NATT_RFC, "RFC 3947") /* misc */ - + { VID_MISC_XAUTH, VID_KEEP, NULL, "XAUTH", { "\x09\x00\x26\x89\xdf\xd6\xb7\x12", 8 } }, @@ -304,7 +306,7 @@ static struct vid_struct _vid_tab[] = { { "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00", 16 } }, DEC_MD5_VID(MISC_FRAGMENTATION, "FRAGMENTATION") - + DEC_MD5_VID(INITIAL_CONTACT, "Vid-Initial-Contact") /** @@ -338,9 +340,9 @@ void init_vendorid(void) else if (vid->flags & VID_MD5HASH) { chunk_t vid_data = { (u_char *)vid->data, strlen(vid->data) }; - + /** VendorID is a string to hash with MD5 **/ - hasher->allocate_hash(hasher, vid_data, &vid->vid); + hasher->allocate_hash(hasher, vid_data, &vid->vid); } if (vid->descr == NULL) diff --git a/src/pluto/vendor.h b/src/pluto/vendor.h index 8aa2f6348..3df1a8196 100644 --- a/src/pluto/vendor.h +++ b/src/pluto/vendor.h @@ -138,6 +138,8 @@ enum known_vendorid { VID_STRONGSWAN_4_3_1 =119, VID_STRONGSWAN_4_3_2 =120, VID_STRONGSWAN_4_3_3 =121, + VID_STRONGSWAN_4_3_4 =122, + VID_STRONGSWAN_4_3_5 =123, /* 101 - 200 : NAT-Traversal */ VID_NATT_STENBERG_01 =151, diff --git a/src/pluto/virtual.c b/src/pluto/virtual.c index 2067bde01..3e8d5fcba 100644 --- a/src/pluto/virtual.c +++ b/src/pluto/virtual.c @@ -180,7 +180,7 @@ init_virtual_ip(const char *private_list) * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24 */ struct virtual_t -*create_virtual(const struct connection *c, const char *string) +*create_virtual(const connection_t *c, const char *string) { unsigned short flags=0, n_net=0, i; const char *str = string, *next, *first_net=NULL; @@ -227,7 +227,7 @@ struct virtual_t } else goto fail; - + str = *next ? next+1 : NULL; } @@ -267,14 +267,13 @@ is_virtual_end(const struct end *that) } bool -is_virtual_connection(const struct connection *c) +is_virtual_connection(const connection_t *c) { return ((c->spd.that.virt)?TRUE:FALSE); } -static bool -net_in_list(const ip_subnet *peer_net, const ip_subnet *list, - unsigned short len) +static bool net_in_list(const ip_subnet *peer_net, const ip_subnet *list, + unsigned short len) { unsigned short i; @@ -289,9 +288,8 @@ net_in_list(const ip_subnet *peer_net, const ip_subnet *list, return FALSE; } -bool -is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net, - const ip_address *his_addr) +bool is_virtual_net_allowed(const connection_t *c, const ip_subnet *peer_net, + const ip_address *his_addr) { if (c->spd.that.virt == NULL) return FALSE; @@ -312,7 +310,7 @@ is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net, if (c->spd.that.virt->n_net && net_in_list(peer_net, c->spd.that.virt->net, c->spd.that.virt->n_net)) return TRUE; - + if (c->spd.that.virt->flags & F_VIRTUAL_ALL) { /** %all must only be used for testing - log it **/ diff --git a/src/pluto/x509.c b/src/pluto/x509.c index 0953f18f5..d8e887955 100644 --- a/src/pluto/x509.c +++ b/src/pluto/x509.c @@ -26,14 +26,13 @@ #include <freeswan.h> #include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <asn1/oid.h> #include <crypto/hashers/hasher.h> +#include <utils/enumerator.h> +#include <utils/identification.h> #include "constants.h" #include "defs.h" #include "log.h" -#include "id.h" #include "x509.h" #include "crl.h" #include "ca.h" @@ -44,1000 +43,6 @@ #include "ocsp.h" /** - * Chained lists of X.509 end certificates - */ -static x509cert_t *x509certs = NULL; - -/** - * ASN.1 definition of a basicConstraints extension - */ -static const asn1Object_t basicConstraintsObjects[] = { - { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ - { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define BASIC_CONSTRAINTS_CA 1 - -/** - * ASN.1 definition of a authorityKeyIdentifier extension - */ -static const asn1Object_t authKeyIdentifierObjects[] = { - { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_BODY }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ - { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define AUTH_KEY_ID_KEY_ID 1 -#define AUTH_KEY_ID_CERT_ISSUER 3 -#define AUTH_KEY_ID_CERT_SERIAL 5 - -/** - * ASN.1 definition of a authorityInfoAccess extension - */ -static const asn1Object_t authInfoAccessObjects[] = { - { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ - { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define AUTH_INFO_ACCESS_METHOD 2 -#define AUTH_INFO_ACCESS_LOCATION 3 - -/** - * ASN.1 definition of a extendedKeyUsage extension - */ -static const asn1Object_t extendedKeyUsageObjects[] = { - { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define EXT_KEY_USAGE_PURPOSE_ID 1 - -/** - * ASN.1 definition of generalNames - */ -static const asn1Object_t generalNamesObjects[] = { - { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define GENERAL_NAMES_GN 1 - -/** - * ASN.1 definition of generalName - */ -static const asn1Object_t generalNameObjects[] = { - { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ - { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ - { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ - { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ - { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ - { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 17 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define GN_OBJ_OTHER_NAME 0 -#define GN_OBJ_RFC822_NAME 2 -#define GN_OBJ_DNS_NAME 4 -#define GN_OBJ_X400_ADDRESS 6 -#define GN_OBJ_DIRECTORY_NAME 8 -#define GN_OBJ_EDI_PARTY_NAME 10 -#define GN_OBJ_URI 12 -#define GN_OBJ_IP_ADDRESS 14 -#define GN_OBJ_REGISTERED_ID 16 - -/** - * ASN.1 definition of otherName - */ -static const asn1Object_t otherNameObjects[] = { - {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ - {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 1 */ - {0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define ON_OBJ_ID_TYPE 0 -#define ON_OBJ_VALUE 1 - -/** - * ASN.1 definition of crlDistributionPoints - */ -static const asn1Object_t crlDistributionPointsObjects[] = { - { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */ - { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ - { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define CRL_DIST_POINTS_FULLNAME 3 - -/** - * ASN.1 definition of an X.509v3 x509_cert - */ -static const asn1Object_t certObjects[] = { - { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ - { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ - { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ - { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ - { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ - { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ - { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */ - { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ - { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */ - { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define X509_OBJ_CERTIFICATE 0 -#define X509_OBJ_TBS_CERTIFICATE 1 -#define X509_OBJ_VERSION 3 -#define X509_OBJ_SERIAL_NUMBER 4 -#define X509_OBJ_SIG_ALG 5 -#define X509_OBJ_ISSUER 6 -#define X509_OBJ_NOT_BEFORE 8 -#define X509_OBJ_NOT_AFTER 9 -#define X509_OBJ_SUBJECT 10 -#define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11 -#define X509_OBJ_EXTN_ID 19 -#define X509_OBJ_CRITICAL 20 -#define X509_OBJ_EXTN_VALUE 21 -#define X509_OBJ_ALGORITHM 24 -#define X509_OBJ_SIGNATURE 25 - -const x509cert_t empty_x509cert = { - NULL , /* *next */ - UNDEFINED_TIME, /* installed */ - 0 , /* count */ - FALSE , /* smartcard */ - AUTH_NONE , /* authority_flags */ - { NULL, 0 } , /* certificate */ - { NULL, 0 } , /* tbsCertificate */ - 1 , /* version */ - { NULL, 0 } , /* serialNumber */ - OID_UNKNOWN , /* sigAlg */ - { NULL, 0 } , /* issuer */ - /* validity */ - 0 , /* notBefore */ - 0 , /* notAfter */ - { NULL, 0 } , /* subject */ - NULL , /* public_key */ - /* issuerUniqueID */ - /* subjectUniqueID */ - /* extensions */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - FALSE , /* isCA */ - FALSE , /* isOcspSigner */ - { NULL, 0 } , /* subjectKeyID */ - { NULL, 0 } , /* authKeyID */ - { NULL, 0 } , /* authKeySerialNumber */ - { NULL, 0 } , /* accessLocation */ - NULL , /* subjectAltName */ - NULL , /* crlDistributionPoints */ - OID_UNKNOWN , /* algorithm */ - { NULL, 0 } /* signature */ -}; - -/* coding of X.501 distinguished name */ - -typedef struct { - const u_char *name; - chunk_t oid; - u_char type; -} x501rdn_t; - -/* X.501 acronyms for well known object identifiers (OIDs) */ - -static u_char oid_ND[] = {0x02, 0x82, 0x06, 0x01, - 0x0A, 0x07, 0x14}; -static u_char oid_UID[] = {0x09, 0x92, 0x26, 0x89, 0x93, - 0xF2, 0x2C, 0x64, 0x01, 0x01}; -static u_char oid_DC[] = {0x09, 0x92, 0x26, 0x89, 0x93, - 0xF2, 0x2C, 0x64, 0x01, 0x19}; -static u_char oid_CN[] = {0x55, 0x04, 0x03}; -static u_char oid_S[] = {0x55, 0x04, 0x04}; -static u_char oid_SN[] = {0x55, 0x04, 0x05}; -static u_char oid_C[] = {0x55, 0x04, 0x06}; -static u_char oid_L[] = {0x55, 0x04, 0x07}; -static u_char oid_ST[] = {0x55, 0x04, 0x08}; -static u_char oid_O[] = {0x55, 0x04, 0x0A}; -static u_char oid_OU[] = {0x55, 0x04, 0x0B}; -static u_char oid_T[] = {0x55, 0x04, 0x0C}; -static u_char oid_D[] = {0x55, 0x04, 0x0D}; -static u_char oid_N[] = {0x55, 0x04, 0x29}; -static u_char oid_G[] = {0x55, 0x04, 0x2A}; -static u_char oid_I[] = {0x55, 0x04, 0x2B}; -static u_char oid_ID[] = {0x55, 0x04, 0x2D}; -static u_char oid_EN[] = {0x60, 0x86, 0x48, 0x01, 0x86, - 0xF8, 0x42, 0x03, 0x01, 0x03}; -static u_char oid_E[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x09, 0x01}; -static u_char oid_UN[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x09, 0x02}; -static u_char oid_TCGID[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x89, - 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B}; - -static const x501rdn_t x501rdns[] = { - {"ND" , {oid_ND, 7}, ASN1_PRINTABLESTRING}, - {"UID" , {oid_UID, 10}, ASN1_PRINTABLESTRING}, - {"DC" , {oid_DC, 10}, ASN1_PRINTABLESTRING}, - {"CN" , {oid_CN, 3}, ASN1_PRINTABLESTRING}, - {"S" , {oid_S, 3}, ASN1_PRINTABLESTRING}, - {"SN" , {oid_SN, 3}, ASN1_PRINTABLESTRING}, - {"serialNumber" , {oid_SN, 3}, ASN1_PRINTABLESTRING}, - {"C" , {oid_C, 3}, ASN1_PRINTABLESTRING}, - {"L" , {oid_L, 3}, ASN1_PRINTABLESTRING}, - {"ST" , {oid_ST, 3}, ASN1_PRINTABLESTRING}, - {"O" , {oid_O, 3}, ASN1_PRINTABLESTRING}, - {"OU" , {oid_OU, 3}, ASN1_PRINTABLESTRING}, - {"T" , {oid_T, 3}, ASN1_PRINTABLESTRING}, - {"D" , {oid_D, 3}, ASN1_PRINTABLESTRING}, - {"N" , {oid_N, 3}, ASN1_PRINTABLESTRING}, - {"G" , {oid_G, 3}, ASN1_PRINTABLESTRING}, - {"I" , {oid_I, 3}, ASN1_PRINTABLESTRING}, - {"ID" , {oid_ID, 3}, ASN1_PRINTABLESTRING}, - {"EN" , {oid_EN, 10}, ASN1_PRINTABLESTRING}, - {"employeeNumber" , {oid_EN, 10}, ASN1_PRINTABLESTRING}, - {"E" , {oid_E, 9}, ASN1_IA5STRING}, - {"Email" , {oid_E, 9}, ASN1_IA5STRING}, - {"emailAddress" , {oid_E, 9}, ASN1_IA5STRING}, - {"UN" , {oid_UN, 9}, ASN1_IA5STRING}, - {"unstructuredName", {oid_UN, 9}, ASN1_IA5STRING}, - {"TCGID" , {oid_TCGID, 12}, ASN1_PRINTABLESTRING} -}; - -#define X501_RDN_ROOF 26 - -static u_char ASN1_subjectAltName_oid_str[] = { - 0x06, 0x03, 0x55, 0x1D, 0x11 -}; - -static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_subjectAltName_oid_str); - -static void update_chunk(chunk_t *ch, int n) -{ - n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1; - ch->ptr += n; ch->len -= n; -} - - -/** - * Pointer is set to the first RDN in a DN - */ -static err_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next) -{ - *rdn = chunk_empty; - *attribute = chunk_empty; - - /* a DN is a SEQUENCE OF RDNs */ - - if (*dn.ptr != ASN1_SEQUENCE) - { - return "DN is not a SEQUENCE"; - } - - rdn->len = asn1_length(&dn); - - if (rdn->len == ASN1_INVALID_LENGTH) - { - return "Invalid RDN length"; - } - rdn->ptr = dn.ptr; - - /* are there any RDNs ? */ - *next = rdn->len > 0; - - return NULL; -} - -/** - * Fetches the next RDN in a DN - */ -static err_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, - chunk_t *value, asn1_t *type, bool *next) -{ - chunk_t body; - - /* initialize return values */ - *oid = chunk_empty; - *value = chunk_empty; - - /* if all attributes have been parsed, get next rdn */ - if (attribute->len <= 0) - { - /* an RDN is a SET OF attributeTypeAndValue */ - if (*rdn->ptr != ASN1_SET) - { - return "RDN is not a SET"; - } - attribute->len = asn1_length(rdn); - - if (attribute->len == ASN1_INVALID_LENGTH) - { - return "Invalid attribute length"; - } - attribute->ptr = rdn->ptr; - - /* advance to start of next RDN */ - rdn->ptr += attribute->len; - rdn->len -= attribute->len; - } - - /* an attributeTypeAndValue is a SEQUENCE */ - if (*attribute->ptr != ASN1_SEQUENCE) - { - return "attributeTypeAndValue is not a SEQUENCE"; - } - - /* extract the attribute body */ - body.len = asn1_length(attribute); - - if (body.len == ASN1_INVALID_LENGTH) - { - return "Invalid attribute body length"; - } - body.ptr = attribute->ptr; - - /* advance to start of next attribute */ - attribute->ptr += body.len; - attribute->len -= body.len; - - /* attribute type is an OID */ - if (*body.ptr != ASN1_OID) - { - return "attributeType is not an OID"; - } - - /* extract OID */ - oid->len = asn1_length(&body); - - if (oid->len == ASN1_INVALID_LENGTH) - { - return "Invalid attribute OID length"; - } - oid->ptr = body.ptr; - - /* advance to the attribute value */ - body.ptr += oid->len; - body.len -= oid->len; - - /* extract string type */ - *type = *body.ptr; - - /* extract string value */ - value->len = asn1_length(&body); - - if (value->len == ASN1_INVALID_LENGTH) - { - return "Invalid attribute string length"; - } - value->ptr = body.ptr; - - /* are there any RDNs left? */ - *next = rdn->len > 0 || attribute->len > 0; - - return NULL; -} - -/** - * Parses an ASN.1 distinguished name int its OID/value pairs - */ -static err_t dn_parse(chunk_t dn, chunk_t *str) -{ - chunk_t rdn, oid, attribute, value; - asn1_t type; - int oid_code; - bool next; - bool first = TRUE; - - err_t ugh = init_rdn(dn, &rdn, &attribute, &next); - - if (ugh != NULL) /* a parsing error has occured */ - { - return ugh; - } - - while (next) - { - ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); - - if (ugh != NULL) /* a parsing error has occured */ - { - return ugh; - } - - if (first) /* first OID/value pair */ - { - first = FALSE; - } - else /* separate OID/value pair by a comma */ - { - update_chunk(str, snprintf(str->ptr,str->len,", ")); - } - - /* print OID */ - oid_code = asn1_known_oid(oid); - if (oid_code == OID_UNKNOWN) /* OID not found in list */ - { - hex_str(oid, str); - } - else - { - update_chunk(str, snprintf(str->ptr,str->len,"%s", - oid_names[oid_code].name)); - } - - /* print value */ - update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", - (int)value.len,value.ptr)); - } - return NULL; -} - -/** - * Count the number of wildcard RDNs in a distinguished name - */ -int dn_count_wildcards(chunk_t dn) -{ - chunk_t rdn, attribute, oid, value; - asn1_t type; - bool next; - int wildcards = 0; - - err_t ugh = init_rdn(dn, &rdn, &attribute, &next); - - if (ugh != NULL) /* a parsing error has occured */ - { - return -1; - } - - while (next) - { - ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); - - if (ugh != NULL) /* a parsing error has occured */ - { - return -1; - } - if (value.len == 1 && *value.ptr == '*') - { - wildcards++; /* we have found a wildcard RDN */ - } - } - return wildcards; -} - -/** - * Prints a binary string in hexadecimal form - */ -void hex_str(chunk_t bin, chunk_t *str) -{ - u_int i; - update_chunk(str, snprintf(str->ptr,str->len,"0x")); - for (i=0; i < bin.len; i++) - update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++)); -} - - -/** Converts a binary DER-encoded ASN.1 distinguished name - * into LDAP-style human-readable ASCII format - */ -int dntoa(char *dst, size_t dstlen, chunk_t dn) -{ - err_t ugh = NULL; - chunk_t str; - - str.ptr = dst; - str.len = dstlen; - ugh = dn_parse(dn, &str); - - if (ugh != NULL) /* error, print DN as hex string */ - { - DBG(DBG_PARSING, - DBG_log("error in DN parsing: %s", ugh) - ) - str.ptr = dst; - str.len = dstlen; - hex_str(dn, &str); - } - return (int)(dstlen - str.len); -} - -/** - * Same as dntoa but prints a special string for a null dn - */ -int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn) -{ - if (dn.ptr == NULL) - { - return snprintf(dst, dstlen, "%s", null_dn); - } - else - { - return dntoa(dst, dstlen, dn); - } -} - - -/** - * Codes ASN.1 lengths up to a size of 16'777'215 bytes - */ -static void code_asn1_length(size_t length, chunk_t *code) -{ - if (length < 128) - { - code->ptr[0] = length; - code->len = 1; - } - else if (length < 256) - { - code->ptr[0] = 0x81; - code->ptr[1] = (u_char) length; - code->len = 2; - } - else if (length < 65536) - { - code->ptr[0] = 0x82; - code->ptr[1] = length >> 8; - code->ptr[2] = length & 0x00ff; - code->len = 3; - } - else - { - code->ptr[0] = 0x83; - code->ptr[1] = length >> 16; - code->ptr[2] = (length >> 8) & 0x00ff; - code->ptr[3] = length & 0x0000ff; - code->len = 4; - } -} - -/** - * Converts an LDAP-style human-readable ASCII-encoded - * ASN.1 distinguished name into binary DER-encoded format - */ -err_t atodn(char *src, chunk_t *dn) -{ - /* finite state machine for atodn */ - - typedef enum { - SEARCH_OID = 0, - READ_OID = 1, - SEARCH_NAME = 2, - READ_NAME = 3, - UNKNOWN_OID = 4 - } state_t; - - u_char oid_len_buf[3]; - u_char name_len_buf[3]; - u_char rdn_seq_len_buf[3]; - u_char rdn_set_len_buf[3]; - u_char dn_seq_len_buf[3]; - - chunk_t asn1_oid_len = { oid_len_buf, 0 }; - chunk_t asn1_name_len = { name_len_buf, 0 }; - chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 }; - chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 }; - chunk_t asn1_dn_seq_len = { dn_seq_len_buf, 0 }; - chunk_t oid = chunk_empty; - chunk_t name = chunk_empty; - - int whitespace = 0; - int rdn_seq_len = 0; - int rdn_set_len = 0; - int dn_seq_len = 0; - int pos = 0; - - err_t ugh = NULL; - - u_char *dn_ptr = dn->ptr + 4; - - state_t state = SEARCH_OID; - - do - { - switch (state) - { - case SEARCH_OID: - if (*src != ' ' && *src != '/' && *src != ',') - { - oid.ptr = src; - oid.len = 1; - state = READ_OID; - } - break; - case READ_OID: - if (*src != ' ' && *src != '=') - { - oid.len++; - } - else - { - for (pos = 0; pos < X501_RDN_ROOF; pos++) - { - if (strlen(x501rdns[pos].name) == oid.len && - strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0) - { - break; /* found a valid OID */ - } - } - if (pos == X501_RDN_ROOF) - { - ugh = "unknown OID in distinguished name"; - state = UNKNOWN_OID; - break; - } - code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len); - - /* reset oid and change state */ - oid = chunk_empty; - state = SEARCH_NAME; - } - break; - case SEARCH_NAME: - if (*src != ' ' && *src != '=') - { - name.ptr = src; - name.len = 1; - whitespace = 0; - state = READ_NAME; - } - break; - case READ_NAME: - if (*src != ',' && *src != '/' && *src != '\0') - { - name.len++; - if (*src == ' ') - { - whitespace++; - } - else - { - whitespace = 0; - } - } - else - { - name.len -= whitespace; - code_asn1_length(name.len, &asn1_name_len); - - /* compute the length of the relative distinguished name sequence */ - rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len + - 1 + asn1_name_len.len + name.len; - code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len); - - /* compute the length of the relative distinguished name set */ - rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len; - code_asn1_length(rdn_set_len, &asn1_rdn_set_len); - - /* encode the relative distinguished name */ - *dn_ptr++ = ASN1_SET; - chunkcpy(dn_ptr, asn1_rdn_set_len); - *dn_ptr++ = ASN1_SEQUENCE; - chunkcpy(dn_ptr, asn1_rdn_seq_len); - *dn_ptr++ = ASN1_OID; - chunkcpy(dn_ptr, asn1_oid_len); - chunkcpy(dn_ptr, x501rdns[pos].oid); - /* encode the ASN.1 character string type of the name */ - *dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING - && !asn1_is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type; - chunkcpy(dn_ptr, asn1_name_len); - chunkcpy(dn_ptr, name); - - /* accumulate the length of the distinguished name sequence */ - dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len; - - /* reset name and change state */ - name = chunk_empty; - state = SEARCH_OID; - } - break; - case UNKNOWN_OID: - break; - } - } while (*src++ != '\0'); - - /* complete the distinguished name sequence*/ - code_asn1_length(dn_seq_len, &asn1_dn_seq_len); - dn->ptr += 3 - asn1_dn_seq_len.len; - dn->len = 1 + asn1_dn_seq_len.len + dn_seq_len; - dn_ptr = dn->ptr; - *dn_ptr++ = ASN1_SEQUENCE; - chunkcpy(dn_ptr, asn1_dn_seq_len); - return ugh; -} - -/** - * compare two distinguished names by comparing the individual RDNs - */ -bool same_dn(chunk_t a, chunk_t b) -{ - chunk_t rdn_a, rdn_b, attribute_a, attribute_b; - chunk_t oid_a, oid_b, value_a, value_b; - asn1_t type_a, type_b; - bool next_a, next_b; - - /* same lengths for the DNs */ - if (a.len != b.len) - { - return FALSE; - } - - /* try a binary comparison first */ - if (memeq(a.ptr, b.ptr, b.len)) - { - return TRUE; - } - - /* initialize DN parsing */ - if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL - || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL) - { - return FALSE; - } - - /* fetch next RDN pair */ - while (next_a && next_b) - { - /* parse next RDNs and check for errors */ - if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL - || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL) - { - return FALSE; - } - - /* OIDs must agree */ - if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) - { - return FALSE; - } - - /* same lengths for values */ - if (value_a.len != value_b.len) - { - return FALSE; - } - - /* printableStrings and email RDNs require uppercase comparison */ - if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || - (type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL))) - { - if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) - { - return FALSE; - } - } - else - { - if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) - { - return FALSE; - } - } - } - /* both DNs must have same number of RDNs */ - if (next_a || next_b) - { - return FALSE; - } - - /* the two DNs are equal! */ - return TRUE; -} - - -/** - * Compare two distinguished names by comparing the individual RDNs. - * A single'*' character designates a wildcard RDN in DN b. - */ -bool match_dn(chunk_t a, chunk_t b, int *wildcards) -{ - chunk_t rdn_a, rdn_b, attribute_a, attribute_b; - chunk_t oid_a, oid_b, value_a, value_b; - asn1_t type_a, type_b; - bool next_a, next_b; - - /* initialize wildcard counter */ - *wildcards = 0; - - /* initialize DN parsing */ - if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL - || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL) - { - return FALSE; - } - - /* fetch next RDN pair */ - while (next_a && next_b) - { - /* parse next RDNs and check for errors */ - if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL - || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL) - { - return FALSE; - } - - /* OIDs must agree */ - if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) - { - return FALSE; - } - - /* does rdn_b contain a wildcard? */ - if (value_b.len == 1 && *value_b.ptr == '*') - { - (*wildcards)++; - continue; - } - - /* same lengths for values */ - if (value_a.len != value_b.len) - { - return FALSE; - } - - /* printableStrings and email RDNs require uppercase comparison */ - if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || - (type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL))) - { - if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) - { - return FALSE; - } - } - else - { - if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) - { - return FALSE; - } - } - } - - /* both DNs must have same number of RDNs */ - if (next_a || next_b) - { - return FALSE; - } - - /* the two DNs match! */ - return TRUE; -} - -/** - * Compare two X.509 certificates by comparing their signatures - */ -bool same_x509cert(const x509cert_t *a, const x509cert_t *b) -{ - return chunk_equals(a->signature, b->signature); -} - -/** - * For each link pointing to the certificate increase the count by one - */ -void share_x509cert(x509cert_t *cert) -{ - if (cert != NULL) - { - cert->count++; - } -} - -/** - * Add a X.509 user/host certificate to the chained list - */ -x509cert_t* add_x509cert(x509cert_t *cert) -{ - x509cert_t *c = x509certs; - - while (c != NULL) - { - if (same_x509cert(c, cert)) /* already in chain, free cert */ - { - free_x509cert(cert); - return c; - } - c = c->next; - } - - /* insert new cert at the root of the chain */ - lock_certs_and_keys("add_x509cert"); - cert->next = x509certs; - x509certs = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" x509 cert inserted") - ) - unlock_certs_and_keys("add_x509cert"); - return cert; -} - -/** - * Choose either subject DN or a subjectAltName as connection end ID - */ -void select_x509cert_id(x509cert_t *cert, struct id *end_id) -{ - bool copy_subject_dn = TRUE; /* ID is subject DN */ - - if (end_id->kind != ID_ANY) /* check for matching subjectAltName */ - { - generalName_t *gn = cert->subjectAltName; - - while (gn != NULL) - { - struct id id = empty_id; - - gntoid(&id, gn); - if (same_id(&id, end_id)) - { - copy_subject_dn = FALSE; /* take subjectAltName instead */ - break; - } - gn = gn->next; - } - } - - if (copy_subject_dn) - { - if (end_id->kind != ID_ANY && end_id->kind != ID_DER_ASN1_DN) - { - char buf[BUF_LEN]; - - idtoa(end_id, buf, BUF_LEN); - plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf); - } - end_id->kind = ID_DER_ASN1_DN; - end_id->name.len = cert->subject.len; - end_id->name.ptr = temporary_cyclic_buffer(); - memcpy(end_id->name.ptr, cert->subject.ptr, cert->subject.len); - } -} - -/** * Check for equality between two key identifiers */ bool same_keyid(chunk_t a, chunk_t b) @@ -1050,271 +55,118 @@ bool same_keyid(chunk_t a, chunk_t b) } /** - * Check for equality between two serial numbers - */ -bool same_serial(chunk_t a, chunk_t b) -{ - /* do not compare serial numbers if one of them is not defined */ - if (a.ptr == NULL || b.ptr == NULL) - { - return TRUE; - } - return chunk_equals(a, b); -} - -/** - * Get a X.509 certificate with a given issuer found at a certain position - */ -x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, - x509cert_t *chain) -{ - x509cert_t *cert = (chain != NULL)? chain->next : x509certs; - - while (cert != NULL) - { - if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->authKeyID) - : (same_dn(issuer, cert->issuer) - && same_serial(serial, cert->authKeySerialNumber))) - { - return cert; - } - cert = cert->next; - } - return NULL; -} - -/** - * Encode a linked list of subjectAltNames - */ -chunk_t build_subjectAltNames(generalName_t *subjectAltNames) -{ - u_char *pos; - chunk_t names; - size_t len = 0; - generalName_t *gn = subjectAltNames; - - /* compute the total size of the ASN.1 attributes object */ - while (gn != NULL) - { - len += gn->name.len; - gn = gn->next; - } - - pos = asn1_build_object(&names, ASN1_SEQUENCE, len); - - gn = subjectAltNames; - while (gn != NULL) - { - chunkcpy(pos, gn->name); - gn = gn->next; - } - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_subjectAltName_oid - , asn1_wrap(ASN1_OCTET_STRING, "m", names)); -} - -/** - * Build a to-be-signed X.509 certificate body - */ -static chunk_t build_tbs_x509cert(x509cert_t *cert, public_key_t *rsa) -{ - /* version is always X.509v3 */ - chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2); - - chunk_t extensions = chunk_empty; - - chunk_t key = rsa->get_encoding(rsa); - - chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm", - asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), - asn1_bitstring("m", key)); - - if (cert->subjectAltName != NULL) - { - extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m" - , asn1_wrap(ASN1_SEQUENCE, "m" - , build_subjectAltNames(cert->subjectAltName))); - } - - return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm" - , version - , asn1_integer("c", cert->serialNumber) - , asn1_algorithmIdentifier(cert->sigAlg) - , cert->issuer - , asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_from_time(&cert->notBefore, ASN1_UTCTIME) - , asn1_from_time(&cert->notAfter, ASN1_UTCTIME) - ) - , cert->subject - , keyInfo - , extensions - ); -} - -/** - * Build a DER-encoded X.509 certificate - */ -void build_x509cert(x509cert_t *cert, public_key_t *cert_key, - private_key_t *signer_key) -{ - chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key); - - chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg - , signer_key, TRUE); - - cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm" - , tbs_cert - , asn1_algorithmIdentifier(cert->sigAlg) - , signature); -} - -/** - * Free the dynamic memory used to store generalNames - */ -void free_generalNames(generalName_t* gn, bool free_name) -{ - while (gn != NULL) - { - generalName_t *gn_top = gn; - if (free_name) - { - free(gn->name.ptr); - } - gn = gn->next; - free(gn_top); - } -} - -/** - * Free a X.509 certificate - */ -void free_x509cert(x509cert_t *cert) -{ - if (cert != NULL) - { - DESTROY_IF(cert->public_key); - free_generalNames(cert->subjectAltName, FALSE); - free_generalNames(cert->crlDistributionPoints, FALSE); - free(cert->certificate.ptr); - free(cert); - cert = NULL; - } -} - -/** - * Release of a certificate decreases the count by one - * the certificate is freed when the counter reaches zero - */ -void release_x509cert(x509cert_t *cert) -{ - if (cert != NULL && --cert->count == 0) - { - x509cert_t **pp = &x509certs; - while (*pp != cert) - { - pp = &(*pp)->next; - } - *pp = cert->next; - free_x509cert(cert); - } -} - -/** * Stores a chained list of end certs and CA certs */ -void store_x509certs(x509cert_t **firstcert, bool strict) +void store_x509certs(linked_list_t *certs, bool strict) { - x509cert_t *cacerts = NULL; - x509cert_t **pp = firstcert; + cert_t *x509cert, *cacerts = NULL; + certificate_t *cert; + enumerator_t *enumerator; - /* first extract CA certs, discarding root CA certs */ + /* first extract CA certs, ignoring self-signed root CA certs */ - while (*pp != NULL) + enumerator = certs->create_enumerator(certs); + while (enumerator->enumerate(enumerator, &cert)) { - x509cert_t *cert = *pp; + x509_t *x509 = (x509_t*)cert; + x509_flag_t flags; - if (cert->isCA) + flags = x509->get_flags(x509); + if (flags & X509_CA) { - *pp = cert->next; - /* we don't accept self-signed CA certs */ - if (same_dn(cert->issuer, cert->subject)) + if (flags & X509_SELF_SIGNED) { plog("self-signed cacert rejected"); - free_x509cert(cert); } else { /* insertion into temporary chain of candidate CA certs */ - cert->next = cacerts; - cacerts = cert; + x509cert = malloc_thing(cert_t); + *x509cert = cert_empty; + x509cert->cert = cert->get_ref(cert); + x509cert->next = cacerts; + cacerts = x509cert; } } - else - { - pp = &cert->next; - } } + enumerator->destroy(enumerator); /* now verify the candidate CA certs */ - - while (cacerts != NULL) + + while (cacerts) { - x509cert_t *cert = cacerts; - + cert_t *cert = cacerts; + cacerts = cacerts->next; if (trust_authcert_candidate(cert, cacerts)) { - add_authcert(cert, AUTH_CA); + add_authcert(cert, X509_CA); } else { plog("intermediate cacert rejected"); - free_x509cert(cert); + cert_free(cert); } } - - /* now verify the end certificates */ - pp = firstcert; + /* now verify the end certificates */ - while (*pp != NULL) + enumerator = certs->create_enumerator(certs); + while (enumerator->enumerate(enumerator, &cert)) { time_t valid_until; - x509cert_t *cert = *pp; + x509_t *x509 = (x509_t*)cert; - if (verify_x509cert(cert, strict, &valid_until)) + if (!(x509->get_flags(x509) & X509_CA)) { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("public key validated") - ) - add_x509_public_key(cert, valid_until, DAL_SIGNED); - } - else - { - plog("X.509 certificate rejected"); + x509cert = malloc_thing(cert_t); + *x509cert = cert_empty; + x509cert->cert = cert->get_ref(cert); + + if (verify_x509cert(x509cert, strict, &valid_until)) + { + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log("public key validated") + ) + add_public_key_from_cert(x509cert, valid_until, DAL_SIGNED); + } + else + { + plog("X.509 certificate rejected"); + cert_free(x509cert); + } } - *pp = cert->next; - free_x509cert(cert); } + enumerator->destroy(enumerator); } /** * Check if a signature over binary blob is genuine */ bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, - const x509cert_t *issuer_cert) + certificate_t *issuer_cert) { - public_key_t *key = issuer_cert->public_key; - signature_scheme_t scheme = signature_scheme_from_oid(algorithm); + bool success; + public_key_t *key; + signature_scheme_t scheme; + scheme = signature_scheme_from_oid(algorithm); if (scheme == SIGN_UNKNOWN) { return FALSE; } - return key->verify(key, scheme, tbs, sig); + + key = issuer_cert->get_public_key(issuer_cert); + if (key == NULL) + { + return FALSE; + } + success = key->verify(key, scheme, tbs, sig); + key->destroy(key); + + return success; } /** @@ -1329,631 +181,58 @@ chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, if (scheme == SIGN_UNKNOWN || !key->sign(key, scheme, tbs, &signature)) { return chunk_empty; - } + } return (bit_string) ? asn1_bitstring("m", signature) : asn1_wrap(ASN1_OCTET_STRING, "m", signature); } /** - * Extracts the basicConstraints extension - */ -static bool parse_basicConstraints(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool isCA = FALSE; - - parser = asn1_parser_create(basicConstraintsObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == BASIC_CONSTRAINTS_CA) - { - isCA = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(isCA)?"TRUE":"FALSE"); - ) - } - } - parser->destroy(parser); - - return isCA; -} - -/** - * Converts a X.500 generalName into an ID - */ -void gntoid(struct id *id, const generalName_t *gn) -{ - switch(gn->kind) - { - case GN_DNS_NAME: /* ID type: ID_FQDN */ - id->kind = ID_FQDN; - id->name = gn->name; - break; - case GN_IP_ADDRESS: /* ID type: ID_IPV4_ADDR */ - { - const struct af_info *afi = &af_inet4_info; - err_t ugh = NULL; - - id->kind = afi->id_addr; - ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr); - } - break; - case GN_RFC822_NAME: /* ID type: ID_USER_FQDN */ - id->kind = ID_USER_FQDN; - id->name = gn->name; - break; - default: - id->kind = ID_ANY; - id->name = chunk_empty; - } -} - -/** - * Compute the subjectKeyIdentifier according to section 4.2.1.2 of RFC 3280 - * as the 160 bit SHA-1 hash of the public key - */ -bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID) -{ - identification_t *keyid; - chunk_t encoding; - - keyid = cert->public_key->get_id(cert->public_key, ID_PUBKEY_SHA1); - if (keyid == NULL) - { - plog(" unable to compute subjectKeyID"); - return FALSE; - } - encoding = keyid->get_encoding(keyid); - memcpy(subjectKeyID.ptr, encoding.ptr, subjectKeyID.len); - return TRUE; -} - -/** - * Extracts an otherName - */ -static bool parse_otherName(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - int oid = OID_UNKNOWN; - bool success = FALSE; - - parser = asn1_parser_create(otherNameObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case ON_OBJ_ID_TYPE: - oid = asn1_known_oid(object); - break; - case ON_OBJ_VALUE: - if (oid == OID_XMPP_ADDR) - { - if (!asn1_parse_simple_object(&object, ASN1_UTF8STRING, - parser->get_level(parser) + 1, "xmppAddr")) - { - goto end; - } - } - break; - default: - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; -} - - -/** - * Extracts a generalName - */ -static generalName_t* parse_generalName(chunk_t blob, int level0) -{ - u_char buf[BUF_LEN]; - asn1_parser_t *parser; - chunk_t object; - generalName_t *gn = NULL; - int objectID; - - parser = asn1_parser_create(generalNameObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - bool valid_gn = FALSE; - - switch (objectID) { - case GN_OBJ_RFC822_NAME: - case GN_OBJ_DNS_NAME: - case GN_OBJ_URI: - DBG(DBG_PARSING, - DBG_log(" '%.*s'", (int)object.len, object.ptr); - ) - valid_gn = TRUE; - break; - case GN_OBJ_DIRECTORY_NAME: - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'", buf) - ) - valid_gn = TRUE; - break; - case GN_OBJ_IP_ADDRESS: - DBG(DBG_PARSING, - DBG_log(" '%d.%d.%d.%d'", *object.ptr, *(object.ptr+1), - *(object.ptr+2), *(object.ptr+3)); - ) - valid_gn = TRUE; - break; - case GN_OBJ_OTHER_NAME: - if (!parse_otherName(object, parser->get_level(parser)+1)) - { - goto end; - } - break; - case GN_OBJ_X400_ADDRESS: - case GN_OBJ_EDI_PARTY_NAME: - case GN_OBJ_REGISTERED_ID: - break; - default: - break; - } - - if (valid_gn) - { - gn = malloc_thing(generalName_t); - gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2; - gn->name = object; - gn->next = NULL; - goto end; - } - } - -end: - parser->destroy(parser); - return gn; -} - -/** - * Extracts one or several GNs and puts them into a chained list - */ -static generalName_t* parse_generalNames(chunk_t blob, int level0, bool implicit) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - generalName_t *top_gn = NULL; - - parser = asn1_parser_create(generalNamesObjects, blob); - parser->set_top_level(parser, level0); - parser->set_flags(parser, implicit, FALSE); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == GENERAL_NAMES_GN) - { - generalName_t *gn = parse_generalName(object, - parser->get_level(parser)+1); - if (gn) - { - gn->next = top_gn; - top_gn = gn; - } - } - } - parser->destroy(parser); - - return top_gn; -} - -/** - * Returns a directoryName - */ -chunk_t get_directoryName(chunk_t blob, int level, bool implicit) -{ - chunk_t name = chunk_empty; - generalName_t * gn = parse_generalNames(blob, level, implicit); - - if (gn != NULL && gn->kind == GN_DIRECTORY_NAME) - { - name= gn->name; - } - free_generalNames(gn, FALSE); - return name; -} - -/** - * Extracts an authoritykeyIdentifier - */ -void parse_authorityKeyIdentifier(chunk_t blob, int level0, - chunk_t *authKeyID, - chunk_t *authKeySerialNumber) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(authKeyIdentifierObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case AUTH_KEY_ID_KEY_ID: - *authKeyID = object; - break; - case AUTH_KEY_ID_CERT_ISSUER: - { - generalName_t * gn = parse_generalNames(object, - parser->get_level(parser) + 1, TRUE); - - free_generalNames(gn, FALSE); - } - break; - case AUTH_KEY_ID_CERT_SERIAL: - *authKeySerialNumber = object; - break; - default: - break; - } - } - parser->destroy(parser); -} - -/** - * Extracts an authorityInfoAcess location - */ -static void parse_authorityInfoAccess(chunk_t blob, int level0, - chunk_t *accessLocation) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - int accessMethod = OID_UNKNOWN; - - parser = asn1_parser_create(authInfoAccessObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case AUTH_INFO_ACCESS_METHOD: - accessMethod = asn1_known_oid(object); - break; - case AUTH_INFO_ACCESS_LOCATION: - { - switch (accessMethod) - { - case OID_OCSP: - if (*object.ptr == ASN1_CONTEXT_S_6) - { - if (asn1_length(&object) == ASN1_INVALID_LENGTH) - { - goto end; - } - DBG(DBG_PARSING, - DBG_log(" '%.*s'",(int)object.len, object.ptr) - ) - - /* only HTTP(S) URIs accepted */ - if (strncasecmp(object.ptr, "http", 4) == 0) - { - *accessLocation = object; - goto end; - } - } - plog("warning: ignoring OCSP InfoAccessLocation with unkown protocol"); - break; - default: - /* unkown accessMethod, ignoring */ - break; - } - } - break; - default: - break; - } - } - -end: - parser->destroy(parser); -} - -/** - * Extracts extendedKeyUsage OIDs - */ -static bool parse_extendedKeyUsage(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool ocsp_signing = FALSE; - - parser = asn1_parser_create(extendedKeyUsageObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == EXT_KEY_USAGE_PURPOSE_ID - && asn1_known_oid(object) == OID_OCSP_SIGNING) - { - ocsp_signing = TRUE; - } - } - parser->destroy(parser); - - return ocsp_signing; -} - -/** - * Extracts one or several crlDistributionPoints - * and puts them into a chained list - */ -static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - generalName_t *top_gn = NULL; /* top of the chained list */ - generalName_t **tail_gn = &top_gn; /* tail of the chained list */ - - parser = asn1_parser_create(crlDistributionPointsObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == CRL_DIST_POINTS_FULLNAME) - { - generalName_t *gn; - - gn = parse_generalNames(object, parser->get_level(parser)+1, TRUE); - /* append extracted generalNames to existing chained list */ - *tail_gn = gn; - /* find new tail of the chained list */ - while (gn != NULL) - { - tail_gn = &gn->next; gn = gn->next; - } - } - } - parser->destroy(parser); - - return top_gn; -} - -/** - * Parses an X.509v3 certificate - */ -bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert) -{ - u_char buf[BUF_LEN]; - asn1_parser_t *parser; - chunk_t object; - int objectID; - int extn_oid = OID_UNKNOWN; - bool critical; - bool success = FALSE; - - parser = asn1_parser_create(certObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser) + 1; - - switch (objectID) { - case X509_OBJ_CERTIFICATE: - cert->certificate = object; - break; - case X509_OBJ_TBS_CERTIFICATE: - cert->tbsCertificate = object; - break; - case X509_OBJ_VERSION: - cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG(DBG_PARSING, - DBG_log(" v%d", cert->version); - ) - break; - case X509_OBJ_SERIAL_NUMBER: - cert->serialNumber = object; - break; - case X509_OBJ_SIG_ALG: - cert->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case X509_OBJ_ISSUER: - cert->issuer = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case X509_OBJ_NOT_BEFORE: - cert->notBefore = asn1_parse_time(object, level); - break; - case X509_OBJ_NOT_AFTER: - cert->notAfter = asn1_parse_time(object, level); - break; - case X509_OBJ_SUBJECT: - cert->subject = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO: - cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, - KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); - if (cert->public_key == NULL) - { - goto end; - } - break; - case X509_OBJ_EXTN_ID: - extn_oid = asn1_known_oid(object); - break; - case X509_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case X509_OBJ_EXTN_VALUE: - { - switch (extn_oid) { - case OID_SUBJECT_KEY_ID: - if (!asn1_parse_simple_object(&object, ASN1_OCTET_STRING, - level, "keyIdentifier")) - { - goto end; - } - cert->subjectKeyID = object; - break; - case OID_SUBJECT_ALT_NAME: - cert->subjectAltName = - parse_generalNames(object, level, FALSE); - break; - case OID_BASIC_CONSTRAINTS: - cert->isCA = - parse_basicConstraints(object, level); - break; - case OID_CRL_DISTRIBUTION_POINTS: - cert->crlDistributionPoints = - parse_crlDistributionPoints(object, level); - break; - case OID_AUTHORITY_KEY_ID: - parse_authorityKeyIdentifier(object, level - , &cert->authKeyID, &cert->authKeySerialNumber); - break; - case OID_AUTHORITY_INFO_ACCESS: - parse_authorityInfoAccess(object, level, &cert->accessLocation); - break; - case OID_EXTENDED_KEY_USAGE: - cert->isOcspSigner = parse_extendedKeyUsage(object, level); - break; - case OID_NS_REVOCATION_URL: - case OID_NS_CA_REVOCATION_URL: - case OID_NS_CA_POLICY_URL: - case OID_NS_COMMENT: - if (!asn1_parse_simple_object(&object, ASN1_IA5STRING - , level, oid_names[extn_oid].name)) - { - goto end; - } - break; - default: - break; - } - } - break; - case X509_OBJ_ALGORITHM: - cert->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case X509_OBJ_SIGNATURE: - cert->signature = object; - break; - default: - break; - } - } - success = parser->success(parser); - time(&cert->installed); - -end: - parser->destroy(parser); - return success; -} - -/** - * Verify the validity of a certificate by - * checking the notBefore and notAfter dates - */ -err_t check_validity(const x509cert_t *cert, time_t *until) -{ - time_t current_time; - - time(¤t_time); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" not before : %T", &cert->notBefore, TRUE); - DBG_log(" current time: %T", ¤t_time, TRUE); - DBG_log(" not after : %T", &cert->notAfter, TRUE); - ) - - if (cert->notAfter < *until) - { - *until = cert->notAfter; - } - if (current_time < cert->notBefore) - { - return "certificate is not valid yet"; - } - if (current_time > cert->notAfter) - { - return "certificate has expired"; - } - else - { - return NULL; - } -} - -/** * Verifies a X.509 certificate */ -bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) +bool verify_x509cert(cert_t *cert, bool strict, time_t *until) { - int pathlen; + int pathlen, pathlen_constraint; - *until = cert->notAfter; + *until = 0; - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) + for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) { - x509cert_t *issuer_cert; - u_char buf[BUF_LEN]; - err_t ugh = NULL; + certificate_t *certificate = cert->cert; + identification_t *subject = certificate->get_subject(certificate); + identification_t *issuer = certificate->get_issuer(certificate); + x509_t *x509 = (x509_t*)certificate; + chunk_t authKeyID = x509->get_authKeyIdentifier(x509); + cert_t *issuer_cert; + time_t notBefore, notAfter; + bool valid; DBG(DBG_CONTROL, - 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) + DBG_log("subject: '%Y'", subject); + DBG_log("issuer: '%Y'", issuer); + if (authKeyID.ptr) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); + DBG_log("authkey: %#B", &authKeyID); } ) - ugh = check_validity(cert, until); - - if (ugh != NULL) + valid = certificate->get_validity(certificate, NULL, + ¬Before, ¬After); + if (*until == UNDEFINED_TIME || notAfter < *until) { - plog("%s", ugh); + *until = notAfter; + } + if (!valid) + { + plog("certificate is invalid (valid from %T to %T)", + ¬Before, FALSE, ¬After, FALSE); return FALSE; } - DBG(DBG_CONTROL, DBG_log("certificate is valid") ) lock_authcert_list("verify_x509cert"); - issuer_cert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); - + issuer_cert = get_authcert(issuer, authKeyID, X509_CA); if (issuer_cert == NULL) { plog("issuer cacert not found"); @@ -1964,8 +243,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) DBG_log("issuer cacert found") ) - if (!x509_check_signature(cert->tbsCertificate, cert->signature, - cert->algorithm, issuer_cert)) + if (!certificate->issued_by(certificate, issuer_cert->cert)) { plog("certificate signature is invalid"); unlock_authcert_list("verify_x509cert"); @@ -1976,11 +254,22 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) ) unlock_authcert_list("verify_x509cert"); + /* check path length constraint */ + pathlen_constraint = x509->get_pathLenConstraint(x509); + if (pathlen_constraint != X509_NO_PATH_LEN_CONSTRAINT && + pathlen > pathlen_constraint) + { + plog("path length of %d violates constraint of %d", + pathlen, pathlen_constraint); + return FALSE; + } + /* check if cert is a self-signed root ca */ - if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) + if (pathlen >= 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) { DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") + DBG_log("reached self-signed root ca with a path length of %d", + pathlen) ) return TRUE; } @@ -1988,7 +277,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) { time_t nextUpdate = *until; time_t revocationDate = UNDEFINED_TIME; - crl_reason_t revocationReason = REASON_UNSPECIFIED; + crl_reason_t revocationReason = CRL_REASON_UNSPECIFIED; /* first check certificate revocation using ocsp */ cert_status_t status = verify_by_ocsp(cert, &nextUpdate @@ -2017,7 +306,7 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) DBG(DBG_CONTROL, DBG_log("certificate is good") ) - + /* with strict crl policy the public key must have the same * lifetime as the validity of the ocsp status or crl lifetime */ @@ -2048,15 +337,15 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) /* go up one step in the trust chain */ cert = issuer_cert; } - plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); return FALSE; } /** * List all X.509 certs in a chained list */ -void list_x509cert_chain(const char *caption, x509cert_t* cert, - u_char auth_flags, bool utc) +void list_x509cert_chain(const char *caption, cert_t* cert, + x509_flag_t flags, bool utc) { bool first = TRUE; time_t now; @@ -2064,74 +353,107 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert, /* determine the current time */ time(&now); - while (cert != NULL) + while (cert) { - if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) - { - u_char buf[BUF_LEN]; - public_key_t *key = cert->public_key; - cert_t c; + certificate_t *certificate = cert->cert; + x509_t *x509 = (x509_t*)certificate; - c.type = CERT_X509_SIGNATURE; - c.u.x509 = cert; + if (certificate->get_type(certificate) == CERT_X509 && + (flags == X509_NONE || (flags & x509->get_flags(x509)))) + { + enumerator_t *enumerator; + char buf[BUF_LEN]; + char *pos = buf; + int len = BUF_LEN, pathlen; + bool first_altName = TRUE; + identification_t *id; + time_t notBefore, notAfter; + public_key_t *key; + chunk_t serial, keyid, subjkey, authkey; if (first) { whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption); - whack_log(RC_COMMENT, " "); first = FALSE; } + whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, - cert->count); - dntoa(buf, BUF_LEN, cert->subject); - whack_log(RC_COMMENT, " subject: '%s'", buf); - dntoa(buf, BUF_LEN, cert->issuer); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':', - buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s", buf); - whack_log(RC_COMMENT, " validity: not before %T %s", - &cert->notBefore, utc, - (cert->notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %T %s", - &cert->notAfter, utc, - check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); - whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", - key_type_names, key->get_type(key), - key->get_keysize(key) * BITS_PER_BYTE, - cert->smartcard ? ", on smartcard" : - (has_private_key(c)? ", has private key" : "")); - whack_log(RC_COMMENT, " keyid: %Y", - key->get_id(key, ID_PUBKEY_INFO_SHA1)); - if (cert->subjectKeyID.ptr != NULL) + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, &id)) { - datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':', - buf, BUF_LEN); - whack_log(RC_COMMENT, " subjkey: %s", buf); + int written; + + if (first_altName) + { + written = snprintf(pos, len, "%Y", id); + first_altName = FALSE; + } + else + { + written = snprintf(pos, len, ", %Y", id); + } + pos += written; + len -= written; + } + enumerator->destroy(enumerator); + if (!first_altName) + { + whack_log(RC_COMMENT, " altNames: %s", buf); + } + + whack_log(RC_COMMENT, " subject: \"%Y\"", + certificate->get_subject(certificate)); + whack_log(RC_COMMENT, " issuer: \"%Y\"", + certificate->get_issuer(certificate)); + serial = x509->get_serial(x509); + whack_log(RC_COMMENT, " serial: %#B", &serial); + + /* list validity */ + certificate->get_validity(certificate, &now, ¬Before, ¬After); + whack_log(RC_COMMENT, " validity: not before %T %s", + ¬Before, utc, + (notBefore < now)?"ok":"fatal (not valid yet)"); + whack_log(RC_COMMENT, " not after %T %s", + ¬After, utc, + check_expiry(notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); + + key = certificate->get_public_key(certificate); + if (key); + { + whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", + key_type_names, key->get_type(key), + key->get_keysize(key) * BITS_PER_BYTE, + cert->smartcard ? ", on smartcard" : + (has_private_key(cert)? ", has private key" : "")); + + if (key->get_fingerprint(key, KEY_ID_PUBKEY_INFO_SHA1, &keyid)) + { + whack_log(RC_COMMENT, " keyid: %#B", &keyid); + } + if (key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &subjkey)) + { + whack_log(RC_COMMENT, " subjkey: %#B", &subjkey); + } + key->destroy(key); } - if (cert->authKeyID.ptr != NULL) + + /* list optional authorityKeyIdentifier */ + authkey = x509->get_authKeyIdentifier(x509); + if (authkey.ptr) { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':', - buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " authkey: %#B", &authkey); } - if (cert->authKeySerialNumber.ptr != NULL) + + /* list optional pathLenConstraint */ + pathlen = x509->get_pathLenConstraint(x509); + if (pathlen != X509_NO_PATH_LEN_CONSTRAINT) { - datatot(cert->authKeySerialNumber.ptr, - cert->authKeySerialNumber.len, ':', buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + whack_log(RC_COMMENT, " pathlen: %d", pathlen); } + } cert = cert->next; } } -/** - * List all X.509 end certificates in a chained list - */ -void list_x509_end_certs(bool utc) -{ - list_x509cert_chain("End", x509certs, AUTH_NONE, utc); -} diff --git a/src/pluto/x509.h b/src/pluto/x509.h index ab0fbac9e..e904618b3 100644 --- a/src/pluto/x509.h +++ b/src/pluto/x509.h @@ -18,122 +18,23 @@ #ifndef _X509_H #define _X509_H -#include <credentials/keys/public_key.h> +#include <utils/identification.h> +#include <utils/linked_list.h> #include <credentials/keys/private_key.h> +#include <credentials/certificates/x509.h> #include "constants.h" -#include "id.h" +#include "certs.h" -/* Definition of generalNames kinds */ - -typedef enum { - GN_OTHER_NAME = 0, - GN_RFC822_NAME = 1, - GN_DNS_NAME = 2, - GN_X400_ADDRESS = 3, - GN_DIRECTORY_NAME = 4, - GN_EDI_PARTY_NAME = 5, - GN_URI = 6, - GN_IP_ADDRESS = 7, - GN_REGISTERED_ID = 8 -} generalNames_t; - -/* access structure for a GeneralName */ - -typedef struct generalName generalName_t; - -struct generalName { - generalName_t *next; - generalNames_t kind; - chunk_t name; -}; - -/* access structure for an X.509v3 certificate */ - -typedef struct x509cert x509cert_t; - -struct x509cert { - x509cert_t *next; - time_t installed; - int count; - bool smartcard; - u_char authority_flags; - chunk_t certificate; - chunk_t tbsCertificate; - u_int version; - chunk_t serialNumber; - /* signature */ - int sigAlg; - chunk_t issuer; - /* validity */ - time_t notBefore; - time_t notAfter; - chunk_t subject; - public_key_t *public_key; - /* issuerUniqueID */ - /* subjectUniqueID */ - /* v3 extensions */ - /* extension */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - bool isCA; - bool isOcspSigner; /* ocsp */ - chunk_t subjectKeyID; - chunk_t authKeyID; - chunk_t authKeySerialNumber; - chunk_t accessLocation; /* ocsp */ - generalName_t *subjectAltName; - generalName_t *crlDistributionPoints; - /* signatureAlgorithm */ - int algorithm; - chunk_t signature; -}; - -/* used for initialization */ -extern const x509cert_t empty_x509cert; - -extern bool same_serial(chunk_t a, chunk_t b); extern bool same_keyid(chunk_t a, chunk_t b); -extern bool same_dn(chunk_t a, chunk_t b); -extern bool match_dn(chunk_t a, chunk_t b, int *wildcards); -extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b); -extern void hex_str(chunk_t bin, chunk_t *str); -extern int dn_count_wildcards(chunk_t dn); -extern int dntoa(char *dst, size_t dstlen, chunk_t dn); -extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, - const char* null_dn); -extern err_t atodn(char *src, chunk_t *dn); -extern void gntoid(struct id *id, const generalName_t *gn); -extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID); -extern void select_x509cert_id(x509cert_t *cert, struct id *end_id); -extern bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert); -extern time_t parse_time(chunk_t blob, int level0); -extern void parse_authorityKeyIdentifier(chunk_t blob, int level0 - , chunk_t *authKeyID, chunk_t *authKeySerialNumber); -extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit); -extern err_t check_validity(const x509cert_t *cert, time_t *until); - extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, - const x509cert_t *issuer_cert); + certificate_t *issuer_cert); extern chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, bool bit_string); - -extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until); -extern x509cert_t* add_x509cert(x509cert_t *cert); -extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, - x509cert_t* chain); -extern void build_x509cert(x509cert_t *cert, public_key_t *cert_key, - private_key_t *signer_key); -extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames); -extern void share_x509cert(x509cert_t *cert); -extern void release_x509cert(x509cert_t *cert); -extern void free_x509cert(x509cert_t *cert); -extern void store_x509certs(x509cert_t **firstcert, bool strict); -extern void list_x509cert_chain(const char *caption, x509cert_t* cert, - u_char auth_flags, bool utc); +extern bool verify_x509cert(cert_t *cert, bool strict, time_t *until); +extern void store_x509certs(linked_list_t *certs, bool strict); +extern void list_x509cert_chain(const char *caption, cert_t* cert, + x509_flag_t flags, bool utc); extern void list_x509_end_certs(bool utc); -extern void free_generalNames(generalName_t* gn, bool free_name); #endif /* _X509_H */ diff --git a/src/pluto/xauth.c b/src/pluto/xauth.c index af2d72d71..2086a92cc 100644 --- a/src/pluto/xauth.c +++ b/src/pluto/xauth.c @@ -1,7 +1,7 @@ /* Initialization and finalization of the dynamic XAUTH module * Copyright (C) 2006 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 @@ -23,7 +23,7 @@ #include "keys.h" #include "log.h" -void +void xauth_init(void) { #ifdef XAUTH_DEFAULT_LIB diff --git a/src/pluto/xauth.h b/src/pluto/xauth.h index 8ab125ac4..23cae3ed8 100644 --- a/src/pluto/xauth.h +++ b/src/pluto/xauth.h @@ -1,7 +1,7 @@ /* Interface definition of the XAUTH server and|or client module * Copyright (C) 2006 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 |