diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-02-23 10:42:46 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-02-23 10:42:46 +0000 |
commit | de6b12502cdf42d5d92118f1c0e38dc31becf7c5 (patch) | |
tree | 0edac9c79f5a43e01913dd7f71c7abc487e5727b /src/libstrongswan/plugins/x509 | |
parent | 172642669d4a23e17f1ed411fbc8629dcaa5fb46 (diff) | |
download | vyos-strongswan-de6b12502cdf42d5d92118f1c0e38dc31becf7c5.tar.gz vyos-strongswan-de6b12502cdf42d5d92118f1c0e38dc31becf7c5.zip |
Updated to new upstream release. interfaces Patch is not from upstream.
Diffstat (limited to 'src/libstrongswan/plugins/x509')
-rw-r--r-- | src/libstrongswan/plugins/x509/Makefile.am | 4 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/Makefile.in | 153 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/ietf_attr_list.c | 396 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/ietf_attr_list.h | 79 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ac.c | 416 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ac.h | 30 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_cert.c | 1143 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_cert.h | 27 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_crl.c | 233 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_crl.h | 11 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ocsp_request.c | 221 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ocsp_request.h | 12 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ocsp_response.c | 212 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ocsp_response.h | 11 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_pkcs10.c | 707 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_pkcs10.h | 65 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_plugin.c | 41 |
17 files changed, 2120 insertions, 1641 deletions
diff --git a/src/libstrongswan/plugins/x509/Makefile.am b/src/libstrongswan/plugins/x509/Makefile.am index e9668b4e4..853b1cebc 100644 --- a/src/libstrongswan/plugins/x509/Makefile.am +++ b/src/libstrongswan/plugins/x509/Makefile.am @@ -9,8 +9,8 @@ libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \ x509_cert.h x509_cert.c \ x509_crl.h x509_crl.c \ x509_ac.h x509_ac.c \ + x509_pkcs10.h x509_pkcs10.c \ x509_ocsp_request.h x509_ocsp_request.c \ - x509_ocsp_response.h x509_ocsp_response.c \ - ietf_attr_list.h ietf_attr_list.c + x509_ocsp_response.h x509_ocsp_response.c libstrongswan_x509_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/x509/Makefile.in b/src/libstrongswan/plugins/x509/Makefile.in index 56cb04769..428643254 100644 --- a/src/libstrongswan/plugins/x509/Makefile.in +++ b/src/libstrongswan/plugins/x509/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. @@ -16,8 +17,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 @@ -35,24 +37,46 @@ host_triplet = @host@ subdir = src/libstrongswan/plugins/x509 DIST_COMMON = $(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__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 = `echo $$p | sed -e 's|^.*/||'`; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__installdirs = "$(DESTDIR)$(plugindir)" -pluginLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(plugin_LTLIBRARIES) libstrongswan_x509_la_LIBADD = am_libstrongswan_x509_la_OBJECTS = x509_plugin.lo x509_cert.lo \ - x509_crl.lo x509_ac.lo x509_ocsp_request.lo \ - x509_ocsp_response.lo ietf_attr_list.lo + x509_crl.lo x509_ac.lo x509_pkcs10.lo x509_ocsp_request.lo \ + x509_ocsp_response.lo libstrongswan_x509_la_OBJECTS = $(am_libstrongswan_x509_la_OBJECTS) libstrongswan_x509_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -60,6 +84,7 @@ libstrongswan_x509_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ 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) \ @@ -107,25 +132,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@ @@ -137,11 +159,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@ @@ -170,9 +195,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@ @@ -195,7 +220,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@ @@ -203,6 +228,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@ @@ -211,10 +237,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@ @@ -222,6 +250,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@ INCLUDES = -I$(top_srcdir)/src/libstrongswan @@ -231,9 +260,9 @@ libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \ x509_cert.h x509_cert.c \ x509_crl.h x509_crl.c \ x509_ac.h x509_ac.c \ + x509_pkcs10.h x509_pkcs10.c \ x509_ocsp_request.h x509_ocsp_request.c \ - x509_ocsp_response.h x509_ocsp_response.c \ - ietf_attr_list.h ietf_attr_list.c + x509_ocsp_response.h x509_ocsp_response.c libstrongswan_x509_la_LDFLAGS = -module -avoid-version all: all-am @@ -249,9 +278,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libstrongswan/plugins/x509/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/libstrongswan/plugins/x509/Makefile + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libstrongswan/plugins/x509/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libstrongswan/plugins/x509/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -269,23 +298,28 @@ $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" - @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ if test -f $$p; then \ - f=$(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \ + list2="$$list2 $$p"; \ else :; fi; \ - done + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) - @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ - p=$(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \ + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: @@ -305,31 +339,31 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attr_list.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_ac.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_cert.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_crl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_ocsp_request.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_ocsp_response.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_pkcs10.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_plugin.Plo@am__quote@ .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 $@ $< @@ -352,7 +386,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 \ @@ -360,29 +394,34 @@ 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 @@ -403,13 +442,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 @@ -440,6 +483,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" @@ -461,6 +505,8 @@ dvi-am: html: html-am +html-am: + info: info-am info-am: @@ -469,18 +515,28 @@ install-data-am: install-pluginLTLIBRARIES install-dvi: install-dvi-am +install-dvi-am: + install-exec-am: install-html: install-html-am +install-html-am: + install-info: install-info-am +install-info-am: + install-man: install-pdf: install-pdf-am +install-pdf-am: + install-ps: install-ps-am +install-ps-am: + installcheck-am: maintainer-clean: maintainer-clean-am @@ -519,6 +575,7 @@ uninstall-am: uninstall-pluginLTLIBRARIES mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/libstrongswan/plugins/x509/ietf_attr_list.c b/src/libstrongswan/plugins/x509/ietf_attr_list.c deleted file mode 100644 index 17f6949b2..000000000 --- a/src/libstrongswan/plugins/x509/ietf_attr_list.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (C) 2007 Andreas Steffen, Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <string.h> -#include <stdio.h> - -#include <debug.h> -#include <library.h> - -#include <asn1/oid.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <utils/lexparser.h> - -#include "ietf_attr_list.h" - -/** - * Private definition of ietfAttribute kinds - */ -typedef enum { - IETF_ATTRIBUTE_OCTETS = 0, - IETF_ATTRIBUTE_OID = 1, - IETF_ATTRIBUTE_STRING = 2 -} ietfAttribute_t; - -typedef struct ietfAttr_t ietfAttr_t; - -/** - * Private definition of an ietfAttribute - */ -struct ietfAttr_t { - /** - * IETF attribute kind - */ - ietfAttribute_t kind; - - /** - * IETF attribute valuse - */ - chunk_t value; - - /** - * Compares two ietfAttributes - * - * return -1 if this is earlier in the alphabet than other - * return 0 if this equals other - * return +1 if this is later in the alphabet than other - * - * @param this calling object - * @param other other object - */ - int (*compare) (const ietfAttr_t *this ,const ietfAttr_t *other); - - /** - * Destroys the ietfAttr_t object. - * - * @param this ietfAttr_t to destroy - */ - void (*destroy) (ietfAttr_t *this); -}; - -/** - * Implements ietfAttr_t.compare. - */ -static int ietfAttr_compare(const ietfAttr_t *this ,const ietfAttr_t *other) -{ - int cmp_len, len, cmp_value; - - /* OID attributes are appended after STRING and OCTETS attributes */ - if (this->kind != IETF_ATTRIBUTE_OID && other->kind == IETF_ATTRIBUTE_OID) - { - return -1; - } - if (this->kind == IETF_ATTRIBUTE_OID && other->kind != IETF_ATTRIBUTE_OID) - { - return 1; - } - - cmp_len = this->value.len - other->value.len; - len = (cmp_len < 0)? this->value.len : other->value.len; - cmp_value = memcmp(this->value.ptr, other->value.ptr, len); - - return (cmp_value == 0)? cmp_len : cmp_value; -} - -/** - * Implements ietfAttr_t.destroy. - */ -static void ietfAttr_destroy(ietfAttr_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Creates an ietfAttr_t object. - */ -static ietfAttr_t *ietfAttr_create(ietfAttribute_t kind, chunk_t value) -{ - ietfAttr_t *this = malloc_thing(ietfAttr_t); - - /* initialize */ - this->kind = kind; - this->value = chunk_clone(value); - - /* function */ - this->compare = ietfAttr_compare; - this->destroy = ietfAttr_destroy; - - return this; -} - -/** - * Adds an ietfAttr_t object to a sorted linked list - */ -static void ietfAttr_add(linked_list_t *list, ietfAttr_t *attr) -{ - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *current_attr; - bool found = FALSE; - - while (iterator->iterate(iterator, (void **)¤t_attr)) - { - int cmp = attr->compare(attr, current_attr); - - if (cmp > 0) - { - continue; - } - if (cmp == 0) - { - attr->destroy(attr); - } - else - { - iterator->insert_before(iterator, attr); - } - found = TRUE; - break; - } - iterator->destroy(iterator); - if (!found) - { - list->insert_last(list, attr); - } -} - -/* - * Described in header. - */ -bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b) -{ - bool result = TRUE; - - /* lists must have the same number of attributes */ - if (list_a->get_count(list_a) != list_b->get_count(list_b)) - { - return FALSE; - } - /* empty lists - no attributes */ - if (list_a->get_count(list_a) == 0) - { - return TRUE; - } - - /* compare two alphabetically-sorted lists */ - { - iterator_t *iterator_a = list_a->create_iterator(list_a, TRUE); - iterator_t *iterator_b = list_b->create_iterator(list_b, TRUE); - ietfAttr_t *attr_a, *attr_b; - - while (iterator_a->iterate(iterator_a, (void **)&attr_a) && - iterator_b->iterate(iterator_b, (void **)&attr_b)) - { - if (attr_a->compare(attr_a, attr_b) != 0) - { - /* we have a mismatch */ - result = FALSE; - break; - } - } - iterator_a->destroy(iterator_a); - iterator_b->destroy(iterator_b); - } - return result; -} - -/* - * Described in header. - */ -void ietfAttr_list_list(linked_list_t *list, FILE *out) -{ - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *attr; - bool first = TRUE; - - while (iterator->iterate(iterator, (void **)&attr)) - { - if (first) - { - first = FALSE; - } - else - { - fprintf(out, ", "); - } - - switch (attr->kind) - { - case IETF_ATTRIBUTE_OCTETS: - case IETF_ATTRIBUTE_STRING: - fprintf(out, "%.*s", (int)attr->value.len, attr->value.ptr); - break; - case IETF_ATTRIBUTE_OID: - { - int oid = asn1_known_oid(attr->value); - - if (oid == OID_UNKNOWN) - { - fprintf(out, "0x#B", &attr->value); - } - else - { - fprintf(out, "%s", oid_names[oid]); - } - } - break; - default: - break; - } - } - iterator->destroy(iterator); -} - -/* - * Described in header. - */ -void ietfAttr_list_create_from_string(char *msg, linked_list_t *list) -{ - chunk_t line = { msg, strlen(msg) }; - - while (eat_whitespace(&line)) - { - chunk_t group; - - /* extract the next comma-separated group attribute */ - if (!extract_token(&group, ',', &line)) - { - group = line; - line.len = 0; - } - - /* remove any trailing spaces */ - while (group.len > 0 && *(group.ptr + group.len - 1) == ' ') - { - group.len--; - } - - /* add the group attribute to the list */ - if (group.len > 0) - { - ietfAttr_t *attr = ietfAttr_create(IETF_ATTRIBUTE_STRING, group); - - ietfAttr_add(list, attr); - } - } -} - -/** - * 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 - -/* - * Described in header. - */ -void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(ietfAttrSyntaxObjects, chunk); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case IETF_ATTR_OCTETS: - case IETF_ATTR_OID: - case IETF_ATTR_STRING: - { - ietfAttribute_t kind = (objectID - IETF_ATTR_OCTETS) / 2; - ietfAttr_t *attr = ietfAttr_create(kind, object); - ietfAttr_add(list, attr); - } - break; - default: - break; - } - } - parser->destroy(parser); -} - -/* - * Described in header. - */ -chunk_t ietfAttr_list_encode(linked_list_t *list) -{ - chunk_t ietfAttributes; - size_t size = 0; - u_char *pos; - iterator_t *iterator = list->create_iterator(list, TRUE); - ietfAttr_t *attr; - - /* precalculate the total size of all values */ - while (iterator->iterate(iterator, (void **)&attr)) - { - size_t len = attr->value.len; - - size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len; - } - iterator->destroy(iterator); - - pos = asn1_build_object(&ietfAttributes, ASN1_SEQUENCE, size); - - iterator = list->create_iterator(list, TRUE); - while (iterator->iterate(iterator, (void **)&attr)) - { - chunk_t ietfAttribute; - asn1_t type = ASN1_NULL; - - switch (attr->kind) - { - case IETF_ATTRIBUTE_OCTETS: - type = ASN1_OCTET_STRING; - break; - case IETF_ATTRIBUTE_STRING: - type = ASN1_UTF8STRING; - break; - case IETF_ATTRIBUTE_OID: - type = ASN1_OID; - break; - } - ietfAttribute = asn1_simple_object(type, attr->value); - - /* copy ietfAttribute into ietfAttributes chunk */ - memcpy(pos, ietfAttribute.ptr, ietfAttribute.len); - pos += ietfAttribute.len; - free(ietfAttribute.ptr); - } - iterator->destroy(iterator); - - return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes); -} - -/* - * Described in header. - */ -void ietfAttr_list_destroy(linked_list_t *list) -{ - list->destroy_offset(list, offsetof(ietfAttr_t, destroy)); -} diff --git a/src/libstrongswan/plugins/x509/ietf_attr_list.h b/src/libstrongswan/plugins/x509/ietf_attr_list.h deleted file mode 100644 index 5807a899e..000000000 --- a/src/libstrongswan/plugins/x509/ietf_attr_list.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2007 Andreas Steffen - * - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ietf_attr_list ietf_attr_list - * @{ @ingroup x509_p - */ - -#ifndef IETF_ATTR_LIST_H_ -#define IETF_ATTR_LIST_H_ - -#include <library.h> -#include <utils/linked_list.h> - - -/** - * @brief Compare two linked lists of ietfAttr_t objects for equality - * - * @param list_a first alphabetically-sorted list - * @param list_b second alphabetically-sorted list - * @return TRUE if equal - */ -bool ietfAttr_list_equals(linked_list_t *list_a, linked_list_t *list_b); - -/** - * @brief Lists a linked list of ietfAttr_t objects - * - * @param list alphabetically-sorted linked list of attributes - * @param out output file - */ -void ietfAttr_list_list(linked_list_t *list, FILE *out); - -/** - * @brief Create a linked list of ietfAttr_t objects from a string - * - * @param msg string with comma-separated group names - * @param list alphabetically-sorted linked list of attributes - */ -void ietfAttr_list_create_from_string(char *msg, linked_list_t *list); - -/** - * @brief Create a linked list of ietfAttr_t objects from an ASN.1-coded chunk - * - * @param chunk chunk containing ASN.1-coded attributes - * @param list alphabetically-sorted linked list of attributes - * @param level0 parsing level - */ -void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0); - -/** - * @brief Encode a linked list of ietfAttr_t objects into an ASN.1-coded chunk - * - * @param list alphabetically-sorted linked list of attributes - * @return chunk containing ASN.1-coded attributes - */ -chunk_t ietfAttr_list_encode(linked_list_t *list); - -/** - * @brief Destroys a linked list of ietfAttr_t objects - * - * @param list list to be destroyed - */ -void ietfAttr_list_destroy(linked_list_t *list); - -#endif /** IETF_ATTR_LIST_H_ @}*/ - diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 638f96b44..79ff80933 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -1,9 +1,10 @@ /* * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2002-2008 Andreas Steffen + * Copyright (C) 2002-2009 Andreas Steffen + * Copyright (C) 2009 Martin Willi * - * Hochschule fuer Technik Rapperswil + * 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 @@ -17,7 +18,6 @@ */ #include "x509_ac.h" -#include "ietf_attr_list.h" #include <time.h> @@ -26,14 +26,14 @@ #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/asn1_parser.h> -#include <asn1/pem.h> #include <utils/identification.h> #include <utils/linked_list.h> #include <credentials/certificates/x509.h> +#include <credentials/ietf_attributes/ietf_attributes.h> #include <credentials/keys/private_key.h> -extern identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, - int level0, chunk_t *authKeySerialNumber); +extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, + int level0, chunk_t *authKeySerialNumber); typedef struct private_x509_ac_t private_x509_ac_t; @@ -46,7 +46,7 @@ struct private_x509_ac_t { * public functions */ x509_ac_t public; - + /** * X.509 attribute certificate encoding in ASN.1 DER format */ @@ -81,7 +81,7 @@ struct private_x509_ac_t { * ID representing the holder */ identification_t *entityName; - + /** * ID representing the attribute certificate issuer */ @@ -100,17 +100,17 @@ struct private_x509_ac_t { /** * List of charging attributes */ - linked_list_t *charging; + ietf_attributes_t *charging; /** * List of groub attributes */ - linked_list_t *groups; + ietf_attributes_t *groups; /** * Authority Key Identifier */ - identification_t *authKeyIdentifier; + chunk_t authKeyIdentifier; /** * Authority Key Serial Number @@ -132,19 +132,19 @@ struct private_x509_ac_t { */ chunk_t signature; - /** - * Holder certificate - */ + /** + * Holder certificate + */ certificate_t *holderCert; - /** - * Signer certificate - */ + /** + * Signer certificate + */ certificate_t *signerCert; - /** - * Signer private key; - */ + /** + * Signer private key; + */ private_key_t *signerKey; /** @@ -153,30 +153,13 @@ struct private_x509_ac_t { refcount_t ref; }; -static u_char ASN1_group_oid_str[] = { - 0x06, 0x08, - 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04 -}; - -static const chunk_t ASN1_group_oid = chunk_from_buf(ASN1_group_oid_str); - -static u_char ASN1_authorityKeyIdentifier_oid_str[] = { - 0x06, 0x03, - 0x55, 0x1d, 0x23 -}; - -static const chunk_t ASN1_authorityKeyIdentifier_oid = - chunk_from_buf(ASN1_authorityKeyIdentifier_oid_str); - -static u_char ASN1_noRevAvail_ext_str[] = { +static chunk_t ASN1_noRevAvail_ext = chunk_from_chars( 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x38, 0x04, 0x02, 0x05, 0x00 -}; - -static const chunk_t ASN1_noRevAvail_ext = chunk_from_buf(ASN1_noRevAvail_ext_str); +); /** * declaration of function implemented in x509_cert.c @@ -294,7 +277,7 @@ static const asn1Object_t acObjects[] = { 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, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */ { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | ASN1_BODY }, /* 25 */ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ @@ -302,7 +285,7 @@ static const asn1Object_t acObjects[] = { 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 | + { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT | ASN1_BODY }, /* 31 */ { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */ { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */ @@ -430,10 +413,14 @@ static bool parse_certificate(private_x509_ac_t *this) DBG2(" need to parse accessIdentity"); break; case OID_CHARGING_IDENTITY: - ietfAttr_list_create_from_chunk(object, this->charging, level); + DBG2("-- > --"); + this->charging = ietf_attributes_create_from_encoding(object); + DBG2("-- < --"); break; case OID_GROUP: - ietfAttr_list_create_from_chunk(object, this->groups, level); + DBG2("-- > --"); + this->groups = ietf_attributes_create_from_encoding(object); + DBG2("-- < --"); break; case OID_ROLE: parse_roleSyntax(object, level); @@ -459,7 +446,7 @@ static bool parse_certificate(private_x509_ac_t *this) break; case OID_AUTHORITY_KEY_ID: this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, - level, &this->authKeySerialNumber); + level, &this->authKeySerialNumber); break; case OID_TARGET_INFORMATION: DBG2(" need to parse targetInformation"); @@ -547,10 +534,10 @@ static chunk_t build_attr_cert_validity(private_x509_ac_t *this) /** * build attribute type */ -static chunk_t build_attribute_type(const chunk_t type, chunk_t content) +static chunk_t build_attribute_type(int type, chunk_t content) { - return asn1_wrap(ASN1_SEQUENCE, "cm", - type, + return asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(type), asn1_wrap(ASN1_SET, "m", content)); } @@ -560,7 +547,7 @@ static chunk_t build_attribute_type(const chunk_t type, chunk_t content) static chunk_t build_attributes(private_x509_ac_t *this) { return asn1_wrap(ASN1_SEQUENCE, "m", - build_attribute_type(ASN1_group_oid, ietfAttr_list_encode(this->groups))); + build_attribute_type(OID_GROUP, this->groups->get_encoding(this->groups))); } /** @@ -568,31 +555,30 @@ static chunk_t build_attributes(private_x509_ac_t *this) */ static chunk_t build_authorityKeyIdentifier(private_x509_ac_t *this) { - chunk_t keyIdentifier; + chunk_t keyIdentifier = chunk_empty; chunk_t authorityCertIssuer; chunk_t authorityCertSerialNumber; - x509_t *x509 = (x509_t*)this->signerCert; - identification_t *issuer = this->signerCert->get_issuer(this->signerCert); - public_key_t *public = this->signerCert->get_public_key(this->signerCert); + identification_t *issuer; + public_key_t *public; + x509_t *x509; + x509 = (x509_t*)this->signerCert; + issuer = this->signerCert->get_issuer(this->signerCert); + public = this->signerCert->get_public_key(this->signerCert); if (public) { - identification_t *keyid = public->get_id(public, ID_PUBKEY_SHA1); - - this->authKeyIdentifier = keyid = keyid->clone(keyid); - keyIdentifier = keyid->get_encoding(keyid); + if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &keyIdentifier)) + { + this->authKeyIdentifier = chunk_clone(keyIdentifier); + } public->destroy(public); } - else - { - keyIdentifier = chunk_empty; - } authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1, - issuer->get_encoding(issuer)); + issuer->get_encoding(issuer)); authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2, - x509->get_serial(x509)); - return asn1_wrap(ASN1_SEQUENCE, "cm", - ASN1_authorityKeyIdentifier_oid, + x509->get_serial(x509)); + return asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_AUTHORITY_KEY_ID), asn1_wrap(ASN1_OCTET_STRING, "m", asn1_wrap(ASN1_SEQUENCE, "cmm", keyIdentifier, @@ -618,7 +604,7 @@ static chunk_t build_extensions(private_x509_ac_t *this) */ static chunk_t build_attr_cert_info(private_x509_ac_t *this) { - return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm", + return asn1_wrap(ASN1_SEQUENCE, "cmmmmmmm", ASN1_INTEGER_1, build_holder(this), build_v2_form(this), @@ -636,14 +622,14 @@ static chunk_t build_attr_cert_info(private_x509_ac_t *this) static chunk_t build_ac(private_x509_ac_t *this) { chunk_t signatureValue; - chunk_t attributeCertificateInfo; + chunk_t attributeCertificateInfo; attributeCertificateInfo = build_attr_cert_info(this); this->signerKey->sign(this->signerKey, SIGN_RSA_EMSA_PKCS1_SHA1, attributeCertificateInfo, &signatureValue); - return asn1_wrap(ASN1_SEQUENCE, "mcm", + return asn1_wrap(ASN1_SEQUENCE, "mmm", attributeCertificateInfo, asn1_algorithmIdentifier(OID_SHA1_WITH_RSA), asn1_bitstring("m", signatureValue)); @@ -676,12 +662,20 @@ static identification_t* get_holderIssuer(private_x509_ac_t *this) /** * Implementation of ac_t.get_authKeyIdentifier. */ -static identification_t* get_authKeyIdentifier(private_x509_ac_t *this) +static chunk_t get_authKeyIdentifier(private_x509_ac_t *this) { return this->authKeyIdentifier; } /** + * Implementation of certificate_t.get_groups. + */ +static ietf_attributes_t* get_groups(private_x509_ac_t *this) +{ + return this->groups ? this->groups->get_ref(this->groups) : NULL; +} + +/** * Implementation of certificate_t.get_type */ static certificate_type_t get_type(private_x509_ac_t *this) @@ -710,7 +704,7 @@ static identification_t* get_issuer(private_x509_ac_t *this) */ static id_match_t has_subject(private_x509_ac_t *this, identification_t *subject) { - return ID_MATCH_NONE; + return ID_MATCH_NONE; } /** @@ -718,24 +712,12 @@ static id_match_t has_subject(private_x509_ac_t *this, identification_t *subject */ static id_match_t has_issuer(private_x509_ac_t *this, identification_t *issuer) { - id_match_t match; - - if (issuer->get_type(issuer) == ID_PUBKEY_SHA1) - { - if (this->authKeyIdentifier) - { - match = issuer->matches(issuer, this->authKeyIdentifier); - } - else - { - match = ID_MATCH_NONE; - } - } - else + if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr && + chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer))) { - match = this->issuerName->matches(this->issuerName, issuer); + return ID_MATCH_PERFECT; } - return match; + return this->issuerName->matches(this->issuerName, issuer); } /** @@ -747,7 +729,7 @@ static bool issued_by(private_x509_ac_t *this, certificate_t *issuer) signature_scheme_t scheme; bool valid; x509_t *x509 = (x509_t*)issuer; - + /* check if issuer is an X.509 AA certificate */ if (issuer->get_type(issuer) != CERT_X509) { @@ -762,19 +744,20 @@ static bool issued_by(private_x509_ac_t *this, certificate_t *issuer) key = issuer->get_public_key(issuer); /* compare keyIdentifiers if available, otherwise use DNs */ - if (this->authKeyIdentifier && key) + if (this->authKeyIdentifier.ptr && key) { - identification_t *subjectKeyIdentifier = key->get_id(key, ID_PUBKEY_SHA1); + chunk_t fingerprint; - if (!subjectKeyIdentifier->equals(subjectKeyIdentifier, - this->authKeyIdentifier)) + if (!key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &fingerprint) || + !chunk_equals(fingerprint, this->authKeyIdentifier)) { return FALSE; } } - else + else { - if (!this->issuerName->equals(this->issuerName, issuer->get_subject(issuer))) + if (!this->issuerName->equals(this->issuerName, + issuer->get_subject(issuer))) { return FALSE; } @@ -815,16 +798,8 @@ static private_x509_ac_t* get_ref(private_x509_ac_t *this) static bool get_validity(private_x509_ac_t *this, time_t *when, time_t *not_before, time_t *not_after) { - time_t t; - - if (when) - { - t = *when; - } - else - { - t = time(NULL); - } + time_t t = when ? *when : time(NULL); + if (not_before) { *not_before = this->notBefore; @@ -849,12 +824,12 @@ static bool is_newer(private_x509_ac_t *this, ac_t *that) this_cert->get_validity(this_cert, &now, &this_update, NULL); that_cert->get_validity(that_cert, &now, &that_update, NULL); new = this_update > that_update; - DBG1(" attr cert from %T is %s - existing attr_cert from %T %s", + DBG1(" attr cert from %T is %s - existing attr cert from %T %s", &this_update, FALSE, new ? "newer":"not newer", &that_update, FALSE, new ? "replaced":"retained"); return new; } - + /** * Implementation of certificate_t.get_encoding. */ @@ -870,14 +845,14 @@ static bool equals(private_x509_ac_t *this, certificate_t *other) { chunk_t encoding; bool equal; - + if ((certificate_t*)this == other) { return TRUE; } if (other->equals == (void*)equals) { /* skip allocation if we have the same implementation */ - return chunk_equals(this->encoding, ((private_x509_ac_t*)other)->encoding); + return chunk_equals(this->encoding, ((private_x509_ac_t*)other)->encoding); } encoding = other->get_encoding(other); equal = chunk_equals(this->encoding, encoding); @@ -895,14 +870,13 @@ static void destroy(private_x509_ac_t *this) DESTROY_IF(this->holderIssuer); DESTROY_IF(this->entityName); DESTROY_IF(this->issuerName); - DESTROY_IF(this->authKeyIdentifier); DESTROY_IF(this->holderCert); DESTROY_IF(this->signerCert); DESTROY_IF(this->signerKey); - - ietfAttr_list_destroy(this->charging); - ietfAttr_list_destroy(this->groups); + DESTROY_IF(this->charging); + DESTROY_IF(this->groups); free(this->serialNumber.ptr); + free(this->authKeyIdentifier.ptr); free(this->encoding.ptr); free(this); } @@ -914,12 +888,13 @@ static void destroy(private_x509_ac_t *this) static private_x509_ac_t *create_empty(void) { private_x509_ac_t *this = malloc_thing(private_x509_ac_t); - + /* public functions */ this->public.interface.get_serial = (chunk_t (*)(ac_t*))get_serial; this->public.interface.get_holderSerial = (chunk_t (*)(ac_t*))get_holderSerial; this->public.interface.get_holderIssuer = (identification_t* (*)(ac_t*))get_holderIssuer; - this->public.interface.get_authKeyIdentifier = (identification_t* (*)(ac_t*))get_authKeyIdentifier; + this->public.interface.get_authKeyIdentifier = (chunk_t (*)(ac_t*))get_authKeyIdentifier; + this->public.interface.get_groups = (ietf_attributes_t* (*)(ac_t*))get_groups; this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_subject; this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; @@ -938,187 +913,108 @@ static private_x509_ac_t *create_empty(void) this->encoding = chunk_empty; this->serialNumber = chunk_empty; this->holderSerial = chunk_empty; + this->authKeyIdentifier = chunk_empty; this->holderIssuer = NULL; this->entityName = NULL; this->issuerName = NULL; - this->authKeyIdentifier = NULL; this->holderCert = NULL; this->signerCert = NULL; this->signerKey = NULL; - this->charging = linked_list_create(); - this->groups = linked_list_create(); + this->charging = NULL; + this->groups = NULL; this->ref = 1; return this; } /** - * create X.509 attribute certificate from a chunk + * See header. */ -static private_x509_ac_t* create_from_chunk(chunk_t chunk) +x509_ac_t *x509_ac_load(certificate_type_t type, va_list args) { - private_x509_ac_t *this = create_empty(); - - this->encoding = chunk; - if (!parse_certificate(this)) - { - destroy(this); - return NULL; - } - return this; -} + chunk_t blob = chunk_empty; -/** - * create X.509 crl from a file - */ -static private_x509_ac_t* create_from_file(char *path) -{ - bool pgp = FALSE; - chunk_t chunk; - private_x509_ac_t *this; - - if (!pem_asn1_load_file(path, NULL, &chunk, &pgp)) + while (TRUE) { - return NULL; + 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; } - - this = create_from_chunk(chunk); - - if (this == NULL) + if (blob.ptr) { - DBG1(" could not parse loaded attribute certificate file '%s'", path); - return NULL; - } - DBG1(" loaded attribute certificate file '%s'", path); - return this; -} - -typedef struct private_builder_t private_builder_t; -/** - * Builder implementation for certificate loading - */ -struct private_builder_t { - /** implements the builder interface */ - builder_t public; - /** X.509 attribute certificate to build */ - private_x509_ac_t *ac; -}; + private_x509_ac_t *ac = create_empty(); -/** - * Implementation of builder_t.build - */ -static private_x509_ac_t* build(private_builder_t *this) -{ - private_x509_ac_t *ac = this->ac; - - free(this); - - /* synthesis if encoding does not exist */ - if (ac && ac->encoding.ptr == NULL) - { - if (ac->holderCert && ac->signerCert && ac->signerKey) + ac->encoding = chunk_clone(blob); + if (parse_certificate(ac)) { - ac->encoding = build_ac(ac); - return ac; + return &ac->public; } destroy(ac); - return NULL; - } - else - { - return ac; } + return NULL; } /** - * Implementation of builder_t.add + * See header. */ -static void add(private_builder_t *this, builder_part_t part, ...) +x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args) { - va_list args; - certificate_t *cert; - chunk_t chunk; + private_x509_ac_t *ac; - va_start(args, part); - switch (part) + ac = create_empty(); + while (TRUE) { - case BUILD_FROM_FILE: - if (this->ac) - { - destroy(this->ac); - } - this->ac = create_from_file(va_arg(args, char*)); - break; - case BUILD_BLOB_ASN1_DER: - if (this->ac) - { - destroy(this->ac); - } - chunk = va_arg(args, chunk_t); - this->ac = create_from_chunk(chunk_clone(chunk)); - break; - case BUILD_NOT_BEFORE_TIME: - this->ac->notBefore = va_arg(args, time_t); - break; - case BUILD_NOT_AFTER_TIME: - this->ac->notAfter = va_arg(args, time_t); - break; - case BUILD_SERIAL: - chunk = va_arg(args, chunk_t); - this->ac->serialNumber = chunk_clone(chunk); - break; - case BUILD_IETF_GROUP_ATTR: - ietfAttr_list_create_from_string(va_arg(args, char*), - this->ac->groups); - break; - case BUILD_CERT: - cert = va_arg(args, certificate_t*); - if (cert->get_type(cert) == CERT_X509) - { - this->ac->holderCert = cert->get_ref(cert); - } - break; - case BUILD_SIGNING_CERT: - cert = va_arg(args, certificate_t*); - if (cert->get_type(cert) == CERT_X509) - { - this->ac->signerCert = cert->get_ref(cert); - } - break; - case BUILD_SIGNING_KEY: - this->ac->signerKey = va_arg(args, private_key_t*); - this->ac->signerKey->get_ref(this->ac->signerKey); - break; - default: - /* abort if unsupported option */ - if (this->ac) - { - destroy(this->ac); - } - builder_cancel(&this->public); - break; + switch (va_arg(args, builder_part_t)) + { + case BUILD_NOT_BEFORE_TIME: + ac->notBefore = va_arg(args, time_t); + continue; + case BUILD_NOT_AFTER_TIME: + ac->notAfter = va_arg(args, time_t); + continue; + case BUILD_SERIAL: + ac->serialNumber = chunk_clone(va_arg(args, chunk_t)); + continue; + case BUILD_IETF_GROUP_ATTR: + ac->groups = ietf_attributes_create_from_string(va_arg(args, char*)); + continue; + case BUILD_CERT: + ac->holderCert = va_arg(args, certificate_t*); + ac->holderCert->get_ref(ac->holderCert); + continue; + case BUILD_SIGNING_CERT: + ac->signerCert = va_arg(args, certificate_t*); + ac->signerCert->get_ref(ac->signerCert); + continue; + case BUILD_SIGNING_KEY: + ac->signerKey = va_arg(args, private_key_t*); + ac->signerKey->get_ref(ac->signerKey); + continue; + case BUILD_END: + break; + default: + destroy(ac); + return NULL; + } + break; } - va_end(args); -} -/** - * Builder construction function - */ -builder_t *x509_ac_builder(certificate_type_t type) -{ - private_builder_t *this; - - if (type != CERT_X509_AC) + if (ac->signerKey && ac->holderCert && ac->signerCert && + ac->holderCert->get_type(ac->holderCert) == CERT_X509 && + ac->signerCert->get_type(ac->signerCert) == CERT_X509) { - return NULL; + ac->encoding = build_ac(ac); + return &ac->public; } - - this = malloc_thing(private_builder_t); - - this->ac = create_empty(); - this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; - this->public.build = (void*(*)(builder_t *this))build; - - return &this->public; + destroy(ac); + return NULL; } diff --git a/src/libstrongswan/plugins/x509/x509_ac.h b/src/libstrongswan/plugins/x509/x509_ac.h index 958d5c57a..da0988c6e 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.h +++ b/src/libstrongswan/plugins/x509/x509_ac.h @@ -2,6 +2,7 @@ * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter * Copyright (C) 2002-2008 Andreas Steffen + * Copyright (C) 2009 Martin Willi * * Hochschule fuer Technik Rapperswil * @@ -24,6 +25,7 @@ #ifndef X509_AC_H_ #define X509_AC_H_ +#include <credentials/builder.h> #include <credentials/certificates/ac.h> typedef struct x509_ac_t x509_ac_t; @@ -40,18 +42,28 @@ struct x509_ac_t { }; /** - * Create the building facility for X.509 attribute certificates. + * Load a X.509 attribute certificate. * - * The resulting builder accepts: - * BUILD_USER_CERT: user certificate, exactly one - * BUILD_SIGNER_CERT: signer certificate, exactly one - * BUILD_SIGNER_KEY: signer private key, exactly one - * BUILD_SERIAL: serial number, exactly one - * BUILD_GROUP_ATTR: group attribute, optional, several possible + * @param type certificate type, CERT_X509_AC only + * @param args builder_part_t argument list + * @return X.509 Attribute certificate, NULL on failure + */ +x509_ac_t *x509_ac_load(certificate_type_t type, va_list args); + +/** + * Generate a X.509 attribute certificate. + * + * Accepted build parts: + * BUILD_USER_CERT: user certificate + * BUILD_SIGNER_CERT: signer certificate + * BUILD_SIGNER_KEY: signer private key + * BUILD_SERIAL: serial number + * BUILD_GROUP_ATTR: group attribute, several possible * * @param type certificate type, CERT_X509_AC only - * @return builder instance to build X.509 attribute certificates + * @param args builder_part_t argument list + * @return X.509 Attribute certificate, NULL on failure */ -builder_t *x509_ac_builder(certificate_type_t type); +x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args); #endif /** X509_AC_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 6fe1809c2..3b729236e 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -3,7 +3,7 @@ * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss * Copyright (C) 2002 Mario Strasser * Copyright (C) 2000-2006 Andreas Steffen - * Copyright (C) 2006-2008 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Copyright (C) 2008 Tobias Brunner * Hochschule fuer Technik Rapperswil * @@ -33,11 +33,11 @@ #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/asn1_parser.h> -#include <asn1/pem.h> #include <crypto/hashers/hasher.h> #include <credentials/keys/private_key.h> #include <utils/linked_list.h> #include <utils/identification.h> +#include <selectors/traffic_selector.h> /** * Different kinds of generalNames @@ -65,17 +65,17 @@ struct private_x509_cert_t { * Public interface for this certificate. */ x509_cert_t public; - + /** * X.509 certificate encoding in ASN.1 DER format */ chunk_t encoding; - + /** * SHA1 hash of the DER encoding of this X.509 certificate */ chunk_t encoding_hash; - + /** * X.509 certificate body over which signature is computed */ @@ -85,100 +85,109 @@ struct private_x509_cert_t { * Version of the X.509 certificate */ u_int version; - + /** * Serial number of the X.509 certificate */ chunk_t serialNumber; - + /** * ID representing the certificate issuer */ identification_t *issuer; - + /** * Start time of certificate validity */ time_t notBefore; - + /** * End time of certificate validity */ time_t notAfter; - + /** * ID representing the certificate subject */ identification_t *subject; - + /** * List of subjectAltNames as identification_t */ linked_list_t *subjectAltNames; - + /** * List of crlDistributionPoints as allocated char* */ linked_list_t *crl_uris; - + /** - * List ocspAccessLocations as identification_t + * List of ocspAccessLocations as allocated char* */ linked_list_t *ocsp_uris; - + /** - * certificates embedded public key + * List of ipAddrBlocks as traffic_selector_t + */ + linked_list_t *ipAddrBlocks; + + /** + * certificate's embedded public key */ public_key_t *public_key; - + /** * Subject Key Identifier */ - chunk_t subjectKeyID; - + chunk_t subjectKeyIdentifier; + /** * Authority Key Identifier */ - identification_t *authKeyIdentifier; - + chunk_t authKeyIdentifier; + /** * Authority Key Serial Number */ chunk_t authKeySerialNumber; - + + /** + * Path Length Constraint + */ + int pathLenConstraint; + /** * x509 constraints and other flags */ x509_flag_t flags; - + /** * Signature algorithm */ int algorithm; - + /** * Signature */ chunk_t signature; - + /** * Certificate parsed from blob/file? */ bool parsed; - + /** * reference count */ refcount_t ref; }; -static u_char ASN1_sAN_oid_buf[] = { +static const chunk_t ASN1_subjectAltName_oid = chunk_from_chars( 0x06, 0x03, 0x55, 0x1D, 0x11 -}; -static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_sAN_oid_buf); +); /** - * ASN.1 definition of a basicConstraints extension + * ASN.1 definition of a basicConstraints extension */ static const asn1Object_t basicConstraintsObjects[] = { { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ @@ -187,12 +196,14 @@ static const asn1Object_t basicConstraintsObjects[] = { { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ { 0, "exit", ASN1_EOC, ASN1_EXIT } }; -#define BASIC_CONSTRAINTS_CA 1 +#define BASIC_CONSTRAINTS_CA 1 +#define BASIC_CONSTRAINTS_PATH_LEN 2 /** * Extracts the basicConstraints extension */ -static bool parse_basicConstraints(chunk_t blob, int level0) +static void parse_basicConstraints(chunk_t blob, int level0, + private_x509_cert_t *this) { asn1_parser_t *parser; chunk_t object; @@ -204,19 +215,39 @@ static bool parse_basicConstraints(chunk_t blob, int level0) while (parser->iterate(parser, &objectID, &object)) { - if (objectID == BASIC_CONSTRAINTS_CA) + switch (objectID) { - isCA = object.len && *object.ptr; - DBG2(" %s", isCA ? "TRUE" : "FALSE"); + case BASIC_CONSTRAINTS_CA: + isCA = object.len && *object.ptr; + DBG2(" %s", isCA ? "TRUE" : "FALSE"); + if (isCA) + { + this->flags |= X509_CA; + } + break; + case BASIC_CONSTRAINTS_PATH_LEN: + if (isCA) + { + if (object.len == 0) + { + this->pathLenConstraint = 0; + } + else if (object.len == 1) + { + this->pathLenConstraint = *object.ptr; + } + /* we ignore path length constraints > 127 */ + } + break; + default: + break; } } parser->destroy(parser); - - return isCA; } /** - * ASN.1 definition of otherName + * ASN.1 definition of otherName */ static const asn1Object_t otherNameObjects[] = { {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ @@ -262,14 +293,14 @@ static bool parse_otherName(chunk_t blob, int level0) } } success = parser->success(parser); - + end: parser->destroy(parser); return success; } /** - * ASN.1 definition of generalName + * ASN.1 definition of generalName */ static const asn1Object_t generalNameObjects[] = { { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ @@ -292,10 +323,10 @@ static const asn1Object_t generalNameObjects[] = { { 0, "end choice", ASN1_EOC, ASN1_END }, /* 17 */ { 0, "exit", ASN1_EOC, ASN1_EXIT } }; -#define GN_OBJ_OTHER_NAME 0 -#define GN_OBJ_RFC822_NAME 2 -#define GN_OBJ_DNS_NAME 4 -#define GN_OBJ_X400_ADDRESS 6 +#define GN_OBJ_OTHER_NAME 0 +#define GN_OBJ_RFC822_NAME 2 +#define GN_OBJ_DNS_NAME 4 +#define GN_OBJ_X400_ADDRESS 6 #define GN_OBJ_DIRECTORY_NAME 8 #define GN_OBJ_EDI_PARTY_NAME 10 #define GN_OBJ_URI 12 @@ -310,16 +341,16 @@ static identification_t *parse_generalName(chunk_t blob, int level0) asn1_parser_t *parser; chunk_t object; int objectID ; - + identification_t *gn = NULL; - + parser = asn1_parser_create(generalNameObjects, blob); parser->set_top_level(parser, level0); - + while (parser->iterate(parser, &objectID, &object)) { id_type_t id_type = ID_ANY; - + switch (objectID) { case GN_OBJ_RFC822_NAME: @@ -356,14 +387,14 @@ static identification_t *parse_generalName(chunk_t blob, int level0) goto end; } } - + end: parser->destroy(parser); return gn; } /** - * ASN.1 definition of generalNames + * ASN.1 definition of generalNames */ static const asn1Object_t generalNamesObjects[] = { { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ @@ -381,18 +412,18 @@ void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_lis asn1_parser_t *parser; chunk_t object; int objectID; - + 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) { identification_t *gn = parse_generalName(object, parser->get_level(parser)+1); - + if (gn) { list->insert_last(list, (void *)gn); @@ -403,7 +434,7 @@ void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_lis } /** - * ASN.1 definition of a authorityKeyIdentifier extension + * ASN.1 definition of a authorityKeyIdentifier extension */ static const asn1Object_t authKeyIdentifierObjects[] = { { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ @@ -422,26 +453,25 @@ static const asn1Object_t authKeyIdentifierObjects[] = { /** * Extracts an authoritykeyIdentifier */ -identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, +chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, chunk_t *authKeySerialNumber) { asn1_parser_t *parser; chunk_t object; int objectID; - identification_t *authKeyIdentifier = NULL; - + chunk_t authKeyIdentifier = chunk_empty; + *authKeySerialNumber = chunk_empty; - + parser = asn1_parser_create(authKeyIdentifierObjects, blob); parser->set_top_level(parser, level0); - + while (parser->iterate(parser, &objectID, &object)) { - switch (objectID) + switch (objectID) { case AUTH_KEY_ID_KEY_ID: - authKeyIdentifier = identification_create_from_encoding( - ID_PUBKEY_SHA1, object); + authKeyIdentifier = chunk_clone(object); break; case AUTH_KEY_ID_CERT_ISSUER: /* TODO: x509_parse_generalNames(object, level+1, TRUE); */ @@ -458,7 +488,7 @@ identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, } /** - * ASN.1 definition of a authorityInfoAccess extension + * ASN.1 definition of a authorityInfoAccess extension */ static const asn1Object_t authInfoAccessObjects[] = { { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ @@ -481,13 +511,13 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, 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) + switch (objectID) { case AUTH_INFO_ACCESS_METHOD: accessMethod = asn1_known_oid(object); @@ -501,7 +531,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, { identification_t *id; char *uri; - + id = parse_generalName(object, parser->get_level(parser)+1); if (id == NULL) @@ -528,7 +558,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, break; } } - + end: parser->destroy(parser); } @@ -547,26 +577,37 @@ static const asn1Object_t extendedKeyUsageObjects[] = { /** * Extracts extendedKeyUsage OIDs - currently only OCSP_SIGING is returned */ -static bool parse_extendedKeyUsage(chunk_t blob, int level0) +static void parse_extendedKeyUsage(chunk_t blob, int level0, + private_x509_cert_t *this) { 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) + if (objectID == EXT_KEY_USAGE_PURPOSE_ID) { - ocsp_signing = TRUE; + switch (asn1_known_oid(object)) + { + case OID_SERVER_AUTH: + this->flags |= X509_SERVER_AUTH; + break; + case OID_CLIENT_AUTH: + this->flags |= X509_CLIENT_AUTH; + break; + case OID_OCSP_SIGNING: + this->flags |= X509_OCSP_SIGNER; + break; + default: + break; + } } } parser->destroy(parser); - return ocsp_signing; } /** @@ -600,24 +641,24 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0, chunk_t object; int objectID; linked_list_t *list = linked_list_create(); - + parser = asn1_parser_create(crlDistributionPointsObjects, blob); parser->set_top_level(parser, level0); - + while (parser->iterate(parser, &objectID, &object)) { if (objectID == CRL_DIST_POINTS_FULLNAME) { identification_t *id; - + /* append extracted generalNames to existing chained list */ x509_parse_generalNames(object, parser->get_level(parser)+1, TRUE, list); - + while (list->remove_last(list, (void**)&id) == SUCCESS) { char *uri; - + if (asprintf(&uri, "%Y", id) > 0) { this->crl_uris->insert_last(this->crl_uris, uri); @@ -631,6 +672,147 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0, } /** + * ASN.1 definition of ipAddrBlocks according to RFC 3779 + */ +static const asn1Object_t ipAddrBlocksObjects[] = { + { 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "ipAddressFamily", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ + { 2, "inherit", ASN1_NULL, ASN1_OPT|ASN1_NONE }, /* 3 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ + { 2, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 5 */ + { 3, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 6 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 3, "addressRange", ASN1_SEQUENCE, ASN1_OPT|ASN1_NONE }, /* 8 */ + { 4, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 9 */ + { 4, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 10 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ + { 2, "end choice/loop", ASN1_EOC, ASN1_END }, /* 12 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 13 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define IP_ADDR_BLOCKS_FAMILY 2 +#define IP_ADDR_BLOCKS_INHERIT 3 +#define IP_ADDR_BLOCKS_PREFIX 6 +#define IP_ADDR_BLOCKS_MIN 9 +#define IP_ADDR_BLOCKS_MAX 10 + +static bool check_address_object(ts_type_t ts_type, chunk_t object) +{ + switch (ts_type) + { + case TS_IPV4_ADDR_RANGE: + if (object.len > 5) + { + DBG1("IPv4 address object is larger than 5 octets"); + return FALSE; + } + break; + case TS_IPV6_ADDR_RANGE: + if (object.len > 17) + { + DBG1("IPv6 address object is larger than 17 octets"); + return FALSE; + } + break; + default: + DBG1("unknown address family"); + return FALSE; + } + if (object.len == 0) + { + DBG1("An ASN.1 bit string must contain at least the initial octet"); + return FALSE; + } + if (object.len == 1 && object.ptr[0] != 0) + { + DBG1("An empty ASN.1 bit string must contain a zero initial octet"); + return FALSE; + } + if (object.ptr[0] > 7) + { + DBG1("number of unused bits is too large"); + return FALSE; + } + return TRUE; +} + +static void parse_ipAddrBlocks(chunk_t blob, int level0, + private_x509_cert_t *this) +{ + asn1_parser_t *parser; + chunk_t object, min_object; + ts_type_t ts_type = 0; + traffic_selector_t *ts; + int objectID; + + parser = asn1_parser_create(ipAddrBlocksObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case IP_ADDR_BLOCKS_FAMILY: + ts_type = 0; + if (object.len == 2 && object.ptr[0] == 0) + { + if (object.ptr[1] == 1) + { + ts_type = TS_IPV4_ADDR_RANGE; + } + else if (object.ptr[1] == 2) + { + ts_type = TS_IPV6_ADDR_RANGE; + } + else + { + break; + } + DBG2(" %N", ts_type_name, ts_type); + } + break; + case IP_ADDR_BLOCKS_INHERIT: + DBG1("inherit choice is not supported"); + break; + case IP_ADDR_BLOCKS_PREFIX: + if (!check_address_object(ts_type, object)) + { + goto end; + } + ts = traffic_selector_create_from_rfc3779_format(ts_type, + object, object); + DBG2(" %R", ts); + this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); + break; + case IP_ADDR_BLOCKS_MIN: + if (!check_address_object(ts_type, object)) + { + goto end; + } + min_object = object; + break; + case IP_ADDR_BLOCKS_MAX: + if (!check_address_object(ts_type, object)) + { + goto end; + } + ts = traffic_selector_create_from_rfc3779_format(ts_type, + min_object, object); + DBG2(" %R", ts); + this->ipAddrBlocks->insert_last(this->ipAddrBlocks, ts); + break; + default: + break; + } + } + this->flags |= X509_IP_ADDR_BLOCKS; + +end: + parser->destroy(parser); +} + +/** * ASN.1 definition of an X.509v3 x509_cert */ static const asn1Object_t certObjects[] = { @@ -671,6 +853,7 @@ static const asn1Object_t certObjects[] = { #define X509_OBJ_NOT_AFTER 9 #define X509_OBJ_SUBJECT 10 #define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11 +#define X509_OBJ_OPTIONAL_EXTENSIONS 16 #define X509_OBJ_EXTN_ID 19 #define X509_OBJ_CRITICAL 20 #define X509_OBJ_EXTN_VALUE 21 @@ -678,6 +861,11 @@ static const asn1Object_t certObjects[] = { #define X509_OBJ_SIGNATURE 25 /** + * forward declaration + */ +static bool issued_by(private_x509_cert_t *this, certificate_t *issuer); + +/** * Parses an X.509v3 certificate */ static bool parse_certificate(private_x509_cert_t *this) @@ -688,14 +876,14 @@ static bool parse_certificate(private_x509_cert_t *this) int extn_oid = OID_UNKNOWN; int sig_alg = OID_UNKNOWN; bool success = FALSE; - bool critical; - + bool critical = FALSE; + parser = asn1_parser_create(certObjects, this->encoding); - + while (parser->iterate(parser, &objectID, &object)) { u_int level = parser->get_level(parser)+1; - + switch (objectID) { case X509_OBJ_TBS_CERTIFICATE: @@ -703,7 +891,15 @@ static bool parse_certificate(private_x509_cert_t *this) break; case X509_OBJ_VERSION: this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG2(" v%d", this->version); + if (this->version < 1 || this->version > 3) + { + DBG1("X.509v%d not supported", this->version); + goto end; + } + else + { + DBG2(" X.509v%d", this->version); + } break; case X509_OBJ_SERIAL_NUMBER: this->serialNumber = object; @@ -726,13 +922,22 @@ static bool parse_certificate(private_x509_cert_t *this) DBG2(" '%Y'", this->subject); break; case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO: + DBG2("-- > --"); this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); + DBG2("-- < --"); if (this->public_key == NULL) { goto end; } break; + case X509_OBJ_OPTIONAL_EXTENSIONS: + if (this->version != 3) + { + DBG1("Only X.509v3 certificates have extensions"); + goto end; + } + break; case X509_OBJ_EXTN_ID: extn_oid = asn1_known_oid(object); break; @@ -750,45 +955,50 @@ static bool parse_certificate(private_x509_cert_t *this) { goto end; } - this->subjectKeyID = object; + this->subjectKeyIdentifier = object; break; case OID_SUBJECT_ALT_NAME: x509_parse_generalNames(object, level, FALSE, this->subjectAltNames); break; case OID_BASIC_CONSTRAINTS: - if (parse_basicConstraints(object, level)) - { - this->flags |= X509_CA; - } + parse_basicConstraints(object, level, this); break; case OID_CRL_DISTRIBUTION_POINTS: parse_crlDistributionPoints(object, level, this); break; case OID_AUTHORITY_KEY_ID: this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, - level, &this->authKeySerialNumber); + level, &this->authKeySerialNumber); break; case OID_AUTHORITY_INFO_ACCESS: parse_authorityInfoAccess(object, level, this); break; case OID_EXTENDED_KEY_USAGE: - if (parse_extendedKeyUsage(object, level)) - { - this->flags |= X509_OCSP_SIGNER; - } + parse_extendedKeyUsage(object, level, this); + break; + case OID_IP_ADDR_BLOCKS: + parse_ipAddrBlocks(object, level, this); 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, + if (!asn1_parse_simple_object(&object, ASN1_IA5STRING, level, oid_names[extn_oid].name)) { goto end; } break; default: + if (critical && lib->settings->get_bool(lib->settings, + "libstrongswan.plugins.x509.enforce_critical", FALSE)) + { + DBG1("critical %s extension not supported", + (extn_oid == OID_UNKNOWN) ? "unknown" : + (char*)oid_names[extn_oid].name); + goto end; + } break; } break; @@ -809,9 +1019,28 @@ static bool parse_certificate(private_x509_cert_t *this) } } success = parser->success(parser); - + end: parser->destroy(parser); + if (success) + { + hasher_t *hasher; + + /* check if the certificate is self-signed */ + if (issued_by(this, &this->public.interface.interface)) + { + this->flags |= X509_SELF_SIGNED; + } + /* create certificate hash */ + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + DBG1(" unable to create hash of certificate, SHA1 not supported"); + return NULL; + } + hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash); + hasher->destroy(hasher); + } return success; } @@ -847,13 +1076,15 @@ static id_match_t has_subject(private_x509_cert_t *this, identification_t *subje identification_t *current; enumerator_t *enumerator; id_match_t match, best; - - if (this->encoding_hash.ptr && subject->get_type(subject) == ID_CERT_DER_SHA1 && - chunk_equals(this->encoding_hash, subject->get_encoding(subject))) + + if (this->encoding_hash.ptr && subject->get_type(subject) == ID_KEY_ID) { - return ID_MATCH_PERFECT; + if (chunk_equals(this->encoding_hash, subject->get_encoding(subject))) + { + return ID_MATCH_PERFECT; + } } - + best = this->subject->matches(this->subject, subject); enumerator = this->subjectAltNames->create_enumerator(this->subjectAltNames); while (enumerator->enumerate(enumerator, ¤t)) @@ -861,15 +1092,15 @@ static id_match_t has_subject(private_x509_cert_t *this, identification_t *subje match = current->matches(current, subject); if (match > best) { - best = match; + best = match; } } enumerator->destroy(enumerator); - return best; + return best; } /** - * Implementation of certificate_t.has_subject. + * Implementation of certificate_t.has_issuer. */ static id_match_t has_issuer(private_x509_cert_t *this, identification_t *issuer) { @@ -878,7 +1109,7 @@ static id_match_t has_issuer(private_x509_cert_t *this, identification_t *issuer } /** - * Implementation of certificate_t.issued_by + * Implementation of certificate_t.issued_by. */ static bool issued_by(private_x509_cert_t *this, certificate_t *issuer) { @@ -886,7 +1117,7 @@ static bool issued_by(private_x509_cert_t *this, certificate_t *issuer) signature_scheme_t scheme; bool valid; x509_t *x509 = (x509_t*)issuer; - + if (&this->public.interface.interface == issuer) { if (this->flags & X509_SELF_SIGNED) @@ -910,17 +1141,18 @@ static bool issued_by(private_x509_cert_t *this, certificate_t *issuer) return FALSE; } - /* get the public key of the issuer */ - key = issuer->get_public_key(issuer); - /* determine signature scheme */ scheme = signature_scheme_from_oid(this->algorithm); - - if (scheme == SIGN_UNKNOWN || key == NULL) + if (scheme == SIGN_UNKNOWN) + { + return FALSE; + } + /* get the public key of the issuer */ + key = issuer->get_public_key(issuer); + if (!key) { return FALSE; } - /* TODO: add a lightweight check option (comparing auth/subject keyids only) */ valid = key->verify(key, scheme, this->tbsCertificate, this->signature); key->destroy(key); return valid; @@ -936,7 +1168,7 @@ static public_key_t* get_public_key(private_x509_cert_t *this) } /** - * Implementation of certificate_t.asdf + * Implementation of certificate_t.get_ref */ static private_x509_cert_t* get_ref(private_x509_cert_t *this) { @@ -958,16 +1190,8 @@ static x509_flag_t get_flags(private_x509_cert_t *this) static bool get_validity(private_x509_cert_t *this, time_t *when, time_t *not_before, time_t *not_after) { - time_t t; - - if (when) - { - t = *when; - } - else - { - t = time(NULL); - } + time_t t = when ? *when : time(NULL); + if (not_before) { *not_before = this->notBefore; @@ -986,7 +1210,7 @@ static bool is_newer(certificate_t *this, certificate_t *that) { time_t this_update, that_update, now = time(NULL); bool new; - + this->get_validity(this, &now, &this_update, NULL); that->get_validity(that, &now, &that_update, NULL); new = this_update > that_update; @@ -995,7 +1219,7 @@ static bool is_newer(certificate_t *this, certificate_t *that) &that_update, FALSE, new ? "replaced":"retained"); return new; } - + /** * Implementation of certificate_t.get_encoding. */ @@ -1011,7 +1235,7 @@ static bool equals(private_x509_cert_t *this, certificate_t *other) { chunk_t encoding; bool equal; - + if (this == (private_x509_cert_t*)other) { return TRUE; @@ -1022,7 +1246,7 @@ static bool equals(private_x509_cert_t *this, certificate_t *other) } if (other->equals == (void*)equals) { /* skip allocation if we have the same implementation */ - return chunk_equals(this->encoding, ((private_x509_cert_t*)other)->encoding); + return chunk_equals(this->encoding, ((private_x509_cert_t*)other)->encoding); } encoding = other->get_encoding(other); equal = chunk_equals(this->encoding, encoding); @@ -1039,14 +1263,47 @@ static chunk_t get_serial(private_x509_cert_t *this) } /** + * Implementation of x509_t.get_subjectKeyIdentifier. + */ +static chunk_t get_subjectKeyIdentifier(private_x509_cert_t *this) +{ + if (this->subjectKeyIdentifier.ptr) + { + return this->subjectKeyIdentifier; + } + else + { + chunk_t fingerprint; + + if (this->public_key->get_fingerprint(this->public_key, + KEY_ID_PUBKEY_SHA1, &fingerprint)) + { + return fingerprint; + } + else + { + return chunk_empty; + } + } +} + +/** * Implementation of x509_t.get_authKeyIdentifier. */ -static identification_t *get_authKeyIdentifier(private_x509_cert_t *this) +static chunk_t get_authKeyIdentifier(private_x509_cert_t *this) { return this->authKeyIdentifier; } /** + * Implementation of x509_t.get_pathLenConstraint. + */ +static int get_pathLenConstraint(private_x509_cert_t *this) +{ + return this->pathLenConstraint; +} + +/** * Implementation of x509_cert_t.create_subjectAltName_enumerator. */ static enumerator_t* create_subjectAltName_enumerator(private_x509_cert_t *this) @@ -1071,7 +1328,15 @@ static enumerator_t* create_crl_uri_enumerator(private_x509_cert_t *this) } /** - * Implementation of certificate_t.asdf + * Implementation of x509_cert_t.create_ipAddrBlock_enumerator. + */ +static enumerator_t* create_ipAddrBlock_enumerator(private_x509_cert_t *this) +{ + return this->ipAddrBlocks->create_enumerator(this->ipAddrBlocks); +} + +/** + * Implementation of certificate_t.destroy. */ static void destroy(private_x509_cert_t *this) { @@ -1081,10 +1346,11 @@ static void destroy(private_x509_cert_t *this) offsetof(identification_t, destroy)); this->crl_uris->destroy_function(this->crl_uris, free); this->ocsp_uris->destroy_function(this->ocsp_uris, free); + this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks, offsetof(traffic_selector_t, destroy)); DESTROY_IF(this->issuer); DESTROY_IF(this->subject); DESTROY_IF(this->public_key); - DESTROY_IF(this->authKeyIdentifier); + chunk_free(&this->authKeyIdentifier); chunk_free(&this->encoding); chunk_free(&this->encoding_hash); if (!this->parsed) @@ -1103,7 +1369,7 @@ static void destroy(private_x509_cert_t *this) static private_x509_cert_t* create_empty(void) { private_x509_cert_t *this = malloc_thing(private_x509_cert_t); - + this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type; this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject; this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_issuer; @@ -1119,16 +1385,19 @@ static private_x509_cert_t* create_empty(void) this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy; this->public.interface.get_flags = (x509_flag_t (*)(x509_t*))get_flags; this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial; - this->public.interface.get_authKeyIdentifier = (identification_t* (*)(x509_t*))get_authKeyIdentifier; + this->public.interface.get_subjectKeyIdentifier = (chunk_t (*)(x509_t*))get_subjectKeyIdentifier; + this->public.interface.get_authKeyIdentifier = (chunk_t (*)(x509_t*))get_authKeyIdentifier; + this->public.interface.get_pathLenConstraint = (int (*)(x509_t*))get_pathLenConstraint; this->public.interface.create_subjectAltName_enumerator = (enumerator_t* (*)(x509_t*))create_subjectAltName_enumerator; this->public.interface.create_crl_uri_enumerator = (enumerator_t* (*)(x509_t*))create_crl_uri_enumerator; this->public.interface.create_ocsp_uri_enumerator = (enumerator_t* (*)(x509_t*))create_ocsp_uri_enumerator; - + this->public.interface.create_ipAddrBlock_enumerator = (enumerator_t* (*)(x509_t*))create_ipAddrBlock_enumerator; + this->encoding = chunk_empty; this->encoding_hash = chunk_empty; this->tbsCertificate = chunk_empty; - this->version = 3; - this->serialNumber = chunk_empty; + this->version = 1; + this->serialNumber = chunk_empty; this->notBefore = 0; this->notAfter = 0; this->public_key = NULL; @@ -1137,111 +1406,96 @@ static private_x509_cert_t* create_empty(void) this->subjectAltNames = linked_list_create(); this->crl_uris = linked_list_create(); this->ocsp_uris = linked_list_create(); - this->subjectKeyID = chunk_empty; - this->authKeyIdentifier = NULL; + this->ipAddrBlocks = linked_list_create(); + this->subjectKeyIdentifier = chunk_empty; + this->authKeyIdentifier = chunk_empty; this->authKeySerialNumber = chunk_empty; + this->pathLenConstraint = X509_NO_PATH_LEN_CONSTRAINT; this->algorithm = 0; this->signature = chunk_empty; this->flags = 0; this->ref = 1; this->parsed = FALSE; - - return this; -} -/** - * create an X.509 certificate from a chunk - */ -static private_x509_cert_t *create_from_chunk(chunk_t chunk) -{ - hasher_t *hasher; - private_x509_cert_t *this = create_empty(); - - this->encoding = chunk; - this->parsed = TRUE; - if (!parse_certificate(this)) - { - destroy(this); - return NULL; - } - - /* check if the certificate is self-signed */ - if (issued_by(this, &this->public.interface.interface)) - { - this->flags |= X509_SELF_SIGNED; - } - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - DBG1(" unable to create hash of certificate, SHA1 not supported"); - destroy(this); - return NULL; - } - hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash); - hasher->destroy(hasher); - return this; } /** - * create an X.509 certificate from a file + * Encode a linked list of subjectAltNames */ -static private_x509_cert_t *create_from_file(char *path) +chunk_t x509_build_subjectAltNames(linked_list_t *list) { - bool pgp = FALSE; - chunk_t chunk; - private_x509_cert_t *this; - - if (!pem_asn1_load_file(path, NULL, &chunk, &pgp)) + chunk_t subjectAltNames = chunk_empty; + enumerator_t *enumerator; + identification_t *id; + + if (list->get_count(list) == 0) { - return NULL; + return chunk_empty; } - this = create_from_chunk(chunk); - - if (this == NULL) + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &id)) { - DBG1(" could not parse loaded certificate file '%s'",path); - return NULL; + int context; + chunk_t name; + + switch (id->get_type(id)) + { + case ID_RFC822_ADDR: + context = ASN1_CONTEXT_S_1; + break; + case ID_FQDN: + context = ASN1_CONTEXT_S_2; + break; + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + context = ASN1_CONTEXT_S_7; + break; + default: + DBG1("encoding %N as subjectAltName not supported", + id_type_names, id->get_type(id)); + enumerator->destroy(enumerator); + free(subjectAltNames.ptr); + return chunk_empty; + } + name = asn1_wrap(context, "c", id->get_encoding(id)); + subjectAltNames = chunk_cat("mm", subjectAltNames, name); } - DBG1(" loaded certificate file '%s'", path); - return this; -} + enumerator->destroy(enumerator); -typedef struct private_builder_t private_builder_t; -/** - * Builder implementation for certificate loading - */ -struct private_builder_t { - /** implements the builder interface */ - builder_t public; - /** loaded certificate */ - private_x509_cert_t *cert; - /** additional flags to enforce */ - x509_flag_t flags; - /** certificate to sign, if we generate a new cert */ - certificate_t *sign_cert; - /** private key to sign, if we generate a new cert */ - private_key_t *sign_key; -}; + return asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_SUBJECT_ALT_NAME), + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames) + ) + ); +} /** * Generate and sign a new certificate */ -static bool generate(private_builder_t *this) +static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, + private_key_t *sign_key, int digest_alg) { - chunk_t extensions = chunk_empty; + chunk_t extensions = chunk_empty, extendedKeyUsage = chunk_empty; + chunk_t serverAuth = chunk_empty, clientAuth = chunk_empty; + chunk_t ocspSigning = chunk_empty; + chunk_t basicConstraints = chunk_empty, subjectAltNames = chunk_empty; + chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty; + chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty; identification_t *issuer, *subject; - chunk_t key_info, key; + chunk_t key_info; signature_scheme_t scheme; hasher_t *hasher; - - subject = this->cert->subject; - if (this->sign_cert) + enumerator_t *enumerator; + char *uri; + + subject = cert->subject; + if (sign_cert) { - issuer = this->sign_cert->get_subject(this->sign_cert); - if (!this->cert->public_key) + issuer = sign_cert->get_subject(sign_cert); + if (!cert->public_key) { return FALSE; } @@ -1249,216 +1503,355 @@ static bool generate(private_builder_t *this) else { /* self signed */ issuer = subject; - if (!this->cert->public_key) + if (!cert->public_key) { - this->cert->public_key = this->sign_key->get_public_key(this->sign_key); + cert->public_key = sign_key->get_public_key(sign_key); } - this->flags |= X509_SELF_SIGNED; + cert->flags |= X509_SELF_SIGNED; } - this->cert->issuer = issuer->clone(issuer); - if (!this->cert->notBefore) + cert->issuer = issuer->clone(issuer); + if (!cert->notBefore) { - this->cert->notBefore = time(NULL); + cert->notBefore = time(NULL); } - if (!this->cert->notAfter) - { /* defaults to 1 years from now on */ - this->cert->notAfter = this->cert->notBefore + 60 * 60 * 24 * 365; + if (!cert->notAfter) + { /* defaults to 1 year from now */ + cert->notAfter = cert->notBefore + 60 * 60 * 24 * 365; } - this->cert->flags = this->flags; - - switch (this->sign_key->get_type(this->sign_key)) + + /* select signature scheme */ + cert->algorithm = hasher_signature_algorithm_to_oid(digest_alg, + sign_key->get_type(sign_key)); + if (cert->algorithm == OID_UNKNOWN) { - case KEY_RSA: - this->cert->algorithm = OID_SHA1_WITH_RSA; - scheme = SIGN_RSA_EMSA_PKCS1_SHA1; - break; - default: - return FALSE; + return FALSE; } - - switch (this->cert->public_key->get_type(this->cert->public_key)) + scheme = signature_scheme_from_oid(cert->algorithm); + + if (!cert->public_key->get_encoding(cert->public_key, + KEY_PUB_SPKI_ASN1_DER, &key_info)) { - case KEY_RSA: - key = this->cert->public_key->get_encoding(this->cert->public_key); - key_info = asn1_wrap(ASN1_SEQUENCE, "cm", - asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), - asn1_bitstring("m", key)); - break; - default: - return FALSE; + return FALSE; + } + + /* encode subjectAltNames */ + subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames); + + /* encode CRL distribution points extension */ + enumerator = cert->crl_uris->create_enumerator(cert->crl_uris); + while (enumerator->enumerate(enumerator, &uri)) + { + chunk_t distributionPoint; + + distributionPoint = asn1_wrap(ASN1_SEQUENCE, "m", + asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_CONTEXT_C_0, "m", + asn1_wrap(ASN1_CONTEXT_S_6, "c", + chunk_create(uri, strlen(uri)))))); + + crlDistributionPoints = chunk_cat("mm", crlDistributionPoints, + distributionPoint); + } + enumerator->destroy(enumerator); + if (crlDistributionPoints.ptr) + { + crlDistributionPoints = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_CRL_DISTRIBUTION_POINTS), + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints))); + } + + /* encode OCSP URIs in authorityInfoAccess extension */ + enumerator = cert->ocsp_uris->create_enumerator(cert->ocsp_uris); + while (enumerator->enumerate(enumerator, &uri)) + { + chunk_t accessDescription; + + accessDescription = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_OCSP), + asn1_wrap(ASN1_CONTEXT_S_6, "c", + chunk_create(uri, strlen(uri)))); + authorityInfoAccess = chunk_cat("mm", authorityInfoAccess, + accessDescription); + } + enumerator->destroy(enumerator); + if (authorityInfoAccess.ptr) + { + authorityInfoAccess = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_AUTHORITY_INFO_ACCESS), + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_SEQUENCE, "m", authorityInfoAccess))); + } + + /* build CA basicConstraint for CA certificates */ + if (cert->flags & X509_CA) + { + chunk_t pathLenConstraint = chunk_empty; + + if (cert->pathLenConstraint != X509_NO_PATH_LEN_CONSTRAINT) + { + char pathlen = (char)cert->pathLenConstraint; + + pathLenConstraint = asn1_integer("c", chunk_from_thing(pathlen)); + } + basicConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm", + asn1_build_known_oid(OID_BASIC_CONSTRAINTS), + asn1_wrap(ASN1_BOOLEAN, "c", + chunk_from_chars(0xFF)), + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_wrap(ASN1_BOOLEAN, "c", + chunk_from_chars(0xFF)), + pathLenConstraint))); + } + + /* add serverAuth extendedKeyUsage flag */ + if (cert->flags & X509_SERVER_AUTH) + { + serverAuth = asn1_build_known_oid(OID_SERVER_AUTH); + } + if (cert->flags & X509_CLIENT_AUTH) + { + clientAuth = asn1_build_known_oid(OID_CLIENT_AUTH); + } + + /* add ocspSigning extendedKeyUsage flag */ + if (cert->flags & X509_OCSP_SIGNER) + { + ocspSigning = asn1_build_known_oid(OID_OCSP_SIGNING); + } + + if (serverAuth.ptr || clientAuth.ptr || ocspSigning.ptr) + { + extendedKeyUsage = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_EXTENDED_KEY_USAGE), + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_SEQUENCE, "mmm", + serverAuth, clientAuth, ocspSigning))); + } + + /* add subjectKeyIdentifier to CA and OCSP signer certificates */ + if (cert->flags & (X509_CA | X509_OCSP_SIGNER)) + { + chunk_t keyid; + + if (cert->public_key->get_fingerprint(cert->public_key, + KEY_ID_PUBKEY_SHA1, &keyid)) + { + subjectKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_SUBJECT_KEY_ID), + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_OCTET_STRING, "c", keyid))); + } + } + + /* add the keyid authKeyIdentifier for non self-signed certificates */ + if (sign_key) + { + chunk_t keyid; + + if (sign_key->get_fingerprint(sign_key, KEY_ID_PUBKEY_SHA1, &keyid)) + { + authKeyIdentifier = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_AUTHORITY_KEY_ID), + asn1_wrap(ASN1_OCTET_STRING, "m", + asn1_wrap(ASN1_SEQUENCE, "m", + asn1_wrap(ASN1_CONTEXT_S_0, "c", keyid)))); + } } - - if (this->cert->subjectAltNames->get_count(this->cert->subjectAltNames)) + if (basicConstraints.ptr || subjectAltNames.ptr || authKeyIdentifier.ptr || + crlDistributionPoints.ptr) { - /* TODO: encode subjectAltNames */ + extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m", + asn1_wrap(ASN1_SEQUENCE, "mmmmmmm", + basicConstraints, subjectKeyIdentifier, + authKeyIdentifier, subjectAltNames, + extendedKeyUsage, crlDistributionPoints, + authorityInfoAccess)); } - - this->cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm", + + cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm", asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2), - asn1_integer("c", this->cert->serialNumber), - asn1_algorithmIdentifier(this->cert->algorithm), + asn1_integer("c", cert->serialNumber), + asn1_algorithmIdentifier(cert->algorithm), issuer->get_encoding(issuer), asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_from_time(&this->cert->notBefore, ASN1_UTCTIME), - asn1_from_time(&this->cert->notAfter, ASN1_UTCTIME)), + asn1_from_time(&cert->notBefore, ASN1_UTCTIME), + asn1_from_time(&cert->notAfter, ASN1_UTCTIME)), subject->get_encoding(subject), key_info, extensions); - - if (!this->sign_key->sign(this->sign_key, scheme, - this->cert->tbsCertificate, &this->cert->signature)) + + if (!sign_key->sign(sign_key, scheme, cert->tbsCertificate, &cert->signature)) { return FALSE; } - this->cert->encoding = asn1_wrap(ASN1_SEQUENCE, "ccm", - this->cert->tbsCertificate, - asn1_algorithmIdentifier(this->cert->algorithm), - asn1_bitstring("c", this->cert->signature)); - + cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", cert->tbsCertificate, + asn1_algorithmIdentifier(cert->algorithm), + asn1_bitstring("c", cert->signature)); + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher) { return FALSE; } - hasher->allocate_hash(hasher, this->cert->encoding, - &this->cert->encoding_hash); + hasher->allocate_hash(hasher, cert->encoding, &cert->encoding_hash); hasher->destroy(hasher); return TRUE; } /** - * Implementation of builder_t.build + * See header. */ -static private_x509_cert_t *build(private_builder_t *this) +x509_cert_t *x509_cert_load(certificate_type_t type, va_list args) { - private_x509_cert_t *cert; - - if (this->cert) + x509_flag_t flags = 0; + chunk_t blob = chunk_empty; + + while (TRUE) { - this->cert->flags |= this->flags; - if (!this->cert->encoding.ptr) - { /* generate a new certificate */ - if (!this->sign_key || !generate(this)) - { - destroy(this->cert); - free(this); + switch (va_arg(args, builder_part_t)) + { + 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) + { + private_x509_cert_t *cert = create_empty(); + + cert->encoding = chunk_clone(blob); + cert->parsed = TRUE; + if (parse_certificate(cert)) + { + cert->flags |= flags; + return &cert->public; + } + destroy(cert); } - cert = this->cert; - free(this); - return cert; + return NULL; } /** - * Implementation of builder_t.add + * See header. */ -static void add(private_builder_t *this, builder_part_t part, ...) +x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args) { - va_list args; - chunk_t chunk; - bool handled = TRUE; - - va_start(args, part); - switch (part) + private_x509_cert_t *cert; + certificate_t *sign_cert = NULL; + private_key_t *sign_key = NULL; + hash_algorithm_t digest_alg = HASH_SHA1; + + cert = create_empty(); + while (TRUE) { - case BUILD_FROM_FILE: - this->cert = create_from_file(va_arg(args, char*)); - break; - case BUILD_BLOB_ASN1_DER: - chunk = va_arg(args, chunk_t); - this->cert = create_from_chunk(chunk_clone(chunk)); - break; - case BUILD_X509_FLAG: - this->flags = va_arg(args, x509_flag_t); - break; - case BUILD_SIGNING_KEY: - this->sign_key = va_arg(args, private_key_t*); - break; - case BUILD_SIGNING_CERT: - this->sign_cert = va_arg(args, certificate_t*); - break; - default: - /* all other parts need an empty cert */ - if (!this->cert) + switch (va_arg(args, builder_part_t)) + { + case BUILD_X509_FLAG: + cert->flags |= va_arg(args, x509_flag_t); + continue; + case BUILD_SIGNING_KEY: + sign_key = va_arg(args, private_key_t*); + continue; + case BUILD_SIGNING_CERT: + sign_cert = va_arg(args, certificate_t*); + continue; + case BUILD_PUBLIC_KEY: + cert->public_key = va_arg(args, public_key_t*); + cert->public_key->get_ref(cert->public_key); + continue; + case BUILD_SUBJECT: + cert->subject = va_arg(args, identification_t*); + cert->subject = cert->subject->clone(cert->subject); + continue; + case BUILD_SUBJECT_ALTNAMES: { - this->cert = create_empty(); + enumerator_t *enumerator; + identification_t *id; + linked_list_t *list; + + list = va_arg(args, linked_list_t*); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &id)) + { + cert->subjectAltNames->insert_last(cert->subjectAltNames, + id->clone(id)); + } + enumerator->destroy(enumerator); + continue; } - handled = FALSE; - break; - } - if (handled) - { - va_end(args); - return; - } - - switch (part) - { - case BUILD_PUBLIC_KEY: - { - public_key_t *key = va_arg(args, public_key_t*); - this->cert->public_key = key->get_ref(key); - break; - } - case BUILD_SUBJECT: - { - identification_t *id = va_arg(args, identification_t*); - this->cert->subject = id->clone(id); - break; - } - case BUILD_SUBJECT_ALTNAME: - { - identification_t *id = va_arg(args, identification_t*); - this->cert->subjectAltNames->insert_last( - this->cert->subjectAltNames, id->clone(id)); - break; - } - case BUILD_NOT_BEFORE_TIME: - this->cert->notBefore = va_arg(args, time_t); - break; - case BUILD_NOT_AFTER_TIME: - this->cert->notAfter = va_arg(args, time_t); - break; - case BUILD_SERIAL: - { - chunk_t serial = va_arg(args, chunk_t); - this->cert->serialNumber = chunk_clone(serial); - break; - } - default: - /* abort if unsupported option */ - if (this->cert) + case BUILD_CRL_DISTRIBUTION_POINTS: { - destroy(this->cert); + enumerator_t *enumerator; + linked_list_t *list; + char *uri; + + list = va_arg(args, linked_list_t*); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &uri)) + { + cert->crl_uris->insert_last(cert->crl_uris, strdup(uri)); + } + enumerator->destroy(enumerator); + continue; } - builder_cancel(&this->public); - break; + case BUILD_OCSP_ACCESS_LOCATIONS: + { + enumerator_t *enumerator; + linked_list_t *list; + char *uri; + + list = va_arg(args, linked_list_t*); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &uri)) + { + cert->ocsp_uris->insert_last(cert->ocsp_uris, strdup(uri)); + } + enumerator->destroy(enumerator); + continue; + } + case BUILD_PATHLEN: + cert->pathLenConstraint = va_arg(args, int); + if (cert->pathLenConstraint < 0 || cert->pathLenConstraint > 127) + { + cert->pathLenConstraint = X509_NO_PATH_LEN_CONSTRAINT; + } + continue; + case BUILD_NOT_BEFORE_TIME: + cert->notBefore = va_arg(args, time_t); + continue; + case BUILD_NOT_AFTER_TIME: + cert->notAfter = va_arg(args, time_t); + continue; + case BUILD_SERIAL: + cert->serialNumber = chunk_clone(va_arg(args, chunk_t)); + continue; + case BUILD_DIGEST_ALG: + digest_alg = va_arg(args, int); + continue; + case BUILD_END: + break; + default: + destroy(cert); + return NULL; + } + break; } - va_end(args); -} -/** - * Builder construction function - */ -builder_t *x509_cert_builder(certificate_type_t type) -{ - private_builder_t *this; - - if (type != CERT_X509) + if (sign_key && generate(cert, sign_cert, sign_key, digest_alg)) { - return NULL; + return &cert->public; } - - this = malloc_thing(private_builder_t); - - this->cert = NULL; - this->flags = 0; - this->sign_cert = NULL; - this->sign_key = NULL; - this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; - this->public.build = (void*(*)(builder_t *this))build; - - return &this->public; + destroy(cert); + return NULL; } diff --git a/src/libstrongswan/plugins/x509/x509_cert.h b/src/libstrongswan/plugins/x509/x509_cert.h index 5ebe1567d..772117f1c 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.h +++ b/src/libstrongswan/plugins/x509/x509_cert.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ typedef struct x509_cert_t x509_cert_t; +#include <credentials/builder.h> #include <credentials/certificates/x509.h> /** @@ -37,11 +38,29 @@ struct x509_cert_t { }; /** - * Create the building facility for x509 certificates + * Load a X.509 certificate. + * + * This function takes a BUILD_BLOB_ASN1_DER. + * + * @param type certificate type, CERT_X509 only + * @param args builder_part_t argument list + * @return X.509 certificate, NULL on failure + */ +x509_cert_t *x509_cert_load(certificate_type_t type, va_list args); + +/** + * Generate a X.509 certificate. + * + * To issue a self-signed certificate, the function takes: + * BUILD_SUBJECT, BUILD_SUBJECT_ALTNAMES, BUILD_SIGNING_KEY, BUILD_X509_FLAG, + * BUILD_NOT_BEFORE_TIME, BUILD_NOT_AFTER_TIME, BUILD_SERIAL, BUILD_DIGEST_ALG. + * To issue certificates from a CA, additionally pass: + * BUILD_SIGNING_CERT and BUILD_PUBLIC_KEY. * * @param type certificate type, CERT_X509 only - * @return builder instance to build certificate + * @param args builder_part_t argument list + * @return X.509 certificate, NULL on failure */ -builder_t *x509_cert_builder(certificate_type_t type); +x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args); #endif /** X509_CERT_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c index f502668cb..b9ef3218b 100644 --- a/src/libstrongswan/plugins/x509/x509_crl.c +++ b/src/libstrongswan/plugins/x509/x509_crl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ typedef struct revoked_t revoked_t; #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/asn1_parser.h> -#include <asn1/pem.h> #include <credentials/certificates/x509.h> #include <utils/linked_list.h> @@ -37,12 +36,12 @@ struct revoked_t { * serial of the revoked certificate */ chunk_t serial; - + /** * date of revocation */ time_t date; - + /** * reason for revocation */ @@ -58,7 +57,7 @@ struct private_x509_crl_t { * public functions */ x509_crl_t public; - + /** * X.509 crl encoding in ASN.1 DER format */ @@ -73,12 +72,12 @@ struct private_x509_crl_t { * Version of the X.509 crl */ u_int version; - + /** * ID representing the crl issuer */ identification_t *issuer; - + /** * CRL number */ @@ -98,27 +97,27 @@ struct private_x509_crl_t { * list of revoked certificates as revoked_t */ linked_list_t *revoked; - + /** * Authority Key Identifier */ - identification_t *authKeyIdentifier; + chunk_t authKeyIdentifier; /** * Authority Key Serial Number */ chunk_t authKeySerialNumber; - + /** * Signature algorithm */ int algorithm; - + /** * Signature */ chunk_t signature; - + /** * reference counter */ @@ -128,8 +127,8 @@ struct private_x509_crl_t { /** * from x509_cert */ -extern identification_t* x509_parse_authorityKeyIdentifier( - chunk_t blob, int level0, +extern chunk_t x509_parse_authorityKeyIdentifier( + chunk_t blob, int level0, chunk_t *authKeySerialNumber); /** @@ -141,7 +140,7 @@ static const asn1Object_t crlObjects[] = { { 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, "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 */ @@ -151,7 +150,7 @@ static const asn1Object_t crlObjects[] = { { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | - ASN1_LOOP }, /* 12 */ + ASN1_LOOP }, /* 12 */ { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | @@ -239,7 +238,7 @@ static bool parse(private_x509_crl_t *this) revoked = malloc_thing(revoked_t); revoked->serial = userCertificate; revoked->date = asn1_parse_time(object, level); - revoked->reason = CRL_UNSPECIFIED; + revoked->reason = CRL_REASON_UNSPECIFIED; this->revoked->insert_last(this->revoked, (void *)revoked); break; case CRL_OBJ_CRL_ENTRY_EXTN_ID: @@ -269,7 +268,7 @@ static bool parse(private_x509_crl_t *this) { this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, - level, &this->authKeySerialNumber); + level, &this->authKeySerialNumber); } else if (extn_oid == OID_CRL_NUMBER) { @@ -338,17 +337,18 @@ static chunk_t get_serial(private_x509_crl_t *this) /** * Implementation of crl_t.get_authKeyIdentifier. */ -static identification_t* get_authKeyIdentifier(private_x509_crl_t *this) +static chunk_t get_authKeyIdentifier(private_x509_crl_t *this) { return this->authKeyIdentifier; } + /** * Implementation of crl_t.create_enumerator. */ static enumerator_t* create_enumerator(private_x509_crl_t *this) { return enumerator_create_filter( - this->revoked->create_enumerator(this->revoked), + this->revoked->create_enumerator(this->revoked), (void*)filter, NULL, NULL); } @@ -373,24 +373,12 @@ static identification_t* get_issuer(private_x509_crl_t *this) */ static id_match_t has_issuer(private_x509_crl_t *this, identification_t *issuer) { - id_match_t match; - - if (issuer->get_type(issuer) == ID_PUBKEY_SHA1) - { - if (this->authKeyIdentifier) - { - match = issuer->matches(issuer, this->authKeyIdentifier); - } - else - { - match = ID_MATCH_NONE; - } - } - else + if (issuer->get_type(issuer) == ID_KEY_ID && this->authKeyIdentifier.ptr && + chunk_equals(this->authKeyIdentifier, issuer->get_encoding(issuer))) { - match = this->issuer->matches(this->issuer, issuer); + return ID_MATCH_PERFECT; } - return match; + return this->issuer->matches(this->issuer, issuer); } /** @@ -402,7 +390,7 @@ static bool issued_by(private_x509_crl_t *this, certificate_t *issuer) signature_scheme_t scheme; bool valid; x509_t *x509 = (x509_t*)issuer; - + /* check if issuer is an X.509 CA certificate */ if (issuer->get_type(issuer) != CERT_X509) { @@ -417,17 +405,17 @@ static bool issued_by(private_x509_crl_t *this, certificate_t *issuer) key = issuer->get_public_key(issuer); /* compare keyIdentifiers if available, otherwise use DNs */ - if (this->authKeyIdentifier && key) + if (this->authKeyIdentifier.ptr && key) { - identification_t *subjectKeyIdentifier = key->get_id(key, ID_PUBKEY_SHA1); + chunk_t fingerprint; - if (!subjectKeyIdentifier->equals(subjectKeyIdentifier, - this->authKeyIdentifier)) + if (!key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &fingerprint) || + !chunk_equals(fingerprint, this->authKeyIdentifier)) { return FALSE; } } - else + else { if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) { @@ -470,16 +458,8 @@ static private_x509_crl_t* get_ref(private_x509_crl_t *this) static bool get_validity(private_x509_crl_t *this, time_t *when, time_t *not_before, time_t *not_after) { - time_t t; - - if (when) - { - t = *when; - } - else - { - t = time(NULL); - } + time_t t = when ? *when : time(NULL); + if (not_before) { *not_before = this->thisUpdate; @@ -498,7 +478,7 @@ static bool is_newer(private_x509_crl_t *this, crl_t *that) { chunk_t that_crlNumber = that->get_serial(that); bool new; - + /* compare crlNumbers if available - otherwise use thisUpdate */ if (this->crlNumber.ptr != NULL && that_crlNumber.ptr != NULL) { @@ -507,7 +487,7 @@ static bool is_newer(private_x509_crl_t *this, crl_t *that) &this->crlNumber, new ? "newer":"not newer", &that_crlNumber, new ? "replaced":"retained"); } - else + else { certificate_t *this_cert = &this->public.crl.certificate; certificate_t *that_cert = &that->certificate; @@ -523,7 +503,7 @@ static bool is_newer(private_x509_crl_t *this, crl_t *that) } return new; } - + /** * Implementation of certificate_t.get_encoding. */ @@ -539,14 +519,14 @@ static bool equals(private_x509_crl_t *this, certificate_t *other) { chunk_t encoding; bool equal; - + if ((certificate_t*)this == other) { return TRUE; } if (other->equals == (void*)equals) { /* skip allocation if we have the same implementation */ - return chunk_equals(this->encoding, ((private_x509_crl_t*)other)->encoding); + return chunk_equals(this->encoding, ((private_x509_crl_t*)other)->encoding); } encoding = other->get_encoding(other); equal = chunk_equals(this->encoding, encoding); @@ -563,7 +543,7 @@ static void destroy(private_x509_crl_t *this) { this->revoked->destroy_function(this->revoked, free); DESTROY_IF(this->issuer); - DESTROY_IF(this->authKeyIdentifier); + free(this->authKeyIdentifier.ptr); free(this->encoding.ptr); free(this); } @@ -575,9 +555,9 @@ static void destroy(private_x509_crl_t *this) static private_x509_crl_t* create_empty(void) { private_x509_crl_t *this = malloc_thing(private_x509_crl_t); - + this->public.crl.get_serial = (chunk_t (*)(crl_t*))get_serial; - this->public.crl.get_authKeyIdentifier = (identification_t* (*)(crl_t*))get_authKeyIdentifier; + this->public.crl.get_authKeyIdentifier = (chunk_t (*)(crl_t*))get_authKeyIdentifier; this->public.crl.create_enumerator = (enumerator_t* (*)(crl_t*))create_enumerator; this->public.crl.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; this->public.crl.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_issuer; @@ -592,138 +572,51 @@ static private_x509_crl_t* create_empty(void) this->public.crl.certificate.equals = (bool (*)(certificate_t*, certificate_t *other))equals; this->public.crl.certificate.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; this->public.crl.certificate.destroy = (void (*)(certificate_t *this))destroy; - + this->encoding = chunk_empty; this->tbsCertList = chunk_empty; this->issuer = NULL; this->crlNumber = chunk_empty; this->revoked = linked_list_create(); - this->authKeyIdentifier = NULL; + this->authKeyIdentifier = chunk_empty; this->authKeySerialNumber = chunk_empty; this->ref = 1; - - return this; -} -/** - * create an X.509 crl from a chunk - */ -static private_x509_crl_t* create_from_chunk(chunk_t chunk) -{ - private_x509_crl_t *this = create_empty(); - - this->encoding = chunk; - if (!parse(this)) - { - destroy(this); - return NULL; - } return this; } /** - * create an X.509 crl from a file + * See header. */ -static private_x509_crl_t* create_from_file(char *path) +x509_crl_t *x509_crl_load(certificate_type_t type, va_list args) { - bool pgp = FALSE; - chunk_t chunk; - private_x509_crl_t *this; - - if (!pem_asn1_load_file(path, NULL, &chunk, &pgp)) - { - return NULL; - } - - this = create_from_chunk(chunk); - - if (this == NULL) - { - DBG1(" could not parse loaded crl file '%s'",path); - return NULL; - } - DBG1(" loaded crl file '%s'", path); - return this; -} + chunk_t blob = chunk_empty; -typedef struct private_builder_t private_builder_t; -/** - * Builder implementation for certificate loading - */ -struct private_builder_t { - /** implements the builder interface */ - builder_t public; - /** loaded CRL */ - private_x509_crl_t *crl; -}; - -/** - * Implementation of builder_t.build - */ -static private_x509_crl_t *build(private_builder_t *this) -{ - private_x509_crl_t *crl = this->crl; - - free(this); - return crl; -} - -/** - * Implementation of builder_t.add - */ -static void add(private_builder_t *this, builder_part_t part, ...) -{ - if (!this->crl) + while (TRUE) { - va_list args; - chunk_t chunk; - - switch (part) + switch (va_arg(args, builder_part_t)) { - case BUILD_FROM_FILE: - { - va_start(args, part); - this->crl = create_from_file(va_arg(args, char*)); - va_end(args); - return; - } case BUILD_BLOB_ASN1_DER: - { - va_start(args, part); - chunk = va_arg(args, chunk_t); - this->crl = create_from_chunk(chunk_clone(chunk)); - va_end(args); - return; - } - default: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: break; + default: + return NULL; } + break; } - if (this->crl) + if (blob.ptr) { - destroy(this->crl); - } - builder_cancel(&this->public); -} + private_x509_crl_t *crl = create_empty(); -/** - * Builder construction function - */ -builder_t *x509_crl_builder(certificate_type_t type) -{ - private_builder_t *this; - - if (type != CERT_X509_CRL) - { - return NULL; + crl->encoding = chunk_clone(blob); + if (parse(crl)) + { + return &crl->public; + } + destroy(crl); } - - this = malloc_thing(private_builder_t); - - this->crl = NULL; - this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; - this->public.build = (void*(*)(builder_t *this))build; - - return &this->public; -} + return NULL; +}; diff --git a/src/libstrongswan/plugins/x509/x509_crl.h b/src/libstrongswan/plugins/x509/x509_crl.h index daa8e4846..890650162 100644 --- a/src/libstrongswan/plugins/x509/x509_crl.h +++ b/src/libstrongswan/plugins/x509/x509_crl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ typedef struct x509_crl_t x509_crl_t; +#include <credentials/builder.h> #include <credentials/certificates/crl.h> /** @@ -36,13 +37,13 @@ struct x509_crl_t { crl_t crl; }; - /** - * Create the building facility for x509 certificate revocation lists. + * Load a X.509 CRL. * * @param type certificate type, CERT_X509_CRL only - * @return builder instance to build certificate + * @param args builder_part_t argument list + * @return X.509 CRL, NULL on failure */ -builder_t *x509_crl_builder(certificate_type_t type); +x509_crl_t *x509_crl_load(certificate_type_t type, va_list args); #endif /** X509_CRL_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_request.c b/src/libstrongswan/plugins/x509/x509_ocsp_request.c index 4020d8d95..f86f87751 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_request.c +++ b/src/libstrongswan/plugins/x509/x509_ocsp_request.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Copyright (C) 2007 Andreas Steffen * Hochschule fuer Technik Rapperswil * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen @@ -39,12 +39,12 @@ struct private_x509_ocsp_request_t { * public functions */ x509_ocsp_request_t public; - + /** * CA the candidates belong to */ x509_t *ca; - + /** * Requestor name, subject of cert used if not set */ @@ -54,56 +54,50 @@ struct private_x509_ocsp_request_t { * Requestor certificate, included in request */ certificate_t *cert; - + /** * Requestor private key to sign request */ private_key_t *key; - + /** * list of certificates to check, x509_t */ linked_list_t *candidates; - + /** * nonce used in request */ chunk_t nonce; - + /** * encoded OCSP request */ chunk_t encoding; - + /** * reference count */ refcount_t ref; }; -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 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 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_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); -static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); -static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); +); /** * build requestorName @@ -120,7 +114,7 @@ static chunk_t build_requestorName(private_x509_ocsp_request_t *this) return asn1_wrap(ASN1_CONTEXT_C_1, "m", asn1_simple_object(ASN1_CONTEXT_C_4, this->requestor->get_encoding(this->requestor))); - + } return chunk_empty; } @@ -133,7 +127,7 @@ static chunk_t build_Request(private_x509_ocsp_request_t *this, chunk_t serialNumber) { return asn1_wrap(ASN1_SEQUENCE, "m", - asn1_wrap(ASN1_SEQUENCE, "cmmm", + asn1_wrap(ASN1_SEQUENCE, "mmmm", asn1_algorithmIdentifier(OID_SHA1), asn1_simple_object(ASN1_OCTET_STRING, issuerNameHash), asn1_simple_object(ASN1_OCTET_STRING, issuerKeyHash), @@ -151,7 +145,7 @@ static chunk_t build_requestList(private_x509_ocsp_request_t *this) certificate_t *cert; chunk_t list = chunk_empty; public_key_t *public; - + cert = (certificate_t*)this->ca; public = cert->get_public_key(cert); if (public) @@ -159,23 +153,21 @@ static chunk_t build_requestList(private_x509_ocsp_request_t *this) hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (hasher) { - identification_t *keyid = public->get_id(public, ID_PUBKEY_SHA1); - if (keyid) + if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, + &issuerKeyHash)) { enumerator_t *enumerator; - - issuerKeyHash = keyid->get_encoding(keyid); - + issuer = cert->get_subject(cert); hasher->allocate_hash(hasher, issuer->get_encoding(issuer), &issuerNameHash); hasher->destroy(hasher); - + enumerator = this->candidates->create_enumerator(this->candidates); while (enumerator->enumerate(enumerator, &x509)) { chunk_t request, serialNumber; - + serialNumber = x509->get_serial(x509); request = build_Request(this, issuerNameHash, issuerKeyHash, serialNumber); @@ -204,7 +196,7 @@ static chunk_t build_requestList(private_x509_ocsp_request_t *this) static chunk_t build_nonce(private_x509_ocsp_request_t *this) { rng_t *rng; - + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); if (rng) { @@ -232,7 +224,7 @@ static chunk_t build_acceptableResponses(private_x509_ocsp_request_t *this) */ static chunk_t build_requestExtensions(private_x509_ocsp_request_t *this) { - return asn1_wrap(ASN1_CONTEXT_C_2, "m", + return asn1_wrap(ASN1_CONTEXT_C_2, "m", asn1_wrap(ASN1_SEQUENCE, "mm", build_nonce(this), build_acceptableResponses(this))); @@ -258,7 +250,7 @@ static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this, int oid; signature_scheme_t scheme; chunk_t certs, signature; - + switch (this->key->get_type(this->key)) { /* TODO: use a generic mapping function */ @@ -268,14 +260,14 @@ static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this, break; case KEY_ECDSA: oid = OID_ECDSA_WITH_SHA1; - scheme = SIGN_ECDSA_WITH_SHA1; + scheme = SIGN_ECDSA_WITH_SHA1_DER; break; default: DBG1("unable to sign OCSP request, %N signature not supported", key_type_names, this->key->get_type(this->key)); return chunk_empty; } - + if (!this->key->sign(this->key, scheme, tbsRequest, &signature)) { DBG1("creating OCSP signature failed, skipped"); @@ -288,7 +280,7 @@ static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this, this->cert->get_encoding(this->cert))); } return asn1_wrap(ASN1_CONTEXT_C_0, "m", - asn1_wrap(ASN1_SEQUENCE, "cmm", + asn1_wrap(ASN1_SEQUENCE, "cmm", asn1_algorithmIdentifier(oid), asn1_bitstring("m", signature), certs)); @@ -301,7 +293,7 @@ static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this, static chunk_t build_OCSPRequest(private_x509_ocsp_request_t *this) { chunk_t tbsRequest, optionalSignature = chunk_empty; - + tbsRequest = build_tbsRequest(this); if (this->key) { @@ -325,7 +317,7 @@ static certificate_type_t get_type(private_x509_ocsp_request_t *this) static identification_t* get_subject(private_x509_ocsp_request_t *this) { certificate_t *ca = (certificate_t*)this->ca; - + if (this->requestor) { return this->requestor; @@ -343,7 +335,7 @@ static identification_t* get_subject(private_x509_ocsp_request_t *this) static identification_t* get_issuer(private_x509_ocsp_request_t *this) { certificate_t *ca = (certificate_t*)this->ca; - + return ca->get_subject(ca); } @@ -363,11 +355,11 @@ static id_match_t has_subject(private_x509_ocsp_request_t *this, match = current->has_subject(current, subject); if (match > best) { - best = match; + best = match; } } enumerator->destroy(enumerator); - return best; + return best; } /** @@ -416,7 +408,7 @@ static bool get_validity(private_x509_ocsp_request_t *this, time_t *when, } return cert->get_validity(cert, when, not_before, not_after); } - + /** * Implementation of certificate_t.get_encoding. */ @@ -432,7 +424,7 @@ static bool equals(private_x509_ocsp_request_t *this, certificate_t *other) { chunk_t encoding; bool equal; - + if (this == (private_x509_ocsp_request_t*)other) { return TRUE; @@ -443,7 +435,7 @@ static bool equals(private_x509_ocsp_request_t *this, certificate_t *other) } if (other->equals == (void*)equals) { /* skip allocation if we have the same implementation */ - return chunk_equals(this->encoding, ((private_x509_ocsp_request_t*)other)->encoding); + return chunk_equals(this->encoding, ((private_x509_ocsp_request_t*)other)->encoding); } encoding = other->get_encoding(other); equal = chunk_equals(this->encoding, encoding); @@ -484,7 +476,7 @@ static void destroy(private_x509_ocsp_request_t *this) static private_x509_ocsp_request_t *create_empty() { private_x509_ocsp_request_t *this = malloc_thing(private_x509_ocsp_request_t); - + this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type; this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject; this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; @@ -497,7 +489,7 @@ static private_x509_ocsp_request_t *create_empty() this->public.interface.interface.equals = (bool(*)(certificate_t*, certificate_t *other))equals; this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref; this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy; - + this->ca = NULL; this->requestor = NULL; this->cert = NULL; @@ -506,30 +498,60 @@ static private_x509_ocsp_request_t *create_empty() this->encoding = chunk_empty; this->candidates = linked_list_create(); this->ref = 1; - + return this; } -typedef struct private_builder_t private_builder_t; /** - * Builder implementation for certificate loading + * See header. */ -struct private_builder_t { - /** implements the builder interface */ - builder_t public; - /** OCSP request to build */ - private_x509_ocsp_request_t *req; -}; - -/** - * Implementation of builder_t.build - */ -static x509_ocsp_request_t *build(private_builder_t *this) +x509_ocsp_request_t *x509_ocsp_request_gen(certificate_type_t type, va_list args) { private_x509_ocsp_request_t *req; - - req = this->req; - free(this); + certificate_t *cert; + private_key_t *private; + identification_t *subject; + + req = create_empty(); + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_CA_CERT: + cert = va_arg(args, certificate_t*); + if (cert->get_type(cert) == CERT_X509) + { + req->ca = (x509_t*)cert->get_ref(cert); + } + continue; + case BUILD_CERT: + cert = va_arg(args, certificate_t*); + if (cert->get_type(cert) == CERT_X509) + { + req->candidates->insert_last(req->candidates, + cert->get_ref(cert)); + } + continue; + case BUILD_SIGNING_CERT: + cert = va_arg(args, certificate_t*); + req->cert = cert->get_ref(cert); + continue; + case BUILD_SIGNING_KEY: + private = va_arg(args, private_key_t*); + req->key = private->get_ref(private); + continue; + case BUILD_SUBJECT: + subject = va_arg(args, identification_t*); + req->requestor = subject->clone(subject); + continue; + case BUILD_END: + break; + default: + destroy(req); + return NULL; + } + break; + } if (req->ca) { req->encoding = build_OCSPRequest(req); @@ -539,76 +561,3 @@ static x509_ocsp_request_t *build(private_builder_t *this) return NULL; } -/** - * Implementation of builder_t.add - */ -static void add(private_builder_t *this, builder_part_t part, ...) -{ - va_list args; - certificate_t *cert; - identification_t *subject; - private_key_t *private; - - va_start(args, part); - switch (part) - { - case BUILD_CA_CERT: - cert = va_arg(args, certificate_t*); - if (cert->get_type(cert) == CERT_X509) - { - this->req->ca = (x509_t*)cert->get_ref(cert); - } - break; - case BUILD_CERT: - cert = va_arg(args, certificate_t*); - if (cert->get_type(cert) == CERT_X509) - { - this->req->candidates->insert_last(this->req->candidates, - cert->get_ref(cert)); - } - break; - case BUILD_SIGNING_CERT: - cert = va_arg(args, certificate_t*); - this->req->cert = cert->get_ref(cert); - break; - case BUILD_SIGNING_KEY: - private = va_arg(args, private_key_t*); - this->req->key = private->get_ref(private); - break; - case BUILD_SUBJECT: - subject = va_arg(args, identification_t*); - this->req->requestor = subject->clone(subject); - break; - default: - /* cancel if option not supported */ - if (this->req) - { - destroy(this->req); - } - builder_cancel(&this->public); - break; - } - va_end(args); -} - -/** - * Builder construction function - */ -builder_t *x509_ocsp_request_builder(certificate_type_t type) -{ - private_builder_t *this; - - if (type != CERT_X509_OCSP_REQUEST) - { - return NULL; - } - - this = malloc_thing(private_builder_t); - - this->req = create_empty(); - this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; - this->public.build = (void*(*)(builder_t *this))build; - - return &this->public; -} - diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_request.h b/src/libstrongswan/plugins/x509/x509_ocsp_request.h index ffaa3c634..4c0e4b8f2 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_request.h +++ b/src/libstrongswan/plugins/x509/x509_ocsp_request.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ #ifndef X509_OCSP_REQUEST_H_ #define X509_OCSP_REQUEST_H_ +#include <credentials/builder.h> #include <credentials/certificates/ocsp_request.h> typedef struct x509_ocsp_request_t x509_ocsp_request_t; @@ -37,7 +38,7 @@ struct x509_ocsp_request_t { }; /** - * Create the building facility for OCSP requests. + * Generate a X.509 OCSP request. * * The resulting builder accepts: * BUILD_CA_CERT: CA of the checked certificates, exactly one @@ -46,9 +47,10 @@ struct x509_ocsp_request_t { * BUILD_SIGNING_CERT: certificate to create requestor signature, optional * BUILD_SIGNING_KEY: private key to create requestor signature, optional * - * @param type certificate type, CERT_X509_OCSP_REQUEST only - * @return builder instance to build OCSP requests + * @param type certificate type, CERT_X509_OCSP_REQUEST only + * @param args builder_part_t argument list + * @return OCSP request, NULL on failure */ -builder_t *x509_ocsp_request_builder(certificate_type_t type); +x509_ocsp_request_t *x509_ocsp_request_gen(certificate_type_t type, va_list args); #endif /** X509_OCSP_REQUEST_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c index 1b3187258..948d7ad85 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_response.c +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Copyright (C) 2007 Andreas Steffen * Hochschule fuer Technik Rapperswil * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen @@ -45,42 +45,42 @@ struct private_x509_ocsp_response_t { * Public interface for this ocsp object. */ x509_ocsp_response_t public; - + /** * complete encoded OCSP response */ chunk_t encoding; - + /** * data for signature verficiation */ chunk_t tbsResponseData; - + /** * signature algorithm (OID) */ int signatureAlgorithm; - + /** * signature */ chunk_t signature; - + /** * name or keyid of the responder */ identification_t *responderId; - + /** * time of response production */ time_t producedAt; - + /** * latest nextUpdate in this OCSP response */ time_t usableUntil; - + /** * list of included certificates */ @@ -95,7 +95,7 @@ struct private_x509_ocsp_response_t { * Nonce required for ocsp request and response */ chunk_t nonce; - + /** * reference counter */ @@ -130,29 +130,23 @@ typedef struct { #define OCSP_BASIC_RESPONSE_VERSION 1 /* 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 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 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_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); -static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); -static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); +); /** * Implementaiton of ocsp_response_t.get_status @@ -167,14 +161,15 @@ static cert_validation_t get_status(private_x509_ocsp_response_t *this, single_response_t *response; cert_validation_t status = VALIDATION_FAILED; certificate_t *issuercert = &issuer->interface; - + enumerator = this->responses->create_enumerator(this->responses); while (enumerator->enumerate(enumerator, &response)) { hasher_t *hasher; identification_t *id; - chunk_t hash; - + key_encoding_type_t type; + chunk_t hash, fingerprint; + /* check serial first, is cheaper */ if (!chunk_equals(subject->get_serial(subject), response->serialNumber)) { @@ -184,22 +179,23 @@ static cert_validation_t get_status(private_x509_ocsp_response_t *this, if (response->issuerKeyHash.ptr) { public_key_t *public; - + public = issuercert->get_public_key(issuercert); if (!public) { continue; } switch (response->hashAlgorithm) - { /* TODO: generic mapper function */ + { case OID_SHA1: - id = public->get_id(public, ID_PUBKEY_SHA1); + type = KEY_ID_PUBKEY_SHA1; break; default: public->destroy(public); continue; } - if (!chunk_equals(response->issuerKeyHash, id->get_encoding(id))) + if (!public->get_fingerprint(public, type, &fingerprint) || + !chunk_equals(response->issuerKeyHash, fingerprint)) { public->destroy(public); continue; @@ -209,7 +205,7 @@ static cert_validation_t get_status(private_x509_ocsp_response_t *this, /* check issuerNameHash, if available */ else if (response->issuerNameHash.ptr) { - hasher = lib->crypto->create_hasher(lib->crypto, + hasher = lib->crypto->create_hasher(lib->crypto, hasher_algorithm_from_oid(response->hashAlgorithm)); if (!hasher) { @@ -233,7 +229,7 @@ static cert_validation_t get_status(private_x509_ocsp_response_t *this, *revocation_reason = response->revocationReason; *this_update = response->thisUpdate; *next_update = response->nextUpdate; - + break; } enumerator->destroy(enumerator); @@ -310,7 +306,7 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this, bool success = FALSE; single_response_t *response; - + response = malloc_thing(single_response_t); response->hashAlgorithm = OID_UNKNOWN; response->issuerNameHash = chunk_empty; @@ -318,7 +314,7 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this, response->serialNumber = chunk_empty; response->status = VALIDATION_FAILED; response->revocationTime = 0; - response->revocationReason = CRL_UNSPECIFIED; + response->revocationReason = CRL_REASON_UNSPECIFIED; response->thisUpdate = UNDEFINED_TIME; /* if nextUpdate is missing, we give it a short lifetime */ response->nextUpdate = this->producedAt + OCSP_DEFAULT_LIFETIME; @@ -357,7 +353,7 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this, { response->revocationReason = *object.ptr; } - break; + break; case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: response->status = VALIDATION_FAILED; break; @@ -370,7 +366,7 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this, { this->usableUntil = response->nextUpdate; } - break; + break; } } success = parser->success(parser); @@ -400,14 +396,14 @@ static const asn1Object_t responsesObjects[] = { /** * Parse all responses */ -static bool parse_responses(private_x509_ocsp_response_t *this, +static bool parse_responses(private_x509_ocsp_response_t *this, chunk_t blob, int level0) { asn1_parser_t *parser; chunk_t object; int objectID; bool success = FALSE; - + parser = asn1_parser_create(responsesObjects, blob); parser->set_top_level(parser, level0); @@ -484,7 +480,7 @@ static const asn1Object_t basicResponseObjects[] = { /** * Parse a basicOCSPResponse */ -static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, +static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, chunk_t blob, int level0) { asn1_parser_t *parser; @@ -496,7 +492,7 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, certificate_t *cert; bool success = FALSE; bool critical; - + parser = asn1_parser_create(basicResponseObjects, blob); parser->set_top_level(parser, level0); @@ -525,7 +521,7 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, break; case BASIC_RESPONSE_ID_BY_KEY: this->responderId = identification_create_from_encoding( - ID_PUBKEY_INFO_SHA1, object); + ID_KEY_ID, object); DBG2(" '%Y'", this->responderId); break; case BASIC_RESPONSE_PRODUCED_AT: @@ -622,15 +618,15 @@ static bool parse_OCSPResponse(private_x509_ocsp_response_t *this) case OCSP_RESPONSE_STATUS: status = (ocsp_status_t)*object.ptr; switch (status) - { - case OCSP_SUCCESSFUL: + { + case OCSP_SUCCESSFUL: break; default: DBG1(" ocsp response status: %N", ocsp_status_names, status); goto end; } - break; + break; case OCSP_RESPONSE_TYPE: responseType = asn1_known_oid(object); break; @@ -689,35 +685,33 @@ static bool issued_by(private_x509_ocsp_response_t *this, certificate_t *issuer) signature_scheme_t scheme; bool valid; x509_t *x509 = (x509_t*)issuer; - + if (issuer->get_type(issuer) != CERT_X509) { return FALSE; } - if (this->responderId->get_type(this->responderId) == ID_DER_ASN1_DN) + if (this->responderId->get_type(this->responderId) == ID_KEY_ID) { - if (!this->responderId->equals(this->responderId, - issuer->get_subject(issuer))) + chunk_t fingerprint; + + key = issuer->get_public_key(issuer); + if (!key || + !key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &fingerprint) || + !chunk_equals(fingerprint, + this->responderId->get_encoding(this->responderId))) { + DESTROY_IF(key); return FALSE; } + key->destroy(key); } else { - bool equal; - public_key_t *public = issuer->get_public_key(issuer); - - if (public == NULL) + if (!this->responderId->equals(this->responderId, + issuer->get_subject(issuer))) { return FALSE; } - equal = this->responderId->equals(this->responderId, - public->get_id(public, ID_PUBKEY_SHA1)); - public->destroy(public); - if (!equal) - { - return FALSE; - } } if (!(x509->get_flags(x509) & X509_OCSP_SIGNER) && !(x509->get_flags(x509) & X509_CA)) @@ -754,16 +748,8 @@ static public_key_t* get_public_key(private_x509_ocsp_response_t *this) static bool get_validity(private_x509_ocsp_response_t *this, time_t *when, time_t *not_before, time_t *not_after) { - time_t t; + time_t t = when ? *when : time(NULL); - if (when == NULL) - { - t = time(NULL); - } - else - { - t = *when; - } if (not_before) { *not_before = this->producedAt; @@ -791,7 +777,7 @@ static bool is_newer(certificate_t *this, certificate_t *that) &that_update, FALSE, new ? "replaced":"retained"); return new; } - + /** * Implementation of certificate_t.get_encoding. */ @@ -807,7 +793,7 @@ static bool equals(private_x509_ocsp_response_t *this, certificate_t *other) { chunk_t encoding; bool equal; - + if (this == (private_x509_ocsp_response_t*)other) { return TRUE; @@ -818,7 +804,7 @@ static bool equals(private_x509_ocsp_response_t *this, certificate_t *other) } if (other->equals == (void*)equals) { /* skip allocation if we have the same implementation */ - return chunk_equals(this->encoding, ((private_x509_ocsp_response_t*)other)->encoding); + return chunk_equals(this->encoding, ((private_x509_ocsp_response_t*)other)->encoding); } encoding = other->get_encoding(other); equal = chunk_equals(this->encoding, encoding); @@ -853,12 +839,12 @@ static void destroy(private_x509_ocsp_response_t *this) /** * load an OCSP response */ -static x509_ocsp_response_t *load(chunk_t data) +static x509_ocsp_response_t *load(chunk_t blob) { private_x509_ocsp_response_t *this; - + this = malloc_thing(private_x509_ocsp_response_t); - + this->public.interface.certificate.get_type = (certificate_type_t (*)(certificate_t *this))get_type; this->public.interface.certificate.get_subject = (identification_t* (*)(certificate_t *this))get_issuer; this->public.interface.certificate.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer; @@ -874,9 +860,9 @@ static x509_ocsp_response_t *load(chunk_t data) this->public.interface.certificate.destroy = (void (*)(certificate_t *this))destroy; this->public.interface.get_status = (cert_validation_t(*)(ocsp_response_t*, x509_t *subject, x509_t *issuer, time_t *revocation_time,crl_reason_t *revocation_reason,time_t *this_update, time_t *next_update))get_status; this->public.interface.create_cert_enumerator = (enumerator_t*(*)(ocsp_response_t*))create_cert_enumerator; - + this->ref = 1; - this->encoding = data; + this->encoding = chunk_clone(blob); this->tbsResponseData = chunk_empty; this->responderId = NULL; this->producedAt = UNDEFINED_TIME; @@ -895,78 +881,32 @@ static x509_ocsp_response_t *load(chunk_t data) return &this->public; } - -typedef struct private_builder_t private_builder_t; /** - * Builder implementation for certificate loading + * See header. */ -struct private_builder_t { - /** implements the builder interface */ - builder_t public; - /** loaded response */ - x509_ocsp_response_t *res; -}; - -/** - * Implementation of builder_t.build - */ -static x509_ocsp_response_t *build(private_builder_t *this) +x509_ocsp_response_t *x509_ocsp_response_load(certificate_type_t type, + va_list args) { - x509_ocsp_response_t *res = this->res; - - free(this); - return res; -} + chunk_t blob = chunk_empty; -/** - * Implementation of builder_t.add - */ -static void add(private_builder_t *this, builder_part_t part, ...) -{ - if (!this->res) + while (TRUE) { - va_list args; - chunk_t chunk; - - switch (part) + switch (va_arg(args, builder_part_t)) { case BUILD_BLOB_ASN1_DER: - { - va_start(args, part); - chunk = va_arg(args, chunk_t); - this->res = load(chunk_clone(chunk)); - va_end(args); - return; - } - default: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: break; + default: + return NULL; } + break; } - if (this->res) + if (blob.ptr) { - destroy((private_x509_ocsp_response_t*)this->res); + return load(blob); } - builder_cancel(&this->public); -} - -/** - * Builder construction function - */ -builder_t *x509_ocsp_response_builder(certificate_type_t type) -{ - private_builder_t *this; - - if (type != CERT_X509_OCSP_RESPONSE) - { - return NULL; - } - - this = malloc_thing(private_builder_t); - - this->res = NULL; - this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add; - this->public.build = (void*(*)(builder_t *this))build; - - return &this->public; + return NULL; } diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.h b/src/libstrongswan/plugins/x509/x509_ocsp_response.h index 06a9fd3c7..7a525626e 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_response.h +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ #ifndef X509_OCSP_RESPONSE_H_ #define X509_OCSP_RESPONSE_H_ +#include <credentials/builder.h> #include <credentials/certificates/ocsp_response.h> typedef struct x509_ocsp_response_t x509_ocsp_response_t; @@ -37,11 +38,13 @@ struct x509_ocsp_response_t { }; /** - * Create the building facility for OCSP responses. + * Load a X.509 OCSP response. * * @param type certificate type, CERT_X509_OCSP_RESPONSE only - * @return builder instance to build OCSP responses + * @param args builder_part_t argument list + * @return OCSP response, NULL on failure */ -builder_t *x509_ocsp_response_builder(certificate_type_t type); +x509_ocsp_response_t *x509_ocsp_response_load(certificate_type_t type, + va_list args); #endif /** X509_OCSP_RESPONSE_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.c b/src/libstrongswan/plugins/x509/x509_pkcs10.c new file mode 100644 index 000000000..6d750c98c --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_pkcs10.c @@ -0,0 +1,707 @@ +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Copyright (C) 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 "x509_pkcs10.h" + +#include <library.h> +#include <debug.h> +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <credentials/keys/private_key.h> +#include <utils/linked_list.h> +#include <utils/identification.h> + +typedef struct private_x509_pkcs10_t private_x509_pkcs10_t; + +/** + * Private data of a x509_pkcs10_t object. + */ +struct private_x509_pkcs10_t { + /** + * Public interface for this certificate. + */ + x509_pkcs10_t public; + + /** + * PKCS#10 certificate request encoding in ASN.1 DER format + */ + chunk_t encoding; + + /** + * PKCS#10 request body over which signature is computed + */ + chunk_t certificationRequestInfo; + + /** + * Version of the PKCS#10 certificate request + */ + u_int version; + + /** + * ID representing the certificate subject + */ + identification_t *subject; + + /** + * List of subjectAltNames as identification_t + */ + linked_list_t *subjectAltNames; + + /** + * certificate's embedded public key + */ + public_key_t *public_key; + + /** + * challenge password + */ + chunk_t challengePassword; + + /** + * Signature algorithm + */ + int algorithm; + + /** + * Signature + */ + chunk_t signature; + + /** + * Is the certificate request self-signed? + */ + bool self_signed; + + /** + * Certificate request parsed from blob/file? + */ + bool parsed; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * Imported from x509_cert.c + */ +extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list); +extern chunk_t x509_build_subjectAltNames(linked_list_t *list); + +/** + * Implementation of certificate_t.get_type. + */ +static certificate_type_t get_type(private_x509_pkcs10_t *this) +{ + return CERT_PKCS10_REQUEST; +} + +/** + * Implementation of certificate_t.get_subject and get_issuer. + */ +static identification_t* get_subject(private_x509_pkcs10_t *this) +{ + return this->subject; +} + +/** + * Implementation of certificate_t.has_subject and has_issuer. + */ +static id_match_t has_subject(private_x509_pkcs10_t *this, identification_t *subject) +{ + return this->subject->matches(this->subject, subject); +} + +/** + * Implementation of certificate_t.issued_by. + */ +static bool issued_by(private_x509_pkcs10_t *this, certificate_t *issuer) +{ + public_key_t *key; + signature_scheme_t scheme; + + if (&this->public.interface.interface != issuer) + { + return FALSE; + } + if (this->self_signed) + { + return TRUE; + } + + /* determine signature scheme */ + scheme = signature_scheme_from_oid(this->algorithm); + if (scheme == SIGN_UNKNOWN) + { + return FALSE; + } + + /* get the public key contained in the certificate request */ + key = this->public_key; + if (!key) + { + return FALSE; + } + return key->verify(key, scheme, this->certificationRequestInfo, + this->signature); +} + +/** + * Implementation of certificate_t.get_public_key. + */ +static public_key_t* get_public_key(private_x509_pkcs10_t *this) +{ + this->public_key->get_ref(this->public_key); + return this->public_key; +} + +/** + * Implementation of certificate_t.get_validity. + */ +static bool get_validity(private_x509_pkcs10_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + if (not_before) + { + *not_before = 0; + } + if (not_after) + { + *not_after = ~0; + } + return TRUE; +} + +/** + * Implementation of certificate_t.is_newer. + */ +static bool is_newer(certificate_t *this, certificate_t *that) +{ + return FALSE; +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_pkcs10_t *this) +{ + return chunk_clone(this->encoding); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_pkcs10_t *this, certificate_t *other) +{ + chunk_t encoding; + bool equal; + + if (this == (private_x509_pkcs10_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_PKCS10_REQUEST) + { + return FALSE; + } + if (other->equals == (void*)equals) + { /* skip allocation if we have the same implementation */ + return chunk_equals(this->encoding, ((private_x509_pkcs10_t*)other)->encoding); + } + encoding = other->get_encoding(other); + equal = chunk_equals(this->encoding, encoding); + free(encoding.ptr); + return equal; +} + +/** + * Implementation of certificate_t.get_ref + */ +static private_x509_pkcs10_t* get_ref(private_x509_pkcs10_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of certificate_t.get_challengePassword. + */ +static chunk_t get_challengePassword(private_x509_pkcs10_t *this) +{ + return this->challengePassword; +} + +/** + * Implementation of pkcs10_t.create_subjectAltName_enumerator. + */ +static enumerator_t* create_subjectAltName_enumerator(private_x509_pkcs10_t *this) +{ + return this->subjectAltNames->create_enumerator(this->subjectAltNames); +} + +/** + * ASN.1 definition of a PKCS#10 extension request + */ +static const asn1Object_t extensionRequestObjects[] = { + { 0, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "extnID", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 3 */ + { 2, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS10_EXTN_ID 2 +#define PKCS10_EXTN_CRITICAL 3 +#define PKCS10_EXTN_VALUE 4 + +/** + * Parses a PKCS#10 extension request + */ +static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, int level0) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + int extn_oid = OID_UNKNOWN; + bool success = FALSE; + bool critical; + + parser = asn1_parser_create(extensionRequestObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; + + switch (objectID) + { + case PKCS10_EXTN_ID: + extn_oid = asn1_known_oid(object); + break; + case PKCS10_EXTN_CRITICAL: + critical = object.len && *object.ptr; + DBG2(" %s", critical ? "TRUE" : "FALSE"); + break; + case PKCS10_EXTN_VALUE: + { + switch (extn_oid) + { + case OID_SUBJECT_ALT_NAME: + x509_parse_generalNames(object, level, FALSE, + this->subjectAltNames); + break; + default: + break; + } + break; + } + default: + break; + } + } + success = parser->success(parser); + parser->destroy(parser); + return success; +} + +/** + * Parses a PKCS#10 challenge password + */ +static bool parse_challengePassword(private_x509_pkcs10_t *this, chunk_t blob, int level) +{ + char tag; + + if (blob.len < 2) + { + DBG1("L%d - challengePassword: ASN.1 object smaller than 2 octets", + level); + return FALSE; + } + tag = *blob.ptr; + if (tag < ASN1_UTF8STRING || tag > ASN1_IA5STRING) + { + DBG1("L%d - challengePassword: ASN.1 object is not a character string", + level); + return FALSE; + } + if (asn1_length(&blob) == ASN1_INVALID_LENGTH) + { + DBG1("L%d - challengePassword: ASN.1 object has an invalid length", + level); + return FALSE; + } + DBG2("L%d - challengePassword:", level); + DBG4(" '%.*s'", blob.len, blob.ptr); + return TRUE; +} + +/** + * ASN.1 definition of a PKCS#10 certificate request + */ +static const asn1Object_t certificationRequestObjects[] = { + { 0, "certificationRequest", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "certificationRequestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "version", ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 3 */ + { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_RAW }, /* 4 */ + { 2, "attributes", ASN1_CONTEXT_C_0, ASN1_LOOP }, /* 5 */ + { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 6 */ + { 4, "type", ASN1_OID, ASN1_BODY }, /* 7 */ + { 4, "values", ASN1_SET, ASN1_LOOP }, /* 8 */ + { 5, "value", ASN1_EOC, ASN1_RAW }, /* 9 */ + { 4, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 11 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ + { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS10_CERT_REQUEST_INFO 1 +#define PKCS10_VERSION 2 +#define PKCS10_SUBJECT 3 +#define PKCS10_SUBJECT_PUBLIC_KEY_INFO 4 +#define PKCS10_ATTR_TYPE 7 +#define PKCS10_ATTR_VALUE 9 +#define PKCS10_ALGORITHM 12 +#define PKCS10_SIGNATURE 13 + +/** + * Parses a PKCS#10 certificate request + */ +static bool parse_certificate_request(private_x509_pkcs10_t *this) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + int attr_oid = OID_UNKNOWN; + bool success = FALSE; + + parser = asn1_parser_create(certificationRequestObjects, this->encoding); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; + + switch (objectID) + { + case PKCS10_CERT_REQUEST_INFO: + this->certificationRequestInfo = object; + break; + case PKCS10_VERSION: + if (object.len > 0 && *object.ptr != 0) + { + DBG1("PKCS#10 certificate request format is not version 1"); + goto end; + } + break; + case PKCS10_SUBJECT: + this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%Y'", this->subject); + break; + case PKCS10_SUBJECT_PUBLIC_KEY_INFO: + this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, + KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); + if (this->public_key == NULL) + { + goto end; + } + break; + case PKCS10_ATTR_TYPE: + attr_oid = asn1_known_oid(object); + break; + case PKCS10_ATTR_VALUE: + switch (attr_oid) + { + case OID_EXTENSION_REQUEST: + if (!parse_extension_request(this, object, level)) + { + goto end; + } + break; + case OID_CHALLENGE_PASSWORD: + if (!parse_challengePassword(this, object, level)) + { + goto end; + } + break; + default: + break; + } + break; + case PKCS10_ALGORITHM: + this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS10_SIGNATURE: + this->signature = object; + break; + default: + break; + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (success) + { + /* check if the certificate request is self-signed */ + if (issued_by(this, &this->public.interface.interface)) + { + this->self_signed = TRUE; + } + else + { + DBG1("certificate request is not self-signed"); + success = FALSE; + } + } + return success; +} + +/** + * Implementation of certificate_t.destroy + */ +static void destroy(private_x509_pkcs10_t *this) +{ + if (ref_put(&this->ref)) + { + this->subjectAltNames->destroy_offset(this->subjectAltNames, + offsetof(identification_t, destroy)); + DESTROY_IF(this->subject); + DESTROY_IF(this->public_key); + chunk_free(&this->encoding); + if (!this->parsed) + { /* only parsed certificate requests point these fields to "encoded" */ + chunk_free(&this->certificationRequestInfo); + chunk_free(&this->challengePassword); + chunk_free(&this->signature); + } + free(this); + } +} + +/** + * create an empty but initialized PKCS#10 certificate request + */ +static private_x509_pkcs10_t* create_empty(void) +{ + private_x509_pkcs10_t *this = malloc_thing(private_x509_pkcs10_t); + + this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type; + this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject; + this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_subject; + this->public.interface.interface.has_subject = (id_match_t (*) (certificate_t*, identification_t*))has_subject; + this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_subject; + this->public.interface.interface.issued_by = (bool (*) (certificate_t*, certificate_t*))issued_by; + this->public.interface.interface.get_public_key = (public_key_t* (*) (certificate_t*))get_public_key; + this->public.interface.interface.get_validity = (bool (*) (certificate_t*, time_t*, time_t*, time_t*))get_validity; + this->public.interface.interface.is_newer = (bool (*) (certificate_t*,certificate_t*))is_newer; + this->public.interface.interface.get_encoding = (chunk_t (*) (certificate_t*))get_encoding; + this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals; + this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref; + this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy; + this->public.interface.get_challengePassword = (chunk_t (*)(pkcs10_t*))get_challengePassword; + this->public.interface.create_subjectAltName_enumerator = (enumerator_t* (*)(pkcs10_t*))create_subjectAltName_enumerator; + + this->encoding = chunk_empty; + this->certificationRequestInfo = chunk_empty; + this->subject = NULL; + this->public_key = NULL; + this->subjectAltNames = linked_list_create(); + this->challengePassword = chunk_empty; + this->signature = chunk_empty; + this->ref = 1; + this->self_signed = FALSE; + this->parsed = FALSE; + + return this; +} + +/** + * Generate and sign a new certificate request + */ +static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key, + int digest_alg) +{ + chunk_t key_info, subjectAltNames, attributes; + chunk_t extensionRequest = chunk_empty; + chunk_t challengePassword = chunk_empty; + signature_scheme_t scheme; + identification_t *subject; + + subject = cert->subject; + cert->public_key = sign_key->get_public_key(sign_key); + + /* select signature scheme */ + cert->algorithm = hasher_signature_algorithm_to_oid(digest_alg, + sign_key->get_type(sign_key)); + if (cert->algorithm == OID_UNKNOWN) + { + return FALSE; + } + scheme = signature_scheme_from_oid(cert->algorithm); + + if (!cert->public_key->get_encoding(cert->public_key, + KEY_PUB_SPKI_ASN1_DER, &key_info)) + { + return FALSE; + } + + /* encode subjectAltNames */ + subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames); + + if (subjectAltNames.ptr) + { + extensionRequest = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_EXTENSION_REQUEST), + asn1_wrap(ASN1_SET, "m", + asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames) + )); + } + if (cert->challengePassword.len > 0) + { + asn1_t type = asn1_is_printablestring(cert->challengePassword) ? + ASN1_PRINTABLESTRING : ASN1_T61STRING; + + challengePassword = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(OID_CHALLENGE_PASSWORD), + asn1_wrap(ASN1_SET, "m", + asn1_simple_object(type, cert->challengePassword) + ) + ); + } + attributes = asn1_wrap(ASN1_CONTEXT_C_0, "mm", extensionRequest, + challengePassword); + + cert->certificationRequestInfo = asn1_wrap(ASN1_SEQUENCE, "ccmm", + ASN1_INTEGER_0, + subject->get_encoding(subject), + key_info, + attributes); + + if (!sign_key->sign(sign_key, scheme, cert->certificationRequestInfo, + &cert->signature)) + { + return FALSE; + } + + cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", + cert->certificationRequestInfo, + asn1_algorithmIdentifier(cert->algorithm), + asn1_bitstring("c", cert->signature)); + return TRUE; +} + +/** + * See header. + */ +x509_pkcs10_t *x509_pkcs10_load(certificate_type_t type, va_list args) +{ + chunk_t blob = chunk_empty; + + 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) + { + private_x509_pkcs10_t *cert = create_empty(); + + cert->encoding = chunk_clone(blob); + cert->parsed = TRUE; + if (parse_certificate_request(cert)) + { + return &cert->public; + } + destroy(cert); + } + return NULL; +} + +/** + * See header. + */ +x509_pkcs10_t *x509_pkcs10_gen(certificate_type_t type, va_list args) +{ + private_x509_pkcs10_t *cert; + private_key_t *sign_key = NULL; + hash_algorithm_t digest_alg = HASH_SHA1; + + cert = create_empty(); + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_SIGNING_KEY: + sign_key = va_arg(args, private_key_t*); + continue; + case BUILD_SUBJECT: + cert->subject = va_arg(args, identification_t*); + cert->subject = cert->subject->clone(cert->subject); + continue; + case BUILD_SUBJECT_ALTNAMES: + { + enumerator_t *enumerator; + identification_t *id; + linked_list_t *list; + + list = va_arg(args, linked_list_t*); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &id)) + { + cert->subjectAltNames->insert_last(cert->subjectAltNames, + id->clone(id)); + } + enumerator->destroy(enumerator); + continue; + } + case BUILD_PASSPHRASE: + cert->challengePassword = chunk_clone(va_arg(args, chunk_t)); + continue; + case BUILD_DIGEST_ALG: + digest_alg = va_arg(args, int); + continue; + case BUILD_END: + break; + default: + destroy(cert); + return NULL; + } + break; + } + + if (sign_key && generate(cert, sign_key, digest_alg)) + { + return &cert->public; + } + destroy(cert); + return NULL; +} + diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.h b/src/libstrongswan/plugins/x509/x509_pkcs10.h new file mode 100644 index 000000000..f9490b1dc --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_pkcs10.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008-2009 Martin Willi + * Copyright (C) 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. + */ + +/** + * @defgroup x509_pkcs10 x509_pkcs10 + * @{ @ingroup x509_p + */ + +#ifndef X509_PKCS10_H_ +#define X509_PKCS10_H_ + +typedef struct x509_pkcs10_t x509_pkcs10_t; + +#include <credentials/builder.h> +#include <credentials/certificates/pkcs10.h> + +/** + * Implementation of pkcs10_t/certificate_t using own ASN.1 parser. + */ +struct x509_pkcs10_t { + + /** + * Implements the pkcs10_t interface + */ + pkcs10_t interface; +}; + +/** + * Load a PKCS#10 certificate. + * + * This function takes a BUILD_BLOB_ASN1_DER. + * + * @param type certificate type, CERT_PKCS10_REQUEST only + * @param args builder_part_t argument list + * @return PKCS#10 certificate request, NULL on failure + */ +x509_pkcs10_t *x509_pkcs10_load(certificate_type_t type, va_list args); + +/** + * Generate a PKCS#10 certificate request. + * + * To issue a self-signed certificate request, the function takes: + * BUILD_SUBJECT, BUILD_SUBJECT_ALTNAMES, BUILD_SIGNING_KEY, BUILD_DIGEST_ALG. + * + * @param type certificate type, CERT_PKCS10_REQUEST only + * @param args builder_part_t argument list + * @return PKCS#10 certificate request, NULL on failure + */ +x509_pkcs10_t *x509_pkcs10_gen(certificate_type_t type, va_list args); + +#endif /** X509_PKCS10_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_plugin.c b/src/libstrongswan/plugins/x509/x509_plugin.c index 9ed7f95bd..94c49b1e1 100644 --- a/src/libstrongswan/plugins/x509/x509_plugin.c +++ b/src/libstrongswan/plugins/x509/x509_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2008-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ #include "x509_crl.h" #include "x509_ocsp_request.h" #include "x509_ocsp_response.h" +#include "x509_pkcs10.h" typedef struct private_x509_plugin_t private_x509_plugin_t; @@ -41,15 +42,23 @@ struct private_x509_plugin_t { static void destroy(private_x509_plugin_t *this) { lib->creds->remove_builder(lib->creds, - (builder_constructor_t)x509_cert_builder); + (builder_function_t)x509_cert_gen); lib->creds->remove_builder(lib->creds, - (builder_constructor_t)x509_ac_builder); + (builder_function_t)x509_cert_load); lib->creds->remove_builder(lib->creds, - (builder_constructor_t)x509_crl_builder); + (builder_function_t)x509_ac_gen); lib->creds->remove_builder(lib->creds, - (builder_constructor_t)x509_ocsp_request_builder); + (builder_function_t)x509_ac_load); lib->creds->remove_builder(lib->creds, - (builder_constructor_t)x509_ocsp_response_builder); + (builder_function_t)x509_crl_load); + lib->creds->remove_builder(lib->creds, + (builder_function_t)x509_ocsp_request_gen); + lib->creds->remove_builder(lib->creds, + (builder_function_t)x509_ocsp_response_load); + lib->creds->remove_builder(lib->creds, + (builder_function_t)x509_pkcs10_gen); + lib->creds->remove_builder(lib->creds, + (builder_function_t)x509_pkcs10_load); free(this); } @@ -59,19 +68,27 @@ static void destroy(private_x509_plugin_t *this) plugin_t *plugin_create() { private_x509_plugin_t *this = malloc_thing(private_x509_plugin_t); - + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509, - (builder_constructor_t)x509_cert_builder); + (builder_function_t)x509_cert_gen); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509, + (builder_function_t)x509_cert_load); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, + (builder_function_t)x509_ac_gen); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, - (builder_constructor_t)x509_ac_builder); + (builder_function_t)x509_ac_load); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, - (builder_constructor_t)x509_crl_builder); + (builder_function_t)x509_crl_load); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST, - (builder_constructor_t)x509_ocsp_request_builder); + (builder_function_t)x509_ocsp_request_gen); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE, - (builder_constructor_t)x509_ocsp_response_builder); + (builder_function_t)x509_ocsp_response_load); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, + (builder_function_t)x509_pkcs10_gen); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, + (builder_function_t)x509_pkcs10_load); return &this->public.plugin; } |