diff options
author | davilla <davilla@svn> | 2010-02-13 17:31:51 +0000 |
---|---|---|
committer | davilla <davilla@svn> | 2010-02-13 17:31:51 +0000 |
commit | fa8e3ef23bd203e98e3b3de423e8359c10167159 (patch) | |
tree | 7eb0513fb5ee6fa0f71726e49fdcaf1e0de59973 /lib/libmicrohttpd/src | |
parent | 7ab2873c972ab1cd95f9bd7f158fc5aeeb25e2dd (diff) |
commit libmicrohttpd-0.4.5 into trunk
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@27720 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'lib/libmicrohttpd/src')
203 files changed, 64432 insertions, 0 deletions
diff --git a/lib/libmicrohttpd/src/Makefile.am b/lib/libmicrohttpd/src/Makefile.am new file mode 100644 index 0000000000..4868557b19 --- /dev/null +++ b/lib/libmicrohttpd/src/Makefile.am @@ -0,0 +1,9 @@ +if HAVE_CURL +curltests = testcurl +if HAVE_ZZUF +if HAVE_SOCAT +zzuftests = testzzuf +endif +endif +endif +SUBDIRS = include daemon examples $(curltests) $(zzuftests) . diff --git a/lib/libmicrohttpd/src/Makefile.in b/lib/libmicrohttpd/src/Makefile.in new file mode 100644 index 0000000000..ac7d244307 --- /dev/null +++ b/lib/libmicrohttpd/src/Makefile.in @@ -0,0 +1,576 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = include daemon examples testcurl testzzuf . +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@HAVE_CURL_TRUE@curltests = testcurl +@HAVE_CURL_TRUE@@HAVE_SOCAT_TRUE@@HAVE_ZZUF_TRUE@zzuftests = testzzuf +SUBDIRS = include daemon examples $(curltests) $(zzuftests) . +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/daemon/EXPORT.sym b/lib/libmicrohttpd/src/daemon/EXPORT.sym new file mode 100644 index 0000000000..b57c523384 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/EXPORT.sym @@ -0,0 +1,23 @@ +MHD_start_daemon +MHD_start_daemon_va +MHD_stop_daemon +MHD_get_fdset +MHD_get_timeout +MHD_run +MHD_get_connection_values +MHD_set_connection_value +MHD_lookup_connection_value +MHD_queue_response +MHD_create_response_from_callback +MHD_create_response_from_data +MHD_destroy_response +MHD_add_response_header +MHD_del_response_header +MHD_get_response_headers +MHD_get_response_header +MHD_create_post_processor +MHD_post_process +MHD_destroy_post_processor +MHD_get_daemon_info +MHD_get_connection_info +MHD_set_panic_func diff --git a/lib/libmicrohttpd/src/daemon/Makefile.am b/lib/libmicrohttpd/src/daemon/Makefile.am new file mode 100644 index 0000000000..de5152f2cc --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/Makefile.am @@ -0,0 +1,64 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/x509 \ + -I$(top_srcdir)/src/daemon/https/minitasn1 \ + -I$(top_srcdir)/src/daemon/https/tls \ + -I$(top_srcdir)/src/daemon/https \ + @LIBGCRYPT_CFLAGS@ + +EXTRA_DIST = EXPORT.sym + +lib_LTLIBRARIES = \ + libmicrohttpd.la + +libmicrohttpd_la_SOURCES = \ + connection.c connection.h \ + reason_phrase.c reason_phrase.h \ + daemon.c \ + internal.c internal.h \ + memorypool.c memorypool.h \ + postprocessor.c \ + response.c response.h +libmicrohttpd_la_LDFLAGS = \ + $(MHD_LIB_LDFLAGS) \ + -version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@ + +if USE_COVERAGE + AM_CFLAGS = --coverage +endif + + +if ENABLE_HTTPS +SUBDIRS = https . +libmicrohttpd_la_SOURCES += \ + connection_https.c connection_https.h +libmicrohttpd_la_LIBADD = \ + https/lgl/liblgl.la \ + https/x509/libx509.la \ + https/tls/libtls.la \ + https/minitasn1/libasn1.la +endif + +check_PROGRAMS = \ + postprocessor_test \ + postprocessor_large_test \ + daemon_test + +TESTS = $(check_PROGRAMS) + +daemon_test_SOURCES = \ + daemon_test.c +daemon_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +postprocessor_test_SOURCES = \ + postprocessor_test.c +postprocessor_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +postprocessor_large_test_SOURCES = \ + postprocessor_large_test.c +postprocessor_large_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la diff --git a/lib/libmicrohttpd/src/daemon/Makefile.in b/lib/libmicrohttpd/src/daemon/Makefile.in new file mode 100644 index 0000000000..212c3d9f28 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/Makefile.in @@ -0,0 +1,896 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@ENABLE_HTTPS_TRUE@am__append_1 = \ +@ENABLE_HTTPS_TRUE@ connection_https.c connection_https.h + +check_PROGRAMS = postprocessor_test$(EXEEXT) \ + postprocessor_large_test$(EXEEXT) daemon_test$(EXEEXT) +subdir = src/daemon +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +@ENABLE_HTTPS_TRUE@libmicrohttpd_la_DEPENDENCIES = \ +@ENABLE_HTTPS_TRUE@ https/lgl/liblgl.la https/x509/libx509.la \ +@ENABLE_HTTPS_TRUE@ https/tls/libtls.la \ +@ENABLE_HTTPS_TRUE@ https/minitasn1/libasn1.la +am__libmicrohttpd_la_SOURCES_DIST = connection.c connection.h \ + reason_phrase.c reason_phrase.h daemon.c internal.c internal.h \ + memorypool.c memorypool.h postprocessor.c response.c \ + response.h connection_https.c connection_https.h +@ENABLE_HTTPS_TRUE@am__objects_1 = connection_https.lo +am_libmicrohttpd_la_OBJECTS = connection.lo reason_phrase.lo daemon.lo \ + internal.lo memorypool.lo postprocessor.lo response.lo \ + $(am__objects_1) +libmicrohttpd_la_OBJECTS = $(am_libmicrohttpd_la_OBJECTS) +libmicrohttpd_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libmicrohttpd_la_LDFLAGS) $(LDFLAGS) -o $@ +am_daemon_test_OBJECTS = daemon_test.$(OBJEXT) +daemon_test_OBJECTS = $(am_daemon_test_OBJECTS) +daemon_test_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_postprocessor_large_test_OBJECTS = \ + postprocessor_large_test.$(OBJEXT) +postprocessor_large_test_OBJECTS = \ + $(am_postprocessor_large_test_OBJECTS) +postprocessor_large_test_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_postprocessor_test_OBJECTS = postprocessor_test.$(OBJEXT) +postprocessor_test_OBJECTS = $(am_postprocessor_test_OBJECTS) +postprocessor_test_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libmicrohttpd_la_SOURCES) $(daemon_test_SOURCES) \ + $(postprocessor_large_test_SOURCES) \ + $(postprocessor_test_SOURCES) +DIST_SOURCES = $(am__libmicrohttpd_la_SOURCES_DIST) \ + $(daemon_test_SOURCES) $(postprocessor_large_test_SOURCES) \ + $(postprocessor_test_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DIST_SUBDIRS = https . +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/x509 \ + -I$(top_srcdir)/src/daemon/https/minitasn1 \ + -I$(top_srcdir)/src/daemon/https/tls \ + -I$(top_srcdir)/src/daemon/https \ + @LIBGCRYPT_CFLAGS@ + +EXTRA_DIST = EXPORT.sym +lib_LTLIBRARIES = \ + libmicrohttpd.la + +libmicrohttpd_la_SOURCES = connection.c connection.h reason_phrase.c \ + reason_phrase.h daemon.c internal.c internal.h memorypool.c \ + memorypool.h postprocessor.c response.c response.h \ + $(am__append_1) +libmicrohttpd_la_LDFLAGS = \ + $(MHD_LIB_LDFLAGS) \ + -version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@ + +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage +@ENABLE_HTTPS_TRUE@SUBDIRS = https . +@ENABLE_HTTPS_TRUE@libmicrohttpd_la_LIBADD = \ +@ENABLE_HTTPS_TRUE@ https/lgl/liblgl.la \ +@ENABLE_HTTPS_TRUE@ https/x509/libx509.la \ +@ENABLE_HTTPS_TRUE@ https/tls/libtls.la \ +@ENABLE_HTTPS_TRUE@ https/minitasn1/libasn1.la + +TESTS = $(check_PROGRAMS) +daemon_test_SOURCES = \ + daemon_test.c + +daemon_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +postprocessor_test_SOURCES = \ + postprocessor_test.c + +postprocessor_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +postprocessor_large_test_SOURCES = \ + postprocessor_large_test.c + +postprocessor_large_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/daemon/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/daemon/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmicrohttpd.la: $(libmicrohttpd_la_OBJECTS) $(libmicrohttpd_la_DEPENDENCIES) + $(libmicrohttpd_la_LINK) -rpath $(libdir) $(libmicrohttpd_la_OBJECTS) $(libmicrohttpd_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +daemon_test$(EXEEXT): $(daemon_test_OBJECTS) $(daemon_test_DEPENDENCIES) + @rm -f daemon_test$(EXEEXT) + $(LINK) $(daemon_test_OBJECTS) $(daemon_test_LDADD) $(LIBS) +postprocessor_large_test$(EXEEXT): $(postprocessor_large_test_OBJECTS) $(postprocessor_large_test_DEPENDENCIES) + @rm -f postprocessor_large_test$(EXEEXT) + $(LINK) $(postprocessor_large_test_OBJECTS) $(postprocessor_large_test_LDADD) $(LIBS) +postprocessor_test$(EXEEXT): $(postprocessor_test_OBJECTS) $(postprocessor_test_DEPENDENCIES) + @rm -f postprocessor_test$(EXEEXT) + $(LINK) $(postprocessor_test_OBJECTS) $(postprocessor_test_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection_https.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/internal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memorypool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/postprocessor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/postprocessor_large_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/postprocessor_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reason_phrase.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-libLTLIBRARIES + + +# 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/lib/libmicrohttpd/src/daemon/connection.c b/lib/libmicrohttpd/src/daemon/connection.c new file mode 100644 index 0000000000..ef47b1c95f --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/connection.c @@ -0,0 +1,2230 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** + * @file connection.c + * @brief Methods for managing connections + * @author Daniel Pittman + * @author Christian Grothoff + */ + +#include "internal.h" +#include "connection.h" +#include "memorypool.h" +#include "response.h" +#include "reason_phrase.h" + +#if HAVE_NETINET_TCP_H +/* for TCP_CORK */ +#include <netinet/tcp.h> +#endif + +/** + * Message to transmit when http 1.1 request is received + */ +#define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n" + +/** + * Response text used when the request (http header) is too big to + * be processed. + * + * Intentionally empty here to keep our memory footprint + * minimal. + */ +#if HAVE_MESSAGES +#define REQUEST_TOO_BIG "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>" +#else +#define REQUEST_TOO_BIG "" +#endif + +/** + * Response text used when the request (http header) does not + * contain a "Host:" header and still claims to be HTTP 1.1. + * + * Intentionally empty here to keep our memory footprint + * minimal. + */ +#if HAVE_MESSAGES +#define REQUEST_LACKS_HOST "<html><head><title>"Host:" header required</title></head><body>In HTTP 1.1, requests must include a "Host:" header, and your HTTP 1.1 request lacked such a header.</body></html>" +#else +#define REQUEST_LACKS_HOST "" +#endif + +/** + * Response text used when the request (http header) is + * malformed. + * + * Intentionally empty here to keep our memory footprint + * minimal. + */ +#if HAVE_MESSAGES +#define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>" +#else +#define REQUEST_MALFORMED "" +#endif + +/** + * Response text used when there is an internal server error. + * + * Intentionally empty here to keep our memory footprint + * minimal. + */ +#if HAVE_MESSAGES +#define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>" +#else +#define INTERNAL_ERROR "" +#endif + +/** + * Add extra debug messages with reasons for closing connections + * (non-error reasons). + */ +#define DEBUG_CLOSE MHD_NO + +/** + * Should all data send be printed to stderr? + */ +#define DEBUG_SEND_DATA MHD_NO + +/** + * Get all of the headers from the request. + * + * @param iterator callback to call on each header; + * maybe NULL (then just count headers) + * @param iterator_cls extra argument to iterator + * @return number of entries iterated over + */ +int +MHD_get_connection_values (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + MHD_KeyValueIterator iterator, void *iterator_cls) +{ + int ret; + struct MHD_HTTP_Header *pos; + + if (connection == NULL) + return -1; + ret = 0; + pos = connection->headers_received; + while (pos != NULL) + { + if (0 != (pos->kind & kind)) + { + ret++; + if ((iterator != NULL) && + (MHD_YES != iterator (iterator_cls, + kind, pos->header, pos->value))) + return ret; + } + pos = pos->next; + } + return ret; +} + +/** + * This function can be used to add an entry to + * the HTTP headers of a connection (so that the + * MHD_get_connection_values function will return + * them -- and the MHD PostProcessor will also + * see them). This maybe required in certain + * situations (see Mantis #1399) where (broken) + * HTTP implementations fail to supply values needed + * by the post processor (or other parts of the + * application). + * <p> + * This function MUST only be called from within + * the MHD_AccessHandlerCallback (otherwise, access + * maybe improperly synchronized). Furthermore, + * the client must guarantee that the key and + * value arguments are 0-terminated strings that + * are NOT freed until the connection is closed. + * (The easiest way to do this is by passing only + * arguments to permanently allocated strings.). + * + * @param connection the connection for which a + * value should be set + * @param kind kind of the value + * @param key key for the value + * @param value the value itself + * @return MHD_NO if the operation could not be + * performed due to insufficient memory; + * MHD_YES on success + */ +int +MHD_set_connection_value (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + const char *key, const char *value) +{ + struct MHD_HTTP_Header *pos; + + pos = MHD_pool_allocate (connection->pool, + sizeof (struct MHD_HTTP_Header), MHD_NO); + if (pos == NULL) + return MHD_NO; + pos->header = (char *) key; + pos->value = (char *) value; + pos->kind = kind; + pos->next = connection->headers_received; + connection->headers_received = pos; + return MHD_YES; +} + +/** + * Get a particular header value. If multiple + * values match the kind, return any one of them. + * + * @param key the header to look for + * @return NULL if no such item was found + */ +const char * +MHD_lookup_connection_value (struct MHD_Connection *connection, + enum MHD_ValueKind kind, const char *key) +{ + struct MHD_HTTP_Header *pos; + + if (connection == NULL) + return NULL; + pos = connection->headers_received; + while (pos != NULL) + { + if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header))) + return pos->value; + pos = pos->next; + } + return NULL; +} + +/** + * Queue a response to be transmitted to the client (as soon as + * possible but after MHD_AccessHandlerCallback returns). + * + * @param connection the connection identifying the client + * @param status_code HTTP status code (i.e. 200 for OK) + * @param response response to transmit + * @return MHD_NO on error (i.e. reply already sent), + * MHD_YES on success or if message has been queued + */ +int +MHD_queue_response (struct MHD_Connection *connection, + unsigned int status_code, struct MHD_Response *response) +{ + if ((connection == NULL) || + (response == NULL) || + (connection->response != NULL) || + ((connection->state != MHD_CONNECTION_HEADERS_PROCESSED) && + (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED))) + return MHD_NO; + MHD_increment_response_rc (response); + connection->response = response; + connection->responseCode = status_code; + if ((connection->method != NULL) && + (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD))) + { + /* if this is a "HEAD" request, pretend that we + have already sent the full message body */ + connection->response_write_position = response->total_size; + } + if ((response->total_size == MHD_SIZE_UNKNOWN) && + (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) + connection->have_chunked_response = MHD_YES; + else + connection->have_chunked_response = MHD_NO; + if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED) + { + /* response was queued "early", + refuse to read body / footers or further + requests! */ + SHUTDOWN (connection->socket_fd, SHUT_RD); + connection->read_closed = MHD_YES; + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + } + return MHD_YES; +} + +/** + * Do we (still) need to send a 100 continue + * message for this connection? + */ +static int +need_100_continue (struct MHD_Connection *connection) +{ + const char *expect; + + return ((connection->response == NULL) && + (connection->version != NULL) && + (0 == strcasecmp (connection->version, + MHD_HTTP_VERSION_1_1)) && + (NULL != (expect = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_EXPECT))) + && (0 == strcasecmp (expect, "100-continue")) + && (connection->continue_message_write_offset < + strlen (HTTP_100_CONTINUE))); +} + +/** + * Close the given connection and give the + * specified termination code to the user. + */ +void +MHD_connection_close (struct MHD_Connection *connection, + enum MHD_RequestTerminationCode termination_code) +{ + SHUTDOWN (connection->socket_fd, SHUT_RDWR); + CLOSE (connection->socket_fd); + connection->socket_fd = -1; + connection->state = MHD_CONNECTION_CLOSED; + if ( (NULL != connection->daemon->notify_completed) && + (MHD_YES == connection->client_aware) ) + connection->daemon->notify_completed (connection->daemon-> + notify_completed_cls, connection, + &connection->client_context, + termination_code); + connection->client_aware = MHD_NO; +} + +/** + * A serious error occured, close the + * connection (and notify the application). + */ +static void +connection_close_error (struct MHD_Connection *connection) +{ + MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR); +} + +/** + * Prepare the response buffer of this connection for + * sending. Assumes that the response mutex is + * already held. If the transmission is complete, + * this function may close the socket (and return + * MHD_NO). + * + * @return MHD_NO if readying the response failed + */ +static int +try_ready_normal_body (struct MHD_Connection *connection) +{ + int ret; + struct MHD_Response *response; + + response = connection->response; + if (response->crc == NULL) + return MHD_YES; + if ( (response->data_start <= + connection->response_write_position) && + (response->data_size + response->data_start > + connection->response_write_position) ) + return MHD_YES; /* response already ready */ + ret = response->crc (response->crc_cls, + connection->response_write_position, + response->data, + MHD_MIN (response->data_buffer_size, + response->total_size - + connection->response_write_position)); + if ((ret == 0) && + (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY))) + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, +#if HAVE_MESSAGES + "API violation" +#else + NULL +#endif + ); + if (ret == -1) + { + /* either error or http 1.0 transfer, close + socket! */ +#if DEBUG_CLOSE +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "Closing connection (end of response)\n"); +#endif +#endif + response->total_size = connection->response_write_position; + connection_close_error (connection); + return MHD_NO; + } + response->data_start = connection->response_write_position; + response->data_size = ret; + if (ret == 0) + return MHD_NO; + return MHD_YES; +} + +/** + * Prepare the response buffer of this connection for + * sending. Assumes that the response mutex is + * already held. If the transmission is complete, + * this function may close the socket (and return + * MHD_NO). + * + * @return MHD_NO if readying the response failed + */ +static int +try_ready_chunked_body (struct MHD_Connection *connection) +{ + int ret; + char *buf; + struct MHD_Response *response; + size_t size; + char cbuf[10]; /* 10: max strlen of "%x\r\n" */ + int cblen; + + response = connection->response; + if (connection->write_buffer_size == 0) + { + size = connection->daemon->pool_size; + do + { + size /= 2; + if (size < 128) + { + /* not enough memory */ +#if DEBUG_CLOSE +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Closing connection (out of memory)\n"); +#endif +#endif + connection_close_error (connection); + return MHD_NO; + } + buf = MHD_pool_allocate (connection->pool, size, MHD_NO); + } + while (buf == NULL); + connection->write_buffer_size = size; + connection->write_buffer = buf; + } + + if ( (response->data_start <= + connection->response_write_position) && + (response->data_size + response->data_start > + connection->response_write_position) ) + { + /* buffer already ready, use what is there for the chunk */ + ret = response->data_size + response->data_start - connection->response_write_position; + if (ret > connection->write_buffer_size - sizeof (cbuf) - 2) + ret = connection->write_buffer_size - sizeof (cbuf) - 2; + memcpy (&connection->write_buffer[sizeof (cbuf)], + &response->data[connection->response_write_position - response->data_start], + ret); + } + else + { + /* buffer not in range, try to fill it */ + ret = response->crc (response->crc_cls, + connection->response_write_position, + &connection->write_buffer[sizeof (cbuf)], + connection->write_buffer_size - sizeof (cbuf) - 2); + } + if (ret == -1) + { + /* end of message, signal other side! */ + strcpy (connection->write_buffer, "0\r\n"); + connection->write_buffer_append_offset = 3; + connection->write_buffer_send_offset = 0; + response->total_size = connection->response_write_position; + return MHD_YES; + } + if (ret == 0) + { + connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; + return MHD_NO; + } + if (ret > 0xFFFFFF) + ret = 0xFFFFFF; + SPRINTF (cbuf, "%X\r\n", ret); + cblen = strlen (cbuf); + EXTRA_CHECK (cblen <= sizeof (cbuf)); + memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen); + memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2); + connection->response_write_position += ret; + connection->write_buffer_send_offset = sizeof (cbuf) - cblen; + connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2; + return MHD_YES; +} + +/** + * Check if we need to set some additional headers + * for http-compiliance. + */ +static void +add_extra_headers (struct MHD_Connection *connection) +{ + const char *have; + char buf[128]; + + connection->have_chunked_upload = MHD_NO; + if (connection->response->total_size == MHD_SIZE_UNKNOWN) + { + have = MHD_get_response_header (connection->response, + MHD_HTTP_HEADER_CONNECTION); + if ((have == NULL) || (0 != strcasecmp (have, "close"))) + { + if ((connection->version != NULL) && + (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1))) + { + connection->have_chunked_upload = MHD_YES; + have = MHD_get_response_header (connection->response, + MHD_HTTP_HEADER_TRANSFER_ENCODING); + if (have == NULL) + MHD_add_response_header (connection->response, + MHD_HTTP_HEADER_TRANSFER_ENCODING, + "chunked"); + } + else + { + MHD_add_response_header (connection->response, + MHD_HTTP_HEADER_CONNECTION, "close"); + } + } + } + else if (NULL == MHD_get_response_header (connection->response, + MHD_HTTP_HEADER_CONTENT_LENGTH)) + { + SPRINTF (buf, + "%llu", + (unsigned long long)connection->response->total_size); + MHD_add_response_header (connection->response, + MHD_HTTP_HEADER_CONTENT_LENGTH, buf); + } +} + +/** + * Produce HTTP "Date:" header. + * + * @param date where to write the header, with + * at least 128 bytes available space. + */ +static void +get_date_string (char *date) +{ + static const char *days[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static const char *mons[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", + "Nov", "Dec" + }; + struct tm now; + time_t t; + + time (&t); + gmtime_r (&t, &now); + SPRINTF (date, + "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n", + days[now.tm_wday % 7], + now.tm_mday, + mons[now.tm_mon % 12], + 1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec); +} + +/** + * Try growing the read buffer + * + * @return MHD_YES on success, MHD_NO on failure + */ +static int +try_grow_read_buffer (struct MHD_Connection *connection) +{ + void *buf; + + buf = MHD_pool_reallocate (connection->pool, + connection->read_buffer, + connection->read_buffer_size, + connection->read_buffer_size * 2 + + MHD_BUF_INC_SIZE + 1); + if (buf == NULL) + return MHD_NO; + /* we can actually grow the buffer, do it! */ + connection->read_buffer = buf; + connection->read_buffer_size = + connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; + return MHD_YES; +} + +/** + * Allocate the connection's write buffer and + * fill it with all of the headers (or footers, + * if we have already sent the body) from the + * HTTPd's response. + */ +static int +build_header_response (struct MHD_Connection *connection) +{ + size_t size; + size_t off; + struct MHD_HTTP_Header *pos; + char code[256]; + char date[128]; + char *data; + enum MHD_ValueKind kind; + const char *reason_phrase; + + if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) + { + add_extra_headers (connection); + reason_phrase = MHD_get_reason_phrase_for (connection->responseCode); + SPRINTF (code, + "%s %u %s\r\n", + MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase); + off = strlen (code); + /* estimate size */ + size = off + 2; /* extra \r\n at the end */ + kind = MHD_HEADER_KIND; + if (NULL == MHD_get_response_header (connection->response, + MHD_HTTP_HEADER_DATE)) + get_date_string (date); + else + date[0] = '\0'; + size += strlen (date); + } + else + { + size = 2; + kind = MHD_FOOTER_KIND; + off = 0; + } + pos = connection->response->first_header; + while (pos != NULL) + { + if (pos->kind == kind) + size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */ + pos = pos->next; + } + /* produce data */ + data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES); + if (data == NULL) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "Not enough memory for write!\n"); +#endif + return MHD_NO; + } + if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) + { + memcpy (data, code, off); + } + pos = connection->response->first_header; + while (pos != NULL) + { + if (pos->kind == kind) + off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value); + pos = pos->next; + } + if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) + { + strcpy (&data[off], date); + off += strlen (date); + } + memcpy (&data[off], "\r\n", 2); + off += 2; + if (off != size) + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); + connection->write_buffer = data; + connection->write_buffer_append_offset = size; + connection->write_buffer_send_offset = 0; + connection->write_buffer_size = size + 1; + return MHD_YES; +} + +/** + * We encountered an error processing the request. + * Handle it properly by stopping to read data + * and sending the indicated response code and message. + * + * @param status_code the response code to send (400, 413 or 414) + */ +static void +transmit_error_response (struct MHD_Connection *connection, + unsigned int status_code, const char *message) +{ + struct MHD_Response *response; + + /* die, header far too long to be reasonable */ + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + connection->read_closed = MHD_YES; +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Error %u (`%s') processing request, closing connection.\n", + status_code, message); +#endif + response = MHD_create_response_from_data (strlen (message), + (void *) message, MHD_NO, MHD_NO); + MHD_queue_response (connection, status_code, response); + EXTRA_CHECK (connection->response != NULL); + MHD_destroy_response (response); + if (MHD_NO == build_header_response (connection)) + { + /* oops - close! */ +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Closing connection (failed to create response header)\n"); +#endif + connection->state = MHD_CONNECTION_CLOSED; + } + else + { + connection->state = MHD_CONNECTION_HEADERS_SENDING; + } +} + +/** + * Add "fd" to the "fd_set". If "fd" is + * greater than "*max", set "*max" to fd. + */ +static void +do_fd_set (int fd, fd_set * set, int *max_fd) +{ + FD_SET (fd, set); + if (fd > *max_fd) + *max_fd = fd; +} + +/** + * Obtain the select sets for this connection + * + * @return MHD_YES on success + */ +int +MHD_connection_get_fdset (struct MHD_Connection *connection, + fd_set * read_fd_set, + fd_set * write_fd_set, + fd_set * except_fd_set, int *max_fd) +{ + int ret; + struct MHD_Pollfd p; + + memset(&p, 0, sizeof(struct MHD_Pollfd)); + ret = MHD_connection_get_pollfd(connection, &p); + if ( (ret == MHD_YES) && (p.fd >= 0) ) { + if (0 != (p.events & MHD_POLL_ACTION_IN)) + do_fd_set(p.fd, read_fd_set, max_fd); + if (0 != (p.events & MHD_POLL_ACTION_OUT)) + do_fd_set(p.fd, write_fd_set, max_fd); + } + return ret; +} + +/** + * Obtain the pollfd for this connection + * + * @return MHD_YES on success. If return MHD_YES and p->fd < 0, this + * connection is not waiting for any read or write events + */ +int +MHD_connection_get_pollfd(struct MHD_Connection *connection, struct MHD_Pollfd *p) +{ + int fd; + + if (connection->pool == NULL) + connection->pool = MHD_pool_create (connection->daemon->pool_size); + if (connection->pool == NULL) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "Failed to create memory pool!\n"); +#endif + connection_close_error (connection); + return MHD_NO; + } + fd = connection->socket_fd; + p->fd = fd; + if (fd == -1) + return MHD_YES; + while (1) + { +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); +#endif + switch (connection->state) + { + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_URL_RECEIVED: + case MHD_CONNECTION_HEADER_PART_RECEIVED: +#if HTTPS_SUPPORT + case MHD_TLS_CONNECTION_INIT: +#endif + /* while reading headers, we always grow the + read buffer if needed, no size-check required */ + if ((connection->read_closed) && + (connection->read_buffer_offset == 0)) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + if ((connection->read_buffer_offset == connection->read_buffer_size) + && (MHD_NO == try_grow_read_buffer (connection))) + { + transmit_error_response (connection, + (connection->url != NULL) + ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE + : MHD_HTTP_REQUEST_URI_TOO_LONG, + REQUEST_TOO_BIG); + continue; + } + if (MHD_NO == connection->read_closed) + p->events |= MHD_POLL_ACTION_IN; + break; + case MHD_CONNECTION_HEADERS_RECEIVED: + /* we should never get here */ + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_HEADERS_PROCESSED: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_CONTINUE_SENDING: + p->events |= MHD_POLL_ACTION_OUT; + break; + case MHD_CONNECTION_CONTINUE_SENT: + if (connection->read_buffer_offset == connection->read_buffer_size) + { + if ((MHD_YES != try_grow_read_buffer (connection)) && + (0 != (connection->daemon->options & + (MHD_USE_SELECT_INTERNALLY | + MHD_USE_THREAD_PER_CONNECTION)))) + { + /* failed to grow the read buffer, and the + client which is supposed to handle the + received data in a *blocking* fashion + (in this mode) did not handle the data as + it was supposed to! + => we would either have to do busy-waiting + (on the client, which would likely fail), + or if we do nothing, we would just timeout + on the connection (if a timeout is even + set!). + Solution: we kill the connection with an error */ + transmit_error_response (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + INTERNAL_ERROR); + continue; + } + } + if ((connection->read_buffer_offset < connection->read_buffer_size) + && (MHD_NO == connection->read_closed)) + p->events |= MHD_POLL_ACTION_IN; + break; + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + /* while reading footers, we always grow the + read buffer if needed, no size-check required */ + if (MHD_YES == connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + p->events |= MHD_POLL_ACTION_IN; + /* transition to FOOTERS_RECEIVED + happens in read handler */ + break; + case MHD_CONNECTION_FOOTERS_RECEIVED: + /* no socket action, wait for client + to provide response */ + break; + case MHD_CONNECTION_HEADERS_SENDING: + /* headers in buffer, keep writing */ + p->events |= MHD_POLL_ACTION_OUT; + break; + case MHD_CONNECTION_HEADERS_SENT: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_NORMAL_BODY_READY: + p->events |= MHD_POLL_ACTION_OUT; + break; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + /* not ready, no socket action */ + break; + case MHD_CONNECTION_CHUNKED_BODY_READY: + p->events |= MHD_POLL_ACTION_OUT; + break; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + /* not ready, no socket action */ + break; + case MHD_CONNECTION_BODY_SENT: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_FOOTERS_SENDING: + p->events |= MHD_POLL_ACTION_OUT; + break; + case MHD_CONNECTION_FOOTERS_SENT: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + return MHD_YES; /* do nothing, not even reading */ + + default: + EXTRA_CHECK (0); + } + break; + } + return MHD_YES; +} + +/** + * Parse a single line of the HTTP header. Advance + * read_buffer (!) appropriately. If the current line does not + * fit, consider growing the buffer. If the line is + * far too long, close the connection. If no line is + * found (incomplete, buffer too small, line too long), + * return NULL. Otherwise return a pointer to the line. + */ +static char * +get_next_header_line (struct MHD_Connection *connection) +{ + char *rbuf; + size_t pos; + + if (connection->read_buffer_offset == 0) + return NULL; + pos = 0; + rbuf = connection->read_buffer; + while ((pos < connection->read_buffer_offset - 1) && + (rbuf[pos] != '\r') && (rbuf[pos] != '\n')) + pos++; + if (pos == connection->read_buffer_offset - 1) + { + /* not found, consider growing... */ + if (connection->read_buffer_offset == connection->read_buffer_size) + { + rbuf = MHD_pool_reallocate (connection->pool, + connection->read_buffer, + connection->read_buffer_size, + connection->read_buffer_size * 2 + + MHD_BUF_INC_SIZE); + if (rbuf == NULL) + { + transmit_error_response (connection, + (connection->url != NULL) + ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE + : MHD_HTTP_REQUEST_URI_TOO_LONG, + REQUEST_TOO_BIG); + } + else + { + connection->read_buffer_size = + connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE; + connection->read_buffer = rbuf; + } + } + return NULL; + } + /* found, check if we have proper CRLF */ + if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n')) + rbuf[pos++] = '\0'; /* skip both r and n */ + rbuf[pos++] = '\0'; + connection->read_buffer += pos; + connection->read_buffer_size -= pos; + connection->read_buffer_offset -= pos; + return rbuf; +} + +/** + * @return MHD_NO on failure (out of memory), MHD_YES for success + */ +static int +connection_add_header (struct MHD_Connection *connection, + char *key, char *value, enum MHD_ValueKind kind) +{ + struct MHD_HTTP_Header *hdr; + + hdr = MHD_pool_allocate (connection->pool, + sizeof (struct MHD_HTTP_Header), MHD_YES); + if (hdr == NULL) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Not enough memory to allocate header record!\n"); +#endif + transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } + hdr->next = connection->headers_received; + hdr->header = key; + hdr->value = value; + hdr->kind = kind; + connection->headers_received = hdr; + return MHD_YES; +} + +/** + * @return MHD_NO on failure (out of memory), MHD_YES for success + */ +static int +parse_arguments (enum MHD_ValueKind kind, + struct MHD_Connection *connection, char *args) +{ + char *equals; + char *amper; + + while (args != NULL) + { + equals = strstr (args, "="); + if (equals == NULL) + return MHD_NO; /* invalid, ignore */ + equals[0] = '\0'; + equals++; + amper = strstr (equals, "&"); + if (amper != NULL) + { + amper[0] = '\0'; + amper++; + } + MHD_http_unescape (args); + MHD_http_unescape (equals); + if (MHD_NO == connection_add_header (connection, args, equals, kind)) + return MHD_NO; + args = amper; + } + return MHD_YES; +} + +/** + * Parse the cookie header (see RFC 2109). + * + * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory) + */ +static int +parse_cookie_header (struct MHD_Connection *connection) +{ + const char *hdr; + char *cpy; + char *pos; + char *sce; + char *semicolon; + char *equals; + char *ekill; + char old; + int quotes; + + hdr = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_COOKIE); + if (hdr == NULL) + return MHD_YES; + cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES); + if (cpy == NULL) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n"); +#endif + transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } + memcpy (cpy, hdr, strlen (hdr) + 1); + pos = cpy; + while (pos != NULL) + { + while (*pos == ' ') + pos++; /* skip spaces */ + + sce = pos; + while (((*sce) != '\0') && + ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '=')) + sce++; + /* remove tailing whitespace (if any) from key */ + ekill = sce - 1; + while ((*ekill == ' ') && (ekill >= pos)) + *(ekill--) = '\0'; + old = *sce; + *sce = '\0'; + if (old != '=') + { + /* value part omitted, use empty string... */ + if (MHD_NO == + connection_add_header (connection, pos, "", MHD_COOKIE_KIND)) + return MHD_NO; + if (old == '\0') + break; + pos = sce + 1; + continue; + } + equals = sce + 1; + quotes = 0; + semicolon = equals; + while ((semicolon[0] != '\0') && + ((quotes != 0) || + ((semicolon[0] != ';') && (semicolon[0] != ',')))) + { + if (semicolon[0] == '"') + quotes = (quotes + 1) & 1; + semicolon++; + } + if (semicolon[0] == '\0') + semicolon = NULL; + if (semicolon != NULL) + { + semicolon[0] = '\0'; + semicolon++; + } + /* remove quotes */ + if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"')) + { + equals[strlen (equals) - 1] = '\0'; + equals++; + } + if (MHD_NO == connection_add_header (connection, + pos, equals, MHD_COOKIE_KIND)) + return MHD_NO; + pos = semicolon; + } + return MHD_YES; +} + +/** + * Parse the first line of the HTTP HEADER. + * + * @param connection the connection (updated) + * @param line the first line + * @return MHD_YES if the line is ok, MHD_NO if it is malformed + */ +static int +parse_initial_message_line (struct MHD_Connection *connection, char *line) +{ + char *uri; + char *httpVersion; + char *args; + + uri = strstr (line, " "); + if (uri == NULL) + return MHD_NO; /* serious error */ + uri[0] = '\0'; + connection->method = line; + uri++; + while (uri[0] == ' ') + uri++; + httpVersion = strstr (uri, " "); + if (httpVersion != NULL) + { + httpVersion[0] = '\0'; + httpVersion++; + } + if (connection->daemon->uri_log_callback != NULL) + connection->client_context + = + connection->daemon->uri_log_callback (connection->daemon-> + uri_log_callback_cls, uri); + args = strstr (uri, "?"); + if (args != NULL) + { + args[0] = '\0'; + args++; + parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args); + } + MHD_http_unescape (uri); + connection->url = uri; + if (httpVersion == NULL) + connection->version = ""; + else + connection->version = httpVersion; + return MHD_YES; +} + +/** + * Call the handler of the application for this + * connection. Handles chunking of the upload + * as well as normal uploads. + */ +static void +call_connection_handler (struct MHD_Connection *connection) +{ + size_t processed; + size_t available; + size_t used; + size_t i; + int instant_retry; + int malformed; + char *buffer_head; + + if (connection->response != NULL) + return; /* already queued a response */ + + buffer_head = connection->read_buffer; + available = connection->read_buffer_offset; + do + { + instant_retry = MHD_NO; + if ((connection->have_chunked_upload == MHD_YES) && + (connection->remaining_upload_size == MHD_SIZE_UNKNOWN)) + { + if ((connection->current_chunk_offset == + connection->current_chunk_size) + && (connection->current_chunk_offset != 0) && (available >= 2)) + { + /* skip new line at the *end* of a chunk */ + i = 0; + if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) + i++; /* skip 1st part of line feed */ + if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) + i++; /* skip 2nd part of line feed */ + if (i == 0) + { + /* malformed encoding */ +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); +#endif + connection_close_error (connection); + return; + } + available -= i; + buffer_head += i; + connection->current_chunk_offset = 0; + connection->current_chunk_size = 0; + } + if (connection->current_chunk_offset < + connection->current_chunk_size) + { + /* we are in the middle of a chunk, give + as much as possible to the client (without + crossing chunk boundaries) */ + processed = + connection->current_chunk_size - + connection->current_chunk_offset; + if (processed > available) + processed = available; + if (available > processed) + instant_retry = MHD_YES; + } + else + { + /* we need to read chunk boundaries */ + i = 0; + while (i < available) + { + if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')) + break; + i++; + if (i >= 6) + break; + } + /* take '\n' into account; if '\n' + is the unavailable character, we + will need to wait until we have it + before going further */ + if ((i + 1 >= available) && + !((i == 1) && (available == 2) && (buffer_head[0] == '0'))) + break; /* need more data... */ + malformed = (i >= 6); + if (!malformed) + { + buffer_head[i] = '\0'; + malformed = + (1 != SSCANF (buffer_head, "%X", + &connection->current_chunk_size)) && + (1 != SSCANF (buffer_head, "%x", + &connection->current_chunk_size)); + } + if (malformed) + { + /* malformed encoding */ +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received malformed HTTP request (bad chunked encoding), closing connection.\n"); +#endif + connection_close_error (connection); + return; + } + i++; + if ((i < available) && + ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))) + i++; /* skip 2nd part of line feed */ + + buffer_head += i; + available -= i; + connection->current_chunk_offset = 0; + + if (available > 0) + instant_retry = MHD_YES; + if (connection->current_chunk_size == 0) + { + connection->remaining_upload_size = 0; + break; + } + continue; + } + } + else + { + /* no chunked encoding, give all to the client */ + processed = available; + } + used = processed; + connection->client_aware = MHD_YES; + if (MHD_NO == + connection->daemon->default_handler (connection->daemon-> + default_handler_cls, + connection, connection->url, + connection->method, + connection->version, + buffer_head, &processed, + &connection->client_context)) + { + /* serious internal error, close connection */ +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Internal application error, closing connection.\n"); +#endif + connection_close_error (connection); + return; + } + if (processed > used) + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, +#if HAVE_MESSAGES + "API violation" +#else + NULL +#endif + ); + if (processed != 0) + instant_retry = MHD_NO; /* client did not process everything */ + used -= processed; + if (connection->have_chunked_upload == MHD_YES) + connection->current_chunk_offset += used; + /* dh left "processed" bytes in buffer for next time... */ + buffer_head += used; + available -= used; + if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN) + connection->remaining_upload_size -= used; + } + while (instant_retry == MHD_YES); + if (available > 0) + memmove (connection->read_buffer, buffer_head, available); + connection->read_buffer_offset = available; +} + +/** + * Try reading data from the socket into the + * read buffer of the connection. + * + * @return MHD_YES if something changed, + * MHD_NO if we were interrupted or if + * no space was available + */ +static int +do_read (struct MHD_Connection *connection) +{ + int bytes_read; + + if (connection->read_buffer_size == connection->read_buffer_offset) + return MHD_NO; + + bytes_read = connection->recv_cls (connection, + &connection->read_buffer + [connection->read_buffer_offset], + connection->read_buffer_size - + connection->read_buffer_offset); + if (bytes_read < 0) + { + if (errno == EINTR) + return MHD_NO; +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Failed to receive data: %s\n", STRERROR (errno)); +#endif + connection_close_error (connection); + return MHD_YES; + } + if (bytes_read == 0) + { + /* other side closed connection */ + connection->read_closed = MHD_YES; + SHUTDOWN (connection->socket_fd, SHUT_RD); + return MHD_NO; + } + connection->read_buffer_offset += bytes_read; + return MHD_YES; +} + +/** + * Try writing data to the socket from the + * write buffer of the connection. + * + * @return MHD_YES if something changed, + * MHD_NO if we were interrupted + */ +static int +do_write (struct MHD_Connection *connection) +{ + int ret; + + ret = connection->send_cls (connection, + &connection->write_buffer + [connection->write_buffer_send_offset], + connection->write_buffer_append_offset + - connection->write_buffer_send_offset); + + if (ret < 0) + { + if (errno == EINTR) + return MHD_NO; +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Failed to send data: %s\n", STRERROR (errno)); +#endif + connection_close_error (connection); + return MHD_YES; + } +#if DEBUG_SEND_DATA + FPRINTF (stderr, + "Sent response: `%.*s'\n", + ret, + &connection->write_buffer[connection->write_buffer_send_offset]); +#endif + connection->write_buffer_send_offset += ret; + return MHD_YES; +} + +/** + * Check if we are done sending the write-buffer. + * If so, transition into "next_state". + * @return MHY_NO if we are not done, MHD_YES if we are + */ +static int +check_write_done (struct MHD_Connection *connection, + enum MHD_CONNECTION_STATE next_state) +{ + if (connection->write_buffer_append_offset != + connection->write_buffer_send_offset) + return MHD_NO; + connection->write_buffer_append_offset = 0; + connection->write_buffer_send_offset = 0; + connection->state = next_state; + MHD_pool_reallocate (connection->pool, connection->write_buffer, + connection->write_buffer_size, 0); + connection->write_buffer = NULL; + connection->write_buffer_size = 0; + return MHD_YES; +} + +/** + * We have received (possibly the beginning of) a line in the + * header (or footer). Validate (check for ":") and prepare + * to process. + */ +static int +process_header_line (struct MHD_Connection *connection, char *line) +{ + char *colon; + + /* line should be normal header line, find colon */ + colon = strstr (line, ":"); + if (colon == NULL) + { + /* error in header line, die hard */ +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received malformed line (no colon), closing connection.\n"); +#endif + connection->state = MHD_CONNECTION_CLOSED; + return MHD_NO; + } + /* zero-terminate header */ + colon[0] = '\0'; + colon++; /* advance to value */ + while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t'))) + colon++; + /* we do the actual adding of the connection + header at the beginning of the while + loop since we need to be able to inspect + the *next* header line (in case it starts + with a space...) */ + connection->last = line; + connection->colon = colon; + return MHD_YES; +} + +/** + * Process a header value that spans multiple lines. + * The previous line(s) are in connection->last. + * + * @param line the current input line + * @param kind if the line is complete, add a header + * of the given kind + * @return MHD_YES if the line was processed successfully + */ +static int +process_broken_line (struct MHD_Connection *connection, + char *line, enum MHD_ValueKind kind) +{ + char *last; + char *tmp; + + last = connection->last; + if ((line[0] == ' ') || (line[0] == '\t')) + { + /* value was continued on the next line, see + http://www.jmarshall.com/easy/http/ */ + last = MHD_pool_reallocate (connection->pool, + last, + strlen (last) + 1, + strlen (line) + strlen (last) + 1); + if (last == NULL) + { + transmit_error_response (connection, + MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } + tmp = line; + while ((tmp[0] == ' ') || (tmp[0] == '\t')) + tmp++; /* skip whitespace at start of 2nd line */ + strcat (last, tmp); + connection->last = last; + return MHD_YES; /* possibly more than 2 lines... */ + } + EXTRA_CHECK ((last != NULL) && (connection->colon != NULL)); + if ((MHD_NO == connection_add_header (connection, + last, connection->colon, kind))) + { + transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, + REQUEST_TOO_BIG); + return MHD_NO; + } + /* we still have the current line to deal with... */ + if (strlen (line) != 0) + { + if (MHD_NO == process_header_line (connection, line)) + { + transmit_error_response (connection, + MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED); + return MHD_NO; + } + } + return MHD_YES; +} + +/** + * Parse the various headers; figure out the size + * of the upload and make sure the headers follow + * the protocol. Advance to the appropriate state. + */ +static void +parse_connection_headers (struct MHD_Connection *connection) +{ + const char *clen; + unsigned long long cval; + struct MHD_Response *response; + + parse_cookie_header (connection); + if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options)) + && (NULL != connection->version) + && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)) + && (NULL == + MHD_lookup_connection_value (connection, MHD_HEADER_KIND, + MHD_HTTP_HEADER_HOST))) + { + /* die, http 1.1 request without host and we are pedantic */ + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + connection->read_closed = MHD_YES; +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received `%s' request without `%s' header.\n", + MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST); +#endif + response = + MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST), + REQUEST_LACKS_HOST, MHD_NO, MHD_NO); + MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response); + MHD_destroy_response (response); + return; + } + + clen = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONTENT_LENGTH); + if (clen != NULL) + { + if (1 != SSCANF (clen, "%llu", &cval)) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Failed to parse `%s' header `%s', closing connection.\n", + MHD_HTTP_HEADER_CONTENT_LENGTH, clen); +#endif + connection->state = MHD_CONNECTION_CLOSED; + return; + } + connection->remaining_upload_size = cval; + } + else + { + if (NULL == MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_TRANSFER_ENCODING)) + { + /* this request does not have a body */ + connection->remaining_upload_size = 0; + } + else + { + connection->remaining_upload_size = MHD_SIZE_UNKNOWN; + if (0 == + strcasecmp (MHD_lookup_connection_value + (connection, MHD_HEADER_KIND, + MHD_HTTP_HEADER_TRANSFER_ENCODING), "chunked")) + connection->have_chunked_upload = MHD_YES; + } + } +} + +/** + * This function handles a particular connection when it has been + * determined that there is data to be read off a socket. All + * implementations (multithreaded, external select, internal select) + * call this function to handle reads. + * + * @return MHD_YES if we should continue to process the + * connection (not dead yet), MHD_NO if it died + */ +int +MHD_connection_handle_read (struct MHD_Connection *connection) +{ + connection->last_activity = time (NULL); + if (connection->state == MHD_CONNECTION_CLOSED) + return MHD_NO; + /* make sure "read" has a reasonable number of bytes + in buffer to use per system call (if possible) */ + if (connection->read_buffer_offset + MHD_BUF_INC_SIZE > + connection->read_buffer_size) + try_grow_read_buffer (connection); + if (MHD_NO == do_read (connection)) + return MHD_YES; + while (1) + { +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); +#endif + switch (connection->state) + { + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_URL_RECEIVED: + case MHD_CONNECTION_HEADER_PART_RECEIVED: + case MHD_CONNECTION_HEADERS_RECEIVED: + case MHD_CONNECTION_HEADERS_PROCESSED: + case MHD_CONNECTION_CONTINUE_SENDING: + case MHD_CONNECTION_CONTINUE_SENT: + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + /* nothing to do but default action */ + if (MHD_YES == connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + break; + case MHD_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + return MHD_NO; + default: + /* shrink read buffer to how much is actually used */ + MHD_pool_reallocate (connection->pool, + connection->read_buffer, + connection->read_buffer_size + 1, + connection->read_buffer_offset); + break; + } + break; + } + return MHD_YES; +} + +/** + * This function was created to handle writes to sockets when it has + * been determined that the socket can be written to. All + * implementations (multithreaded, external select, internal select) + * call this function + * + * @return MHD_YES if we should continue to process the + * connection (not dead yet), MHD_NO if it died + */ +int +MHD_connection_handle_write (struct MHD_Connection *connection) +{ + struct MHD_Response *response; + int ret; + connection->last_activity = time (NULL); + while (1) + { +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); +#endif + switch (connection->state) + { + case MHD_CONNECTION_INIT: + case MHD_CONNECTION_URL_RECEIVED: + case MHD_CONNECTION_HEADER_PART_RECEIVED: + case MHD_CONNECTION_HEADERS_RECEIVED: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_HEADERS_PROCESSED: + break; + case MHD_CONNECTION_CONTINUE_SENDING: + ret = connection->send_cls (connection, + &HTTP_100_CONTINUE + [connection->continue_message_write_offset], + strlen (HTTP_100_CONTINUE) - + connection->continue_message_write_offset); + if (ret < 0) + { + if (errno == EINTR) + break; +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Failed to send data: %s\n", STRERROR (errno)); +#endif + connection_close_error (connection); + return MHD_NO; + } +#if DEBUG_SEND_DATA + FPRINTF (stderr, + "Sent 100 continue response: `%.*s'\n", + ret, + &HTTP_100_CONTINUE + [connection->continue_message_write_offset]); +#endif + connection->continue_message_write_offset += ret; + break; + case MHD_CONNECTION_CONTINUE_SENT: + case MHD_CONNECTION_BODY_RECEIVED: + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + case MHD_CONNECTION_FOOTERS_RECEIVED: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_HEADERS_SENDING: + do_write (connection); + check_write_done (connection, MHD_CONNECTION_HEADERS_SENT); + break; + case MHD_CONNECTION_HEADERS_SENT: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_NORMAL_BODY_READY: + response = connection->response; + if (response->crc != NULL) + pthread_mutex_lock (&response->mutex); + if (MHD_YES != try_ready_normal_body (connection)) + { + if (response->crc != NULL) + pthread_mutex_unlock (&response->mutex); + connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; + break; + } +#if HTTPS_SUPPORT + if (connection->daemon->options & MHD_USE_SSL) + { + ret = MHD__gnutls_record_send (connection->tls_session, + &connection->response->data + [connection-> + response_write_position - + response->data_start], + response->data_size - + (connection->response_write_position + - response->data_start)); + } + else +#endif + { + ret = connection->send_cls (connection, + &response->data + [connection->response_write_position + - response->data_start], + response->data_size - + (connection->response_write_position + - response->data_start)); + } +#if DEBUG_SEND_DATA + if (ret > 0) + FPRINTF (stderr, + "Sent DATA response: `%.*s'\n", + ret, + &response->data[connection->response_write_position - + response->data_start]); +#endif + if (response->crc != NULL) + pthread_mutex_unlock (&response->mutex); + if (ret < 0) + { + if (errno == EINTR) + return MHD_YES; +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Failed to send data: %s\n", STRERROR (errno)); +#endif + connection_close_error (connection); + return MHD_NO; + } + connection->response_write_position += ret; + if (connection->response_write_position == + connection->response->total_size) + connection->state = MHD_CONNECTION_FOOTERS_SENT; /* have no footers... */ + break; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_CHUNKED_BODY_READY: + do_write (connection); + check_write_done (connection, + (connection->response->total_size == + connection->response_write_position) ? + MHD_CONNECTION_BODY_SENT : + MHD_CONNECTION_CHUNKED_BODY_UNREADY); + break; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + case MHD_CONNECTION_BODY_SENT: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_FOOTERS_SENDING: + do_write (connection); + check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT); + break; + case MHD_CONNECTION_FOOTERS_SENT: + EXTRA_CHECK (0); + break; + case MHD_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + return MHD_NO; + case MHD_TLS_CONNECTION_INIT: + case MHD_TLS_HELLO_REQUEST: + case MHD_TLS_HANDSHAKE_FAILED: + EXTRA_CHECK (0); + break; + default: + EXTRA_CHECK (0); + connection_close_error (connection); + return MHD_NO; + } + break; + } + return MHD_YES; +} + +/** + * This function was created to handle per-connection processing that + * has to happen even if the socket cannot be read or written to. All + * implementations (multithreaded, external select, internal select) + * call this function. + * + * @return MHD_YES if we should continue to process the + * connection (not dead yet), MHD_NO if it died + */ +int +MHD_connection_handle_idle (struct MHD_Connection *connection) +{ + unsigned int timeout; + const char *end; + char *line; + + while (1) + { +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); +#endif + switch (connection->state) + { + case MHD_CONNECTION_INIT: + line = get_next_header_line (connection); + if (line == NULL) + { + if (connection->state != MHD_CONNECTION_INIT) + continue; + if (connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + break; + } + if (MHD_NO == parse_initial_message_line (connection, line)) + connection->state = MHD_CONNECTION_CLOSED; + else + connection->state = MHD_CONNECTION_URL_RECEIVED; + continue; + case MHD_CONNECTION_URL_RECEIVED: + line = get_next_header_line (connection); + if (line == NULL) + { + if (connection->state != MHD_CONNECTION_URL_RECEIVED) + continue; + if (connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + break; + } + if (strlen (line) == 0) + { + connection->state = MHD_CONNECTION_HEADERS_RECEIVED; + continue; + } + if (MHD_NO == process_header_line (connection, line)) + { + transmit_error_response (connection, + MHD_HTTP_BAD_REQUEST, + REQUEST_MALFORMED); + break; + } + connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED; + continue; + case MHD_CONNECTION_HEADER_PART_RECEIVED: + line = get_next_header_line (connection); + if (line == NULL) + { + if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED) + continue; + if (connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + break; + } + if (MHD_NO == + process_broken_line (connection, line, MHD_HEADER_KIND)) + continue; + if (strlen (line) == 0) + { + connection->state = MHD_CONNECTION_HEADERS_RECEIVED; + continue; + } + continue; + case MHD_CONNECTION_HEADERS_RECEIVED: + parse_connection_headers (connection); + if (connection->state == MHD_CONNECTION_CLOSED) + continue; + connection->state = MHD_CONNECTION_HEADERS_PROCESSED; + continue; + case MHD_CONNECTION_HEADERS_PROCESSED: + call_connection_handler (connection); /* first call */ + if (connection->state == MHD_CONNECTION_CLOSED) + continue; + if (need_100_continue (connection)) + { + connection->state = MHD_CONNECTION_CONTINUE_SENDING; + break; + } + if (connection->response != NULL) + { + /* we refused (no upload allowed!) */ + connection->remaining_upload_size = 0; + /* force close, in case client still tries to upload... */ + connection->read_closed = MHD_YES; + } + connection->state = (connection->remaining_upload_size == 0) + ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT; + continue; + case MHD_CONNECTION_CONTINUE_SENDING: + if (connection->continue_message_write_offset == + strlen (HTTP_100_CONTINUE)) + { + connection->state = MHD_CONNECTION_CONTINUE_SENT; + continue; + } + break; + case MHD_CONNECTION_CONTINUE_SENT: + if (connection->read_buffer_offset != 0) + { + call_connection_handler (connection); /* loop call */ + if (connection->state == MHD_CONNECTION_CLOSED) + continue; + } + if ((connection->remaining_upload_size == 0) || + ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) && + (connection->read_buffer_offset == 0) && + (MHD_YES == connection->read_closed))) + { + if ((MHD_YES == connection->have_chunked_upload) && + (MHD_NO == connection->read_closed)) + connection->state = MHD_CONNECTION_BODY_RECEIVED; + else + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + continue; + } + break; + case MHD_CONNECTION_BODY_RECEIVED: + line = get_next_header_line (connection); + if (line == NULL) + { + if (connection->state != MHD_CONNECTION_BODY_RECEIVED) + continue; + if (connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + break; + } + if (strlen (line) == 0) + { + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + continue; + } + if (MHD_NO == process_header_line (connection, line)) + { + transmit_error_response (connection, + MHD_HTTP_BAD_REQUEST, + REQUEST_MALFORMED); + break; + } + connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED; + continue; + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + line = get_next_header_line (connection); + if (line == NULL) + { + if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED) + continue; + if (connection->read_closed) + { + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + break; + } + if (MHD_NO == + process_broken_line (connection, line, MHD_FOOTER_KIND)) + continue; + if (strlen (line) == 0) + { + connection->state = MHD_CONNECTION_FOOTERS_RECEIVED; + continue; + } + continue; + case MHD_CONNECTION_FOOTERS_RECEIVED: + call_connection_handler (connection); /* "final" call */ + if (connection->state == MHD_CONNECTION_CLOSED) + continue; + if (connection->response == NULL) + break; /* try again next time */ + if (MHD_NO == build_header_response (connection)) + { + /* oops - close! */ +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Closing connection (failed to create response header)\n"); +#endif + connection->state = MHD_CONNECTION_CLOSED; + continue; + } + connection->state = MHD_CONNECTION_HEADERS_SENDING; + +#if HAVE_DECL_TCP_CORK + /* starting header send, set TCP cork */ + { + const int val = 1; + setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, + sizeof (val)); + } +#endif + break; + case MHD_CONNECTION_HEADERS_SENDING: + /* no default action */ + break; + case MHD_CONNECTION_HEADERS_SENT: + if (connection->have_chunked_upload) + connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY; + else + connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY; + continue; + case MHD_CONNECTION_NORMAL_BODY_READY: + /* nothing to do here */ + break; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + if (connection->response->crc != NULL) + pthread_mutex_lock (&connection->response->mutex); + if (MHD_YES == try_ready_normal_body (connection)) + { + if (connection->response->crc != NULL) + pthread_mutex_unlock (&connection->response->mutex); + connection->state = MHD_CONNECTION_NORMAL_BODY_READY; + break; + } + if (connection->response->crc != NULL) + pthread_mutex_unlock (&connection->response->mutex); + /* not ready, no socket action */ + break; + case MHD_CONNECTION_CHUNKED_BODY_READY: + /* nothing to do here */ + break; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + if (connection->response->crc != NULL) + pthread_mutex_lock (&connection->response->mutex); + if (MHD_YES == try_ready_chunked_body (connection)) + { + if (connection->response->crc != NULL) + pthread_mutex_unlock (&connection->response->mutex); + connection->state = MHD_CONNECTION_CHUNKED_BODY_READY; + continue; + } + if (connection->response->crc != NULL) + pthread_mutex_unlock (&connection->response->mutex); + break; + case MHD_CONNECTION_BODY_SENT: + build_header_response (connection); + if (connection->write_buffer_send_offset == + connection->write_buffer_append_offset) + connection->state = MHD_CONNECTION_FOOTERS_SENT; + else + connection->state = MHD_CONNECTION_FOOTERS_SENDING; + continue; + case MHD_CONNECTION_FOOTERS_SENDING: + /* no default action */ + break; + case MHD_CONNECTION_FOOTERS_SENT: +#if HAVE_DECL_TCP_CORK + /* done sending, uncork */ + { + const int val = 0; + setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val, + sizeof (val)); + } +#endif + MHD_destroy_response (connection->response); + if (connection->daemon->notify_completed != NULL) + { + connection->daemon->notify_completed (connection->daemon-> + notify_completed_cls, + connection, + &connection->client_context, + MHD_REQUEST_TERMINATED_COMPLETED_OK); + } + connection->client_aware = MHD_NO; + end = + MHD_lookup_connection_value (connection, MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONNECTION); + connection->client_context = NULL; + connection->continue_message_write_offset = 0; + connection->responseCode = 0; + connection->response = NULL; + connection->headers_received = NULL; + connection->response_write_position = 0; + connection->have_chunked_upload = MHD_NO; + connection->method = NULL; + connection->url = NULL; + connection->write_buffer = NULL; + connection->write_buffer_size = 0; + connection->write_buffer_send_offset = 0; + connection->write_buffer_append_offset = 0; + if ((end != NULL) && (0 == strcasecmp (end, "close"))) + { + connection->read_closed = MHD_YES; + connection->read_buffer_offset = 0; + } + if (((MHD_YES == connection->read_closed) && + (0 == connection->read_buffer_offset)) || + (connection->version == NULL) || + (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))) + { + /* http 1.0, version-less requests cannot be pipelined */ + connection->state = MHD_CONNECTION_CLOSED; + MHD_pool_destroy (connection->pool); + connection->pool = NULL; + connection->read_buffer = NULL; + connection->read_buffer_size = 0; + connection->read_buffer_offset = 0; + } + else + { + connection->version = NULL; + connection->state = MHD_CONNECTION_INIT; + connection->read_buffer + = MHD_pool_reset (connection->pool, + connection->read_buffer, + connection->read_buffer_size); + } + continue; + case MHD_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + connection_close_error (connection); + break; + default: + EXTRA_CHECK (0); + break; + } + break; + } + timeout = connection->daemon->connection_timeout; + if ((connection->socket_fd != -1) && + (timeout != 0) && (time (NULL) - timeout > connection->last_activity)) + { + MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); + return MHD_NO; + } + return MHD_YES; + +} + +void +MHD_set_http_calbacks (struct MHD_Connection *connection) +{ + connection->read_handler = &MHD_connection_handle_read; + connection->write_handler = &MHD_connection_handle_write; + connection->idle_handler = &MHD_connection_handle_idle; +} + +#if HTTPS_SUPPORT +#include "gnutls_int.h" +#include "gnutls_record.h" +#endif + +/** + * Obtain information about the given connection. + * + * @param connection what connection to get information about + * @param infoType what information is desired? + * @param ... depends on infoType + * @return NULL if this information is not available + * (or if the infoType is unknown) + */ +const union MHD_ConnectionInfo * +MHD_get_connection_info (struct MHD_Connection *connection, + enum MHD_ConnectionInfoType infoType, ...) +{ + switch (infoType) + { +#if HTTPS_SUPPORT + case MHD_CONNECTION_INFO_CIPHER_ALGO: + if (connection->tls_session == NULL) + return NULL; + return (const union MHD_ConnectionInfo *) &connection-> + tls_session->security_parameters.read_bulk_cipher_algorithm; + case MHD_CONNECTION_INFO_PROTOCOL: + if (connection->tls_session == NULL) + return NULL; + return (const union MHD_ConnectionInfo *) &connection-> + tls_session->security_parameters.version; +#endif + case MHD_CONNECTION_INFO_CLIENT_ADDRESS: + return (const union MHD_ConnectionInfo *) &connection->addr; + default: + return NULL; + }; +} + + +/* end of connection.c */ diff --git a/lib/libmicrohttpd/src/daemon/connection.h b/lib/libmicrohttpd/src/daemon/connection.h new file mode 100644 index 0000000000..e7491590c2 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/connection.h @@ -0,0 +1,66 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file connection.h + * @brief Methods for managing connections + * @author Daniel Pittman + * @author Christian Grothoff + */ + +#ifndef CONNECTION_H +#define CONNECTION_H + +#include "internal.h" + +/** + * Obtain the select sets for this connection. + * + * @return MHD_YES on success + */ +int +MHD_connection_get_fdset (struct MHD_Connection *connection, + fd_set * read_fd_set, + fd_set * write_fd_set, + fd_set * except_fd_set, int *max_fd); + +/** + * Obtain the pollfd for this connection. The poll interface allows large + * file descriptors. Select goes stupid when the fd overflows fdset (which + * is fixed). + */ +int MHD_connection_get_pollfd(struct MHD_Connection *connection, + struct MHD_Pollfd *p); + +void MHD_set_http_calbacks (struct MHD_Connection *connection); + +int MHD_connection_handle_read (struct MHD_Connection *connection); + +int MHD_connection_handle_write (struct MHD_Connection *connection); + +int MHD_connection_handle_idle (struct MHD_Connection *connection); + +/** + * Close the given connection and give the + * specified termination code to the user. + */ +void MHD_connection_close (struct MHD_Connection *connection, + enum MHD_RequestTerminationCode termination_code); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/connection_https.c b/lib/libmicrohttpd/src/daemon/connection_https.c new file mode 100644 index 0000000000..b5b1a4ba8f --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/connection_https.c @@ -0,0 +1,309 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** + * @file connection.c + * @brief Methods for managing SSL/TLS connections. This file is only + * compiled if ENABLE_HTTPS is set. + * @author Sagie Amir + * @author Christian Grothoff + */ + +#include "internal.h" +#include "connection.h" +#include "memorypool.h" +#include "response.h" +#include "reason_phrase.h" + +/* get opaque type */ +#include "gnutls_int.h" +#include "gnutls_record.h" + +/* TODO #include rm "gnutls_errors.h" */ +#include "gnutls_errors.h" + +/** + * This function is called once a secure connection has been marked + * for closure. + * + * NOTE: Some code duplication with connection_close_error + * in connection.c + * + * @param connection: the connection to close + * @param termination_code: the termination code with which the notify completed callback function is called. + */ +static void +MHD_tls_connection_close (struct MHD_Connection *connection, + enum MHD_RequestTerminationCode termination_code) +{ + MHD__gnutls_bye (connection->tls_session, GNUTLS_SHUT_WR); + connection->tls_session->internals.read_eof = 1; + MHD_connection_close (connection, termination_code); +} + +/** + * This function was created to handle per-connection processing that + * has to happen even if the socket cannot be read or written to. All + * implementations (multithreaded, external select, internal select) + * call this function. + * + * @param connection being handled + * @return MHD_YES if we should continue to process the + * connection (not dead yet), MHD_NO if it died + */ +static int +MHD_tls_connection_handle_idle (struct MHD_Connection *connection) +{ + unsigned int timeout; + +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); +#endif + timeout = connection->daemon->connection_timeout; + if ((connection->socket_fd != -1) && (timeout != 0) + && (time (NULL) - timeout > connection->last_activity)) + { + MHD_tls_connection_close (connection, + MHD_REQUEST_TERMINATED_TIMEOUT_REACHED); + return MHD_NO; + } + switch (connection->state) + { + /* on newly created connections we might reach here before any reply has been received */ + case MHD_TLS_CONNECTION_INIT: + return MHD_YES; + /* close connection if necessary */ + case MHD_CONNECTION_CLOSED: + if (connection->socket_fd != -1) + MHD_tls_connection_close (connection, + MHD_REQUEST_TERMINATED_COMPLETED_OK); + return MHD_NO; + case MHD_TLS_HANDSHAKE_FAILED: + MHD_tls_connection_close (connection, + MHD_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; + /* some HTTP state */ + default: + return MHD_connection_handle_idle (connection); + } + return MHD_YES; +} + +/** + * This function handles a particular SSL/TLS connection when + * it has been determined that there is data to be read off a + * socket. Message processing is done by message type which is + * determined by peeking into the first message type byte of the + * stream. + * + * Error message handling: all fatal level messages cause the + * connection to be terminated. + * + * Application data is forwarded to the underlying daemon for + * processing. + * + * @param connection : the source connection + * @return MHD_YES if we should continue to process the + * connection (not dead yet), MHD_NO if it died + */ +static int +MHD_tls_connection_handle_read (struct MHD_Connection *connection) +{ + int ret; + unsigned char msg_type; + + connection->last_activity = time (NULL); + if (connection->state == MHD_CONNECTION_CLOSED || + connection->state == MHD_TLS_HANDSHAKE_FAILED) + return MHD_NO; + +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); +#endif + + /* discover content type */ + if (RECV (connection->socket_fd, &msg_type, 1, MSG_PEEK) == -1) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, "Failed to peek into TLS content type\n"); +#endif + return MHD_NO; + } + + switch (msg_type) + { + /* check for handshake messages first */ + case GNUTLS_HANDSHAKE: + /* negotiate handshake only while in INIT & HELLO_REQUEST states */ + if (connection->state == MHD_TLS_CONNECTION_INIT || + connection->state == MHD_TLS_HELLO_REQUEST) + { + ret = MHD__gnutls_handshake (connection->tls_session); + if (ret == 0) + { + /* set connection state to enable HTTP processing */ + connection->state = MHD_CONNECTION_INIT; + break; + } + /* set connection as closed */ + else + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Error: Handshake has failed (%d)\n", ret); +#endif + connection->state = MHD_TLS_HANDSHAKE_FAILED; + return MHD_NO; + } + } + /* a handshake message has been received out of bound */ + else + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Error: received handshake message out of context\n"); +#endif + MHD_tls_connection_close (connection, + MHD_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; + } + + /* ignore any out of bound change chiper spec messages */ + case GNUTLS_CHANGE_CIPHER_SPEC: + MHD_tls_connection_close (connection, + MHD_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; + + case GNUTLS_ALERT: + /* + * this call of MHD_gtls_recv_int expects 0 bytes read. + * done to decrypt alert message + */ + MHD_gtls_recv_int (connection->tls_session, GNUTLS_ALERT, + GNUTLS_HANDSHAKE_FINISHED, 0, 0); + + /* CLOSE_NOTIFY */ + if (connection->tls_session->internals.last_alert == + GNUTLS_A_CLOSE_NOTIFY) + { + connection->state = MHD_CONNECTION_CLOSED; + return MHD_YES; + } + /* non FATAL or WARNING */ + else if (connection->tls_session->internals.last_alert_level != + GNUTLS_AL_FATAL) + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received TLS alert: %s\n", + MHD__gnutls_alert_get_name ((int) + connection->tls_session-> + internals.last_alert)); +#endif + return MHD_YES; + } + /* FATAL */ + else if (connection->tls_session->internals.last_alert_level == + GNUTLS_AL_FATAL) + { + MHD_tls_connection_close (connection, + MHD_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; + } + /* this should never execute */ + else + { +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Received unrecognized alert: %d\n", + connection->tls_session->internals.last_alert); +#endif + return MHD_NO; + } + + + /* forward application level content to MHD */ + case GNUTLS_APPLICATION_DATA: + return MHD_connection_handle_read (connection); + + case GNUTLS_INNER_APPLICATION: + break; + default: +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Error: unrecognized TLS message type: %d, connection state: %s. l: %d, f: %s\n", + msg_type, MHD_state_to_string (connection->state), __LINE__, + __FUNCTION__); +#endif + /* close connection upon reception of unrecognized message type */ + MHD_tls_connection_close (connection, + MHD_REQUEST_TERMINATED_WITH_ERROR); + return MHD_NO; + } + + return MHD_YES; +} + +/** + * This function was created to handle writes to sockets when it has + * been determined that the socket can be written to. This function + * will forward all write requests to the underlying daemon unless + * the connection has been marked for closing. + * + * @return MHD_connection_handle_write() if we should continue to + * process the connection (not dead yet), MHD_NO if it died + */ +static int +MHD_tls_connection_handle_write (struct MHD_Connection *connection) +{ + connection->last_activity = time (NULL); + +#if DEBUG_STATES + MHD_DLOG (connection->daemon, "%s: state: %s\n", + __FUNCTION__, MHD_state_to_string (connection->state)); +#endif + + switch (connection->state) + { + case MHD_CONNECTION_CLOSED: + case MHD_TLS_HANDSHAKE_FAILED: + return MHD_NO; + /* some HTTP connection state */ + default: + return MHD_connection_handle_write (connection); + } + return MHD_NO; +} + +/** + * Set connection callback function to be used through out + * the processing of this secure connection. + */ +void +MHD_set_https_calbacks (struct MHD_Connection *connection) +{ + connection->read_handler = &MHD_tls_connection_handle_read; + connection->write_handler = &MHD_tls_connection_handle_write; + connection->idle_handler = &MHD_tls_connection_handle_idle; +} + +/* end of connection_https.c */ diff --git a/lib/libmicrohttpd/src/daemon/connection_https.h b/lib/libmicrohttpd/src/daemon/connection_https.h new file mode 100644 index 0000000000..ef6f5dc683 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/connection_https.h @@ -0,0 +1,35 @@ +/* + This file is part of libmicrohttpd + (C) 2008 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file connection_https.h + * @brief Methods for managing connections + * @author Christian Grothoff + */ + +#ifndef CONNECTION_HTTPS_H +#define CONNECTION_HTTPS_H + +#include "internal.h" + +#if HTTPS_SUPPORT +void MHD_set_https_calbacks (struct MHD_Connection *connection); +#endif + +#endif diff --git a/lib/libmicrohttpd/src/daemon/daemon.c b/lib/libmicrohttpd/src/daemon/daemon.c new file mode 100644 index 0000000000..98b22bdd95 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/daemon.c @@ -0,0 +1,1971 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008, 2009 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** + * @file daemon.c + * @brief A minimal-HTTP server library + * @author Daniel Pittman + * @author Christian Grothoff + */ +#include "platform.h" +#include "internal.h" +#include "response.h" +#include "connection.h" +#include "memorypool.h" + +#if HTTPS_SUPPORT +#include "connection_https.h" +#include "gnutls_int.h" +#include "gnutls_global.h" +#endif + +#ifdef HAVE_POLL_H +#include <poll.h> +#endif + +/** + * Default connection limit. + */ +#ifndef WINDOWS +#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE -4 +#else +#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE +#endif + +/** + * Default memory allowed per connection. + */ +#define MHD_POOL_SIZE_DEFAULT (32 * 1024) + +/** + * Print extra messages with reasons for closing + * sockets? (only adds non-error messages). + */ +#define DEBUG_CLOSE MHD_NO + +/** + * Print extra messages when establishing + * connections? (only adds non-error messages). + */ +#define DEBUG_CONNECT MHD_NO + +#ifndef LINUX +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif +#endif + +#ifdef __SYMBIAN32__ +static void pthread_kill (int, int) { + // Symbian doesn't have signals. The user of the library is required to + // run it in an external select loop. + abort(); +} +#endif // __SYMBIAN32__ + +/** + * Default implementation of the panic function + */ +static void +mhd_panic_std(void *cls, + const char *file, + unsigned int line, + const char *reason) +{ + abort (); +} + + +/** + * Handler for fatal errors. + */ +MHD_PanicCallback mhd_panic; + +/** + * Closure argument for "mhd_panic". + */ +void *mhd_panic_cls; + +/** + * Trace up to and return master daemon. If the supplied daemon + * is a master, then return the daemon itself. + */ +static struct MHD_Daemon* +MHD_get_master (struct MHD_Daemon *daemon) +{ + while (NULL != daemon->master) + daemon = daemon->master; + return daemon; +} + +/** + * Maintain connection count for single address. + */ +struct MHD_IPCount +{ + int family; + union + { + struct in_addr ipv4; +#if HAVE_IPV6 + struct in6_addr ipv6; +#endif + } addr; + unsigned int count; +}; + +/** + * Lock shared structure for IP connection counts + */ +static void +MHD_ip_count_lock(struct MHD_Daemon *daemon) +{ + if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex)) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to acquire IP connection limit mutex\n"); +#endif + abort(); + } +} + +/** + * Unlock shared structure for IP connection counts + */ +static void +MHD_ip_count_unlock(struct MHD_Daemon *daemon) +{ + if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex)) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to release IP connection limit mutex\n"); +#endif + abort(); + } +} + +/** + * Tree comparison function for IP addresses (supplied to tsearch() family). + * We compare everything in the struct up through the beginning of the + * 'count' field. + */ +static int +MHD_ip_addr_compare(const void *a1, const void *a2) +{ + return memcmp (a1, a2, offsetof(struct MHD_IPCount, count)); +} + +/** + * Parse address and initialize 'key' using the address. Returns MHD_YES + * on success and MHD_NO otherwise (e.g., invalid address type). + */ +static int +MHD_ip_addr_to_key(struct sockaddr *addr, socklen_t addrlen, + struct MHD_IPCount *key) +{ + memset(key, 0, sizeof(*key)); + + /* IPv4 addresses */ + if (addrlen == sizeof(struct sockaddr_in)) + { + const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr; + key->family = AF_INET; + memcpy (&key->addr.ipv4, &addr4->sin_addr, sizeof(addr4->sin_addr)); + return MHD_YES; + } + +#if HAVE_IPV6 + /* IPv6 addresses */ + if (addrlen == sizeof (struct sockaddr_in6)) + { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)addr; + key->family = AF_INET6; + memcpy (&key->addr.ipv6, &addr6->sin6_addr, sizeof(addr6->sin6_addr)); + return MHD_YES; + } +#endif + + /* Some other address */ + return MHD_NO; +} + +/** + * Check if IP address is over its limit. + * + * @return Return MHD_YES if IP below limit, MHD_NO if IP has surpassed limit. + * Also returns MHD_NO if fails to allocate memory. + */ +static int +MHD_ip_limit_add(struct MHD_Daemon *daemon, + struct sockaddr *addr, socklen_t addrlen) +{ + struct MHD_IPCount *key; + void *node; + int result; + + daemon = MHD_get_master (daemon); + + /* Ignore if no connection limit assigned */ + if (daemon->per_ip_connection_limit == 0) + return MHD_YES; + + key = malloc (sizeof(*key)); + if (NULL == key) + return MHD_NO; + + /* Initialize key */ + if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, key)) + { + /* Allow unhandled address types through */ + free (key); + return MHD_YES; + } + + MHD_ip_count_lock (daemon); + + /* Search for the IP address */ + node = (void*)TSEARCH (key, &daemon->per_ip_connection_count, MHD_ip_addr_compare); + if (!node) + { +#if HAVE_MESSAGES + MHD_DLOG(daemon, + "Failed to add IP connection count node\n"); +#endif + MHD_ip_count_unlock (daemon); + return MHD_NO; + } + node = *(void**)node; + + /* If we got an existing node back, free the one we created */ + if (node != key) + free(key); + key = (struct MHD_IPCount*)node; + + /* Test if there is room for another connection; if so, + * increment count */ + result = (key->count < daemon->per_ip_connection_limit); + if (result == MHD_YES) + ++key->count; + + MHD_ip_count_unlock (daemon); + return result; +} + +/** + * Decrement connection count for IP address, removing from table + * count reaches 0 + */ +static void +MHD_ip_limit_del(struct MHD_Daemon *daemon, + struct sockaddr *addr, socklen_t addrlen) +{ + struct MHD_IPCount search_key; + struct MHD_IPCount *found_key; + void *node; + + daemon = MHD_get_master (daemon); + + /* Ignore if no connection limit assigned */ + if (daemon->per_ip_connection_limit == 0) + return; + + /* Initialize search key */ + if (MHD_NO == MHD_ip_addr_to_key (addr, addrlen, &search_key)) + return; + + MHD_ip_count_lock (daemon); + + /* Search for the IP address */ + node = (void*)TFIND (&search_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare); + + /* Something's wrong if we couldn't find an IP address + * that was previously added */ + if (!node) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, + "Failed to find previously-added IP address\n"); +#endif + abort(); + } + found_key = (struct MHD_IPCount*)*(void**)node; + + /* Validate existing count for IP address */ + if (found_key->count == 0) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, + "Previously-added IP address had 0 count\n"); +#endif + abort(); + } + + /* Remove the node entirely if count reduces to 0 */ + if (--found_key->count == 0) + { + TDELETE (found_key, &daemon->per_ip_connection_count, MHD_ip_addr_compare); + free (found_key); + } + + MHD_ip_count_unlock (daemon); +} + +#if HTTPS_SUPPORT +pthread_mutex_t MHD_gnutls_init_mutex; + +/** + * Note: code duplication with code in MHD_gnutls_priority.c + * + * @return 0 + */ +static int +_set_priority (MHD_gtls_priority_st * st, const int *list) +{ + int num = 0; + + while ((list[num] != 0) && (num < MAX_ALGOS)) + num++; + st->num_algorithms = num; + memcpy (st->priority, list, num * sizeof (int)); + return 0; +} + + +/** + * Callback for receiving data from the socket. + * + * @param conn the MHD connection structure + * @param other where to write received data to + * @param i maximum size of other (in bytes) + * @return number of bytes actually received + */ +static ssize_t +recv_tls_adapter (struct MHD_Connection *connection, void *other, size_t i) +{ + return MHD__gnutls_record_recv (connection->tls_session, other, i); +} + +/** + * Callback for writing data to the socket. + * + * @param conn the MHD connection structure + * @param other data to write + * @param i number of bytes to write + * @return actual number of bytes written + */ +static ssize_t +send_tls_adapter (struct MHD_Connection *connection, + const void *other, size_t i) +{ + return MHD__gnutls_record_send (connection->tls_session, other, i); +} + + +/** + * Read and setup our certificate and key. + * + * @return 0 on success + */ +static int +MHD_init_daemon_certificate (struct MHD_Daemon *daemon) +{ + MHD_gnutls_datum_t key; + MHD_gnutls_datum_t cert; + + /* certificate & key loaded from memory */ + if (daemon->https_mem_cert && daemon->https_mem_key) + { + key.data = (unsigned char *) daemon->https_mem_key; + key.size = strlen (daemon->https_mem_key); + cert.data = (unsigned char *) daemon->https_mem_cert; + cert.size = strlen (daemon->https_mem_cert); + + return MHD__gnutls_certificate_set_x509_key_mem (daemon->x509_cred, + &cert, &key, + GNUTLS_X509_FMT_PEM); + } +#if HAVE_MESSAGES + MHD_DLOG (daemon, "You need to specify a certificate and key location\n"); +#endif + return -1; +} + +/** + * Initialize security aspects of the HTTPS daemon + * + * @return 0 on success + */ +static int +MHD_TLS_init (struct MHD_Daemon *daemon) +{ + switch (daemon->cred_type) + { + case MHD_GNUTLS_CRD_CERTIFICATE: + if (0 != + MHD__gnutls_certificate_allocate_credentials (&daemon->x509_cred)) + return GNUTLS_E_MEMORY_ERROR; + return MHD_init_daemon_certificate (daemon); + default: +#if HAVE_MESSAGES + MHD_DLOG (daemon, + "Error: invalid credentials type %d specified.\n", + daemon->cred_type); +#endif + return -1; + } +} +#endif + +/** + * Obtain the select sets for this daemon. + * + * @return MHD_YES on success, MHD_NO if this + * daemon was not started with the right + * options for this call. + */ +int +MHD_get_fdset (struct MHD_Daemon *daemon, + fd_set * read_fd_set, + fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd) +{ + struct MHD_Connection *con_itr; + int fd; + + if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL) + || (except_fd_set == NULL) || (max_fd == NULL) + || (-1 == (fd = daemon->socket_fd)) || (daemon->shutdown == MHD_YES) + || ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0) + || ((daemon->options & MHD_USE_POLL) != 0)) + return MHD_NO; + + FD_SET (fd, read_fd_set); + /* update max file descriptor */ + if ((*max_fd) < fd) + *max_fd = fd; + + con_itr = daemon->connections; + while (con_itr != NULL) + { + if (MHD_YES != MHD_connection_get_fdset (con_itr, + read_fd_set, + write_fd_set, + except_fd_set, max_fd)) + return MHD_NO; + con_itr = con_itr->next; + } +#if DEBUG_CONNECT + MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd); +#endif + return MHD_YES; +} + +/** + * Main function of the thread that handles an individual + * connection when MHD_USE_THREAD_PER_CONNECTION. + */ +static void * +MHD_handle_connection (void *data) +{ + struct MHD_Connection *con = data; + int num_ready; + fd_set rs; + fd_set ws; + fd_set es; + int max; + struct timeval tv; + unsigned int timeout; + time_t now; +#ifdef HAVE_POLL_H + struct MHD_Pollfd mp; + struct pollfd p; +#endif + + timeout = con->daemon->connection_timeout; + while ((!con->daemon->shutdown) && (con->socket_fd != -1)) { + now = time (NULL); + tv.tv_usec = 0; + if ( (timeout > (now - con->last_activity)) || + (timeout == 0) ) + { + /* in case we are missing the SIGALRM, keep going after + at most 1s; see http://lists.gnu.org/archive/html/libmicrohttpd/2009-10/msg00013.html */ + tv.tv_sec = 1; + if ((con->state == MHD_CONNECTION_NORMAL_BODY_UNREADY) || + (con->state == MHD_CONNECTION_CHUNKED_BODY_UNREADY)) + { + /* do not block (we're waiting for our callback to succeed) */ + tv.tv_sec = 0; + } + } + else + { + tv.tv_sec = 0; + } +#ifdef HAVE_POLL_H + if (0 == (con->daemon->options & MHD_USE_POLL)) { +#else + { +#endif + /* use select */ + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + max = 0; + MHD_connection_get_fdset (con, &rs, &ws, &es, &max); + num_ready = SELECT (max + 1, &rs, &ws, &es, &tv); + if (num_ready < 0) { + if (errno == EINTR) + continue; +#if HAVE_MESSAGES + MHD_DLOG (con->daemon, "Error during select (%d): `%s'\n", max, + STRERROR (errno)); +#endif + break; + } + /* call appropriate connection handler if necessary */ + if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &rs))) + con->read_handler (con); + if ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws))) + con->write_handler (con); + if (con->socket_fd != -1) + con->idle_handler (con); + } +#ifdef HAVE_POLL_H + else + { + /* use poll */ + memset(&mp, 0, sizeof (struct MHD_Pollfd)); + MHD_connection_get_pollfd(con, &mp); + memset(&p, 0, sizeof (struct pollfd)); + p.fd = mp.fd; + if (mp.events & MHD_POLL_ACTION_IN) + p.events |= POLLIN; + if (mp.events & MHD_POLL_ACTION_OUT) + p.events |= POLLOUT; + /* in case we are missing the SIGALRM, keep going after + at most 1s */ + if (poll (&p, 1, 1000) < 0) { + if (errno == EINTR) + continue; +#if HAVE_MESSAGES + MHD_DLOG (con->daemon, "Error during poll: `%s'\n", + STRERROR (errno)); +#endif + break; + } + if ( (con->socket_fd != -1) && + (0 != (p.revents & POLLIN)) ) + con->read_handler (con); + if ( (con->socket_fd != -1) && + (0 != (p.revents & POLLOUT)) ) + con->write_handler (con); + if (con->socket_fd != -1) + con->idle_handler (con); + if ( (con->socket_fd != -1) && + (0 != (p.revents & (POLLERR | POLLHUP))) ) + MHD_connection_close (con, MHD_REQUEST_TERMINATED_WITH_ERROR); + } +#endif + } + if (con->socket_fd != -1) + { +#if DEBUG_CLOSE +#if HAVE_MESSAGES + MHD_DLOG (con->daemon, + "Processing thread terminating, closing connection\n"); +#endif +#endif + MHD_connection_close (con, MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); + } + return NULL; +} + +/** + * Callback for receiving data from the socket. + * + * @param conn the MHD connection structure + * @param other where to write received data to + * @param i maximum size of other (in bytes) + * @return number of bytes actually received + */ +static ssize_t +recv_param_adapter (struct MHD_Connection *connection, void *other, size_t i) +{ + if (connection->socket_fd == -1) + return -1; + if (0 != (connection->daemon->options & MHD_USE_SSL)) + return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL); + else + return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT); +} + +/** + * Callback for writing data to the socket. + * + * @param conn the MHD connection structure + * @param other data to write + * @param i number of bytes to write + * @return actual number of bytes written + */ +static ssize_t +send_param_adapter (struct MHD_Connection *connection, + const void *other, size_t i) +{ + if (connection->socket_fd == -1) + return -1; + if (0 != (connection->daemon->options & MHD_USE_SSL)) + return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL); + else + return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL | MSG_DONTWAIT); +} + +/** + * Accept an incoming connection and create the MHD_Connection object for + * it. This function also enforces policy by way of checking with the + * accept policy callback. + */ +static int +MHD_accept_connection (struct MHD_Daemon *daemon) +{ + struct MHD_Connection *connection; +#if HAVE_INET6 + struct sockaddr_in6 addrstorage; +#else + struct sockaddr_in addrstorage; +#endif + struct sockaddr *addr = (struct sockaddr *) &addrstorage; + socklen_t addrlen; + int s; + int res_thread_create; +#if OSX + static int on = 1; +#endif + + addrlen = sizeof (addrstorage); + memset (addr, 0, sizeof (addrstorage)); + + s = ACCEPT (daemon->socket_fd, addr, &addrlen); + if ((s == -1) || (addrlen <= 0)) + { +#if HAVE_MESSAGES + /* This could be a common occurance with multiple worker threads */ + if ((EAGAIN != errno) && (EWOULDBLOCK != errno)) + MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); +#endif + if (s != -1) + { + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + /* just in case */ + } + return MHD_NO; + } +#ifndef WINDOWS + if ( (s >= FD_SETSIZE) && + (0 == (daemon->options & MHD_USE_POLL)) ) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, + "Socket descriptor larger than FD_SETSIZE: %d > %d\n", + s, + FD_SETSIZE); +#endif + CLOSE (s); + return MHD_NO; + } +#endif + + +#if HAVE_MESSAGES +#if DEBUG_CONNECT + MHD_DLOG (daemon, "Accepted connection on socket %d\n", s); +#endif +#endif + if ((daemon->max_connections == 0) + || (MHD_ip_limit_add (daemon, addr, addrlen) == MHD_NO)) + { + /* above connection limit - reject */ +#if HAVE_MESSAGES + MHD_DLOG (daemon, + "Server reached connection limit (closing inbound connection)\n"); +#endif + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + return MHD_NO; + } + + /* apply connection acceptance policy if present */ + if ((daemon->apc != NULL) + && (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen))) + { +#if DEBUG_CLOSE +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Connection rejected, closing connection\n"); +#endif +#endif + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + MHD_ip_limit_del (daemon, addr, addrlen); + return MHD_YES; + } +#if OSX +#ifdef SOL_SOCKET +#ifdef SO_NOSIGPIPE + setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof (on)); +#endif +#endif +#endif + connection = malloc (sizeof (struct MHD_Connection)); + if (NULL == connection) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); +#endif + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + MHD_ip_limit_del (daemon, addr, addrlen); + return MHD_NO; + } + memset (connection, 0, sizeof (struct MHD_Connection)); + connection->pool = NULL; + connection->addr = malloc (addrlen); + if (connection->addr == NULL) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Error allocating memory: %s\n", STRERROR (errno)); +#endif + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + MHD_ip_limit_del (daemon, addr, addrlen); + free (connection); + return MHD_NO; + } + memcpy (connection->addr, addr, addrlen); + connection->addr_len = addrlen; + connection->socket_fd = s; + connection->daemon = daemon; + connection->last_activity = time (NULL); + + /* set default connection handlers */ + MHD_set_http_calbacks (connection); + connection->recv_cls = &recv_param_adapter; + connection->send_cls = &send_param_adapter; +#if HTTPS_SUPPORT + if (0 != (daemon->options & MHD_USE_SSL)) + { + connection->recv_cls = &recv_tls_adapter; + connection->send_cls = &send_tls_adapter; + connection->state = MHD_TLS_CONNECTION_INIT; + MHD_set_https_calbacks (connection); + MHD__gnutls_init (&connection->tls_session, GNUTLS_SERVER); + MHD__gnutls_priority_set (connection->tls_session, + connection->daemon->priority_cache); + switch (connection->daemon->cred_type) + { + /* set needed credentials for certificate authentication. */ + case MHD_GNUTLS_CRD_CERTIFICATE: + MHD__gnutls_credentials_set (connection->tls_session, + MHD_GNUTLS_CRD_CERTIFICATE, + connection->daemon->x509_cred); + break; + default: +#if HAVE_MESSAGES + MHD_DLOG (connection->daemon, + "Failed to setup TLS credentials: unknown credential type %d\n", + connection->daemon->cred_type); +#endif + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + MHD_ip_limit_del (daemon, addr, addrlen); + free (connection->addr); + free (connection); + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, +#if HAVE_MESSAGES + "Unknown credential type" +#else + NULL +#endif + ); + return MHD_NO; + } + MHD__gnutls_transport_set_ptr (connection->tls_session, + (MHD_gnutls_transport_ptr_t) connection); + MHD__gnutls_transport_set_pull_function (connection->tls_session, + (MHD_gtls_pull_func) & + recv_param_adapter); + MHD__gnutls_transport_set_push_function (connection->tls_session, + (MHD_gtls_push_func) & + send_param_adapter); + } +#endif + + /* attempt to create handler thread */ + if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + { + res_thread_create = pthread_create (&connection->pid, NULL, + &MHD_handle_connection, connection); + if (res_thread_create != 0) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to create a thread: %s\n", + STRERROR (res_thread_create)); +#endif + SHUTDOWN (s, SHUT_RDWR); + CLOSE (s); + MHD_ip_limit_del (daemon, addr, addrlen); + free (connection->addr); + free (connection); + return MHD_NO; + } + } + connection->next = daemon->connections; + daemon->connections = connection; + daemon->max_connections--; + return MHD_YES; +} + +/** + * Free resources associated with all closed connections. + * (destroy responses, free buffers, etc.). A connection + * is known to be closed if the socket_fd is -1. + */ +static void +MHD_cleanup_connections (struct MHD_Daemon *daemon) +{ + struct MHD_Connection *pos; + struct MHD_Connection *prev; + void *unused; + int rc; + + pos = daemon->connections; + prev = NULL; + while (pos != NULL) + { + if ((pos->socket_fd == -1) || + (((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && + (daemon->shutdown) && (pos->socket_fd != -1)))) + { + if (prev == NULL) + daemon->connections = pos->next; + else + prev->next = pos->next; + if (0 != (pos->daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + { + pthread_kill (pos->pid, SIGALRM); + if (0 != (rc = pthread_join (pos->pid, &unused))) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to join a thread: %s\n", + STRERROR (rc)); +#endif + abort(); + } + } + MHD_destroy_response (pos->response); + MHD_pool_destroy (pos->pool); +#if HTTPS_SUPPORT + if (pos->tls_session != NULL) + MHD__gnutls_deinit (pos->tls_session); +#endif + MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len); + free (pos->addr); + free (pos); + daemon->max_connections++; + if (prev == NULL) + pos = daemon->connections; + else + pos = prev->next; + continue; + } + prev = pos; + pos = pos->next; + } +} + +/** + * Obtain timeout value for select for this daemon + * (only needed if connection timeout is used). The + * returned value is how long select should at most + * block, not the timeout value set for connections. + * + * @param timeout set to the timeout (in milliseconds) + * @return MHD_YES on success, MHD_NO if timeouts are + * not used (or no connections exist that would + * necessiate the use of a timeout right now). + */ +int +MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout) +{ + time_t earliest_deadline; + time_t now; + struct MHD_Connection *pos; + unsigned int dto; + + dto = daemon->connection_timeout; + if (0 == dto) + return MHD_NO; + pos = daemon->connections; + if (pos == NULL) + return MHD_NO; /* no connections */ + now = time (NULL); + /* start with conservative estimate */ + earliest_deadline = now + dto; + while (pos != NULL) + { + if (earliest_deadline > pos->last_activity + dto) + earliest_deadline = pos->last_activity + dto; + pos = pos->next; + } + if (earliest_deadline < now) + *timeout = 0; + else + *timeout = (earliest_deadline - now); + return MHD_YES; +} + +/** + * Main select call. + * + * @param may_block YES if blocking, NO if non-blocking + * @return MHD_NO on serious errors, MHD_YES on success + */ +static int +MHD_select (struct MHD_Daemon *daemon, int may_block) +{ + struct MHD_Connection *pos; + int num_ready; + fd_set rs; + fd_set ws; + fd_set es; + int max; + struct timeval timeout; + unsigned long long ltimeout; + int ds; + time_t now; + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (daemon->shutdown == MHD_YES) + return MHD_NO; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + max = 0; + + if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + { + /* single-threaded, go over everything */ + if (MHD_NO == MHD_get_fdset (daemon, &rs, &ws, &es, &max)) + return MHD_NO; + + /* If we're at the connection limit, no need to + accept new connections. */ + if ( (daemon->max_connections == 0) && (daemon->socket_fd != -1) ) + FD_CLR(daemon->socket_fd, &rs); + } + else + { + /* accept only, have one thread per connection */ + max = daemon->socket_fd; + if (max == -1) + return MHD_NO; + FD_SET (max, &rs); + } + + /* in case we are missing the SIGALRM, keep going after + at most 1s; see http://lists.gnu.org/archive/html/libmicrohttpd/2009-10/msg00013.html */ + timeout.tv_usec = 0; + timeout.tv_sec = 1; + if (may_block == MHD_NO) + { + timeout.tv_usec = 0; + timeout.tv_sec = 0; + } + else + { + /* ltimeout is in ms */ + if ( (MHD_YES == MHD_get_timeout (daemon, <imeout)) && + (ltimeout < 1000) ) + { + timeout.tv_usec = ltimeout * 1000; + timeout.tv_sec = 0; + } + } + num_ready = SELECT (max + 1, &rs, &ws, &es, &timeout); + + if (daemon->shutdown == MHD_YES) + return MHD_NO; + if (num_ready < 0) + { + if (errno == EINTR) + return MHD_YES; +#if HAVE_MESSAGES + MHD_DLOG (daemon, "select failed: %s\n", STRERROR (errno)); +#endif + return MHD_NO; + } + ds = daemon->socket_fd; + if (ds == -1) + return MHD_YES; + + /* select connection thread handling type */ + if (FD_ISSET (ds, &rs)) + MHD_accept_connection (daemon); + if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + { + /* do not have a thread per connection, process all connections now */ + now = time (NULL); + pos = daemon->connections; + while (pos != NULL) + { + ds = pos->socket_fd; + if (ds != -1) + { + /* TODO call con->read handler */ + if (FD_ISSET (ds, &rs)) + pos->read_handler (pos); + if ((pos->socket_fd != -1) && (FD_ISSET (ds, &ws))) + pos->write_handler (pos); + if (pos->socket_fd != -1) + pos->idle_handler (pos); + } + pos = pos->next; + } + } + return MHD_YES; +} + +/** + * Poll for new connection. Used only with THREAD_PER_CONNECTION + */ +static int +MHD_poll (struct MHD_Daemon *daemon) +{ +#ifdef HAVE_POLL_H + struct pollfd p; + + if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) + return MHD_NO; + p.fd = daemon->socket_fd; + p.events = POLLIN; + p.revents = 0; + + if (poll(&p, 1, 0) < 0) { + if (errno == EINTR) + return MHD_YES; +#if HAVE_MESSAGES + MHD_DLOG (daemon, "poll failed: %s\n", STRERROR (errno)); +#endif + return MHD_NO; + } + /* handle shutdown cases */ + if (daemon->shutdown == MHD_YES) + return MHD_NO; + if (daemon->socket_fd < 0) + return MHD_YES; + if (0 != (p.revents & POLLIN)) + MHD_accept_connection (daemon); + return MHD_YES; +#else + return MHD_NO; +#endif +} + +/** + * Run webserver operations (without blocking unless + * in client callbacks). This method should be called + * by clients in combination with MHD_get_fdset + * if the client-controlled select method is used. + * + * @return MHD_YES on success, MHD_NO if this + * daemon was not started with the right + * options for this call. + */ +int +MHD_run (struct MHD_Daemon *daemon) +{ + if ((daemon->shutdown != MHD_NO) || (0 != (daemon->options + & MHD_USE_THREAD_PER_CONNECTION)) + || (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))) + return MHD_NO; + MHD_select (daemon, MHD_NO); + MHD_cleanup_connections (daemon); + return MHD_YES; +} + +/** + * Thread that runs the select loop until the daemon + * is explicitly shut down. + */ +static void * +MHD_select_thread (void *cls) +{ + struct MHD_Daemon *daemon = cls; + while (daemon->shutdown == MHD_NO) + { + if ((daemon->options & MHD_USE_POLL) == 0) + MHD_select (daemon, MHD_YES); + else + MHD_poll(daemon); + MHD_cleanup_connections (daemon); + } + return NULL; +} + +/** + * Start a webserver on the given port. + * + * @param port port to bind to + * @param apc callback to call to check which clients + * will be allowed to connect + * @param apc_cls extra argument to apc + * @param dh default handler for all URIs + * @param dh_cls extra argument to dh + * @return NULL on error, handle to daemon on success + */ +struct MHD_Daemon * +MHD_start_daemon (unsigned int options, + unsigned short port, + MHD_AcceptPolicyCallback apc, + void *apc_cls, + MHD_AccessHandlerCallback dh, void *dh_cls, ...) +{ + struct MHD_Daemon *ret; + va_list ap; + + va_start (ap, dh_cls); + ret = MHD_start_daemon_va (options, port, apc, apc_cls, dh, dh_cls, ap); + va_end (ap); + return ret; +} + + +typedef void (*VfprintfFunctionPointerType)(void *, const char *, va_list); + + +/** + * Parse a list of options given as varargs. + * + * @param daemon the daemon to initialize + * @param ap the options + * @return MHD_YES on success, MHD_NO on error + */ +static int +parse_options_va (struct MHD_Daemon *daemon, + const struct sockaddr **servaddr, + va_list ap); + + +/** + * Parse a list of options given as varargs. + * + * @param daemon the daemon to initialize + * @param ... the options + * @return MHD_YES on success, MHD_NO on error + */ +static int +parse_options (struct MHD_Daemon *daemon, + const struct sockaddr **servaddr, + ...) +{ + va_list ap; + int ret; + + va_start (ap, servaddr); + ret = parse_options_va (daemon, servaddr, ap); + va_end (ap); + return ret; +} + + +/** + * Parse a list of options given as varargs. + * + * @param daemon the daemon to initialize + * @param ap the options + * @return MHD_YES on success, MHD_NO on error + */ +static int +parse_options_va (struct MHD_Daemon *daemon, + const struct sockaddr **servaddr, + va_list ap) +{ + enum MHD_OPTION opt; + struct MHD_OptionItem *oa; + unsigned int i; + + while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION))) + { + switch (opt) + { + case MHD_OPTION_CONNECTION_MEMORY_LIMIT: + daemon->pool_size = va_arg (ap, size_t); + break; + case MHD_OPTION_CONNECTION_LIMIT: + daemon->max_connections = va_arg (ap, unsigned int); + break; + case MHD_OPTION_CONNECTION_TIMEOUT: + daemon->connection_timeout = va_arg (ap, unsigned int); + break; + case MHD_OPTION_NOTIFY_COMPLETED: + daemon->notify_completed = + va_arg (ap, MHD_RequestCompletedCallback); + daemon->notify_completed_cls = va_arg (ap, void *); + break; + case MHD_OPTION_PER_IP_CONNECTION_LIMIT: + daemon->per_ip_connection_limit = va_arg (ap, unsigned int); + break; + case MHD_OPTION_SOCK_ADDR: + *servaddr = va_arg (ap, const struct sockaddr *); + break; + case MHD_OPTION_URI_LOG_CALLBACK: + daemon->uri_log_callback = + va_arg (ap, LogCallback); + daemon->uri_log_callback_cls = va_arg (ap, void *); + break; + case MHD_OPTION_THREAD_POOL_SIZE: + daemon->worker_pool_size = va_arg (ap, unsigned int); + break; +#if HTTPS_SUPPORT + case MHD_OPTION_PROTOCOL_VERSION: + _set_priority (&daemon->priority_cache->protocol, + va_arg (ap, const int *)); + break; + case MHD_OPTION_HTTPS_MEM_KEY: + daemon->https_mem_key = va_arg (ap, const char *); + break; + case MHD_OPTION_HTTPS_MEM_CERT: + daemon->https_mem_cert = va_arg (ap, const char *); + break; + case MHD_OPTION_CIPHER_ALGORITHM: + _set_priority (&daemon->priority_cache->cipher, + va_arg (ap, const int *)); + break; +#endif + case MHD_OPTION_EXTERNAL_LOGGER: +#if HAVE_MESSAGES + daemon->custom_error_log = + va_arg (ap, VfprintfFunctionPointerType); + daemon->custom_error_log_cls = va_arg (ap, void *); +#else + va_arg (ap, VfprintfFunctionPointerType); + va_arg (ap, void *); +#endif + break; + case MHD_OPTION_ARRAY: + oa = va_arg (ap, struct MHD_OptionItem*); + i = 0; + while (MHD_OPTION_END != (opt = oa[i].option)) + { + switch (opt) + { + /* all options taking 'size_t' */ + case MHD_OPTION_CONNECTION_MEMORY_LIMIT: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (size_t) oa[i].value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking 'unsigned int' */ + case MHD_OPTION_CONNECTION_LIMIT: + case MHD_OPTION_CONNECTION_TIMEOUT: + case MHD_OPTION_PER_IP_CONNECTION_LIMIT: + case MHD_OPTION_THREAD_POOL_SIZE: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (unsigned int) oa[i].value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking 'int' or 'enum' */ + case MHD_OPTION_CRED_TYPE: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (int) oa[i].value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking one pointer */ + case MHD_OPTION_SOCK_ADDR: + case MHD_OPTION_HTTPS_MEM_KEY: + case MHD_OPTION_HTTPS_MEM_CERT: + case MHD_OPTION_PROTOCOL_VERSION: + case MHD_OPTION_CIPHER_ALGORITHM: + case MHD_OPTION_ARRAY: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + oa[i].ptr_value, + MHD_OPTION_END)) + return MHD_NO; + break; + /* all options taking two pointers */ + case MHD_OPTION_NOTIFY_COMPLETED: + case MHD_OPTION_URI_LOG_CALLBACK: + case MHD_OPTION_EXTERNAL_LOGGER: + if (MHD_YES != parse_options (daemon, + servaddr, + opt, + (void *) oa[i].value, + oa[i].ptr_value, + MHD_OPTION_END)) + return MHD_NO; + break; + + default: + return MHD_NO; + } + i++; + } + break; + default: +#if HAVE_MESSAGES + if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) && + (opt <= MHD_OPTION_CIPHER_ALGORITHM)) + { + FPRINTF (stderr, + "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n", + opt); + } + else + { + FPRINTF (stderr, + "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n", + opt); + } +#endif + return MHD_NO; + } + } + return MHD_YES; +} + + +/** + * Start a webserver on the given port. + * + * @param port port to bind to + * @param apc callback to call to check which clients + * will be allowed to connect + * @param apc_cls extra argument to apc + * @param dh default handler for all URIs + * @param dh_cls extra argument to dh + * @return NULL on error, handle to daemon on success + */ +struct MHD_Daemon * +MHD_start_daemon_va (unsigned int options, + unsigned short port, + MHD_AcceptPolicyCallback apc, + void *apc_cls, + MHD_AccessHandlerCallback dh, void *dh_cls, va_list ap) +{ + const int on = 1; + struct MHD_Daemon *retVal; + int socket_fd; + struct sockaddr_in servaddr4; +#if HAVE_INET6 + struct sockaddr_in6 servaddr6; +#endif + const struct sockaddr *servaddr = NULL; + socklen_t addrlen; + unsigned int i; + int res_thread_create; + + if ((port == 0) || (dh == NULL)) + return NULL; + retVal = malloc (sizeof (struct MHD_Daemon)); + if (retVal == NULL) + return NULL; + memset (retVal, 0, sizeof (struct MHD_Daemon)); + retVal->options = (enum MHD_OPTION)options; + retVal->port = port; + retVal->apc = apc; + retVal->apc_cls = apc_cls; + retVal->default_handler = dh; + retVal->default_handler_cls = dh_cls; + retVal->max_connections = MHD_MAX_CONNECTIONS_DEFAULT; + retVal->pool_size = MHD_POOL_SIZE_DEFAULT; + retVal->connection_timeout = 0; /* no timeout */ +#if HAVE_MESSAGES + retVal->custom_error_log = + (void (*)(void *, const char *, va_list)) &vfprintf; + retVal->custom_error_log_cls = stderr; +#endif +#if HTTPS_SUPPORT + if (options & MHD_USE_SSL) + { + /* lock MHD_gnutls_global mutex since it uses reference counting */ + if (0 != pthread_mutex_lock (&MHD_gnutls_init_mutex)) + { +#if HAVE_MESSAGES + MHD_DLOG (retVal, "Failed to aquire gnutls mutex\n"); +#endif + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); + } + if (0 != pthread_mutex_unlock (&MHD_gnutls_init_mutex)) + { +#if HAVE_MESSAGES + MHD_DLOG (retVal, "Failed to release gnutls mutex\n"); +#endif + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); + } + /* set default priorities */ + MHD_tls_set_default_priority (&retVal->priority_cache, "", NULL); + retVal->cred_type = MHD_GNUTLS_CRD_CERTIFICATE; + } +#endif + + if (MHD_YES != parse_options_va (retVal, &servaddr, ap)) + { + free (retVal); + return NULL; + } + + /* poll support currently only works with MHD_USE_THREAD_PER_CONNECTION */ + if ( (0 != (options & MHD_USE_POLL)) && + (0 == (options & MHD_USE_THREAD_PER_CONNECTION)) ) { +#if HAVE_MESSAGES + fprintf (stderr, + "MHD poll support only works with MHD_USE_THREAD_PER_CONNECTION\n"); +#endif + free (retVal); + return NULL; + } + + /* Thread pooling currently works only with internal select thread model */ + if ((0 == (options & MHD_USE_SELECT_INTERNALLY)) + && (retVal->worker_pool_size > 0)) + { +#if HAVE_MESSAGES + fprintf (stderr, + "MHD thread pooling only works with MHD_USE_SELECT_INTERNALLY\n"); +#endif + free (retVal); + return NULL; + } + +#ifdef __SYMBIAN32__ + if (0 != (options & (MHD_USE_SELECT_INTERNALLY | MHD_USE_THREAD_PER_CONNECTION))) + { +#if HAVE_MESSAGES + fprintf (stderr, + "Threaded operations are not supported on Symbian.\n"); +#endif + free (retVal); + return NULL; + } +#endif + if ((options & MHD_USE_IPv6) != 0) +#if HAVE_INET6 + socket_fd = SOCKET (PF_INET6, SOCK_STREAM, 0); +#else + { +#if HAVE_MESSAGES + fprintf (stderr, "AF_INET6 not supported\n"); +#endif + free (retVal); + return NULL; + } +#endif + else + socket_fd = SOCKET (PF_INET, SOCK_STREAM, 0); + if (socket_fd == -1) + { +#if HAVE_MESSAGES + if ((options & MHD_USE_DEBUG) != 0) + FPRINTF (stderr, "Call to socket failed: %s\n", STRERROR (errno)); +#endif + free (retVal); + return NULL; + } +#ifndef WINDOWS + if ( (socket_fd >= FD_SETSIZE) && + (0 == (options & MHD_USE_POLL)) ) + { +#if HAVE_MESSAGES + if ((options & MHD_USE_DEBUG) != 0) + FPRINTF (stderr, + "Socket descriptor larger than FD_SETSIZE: %d > %d\n", + socket_fd, + FD_SETSIZE); +#endif + CLOSE (socket_fd); + free (retVal); + return NULL; + } +#endif + if ((SETSOCKOPT (socket_fd, + SOL_SOCKET, + SO_REUSEADDR, + &on, sizeof (on)) < 0) && (options & MHD_USE_DEBUG) != 0) + { +#if HAVE_MESSAGES + FPRINTF (stderr, "setsockopt failed: %s\n", STRERROR (errno)); +#endif + } + + /* check for user supplied sockaddr */ +#if HAVE_INET6 + if ((options & MHD_USE_IPv6) != 0) + addrlen = sizeof (struct sockaddr_in6); + else +#endif + addrlen = sizeof (struct sockaddr_in); + if (NULL == servaddr) + { +#if HAVE_INET6 + if ((options & MHD_USE_IPv6) != 0) + { + memset (&servaddr6, 0, sizeof (struct sockaddr_in6)); + servaddr6.sin6_family = AF_INET6; + servaddr6.sin6_port = htons (port); + servaddr = (struct sockaddr *) &servaddr6; + } + else +#endif + { + memset (&servaddr4, 0, sizeof (struct sockaddr_in)); + servaddr4.sin_family = AF_INET; + servaddr4.sin_port = htons (port); + servaddr = (struct sockaddr *) &servaddr4; + } + } + retVal->socket_fd = socket_fd; + if (BIND (socket_fd, servaddr, addrlen) == -1) + { +#if HAVE_MESSAGES + if ((options & MHD_USE_DEBUG) != 0) + FPRINTF (stderr, + "Failed to bind to port %u: %s\n", port, STRERROR (errno)); +#endif + CLOSE (socket_fd); + free (retVal); + return NULL; + } + + if (LISTEN (socket_fd, 20) < 0) + { +#if HAVE_MESSAGES + if ((options & MHD_USE_DEBUG) != 0) + FPRINTF (stderr, + "Failed to listen for connections: %s\n", STRERROR (errno)); +#endif + CLOSE (socket_fd); + free (retVal); + return NULL; + } + + if (0 != pthread_mutex_init (&retVal->per_ip_connection_mutex, NULL)) + { +#if HAVE_MESSAGES + MHD_DLOG (retVal, + "MHD failed to initialize IP connection limit mutex\n"); +#endif + CLOSE (socket_fd); + free (retVal); + return NULL; + } + +#if HTTPS_SUPPORT + /* initialize HTTPS daemon certificate aspects & send / recv functions */ + if ((0 != (options & MHD_USE_SSL)) && (0 != MHD_TLS_init (retVal))) + { +#if HAVE_MESSAGES + MHD_DLOG (retVal, "Failed to initialize TLS support\n"); +#endif + CLOSE (socket_fd); + pthread_mutex_destroy (&retVal->per_ip_connection_mutex); + free (retVal); + return NULL; + } +#endif + if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || + ( (0 != (options & MHD_USE_SELECT_INTERNALLY)) && + (0 == retVal->worker_pool_size)) ) && + (0 != (res_thread_create = + pthread_create (&retVal->pid, NULL, &MHD_select_thread, retVal)))) + { +#if HAVE_MESSAGES + MHD_DLOG (retVal, + "Failed to create listen thread: %s\n", STRERROR (res_thread_create)); +#endif + pthread_mutex_destroy (&retVal->per_ip_connection_mutex); + free (retVal); + CLOSE (socket_fd); + return NULL; + } + else if (retVal->worker_pool_size > 0) + { +#ifndef MINGW + int sk_flags; +#else + unsigned long sk_flags; +#endif + + /* Coarse-grained count of connections per thread (note error + * due to integer division). Also keep track of how many + * connections are leftover after an equal split. */ + unsigned int conns_per_thread = retVal->max_connections + / retVal->worker_pool_size; + unsigned int leftover_conns = retVal->max_connections + % retVal->worker_pool_size; + + i = 0; /* we need this in case fcntl or malloc fails */ + + /* Accept must be non-blocking. Multiple children may wake up + * to handle a new connection, but only one will win the race. + * The others must immediately return. */ +#ifndef MINGW + sk_flags = fcntl (socket_fd, F_GETFL); + if (sk_flags < 0) + goto thread_failed; + if (fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK) < 0) + goto thread_failed; +#else + sk_flags = 1; +#if HAVE_PLIBC_FD + if (ioctlsocket (plibc_fd_get_handle (socket_fd), FIONBIO, &sk_flags) == + SOCKET_ERROR) +#else + if (ioctlsocket (socket_fd, FIONBIO, &sk_flags) == SOCKET_ERROR) +#endif // PLIBC_FD + goto thread_failed; +#endif // MINGW + + /* Allocate memory for pooled objects */ + retVal->worker_pool = malloc (sizeof (struct MHD_Daemon) + * retVal->worker_pool_size); + if (NULL == retVal->worker_pool) + goto thread_failed; + + /* Start the workers in the pool */ + for (i = 0; i < retVal->worker_pool_size; ++i) + { + /* Create copy of the Daemon object for each worker */ + struct MHD_Daemon *d = &retVal->worker_pool[i]; + memcpy (d, retVal, sizeof (struct MHD_Daemon)); + + /* Adjust pooling params for worker daemons; note that memcpy() + has already copied MHD_USE_SELECT_INTERNALLY thread model into + the worker threads. */ + d->master = retVal; + d->worker_pool_size = 0; + d->worker_pool = NULL; + + /* Divide available connections evenly amongst the threads. + * Thread indexes in [0, leftover_conns) each get one of the + * leftover connections. */ + d->max_connections = conns_per_thread; + if (i < leftover_conns) + ++d->max_connections; + + /* Spawn the worker thread */ + if (0 != (res_thread_create = pthread_create (&d->pid, NULL, &MHD_select_thread, d))) + { +#if HAVE_MESSAGES + MHD_DLOG (retVal, + "Failed to create pool thread: %s\n", + STRERROR (res_thread_create)); +#endif + /* Free memory for this worker; cleanup below handles + * all previously-created workers. */ + goto thread_failed; + } + } + } + return retVal; + +thread_failed: + /* If no worker threads created, then shut down normally. Calling + MHD_stop_daemon (as we do below) doesn't work here since it + assumes a 0-sized thread pool means we had been in the default + MHD_USE_SELECT_INTERNALLY mode. */ + if (i == 0) + { + CLOSE (socket_fd); + pthread_mutex_destroy (&retVal->per_ip_connection_mutex); + if (NULL != retVal->worker_pool) + free (retVal->worker_pool); + free (retVal); + return NULL; + } + + /* Shutdown worker threads we've already created. Pretend + as though we had fully initialized our daemon, but + with a smaller number of threads than had been + requested. */ + retVal->worker_pool_size = i - 1; + MHD_stop_daemon (retVal); + return NULL; +} + +/** + * Close all connections for the daemon + */ +static void +MHD_close_connections (struct MHD_Daemon *daemon) +{ + while (daemon->connections != NULL) + { + if (-1 != daemon->connections->socket_fd) + { +#if DEBUG_CLOSE +#if HAVE_MESSAGES + MHD_DLOG (daemon, "MHD shutdown, closing active connections\n"); +#endif +#endif + MHD_connection_close (daemon->connections, + MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN); + } + MHD_cleanup_connections (daemon); + } +} + +/** + * Shutdown an http daemon + */ +void +MHD_stop_daemon (struct MHD_Daemon *daemon) +{ + void *unused; + int fd; + unsigned int i; + int rc; + + if (daemon == NULL) + return; + daemon->shutdown = MHD_YES; + fd = daemon->socket_fd; + daemon->socket_fd = -1; + + /* Prepare workers for shutdown */ + for (i = 0; i < daemon->worker_pool_size; ++i) + { + daemon->worker_pool[i].shutdown = MHD_YES; + daemon->worker_pool[i].socket_fd = -1; + } + +#if OSX + /* without this, either (thread pool = 0) threads would get stuck or + * CLOSE would get stuck if attempted before (thread pool > 0) + * threads have ended */ + SHUTDOWN (fd, SHUT_RDWR); +#else +#if DEBUG_CLOSE +#if HAVE_MESSAGES + MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n"); +#endif +#endif + CLOSE (fd); +#endif + + /* Signal workers to stop and clean them up */ + for (i = 0; i < daemon->worker_pool_size; ++i) + pthread_kill (daemon->worker_pool[i].pid, SIGALRM); + for (i = 0; i < daemon->worker_pool_size; ++i) + { + if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused))) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to join a thread: %s\n", + STRERROR (rc)); +#endif + abort(); + } + MHD_close_connections (&daemon->worker_pool[i]); + } + free (daemon->worker_pool); + + if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) || + ((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) + && (0 == daemon->worker_pool_size))) + { + pthread_kill (daemon->pid, SIGALRM); + if (0 != (rc = pthread_join (daemon->pid, &unused))) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to join a thread: %s\n", + STRERROR (rc)); +#endif + abort(); + } + } + MHD_close_connections (daemon); + +#if OSX +#if DEBUG_CLOSE +#if HAVE_MESSAGES + MHD_DLOG (daemon, "MHD shutdown, closing listen socket\n"); +#endif +#endif + CLOSE (fd); +#endif + + /* TLS clean up */ +#if HTTPS_SUPPORT + if (daemon->options & MHD_USE_SSL) + { + MHD__gnutls_priority_deinit (daemon->priority_cache); + if (daemon->x509_cred) + MHD__gnutls_certificate_free_credentials (daemon->x509_cred); + /* lock MHD_gnutls_global mutex since it uses reference counting */ + if (0 != pthread_mutex_lock (&MHD_gnutls_init_mutex)) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to aquire gnutls mutex\n"); +#endif + abort(); + } + if (0 != pthread_mutex_unlock (&MHD_gnutls_init_mutex)) + { +#if HAVE_MESSAGES + MHD_DLOG (daemon, "Failed to release gnutls mutex\n"); +#endif + abort(); + } + } +#endif + pthread_mutex_destroy (&daemon->per_ip_connection_mutex); + free (daemon); +} + +/** + * Obtain information about the given daemon + * (not fully implemented!). + * + * @param daemon what daemon to get information about + * @param infoType what information is desired? + * @param ... depends on infoType + * @return NULL if this information is not available + * (or if the infoType is unknown) + */ +const union MHD_DaemonInfo * +MHD_get_daemon_info (struct MHD_Daemon *daemon, + enum MHD_DaemonInfoType infoType, ...) +{ + switch (infoType) + { + case MHD_DAEMON_INFO_LISTEN_FD: + return (const union MHD_DaemonInfo *) &daemon->socket_fd; + default: + return NULL; + }; +} + +/** + * Sets the global error handler to a different implementation. "cb" + * will only be called in the case of typically fatal, serious + * internal consistency issues. These issues should only arise in the + * case of serious memory corruption or similar problems with the + * architecture. While "cb" is allowed to return and MHD will then + * try to continue, this is never safe. + * + * The default implementation that is used if no panic function is set + * simply calls "abort". Alternative implementations might call + * "exit" or other similar functions. + * + * @param cb new error handler + * @param cls passed to error handler + */ +void MHD_set_panic_func (MHD_PanicCallback cb, void *cls) +{ + mhd_panic = cb; + mhd_panic_cls = cls; +} + +/** + * Obtain the version of this library + * + * @return static version string, e.g. "0.4.1" + */ +const char * +MHD_get_version (void) +{ + return PACKAGE_VERSION; +} + +#ifndef WINDOWS + +static struct sigaction sig; + +static struct sigaction old; + +static void +sigalrmHandler (int sig) +{ +} +#endif + +#ifdef __GNUC__ +#define ATTRIBUTE_CONSTRUCTOR __attribute__ ((constructor)) +#define ATTRIBUTE_DESTRUCTOR __attribute__ ((destructor)) +#else // !__GNUC__ +#define ATTRIBUTE_CONSTRUCTOR +#define ATTRIBUTE_DESTRUCTOR +#endif // __GNUC__ + +/** + * Initialize the signal handler for SIGALRM + * and do other setup work. + */ +void ATTRIBUTE_CONSTRUCTOR MHD_init () +{ + mhd_panic = &mhd_panic_std; + mhd_panic_cls = NULL; + +#ifndef WINDOWS + /* make sure SIGALRM does not kill us */ + memset (&sig, 0, sizeof (struct sigaction)); + memset (&old, 0, sizeof (struct sigaction)); + sig.sa_flags = SA_NODEFER; + sig.sa_handler = &sigalrmHandler; + sigaction (SIGALRM, &sig, &old); +#else + plibc_init ("GNU", "libmicrohttpd"); +#endif +#if HTTPS_SUPPORT + MHD__gnutls_global_init (); + if (0 != pthread_mutex_init(&MHD_gnutls_init_mutex, NULL)) + abort(); +#endif +} + +void ATTRIBUTE_DESTRUCTOR MHD_fini () +{ +#if HTTPS_SUPPORT + MHD__gnutls_global_deinit (); + if (0 != pthread_mutex_destroy(&MHD_gnutls_init_mutex)) + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); +#endif +#ifndef WINDOWS + sigaction (SIGALRM, &old, &sig); +#else + plibc_shutdown (); +#endif +} + +/* end of daemon.c */ diff --git a/lib/libmicrohttpd/src/daemon/daemon_test.c b/lib/libmicrohttpd/src/daemon/daemon_test.c new file mode 100644 index 0000000000..6340a2e73b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/daemon_test.c @@ -0,0 +1,168 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest.c + * @brief Testcase for libmicrohttpd starts and stops + * @author Christian Grothoff + */ + +#include "platform.h" +#include "platform.h" +#include "microhttpd.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + + +static int +testStartError () +{ + struct MHD_Daemon *d; + + d = MHD_start_daemon (MHD_USE_DEBUG, 0, NULL, NULL, NULL, NULL); + if (d != NULL) + return 1; + return 0; +} + +static int +apc_nothing (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + return MHD_NO; +} + +static int +apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + return MHD_YES; +} + +static int +ahc_nothing (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + return MHD_NO; +} + +static int +testStartStop () +{ + struct MHD_Daemon *d; + + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1080, + &apc_nothing, + NULL, &ahc_nothing, NULL, MHD_OPTION_END); + if (d == NULL) + return 2; + MHD_stop_daemon (d); + return 0; +} + +static int +testExternalRun () +{ + struct MHD_Daemon *d; + fd_set rs; + int maxfd; + int i; + + d = MHD_start_daemon (MHD_USE_DEBUG, + 1081, + &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END); + + if (d == NULL) + return 4; + i = 0; + while (i < 15) + { + maxfd = 0; + FD_ZERO (&rs); + if (MHD_YES != MHD_get_fdset (d, &rs, &rs, &rs, &maxfd)) + { + MHD_stop_daemon (d); + return 256; + } + if (MHD_run (d) == MHD_NO) + { + MHD_stop_daemon (d); + return 8; + } + i++; + } + MHD_stop_daemon (d); + return 0; +} + +static int +testThread () +{ + struct MHD_Daemon *d; + d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY, + 1082, + &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END); + + if (d == NULL) + return 16; + if (MHD_run (d) != MHD_NO) + return 32; + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithread () +{ + struct MHD_Daemon *d; + d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION, + 1083, + &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END); + + if (d == NULL) + return 64; + if (MHD_run (d) != MHD_NO) + return 128; + MHD_stop_daemon (d); + return 0; +} + +int +main (int argc, char *const *argv) +{ + int errorCount = 0; + errorCount += testStartError (); + errorCount += testStartStop (); + errorCount += testExternalRun (); + errorCount += testThread (); + errorCount += testMultithread (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/daemon/https/Makefile.am b/lib/libmicrohttpd/src/daemon/https/Makefile.am new file mode 100644 index 0000000000..8b4c1aa15c --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/Makefile.am @@ -0,0 +1,3 @@ +EXTRA_DIST = gnutls.h + +SUBDIRS = minitasn1 lgl x509 tls . diff --git a/lib/libmicrohttpd/src/daemon/https/Makefile.in b/lib/libmicrohttpd/src/daemon/https/Makefile.in new file mode 100644 index 0000000000..069f1c6e87 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/Makefile.in @@ -0,0 +1,575 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/daemon/https +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = gnutls.h +SUBDIRS = minitasn1 lgl x509 tls . +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/daemon/https/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/daemon/https/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/daemon/https/gnutls.h b/lib/libmicrohttpd/src/daemon/https/gnutls.h new file mode 100644 index 0000000000..f2f6f06925 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/gnutls.h @@ -0,0 +1,697 @@ +/* -*- c -*- + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavroyanopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + */ + +/* This file contains the types and prototypes for all the + * high level functionality of gnutls main library. For the + * extra functionality (which is under the GNU GPL license) check + * the gnutls/extra.h header. The openssl compatibility layer is + * in gnutls/openssl.h. + * + * The low level cipher functionality is in libgcrypt. Check + * gcrypt.h + */ + +#ifndef GNUTLS_H +#define GNUTLS_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * List of key exchange algorithms. + * Note that not all listed algorithms are necessarily + * supported by all builds of MHD. + */ +enum MHD_GNUTLS_KeyExchangeAlgorithm +{ + MHD_GNUTLS_KX_UNKNOWN = 0, + MHD_GNUTLS_KX_RSA = 1, +}; + +/** + * Server credentials type (note that not all types + * maybe supported by all MHD builds). + */ +enum MHD_GNUTLS_CredentialsType +{ + /** + * We have a x.509 certificate. + */ + MHD_GNUTLS_CRD_CERTIFICATE = 1, + +}; + +/** + * Enumeration of possible cryptographic + * hash functions (for MAC and Digest operations). + * Note that not all listed algorithms are necessarily + * supported by all builds of MHD. + */ +enum MHD_GNUTLS_HashAlgorithm +{ + MHD_GNUTLS_MAC_UNKNOWN = 0, + MHD_GNUTLS_MAC_NULL = 1, + MHD_GNUTLS_MAC_MD5, + MHD_GNUTLS_MAC_SHA1, + MHD_GNUTLS_MAC_SHA256 +}; + +/** + * List of compression methods. + * Note that not all listed algorithms are necessarily + * supported by all builds of MHD. + */ +enum MHD_GNUTLS_CompressionMethod +{ + MHD_GNUTLS_COMP_UNKNOWN = 0, + + /** + * No compression. + */ + MHD_GNUTLS_COMP_NULL = 1, + +}; +/** + * Types of certificates. + */ +enum MHD_GNUTLS_CertificateType +{ + MHD_GNUTLS_CRT_UNKNOWN = 0, + MHD_GNUTLS_CRT_X509 = 1 +}; + +/** + * List of public key algorithms. + * Note that not all listed algorithms are necessarily + * supported by all builds of MHD. + */ +enum MHD_GNUTLS_PublicKeyAlgorithm +{ + MHD_GNUTLS_PK_UNKNOWN = 0, + MHD_GNUTLS_PK_RSA = 1, + MHD_GNUTLS_KX_RSA_EXPORT +}; + + + +#define LIBGNUTLS_VERSION "2.2.3" + +/* Get size_t. */ +#include <stddef.h> + +#define GNUTLS_CIPHER_RIJNDAEL_128_CBC GNUTLS_CIPHER_AES_128_CBC +#define GNUTLS_CIPHER_RIJNDAEL_256_CBC GNUTLS_CIPHER_AES_256_CBC +#define GNUTLS_CIPHER_RIJNDAEL_CBC GNUTLS_CIPHER_AES_128_CBC +#define GNUTLS_CIPHER_ARCFOUR GNUTLS_CIPHER_ARCFOUR_128 + +#define GNUTLS_MAX_SESSION_ID 32 +#define TLS_MASTER_SIZE 48 +#define TLS_RANDOM_SIZE 32 + +#include "platform.h" +#include "microhttpd.h" + +typedef enum +{ + GNUTLS_PARAMS_RSA_EXPORT = 1, + GNUTLS_PARAMS_DH +} MHD_gnutls_params_type_t; + + /* exported for other gnutls headers. This is the maximum number of + * algorithms (ciphers, kx or macs). + */ +#define GNUTLS_MAX_ALGORITHM_NUM 16 +#define GNUTLS_COMP_ZLIB GNUTLS_COMP_DEFLATE + +typedef enum +{ + GNUTLS_SERVER = 1, + GNUTLS_CLIENT +} MHD_gnutls_connection_end_t; + +typedef enum +{ + GNUTLS_AL_WARNING = 1, + GNUTLS_AL_FATAL +} MHD_gnutls_alert_level_t; + +typedef enum +{ + GNUTLS_A_CLOSE_NOTIFY, + GNUTLS_A_UNEXPECTED_MESSAGE = 10, + GNUTLS_A_BAD_RECORD_MAC = 20, + GNUTLS_A_DECRYPTION_FAILED, + GNUTLS_A_RECORD_OVERFLOW, + GNUTLS_A_DECOMPRESSION_FAILURE = 30, + GNUTLS_A_HANDSHAKE_FAILURE = 40, + GNUTLS_A_SSL3_NO_CERTIFICATE = 41, + GNUTLS_A_BAD_CERTIFICATE = 42, + GNUTLS_A_UNSUPPORTED_CERTIFICATE, + GNUTLS_A_CERTIFICATE_REVOKED, + GNUTLS_A_CERTIFICATE_EXPIRED, + GNUTLS_A_CERTIFICATE_UNKNOWN, + GNUTLS_A_ILLEGAL_PARAMETER, + GNUTLS_A_UNKNOWN_CA, + GNUTLS_A_ACCESS_DENIED, + GNUTLS_A_DECODE_ERROR = 50, + GNUTLS_A_DECRYPT_ERROR, + GNUTLS_A_EXPORT_RESTRICTION = 60, + GNUTLS_A_PROTOCOL_VERSION = 70, + GNUTLS_A_INSUFFICIENT_SECURITY, + GNUTLS_A_INTERNAL_ERROR = 80, + GNUTLS_A_USER_CANCELED = 90, + GNUTLS_A_NO_RENEGOTIATION = 100, + GNUTLS_A_UNSUPPORTED_EXTENSION = 110, + GNUTLS_A_CERTIFICATE_UNOBTAINABLE = 111, + GNUTLS_A_UNRECOGNIZED_NAME = 112, + GNUTLS_A_UNKNOWN_PSK_IDENTITY = 115, +} MHD_gnutls_alert_description_t; + +typedef enum +{ GNUTLS_HANDSHAKE_HELLO_REQUEST = 0, + GNUTLS_HANDSHAKE_CLIENT_HELLO = 1, + GNUTLS_HANDSHAKE_SERVER_HELLO = 2, + GNUTLS_HANDSHAKE_CERTIFICATE_PKT = 11, + GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE = 12, + GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST = 13, + GNUTLS_HANDSHAKE_SERVER_HELLO_DONE = 14, + GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY = 15, + GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE = 16, + GNUTLS_HANDSHAKE_FINISHED = 20, + GNUTLS_HANDSHAKE_SUPPLEMENTAL = 23 +} MHD_gnutls_handshake_description_t; + +typedef enum +{ + GNUTLS_CERT_INVALID = 2, /* will be set if the certificate + * was not verified. + */ + GNUTLS_CERT_REVOKED = 32, /* in X.509 this will be set only if CRLs are checked + */ + + /* Those are extra information about the verification + * process. Will be set only if the certificate was + * not verified. + */ + GNUTLS_CERT_SIGNER_NOT_FOUND = 64, + GNUTLS_CERT_SIGNER_NOT_CA = 128, + GNUTLS_CERT_INSECURE_ALGORITHM = 256 +} MHD_gnutls_certificate_status_t; + +typedef enum +{ + GNUTLS_CERT_IGNORE, + GNUTLS_CERT_REQUEST = 1, + GNUTLS_CERT_REQUIRE +} MHD_gnutls_certificate_request_t; + +typedef enum +{ + GNUTLS_SHUT_RDWR = 0, + GNUTLS_SHUT_WR = 1 +} MHD_gnutls_close_request_t; + +typedef enum +{ + GNUTLS_X509_FMT_DER, + GNUTLS_X509_FMT_PEM +} MHD_gnutls_x509_crt_fmt_t; + +typedef enum +{ + GNUTLS_SIGN_UNKNOWN = 0, + GNUTLS_SIGN_RSA_SHA1 = 1, + GNUTLS_SIGN_DSA_SHA1, + GNUTLS_SIGN_RSA_MD5, + GNUTLS_SIGN_RSA_MD2, + GNUTLS_SIGN_RSA_RMD160, + GNUTLS_SIGN_RSA_SHA256, + GNUTLS_SIGN_RSA_SHA384, + GNUTLS_SIGN_RSA_SHA512 +} MHD_gnutls_sign_algorithm_t; + +/* If you want to change this, then also change the define in + * MHD_gnutls_int.h, and recompile. + */ +typedef void *MHD_gnutls_transport_ptr_t; + +struct MHD_gtls_session_int; +typedef struct MHD_gtls_session_int *MHD_gtls_session_t; + +struct MHD_gtls_dh_params_int; +typedef struct MHD_gtls_dh_params_int *MHD_gtls_dh_params_t; + +struct MHD_gtls_x509_privkey_int; /* XXX ugly. */ +typedef struct MHD_gtls_x509_privkey_int *MHD_gtls_rsa_params_t; /* XXX ugly. */ + +struct MHD_gtls_priority_st; +typedef struct MHD_gtls_priority_st *MHD_gnutls_priority_t; + +typedef struct +{ + unsigned char *data; + unsigned int size; +} MHD_gnutls_datum_t; + + +typedef struct MHD_gnutls_params_st +{ + MHD_gnutls_params_type_t type; + union params + { + MHD_gtls_dh_params_t dh; + MHD_gtls_rsa_params_t rsa_export; + } params; + int deinit; +} MHD_gnutls_params_st; + +typedef int MHD_gnutls_params_function (MHD_gtls_session_t, + MHD_gnutls_params_type_t, + MHD_gnutls_params_st *); + +/* internal functions */ +int MHD__gnutls_global_init (void); +void MHD__gnutls_global_deinit (void); + +int MHD__gnutls_init (MHD_gtls_session_t * session, + MHD_gnutls_connection_end_t con_end); +void MHD__gnutls_deinit (MHD_gtls_session_t session); + +int MHD__gnutls_bye (MHD_gtls_session_t session, + MHD_gnutls_close_request_t how); +int MHD__gnutls_handshake (MHD_gtls_session_t session); +int MHD__gnutls_rehandshake (MHD_gtls_session_t session); + +MHD_gnutls_alert_description_t MHD_gnutls_alert_get (MHD_gtls_session_t + session); +int MHD__gnutls_alert_send (MHD_gtls_session_t session, + MHD_gnutls_alert_level_t level, + MHD_gnutls_alert_description_t desc); +int MHD__gnutls_alert_send_appropriate (MHD_gtls_session_t session, int err); +const char *MHD__gnutls_alert_get_name (MHD_gnutls_alert_description_t alert); + +size_t MHD__gnutls_cipher_get_key_size (enum MHD_GNUTLS_CipherAlgorithm + algorithm); + + /* error functions */ +int MHD_gtls_error_is_fatal (int error); +int MHD_gtls_error_to_alert (int err, int *level); +void MHD_gtls_perror (int error); +const char *MHD_gtls_strerror (int error); + +/* + * Record layer functions. + */ +ssize_t MHD__gnutls_record_send (MHD_gtls_session_t session, + const void *data, size_t sizeofdata); +ssize_t MHD__gnutls_record_recv (MHD_gtls_session_t session, void *data, + size_t sizeofdata); + + /* provides extra compatibility */ +int MHD__gnutls_record_get_direction (MHD_gtls_session_t session); + +/* + * TLS Extensions + */ +typedef enum +{ + GNUTLS_NAME_DNS = 1 +} MHD_gnutls_server_name_type_t; + + /* Supplemental data, RFC 4680. */ +typedef enum +{ + GNUTLS_SUPPLEMENTAL_USER_MAPPING_DATA = 0 +} MHD_gnutls_supplemental_data_format_type_t; + + +int MHD_tls_set_default_priority (MHD_gnutls_priority_t *, + const char *priority, const char **err_pos); +void MHD__gnutls_priority_deinit (MHD_gnutls_priority_t); + +int MHD__gnutls_priority_set (MHD_gtls_session_t session, + MHD_gnutls_priority_t); +int MHD__gnutls_priority_set_direct (MHD_gtls_session_t session, + const char *priority, + const char **err_pos); + +/* get the currently used protocol version */ +enum MHD_GNUTLS_Protocol +MHD__gnutls_protocol_get_version (MHD_gtls_session_t session); + +typedef + int (*MHD_gnutls_handshake_post_client_hello_func) (MHD_gtls_session_t); +void MHD__gnutls_handshake_set_max_packet_length (MHD_gtls_session_t + session, size_t max); + +/* + * Functions for setting/clearing credentials + */ +void MHD__gnutls_credentials_clear (MHD_gtls_session_t session); + +/* + * cred is a structure defined by the kx algorithm + */ +int MHD__gnutls_credentials_set (MHD_gtls_session_t session, + enum MHD_GNUTLS_CredentialsType type, + void *cred); + +/* Credential structures - used in MHD__gnutls_credentials_set(); */ +struct MHD_gtls_certificate_credentials_st; +typedef struct MHD_gtls_certificate_credentials_st + *MHD_gtls_cert_credentials_t; +typedef MHD_gtls_cert_credentials_t MHD_gtls_cert_server_credentials; +typedef MHD_gtls_cert_credentials_t MHD_gtls_cert_client_credentials; + +void MHD__gnutls_certificate_free_credentials (MHD_gtls_cert_credentials_t + sc); +int +MHD__gnutls_certificate_allocate_credentials (MHD_gtls_cert_credentials_t + * res); + +void MHD__gnutls_certificate_free_keys (MHD_gtls_cert_credentials_t sc); +void MHD__gnutls_certificate_free_cas (MHD_gtls_cert_credentials_t sc); +void MHD__gnutls_certificate_free_ca_names (MHD_gtls_cert_credentials_t sc); + +int MHD__gnutls_certificate_set_x509_key_mem (MHD_gtls_cert_credentials_t + res, + const MHD_gnutls_datum_t * + CERT, + const MHD_gnutls_datum_t * + KEY, + MHD_gnutls_x509_crt_fmt_t type); + +void MHD__gnutls_certificate_send_x509_rdn_sequence (MHD_gtls_session_t + session, int status); + +/* + * New functions to allow setting already parsed X.509 stuff. + */ +struct MHD_gtls_x509_privkey_int; +typedef struct MHD_gtls_x509_privkey_int *MHD_gnutls_x509_privkey_t; + +struct MHD_gnutls_x509_crl_int; +typedef struct MHD_gnutls_x509_crl_int *MHD_gnutls_x509_crl_t; + +struct MHD_gnutls_x509_crt_int; +typedef struct MHD_gnutls_x509_crt_int *MHD_gnutls_x509_crt_t; + +/* global state functions + */ + + +typedef void *(*MHD_gnutls_alloc_function) (size_t); +typedef int (*MHD_gnutls_is_secure_function) (const void *); +typedef void *(*MHD_gnutls_calloc_function) (size_t, size_t); +typedef void (*MHD_gnutls_free_function) (void *); +typedef void *(*MHD_gnutls_realloc_function) (void *, size_t); + +/* For use in callbacks */ +extern MHD_gnutls_alloc_function MHD_gnutls_malloc; +extern MHD_gnutls_alloc_function MHD_gnutls_secure_malloc; +extern MHD_gnutls_realloc_function MHD_gnutls_realloc; +extern MHD_gnutls_calloc_function MHD_gnutls_calloc; +extern MHD_gnutls_free_function MHD_gnutls_free; + +typedef void (*MHD_gnutls_log_func) (int, const char *); +void MHD_gtls_global_set_log_function (MHD_gnutls_log_func log_func); +void MHD_gtls_global_set_log_level (int level); + +/* + * Diffie Hellman parameter handling. + */ +int MHD__gnutls_dh_params_init (MHD_gtls_dh_params_t * dh_params); +void MHD__gnutls_dh_params_deinit (MHD_gtls_dh_params_t dh_params); + + +/* RSA params */ +int MHD__gnutls_rsa_params_init (MHD_gtls_rsa_params_t * rsa_params); +void MHD__gnutls_rsa_params_deinit (MHD_gtls_rsa_params_t rsa_params); +int MHD__gnutls_rsa_params_generate2 (MHD_gtls_rsa_params_t params, + unsigned int bits); + + +/* + * Session stuff + */ +typedef ssize_t (*MHD_gtls_pull_func) (MHD_gnutls_transport_ptr_t, void *, + size_t); +typedef ssize_t (*MHD_gtls_push_func) (MHD_gnutls_transport_ptr_t, + const void *, size_t); +void MHD__gnutls_transport_set_ptr (MHD_gtls_session_t session, + MHD_gnutls_transport_ptr_t ptr); +void MHD__gnutls_transport_set_lowat (MHD_gtls_session_t session, int num); + + +void MHD__gnutls_transport_set_push_function (MHD_gtls_session_t session, + MHD_gtls_push_func push_func); +void MHD__gnutls_transport_set_pull_function (MHD_gtls_session_t session, + MHD_gtls_pull_func pull_func); + +typedef enum MHD_gnutls_x509_subject_alt_name_t +{ + GNUTLS_SAN_DNSNAME = 1, + GNUTLS_SAN_RFC822NAME, + GNUTLS_SAN_URI, + GNUTLS_SAN_IPADDRESS, + GNUTLS_SAN_OTHERNAME, + GNUTLS_SAN_DN, + /* The following are "virtual" subject alternative name types, in + that they are represented by an otherName value and an OID. + Used by MHD_gnutls_x509_crt_get_subject_alt_othername_oid(). */ + GNUTLS_SAN_OTHERNAME_XMPP = 1000 +} MHD_gnutls_x509_subject_alt_name_t; + +typedef struct MHD_gnutls_retr_st +{ + enum MHD_GNUTLS_CertificateType type; + union cert + { + MHD_gnutls_x509_crt_t *x509; + } cert; + unsigned int ncerts; + + union key + { + MHD_gnutls_x509_privkey_t x509; + } key; + + unsigned int deinit_all; /* if non zero all keys will be deinited */ +} MHD_gnutls_retr_st; + +typedef int +MHD_gnutls_certificate_client_retrieve_function (MHD_gtls_session_t, + const MHD_gnutls_datum_t + * req_ca_rdn, int nreqs, + const enum + MHD_GNUTLS_PublicKeyAlgorithm + *pk_algos, + int pk_algos_length, + MHD_gnutls_retr_st *); + +typedef int +MHD_gnutls_certificate_server_retrieve_function (MHD_gtls_session_t, + MHD_gnutls_retr_st *); + + /* + * Functions that allow auth_info_t structures handling + */ +enum MHD_GNUTLS_CredentialsType MHD_gtls_auth_get_type (MHD_gtls_session_t + session); + /* + * DH + */ +void MHD__gnutls_dh_set_prime_bits (MHD_gtls_session_t session, + unsigned int bits); + + /* External signing callback. Experimental. */ +typedef int (*MHD_gnutls_sign_func) (MHD_gtls_session_t session, + void *userdata, + enum MHD_GNUTLS_CertificateType + cert_type, + const MHD_gnutls_datum_t * cert, + const MHD_gnutls_datum_t * hash, + MHD_gnutls_datum_t * signature); + + /* key_usage will be an OR of the following values: */ + /* when the key is to be used for signing: */ +#define GNUTLS_KEY_DIGITAL_SIGNATURE 128 +#define GNUTLS_KEY_NON_REPUDIATION 64 + /* when the key is to be used for encryption: */ +#define GNUTLS_KEY_KEY_ENCIPHERMENT 32 +#define GNUTLS_KEY_DATA_ENCIPHERMENT 16 +#define GNUTLS_KEY_KEY_AGREEMENT 8 +#define GNUTLS_KEY_KEY_CERT_SIGN 4 +#define GNUTLS_KEY_CRL_SIGN 2 +#define GNUTLS_KEY_ENCIPHER_ONLY 1 +#define GNUTLS_KEY_DECIPHER_ONLY 32768 + + /* + * Error codes. TLS alert mapping shown in comments. + */ +#define GNUTLS_E_SUCCESS 0 +#define GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM -3 +#define GNUTLS_E_UNKNOWN_CIPHER_TYPE -6 +#define GNUTLS_E_LARGE_PACKET -7 +#define GNUTLS_E_UNSUPPORTED_VERSION_PACKET -8 /* GNUTLS_A_PROTOCOL_VERSION */ +#define GNUTLS_E_UNEXPECTED_PACKET_LENGTH -9 /* GNUTLS_A_RECORD_OVERFLOW */ +#define GNUTLS_E_INVALID_SESSION -10 +#define GNUTLS_E_FATAL_ALERT_RECEIVED -12 +#define GNUTLS_E_UNEXPECTED_PACKET -15 /* GNUTLS_A_UNEXPECTED_MESSAGE */ +#define GNUTLS_E_WARNING_ALERT_RECEIVED -16 +#define GNUTLS_E_ERROR_IN_FINISHED_PACKET -18 +#define GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET -19 +#define GNUTLS_E_UNKNOWN_CIPHER_SUITE -21 /* GNUTLS_A_HANDSHAKE_FAILURE */ +#define GNUTLS_E_UNWANTED_ALGORITHM -22 +#define GNUTLS_E_MPI_SCAN_FAILED -23 +#define GNUTLS_E_DECRYPTION_FAILED -24 /* GNUTLS_A_DECRYPTION_FAILED, GNUTLS_A_BAD_RECORD_MAC */ +#define GNUTLS_E_MEMORY_ERROR -25 +#define GNUTLS_E_DECOMPRESSION_FAILED -26 /* GNUTLS_A_DECOMPRESSION_FAILURE */ +#define GNUTLS_E_COMPRESSION_FAILED -27 +#define GNUTLS_E_AGAIN -28 +#define GNUTLS_E_EXPIRED -29 +#define GNUTLS_E_DB_ERROR -30 +#define GNUTLS_E_SRP_PWD_ERROR -31 +#define GNUTLS_E_INSUFFICIENT_CREDENTIALS -32 +#define GNUTLS_E_INSUFICIENT_CREDENTIALS GNUTLS_E_INSUFFICIENT_CREDENTIALS /* for backwards compatibility only */ +#define GNUTLS_E_INSUFFICIENT_CRED GNUTLS_E_INSUFFICIENT_CREDENTIALS +#define GNUTLS_E_INSUFICIENT_CRED GNUTLS_E_INSUFFICIENT_CREDENTIALS /* for backwards compatibility only */ + +#define GNUTLS_E_HASH_FAILED -33 +#define GNUTLS_E_BASE64_DECODING_ERROR -34 + +#define GNUTLS_E_MPI_PRINT_FAILED -35 +#define GNUTLS_E_REHANDSHAKE -37 /* GNUTLS_A_NO_RENEGOTIATION */ +#define GNUTLS_E_GOT_APPLICATION_DATA -38 +#define GNUTLS_E_RECORD_LIMIT_REACHED -39 +#define GNUTLS_E_ENCRYPTION_FAILED -40 + +#define GNUTLS_E_PK_ENCRYPTION_FAILED -44 +#define GNUTLS_E_PK_DECRYPTION_FAILED -45 +#define GNUTLS_E_PK_SIGN_FAILED -46 +#define GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION -47 +#define GNUTLS_E_KEY_USAGE_VIOLATION -48 +#define GNUTLS_E_NO_CERTIFICATE_FOUND -49 /* GNUTLS_A_BAD_CERTIFICATE */ +#define GNUTLS_E_INVALID_REQUEST -50 +#define GNUTLS_E_SHORT_MEMORY_BUFFER -51 +#define GNUTLS_E_INTERRUPTED -52 +#define GNUTLS_E_PUSH_ERROR -53 +#define GNUTLS_E_PULL_ERROR -54 +#define GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER -55 /* GNUTLS_A_ILLEGAL_PARAMETER */ +#define GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE -56 +#define GNUTLS_E_PKCS1_WRONG_PAD -57 +#define GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION -58 +#define GNUTLS_E_INTERNAL_ERROR -59 +#define GNUTLS_E_DH_PRIME_UNACCEPTABLE -63 +#define GNUTLS_E_FILE_ERROR -64 +#define GNUTLS_E_TOO_MANY_EMPTY_PACKETS -78 +#define GNUTLS_E_UNKNOWN_PK_ALGORITHM -80 + + + /* returned if libextra functionality was requested but + * MHD_gnutls_global_init_extra() was not called. + */ +#define GNUTLS_E_INIT_LIBEXTRA -82 +#define GNUTLS_E_LIBRARY_VERSION_MISMATCH -83 + + + /* returned if you need to generate temporary RSA + * parameters. These are needed for export cipher suites. + */ +#define GNUTLS_E_NO_TEMPORARY_RSA_PARAMS -84 + +#define GNUTLS_E_LZO_INIT_FAILED -85 +#define GNUTLS_E_NO_COMPRESSION_ALGORITHMS -86 +#define GNUTLS_E_NO_CIPHER_SUITES -87 + +#define GNUTLS_E_PK_SIG_VERIFY_FAILED -89 + +#define GNUTLS_E_ILLEGAL_SRP_USERNAME -90 +#define GNUTLS_E_SRP_PWD_PARSING_ERROR -91 +#define GNUTLS_E_NO_TEMPORARY_DH_PARAMS -93 + + /* For certificate and key stuff + */ +#define GNUTLS_E_ASN1_ELEMENT_NOT_FOUND -67 +#define GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND -68 +#define GNUTLS_E_ASN1_DER_ERROR -69 +#define GNUTLS_E_ASN1_VALUE_NOT_FOUND -70 +#define GNUTLS_E_ASN1_GENERIC_ERROR -71 +#define GNUTLS_E_ASN1_VALUE_NOT_VALID -72 +#define GNUTLS_E_ASN1_TAG_ERROR -73 +#define GNUTLS_E_ASN1_TAG_IMPLICIT -74 +#define GNUTLS_E_ASN1_TYPE_ANY_ERROR -75 +#define GNUTLS_E_ASN1_SYNTAX_ERROR -76 +#define GNUTLS_E_ASN1_DER_OVERFLOW -77 +#define GNUTLS_E_CERTIFICATE_ERROR -43 +#define GNUTLS_E_X509_CERTIFICATE_ERROR GNUTLS_E_CERTIFICATE_ERROR +#define GNUTLS_E_CERTIFICATE_KEY_MISMATCH -60 +#define GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE -61 /* GNUTLS_A_UNSUPPORTED_CERTIFICATE */ +#define GNUTLS_E_X509_UNKNOWN_SAN -62 +#define GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE -95 +#define GNUTLS_E_UNKNOWN_HASH_ALGORITHM -96 +#define GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE -97 +#define GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE -98 +#define GNUTLS_E_INVALID_PASSWORD -99 +#define GNUTLS_E_MAC_VERIFY_FAILED -100 /* for PKCS #12 MAC */ +#define GNUTLS_E_CONSTRAINT_ERROR -101 + +#define GNUTLS_E_WARNING_IA_IPHF_RECEIVED -102 +#define GNUTLS_E_WARNING_IA_FPHF_RECEIVED -103 + +#define GNUTLS_E_IA_VERIFY_FAILED -104 + +#define GNUTLS_E_UNKNOWN_ALGORITHM -105 + +#define GNUTLS_E_BASE64_ENCODING_ERROR -201 +#define GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY -202 /* obsolete */ +#define GNUTLS_E_INCOMPATIBLE_CRYPTO_LIBRARY -202 +#define GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY -203 + +#define GNUTLS_E_X509_UNSUPPORTED_OID -205 + +#define GNUTLS_E_RANDOM_FAILED -206 +#define GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR -207 + + +#define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 + +#define GNUTLS_E_APPLICATION_ERROR_MAX -65000 +#define GNUTLS_E_APPLICATION_ERROR_MIN -65500 + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* GNUTLS_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/lgl/Makefile.am b/lib/libmicrohttpd/src/daemon/https/lgl/Makefile.am new file mode 100644 index 0000000000..5659d5c5ef --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/lgl/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include @LIBGCRYPT_CFLAGS@ + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +noinst_LTLIBRARIES = liblgl.la + +liblgl_la_SOURCES = \ + gc-libgcrypt.c \ + gc.h +liblgl_la_LIBADD = @LIBGCRYPT_LIBS@ diff --git a/lib/libmicrohttpd/src/daemon/https/lgl/Makefile.in b/lib/libmicrohttpd/src/daemon/https/lgl/Makefile.in new file mode 100644 index 0000000000..ea0602fda9 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/lgl/Makefile.in @@ -0,0 +1,495 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/daemon/https/lgl +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +liblgl_la_DEPENDENCIES = +am_liblgl_la_OBJECTS = gc-libgcrypt.lo +liblgl_la_OBJECTS = $(am_liblgl_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(liblgl_la_SOURCES) +DIST_SOURCES = $(liblgl_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include @LIBGCRYPT_CFLAGS@ + +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +noinst_LTLIBRARIES = liblgl.la +liblgl_la_SOURCES = \ + gc-libgcrypt.c \ + gc.h + +liblgl_la_LIBADD = @LIBGCRYPT_LIBS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/daemon/https/lgl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/daemon/https/lgl/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +liblgl.la: $(liblgl_la_OBJECTS) $(liblgl_la_DEPENDENCIES) + $(LINK) $(liblgl_la_OBJECTS) $(liblgl_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gc-libgcrypt.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/daemon/https/lgl/gc-libgcrypt.c b/lib/libmicrohttpd/src/daemon/https/lgl/gc-libgcrypt.c new file mode 100644 index 0000000000..0995740584 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/lgl/gc-libgcrypt.c @@ -0,0 +1,407 @@ +/* gc-libgcrypt.c --- Crypto wrappers around Libgcrypt for GC. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Simon Josefsson + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +/* Note: This file is only built if GC uses Libgcrypt. */ + +#include "MHD_config.h" + +/* Get prototype. */ +#include "gc.h" + +#include <stdlib.h> +#include <string.h> + +/* Get libgcrypt API. */ +#include <gcrypt.h> + +#include <assert.h> + +/* Initialization. */ + +Gc_rc +MHD_gc_init (void) +{ + gcry_error_t err; + + err = gcry_control (GCRYCTL_ANY_INITIALIZATION_P); + if (err == GPG_ERR_NO_ERROR) + { + if (gcry_check_version (GCRYPT_VERSION) == NULL) + return GC_INIT_ERROR; + + err = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0); + if (err != GPG_ERR_NO_ERROR) + return GC_INIT_ERROR; + } + return GC_OK; +} + +void +MHD_gc_done (void) +{ + return; +} + +#ifdef GNULIB_GC_RANDOM + +/* Randomness. */ + +Gc_rc +MHD_gc_nonce (char *data, size_t datalen) +{ + gcry_create_nonce ((unsigned char *) data, datalen); + return GC_OK; +} + +Gc_rc +MHD_gc_pseudo_random (char *data, size_t datalen) +{ + gcry_randomize ((unsigned char *) data, datalen, GCRY_STRONG_RANDOM); + return GC_OK; +} + +#endif + +/* Memory allocation. */ + +/* Ciphers. */ + +Gc_rc +MHD_gc_cipher_open (Gc_cipher alg, + Gc_cipher_mode mode, MHD_gc_cipher_handle * outhandle) +{ + int gcryalg, gcrymode; + gcry_error_t err; + + switch (alg) + { + case GC_AES128: + gcryalg = GCRY_CIPHER_RIJNDAEL; + break; + + case GC_AES192: + gcryalg = GCRY_CIPHER_RIJNDAEL; + break; + + case GC_AES256: + gcryalg = GCRY_CIPHER_RIJNDAEL256; + break; + + case GC_3DES: + gcryalg = GCRY_CIPHER_3DES; + break; + + case GC_DES: + gcryalg = GCRY_CIPHER_DES; + break; + + case GC_ARCFOUR128: + case GC_ARCFOUR40: + gcryalg = GCRY_CIPHER_ARCFOUR; + break; + + case GC_ARCTWO40: + gcryalg = GCRY_CIPHER_RFC2268_40; + break; + + default: + return GC_INVALID_CIPHER; + } + + switch (mode) + { + case GC_ECB: + gcrymode = GCRY_CIPHER_MODE_ECB; + break; + + case GC_CBC: + gcrymode = GCRY_CIPHER_MODE_CBC; + break; + + case GC_STREAM: + gcrymode = GCRY_CIPHER_MODE_STREAM; + break; + + default: + return GC_INVALID_CIPHER; + } + + err = + gcry_cipher_open ((gcry_cipher_hd_t *) outhandle, gcryalg, gcrymode, 0); + if (gcry_err_code (err)) + return GC_INVALID_CIPHER; + + return GC_OK; +} + +Gc_rc +MHD_gc_cipher_setkey (MHD_gc_cipher_handle handle, size_t keylen, + const char *key) +{ + gcry_error_t err; + + err = gcry_cipher_setkey ((gcry_cipher_hd_t) handle, key, keylen); + if (gcry_err_code (err)) + return GC_INVALID_CIPHER; + + return GC_OK; +} + +Gc_rc +MHD_gc_cipher_setiv (MHD_gc_cipher_handle handle, size_t ivlen, + const char *iv) +{ + gcry_error_t err; + + err = gcry_cipher_setiv ((gcry_cipher_hd_t) handle, iv, ivlen); + if (gcry_err_code (err)) + return GC_INVALID_CIPHER; + + return GC_OK; +} + +Gc_rc +MHD_gc_cipher_encrypt_inline (MHD_gc_cipher_handle handle, size_t len, + char *data) +{ + if (gcry_cipher_encrypt ((gcry_cipher_hd_t) handle, data, len, NULL, len) != + 0) + return GC_INVALID_CIPHER; + + return GC_OK; +} + +Gc_rc +MHD_gc_cipher_decrypt_inline (MHD_gc_cipher_handle handle, size_t len, + char *data) +{ + if (gcry_cipher_decrypt ((gcry_cipher_hd_t) handle, data, len, NULL, len) != + 0) + return GC_INVALID_CIPHER; + + return GC_OK; +} + +Gc_rc +MHD_gc_cipher_close (MHD_gc_cipher_handle handle) +{ + gcry_cipher_close (handle); + + return GC_OK; +} + +/* Hashes. */ + +typedef struct _MHD_gc_hash_ctx +{ + Gc_hash alg; + Gc_hash_mode mode; + gcry_md_hd_t gch; +} _MHD_gc_hash_ctx; + +Gc_rc +MHD_gc_hash_open (Gc_hash hash, Gc_hash_mode mode, + MHD_gc_hash_handle * outhandle) +{ + _MHD_gc_hash_ctx *ctx; + int gcryalg = 0, gcrymode = 0; + gcry_error_t err; + Gc_rc rc = GC_OK; + + ctx = calloc (sizeof (*ctx), 1); + if (!ctx) + return GC_MALLOC_ERROR; + + ctx->alg = hash; + ctx->mode = mode; + + switch (hash) + { + case GC_MD2: + gcryalg = GCRY_MD_NONE; + break; + + case GC_MD4: + gcryalg = GCRY_MD_MD4; + break; + + case GC_MD5: + gcryalg = GCRY_MD_MD5; + break; + + case GC_SHA1: + gcryalg = GCRY_MD_SHA1; + break; + + case GC_SHA256: + gcryalg = GCRY_MD_SHA256; + break; + + case GC_SHA384: + gcryalg = GCRY_MD_SHA384; + break; + + case GC_SHA512: + gcryalg = GCRY_MD_SHA512; + break; + + case GC_RMD160: + gcryalg = GCRY_MD_RMD160; + break; + + default: + rc = GC_INVALID_HASH; + } + + switch (mode) + { + case 0: + gcrymode = 0; + break; + + case GC_HMAC: + gcrymode = GCRY_MD_FLAG_HMAC; + break; + + default: + rc = GC_INVALID_HASH; + } + + if (rc == GC_OK && gcryalg != GCRY_MD_NONE) + { + err = gcry_md_open (&ctx->gch, gcryalg, gcrymode); + if (gcry_err_code (err)) + rc = GC_INVALID_HASH; + } + + if (rc == GC_OK) + *outhandle = ctx; + else + free (ctx); + + return rc; +} + +Gc_rc +MHD_gc_hash_clone (MHD_gc_hash_handle handle, MHD_gc_hash_handle * outhandle) +{ + _MHD_gc_hash_ctx *in = handle; + _MHD_gc_hash_ctx *out; + int err; + + *outhandle = out = calloc (sizeof (*out), 1); + if (!out) + return GC_MALLOC_ERROR; + + memcpy (out, in, sizeof (*out)); + + err = gcry_md_copy (&out->gch, in->gch); + if (err) + { + free (out); + return GC_INVALID_HASH; + } + + return GC_OK; +} + +size_t +MHD_gc_hash_digest_length (Gc_hash hash) +{ + size_t len; + + switch (hash) + { + case GC_MD2: + len = GC_MD2_DIGEST_SIZE; + break; + + case GC_MD4: + len = GC_MD4_DIGEST_SIZE; + break; + + case GC_MD5: + len = GC_MD5_DIGEST_SIZE; + break; + + case GC_RMD160: + len = GC_RMD160_DIGEST_SIZE; + break; + + case GC_SHA1: + len = GC_SHA1_DIGEST_SIZE; + break; + + case GC_SHA256: + len = GC_SHA256_DIGEST_SIZE; + break; + + case GC_SHA384: + len = GC_SHA384_DIGEST_SIZE; + break; + + case GC_SHA512: + len = GC_SHA512_DIGEST_SIZE; + break; + + default: + return 0; + } + + return len; +} + +void +MHD_gc_hash_MHD_hmac_setkey (MHD_gc_hash_handle handle, size_t len, + const char *key) +{ + _MHD_gc_hash_ctx *ctx = handle; + gcry_md_setkey (ctx->gch, key, len); +} + +void +MHD_gc_hash_write (MHD_gc_hash_handle handle, size_t len, const char *data) +{ + _MHD_gc_hash_ctx *ctx = handle; + gcry_md_write (ctx->gch, data, len); +} + +const char * +MHD_gc_hash_read (MHD_gc_hash_handle handle) +{ + _MHD_gc_hash_ctx *ctx = handle; + const char *digest; + { + gcry_md_final (ctx->gch); + digest = (const char *) gcry_md_read (ctx->gch, 0); + } + + return digest; +} + +void +MHD_gc_hash_close (MHD_gc_hash_handle handle) +{ + _MHD_gc_hash_ctx *ctx = handle; + + gcry_md_close (ctx->gch); + + free (ctx); +} diff --git a/lib/libmicrohttpd/src/daemon/https/lgl/gc.h b/lib/libmicrohttpd/src/daemon/https/lgl/gc.h new file mode 100644 index 0000000000..30c4e45bc2 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/lgl/gc.h @@ -0,0 +1,172 @@ +/* gc.h --- Header file for implementation agnostic crypto wrapper API. + * Copyright (C) 2002, 2003, 2004, 2005, 2007 Simon Josefsson + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef GC_H +#define GC_H + +/* Get size_t. */ +# include <stddef.h> + +enum Gc_rc +{ + GC_OK = 0, + GC_MALLOC_ERROR, + GC_INIT_ERROR, + GC_RANDOM_ERROR, + GC_INVALID_CIPHER, + GC_INVALID_HASH, + GC_PKCS5_INVALID_ITERATION_COUNT, + GC_PKCS5_INVALID_DERIVED_KEY_LENGTH, + GC_PKCS5_DERIVED_KEY_TOO_LONG +}; +typedef enum Gc_rc Gc_rc; + +/* Hash types. */ +enum Gc_hash +{ + GC_MD4, + GC_MD5, + GC_SHA1, + GC_MD2, + GC_RMD160, + GC_SHA256, + GC_SHA384, + GC_SHA512 +}; +typedef enum Gc_hash Gc_hash; + +enum Gc_hash_mode +{ + GC_HMAC = 1 +}; +typedef enum Gc_hash_mode Gc_hash_mode; + +typedef void *MHD_gc_hash_handle; + +#define GC_MD2_DIGEST_SIZE 16 +#define GC_MD4_DIGEST_SIZE 16 +#define GC_MD5_DIGEST_SIZE 16 +#define GC_RMD160_DIGEST_SIZE 20 +#define GC_SHA1_DIGEST_SIZE 20 +#define GC_SHA256_DIGEST_SIZE 32 +#define GC_SHA384_DIGEST_SIZE 48 +#define GC_SHA512_DIGEST_SIZE 64 + +/* Cipher types. */ +enum Gc_cipher +{ + GC_AES128, + GC_AES192, + GC_AES256, + GC_3DES, + GC_DES, + GC_ARCFOUR128, + GC_ARCFOUR40, + GC_ARCTWO40, + GC_CAMELLIA128, + GC_CAMELLIA256 +}; +typedef enum Gc_cipher Gc_cipher; + +enum Gc_cipher_mode +{ + GC_ECB, + GC_CBC, + GC_STREAM +}; +typedef enum Gc_cipher_mode Gc_cipher_mode; + +typedef void *MHD_gc_cipher_handle; + +/* Call before respectively after any other functions. */ +Gc_rc MHD_gc_init (void); +void MHD_gc_done (void); + +/* Memory allocation (avoid). */ +typedef void *(*MHD_gc_malloc_t) (size_t n); +typedef int (*MHD_gc_secure_check_t) (const void *); +typedef void *(*MHD_gc_realloc_t) (void *p, size_t n); +typedef void (*MHD_gc_free_t) (void *); +/* Randomness. */ +Gc_rc MHD_gc_nonce (char *data, size_t datalen); +Gc_rc MHD_gc_pseudo_random (char *data, size_t datalen); + +/* Ciphers. */ +Gc_rc MHD_gc_cipher_open (Gc_cipher cipher, + Gc_cipher_mode mode, + MHD_gc_cipher_handle * outhandle); +Gc_rc MHD_gc_cipher_setkey (MHD_gc_cipher_handle handle, size_t keylen, + const char *key); +Gc_rc MHD_gc_cipher_setiv (MHD_gc_cipher_handle handle, size_t ivlen, + const char *iv); +Gc_rc MHD_gc_cipher_encrypt_inline (MHD_gc_cipher_handle handle, size_t len, + char *data); +Gc_rc MHD_gc_cipher_decrypt_inline (MHD_gc_cipher_handle handle, size_t len, + char *data); +Gc_rc MHD_gc_cipher_close (MHD_gc_cipher_handle handle); + +/* Hashes. */ + +Gc_rc MHD_gc_hash_open (Gc_hash hash, + Gc_hash_mode mode, MHD_gc_hash_handle * outhandle); +Gc_rc MHD_gc_hash_clone (MHD_gc_hash_handle handle, + MHD_gc_hash_handle * outhandle); +size_t MHD_gc_hash_digest_length (Gc_hash hash); +void MHD_gc_hash_MHD_hmac_setkey (MHD_gc_hash_handle handle, size_t len, + const char *key); +void MHD_gc_hash_write (MHD_gc_hash_handle handle, size_t len, + const char *data); +const char *MHD_gc_hash_read (MHD_gc_hash_handle handle); +void MHD_gc_hash_close (MHD_gc_hash_handle handle); + +/* Compute a hash value over buffer IN of INLEN bytes size using the + algorithm HASH, placing the result in the pre-allocated buffer OUT. + The required size of OUT depends on HASH, and is generally + GC_<HASH>_DIGEST_SIZE. For example, for GC_MD5 the output buffer + must be 16 bytes. The return value is 0 (GC_OK) on success, or + another Gc_rc error code. */ +Gc_rc MHD_gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, + char *out); + +/* One-call interface. */ +Gc_rc MHD_gc_md2 (const void *in, size_t inlen, void *resbuf); +Gc_rc MHD_gc_md4 (const void *in, size_t inlen, void *resbuf); +Gc_rc MHD_gc_md5 (const void *in, size_t inlen, void *resbuf); +Gc_rc MHD_gc_sha1 (const void *in, size_t inlen, void *resbuf); +Gc_rc MHD_gc_MHD_hmac_md5 (const void *key, + size_t keylen, const void *in, size_t inlen, + char *resbuf); +Gc_rc MHD_gc_MHD_hmac_sha1 (const void *key, size_t keylen, const void *in, + size_t inlen, char *resbuf); + +/* Derive cryptographic keys from a password P of length PLEN, with + salt S of length SLEN, placing the result in pre-allocated buffer + DK of length DKLEN. An iteration count is specified in C, where a + larger value means this function take more time (typical iteration + counts are 1000-20000). This function "stretches" the key to be + exactly dkLen bytes long. GC_OK is returned on success, otherwise + an Gc_rc error code is returned. */ +Gc_rc MHD_gc_pbkdf2_sha1 (const char *P, + size_t Plen, + const char *S, + size_t Slen, unsigned int c, char *DK, + size_t dkLen); + +#endif /* GC_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/Makefile.am b/lib/libmicrohttpd/src/daemon/https/minitasn1/Makefile.am new file mode 100644 index 0000000000..1d5c68d99e --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/tls + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +noinst_LTLIBRARIES = libasn1.la + +libasn1_la_SOURCES = \ +libtasn1.h \ +mem.h \ +gstr.h \ +int.h \ +parser_aux.h structure.h element.h decoding.c gstr.c \ +parser_aux.c structure.c element.c coding.c diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/Makefile.in b/lib/libmicrohttpd/src/daemon/https/minitasn1/Makefile.in new file mode 100644 index 0000000000..29440d3362 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/Makefile.in @@ -0,0 +1,506 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/daemon/https/minitasn1 +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libasn1_la_LIBADD = +am_libasn1_la_OBJECTS = decoding.lo gstr.lo parser_aux.lo structure.lo \ + element.lo coding.lo +libasn1_la_OBJECTS = $(am_libasn1_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libasn1_la_SOURCES) +DIST_SOURCES = $(libasn1_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/tls + +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +noinst_LTLIBRARIES = libasn1.la +libasn1_la_SOURCES = \ +libtasn1.h \ +mem.h \ +gstr.h \ +int.h \ +parser_aux.h structure.h element.h decoding.c gstr.c \ +parser_aux.c structure.c element.c coding.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/daemon/https/minitasn1/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/daemon/https/minitasn1/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libasn1.la: $(libasn1_la_OBJECTS) $(libasn1_la_DEPENDENCIES) + $(LINK) $(libasn1_la_OBJECTS) $(libasn1_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coding.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decoding.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/element.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gstr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_aux.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/structure.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/daemon/https/minitasn1/README b/lib/libmicrohttpd/src/daemon/https/minitasn1/README new file mode 100644 index 0000000000..9d484dfccc --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/README @@ -0,0 +1,3 @@ +This is just a mirror of the files in the libtasn1's +lib/ directory. + diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/coding.c b/lib/libmicrohttpd/src/daemon/https/minitasn1/coding.c new file mode 100644 index 0000000000..02d046834c --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/coding.c @@ -0,0 +1,1211 @@ +/* + * Copyright (C) 2004, 2006 Free Software Foundation + * Copyright (C) 2002 Fabio Fiorina + * + * This file is part of LIBTASN1. + * + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +/*****************************************************/ +/* File: coding.c */ +/* Description: Functions to create a DER coding of */ +/* an ASN1 type. */ +/*****************************************************/ + +#include <int.h> +#include "parser_aux.h" +#include <gstr.h> +#include "element.h" +#include <structure.h> + +#define MAX_TAG_LEN 16 + +/******************************************************/ +/* Function : MHD__asn1_error_description_value_not_found */ +/* Description: creates the ErrorDescription string */ +/* for the ASN1_VALUE_NOT_FOUND error. */ +/* Parameters: */ +/* node: node of the tree where the value is NULL. */ +/* ErrorDescription: string returned. */ +/* Return: */ +/******************************************************/ +static void +MHD__asn1_error_description_value_not_found (node_asn * node, + char *ErrorDescription) +{ + + if (ErrorDescription == NULL) + return; + + Estrcpy (ErrorDescription, ":: value of element '"); + MHD__asn1_hierarchical_name (node, + ErrorDescription + strlen (ErrorDescription), + MAX_ERROR_DESCRIPTION_SIZE - 40); + Estrcat (ErrorDescription, "' not found"); + +} + +/** + * MHD__asn1_length_der: + * @len: value to convert. + * @ans: string returned. + * @ans_len: number of meaningful bytes of ANS (ans[0]..ans[ans_len-1]). + * + * Creates the DER coding for the LEN parameter (only the length). + * The @ans buffer is pre-allocated and must have room for the output. + **/ +void +MHD__asn1_length_der (unsigned long int len, unsigned char *ans, int *ans_len) +{ + int k; + unsigned char temp[SIZEOF_UNSIGNED_LONG_INT]; + + if (len < 128) + { + /* short form */ + if (ans != NULL) + ans[0] = (unsigned char) len; + *ans_len = 1; + } + else + { + /* Long form */ + k = 0; + while (len) + { + temp[k++] = len & 0xFF; + len = len >> 8; + } + *ans_len = k + 1; + if (ans != NULL) + { + ans[0] = ((unsigned char) k & 0x7F) + 128; + while (k--) + ans[*ans_len - 1 - k] = temp[k]; + } + } +} + +/******************************************************/ +/* Function : MHD__asn1_tag_der */ +/* Description: creates the DER coding for the CLASS */ +/* and TAG parameters. */ +/* Parameters: */ +/* class: value to convert. */ +/* tag_value: value to convert. */ +/* ans: string returned. */ +/* ans_len: number of meaningful bytes of ANS */ +/* (ans[0]..ans[ans_len-1]). */ +/* Return: */ +/******************************************************/ +static void +MHD__asn1_tag_der (unsigned char class, unsigned int tag_value, + unsigned char *ans, int *ans_len) +{ + int k; + unsigned char temp[SIZEOF_UNSIGNED_INT]; + + if (tag_value < 31) + { + /* short form */ + ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F)); + *ans_len = 1; + } + else + { + /* Long form */ + ans[0] = (class & 0xE0) + 31; + k = 0; + while (tag_value) + { + temp[k++] = tag_value & 0x7F; + tag_value = tag_value >> 7; + } + *ans_len = k + 1; + while (k--) + ans[*ans_len - 1 - k] = temp[k] + 128; + ans[*ans_len - 1] -= 128; + } +} + +/** + * MHD__asn1_octet_der: + * @str: OCTET string. + * @str_len: STR length (str[0]..str[str_len-1]). + * @der: string returned. + * @der_len: number of meaningful bytes of DER (der[0]..der[ans_len-1]). + * + * Creates the DER coding for an OCTET type (length included). + **/ +void +MHD__asn1_octet_der (const unsigned char *str, int str_len, + unsigned char *der, int *der_len) +{ + int len_len; + + if (der == NULL || str_len < 0) + return; + MHD__asn1_length_der (str_len, der, &len_len); + memcpy (der + len_len, str, str_len); + *der_len = str_len + len_len; +} + +/******************************************************/ +/* Function : MHD__asn1_time_der */ +/* Description: creates the DER coding for a TIME */ +/* type (length included). */ +/* Parameters: */ +/* str: TIME null-terminated string. */ +/* der: string returned. */ +/* der_len: number of meaningful bytes of DER */ +/* (der[0]..der[ans_len-1]). Initially it */ +/* if must store the lenght of DER. */ +/* Return: */ +/* ASN1_MEM_ERROR when DER isn't big enough */ +/* ASN1_SUCCESS otherwise */ +/******************************************************/ +static MHD__asn1_retCode +MHD__asn1_time_der (unsigned char *str, unsigned char *der, int *der_len) +{ + int len_len; + int max_len; + + max_len = *der_len; + + MHD__asn1_length_der (strlen ((const char *) str), + (max_len > 0) ? der : NULL, &len_len); + + if ((len_len + (int) strlen ((const char *) str)) <= max_len) + memcpy (der + len_len, str, strlen ((const char *) str)); + *der_len = len_len + strlen ((const char *) str); + + if ((*der_len) > max_len) + return ASN1_MEM_ERROR; + + return ASN1_SUCCESS; +} + +/******************************************************/ +/* Function : MHD__asn1_objectid_der */ +/* Description: creates the DER coding for an */ +/* OBJECT IDENTIFIER type (length included). */ +/* Parameters: */ +/* str: OBJECT IDENTIFIER null-terminated string. */ +/* der: string returned. */ +/* der_len: number of meaningful bytes of DER */ +/* (der[0]..der[ans_len-1]). Initially it */ +/* must store the length of DER. */ +/* Return: */ +/* ASN1_MEM_ERROR when DER isn't big enough */ +/* ASN1_SUCCESS otherwise */ +/******************************************************/ +static MHD__asn1_retCode +MHD__asn1_objectid_der (unsigned char *str, unsigned char *der, int *der_len) +{ + int len_len, counter, k, first, max_len; + char *temp, *n_end, *n_start; + unsigned char bit7; + unsigned long val, val1 = 0; + + max_len = *der_len; + + temp = (char *) MHD__asn1_alloca (strlen ((const char *) str) + 2); + if (temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + + strcpy (temp, (const char *) str); + strcat (temp, "."); + + counter = 0; + n_start = temp; + while ((n_end = strchr (n_start, '.'))) + { + *n_end = 0; + val = strtoul (n_start, NULL, 10); + counter++; + + if (counter == 1) + val1 = val; + else if (counter == 2) + { + if (max_len > 0) + der[0] = 40 * val1 + val; + *der_len = 1; + } + else + { + first = 0; + for (k = 4; k >= 0; k--) + { + bit7 = (val >> (k * 7)) & 0x7F; + if (bit7 || first || !k) + { + if (k) + bit7 |= 0x80; + if (max_len > (*der_len)) + der[*der_len] = bit7; + (*der_len)++; + first = 1; + } + } + + } + n_start = n_end + 1; + } + + MHD__asn1_length_der (*der_len, NULL, &len_len); + if (max_len >= (*der_len + len_len)) + { + memmove (der + len_len, der, *der_len); + MHD__asn1_length_der (*der_len, der, &len_len); + } + *der_len += len_len; + + MHD__asn1_afree (temp); + + if (max_len < (*der_len)) + return ASN1_MEM_ERROR; + + return ASN1_SUCCESS; +} + + +const char MHD_bit_mask[] = + { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 }; + +/** + * MHD__asn1_bit_der: + * @str: BIT string. + * @bit_len: number of meaningful bits in STR. + * @der: string returned. + * @der_len: number of meaningful bytes of DER + * (der[0]..der[ans_len-1]). + * + * Creates the DER coding for a BIT STRING type (length and pad + * included). + **/ +void +MHD__asn1_bit_der (const unsigned char *str, int bit_len, + unsigned char *der, int *der_len) +{ + int len_len, len_byte, len_pad; + + if (der == NULL) + return; + len_byte = bit_len >> 3; + len_pad = 8 - (bit_len & 7); + if (len_pad == 8) + len_pad = 0; + else + len_byte++; + MHD__asn1_length_der (len_byte + 1, der, &len_len); + der[len_len] = len_pad; + memcpy (der + len_len + 1, str, len_byte); + der[len_len + len_byte] &= MHD_bit_mask[len_pad]; + *der_len = len_byte + len_len + 1; +} + + +/******************************************************/ +/* Function : MHD__asn1_complete_explicit_tag */ +/* Description: add the length coding to the EXPLICIT */ +/* tags. */ +/* Parameters: */ +/* node: pointer to the tree element. */ +/* der: string with the DER coding of the whole tree*/ +/* counter: number of meaningful bytes of DER */ +/* (der[0]..der[*counter-1]). */ +/* max_len: size of der vector */ +/* Return: */ +/* ASN1_MEM_ERROR if der vector isn't big enough, */ +/* otherwise ASN1_SUCCESS. */ +/******************************************************/ +static MHD__asn1_retCode +MHD__asn1_complete_explicit_tag (node_asn * node, unsigned char *der, + int *counter, int *max_len) +{ + node_asn *p; + int is_tag_implicit, len2, len3; + unsigned char temp[SIZEOF_UNSIGNED_INT]; + + is_tag_implicit = 0; + + if (node->type & CONST_TAG) + { + p = node->down; + /* When there are nested tags we must complete them reverse to + the order they were created. This is because completing a tag + modifies all data within it, including the incomplete tags + which store buffer positions -- simon@josefsson.org 2002-09-06 + */ + while (p->right) + p = p->right; + while (p && p != node->down->left) + { + if (type_field (p->type) == TYPE_TAG) + { + if (p->type & CONST_EXPLICIT) + { + len2 = strtol (p->name, NULL, 10); + MHD__asn1_set_name (p, NULL); + MHD__asn1_length_der (*counter - len2, temp, &len3); + if (len3 <= (*max_len)) + { + memmove (der + len2 + len3, der + len2, + *counter - len2); + memcpy (der + len2, temp, len3); + } + *max_len -= len3; + *counter += len3; + is_tag_implicit = 0; + } + else + { /* CONST_IMPLICIT */ + if (!is_tag_implicit) + { + is_tag_implicit = 1; + } + } + } + p = p->left; + } + } + + if (*max_len < 0) + return ASN1_MEM_ERROR; + + return ASN1_SUCCESS; +} + + +/******************************************************/ +/* Function : MHD__asn1_insert_tag_der */ +/* Description: creates the DER coding of tags of one */ +/* NODE. */ +/* Parameters: */ +/* node: pointer to the tree element. */ +/* der: string returned */ +/* counter: number of meaningful bytes of DER */ +/* (counter[0]..der[*counter-1]). */ +/* max_len: size of der vector */ +/* Return: */ +/* ASN1_GENERIC_ERROR if the type is unknown, */ +/* ASN1_MEM_ERROR if der vector isn't big enough, */ +/* otherwise ASN1_SUCCESS. */ +/******************************************************/ +static MHD__asn1_retCode +MHD__asn1_insert_tag_der (node_asn * node, unsigned char *der, int *counter, + int *max_len) +{ + node_asn *p; + int tag_len, is_tag_implicit; + unsigned char class, class_implicit = 0, temp[SIZEOF_UNSIGNED_INT * 3 + 1]; + unsigned long tag_implicit = 0; + char tag_der[MAX_TAG_LEN]; + + is_tag_implicit = 0; + + if (node->type & CONST_TAG) + { + p = node->down; + while (p) + { + if (type_field (p->type) == TYPE_TAG) + { + if (p->type & CONST_APPLICATION) + class = ASN1_CLASS_APPLICATION; + else if (p->type & CONST_UNIVERSAL) + class = ASN1_CLASS_UNIVERSAL; + else if (p->type & CONST_PRIVATE) + class = ASN1_CLASS_PRIVATE; + else + class = ASN1_CLASS_CONTEXT_SPECIFIC; + + if (p->type & CONST_EXPLICIT) + { + if (is_tag_implicit) + MHD__asn1_tag_der (class_implicit, tag_implicit, + (unsigned char *) tag_der, &tag_len); + else + MHD__asn1_tag_der (class | ASN1_CLASS_STRUCTURED, + strtoul ((const char *) p->value, NULL, + 10), + (unsigned char *) tag_der, &tag_len); + + *max_len -= tag_len; + if (*max_len >= 0) + memcpy (der + *counter, tag_der, tag_len); + *counter += tag_len; + + MHD__asn1_ltostr (*counter, (char *) temp); + MHD__asn1_set_name (p, (const char *) temp); + + is_tag_implicit = 0; + } + else + { /* CONST_IMPLICIT */ + if (!is_tag_implicit) + { + if ((type_field (node->type) == TYPE_SEQUENCE) || + (type_field (node->type) == TYPE_SEQUENCE_OF) || + (type_field (node->type) == TYPE_SET) || + (type_field (node->type) == TYPE_SET_OF)) + class |= ASN1_CLASS_STRUCTURED; + class_implicit = class; + tag_implicit = + strtoul ((const char *) p->value, NULL, 10); + is_tag_implicit = 1; + } + } + } + p = p->right; + } + } + + if (is_tag_implicit) + { + MHD__asn1_tag_der (class_implicit, tag_implicit, + (unsigned char *) tag_der, &tag_len); + } + else + { + switch (type_field (node->type)) + { + case TYPE_NULL: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_NULL, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_BOOLEAN: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_BOOLEAN, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_INTEGER: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_INTEGER, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_ENUMERATED: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_ENUMERATED, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_OBJECT_ID: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_OBJECT_ID, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_TIME: + if (node->type & CONST_UTC) + { + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_UTCTime, + (unsigned char *) tag_der, &tag_len); + } + else + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_GENERALIZEDTime, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_OCTET_STRING: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_OCTET_STRING, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_GENERALSTRING: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_GENERALSTRING, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_BIT_STRING: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL, ASN1_TAG_BIT_STRING, + (unsigned char *) tag_der, &tag_len); + break; + case TYPE_SEQUENCE: + case TYPE_SEQUENCE_OF: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, + ASN1_TAG_SEQUENCE, (unsigned char *) tag_der, + &tag_len); + break; + case TYPE_SET: + case TYPE_SET_OF: + MHD__asn1_tag_der (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, + ASN1_TAG_SET, (unsigned char *) tag_der, + &tag_len); + break; + case TYPE_TAG: + tag_len = 0; + break; + case TYPE_CHOICE: + tag_len = 0; + break; + case TYPE_ANY: + tag_len = 0; + break; + default: + return ASN1_GENERIC_ERROR; + } + } + + *max_len -= tag_len; + if (*max_len >= 0) + memcpy (der + *counter, tag_der, tag_len); + *counter += tag_len; + + if (*max_len < 0) + return ASN1_MEM_ERROR; + + return ASN1_SUCCESS; +} + +/******************************************************/ +/* Function : MHD__asn1_ordering_set */ +/* Description: puts the elements of a SET type in */ +/* the correct order according to DER rules. */ +/* Parameters: */ +/* der: string with the DER coding. */ +/* node: pointer to the SET element. */ +/* Return: */ +/******************************************************/ +static void +MHD__asn1_ordering_set (unsigned char *der, int der_len, node_asn * node) +{ + struct vet + { + int end; + uint32_t value; + struct vet *next, *prev; + }; + + int counter, len, len2; + struct vet *first, *last, *p_vet, *p2_vet; + node_asn *p; + unsigned char class, *temp; + unsigned long tag; + + counter = 0; + + if (type_field (node->type) != TYPE_SET) + return; + + p = node->down; + while ((p != NULL) && + ((type_field (p->type) == TYPE_TAG) + || (type_field (p->type) == TYPE_SIZE))) + p = p->right; + + if ((p == NULL) || (p->right == NULL)) + return; + + first = last = NULL; + while (p) + { + p_vet = (struct vet *) MHD__asn1_alloca (sizeof (struct vet)); + if (p_vet == NULL) + return; + + p_vet->next = NULL; + p_vet->prev = last; + if (first == NULL) + first = p_vet; + else + last->next = p_vet; + last = p_vet; + + /* tag value calculation */ + if (MHD__asn1_get_tag_der + (der + counter, der_len - counter, &class, &len2, + &tag) != ASN1_SUCCESS) + return; + p_vet->value = (class << 24) | tag; + counter += len2; + + /* extraction and length */ + len2 = + MHD__asn1_get_length_der (der + counter, der_len - counter, &len); + if (len2 < 0) + return; + counter += len + len2; + + p_vet->end = counter; + p = p->right; + } + + p_vet = first; + + while (p_vet) + { + p2_vet = p_vet->next; + counter = 0; + while (p2_vet) + { + if (p_vet->value > p2_vet->value) + { + /* change position */ + temp = + (unsigned char *) MHD__asn1_alloca (p_vet->end - counter); + if (temp == NULL) + return; + + memcpy (temp, der + counter, p_vet->end - counter); + memcpy (der + counter, der + p_vet->end, + p2_vet->end - p_vet->end); + memcpy (der + counter + p2_vet->end - p_vet->end, temp, + p_vet->end - counter); + MHD__asn1_afree (temp); + + tag = p_vet->value; + p_vet->value = p2_vet->value; + p2_vet->value = tag; + + p_vet->end = counter + (p2_vet->end - p_vet->end); + } + counter = p_vet->end; + + p2_vet = p2_vet->next; + p_vet = p_vet->next; + } + + if (p_vet != first) + p_vet->prev->next = NULL; + else + first = NULL; + MHD__asn1_afree (p_vet); + p_vet = first; + } +} + +/******************************************************/ +/* Function : MHD__asn1_ordering_set_of */ +/* Description: puts the elements of a SET OF type in */ +/* the correct order according to DER rules. */ +/* Parameters: */ +/* der: string with the DER coding. */ +/* node: pointer to the SET OF element. */ +/* Return: */ +/******************************************************/ +static void +MHD__asn1_ordering_set_of (unsigned char *der, int der_len, node_asn * node) +{ + struct vet + { + int end; + struct vet *next, *prev; + }; + + int counter, len, len2, change; + struct vet *first, *last, *p_vet, *p2_vet; + node_asn *p; + unsigned char *temp, class; + unsigned long k, max; + + counter = 0; + + if (type_field (node->type) != TYPE_SET_OF) + return; + + p = node->down; + while ((type_field (p->type) == TYPE_TAG) + || (type_field (p->type) == TYPE_SIZE)) + p = p->right; + p = p->right; + + if ((p == NULL) || (p->right == NULL)) + return; + + first = last = NULL; + while (p) + { + p_vet = (struct vet *) MHD__asn1_alloca (sizeof (struct vet)); + if (p_vet == NULL) + return; + + p_vet->next = NULL; + p_vet->prev = last; + if (first == NULL) + first = p_vet; + else + last->next = p_vet; + last = p_vet; + + /* extraction of tag and length */ + if (der_len - counter > 0) + { + + if (MHD__asn1_get_tag_der + (der + counter, der_len - counter, &class, &len, + NULL) != ASN1_SUCCESS) + return; + counter += len; + + len2 = + MHD__asn1_get_length_der (der + counter, der_len - counter, &len); + if (len2 < 0) + return; + counter += len + len2; + } + + p_vet->end = counter; + p = p->right; + } + + p_vet = first; + + while (p_vet) + { + p2_vet = p_vet->next; + counter = 0; + while (p2_vet) + { + if ((p_vet->end - counter) > (p2_vet->end - p_vet->end)) + max = p_vet->end - counter; + else + max = p2_vet->end - p_vet->end; + + change = -1; + for (k = 0; k < max; k++) + if (der[counter + k] > der[p_vet->end + k]) + { + change = 1; + break; + } + else if (der[counter + k] < der[p_vet->end + k]) + { + change = 0; + break; + } + + if ((change == -1) + && ((p_vet->end - counter) > (p2_vet->end - p_vet->end))) + change = 1; + + if (change == 1) + { + /* change position */ + temp = + (unsigned char *) MHD__asn1_alloca (p_vet->end - counter); + if (temp == NULL) + return; + + memcpy (temp, der + counter, (p_vet->end) - counter); + memcpy (der + counter, der + (p_vet->end), + (p2_vet->end) - (p_vet->end)); + memcpy (der + counter + (p2_vet->end) - (p_vet->end), temp, + (p_vet->end) - counter); + MHD__asn1_afree (temp); + + p_vet->end = counter + (p2_vet->end - p_vet->end); + } + counter = p_vet->end; + + p2_vet = p2_vet->next; + p_vet = p_vet->next; + } + + if (p_vet != first) + p_vet->prev->next = NULL; + else + first = NULL; + MHD__asn1_afree (p_vet); + p_vet = first; + } +} + +/** + * MHD__asn1_der_coding - Creates the DER encoding for the NAME structure + * @element: pointer to an ASN1 element + * @name: the name of the structure you want to encode (it must be + * inside *POINTER). + * @ider: vector that will contain the DER encoding. DER must be a + * pointer to memory cells already allocated. + * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy + * holds the sizeof of der vector. + * @errorDescription : return the error description or an empty + * string if success. + * + * Creates the DER encoding for the NAME structure (inside *POINTER + * structure). + * + * Returns: + * + * ASN1_SUCCESS: DER encoding OK. + * + * ASN1_ELEMENT_NOT_FOUND: NAME is not a valid element. + * + * ASN1_VALUE_NOT_FOUND: There is an element without a value. + * + * ASN1_MEM_ERROR: @ider vector isn't big enough. Also in this case + * LEN will contain the length needed. + * + **/ +MHD__asn1_retCode +MHD__asn1_der_coding (ASN1_TYPE element, const char *name, void *ider, + int *len, char *ErrorDescription) +{ + node_asn *node, *p, *p2; + char temp[SIZEOF_UNSIGNED_LONG_INT * 3 + 1]; + int counter, counter_old, len2, len3, tlen, move, max_len, max_len_old; + MHD__asn1_retCode err; + unsigned char *der = ider; + + node = MHD__asn1_find_node (element, name); + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + /* Node is now a locally allocated variable. + * That is because in some point we modify the + * structure, and I don't know why! --nmav + */ + node = MHD__asn1_copy_structure3 (node); + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + max_len = *len; + + counter = 0; + move = DOWN; + p = node; + while (1) + { + + counter_old = counter; + max_len_old = max_len; + if (move != UP) + { + err = MHD__asn1_insert_tag_der (p, der, &counter, &max_len); + if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) + goto error; + } + switch (type_field (p->type)) + { + case TYPE_NULL: + max_len--; + if (max_len >= 0) + der[counter] = 0; + counter++; + move = RIGHT; + break; + case TYPE_BOOLEAN: + if ((p->type & CONST_DEFAULT) && (p->value == NULL)) + { + counter = counter_old; + max_len = max_len_old; + } + else + { + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + max_len -= 2; + if (max_len >= 0) + { + der[counter++] = 1; + if (p->value[0] == 'F') + der[counter++] = 0; + else + der[counter++] = 0xFF; + } + else + counter += 2; + } + move = RIGHT; + break; + case TYPE_INTEGER: + case TYPE_ENUMERATED: + if ((p->type & CONST_DEFAULT) && (p->value == NULL)) + { + counter = counter_old; + max_len = max_len_old; + } + else + { + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + len2 = MHD__asn1_get_length_der (p->value, p->value_len, &len3); + if (len2 < 0) + { + err = ASN1_DER_ERROR; + goto error; + } + max_len -= len2 + len3; + if (max_len >= 0) + memcpy (der + counter, p->value, len3 + len2); + counter += len3 + len2; + } + move = RIGHT; + break; + case TYPE_OBJECT_ID: + if ((p->type & CONST_DEFAULT) && (p->value == NULL)) + { + counter = counter_old; + max_len = max_len_old; + } + else + { + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + len2 = max_len; + err = MHD__asn1_objectid_der (p->value, der + counter, &len2); + if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) + goto error; + + max_len -= len2; + counter += len2; + } + move = RIGHT; + break; + case TYPE_TIME: + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + len2 = max_len; + err = MHD__asn1_time_der (p->value, der + counter, &len2); + if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) + goto error; + + max_len -= len2; + counter += len2; + move = RIGHT; + break; + case TYPE_OCTET_STRING: + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + len2 = MHD__asn1_get_length_der (p->value, p->value_len, &len3); + if (len2 < 0) + { + err = ASN1_DER_ERROR; + goto error; + } + max_len -= len2 + len3; + if (max_len >= 0) + memcpy (der + counter, p->value, len3 + len2); + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_GENERALSTRING: + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + len2 = MHD__asn1_get_length_der (p->value, p->value_len, &len3); + if (len2 < 0) + { + err = ASN1_DER_ERROR; + goto error; + } + max_len -= len2 + len3; + if (max_len >= 0) + memcpy (der + counter, p->value, len3 + len2); + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_BIT_STRING: + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + len2 = MHD__asn1_get_length_der (p->value, p->value_len, &len3); + if (len2 < 0) + { + err = ASN1_DER_ERROR; + goto error; + } + max_len -= len2 + len3; + if (max_len >= 0) + memcpy (der + counter, p->value, len3 + len2); + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_SEQUENCE: + case TYPE_SET: + if (move != UP) + { + MHD__asn1_ltostr (counter, temp); + tlen = strlen (temp); + if (tlen > 0) + MHD__asn1_set_value (p, temp, tlen + 1); + if (p->down == NULL) + { + move = UP; + continue; + } + else + { + p2 = p->down; + while (p2 && (type_field (p2->type) == TYPE_TAG)) + p2 = p2->right; + if (p2) + { + p = p2; + move = RIGHT; + continue; + } + move = UP; + continue; + } + } + else + { /* move==UP */ + len2 = strtol ((const char *) p->value, NULL, 10); + MHD__asn1_set_value (p, NULL, 0); + if ((type_field (p->type) == TYPE_SET) && (max_len >= 0)) + MHD__asn1_ordering_set (der + len2, max_len - len2, p); + MHD__asn1_length_der (counter - len2, (unsigned char *) temp, + &len3); + max_len -= len3; + if (max_len >= 0) + { + memmove (der + len2 + len3, der + len2, counter - len2); + memcpy (der + len2, temp, len3); + } + counter += len3; + move = RIGHT; + } + break; + case TYPE_SEQUENCE_OF: + case TYPE_SET_OF: + if (move != UP) + { + MHD__asn1_ltostr (counter, temp); + tlen = strlen (temp); + + if (tlen > 0) + MHD__asn1_set_value (p, temp, tlen + 1); + p = p->down; + while ((type_field (p->type) == TYPE_TAG) + || (type_field (p->type) == TYPE_SIZE)) + p = p->right; + if (p->right) + { + p = p->right; + move = RIGHT; + continue; + } + else + p = MHD__asn1_find_up (p); + move = UP; + } + if (move == UP) + { + len2 = strtol ((const char *) p->value, NULL, 10); + MHD__asn1_set_value (p, NULL, 0); + if ((type_field (p->type) == TYPE_SET_OF) + && (max_len - len2 > 0)) + { + MHD__asn1_ordering_set_of (der + len2, max_len - len2, p); + } + MHD__asn1_length_der (counter - len2, (unsigned char *) temp, + &len3); + max_len -= len3; + if (max_len >= 0) + { + memmove (der + len2 + len3, der + len2, counter - len2); + memcpy (der + len2, temp, len3); + } + counter += len3; + move = RIGHT; + } + break; + case TYPE_ANY: + if (p->value == NULL) + { + MHD__asn1_error_description_value_not_found (p, + ErrorDescription); + err = ASN1_VALUE_NOT_FOUND; + goto error; + } + len2 = MHD__asn1_get_length_der (p->value, p->value_len, &len3); + if (len2 < 0) + { + err = ASN1_DER_ERROR; + goto error; + } + max_len -= len2; + if (max_len >= 0) + memcpy (der + counter, p->value + len3, len2); + counter += len2; + move = RIGHT; + break; + default: + move = (move == UP) ? RIGHT : DOWN; + break; + } + + if ((move != DOWN) && (counter != counter_old)) + { + err = MHD__asn1_complete_explicit_tag (p, der, &counter, &max_len); + if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) + goto error; + } + + if (p == node && move != DOWN) + break; + + if (move == DOWN) + { + if (p->down) + p = p->down; + else + move = RIGHT; + } + if (move == RIGHT) + { + if (p->right) + p = p->right; + else + move = UP; + } + if (move == UP) + p = MHD__asn1_find_up (p); + } + + *len = counter; + + if (max_len < 0) + { + err = ASN1_MEM_ERROR; + goto error; + } + + err = ASN1_SUCCESS; + +error: + MHD__asn1_delete_structure (&node); + return err; +} diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/decoding.c b/lib/libmicrohttpd/src/daemon/https/minitasn1/decoding.c new file mode 100644 index 0000000000..9a4e23a397 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/decoding.c @@ -0,0 +1,1673 @@ +/* + * Copyright (C) 2004, 2006 Free Software Foundation + * Copyright (C) 2002 Fabio Fiorina + * + * This file is part of LIBTASN1. + * + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +/*****************************************************/ +/* File: decoding.c */ +/* Description: Functions to manage DER decoding */ +/*****************************************************/ + +#include <int.h> +#include "parser_aux.h" +#include <gstr.h> +#include "structure.h" +#include "element.h" + + +static void +MHD__asn1_error_description_tag_error (node_asn * node, + char *ErrorDescription) +{ + + Estrcpy (ErrorDescription, ":: tag error near element '"); + MHD__asn1_hierarchical_name (node, + ErrorDescription + strlen (ErrorDescription), + MAX_ERROR_DESCRIPTION_SIZE - 40); + Estrcat (ErrorDescription, "'"); + +} + +/** + * MHD__asn1_get_length_der: + * @der: DER data to decode. + * @der_len: Length of DER data to decode. + * @len: Output variable containing the length of the DER length field. + * + * Extract a length field from DER data. + * + * Return value: Return the decoded length value, or -1 on indefinite + * length, or -2 when the value was too big. + **/ +signed long +MHD__asn1_get_length_der (const unsigned char *der, int der_len, int *len) +{ + unsigned long ans; + int k, punt; + + *len = 0; + if (der_len <= 0) + return 0; + + if (!(der[0] & 128)) + { + /* short form */ + *len = 1; + return der[0]; + } + else + { + /* Long form */ + k = der[0] & 0x7F; + punt = 1; + if (k) + { /* definite length method */ + ans = 0; + while (punt <= k && punt < der_len) + { + unsigned long last = ans; + + ans = ans * 256 + der[punt++]; + if (ans < last) + /* we wrapped around, no bignum support... */ + return -2; + } + } + else + { /* indefinite length method */ + ans = -1; + } + + *len = punt; + return ans; + } +} + + + + +/** + * MHD__asn1_get_tag_der: + * @der: DER data to decode. + * @der_len: Length of DER data to decode. + * @cls: Output variable containing decoded class. + * @len: Output variable containing the length of the DER TAG data. + * @tag: Output variable containing the decoded tag. + * + * Decode the class and TAG from DER code. + * + * Return value: Returns ASN1_SUCCESS on success, or an error. + **/ +int +MHD__asn1_get_tag_der (const unsigned char *der, int der_len, + unsigned char *cls, int *len, unsigned long *tag) +{ + int punt, ris; + + if (der == NULL || der_len <= 0 || len == NULL) + return ASN1_DER_ERROR; + + *cls = der[0] & 0xE0; + if ((der[0] & 0x1F) != 0x1F) + { + /* short form */ + *len = 1; + ris = der[0] & 0x1F; + } + else + { + /* Long form */ + punt = 1; + ris = 0; + while (punt <= der_len && der[punt] & 128) + { + int last = ris; + ris = ris * 128 + (der[punt++] & 0x7F); + if (ris < last) + /* wrapper around, and no bignums... */ + return ASN1_DER_ERROR; + } + if (punt >= der_len) + return ASN1_DER_ERROR; + { + int last = ris; + ris = ris * 128 + (der[punt++] & 0x7F); + if (ris < last) + /* wrapper around, and no bignums... */ + return ASN1_DER_ERROR; + } + *len = punt; + } + if (tag) + *tag = ris; + return ASN1_SUCCESS; +} + + + + +/** + * MHD__asn1_get_octet_der: + * @der: DER data to decode containing the OCTET SEQUENCE. + * @der_len: Length of DER data to decode. + * @ret_len: Output variable containing the length of the DER data. + * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in. + * @str_size: Length of pre-allocated output buffer. + * @str_len: Output variable containing the length of the OCTET SEQUENCE. + * + * Extract an OCTET SEQUENCE from DER data. + * + * Return value: Returns ASN1_SUCCESS on success, or an error. + **/ +int +MHD__asn1_get_octet_der (const unsigned char *der, int der_len, + int *ret_len, unsigned char *str, int str_size, + int *str_len) +{ + int len_len; + + if (der_len <= 0) + return ASN1_GENERIC_ERROR; + + /* if(str==NULL) return ASN1_SUCCESS; */ + *str_len = MHD__asn1_get_length_der (der, der_len, &len_len); + + if (*str_len < 0) + return ASN1_DER_ERROR; + + *ret_len = *str_len + len_len; + if (str_size >= *str_len) + memcpy (str, der + len_len, *str_len); + else + { + return ASN1_MEM_ERROR; + } + + return ASN1_SUCCESS; +} + + + +/* Returns ASN1_SUCCESS on success or an error code on error. + */ +static int +MHD__asn1_get_time_der (const unsigned char *der, int der_len, int *ret_len, + char *str, int str_size) +{ + int len_len, str_len; + + if (der_len <= 0 || str == NULL) + return ASN1_DER_ERROR; + str_len = MHD__asn1_get_length_der (der, der_len, &len_len); + if (str_len < 0 || str_size < str_len) + return ASN1_DER_ERROR; + memcpy (str, der + len_len, str_len); + str[str_len] = 0; + *ret_len = str_len + len_len; + + return ASN1_SUCCESS; +} + + + +static void +MHD__asn1_get_objectid_der (const unsigned char *der, int der_len, + int *ret_len, char *str, int str_size) +{ + int len_len, len, k; + char temp[20]; + unsigned long val, val1; + + *ret_len = 0; + if (str && str_size > 0) + str[0] = 0; /* no oid */ + + if (str == NULL || der_len <= 0) + return; + len = MHD__asn1_get_length_der (der, der_len, &len_len); + + if (len < 0 || len > der_len || len_len > der_len) + return; + + val1 = der[len_len] / 40; + val = der[len_len] - val1 * 40; + + MHD__asn1_str_cpy (str, str_size, MHD__asn1_ltostr (val1, temp)); + MHD__asn1_str_cat (str, str_size, "."); + MHD__asn1_str_cat (str, str_size, MHD__asn1_ltostr (val, temp)); + + val = 0; + for (k = 1; k < len; k++) + { + val = val << 7; + val |= der[len_len + k] & 0x7F; + if (!(der[len_len + k] & 0x80)) + { + MHD__asn1_str_cat (str, str_size, "."); + MHD__asn1_str_cat (str, str_size, MHD__asn1_ltostr (val, temp)); + val = 0; + } + } + *ret_len = len + len_len; +} + + + + +/** + * MHD__asn1_get_bit_der: + * @der: DER data to decode containing the BIT SEQUENCE. + * @der_len: Length of DER data to decode. + * @ret_len: Output variable containing the length of the DER data. + * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in. + * @str_size: Length of pre-allocated output buffer. + * @bit_len: Output variable containing the size of the BIT SEQUENCE. + * + * Extract a BIT SEQUENCE from DER data. + * + * Return value: Return ASN1_SUCCESS on success, or an error. + **/ +int +MHD__asn1_get_bit_der (const unsigned char *der, int der_len, + int *ret_len, unsigned char *str, int str_size, + int *bit_len) +{ + int len_len, len_byte; + + if (der_len <= 0) + return ASN1_GENERIC_ERROR; + len_byte = MHD__asn1_get_length_der (der, der_len, &len_len) - 1; + if (len_byte < 0) + return ASN1_DER_ERROR; + + *ret_len = len_byte + len_len + 1; + *bit_len = len_byte * 8 - der[len_len]; + + if (str_size >= len_byte) + memcpy (str, der + len_len + 1, len_byte); + else + { + return ASN1_MEM_ERROR; + } + + return ASN1_SUCCESS; +} + + + + +static int +MHD__asn1_extract_tag_der (node_asn * node, const unsigned char *der, + int der_len, int *ret_len) +{ + node_asn *p; + int counter, len2, len3, is_tag_implicit; + unsigned long tag, tag_implicit = 0; + unsigned char class, class2, class_implicit = 0; + + if (der_len <= 0) + return ASN1_GENERIC_ERROR; + + counter = is_tag_implicit = 0; + + if (node->type & CONST_TAG) + { + p = node->down; + while (p) + { + if (type_field (p->type) == TYPE_TAG) + { + if (p->type & CONST_APPLICATION) + class2 = ASN1_CLASS_APPLICATION; + else if (p->type & CONST_UNIVERSAL) + class2 = ASN1_CLASS_UNIVERSAL; + else if (p->type & CONST_PRIVATE) + class2 = ASN1_CLASS_PRIVATE; + else + class2 = ASN1_CLASS_CONTEXT_SPECIFIC; + + if (p->type & CONST_EXPLICIT) + { + if (MHD__asn1_get_tag_der + (der + counter, der_len - counter, &class, &len2, + &tag) != ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter + len2 > der_len) + return ASN1_DER_ERROR; + counter += len2; + len3 = + MHD__asn1_get_length_der (der + counter, + der_len - counter, &len2); + if (len3 < 0) + return ASN1_DER_ERROR; + counter += len2; + if (!is_tag_implicit) + { + if ((class != (class2 | ASN1_CLASS_STRUCTURED)) || + (tag != strtoul ((char *) p->value, NULL, 10))) + return ASN1_TAG_ERROR; + } + else + { /* ASN1_TAG_IMPLICIT */ + if ((class != class_implicit) || (tag != tag_implicit)) + return ASN1_TAG_ERROR; + } + + is_tag_implicit = 0; + } + else + { /* ASN1_TAG_IMPLICIT */ + if (!is_tag_implicit) + { + if ((type_field (node->type) == TYPE_SEQUENCE) || + (type_field (node->type) == TYPE_SEQUENCE_OF) || + (type_field (node->type) == TYPE_SET) || + (type_field (node->type) == TYPE_SET_OF)) + class2 |= ASN1_CLASS_STRUCTURED; + class_implicit = class2; + tag_implicit = strtoul ((char *) p->value, NULL, 10); + is_tag_implicit = 1; + } + } + } + p = p->right; + } + } + + if (is_tag_implicit) + { + if (MHD__asn1_get_tag_der + (der + counter, der_len - counter, &class, &len2, + &tag) != ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter + len2 > der_len) + return ASN1_DER_ERROR; + + if ((class != class_implicit) || (tag != tag_implicit)) + { + if (type_field (node->type) == TYPE_OCTET_STRING) + { + class_implicit |= ASN1_CLASS_STRUCTURED; + if ((class != class_implicit) || (tag != tag_implicit)) + return ASN1_TAG_ERROR; + } + else + return ASN1_TAG_ERROR; + } + } + else + { + if (type_field (node->type) == TYPE_TAG) + { + counter = 0; + *ret_len = counter; + return ASN1_SUCCESS; + } + + if (MHD__asn1_get_tag_der + (der + counter, der_len - counter, &class, &len2, + &tag) != ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter + len2 > der_len) + return ASN1_DER_ERROR; + + switch (type_field (node->type)) + { + case TYPE_NULL: + if ((class != ASN1_CLASS_UNIVERSAL) || (tag != ASN1_TAG_NULL)) + return ASN1_DER_ERROR; + break; + case TYPE_BOOLEAN: + if ((class != ASN1_CLASS_UNIVERSAL) || (tag != ASN1_TAG_BOOLEAN)) + return ASN1_DER_ERROR; + break; + case TYPE_INTEGER: + if ((class != ASN1_CLASS_UNIVERSAL) || (tag != ASN1_TAG_INTEGER)) + return ASN1_DER_ERROR; + break; + case TYPE_ENUMERATED: + if ((class != ASN1_CLASS_UNIVERSAL) || (tag != ASN1_TAG_ENUMERATED)) + return ASN1_DER_ERROR; + break; + case TYPE_OBJECT_ID: + if ((class != ASN1_CLASS_UNIVERSAL) || (tag != ASN1_TAG_OBJECT_ID)) + return ASN1_DER_ERROR; + break; + case TYPE_TIME: + if (node->type & CONST_UTC) + { + if ((class != ASN1_CLASS_UNIVERSAL) + || (tag != ASN1_TAG_UTCTime)) + return ASN1_DER_ERROR; + } + else + { + if ((class != ASN1_CLASS_UNIVERSAL) + || (tag != ASN1_TAG_GENERALIZEDTime)) + return ASN1_DER_ERROR; + } + break; + case TYPE_OCTET_STRING: + if (((class != ASN1_CLASS_UNIVERSAL) + && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED))) + || (tag != ASN1_TAG_OCTET_STRING)) + return ASN1_DER_ERROR; + break; + case TYPE_GENERALSTRING: + if ((class != ASN1_CLASS_UNIVERSAL) + || (tag != ASN1_TAG_GENERALSTRING)) + return ASN1_DER_ERROR; + break; + case TYPE_BIT_STRING: + if ((class != ASN1_CLASS_UNIVERSAL) || (tag != ASN1_TAG_BIT_STRING)) + return ASN1_DER_ERROR; + break; + case TYPE_SEQUENCE: + case TYPE_SEQUENCE_OF: + if ((class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED)) + || (tag != ASN1_TAG_SEQUENCE)) + return ASN1_DER_ERROR; + break; + case TYPE_SET: + case TYPE_SET_OF: + if ((class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED)) + || (tag != ASN1_TAG_SET)) + return ASN1_DER_ERROR; + break; + case TYPE_ANY: + counter -= len2; + break; + default: + return ASN1_DER_ERROR; + break; + } + } + + counter += len2; + *ret_len = counter; + return ASN1_SUCCESS; +} + + +static int +MHD__asn1_delete_not_used (node_asn * node) +{ + node_asn *p, *p2; + + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + p = node; + while (p) + { + if (p->type & CONST_NOT_USED) + { + p2 = NULL; + if (p != node) + { + p2 = MHD__asn1_find_left (p); + if (!p2) + p2 = MHD__asn1_find_up (p); + } + MHD__asn1_delete_structure (&p); + p = p2; + } + + if (!p) + break; /* reach node */ + + if (p->down) + { + p = p->down; + } + else + { + if (p == node) + p = NULL; + else if (p->right) + p = p->right; + else + { + while (1) + { + p = MHD__asn1_find_up (p); + if (p == node) + { + p = NULL; + break; + } + if (p->right) + { + p = p->right; + break; + } + } + } + } + } + return ASN1_SUCCESS; +} + + +static MHD__asn1_retCode +MHD__asn1_get_octet_string (const unsigned char *der, node_asn * node, + int *len) +{ + int len2, len3, counter, counter2, counter_end, tot_len, indefinite; + unsigned char *temp, *temp2; + + counter = 0; + + if (*(der - 1) & ASN1_CLASS_STRUCTURED) + { + tot_len = 0; + indefinite = MHD__asn1_get_length_der (der, *len, &len3); + if (indefinite < -1) + return ASN1_DER_ERROR; + + counter += len3; + if (indefinite >= 0) + indefinite += len3; + + while (1) + { + if (counter > (*len)) + return ASN1_DER_ERROR; + + if (indefinite == -1) + { + if ((der[counter] == 0) && (der[counter + 1] == 0)) + { + counter += 2; + break; + } + } + else if (counter >= indefinite) + break; + + if (der[counter] != ASN1_TAG_OCTET_STRING) + return ASN1_DER_ERROR; + + counter++; + + len2 = + MHD__asn1_get_length_der (der + counter, *len - counter, &len3); + if (len2 <= 0) + return ASN1_DER_ERROR; + + counter += len3 + len2; + tot_len += len2; + } + + /* copy */ + if (node) + { + MHD__asn1_length_der (tot_len, NULL, &len2); + temp = MHD__asn1_alloca (len2 + tot_len); + if (temp == NULL) + { + return ASN1_MEM_ALLOC_ERROR; + } + + MHD__asn1_length_der (tot_len, temp, &len2); + tot_len += len2; + temp2 = temp + len2; + len2 = MHD__asn1_get_length_der (der, *len, &len3); + if (len2 < -1) + { + MHD__asn1_afree (temp); + return ASN1_DER_ERROR; + } + counter2 = len3 + 1; + + if (indefinite == -1) + counter_end = counter - 2; + else + counter_end = counter; + + while (counter2 < counter_end) + { + len2 = + MHD__asn1_get_length_der (der + counter2, *len - counter, + &len3); + if (len2 < -1) + { + MHD__asn1_afree (temp); + return ASN1_DER_ERROR; + } + + /* FIXME: to be checked. Is this ok? Has the + * size been checked before? + */ + memcpy (temp2, der + counter2 + len3, len2); + temp2 += len2; + counter2 += len2 + len3 + 1; + } + + MHD__asn1_set_value (node, temp, tot_len); + MHD__asn1_afree (temp); + } + } + else + { /* NOT STRUCTURED */ + len2 = MHD__asn1_get_length_der (der, *len, &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + if (len3 + len2 > *len) + return ASN1_DER_ERROR; + if (node) + MHD__asn1_set_value (node, der, len3 + len2); + counter = len3 + len2; + } + + *len = counter; + return ASN1_SUCCESS; + +} + + +static MHD__asn1_retCode +MHD__asn1_get_indefinite_length_string (const unsigned char *der, int *len) +{ + int len2, len3, counter, indefinite; + unsigned long tag; + unsigned char class; + + counter = indefinite = 0; + + while (1) + { + if ((*len) < counter) + return ASN1_DER_ERROR; + + if ((der[counter] == 0) && (der[counter + 1] == 0)) + { + counter += 2; + indefinite--; + if (indefinite <= 0) + break; + else + continue; + } + + if (MHD__asn1_get_tag_der + (der + counter, *len - counter, &class, &len2, + &tag) != ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter + len2 > *len) + return ASN1_DER_ERROR; + counter += len2; + len2 = MHD__asn1_get_length_der (der + counter, *len - counter, &len3); + if (len2 < -1) + return ASN1_DER_ERROR; + if (len2 == -1) + { + indefinite++; + counter += 1; + } + else + { + counter += len2 + len3; + } + } + + *len = counter; + return ASN1_SUCCESS; + +} + + +/** + * MHD__asn1_der_decoding - Fill the structure *ELEMENT with values of a DER encoding string. + * @element: pointer to an ASN1 structure. + * @ider: vector that contains the DER encoding. + * @len: number of bytes of *@ider: @ider[0]..@ider[len-1]. + * @errorDescription: null-terminated string contains details when an + * error occurred. + * + * Fill the structure *ELEMENT with values of a DER encoding + * string. The sructure must just be created with function + * 'create_stucture'. If an error occurs during the decoding + * procedure, the *ELEMENT is deleted and set equal to + * %ASN1_TYPE_EMPTY. + * + * Returns: + * + * ASN1_SUCCESS: DER encoding OK. + * + * ASN1_ELEMENT_NOT_FOUND: ELEMENT is ASN1_TYPE_EMPTY. + * + * ASN1_TAG_ERROR,ASN1_DER_ERROR: The der encoding doesn't match + * the structure NAME. *ELEMENT deleted. + **/ + +MHD__asn1_retCode +MHD__asn1_der_decoding (ASN1_TYPE * element, const void *ider, int len, + char *errorDescription) +{ + node_asn *node, *p, *p2, *p3; + char temp[128]; + int counter, len2, len3, len4, move, ris, tlen; + unsigned char class, *temp2; + unsigned long tag; + int indefinite, result; + const unsigned char *der = ider; + + node = *element; + + if (node == ASN1_TYPE_EMPTY) + return ASN1_ELEMENT_NOT_FOUND; + + if (node->type & CONST_OPTION) + { + MHD__asn1_delete_structure (element); + return ASN1_GENERIC_ERROR; + } + + counter = 0; + move = DOWN; + p = node; + while (1) + { + ris = ASN1_SUCCESS; + if (move != UP) + { + if (p->type & CONST_SET) + { + p2 = MHD__asn1_find_up (p); + len2 = strtol ((const char *) p2->value, NULL, 10); + if (len2 == -1) + { + if (!der[counter] && !der[counter + 1]) + { + p = p2; + move = UP; + counter += 2; + continue; + } + } + else if (counter == len2) + { + p = p2; + move = UP; + continue; + } + else if (counter > len2) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + p2 = p2->down; + while (p2) + { + if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED)) + { + if (type_field (p2->type) != TYPE_CHOICE) + ris = + MHD__asn1_extract_tag_der (p2, der + counter, + len - counter, &len2); + else + { + p3 = p2->down; + while (p3) + { + ris = + MHD__asn1_extract_tag_der (p3, der + counter, + len - counter, + &len2); + if (ris == ASN1_SUCCESS) + break; + p3 = p3->right; + } + } + if (ris == ASN1_SUCCESS) + { + p2->type &= ~CONST_NOT_USED; + p = p2; + break; + } + } + p2 = p2->right; + } + if (p2 == NULL) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + } + + if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) + { + p2 = MHD__asn1_find_up (p); + len2 = strtol ((const char *) p2->value, NULL, 10); + if (counter == len2) + { + if (p->right) + { + p2 = p->right; + move = RIGHT; + } + else + move = UP; + + if (p->type & CONST_OPTION) + MHD__asn1_delete_structure (&p); + + p = p2; + continue; + } + } + + if (type_field (p->type) == TYPE_CHOICE) + { + while (p->down) + { + if (counter < len) + ris = + MHD__asn1_extract_tag_der (p->down, der + counter, + len - counter, &len2); + else + ris = ASN1_DER_ERROR; + if (ris == ASN1_SUCCESS) + { + while (p->down->right) + { + p2 = p->down->right; + MHD__asn1_delete_structure (&p2); + } + break; + } + else if (ris == ASN1_ERROR_TYPE_ANY) + { + MHD__asn1_delete_structure (element); + return ASN1_ERROR_TYPE_ANY; + } + else + { + p2 = p->down; + MHD__asn1_delete_structure (&p2); + } + } + + if (p->down == NULL) + { + if (!(p->type & CONST_OPTION)) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + } + else + p = p->down; + } + + if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) + { + p2 = MHD__asn1_find_up (p); + len2 = strtol ((const char *) p2->value, NULL, 10); + if ((len2 != -1) && (counter > len2)) + ris = ASN1_TAG_ERROR; + } + + if (ris == ASN1_SUCCESS) + ris = + MHD__asn1_extract_tag_der (p, der + counter, len - counter, + &len2); + if (ris != ASN1_SUCCESS) + { + if (p->type & CONST_OPTION) + { + p->type |= CONST_NOT_USED; + move = RIGHT; + } + else if (p->type & CONST_DEFAULT) + { + MHD__asn1_set_value (p, NULL, 0); + move = RIGHT; + } + else + { + if (errorDescription != NULL) + MHD__asn1_error_description_tag_error (p, + errorDescription); + + MHD__asn1_delete_structure (element); + return ASN1_TAG_ERROR; + } + } + else + counter += len2; + } + + if (ris == ASN1_SUCCESS) + { + switch (type_field (p->type)) + { + case TYPE_NULL: + if (der[counter]) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + counter++; + move = RIGHT; + break; + case TYPE_BOOLEAN: + if (der[counter++] != 1) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + if (der[counter++] == 0) + MHD__asn1_set_value (p, "F", 1); + else + MHD__asn1_set_value (p, "T", 1); + move = RIGHT; + break; + case TYPE_INTEGER: + case TYPE_ENUMERATED: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + if (len2 + len3 > len - counter) + return ASN1_DER_ERROR; + MHD__asn1_set_value (p, der + counter, len3 + len2); + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_OBJECT_ID: + MHD__asn1_get_objectid_der (der + counter, len - counter, &len2, + temp, sizeof (temp)); + tlen = strlen (temp); + if (tlen > 0) + MHD__asn1_set_value (p, temp, tlen + 1); + counter += len2; + move = RIGHT; + break; + case TYPE_TIME: + result = + MHD__asn1_get_time_der (der + counter, len - counter, &len2, + temp, sizeof (temp) - 1); + if (result != ASN1_SUCCESS) + { + MHD__asn1_delete_structure (element); + return result; + } + tlen = strlen (temp); + if (tlen > 0) + MHD__asn1_set_value (p, temp, tlen + 1); + counter += len2; + move = RIGHT; + break; + case TYPE_OCTET_STRING: + len3 = len - counter; + ris = MHD__asn1_get_octet_string (der + counter, p, &len3); + if (ris != ASN1_SUCCESS) + return ris; + counter += len3; + move = RIGHT; + break; + case TYPE_GENERALSTRING: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + if (len3 + len2 > len - counter) + return ASN1_DER_ERROR; + MHD__asn1_set_value (p, der + counter, len3 + len2); + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_BIT_STRING: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + if (len3 + len2 > len - counter) + return ASN1_DER_ERROR; + MHD__asn1_set_value (p, der + counter, len3 + len2); + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_SEQUENCE: + case TYPE_SET: + if (move == UP) + { + len2 = strtol ((const char *) p->value, NULL, 10); + MHD__asn1_set_value (p, NULL, 0); + if (len2 == -1) + { /* indefinite length method */ + if (len - counter + 1 > 0) + { + if ((der[counter]) || der[counter + 1]) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + } + else + return ASN1_DER_ERROR; + counter += 2; + } + else + { /* definite length method */ + if (len2 != counter) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + } + move = RIGHT; + } + else + { /* move==DOWN || move==RIGHT */ + len3 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len2); + if (len3 < -1) + return ASN1_DER_ERROR; + counter += len2; + if (len3 > 0) + { + MHD__asn1_ltostr (counter + len3, temp); + tlen = strlen (temp); + if (tlen > 0) + MHD__asn1_set_value (p, temp, tlen + 1); + move = DOWN; + } + else if (len3 == 0) + { + p2 = p->down; + while (p2) + { + if (type_field (p2->type) != TYPE_TAG) + { + p3 = p2->right; + MHD__asn1_delete_structure (&p2); + p2 = p3; + } + else + p2 = p2->right; + } + move = RIGHT; + } + else + { /* indefinite length method */ + MHD__asn1_set_value (p, "-1", 3); + move = DOWN; + } + } + break; + case TYPE_SEQUENCE_OF: + case TYPE_SET_OF: + if (move == UP) + { + len2 = strtol ((const char *) p->value, NULL, 10); + if (len2 == -1) + { /* indefinite length method */ + if ((counter + 2) > len) + return ASN1_DER_ERROR; + if ((der[counter]) || der[counter + 1]) + { + MHD__asn1_append_sequence_set (p); + p = p->down; + while (p->right) + p = p->right; + move = RIGHT; + continue; + } + MHD__asn1_set_value (p, NULL, 0); + counter += 2; + } + else + { /* definite length method */ + if (len2 > counter) + { + MHD__asn1_append_sequence_set (p); + p = p->down; + while (p->right) + p = p->right; + move = RIGHT; + continue; + } + MHD__asn1_set_value (p, NULL, 0); + if (len2 != counter) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + } + } + else + { /* move==DOWN || move==RIGHT */ + len3 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len2); + if (len3 < -1) + return ASN1_DER_ERROR; + counter += len2; + if (len3) + { + if (len3 > 0) + { /* definite length method */ + MHD__asn1_ltostr (counter + len3, temp); + tlen = strlen (temp); + + if (tlen > 0) + MHD__asn1_set_value (p, temp, tlen + 1); + } + else + { /* indefinite length method */ + MHD__asn1_set_value (p, "-1", 3); + } + p2 = p->down; + while ((type_field (p2->type) == TYPE_TAG) + || (type_field (p2->type) == TYPE_SIZE)) + p2 = p2->right; + if (p2->right == NULL) + MHD__asn1_append_sequence_set (p); + p = p2; + } + } + move = RIGHT; + break; + case TYPE_ANY: + if (MHD__asn1_get_tag_der + (der + counter, len - counter, &class, &len2, + &tag) != ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter + len2 > len) + return ASN1_DER_ERROR; + len4 = + MHD__asn1_get_length_der (der + counter + len2, + len - counter - len2, &len3); + if (len4 < -1) + return ASN1_DER_ERROR; + if (len4 > len - counter + len2 + len3) + return ASN1_DER_ERROR; + if (len4 != -1) + { + len2 += len4; + MHD__asn1_length_der (len2 + len3, NULL, &len4); + temp2 = + (unsigned char *) MHD__asn1_alloca (len2 + len3 + len4); + if (temp2 == NULL) + { + MHD__asn1_delete_structure (element); + return ASN1_MEM_ALLOC_ERROR; + } + + MHD__asn1_octet_der (der + counter, len2 + len3, temp2, + &len4); + MHD__asn1_set_value (p, temp2, len4); + MHD__asn1_afree (temp2); + counter += len2 + len3; + } + else + { /* indefinite length */ + /* Check indefinite lenth method in an EXPLICIT TAG */ + if ((p->type & CONST_TAG) && (der[counter - 1] == 0x80)) + indefinite = 1; + else + indefinite = 0; + + len2 = len - counter; + ris = + MHD__asn1_get_indefinite_length_string (der + counter, + &len2); + if (ris != ASN1_SUCCESS) + { + MHD__asn1_delete_structure (element); + return ris; + } + MHD__asn1_length_der (len2, NULL, &len4); + temp2 = (unsigned char *) MHD__asn1_alloca (len2 + len4); + if (temp2 == NULL) + { + MHD__asn1_delete_structure (element); + return ASN1_MEM_ALLOC_ERROR; + } + + MHD__asn1_octet_der (der + counter, len2, temp2, &len4); + MHD__asn1_set_value (p, temp2, len4); + MHD__asn1_afree (temp2); + counter += len2; + + /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with + an indefinite length method. */ + if (indefinite) + { + if (!der[counter] && !der[counter + 1]) + { + counter += 2; + } + else + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + } + } + move = RIGHT; + break; + default: + move = (move == UP) ? RIGHT : DOWN; + break; + } + } + + if (p == node && move != DOWN) + break; + + if (move == DOWN) + { + if (p->down) + p = p->down; + else + move = RIGHT; + } + if ((move == RIGHT) && !(p->type & CONST_SET)) + { + if (p->right) + p = p->right; + else + move = UP; + } + if (move == UP) + p = MHD__asn1_find_up (p); + } + + MHD__asn1_delete_not_used (*element); + + if (counter != len) + { + MHD__asn1_delete_structure (element); + return ASN1_DER_ERROR; + } + + return ASN1_SUCCESS; +} + + +/** + * MHD__asn1_der_decoding_startEnd - Find the start and end point of an element in a DER encoding string. + * @element: pointer to an ASN1 element + * @ider: vector that contains the DER encoding. + * @len: number of bytes of *@ider: @ider[0]..@ider[len-1] + * @name_element: an element of NAME structure. + * @start: the position of the first byte of NAME_ELEMENT decoding + * (@ider[*start]) + * @end: the position of the last byte of NAME_ELEMENT decoding + * (@ider[*end]) + * + * Find the start and end point of an element in a DER encoding + * string. I mean that if you have a der encoding and you have + * already used the function "MHD__asn1_der_decoding" to fill a structure, + * it may happen that you want to find the piece of string concerning + * an element of the structure. + * + * Example: the sequence "tbsCertificate" inside an X509 certificate. + * + * Returns: + * + * ASN1_SUCCESS: DER encoding OK. + * + * ASN1_ELEMENT_NOT_FOUND: ELEMENT is ASN1_TYPE EMPTY or + * NAME_ELEMENT is not a valid element. + * + * ASN1_TAG_ERROR,ASN1_DER_ERROR: the der encoding doesn't match + * the structure ELEMENT. + * + **/ +MHD__asn1_retCode +MHD__asn1_der_decoding_startEnd (ASN1_TYPE element, const void *ider, int len, + const char *name_element, int *start, + int *end) +{ + node_asn *node, *node_to_find, *p, *p2, *p3; + int counter, len2, len3, len4, move, ris; + unsigned char class; + unsigned long tag; + int indefinite; + const unsigned char *der = ider; + + node = element; + + if (node == ASN1_TYPE_EMPTY) + return ASN1_ELEMENT_NOT_FOUND; + + node_to_find = MHD__asn1_find_node (node, name_element); + + if (node_to_find == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + if (node_to_find == node) + { + *start = 0; + *end = len - 1; + return ASN1_SUCCESS; + } + + if (node->type & CONST_OPTION) + return ASN1_GENERIC_ERROR; + + counter = 0; + move = DOWN; + p = node; + while (1) + { + ris = ASN1_SUCCESS; + + if (move != UP) + { + if (p->type & CONST_SET) + { + p2 = MHD__asn1_find_up (p); + len2 = strtol ((const char *) p2->value, NULL, 10); + if (len2 == -1) + { + if (!der[counter] && !der[counter + 1]) + { + p = p2; + move = UP; + counter += 2; + continue; + } + } + else if (counter == len2) + { + p = p2; + move = UP; + continue; + } + else if (counter > len2) + return ASN1_DER_ERROR; + p2 = p2->down; + while (p2) + { + if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED)) + { /* CONTROLLARE */ + if (type_field (p2->type) != TYPE_CHOICE) + ris = + MHD__asn1_extract_tag_der (p2, der + counter, + len - counter, &len2); + else + { + p3 = p2->down; + ris = + MHD__asn1_extract_tag_der (p3, der + counter, + len - counter, &len2); + } + if (ris == ASN1_SUCCESS) + { + p2->type &= ~CONST_NOT_USED; + p = p2; + break; + } + } + p2 = p2->right; + } + if (p2 == NULL) + return ASN1_DER_ERROR; + } + + if (p == node_to_find) + *start = counter; + + if (type_field (p->type) == TYPE_CHOICE) + { + p = p->down; + ris = + MHD__asn1_extract_tag_der (p, der + counter, len - counter, + &len2); + if (p == node_to_find) + *start = counter; + } + + if (ris == ASN1_SUCCESS) + ris = + MHD__asn1_extract_tag_der (p, der + counter, len - counter, + &len2); + if (ris != ASN1_SUCCESS) + { + if (p->type & CONST_OPTION) + { + p->type |= CONST_NOT_USED; + move = RIGHT; + } + else if (p->type & CONST_DEFAULT) + { + move = RIGHT; + } + else + { + return ASN1_TAG_ERROR; + } + } + else + counter += len2; + } + + if (ris == ASN1_SUCCESS) + { + switch (type_field (p->type)) + { + case TYPE_NULL: + if (der[counter]) + return ASN1_DER_ERROR; + counter++; + move = RIGHT; + break; + case TYPE_BOOLEAN: + if (der[counter++] != 1) + return ASN1_DER_ERROR; + counter++; + move = RIGHT; + break; + case TYPE_INTEGER: + case TYPE_ENUMERATED: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_OBJECT_ID: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + counter += len2 + len3; + move = RIGHT; + break; + case TYPE_TIME: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + counter += len2 + len3; + move = RIGHT; + break; + case TYPE_OCTET_STRING: + len3 = len - counter; + ris = MHD__asn1_get_octet_string (der + counter, NULL, &len3); + if (ris != ASN1_SUCCESS) + return ris; + counter += len3; + move = RIGHT; + break; + case TYPE_GENERALSTRING: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_BIT_STRING: + len2 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + counter += len3 + len2; + move = RIGHT; + break; + case TYPE_SEQUENCE: + case TYPE_SET: + if (move != UP) + { + len3 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len2); + if (len3 < -1) + return ASN1_DER_ERROR; + counter += len2; + if (len3 == 0) + move = RIGHT; + else + move = DOWN; + } + else + { + if (!der[counter] && !der[counter + 1]) /* indefinite length method */ + counter += 2; + move = RIGHT; + } + break; + case TYPE_SEQUENCE_OF: + case TYPE_SET_OF: + if (move != UP) + { + len3 = + MHD__asn1_get_length_der (der + counter, len - counter, + &len2); + if (len3 < -1) + return ASN1_DER_ERROR; + counter += len2; + if ((len3 == -1) && !der[counter] && !der[counter + 1]) + counter += 2; + else if (len3) + { + p2 = p->down; + while ((type_field (p2->type) == TYPE_TAG) || + (type_field (p2->type) == TYPE_SIZE)) + p2 = p2->right; + p = p2; + } + } + else + { + if (!der[counter] && !der[counter + 1]) /* indefinite length method */ + counter += 2; + } + move = RIGHT; + break; + case TYPE_ANY: + if (MHD__asn1_get_tag_der + (der + counter, len - counter, &class, &len2, + &tag) != ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter + len2 > len) + return ASN1_DER_ERROR; + + len4 = + MHD__asn1_get_length_der (der + counter + len2, + len - counter - len2, &len3); + if (len4 < -1) + return ASN1_DER_ERROR; + + if (len4 != -1) + { + counter += len2 + len4 + len3; + } + else + { /* indefinite length */ + /* Check indefinite lenth method in an EXPLICIT TAG */ + if ((p->type & CONST_TAG) && (der[counter - 1] == 0x80)) + indefinite = 1; + else + indefinite = 0; + + len2 = len - counter; + ris = + MHD__asn1_get_indefinite_length_string (der + counter, + &len2); + if (ris != ASN1_SUCCESS) + return ris; + counter += len2; + + /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with + an indefinite length method. */ + if (indefinite) + { + if (!der[counter] && !der[counter + 1]) + counter += 2; + else + return ASN1_DER_ERROR; + } + } + move = RIGHT; + break; + default: + move = (move == UP) ? RIGHT : DOWN; + break; + } + } + + if ((p == node_to_find) && (move == RIGHT)) + { + *end = counter - 1; + return ASN1_SUCCESS; + } + + if (p == node && move != DOWN) + break; + + if (move == DOWN) + { + if (p->down) + p = p->down; + else + move = RIGHT; + } + if ((move == RIGHT) && !(p->type & CONST_SET)) + { + if (p->right) + p = p->right; + else + move = UP; + } + if (move == UP) + p = MHD__asn1_find_up (p); + } + + return ASN1_ELEMENT_NOT_FOUND; +} diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/element.c b/lib/libmicrohttpd/src/daemon/https/minitasn1/element.c new file mode 100644 index 0000000000..4834c604a7 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/element.c @@ -0,0 +1,902 @@ +/* + * Copyright (C) 2004, 2006 Free Software Foundation + * Copyright (C) 2000, 2001, 2002, 2003 Fabio Fiorina + * + * This file is part of LIBTASN1. + * + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +/*****************************************************/ +/* File: element.c */ +/* Description: Functions with the read and write */ +/* functions. */ +/*****************************************************/ + + +#include <int.h> +#include "parser_aux.h" +#include <gstr.h> +#include "structure.h" + +void +MHD__asn1_hierarchical_name (node_asn * node, char *name, int name_size) +{ + node_asn *p; + char tmp_name[64]; + + p = node; + + name[0] = 0; + + while (p != NULL) + { + if (p->name != NULL) + { + MHD__asn1_str_cpy (tmp_name, sizeof (tmp_name), name), + MHD__asn1_str_cpy (name, name_size, p->name); + MHD__asn1_str_cat (name, name_size, "."); + MHD__asn1_str_cat (name, name_size, tmp_name); + } + p = MHD__asn1_find_up (p); + } + + if (name[0] == 0) + MHD__asn1_str_cpy (name, name_size, "ROOT"); +} + + +/******************************************************************/ +/* Function : MHD__asn1_convert_integer */ +/* Description: converts an integer from a null terminated string */ +/* to der decoding. The convertion from a null */ +/* terminated string to an integer is made with */ +/* the 'strtol' function. */ +/* Parameters: */ +/* value: null terminated string to convert. */ +/* value_out: convertion result (memory must be already */ +/* allocated). */ +/* value_out_size: number of bytes of value_out. */ +/* len: number of significant byte of value_out. */ +/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS */ +/******************************************************************/ +MHD__asn1_retCode +MHD__asn1_convert_integer (const char *value, unsigned char *value_out, + int value_out_size, int *len) +{ + char negative; + unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; + long valtmp; + int k, k2; + + valtmp = strtol (value, NULL, 10); + + for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) + { + val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF; + } + + if (val[0] & 0x80) + negative = 1; + else + negative = 0; + + for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++) + { + if (negative && (val[k] != 0xFF)) + break; + else if (!negative && val[k]) + break; + } + + if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80))) + k--; + + *len = SIZEOF_UNSIGNED_LONG_INT - k; + + if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size) + /* VALUE_OUT is too short to contain the value conversion */ + return ASN1_MEM_ERROR; + + for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++) + value_out[k2 - k] = val[k2]; + + return ASN1_SUCCESS; +} + + +int +MHD__asn1_append_sequence_set (node_asn * node) +{ + node_asn *p, *p2; + char temp[10]; + long n; + + if (!node || !(node->down)) + return ASN1_GENERIC_ERROR; + + p = node->down; + while ((type_field (p->type) == TYPE_TAG) + || (type_field (p->type) == TYPE_SIZE)) + p = p->right; + p2 = MHD__asn1_copy_structure3 (p); + while (p->right) + p = p->right; + MHD__asn1_set_right (p, p2); + + if (p->name == NULL) + MHD__asn1_str_cpy (temp, sizeof (temp), "?1"); + else + { + n = strtol (p->name + 1, NULL, 0); + n++; + temp[0] = '?'; + MHD__asn1_ltostr (n, temp + 1); + } + MHD__asn1_set_name (p2, temp); + /* p2->type |= CONST_OPTION; */ + + return ASN1_SUCCESS; +} + + +/** + * MHD__asn1_write_value - Set the value of one element inside a structure. + * @node_root: pointer to a structure + * @name: the name of the element inside the structure that you want to set. + * @ivalue: vector used to specify the value to set. If len is >0, + * VALUE must be a two's complement form integer. if len=0 *VALUE + * must be a null terminated string with an integer value. + * @len: number of bytes of *value to use to set the value: + * value[0]..value[len-1] or 0 if value is a null terminated string + * + * Set the value of one element inside a structure. + * + * If an element is OPTIONAL and you want to delete it, you must use + * the value=NULL and len=0. Using "pkix.asn": + * + * result=MHD__asn1_write_value(cert, "tbsCertificate.issuerUniqueID", + * NULL, 0); + * + * Description for each type: + * + * INTEGER: VALUE must contain a two's complement form integer. + * + * value[0]=0xFF , len=1 -> integer=-1. + * value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1. + * value[0]=0x01 , len=1 -> integer= 1. + * value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1. + * value="123" , len=0 -> integer= 123. + * + * ENUMERATED: As INTEGER (but only with not negative numbers). + * + * BOOLEAN: VALUE must be the null terminated string "TRUE" or + * "FALSE" and LEN != 0. + * + * value="TRUE" , len=1 -> boolean=TRUE. + * value="FALSE" , len=1 -> boolean=FALSE. + * + * OBJECT IDENTIFIER: VALUE must be a null terminated string with + * each number separated by a dot (e.g. "1.2.3.543.1"). LEN != 0. + * + * value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha. + * + * UTCTime: VALUE must be a null terminated string in one of these + * formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ", + * "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'", + * "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'". LEN != 0. + * + * value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 + * at 12h 00m Greenwich Mean Time + * + * GeneralizedTime: VALUE must be in one of this format: + * "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ", + * "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'", + * "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s + * indicates the seconds with any precision like "10.1" or "01.02". + * LEN != 0 + * + * value="2001010112001.12-0700" , len=1 -> time=Jannuary + * 1st, 2001 at 12h 00m 01.12s Pacific Daylight Time + * + * OCTET STRING: VALUE contains the octet string and LEN is the + * number of octets. + * + * value="$\backslash$x01$\backslash$x02$\backslash$x03" , + * len=3 -> three bytes octet string + * + * GeneralString: VALUE contains the generalstring and LEN is the + * number of octets. + * + * value="$\backslash$x01$\backslash$x02$\backslash$x03" , + * len=3 -> three bytes generalstring + * + * BIT STRING: VALUE contains the bit string organized by bytes and + * LEN is the number of bits. + * + * value="$\backslash$xCF" , len=6 -> bit string="110011" (six + * bits) + * + * CHOICE: if NAME indicates a choice type, VALUE must specify one of + * the alternatives with a null terminated string. LEN != 0. Using + * "pkix.asn"\: + * + * result=MHD__asn1_write_value(cert, + * "certificate1.tbsCertificate.subject", "rdnSequence", + * 1); + * + * ANY: VALUE indicates the der encoding of a structure. LEN != 0. + * + * SEQUENCE OF: VALUE must be the null terminated string "NEW" and + * LEN != 0. With this instruction another element is appended in + * the sequence. The name of this element will be "?1" if it's the + * first one, "?2" for the second and so on. + * + * Using "pkix.asn"\: + * + * result=MHD__asn1_write_value(cert, + * "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1); + * + * SET OF: the same as SEQUENCE OF. Using "pkix.asn": + * + * result=MHD__asn1_write_value(cert, + * "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1); + * + * Returns: + * + * ASN1_SUCCESS: Set value OK. + * + * ASN1_ELEMENT_NOT_FOUND: NAME is not a valid element. + * + * ASN1_VALUE_NOT_VALID: VALUE has a wrong format. + * + **/ +MHD__asn1_retCode +MHD__asn1_write_value (ASN1_TYPE node_root, const char *name, + const void *ivalue, int len) +{ + node_asn *node, *p, *p2; + unsigned char *temp, *value_temp = NULL, *default_temp = NULL; + int len2, k, k2, negative; + const char *value = ivalue; + + node = MHD__asn1_find_node (node_root, name); + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0)) + { + MHD__asn1_delete_structure (&node); + return ASN1_SUCCESS; + } + + if ((type_field (node->type) == TYPE_SEQUENCE_OF) && (value == NULL) + && (len == 0)) + { + p = node->down; + while ((type_field (p->type) == TYPE_TAG) + || (type_field (p->type) == TYPE_SIZE)) + p = p->right; + + while (p->right) + MHD__asn1_delete_structure (&p->right); + + return ASN1_SUCCESS; + } + + switch (type_field (node->type)) + { + case TYPE_BOOLEAN: + if (!strcmp (value, "TRUE")) + { + if (node->type & CONST_DEFAULT) + { + p = node->down; + while (type_field (p->type) != TYPE_DEFAULT) + p = p->right; + if (p->type & CONST_TRUE) + MHD__asn1_set_value (node, NULL, 0); + else + MHD__asn1_set_value (node, "T", 1); + } + else + MHD__asn1_set_value (node, "T", 1); + } + else if (!strcmp (value, "FALSE")) + { + if (node->type & CONST_DEFAULT) + { + p = node->down; + while (type_field (p->type) != TYPE_DEFAULT) + p = p->right; + if (p->type & CONST_FALSE) + MHD__asn1_set_value (node, NULL, 0); + else + MHD__asn1_set_value (node, "F", 1); + } + else + MHD__asn1_set_value (node, "F", 1); + } + else + return ASN1_VALUE_NOT_VALID; + break; + case TYPE_INTEGER: + case TYPE_ENUMERATED: + if (len == 0) + { + if ((isdigit (value[0])) || (value[0] == '-')) + { + value_temp = + (unsigned char *) MHD__asn1_alloca (SIZEOF_UNSIGNED_LONG_INT); + if (value_temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + + MHD__asn1_convert_integer (value, value_temp, + SIZEOF_UNSIGNED_LONG_INT, &len); + } + else + { /* is an identifier like v1 */ + if (!(node->type & CONST_LIST)) + return ASN1_VALUE_NOT_VALID; + p = node->down; + while (p) + { + if (type_field (p->type) == TYPE_CONSTANT) + { + if ((p->name) && (!strcmp (p->name, value))) + { + value_temp = + (unsigned char *) + MHD__asn1_alloca (SIZEOF_UNSIGNED_LONG_INT); + if (value_temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + + MHD__asn1_convert_integer ((const char *) p->value, + value_temp, + SIZEOF_UNSIGNED_LONG_INT, + &len); + break; + } + } + p = p->right; + } + if (p == NULL) + return ASN1_VALUE_NOT_VALID; + } + } + else + { /* len != 0 */ + value_temp = (unsigned char *) MHD__asn1_alloca (len); + if (value_temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + memcpy (value_temp, value, len); + } + + + if (value_temp[0] & 0x80) + negative = 1; + else + negative = 0; + + if (negative && (type_field (node->type) == TYPE_ENUMERATED)) + { + MHD__asn1_afree (value_temp); + return ASN1_VALUE_NOT_VALID; + } + + for (k = 0; k < len - 1; k++) + if (negative && (value_temp[k] != 0xFF)) + break; + else if (!negative && value_temp[k]) + break; + + if ((negative && !(value_temp[k] & 0x80)) || + (!negative && (value_temp[k] & 0x80))) + k--; + + MHD__asn1_length_der (len - k, NULL, &len2); + temp = (unsigned char *) MHD__asn1_alloca (len - k + len2); + if (temp == NULL) + { + MHD__asn1_afree (value_temp); + return ASN1_MEM_ALLOC_ERROR; + } + + MHD__asn1_octet_der (value_temp + k, len - k, temp, &len2); + MHD__asn1_set_value (node, temp, len2); + + MHD__asn1_afree (temp); + + + if (node->type & CONST_DEFAULT) + { + p = node->down; + while (type_field (p->type) != TYPE_DEFAULT) + p = p->right; + if ((isdigit (p->value[0])) || (p->value[0] == '-')) + { + default_temp = + (unsigned char *) MHD__asn1_alloca (SIZEOF_UNSIGNED_LONG_INT); + if (default_temp == NULL) + { + MHD__asn1_afree (value_temp); + return ASN1_MEM_ALLOC_ERROR; + } + + MHD__asn1_convert_integer ((const char *) p->value, + default_temp, + SIZEOF_UNSIGNED_LONG_INT, &len2); + } + else + { /* is an identifier like v1 */ + if (!(node->type & CONST_LIST)) + { + MHD__asn1_afree (value_temp); + return ASN1_VALUE_NOT_VALID; + } + p2 = node->down; + while (p2) + { + if (type_field (p2->type) == TYPE_CONSTANT) + { + if ((p2->name) + && (!strcmp (p2->name, (const char *) p->value))) + { + default_temp = + (unsigned char *) + MHD__asn1_alloca (SIZEOF_UNSIGNED_LONG_INT); + if (default_temp == NULL) + { + MHD__asn1_afree (value_temp); + return ASN1_MEM_ALLOC_ERROR; + } + + MHD__asn1_convert_integer ((const char *) p2->value, + default_temp, + SIZEOF_UNSIGNED_LONG_INT, + &len2); + break; + } + } + p2 = p2->right; + } + if (p2 == NULL) + { + MHD__asn1_afree (value_temp); + return ASN1_VALUE_NOT_VALID; + } + } + + + if ((len - k) == len2) + { + for (k2 = 0; k2 < len2; k2++) + if (value_temp[k + k2] != default_temp[k2]) + { + break; + } + if (k2 == len2) + MHD__asn1_set_value (node, NULL, 0); + } + MHD__asn1_afree (default_temp); + } + MHD__asn1_afree (value_temp); + break; + case TYPE_OBJECT_ID: + for (k = 0; k < strlen (value); k++) + if ((!isdigit (value[k])) && (value[k] != '.') && (value[k] != '+')) + return ASN1_VALUE_NOT_VALID; + if (node->type & CONST_DEFAULT) + { + p = node->down; + while (type_field (p->type) != TYPE_DEFAULT) + p = p->right; + if (!strcmp (value, (const char *) p->value)) + { + MHD__asn1_set_value (node, NULL, 0); + break; + } + } + MHD__asn1_set_value (node, value, strlen (value) + 1); + break; + case TYPE_TIME: + if (node->type & CONST_UTC) + { + if (strlen (value) < 11) + return ASN1_VALUE_NOT_VALID; + for (k = 0; k < 10; k++) + if (!isdigit (value[k])) + return ASN1_VALUE_NOT_VALID; + switch (strlen (value)) + { + case 11: + if (value[10] != 'Z') + return ASN1_VALUE_NOT_VALID; + break; + case 13: + if ((!isdigit (value[10])) || (!isdigit (value[11])) || + (value[12] != 'Z')) + return ASN1_VALUE_NOT_VALID; + break; + case 15: + if ((value[10] != '+') && (value[10] != '-')) + return ASN1_VALUE_NOT_VALID; + for (k = 11; k < 15; k++) + if (!isdigit (value[k])) + return ASN1_VALUE_NOT_VALID; + break; + case 17: + if ((!isdigit (value[10])) || (!isdigit (value[11]))) + return ASN1_VALUE_NOT_VALID; + if ((value[12] != '+') && (value[12] != '-')) + return ASN1_VALUE_NOT_VALID; + for (k = 13; k < 17; k++) + if (!isdigit (value[k])) + return ASN1_VALUE_NOT_VALID; + break; + default: + return ASN1_VALUE_NOT_FOUND; + } + MHD__asn1_set_value (node, value, strlen (value) + 1); + } + else + { /* GENERALIZED TIME */ + if (value) + MHD__asn1_set_value (node, value, strlen (value) + 1); + } + break; + case TYPE_OCTET_STRING: + if (len == 0) + len = strlen (value); + MHD__asn1_length_der (len, NULL, &len2); + temp = (unsigned char *) MHD__asn1_alloca (len + len2); + if (temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + + MHD__asn1_octet_der ((const unsigned char *) value, len, temp, &len2); + MHD__asn1_set_value (node, temp, len2); + MHD__asn1_afree (temp); + break; + case TYPE_GENERALSTRING: + if (len == 0) + len = strlen (value); + MHD__asn1_length_der (len, NULL, &len2); + temp = (unsigned char *) MHD__asn1_alloca (len + len2); + if (temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + + MHD__asn1_octet_der ((const unsigned char *) value, len, temp, &len2); + MHD__asn1_set_value (node, temp, len2); + MHD__asn1_afree (temp); + break; + case TYPE_BIT_STRING: + if (len == 0) + len = strlen (value); + MHD__asn1_length_der ((len >> 3) + 2, NULL, &len2); + temp = (unsigned char *) MHD__asn1_alloca ((len >> 3) + 2 + len2); + if (temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + + MHD__asn1_bit_der ((const unsigned char *) value, len, temp, &len2); + MHD__asn1_set_value (node, temp, len2); + MHD__asn1_afree (temp); + break; + case TYPE_CHOICE: + p = node->down; + while (p) + { + if (!strcmp (p->name, value)) + { + p2 = node->down; + while (p2) + { + if (p2 != p) + { + MHD__asn1_delete_structure (&p2); + p2 = node->down; + } + else + p2 = p2->right; + } + break; + } + p = p->right; + } + if (!p) + return ASN1_ELEMENT_NOT_FOUND; + break; + case TYPE_ANY: + MHD__asn1_length_der (len, NULL, &len2); + temp = (unsigned char *) MHD__asn1_alloca (len + len2); + if (temp == NULL) + return ASN1_MEM_ALLOC_ERROR; + + MHD__asn1_octet_der ((const unsigned char *) value, len, temp, &len2); + MHD__asn1_set_value (node, temp, len2); + MHD__asn1_afree (temp); + break; + case TYPE_SEQUENCE_OF: + case TYPE_SET_OF: + if (strcmp (value, "NEW")) + return ASN1_VALUE_NOT_VALID; + MHD__asn1_append_sequence_set (node); + break; + default: + return ASN1_ELEMENT_NOT_FOUND; + break; + } + + return ASN1_SUCCESS; +} + + +#define PUT_VALUE( ptr, ptr_size, data, data_size) \ + *len = data_size; \ + if (ptr_size < data_size) { \ + return ASN1_MEM_ERROR; \ + } else { \ + memcpy( ptr, data, data_size); \ + } + +#define PUT_STR_VALUE( ptr, ptr_size, data) \ + *len = strlen(data) + 1; \ + if (ptr_size < *len) { \ + return ASN1_MEM_ERROR; \ + } else { \ + /* this strcpy is checked */ \ + strcpy(ptr, data); \ + } + +#define ADD_STR_VALUE( ptr, ptr_size, data) \ + *len = strlen(data) + 1; \ + if (ptr_size < strlen(ptr)+(*len)) { \ + return ASN1_MEM_ERROR; \ + } else { \ + /* this strcat is checked */ \ + strcat(ptr, data); \ + } + +/** + * MHD__asn1_read_value - Returns the value of one element inside a structure + * @root: pointer to a structure. + * @name: the name of the element inside a structure that you want to read. + * @ivalue: vector that will contain the element's content, must be a + * pointer to memory cells already allocated. + * @len: number of bytes of *value: value[0]..value[len-1]. Initialy + * holds the sizeof value. + * + * Returns the value of one element inside a structure. + * + * If an element is OPTIONAL and the function "read_value" returns + * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present + * in the der encoding that created the structure. The first element + * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and + * so on. + * + * INTEGER: VALUE will contain a two's complement form integer. + * + * integer=-1 -> value[0]=0xFF , len=1. + * integer=1 -> value[0]=0x01 , len=1. + * + * ENUMERATED: As INTEGER (but only with not negative numbers). + * + * BOOLEAN: VALUE will be the null terminated string "TRUE" or + * "FALSE" and LEN=5 or LEN=6. + * + * OBJECT IDENTIFIER: VALUE will be a null terminated string with + * each number separated by a dot (i.e. "1.2.3.543.1"). + * + * LEN = strlen(VALUE)+1 + * + * UTCTime: VALUE will be a null terminated string in one of these + * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". + * LEN=strlen(VALUE)+1. + * + * GeneralizedTime: VALUE will be a null terminated string in the + * same format used to set the value. + * + * OCTET STRING: VALUE will contain the octet string and LEN will be + * the number of octets. + * + * GeneralString: VALUE will contain the generalstring and LEN will + * be the number of octets. + * + * BIT STRING: VALUE will contain the bit string organized by bytes + * and LEN will be the number of bits. + * + * CHOICE: If NAME indicates a choice type, VALUE will specify the + * alternative selected. + * + * ANY: If NAME indicates an any type, VALUE will indicate the DER + * encoding of the structure actually used. + * + * Returns: + * + * ASN1_SUCCESS: Set value OK. + * + * ASN1_ELEMENT_NOT_FOUND: NAME is not a valid element. + * + * ASN1_VALUE_NOT_FOUND: There isn't any value for the element selected. + * + * ASN1_MEM_ERROR: The value vector isn't big enough to store the result. + * In this case LEN will contain the number of bytes needed. + * + **/ +MHD__asn1_retCode +MHD__asn1_read_value (ASN1_TYPE root, const char *name, void *ivalue, + int *len) +{ + node_asn *node, *p, *p2; + int len2, len3; + int value_size = *len; + char *value = ivalue; + + node = MHD__asn1_find_node (root, name); + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + if ((type_field (node->type) != TYPE_NULL) && + (type_field (node->type) != TYPE_CHOICE) && + !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) && + (node->value == NULL)) + return ASN1_VALUE_NOT_FOUND; + + switch (type_field (node->type)) + { + case TYPE_NULL: + PUT_STR_VALUE (value, value_size, "NULL"); + break; + case TYPE_BOOLEAN: + if ((node->type & CONST_DEFAULT) && (node->value == NULL)) + { + p = node->down; + while (type_field (p->type) != TYPE_DEFAULT) + p = p->right; + if (p->type & CONST_TRUE) + { + PUT_STR_VALUE (value, value_size, "TRUE"); + } + else + { + PUT_STR_VALUE (value, value_size, "FALSE"); + } + } + else if (node->value[0] == 'T') + { + PUT_STR_VALUE (value, value_size, "TRUE"); + } + else + { + PUT_STR_VALUE (value, value_size, "FALSE"); + } + break; + case TYPE_INTEGER: + case TYPE_ENUMERATED: + if ((node->type & CONST_DEFAULT) && (node->value == NULL)) + { + p = node->down; + while (type_field (p->type) != TYPE_DEFAULT) + p = p->right; + if ((isdigit (p->value[0])) || (p->value[0] == '-') + || (p->value[0] == '+')) + { + if (MHD__asn1_convert_integer + ((const char *) p->value, (unsigned char *) value, + value_size, len) != ASN1_SUCCESS) + return ASN1_MEM_ERROR; + } + else + { /* is an identifier like v1 */ + p2 = node->down; + while (p2) + { + if (type_field (p2->type) == TYPE_CONSTANT) + { + if ((p2->name) + && (!strcmp (p2->name, (const char *) p->value))) + { + if (MHD__asn1_convert_integer + ((const char *) p2->value, + (unsigned char *) value, value_size, + len) != ASN1_SUCCESS) + return ASN1_MEM_ERROR; + break; + } + } + p2 = p2->right; + } + } + } + else + { + len2 = -1; + if (MHD__asn1_get_octet_der + (node->value, node->value_len, &len2, (unsigned char *) value, + value_size, len) != ASN1_SUCCESS) + return ASN1_MEM_ERROR; + } + break; + case TYPE_OBJECT_ID: + if (node->type & CONST_ASSIGN) + { + value[0] = 0; + p = node->down; + while (p) + { + if (type_field (p->type) == TYPE_CONSTANT) + { + ADD_STR_VALUE (value, value_size, (const char *) p->value); + if (p->right) + { + ADD_STR_VALUE (value, value_size, "."); + } + } + p = p->right; + } + *len = strlen (value) + 1; + } + else if ((node->type & CONST_DEFAULT) && (node->value == NULL)) + { + p = node->down; + while (type_field (p->type) != TYPE_DEFAULT) + p = p->right; + PUT_STR_VALUE (value, value_size, (const char *) p->value); + } + else + { + PUT_STR_VALUE (value, value_size, (const char *) node->value); + } + break; + case TYPE_TIME: + PUT_STR_VALUE (value, value_size, (const char *) node->value); + break; + case TYPE_OCTET_STRING: + len2 = -1; + if (MHD__asn1_get_octet_der + (node->value, node->value_len, &len2, (unsigned char *) value, + value_size, len) != ASN1_SUCCESS) + return ASN1_MEM_ERROR; + break; + case TYPE_GENERALSTRING: + len2 = -1; + if (MHD__asn1_get_octet_der + (node->value, node->value_len, &len2, (unsigned char *) value, + value_size, len) != ASN1_SUCCESS) + return ASN1_MEM_ERROR; + break; + case TYPE_BIT_STRING: + len2 = -1; + if (MHD__asn1_get_bit_der + (node->value, node->value_len, &len2, (unsigned char *) value, + value_size, len) != ASN1_SUCCESS) + return ASN1_MEM_ERROR; + break; + case TYPE_CHOICE: + PUT_STR_VALUE (value, value_size, node->down->name); + break; + case TYPE_ANY: + len3 = -1; + len2 = MHD__asn1_get_length_der (node->value, node->value_len, &len3); + if (len2 < 0) + return ASN1_DER_ERROR; + PUT_VALUE (value, value_size, node->value + len3, len2); + break; + default: + return ASN1_ELEMENT_NOT_FOUND; + break; + } + return ASN1_SUCCESS; +} diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/element.h b/lib/libmicrohttpd/src/daemon/https/minitasn1/element.h new file mode 100644 index 0000000000..e4484925d9 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/element.h @@ -0,0 +1,14 @@ + +#ifndef _ELEMENT_H +#define _ELEMENT_H + + +MHD__asn1_retCode MHD__asn1_append_sequence_set (node_asn * node); + +MHD__asn1_retCode MHD__asn1_convert_integer (const char *value, + unsigned char *value_out, + int value_out_size, int *len); + +void MHD__asn1_hierarchical_name (node_asn * node, char *name, int name_size); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/gstr.c b/lib/libmicrohttpd/src/daemon/https/minitasn1/gstr.c new file mode 100644 index 0000000000..7068db51fc --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/gstr.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006 Free Software Foundation + * Copyright (C) 2002 Nikos Mavroyanopoulos + * + * This file is part of LIBTASN1. + * + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include <int.h> + +/* These function are like strcat, strcpy. They only + * do bounds checking (they shouldn't cause buffer overruns), + * and they always produce null terminated strings. + * + * They should be used only with null terminated strings. + */ +void +MHD__asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) +{ + size_t str_size = strlen (src); + size_t dest_size = strlen (dest); + + if (dest_tot_size - dest_size > str_size) + { + strcat (dest, src); + } + else + { + if (dest_tot_size - dest_size > 0) + { + strncat (dest, src, (dest_tot_size - dest_size) - 1); + dest[dest_tot_size - 1] = 0; + } + } +} + +void +MHD__asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src) +{ + size_t str_size = strlen (src); + + if (dest_tot_size > str_size) + { + strcpy (dest, src); + } + else + { + if (dest_tot_size > 0) + { + strncpy (dest, src, (dest_tot_size) - 1); + dest[dest_tot_size - 1] = 0; + } + } +} diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/gstr.h b/lib/libmicrohttpd/src/daemon/https/minitasn1/gstr.h new file mode 100644 index 0000000000..e0cda357b5 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/gstr.h @@ -0,0 +1,5 @@ +void MHD__asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src); +void MHD__asn1_str_cat (char *dest, size_t dest_tot_size, const char *src); + +#define Estrcpy(x,y) MHD__asn1_str_cpy(x,MAX_ERROR_DESCRIPTION_SIZE,y) +#define Estrcat(x,y) MHD__asn1_str_cat(x,MAX_ERROR_DESCRIPTION_SIZE,y) diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/int.h b/lib/libmicrohttpd/src/daemon/https/minitasn1/int.h new file mode 100644 index 0000000000..a99fb6dbb1 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/int.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2004, 2006 Free Software Foundation, Inc. + * Copyright (C) 2002 Fabio Fiorina + * + * This file is part of LIBTASN1. + * + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef INT_H +#define INT_H + +#include <libtasn1.h> +#include <defines.h> + +/* +#define LIBTASN1_DEBUG +#define LIBTASN1_DEBUG_PARSER +#define LIBTASN1_DEBUG_INTEGER +*/ + +#include <mem.h> + +#define MAX_LOG_SIZE 1024 /* maximum number of characters of a log message */ + +/* Define used for visiting trees. */ +#define UP 1 +#define RIGHT 2 +#define DOWN 3 + +/****************************************/ +/* Returns the first 8 bits. */ +/* Used with the field type of node_asn */ +/****************************************/ +#define type_field(x) (x&0xFF) + +/* List of constants for field type of typedef node_asn */ +#define TYPE_CONSTANT 1 +#define TYPE_IDENTIFIER 2 +#define TYPE_INTEGER 3 +#define TYPE_BOOLEAN 4 +#define TYPE_SEQUENCE 5 +#define TYPE_BIT_STRING 6 +#define TYPE_OCTET_STRING 7 +#define TYPE_TAG 8 +#define TYPE_DEFAULT 9 +#define TYPE_SIZE 10 +#define TYPE_SEQUENCE_OF 11 +#define TYPE_OBJECT_ID 12 +#define TYPE_ANY 13 +#define TYPE_SET 14 +#define TYPE_SET_OF 15 +#define TYPE_DEFINITIONS 16 +#define TYPE_TIME 17 +#define TYPE_CHOICE 18 +#define TYPE_IMPORTS 19 +#define TYPE_NULL 20 +#define TYPE_ENUMERATED 21 +#define TYPE_GENERALSTRING 27 + + +/***********************************************************************/ +/* List of constants to better specify the type of typedef node_asn. */ +/***********************************************************************/ +/* Used with TYPE_TAG */ +#define CONST_UNIVERSAL (1<<8) +#define CONST_PRIVATE (1<<9) +#define CONST_APPLICATION (1<<10) +#define CONST_EXPLICIT (1<<11) +#define CONST_IMPLICIT (1<<12) + +#define CONST_TAG (1<<13) /* Used in ASN.1 assignement */ +#define CONST_OPTION (1<<14) +#define CONST_DEFAULT (1<<15) +#define CONST_TRUE (1<<16) +#define CONST_FALSE (1<<17) + +#define CONST_LIST (1<<18) /* Used with TYPE_INTEGER and TYPE_BIT_STRING */ +#define CONST_MIN_MAX (1<<19) + +#define CONST_1_PARAM (1<<20) + +#define CONST_SIZE (1<<21) + +#define CONST_DEFINED_BY (1<<22) + +#define CONST_GENERALIZED (1<<23) +#define CONST_UTC (1<<24) + +/* #define CONST_IMPORTS (1<<25) */ + +#define CONST_NOT_USED (1<<26) +#define CONST_SET (1<<27) +#define CONST_ASSIGN (1<<28) + +#define CONST_DOWN (1<<29) +#define CONST_RIGHT (1<<30) + +#endif /* INT_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/libtasn1.h b/lib/libmicrohttpd/src/daemon/https/minitasn1/libtasn1.h new file mode 100644 index 0000000000..f478d0b7a5 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/libtasn1.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2004, 2005, 2006 Free Software Foundation + * Copyright (C) 2002 Fabio Fiorina + * + * This file is part of LIBTASN1. + * + * LIBTASN1 is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * LIBTASN1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with LIBTASN1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef LIBTASN1_H +# define LIBTASN1_H + +#include <stdio.h> /* for FILE* */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LIBTASN1_VERSION "1.2" + +#include <sys/types.h> +#include <time.h> + +#define MAX_NAME_SIZE 128 /* maximum number of characters of a name */ + /* inside a file with ASN1 definitons */ +#define MAX_ERROR_DESCRIPTION_SIZE 128 /* maximum number of characters */ + /* of a description message */ + /* (null character included) */ + + + typedef int MHD__asn1_retCode; /* type returned by libtasn1 functions */ + + /*****************************************/ + /* Errors returned by libtasn1 functions */ + /*****************************************/ +#define ASN1_SUCCESS 0 +#define ASN1_FILE_NOT_FOUND 1 +#define ASN1_ELEMENT_NOT_FOUND 2 +#define ASN1_IDENTIFIER_NOT_FOUND 3 +#define ASN1_DER_ERROR 4 +#define ASN1_VALUE_NOT_FOUND 5 +#define ASN1_GENERIC_ERROR 6 +#define ASN1_VALUE_NOT_VALID 7 +#define ASN1_TAG_ERROR 8 +#define ASN1_TAG_IMPLICIT 9 +#define ASN1_ERROR_TYPE_ANY 10 +#define ASN1_SYNTAX_ERROR 11 +#define ASN1_MEM_ERROR 12 +#define ASN1_MEM_ALLOC_ERROR 13 +#define ASN1_DER_OVERFLOW 14 +#define ASN1_NAME_TOO_LONG 15 +#define ASN1_ARRAY_ERROR 16 +#define ASN1_ELEMENT_NOT_EMPTY 17 + +/*************************************/ +/* Constants used in MHD__asn1_visit_tree */ +/*************************************/ +#define ASN1_PRINT_NAME 1 +#define ASN1_PRINT_NAME_TYPE 2 +#define ASN1_PRINT_NAME_TYPE_VALUE 3 +#define ASN1_PRINT_ALL 4 + +/*****************************************/ +/* Constants returned by MHD__asn1_read_tag */ +/*****************************************/ +#define ASN1_CLASS_UNIVERSAL 0x00 /* old: 1 */ +#define ASN1_CLASS_APPLICATION 0x40 /* old: 2 */ +#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /* old: 3 */ +#define ASN1_CLASS_PRIVATE 0xC0 /* old: 4 */ +#define ASN1_CLASS_STRUCTURED 0x20 + +/*****************************************/ +/* Constants returned by MHD__asn1_read_tag */ +/*****************************************/ +#define ASN1_TAG_BOOLEAN 0x01 +#define ASN1_TAG_INTEGER 0x02 +#define ASN1_TAG_SEQUENCE 0x10 +#define ASN1_TAG_SET 0x11 +#define ASN1_TAG_OCTET_STRING 0x04 +#define ASN1_TAG_BIT_STRING 0x03 +#define ASN1_TAG_UTCTime 0x17 +#define ASN1_TAG_GENERALIZEDTime 0x18 +#define ASN1_TAG_OBJECT_ID 0x06 +#define ASN1_TAG_ENUMERATED 0x0A +#define ASN1_TAG_NULL 0x05 +#define ASN1_TAG_GENERALSTRING 0x1B + +/******************************************************/ +/* Structure definition used for the node of the tree */ +/* that represent an ASN.1 DEFINITION. */ +/******************************************************/ + + struct node_asn_struct + { + char *name; /* Node name */ + unsigned int type; /* Node type */ + unsigned char *value; /* Node value */ + int value_len; + struct node_asn_struct *down; /* Pointer to the son node */ + struct node_asn_struct *right; /* Pointer to the brother node */ + struct node_asn_struct *left; /* Pointer to the next list element */ + }; + + typedef struct node_asn_struct node_asn; + + typedef node_asn *ASN1_TYPE; + +#define ASN1_TYPE_EMPTY NULL + + struct static_struct_asn + { + const char *name; /* Node name */ + unsigned int type; /* Node type */ + const void *value; /* Node value */ + }; + + typedef struct static_struct_asn ASN1_ARRAY_TYPE; + + + + /***********************************/ + /* Functions definitions */ + /***********************************/ + + MHD__asn1_retCode MHD__asn1_parser2tree (const char *file_name, + ASN1_TYPE * definitions, + char *errorDescription); + + MHD__asn1_retCode MHD__asn1_parser2array (const char *inputFileName, + const char *outputFileName, + const char *vectorName, + char *errorDescription); + + MHD__asn1_retCode MHD__asn1_array2tree (const ASN1_ARRAY_TYPE * array, + ASN1_TYPE * definitions, + char *errorDescription); + + MHD__asn1_retCode MHD__asn1_create_element (ASN1_TYPE definitions, + const char *source_name, + ASN1_TYPE * element); + + MHD__asn1_retCode MHD__asn1_delete_structure (ASN1_TYPE * structure); + + MHD__asn1_retCode MHD__asn1_write_value (ASN1_TYPE node_root, + const char *name, + const void *ivalue, int len); + + MHD__asn1_retCode MHD__asn1_read_value (ASN1_TYPE root, const char *name, + void *ivalue, int *len); + + MHD__asn1_retCode MHD__asn1_der_coding (ASN1_TYPE element, const char *name, + void *ider, int *len, + char *ErrorDescription); + + MHD__asn1_retCode MHD__asn1_der_decoding (ASN1_TYPE * element, + const void *ider, int len, + char *errorDescription); + + MHD__asn1_retCode MHD__asn1_der_decoding_startEnd (ASN1_TYPE element, + const void *ider, + int len, + const char *name_element, + int *start, int *end); + + /* DER utility functions. */ + + int MHD__asn1_get_tag_der (const unsigned char *der, int der_len, + unsigned char *cls, int *len, + unsigned long *tag); + + void MHD__asn1_octet_der (const unsigned char *str, int str_len, + unsigned char *der, int *der_len); + + MHD__asn1_retCode MHD__asn1_get_octet_der (const unsigned char *der, + int der_len, int *ret_len, + unsigned char *str, int str_size, + int *str_len); + + void MHD__asn1_bit_der (const unsigned char *str, int bit_len, + unsigned char *der, int *der_len); + + MHD__asn1_retCode MHD__asn1_get_bit_der (const unsigned char *der, + int der_len, int *ret_len, + unsigned char *str, int str_size, + int *bit_len); + + signed long MHD__asn1_get_length_der (const unsigned char *der, int der_len, + int *len); + + void MHD__asn1_length_der (unsigned long int len, unsigned char *ans, + int *ans_len); + + /* Other utility functions. */ + + ASN1_TYPE MHD__asn1_find_node (ASN1_TYPE pointer, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBTASN1_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/mem.h b/lib/libmicrohttpd/src/daemon/https/minitasn1/mem.h new file mode 100644 index 0000000000..76139df034 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/mem.h @@ -0,0 +1,25 @@ +#ifndef MEM_H +# define MEM_H + +/* Use MHD__asn1_afree() when calling alloca, or + * memory leaks may occur in systems which do not + * support alloca. + */ +#ifdef HAVE_ALLOCA +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# endif +# define MHD__asn1_alloca alloca +# define MHD__asn1_afree(x) +#else +# define MHD__asn1_alloca MHD__asn1_malloc +# define MHD__asn1_afree MHD__asn1_free +#endif /* HAVE_ALLOCA */ + +#define MHD__asn1_malloc malloc +#define MHD__asn1_free free +#define MHD__asn1_calloc calloc +#define MHD__asn1_realloc realloc +#define MHD__asn1_strdup strdup + +#endif /* MEM_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/parser_aux.c b/lib/libmicrohttpd/src/daemon/https/minitasn1/parser_aux.c new file mode 100644 index 0000000000..0643ff4c56 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/parser_aux.c @@ -0,0 +1,774 @@ +/* + * Copyright (C) 2004, 2006, 2007 Free Software Foundation + * Copyright (C) 2000,2001 Fabio Fiorina + * + * This file is part of LIBTASN1. + * + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include <int.h> +#include "parser_aux.h" +#include "gstr.h" +#include "structure.h" +#include "element.h" + + + +char MHD__asn1_identifierMissing[MAX_NAME_SIZE + 1]; /* identifier name not found */ + +/***********************************************/ +/* Type: list_type */ +/* Description: type used in the list during */ +/* the structure creation. */ +/***********************************************/ +typedef struct list_struct +{ + node_asn *node; + struct list_struct *next; +} list_type; + + +/* Pointer to the first element of the list */ +list_type *MHD_firstElement = NULL; + +/******************************************************/ +/* Function : MHD__asn1_add_node */ +/* Description: creates a new NODE_ASN element and */ +/* puts it in the list pointed by MHD_firstElement. */ +/* Parameters: */ +/* type: type of the new element (see TYPE_ */ +/* and CONST_ constants). */ +/* Return: pointer to the new element. */ +/******************************************************/ +node_asn * +MHD__asn1_add_node (unsigned int type) +{ + list_type *listElement; + node_asn *punt; + + punt = (node_asn *) MHD__asn1_calloc (1, sizeof (node_asn)); + if (punt == NULL) + return NULL; + + listElement = (list_type *) MHD__asn1_malloc (sizeof (list_type)); + if (listElement == NULL) + { + MHD__asn1_free (punt); + return NULL; + } + + listElement->node = punt; + listElement->next = MHD_firstElement; + MHD_firstElement = listElement; + + punt->type = type; + + return punt; +} + +/** + * MHD__asn1_find_node: + * @pointer: NODE_ASN element pointer. + * @name: null terminated string with the element's name to find. + * + * Searches for an element called NAME starting from POINTER. The + * name is composed by differents identifiers separated by dots. When + * *POINTER has a name, the first identifier must be the name of + * *POINTER, otherwise it must be the name of one child of *POINTER. + * + * Return value: the searching result. NULL if not found. + **/ +ASN1_TYPE +MHD__asn1_find_node (ASN1_TYPE pointer, const char *name) +{ + node_asn *p; + char *n_end, n[MAX_NAME_SIZE + 1]; + const char *n_start; + + if (pointer == NULL) + return NULL; + + if (name == NULL) + return NULL; + + p = pointer; + n_start = name; + + if (p->name != NULL) + { /* has *pointer got a name ? */ + n_end = strchr (n_start, '.'); /* search the first dot */ + if (n_end) + { + memcpy (n, n_start, n_end - n_start); + n[n_end - n_start] = 0; + n_start = n_end; + n_start++; + } + else + { + MHD__asn1_str_cpy (n, sizeof (n), n_start); + n_start = NULL; + } + + while (p) + { + if ((p->name) && (!strcmp (p->name, n))) + break; + else + p = p->right; + } /* while */ + + if (p == NULL) + return NULL; + } + else + { /* *pointer doesn't have a name */ + if (n_start[0] == 0) + return p; + } + + while (n_start) + { /* Has the end of NAME been reached? */ + n_end = strchr (n_start, '.'); /* search the next dot */ + if (n_end) + { + memcpy (n, n_start, n_end - n_start); + n[n_end - n_start] = 0; + n_start = n_end; + n_start++; + } + else + { + MHD__asn1_str_cpy (n, sizeof (n), n_start); + n_start = NULL; + } + + if (p->down == NULL) + return NULL; + + p = p->down; + + /* The identifier "?LAST" indicates the last element + in the right chain. */ + if (!strcmp (n, "?LAST")) + { + if (p == NULL) + return NULL; + while (p->right) + p = p->right; + } + else + { /* no "?LAST" */ + while (p) + { + if ((p->name) && (!strcmp (p->name, n))) + break; + else + p = p->right; + } + if (p == NULL) + return NULL; + } + } /* while */ + + return p; +} + + +/******************************************************************/ +/* Function : MHD__asn1_set_value */ +/* Description: sets the field VALUE in a NODE_ASN element. The */ +/* previous value (if exist) will be lost */ +/* Parameters: */ +/* node: element pointer. */ +/* value: pointer to the value that you want to set. */ +/* len: character number of value. */ +/* Return: pointer to the NODE_ASN element. */ +/******************************************************************/ +node_asn * +MHD__asn1_set_value (node_asn * node, const void *_value, unsigned int len) +{ + const unsigned char *value = _value; + + if (node == NULL) + return node; + if (node->value) + { + MHD__asn1_free (node->value); + node->value = NULL; + node->value_len = 0; + } + if (!len) + return node; + node->value = (unsigned char *) MHD__asn1_malloc (len); + if (node->value == NULL) + return NULL; + node->value_len = len; + + memcpy (node->value, value, len); + return node; +} + +/******************************************************************/ +/* Function : MHD__asn1_set_name */ +/* Description: sets the field NAME in a NODE_ASN element. The */ +/* previous value (if exist) will be lost */ +/* Parameters: */ +/* node: element pointer. */ +/* name: a null terminated string with the name that you want */ +/* to set. */ +/* Return: pointer to the NODE_ASN element. */ +/******************************************************************/ +node_asn * +MHD__asn1_set_name (node_asn * node, const char *name) +{ + if (node == NULL) + return node; + + if (node->name) + { + MHD__asn1_free (node->name); + node->name = NULL; + } + + if (name == NULL) + return node; + + if (strlen (name)) + { + node->name = (char *) MHD__asn1_strdup (name); + if (node->name == NULL) + return NULL; + } + else + node->name = NULL; + return node; +} + +/******************************************************************/ +/* Function : MHD__asn1_set_right */ +/* Description: sets the field RIGHT in a NODE_ASN element. */ +/* Parameters: */ +/* node: element pointer. */ +/* right: pointer to a NODE_ASN element that you want be pointed*/ +/* by NODE. */ +/* Return: pointer to *NODE. */ +/******************************************************************/ +node_asn * +MHD__asn1_set_right (node_asn * node, node_asn * right) +{ + if (node == NULL) + return node; + node->right = right; + if (right) + right->left = node; + return node; +} + +/******************************************************************/ +/* Function : MHD__asn1_set_down */ +/* Description: sets the field DOWN in a NODE_ASN element. */ +/* Parameters: */ +/* node: element pointer. */ +/* down: pointer to a NODE_ASN element that you want be pointed */ +/* by NODE. */ +/* Return: pointer to *NODE. */ +/******************************************************************/ +node_asn * +MHD__asn1_set_down (node_asn * node, node_asn * down) +{ + if (node == NULL) + return node; + node->down = down; + if (down) + down->left = node; + return node; +} + +/******************************************************************/ +/* Function : MHD__asn1_remove_node */ +/* Description: gets free the memory allocated for an NODE_ASN */ +/* element (not the elements pointed by it). */ +/* Parameters: */ +/* node: NODE_ASN element pointer. */ +/******************************************************************/ +void +MHD__asn1_remove_node (node_asn * node) +{ + if (node == NULL) + return; + + if (node->name != NULL) + MHD__asn1_free (node->name); + if (node->value != NULL) + MHD__asn1_free (node->value); + MHD__asn1_free (node); +} + +/******************************************************************/ +/* Function : MHD__asn1_find_up */ +/* Description: return the father of the NODE_ASN element. */ +/* Parameters: */ +/* node: NODE_ASN element pointer. */ +/* Return: Null if not found. */ +/******************************************************************/ +node_asn * +MHD__asn1_find_up (node_asn * node) +{ + node_asn *p; + + if (node == NULL) + return NULL; + + p = node; + + while ((p->left != NULL) && (p->left->right == p)) + p = p->left; + + return p->left; +} + +/******************************************************************/ +/* Function : MHD__asn1_delete_list */ +/* Description: deletes the list elements (not the elements */ +/* pointed by them). */ +/******************************************************************/ +void +MHD__asn1_delete_list (void) +{ + list_type *listElement; + + while (MHD_firstElement) + { + listElement = MHD_firstElement; + MHD_firstElement = MHD_firstElement->next; + MHD__asn1_free (listElement); + } +} + +/******************************************************************/ +/* Function : MHD__asn1_delete_list_and nodes */ +/* Description: deletes the list elements and the elements */ +/* pointed by them. */ +/******************************************************************/ +void +MHD__asn1_delete_list_and_nodes (void) +{ + list_type *listElement; + + while (MHD_firstElement) + { + listElement = MHD_firstElement; + MHD_firstElement = MHD_firstElement->next; + MHD__asn1_remove_node (listElement->node); + MHD__asn1_free (listElement); + } +} + + +char * +MHD__asn1_ltostr (long v, char *str) +{ + long d, r; + char temp[20]; + int count, k, start; + + if (v < 0) + { + str[0] = '-'; + start = 1; + v = -v; + } + else + start = 0; + + count = 0; + do + { + d = v / 10; + r = v - d * 10; + temp[start + count] = '0' + (char) r; + count++; + v = d; + } + while (v); + + for (k = 0; k < count; k++) + str[k + start] = temp[start + count - k - 1]; + str[count + start] = 0; + return str; +} + + +/******************************************************************/ +/* Function : MHD__asn1_change_integer_value */ +/* Description: converts into DER coding the value assign to an */ +/* INTEGER constant. */ +/* Parameters: */ +/* node: root of an ASN1element. */ +/* Return: */ +/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ +/* otherwise ASN1_SUCCESS */ +/******************************************************************/ +MHD__asn1_retCode +MHD__asn1_change_integer_value (ASN1_TYPE node) +{ + node_asn *p; + unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; + unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1]; + int len; + + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + p = node; + while (p) + { + if ((type_field (p->type) == TYPE_INTEGER) && (p->type & CONST_ASSIGN)) + { + if (p->value) + { + MHD__asn1_convert_integer ((const char *) p->value, val, + sizeof (val), &len); + MHD__asn1_octet_der (val, len, val2, &len); + MHD__asn1_set_value (p, val2, len); + } + } + + if (p->down) + { + p = p->down; + } + else + { + if (p == node) + p = NULL; + else if (p->right) + p = p->right; + else + { + while (1) + { + p = MHD__asn1_find_up (p); + if (p == node) + { + p = NULL; + break; + } + if (p->right) + { + p = p->right; + break; + } + } + } + } + } + + return ASN1_SUCCESS; +} + + +/******************************************************************/ +/* Function : MHD__asn1_expand_object_id */ +/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */ +/* Parameters: */ +/* node: root of an ASN1 element. */ +/* Return: */ +/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ +/* otherwise ASN1_SUCCESS */ +/******************************************************************/ +MHD__asn1_retCode +MHD__asn1_expand_object_id (ASN1_TYPE node) +{ + node_asn *p, *p2, *p3, *p4, *p5; + char name_root[MAX_NAME_SIZE], name2[2 * MAX_NAME_SIZE + 1]; + int move, tlen; + + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + MHD__asn1_str_cpy (name_root, sizeof (name_root), node->name); + + p = node; + move = DOWN; + + while (!((p == node) && (move == UP))) + { + if (move != UP) + { + if ((type_field (p->type) == TYPE_OBJECT_ID) + && (p->type & CONST_ASSIGN)) + { + p2 = p->down; + if (p2 && (type_field (p2->type) == TYPE_CONSTANT)) + { + if (p2->value && !isdigit (p2->value[0])) + { + MHD__asn1_str_cpy (name2, sizeof (name2), name_root); + MHD__asn1_str_cat (name2, sizeof (name2), "."); + MHD__asn1_str_cat (name2, sizeof (name2), + (const char *) p2->value); + p3 = MHD__asn1_find_node (node, name2); + if (!p3 || (type_field (p3->type) != TYPE_OBJECT_ID) || + !(p3->type & CONST_ASSIGN)) + return ASN1_ELEMENT_NOT_FOUND; + MHD__asn1_set_down (p, p2->right); + MHD__asn1_remove_node (p2); + p2 = p; + p4 = p3->down; + while (p4) + { + if (type_field (p4->type) == TYPE_CONSTANT) + { + p5 = MHD__asn1_add_node_only (TYPE_CONSTANT); + MHD__asn1_set_name (p5, p4->name); + tlen = strlen ((const char *) p4->value); + if (tlen > 0) + MHD__asn1_set_value (p5, p4->value, tlen + 1); + if (p2 == p) + { + MHD__asn1_set_right (p5, p->down); + MHD__asn1_set_down (p, p5); + } + else + { + MHD__asn1_set_right (p5, p2->right); + MHD__asn1_set_right (p2, p5); + } + p2 = p5; + } + p4 = p4->right; + } + move = DOWN; + continue; + } + } + } + move = DOWN; + } + else + move = RIGHT; + + if (move == DOWN) + { + if (p->down) + p = p->down; + else + move = RIGHT; + } + + if (p == node) + { + move = UP; + continue; + } + + if (move == RIGHT) + { + if (p->right) + p = p->right; + else + move = UP; + } + if (move == UP) + p = MHD__asn1_find_up (p); + } + + + /*******************************/ + /* expand DEFAULT */ + /*******************************/ + p = node; + move = DOWN; + + while (!((p == node) && (move == UP))) + { + if (move != UP) + { + if ((type_field (p->type) == TYPE_OBJECT_ID) && + (p->type & CONST_DEFAULT)) + { + p2 = p->down; + if (p2 && (type_field (p2->type) == TYPE_DEFAULT)) + { + MHD__asn1_str_cpy (name2, sizeof (name2), name_root); + MHD__asn1_str_cat (name2, sizeof (name2), "."); + MHD__asn1_str_cat (name2, sizeof (name2), + (const char *) p2->value); + p3 = MHD__asn1_find_node (node, name2); + if (!p3 || (type_field (p3->type) != TYPE_OBJECT_ID) || + !(p3->type & CONST_ASSIGN)) + return ASN1_ELEMENT_NOT_FOUND; + p4 = p3->down; + name2[0] = 0; + while (p4) + { + if (type_field (p4->type) == TYPE_CONSTANT) + { + if (name2[0]) + MHD__asn1_str_cat (name2, sizeof (name2), "."); + MHD__asn1_str_cat (name2, sizeof (name2), + (const char *) p4->value); + } + p4 = p4->right; + } + tlen = strlen (name2); + if (tlen > 0) + MHD__asn1_set_value (p2, name2, tlen + 1); + } + } + move = DOWN; + } + else + move = RIGHT; + + if (move == DOWN) + { + if (p->down) + p = p->down; + else + move = RIGHT; + } + + if (p == node) + { + move = UP; + continue; + } + + if (move == RIGHT) + { + if (p->right) + p = p->right; + else + move = UP; + } + if (move == UP) + p = MHD__asn1_find_up (p); + } + + return ASN1_SUCCESS; +} + +/******************************************************************/ +/* Function : MHD__asn1_check_identifier */ +/* Description: checks the definitions of all the identifiers */ +/* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */ +/* The MHD__asn1_identifierMissing global variable is filled if */ +/* necessary. */ +/* Parameters: */ +/* node: root of an ASN1 element. */ +/* Return: */ +/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ +/* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */ +/* otherwise ASN1_SUCCESS */ +/******************************************************************/ +MHD__asn1_retCode +MHD__asn1_check_identifier (ASN1_TYPE node) +{ + node_asn *p, *p2; + char name2[MAX_NAME_SIZE * 2 + 2]; + + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + p = node; + while (p) + { + if (type_field (p->type) == TYPE_IDENTIFIER) + { + MHD__asn1_str_cpy (name2, sizeof (name2), node->name); + MHD__asn1_str_cat (name2, sizeof (name2), "."); + MHD__asn1_str_cat (name2, sizeof (name2), (const char *) p->value); + p2 = MHD__asn1_find_node (node, name2); + if (p2 == NULL) + { + strcpy (MHD__asn1_identifierMissing, (const char *) p->value); + return ASN1_IDENTIFIER_NOT_FOUND; + } + } + else if ((type_field (p->type) == TYPE_OBJECT_ID) && + (p->type & CONST_DEFAULT)) + { + p2 = p->down; + if (p2 && (type_field (p2->type) == TYPE_DEFAULT)) + { + MHD__asn1_str_cpy (name2, sizeof (name2), node->name); + MHD__asn1_str_cat (name2, sizeof (name2), "."); + MHD__asn1_str_cat (name2, sizeof (name2), + (const char *) p2->value); + strcpy (MHD__asn1_identifierMissing, (const char *) p2->value); + p2 = MHD__asn1_find_node (node, name2); + if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) || + !(p2->type & CONST_ASSIGN)) + return ASN1_IDENTIFIER_NOT_FOUND; + else + MHD__asn1_identifierMissing[0] = 0; + } + } + else if ((type_field (p->type) == TYPE_OBJECT_ID) && + (p->type & CONST_ASSIGN)) + { + p2 = p->down; + if (p2 && (type_field (p2->type) == TYPE_CONSTANT)) + { + if (p2->value && !isdigit (p2->value[0])) + { + MHD__asn1_str_cpy (name2, sizeof (name2), node->name); + MHD__asn1_str_cat (name2, sizeof (name2), "."); + MHD__asn1_str_cat (name2, sizeof (name2), + (const char *) p2->value); + strcpy (MHD__asn1_identifierMissing, + (const char *) p2->value); + p2 = MHD__asn1_find_node (node, name2); + if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) || + !(p2->type & CONST_ASSIGN)) + return ASN1_IDENTIFIER_NOT_FOUND; + else + MHD__asn1_identifierMissing[0] = 0; + } + } + } + + if (p->down) + { + p = p->down; + } + else if (p->right) + p = p->right; + else + { + while (1) + { + p = MHD__asn1_find_up (p); + if (p == node) + { + p = NULL; + break; + } + if (p->right) + { + p = p->right; + break; + } + } + } + } + + return ASN1_SUCCESS; +} diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/parser_aux.h b/lib/libmicrohttpd/src/daemon/https/minitasn1/parser_aux.h new file mode 100644 index 0000000000..4437fb191e --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/parser_aux.h @@ -0,0 +1,37 @@ + +#ifndef _PARSER_AUX_H +#define _PARSER_AUX_H + + +/***************************************/ +/* Functions used by ASN.1 parser */ +/***************************************/ +node_asn *MHD__asn1_add_node (unsigned int type); + +node_asn *MHD__asn1_set_value (node_asn * node, const void *value, + unsigned int len); + +node_asn *MHD__asn1_set_name (node_asn * node, const char *name); + +node_asn *MHD__asn1_set_right (node_asn * node, node_asn * right); + +node_asn *MHD__asn1_set_down (node_asn * node, node_asn * down); + +void MHD__asn1_remove_node (node_asn * node); + +void MHD__asn1_delete_list (void); + +void MHD__asn1_delete_list_and_nodes (void); + +char *MHD__asn1_ltostr (long v, char *str); + +node_asn *MHD__asn1_find_up (node_asn * node); + +MHD__asn1_retCode MHD__asn1_change_integer_value (ASN1_TYPE node); + +MHD__asn1_retCode MHD__asn1_expand_object_id (ASN1_TYPE node); + +MHD__asn1_retCode MHD__asn1_check_identifier (ASN1_TYPE node); + + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/structure.c b/lib/libmicrohttpd/src/daemon/https/minitasn1/structure.c new file mode 100644 index 0000000000..fdaeea471b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/structure.c @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2004, 2006, 2007 Free Software Foundation + * Copyright (C) 2002 Fabio Fiorina + * + * This file is part of LIBTASN1. + * + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +/*****************************************************/ +/* File: structure.c */ +/* Description: Functions to create and delete an */ +/* ASN1 tree. */ +/*****************************************************/ + + +#include <int.h> +#include <structure.h> +#include "parser_aux.h" +#include <gstr.h> + + +extern char MHD__asn1_identifierMissing[]; + +static node_asn *MHD__asn1_copy_structure2 (node_asn * root, + const char *source_name); + + + +/******************************************************/ +/* Function : MHD__asn1_add_node_only */ +/* Description: creates a new NODE_ASN element. */ +/* Parameters: */ +/* type: type of the new element (see TYPE_ */ +/* and CONST_ constants). */ +/* Return: pointer to the new element. */ +/******************************************************/ +node_asn * +MHD__asn1_add_node_only (unsigned int type) +{ + node_asn *punt; + + punt = (node_asn *) MHD__asn1_calloc (1, sizeof (node_asn)); + if (punt == NULL) + return NULL; + + punt->type = type; + + return punt; +} + + +/******************************************************************/ +/* Function : MHD__asn1_find_left */ +/* Description: returns the NODE_ASN element with RIGHT field that*/ +/* points the element NODE. */ +/* Parameters: */ +/* node: NODE_ASN element pointer. */ +/* Return: NULL if not found. */ +/******************************************************************/ +node_asn * +MHD__asn1_find_left (node_asn * node) +{ + if ((node == NULL) || (node->left == NULL) || (node->left->down == node)) + return NULL; + + return node->left; +} + + + +/** + * MHD__asn1_array2tree - Creates the structures needed to manage the ASN1 definitions. + * @array: specify the array that contains ASN.1 declarations + * @definitions: return the pointer to the structure created by + * *ARRAY ASN.1 declarations + * @errorDescription: return the error description. + * + * Creates the structures needed to manage the ASN.1 definitions. + * @array is a vector created by MHD__asn1_parser2array(). + * + * Returns: + * + * ASN1_SUCCESS: Structure created correctly. + * + * ASN1_ELEMENT_NOT_EMPTY: *@definitions not ASN1_TYPE_EMPTY. + * + * ASN1_IDENTIFIER_NOT_FOUND: In the file there is an identifier that + * is not defined (see @errorDescription for more information). + * + * ASN1_ARRAY_ERROR: The array pointed by @array is wrong. + **/ +MHD__asn1_retCode +MHD__asn1_array2tree (const ASN1_ARRAY_TYPE * array, ASN1_TYPE * definitions, + char *errorDescription) +{ + node_asn *p, *p_last = NULL; + unsigned long k; + int move; + MHD__asn1_retCode result; + + + if (*definitions != ASN1_TYPE_EMPTY) + return ASN1_ELEMENT_NOT_EMPTY; + + move = UP; + + k = 0; + while (array[k].value || array[k].type || array[k].name) + { + p = MHD__asn1_add_node (array[k].type & (~CONST_DOWN)); + if (array[k].name) + MHD__asn1_set_name (p, array[k].name); + if (array[k].value) + MHD__asn1_set_value (p, array[k].value, strlen (array[k].value) + 1); + + if (*definitions == NULL) + *definitions = p; + + if (move == DOWN) + MHD__asn1_set_down (p_last, p); + else if (move == RIGHT) + MHD__asn1_set_right (p_last, p); + + p_last = p; + + if (array[k].type & CONST_DOWN) + move = DOWN; + else if (array[k].type & CONST_RIGHT) + move = RIGHT; + else + { + while (1) + { + if (p_last == *definitions) + break; + + p_last = MHD__asn1_find_up (p_last); + + if (p_last == NULL) + break; + + if (p_last->type & CONST_RIGHT) + { + p_last->type &= ~CONST_RIGHT; + move = RIGHT; + break; + } + } /* while */ + } + k++; + } /* while */ + + if (p_last == *definitions) + { + result = MHD__asn1_check_identifier (*definitions); + if (result == ASN1_SUCCESS) + { + MHD__asn1_change_integer_value (*definitions); + MHD__asn1_expand_object_id (*definitions); + } + } + else + { + result = ASN1_ARRAY_ERROR; + } + + if (errorDescription != NULL) + { + if (result == ASN1_IDENTIFIER_NOT_FOUND) + { + Estrcpy (errorDescription, ":: identifier '"); + Estrcat (errorDescription, MHD__asn1_identifierMissing); + Estrcat (errorDescription, "' not found"); + } + else + errorDescription[0] = 0; + } + + if (result != ASN1_SUCCESS) + { + MHD__asn1_delete_list_and_nodes (); + *definitions = ASN1_TYPE_EMPTY; + } + else + MHD__asn1_delete_list (); + + return result; +} + +/** + * MHD__asn1_delete_structure - Deletes the structure pointed by *ROOT. + * @structure: pointer to the structure that you want to delete. + * + * Deletes the structure *@structure. At the end, *@structure is set + * to ASN1_TYPE_EMPTY. + * + * Returns: + * + * ASN1_SUCCESS: Everything OK. + * + * ASN1_ELEMENT_NOT_FOUND: *@structure was ASN1_TYPE_EMPTY. + * + **/ +MHD__asn1_retCode +MHD__asn1_delete_structure (ASN1_TYPE * structure) +{ + node_asn *p, *p2, *p3; + + if (*structure == ASN1_TYPE_EMPTY) + return ASN1_ELEMENT_NOT_FOUND; + + p = *structure; + while (p) + { + if (p->down) + { + p = p->down; + } + else + { /* no down */ + p2 = p->right; + if (p != *structure) + { + p3 = MHD__asn1_find_up (p); + MHD__asn1_set_down (p3, p2); + MHD__asn1_remove_node (p); + p = p3; + } + else + { /* p==root */ + p3 = MHD__asn1_find_left (p); + if (!p3) + { + p3 = MHD__asn1_find_up (p); + if (p3) + MHD__asn1_set_down (p3, p2); + else + { + if (p->right) + p->right->left = NULL; + } + } + else + MHD__asn1_set_right (p3, p2); + MHD__asn1_remove_node (p); + p = NULL; + } + } + } + + *structure = ASN1_TYPE_EMPTY; + return ASN1_SUCCESS; +} + +node_asn * +MHD__asn1_copy_structure3 (node_asn * source_node) +{ + node_asn *dest_node, *p_s, *p_d, *p_d_prev; + int move; + + if (source_node == NULL) + return NULL; + + dest_node = MHD__asn1_add_node_only (source_node->type); + + p_s = source_node; + p_d = dest_node; + + move = DOWN; + + do + { + if (move != UP) + { + if (p_s->name) + MHD__asn1_set_name (p_d, p_s->name); + if (p_s->value) + MHD__asn1_set_value (p_d, p_s->value, p_s->value_len); + move = DOWN; + } + else + move = RIGHT; + + if (move == DOWN) + { + if (p_s->down) + { + p_s = p_s->down; + p_d_prev = p_d; + p_d = MHD__asn1_add_node_only (p_s->type); + MHD__asn1_set_down (p_d_prev, p_d); + } + else + move = RIGHT; + } + + if (p_s == source_node) + break; + + if (move == RIGHT) + { + if (p_s->right) + { + p_s = p_s->right; + p_d_prev = p_d; + p_d = MHD__asn1_add_node_only (p_s->type); + MHD__asn1_set_right (p_d_prev, p_d); + } + else + move = UP; + } + if (move == UP) + { + p_s = MHD__asn1_find_up (p_s); + p_d = MHD__asn1_find_up (p_d); + } + } + while (p_s != source_node); + + return dest_node; +} + + +static node_asn * +MHD__asn1_copy_structure2 (node_asn * root, const char *source_name) +{ + node_asn *source_node; + + source_node = MHD__asn1_find_node (root, source_name); + + return MHD__asn1_copy_structure3 (source_node); + +} + + +static MHD__asn1_retCode +MHD__asn1_type_choice_config (node_asn * node) +{ + node_asn *p, *p2, *p3, *p4; + int move, tlen; + + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + p = node; + move = DOWN; + + while (!((p == node) && (move == UP))) + { + if (move != UP) + { + if ((type_field (p->type) == TYPE_CHOICE) && (p->type & CONST_TAG)) + { + p2 = p->down; + while (p2) + { + if (type_field (p2->type) != TYPE_TAG) + { + p2->type |= CONST_TAG; + p3 = MHD__asn1_find_left (p2); + while (p3) + { + if (type_field (p3->type) == TYPE_TAG) + { + p4 = MHD__asn1_add_node_only (p3->type); + tlen = strlen ((const char *) p3->value); + if (tlen > 0) + MHD__asn1_set_value (p4, p3->value, tlen + 1); + MHD__asn1_set_right (p4, p2->down); + MHD__asn1_set_down (p2, p4); + } + p3 = MHD__asn1_find_left (p3); + } + } + p2 = p2->right; + } + p->type &= ~(CONST_TAG); + p2 = p->down; + while (p2) + { + p3 = p2->right; + if (type_field (p2->type) == TYPE_TAG) + MHD__asn1_delete_structure (&p2); + p2 = p3; + } + } + move = DOWN; + } + else + move = RIGHT; + + if (move == DOWN) + { + if (p->down) + p = p->down; + else + move = RIGHT; + } + + if (p == node) + { + move = UP; + continue; + } + + if (move == RIGHT) + { + if (p->right) + p = p->right; + else + move = UP; + } + if (move == UP) + p = MHD__asn1_find_up (p); + } + + return ASN1_SUCCESS; +} + + +static MHD__asn1_retCode +MHD__asn1_expand_identifier (node_asn ** node, node_asn * root) +{ + node_asn *p, *p2, *p3; + char name2[MAX_NAME_SIZE + 2]; + int move; + + if (node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + p = *node; + move = DOWN; + + while (!((p == *node) && (move == UP))) + { + if (move != UP) + { + if (type_field (p->type) == TYPE_IDENTIFIER) + { + MHD__asn1_str_cpy (name2, sizeof (name2), root->name); + MHD__asn1_str_cat (name2, sizeof (name2), "."); + MHD__asn1_str_cat (name2, sizeof (name2), + (const char *) p->value); + p2 = MHD__asn1_copy_structure2 (root, name2); + if (p2 == NULL) + { + return ASN1_IDENTIFIER_NOT_FOUND; + } + MHD__asn1_set_name (p2, p->name); + p2->right = p->right; + p2->left = p->left; + if (p->right) + p->right->left = p2; + p3 = p->down; + if (p3) + { + while (p3->right) + p3 = p3->right; + MHD__asn1_set_right (p3, p2->down); + MHD__asn1_set_down (p2, p->down); + } + + p3 = MHD__asn1_find_left (p); + if (p3) + MHD__asn1_set_right (p3, p2); + else + { + p3 = MHD__asn1_find_up (p); + if (p3) + MHD__asn1_set_down (p3, p2); + else + { + p2->left = NULL; + } + } + + if (p->type & CONST_SIZE) + p2->type |= CONST_SIZE; + if (p->type & CONST_TAG) + p2->type |= CONST_TAG; + if (p->type & CONST_OPTION) + p2->type |= CONST_OPTION; + if (p->type & CONST_DEFAULT) + p2->type |= CONST_DEFAULT; + if (p->type & CONST_SET) + p2->type |= CONST_SET; + if (p->type & CONST_NOT_USED) + p2->type |= CONST_NOT_USED; + + if (p == *node) + *node = p2; + MHD__asn1_remove_node (p); + p = p2; + move = DOWN; + continue; + } + move = DOWN; + } + else + move = RIGHT; + + if (move == DOWN) + { + if (p->down) + p = p->down; + else + move = RIGHT; + } + + if (p == *node) + { + move = UP; + continue; + } + + if (move == RIGHT) + { + if (p->right) + p = p->right; + else + move = UP; + } + if (move == UP) + p = MHD__asn1_find_up (p); + } + + return ASN1_SUCCESS; +} + + +/** + * MHD__asn1_create_element - Creates a structure of type SOURCE_NAME. + * @definitions: pointer to the structure returned by "parser_asn1" function + * @source_name: the name of the type of the new structure (must be + * inside p_structure). + * @element: pointer to the structure created. + * + * Creates a structure of type @source_name. Example using + * "pkix.asn": + * + * rc = MHD__asn1_create_structure(cert_def, "PKIX1.Certificate", + * certptr); + * + * Returns: + * + * ASN1_SUCCESS: Creation OK. + * + * ASN1_ELEMENT_NOT_FOUND: SOURCE_NAME isn't known + **/ +MHD__asn1_retCode +MHD__asn1_create_element (ASN1_TYPE definitions, const char *source_name, + ASN1_TYPE * element) +{ + node_asn *dest_node; + int res; + + dest_node = MHD__asn1_copy_structure2 (definitions, source_name); + + if (dest_node == NULL) + return ASN1_ELEMENT_NOT_FOUND; + + MHD__asn1_set_name (dest_node, ""); + + res = MHD__asn1_expand_identifier (&dest_node, definitions); + MHD__asn1_type_choice_config (dest_node); + + *element = dest_node; + + return res; +} diff --git a/lib/libmicrohttpd/src/daemon/https/minitasn1/structure.h b/lib/libmicrohttpd/src/daemon/https/minitasn1/structure.h new file mode 100644 index 0000000000..c447fc925b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/minitasn1/structure.h @@ -0,0 +1,18 @@ + +/*************************************************/ +/* File: structure.h */ +/* Description: list of exported object by */ +/* "structure.c" */ +/*************************************************/ + +#ifndef _STRUCTURE_H +#define _STRUCTURE_H + +node_asn *MHD__asn1_copy_structure3 (node_asn * source_node); + + +node_asn *MHD__asn1_add_node_only (unsigned int type); + +node_asn *MHD__asn1_find_left (node_asn * node); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/Makefile.am b/lib/libmicrohttpd/src/daemon/https/tls/Makefile.am new file mode 100644 index 0000000000..d6bb83074e --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/Makefile.am @@ -0,0 +1,100 @@ +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/include \ +-I$(top_srcdir)/src/daemon/ \ +-I$(top_srcdir)/src/daemon/https \ +-I$(top_srcdir)/src/daemon/https/tls \ +-I$(top_srcdir)/src/daemon/https/lgl \ +-I$(top_srcdir)/src/daemon/https/minitasn1 \ +-I$(top_srcdir)/src/daemon/https/x509 \ + @LIBGCRYPT_CFLAGS@ + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +noinst_LTLIBRARIES = libtls.la + +libtls_la_SOURCES = \ +auth_cert.c \ +auth_dhe.c \ +auth_dh_common.c \ +auth_rsa.c \ +auth_rsa_export.c \ +debug.c \ +defines.h \ +ext_cert_type.c \ +ext_max_record.c \ +ext_server_name.c \ +gnutls_alert.c \ +gnutls_algorithms.c \ +gnutls_asn1_tab.c \ +gnutls_auth.c \ +gnutls_buffers.c \ +gnutls_cert.c \ +gnutls_cipher.c \ +gnutls_cipher_int.c \ +gnutls_constate.c \ +gnutls_datum.c \ +gnutls_dh.c \ +gnutls_dh_primes.c \ +gnutls_errors.c \ +gnutls_extensions.c \ +gnutls_global.c \ +gnutls_handshake.c \ +gnutls_hash_int.c \ +gnutls_kx.c \ +gnutls_mem.c \ +gnutls_mpi.c \ +gnutls_num.c \ +gnutls_pk.c \ +gnutls_priority.c \ +gnutls_record.c \ +gnutls_rsa_export.c \ +gnutls_sig.c \ +gnutls_state.c \ +gnutls_str.c \ +gnutls_supplemental.c \ +gnutls_ui.c \ +gnutls_x509.c \ +pkix_asn1_tab.c \ +x509_b64.c \ +auth_cert.h \ +auth_dh_common.h \ +debug.h \ +defines.h \ +ext_cert_type.h \ +ext_max_record.h \ +ext_server_name.h \ +gnutls_algorithms.h \ +gnutls_auth.h \ +gnutls_auth_int.h \ +gnutls_buffers.h \ +gnutls_cert.h \ +gnutls_cipher.h \ +gnutls_cipher_int.h \ +gnutls_constate.h \ +gnutls_datum.h \ +gnutls_dh.h \ +gnutls_errors.h \ +gnutls_extensions.h \ +gnutls_global.h \ +gnutls_handshake.h \ +gnutls_hash_int.h \ +gnutls_int.h \ +gnutls_kx.h \ +gnutls_mem.h \ +gnutls_mpi.h \ +gnutls_num.h \ +gnutls_pk.h \ +gnutls_record.h \ +gnutls_rsa_export.h \ +gnutls_sig.h \ +gnutls_state.h \ +gnutls_str.h \ +gnutls_supplemental.h \ +gnutls_x509.h \ +x509_b64.h \ +memmem.c \ +str-two-way.h +libtls_la_LIBADD = @LIBGCRYPT_LIBS@ + diff --git a/lib/libmicrohttpd/src/daemon/https/tls/Makefile.in b/lib/libmicrohttpd/src/daemon/https/tls/Makefile.in new file mode 100644 index 0000000000..23c09ff54d --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/Makefile.in @@ -0,0 +1,635 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/daemon/https/tls +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libtls_la_DEPENDENCIES = +am_libtls_la_OBJECTS = auth_cert.lo auth_dhe.lo auth_dh_common.lo \ + auth_rsa.lo auth_rsa_export.lo debug.lo ext_cert_type.lo \ + ext_max_record.lo ext_server_name.lo gnutls_alert.lo \ + gnutls_algorithms.lo gnutls_asn1_tab.lo gnutls_auth.lo \ + gnutls_buffers.lo gnutls_cert.lo gnutls_cipher.lo \ + gnutls_cipher_int.lo gnutls_constate.lo gnutls_datum.lo \ + gnutls_dh.lo gnutls_dh_primes.lo gnutls_errors.lo \ + gnutls_extensions.lo gnutls_global.lo gnutls_handshake.lo \ + gnutls_hash_int.lo gnutls_kx.lo gnutls_mem.lo gnutls_mpi.lo \ + gnutls_num.lo gnutls_pk.lo gnutls_priority.lo gnutls_record.lo \ + gnutls_rsa_export.lo gnutls_sig.lo gnutls_state.lo \ + gnutls_str.lo gnutls_supplemental.lo gnutls_ui.lo \ + gnutls_x509.lo pkix_asn1_tab.lo x509_b64.lo memmem.lo +libtls_la_OBJECTS = $(am_libtls_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libtls_la_SOURCES) +DIST_SOURCES = $(libtls_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/include \ +-I$(top_srcdir)/src/daemon/ \ +-I$(top_srcdir)/src/daemon/https \ +-I$(top_srcdir)/src/daemon/https/tls \ +-I$(top_srcdir)/src/daemon/https/lgl \ +-I$(top_srcdir)/src/daemon/https/minitasn1 \ +-I$(top_srcdir)/src/daemon/https/x509 \ + @LIBGCRYPT_CFLAGS@ + +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +noinst_LTLIBRARIES = libtls.la +libtls_la_SOURCES = \ +auth_cert.c \ +auth_dhe.c \ +auth_dh_common.c \ +auth_rsa.c \ +auth_rsa_export.c \ +debug.c \ +defines.h \ +ext_cert_type.c \ +ext_max_record.c \ +ext_server_name.c \ +gnutls_alert.c \ +gnutls_algorithms.c \ +gnutls_asn1_tab.c \ +gnutls_auth.c \ +gnutls_buffers.c \ +gnutls_cert.c \ +gnutls_cipher.c \ +gnutls_cipher_int.c \ +gnutls_constate.c \ +gnutls_datum.c \ +gnutls_dh.c \ +gnutls_dh_primes.c \ +gnutls_errors.c \ +gnutls_extensions.c \ +gnutls_global.c \ +gnutls_handshake.c \ +gnutls_hash_int.c \ +gnutls_kx.c \ +gnutls_mem.c \ +gnutls_mpi.c \ +gnutls_num.c \ +gnutls_pk.c \ +gnutls_priority.c \ +gnutls_record.c \ +gnutls_rsa_export.c \ +gnutls_sig.c \ +gnutls_state.c \ +gnutls_str.c \ +gnutls_supplemental.c \ +gnutls_ui.c \ +gnutls_x509.c \ +pkix_asn1_tab.c \ +x509_b64.c \ +auth_cert.h \ +auth_dh_common.h \ +debug.h \ +defines.h \ +ext_cert_type.h \ +ext_max_record.h \ +ext_server_name.h \ +gnutls_algorithms.h \ +gnutls_auth.h \ +gnutls_auth_int.h \ +gnutls_buffers.h \ +gnutls_cert.h \ +gnutls_cipher.h \ +gnutls_cipher_int.h \ +gnutls_constate.h \ +gnutls_datum.h \ +gnutls_dh.h \ +gnutls_errors.h \ +gnutls_extensions.h \ +gnutls_global.h \ +gnutls_handshake.h \ +gnutls_hash_int.h \ +gnutls_int.h \ +gnutls_kx.h \ +gnutls_mem.h \ +gnutls_mpi.h \ +gnutls_num.h \ +gnutls_pk.h \ +gnutls_record.h \ +gnutls_rsa_export.h \ +gnutls_sig.h \ +gnutls_state.h \ +gnutls_str.h \ +gnutls_supplemental.h \ +gnutls_x509.h \ +x509_b64.h \ +memmem.c \ +str-two-way.h + +libtls_la_LIBADD = @LIBGCRYPT_LIBS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/daemon/https/tls/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/daemon/https/tls/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libtls.la: $(libtls_la_OBJECTS) $(libtls_la_DEPENDENCIES) + $(LINK) $(libtls_la_OBJECTS) $(libtls_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_cert.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_dh_common.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_dhe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_rsa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_rsa_export.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext_cert_type.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext_max_record.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext_server_name.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_alert.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_algorithms.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_asn1_tab.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_auth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_buffers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_cert.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_cipher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_cipher_int.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_constate.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_datum.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_dh.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_dh_primes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_errors.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_extensions.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_global.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_handshake.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_hash_int.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_kx.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_mem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_mpi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_num.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_pk.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_priority.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_record.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_rsa_export.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_sig.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_state.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_str.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_supplemental.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_ui.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnutls_x509.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memmem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkix_asn1_tab.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_b64.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/daemon/https/tls/auth_cert.c b/lib/libmicrohttpd/src/daemon/https/tls/auth_cert.c new file mode 100644 index 0000000000..f4a784b5e3 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/auth_cert.c @@ -0,0 +1,1329 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* The certificate authentication functions which are needed in the handshake, + * and are common to RSA and DHE key exchange, are in this file. + */ + +#include <gnutls_int.h> +#include "gnutls_auth_int.h" +#include "gnutls_errors.h" +#include <gnutls_cert.h> +#include <auth_cert.h> +#include "gnutls_dh.h" +#include "gnutls_num.h" +#include "libtasn1.h" +#include "gnutls_datum.h" +#include <gnutls_pk.h> +#include <gnutls_algorithms.h> +#include <gnutls_global.h> +#include <gnutls_record.h> +#include <gnutls_sig.h> +#include <gnutls_state.h> +#include <gnutls_pk.h> +#include <gnutls_x509.h> +#include "debug.h" + +static MHD_gnutls_cert *alloc_and_load_x509_certs (MHD_gnutls_x509_crt_t * + certs, unsigned); +static MHD_gnutls_privkey *alloc_and_load_x509_key (MHD_gnutls_x509_privkey_t + key); + + +/* Copies data from a internal certificate struct (MHD_gnutls_cert) to + * exported certificate struct (cert_auth_info_t) + */ +static int +MHD__gnutls_copy_certificate_auth_info (cert_auth_info_t info, + MHD_gnutls_cert * cert, int ncerts) +{ + /* Copy peer's information to auth_info_t + */ + int ret, i, j; + + if (ncerts == 0) + { + info->raw_certificate_list = NULL; + info->ncerts = 0; + return 0; + } + + info->raw_certificate_list = + MHD_gnutls_calloc (1, sizeof (MHD_gnutls_datum_t) * ncerts); + if (info->raw_certificate_list == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + for (i = 0; i < ncerts; i++) + { + if (cert->raw.size > 0) + { + ret = + MHD__gnutls_set_datum (&info->raw_certificate_list[i], + cert[i].raw.data, cert[i].raw.size); + if (ret < 0) + { + MHD_gnutls_assert (); + goto clear; + } + } + } + info->ncerts = ncerts; + + return 0; + +clear: + + for (j = 0; j < i; j++) + MHD__gnutls_free_datum (&info->raw_certificate_list[j]); + + MHD_gnutls_free (info->raw_certificate_list); + info->raw_certificate_list = NULL; + + return ret; +} + + + + +/* returns 0 if the algo_to-check exists in the pk_algos list, + * -1 otherwise. + */ +inline static int +MHD__gnutls_check_pk_algo_in_list (const enum MHD_GNUTLS_PublicKeyAlgorithm + *pk_algos, int pk_algos_length, + enum MHD_GNUTLS_PublicKeyAlgorithm + algo_to_check) +{ + int i; + for (i = 0; i < pk_algos_length; i++) + { + if (algo_to_check == pk_algos[i]) + { + return 0; + } + } + return -1; +} + + +/* Returns the issuer's Distinguished name in odn, of the certificate + * specified in cert. + */ +static int +MHD__gnutls_cert_get_issuer_dn (MHD_gnutls_cert * cert, + MHD_gnutls_datum_t * odn) +{ + ASN1_TYPE dn; + int len, result; + int start, end; + + if ((result = MHD__asn1_create_element + (MHD__gnutls_get_pkix (), "PKIX1.Certificate", &dn)) != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + result = MHD__asn1_der_decoding (&dn, cert->raw.data, cert->raw.size, NULL); + if (result != ASN1_SUCCESS) + { + /* couldn't decode DER */ + MHD_gnutls_assert (); + MHD__asn1_delete_structure (&dn); + return MHD_gtls_asn2err (result); + } + + result = + MHD__asn1_der_decoding_startEnd (dn, cert->raw.data, cert->raw.size, + "tbsCertificate.issuer", &start, &end); + + if (result != ASN1_SUCCESS) + { + /* couldn't decode DER */ + MHD_gnutls_assert (); + MHD__asn1_delete_structure (&dn); + return MHD_gtls_asn2err (result); + } + MHD__asn1_delete_structure (&dn); + + len = end - start + 1; + + odn->size = len; + odn->data = &cert->raw.data[start]; + + return 0; +} + + +/* Locates the most appropriate x509 certificate using the + * given DN. If indx == -1 then no certificate was found. + * + * That is to guess which certificate to use, based on the + * CAs and sign algorithms supported by the peer server. + */ +static int +_find_x509_cert (const MHD_gtls_cert_credentials_t cred, + opaque * _data, size_t _data_size, + const enum MHD_GNUTLS_PublicKeyAlgorithm *pk_algos, + int pk_algos_length, int *indx) +{ + unsigned size; + MHD_gnutls_datum_t odn; + opaque *data = _data; + ssize_t data_size = _data_size; + unsigned i, j; + int result, cert_pk; + + *indx = -1; + odn.size = 0; + odn.data = NULL; + do + { + + DECR_LENGTH_RET (data_size, 2, 0); + size = MHD_gtls_read_uint16 (data); + DECR_LENGTH_RET (data_size, size, 0); + data += 2; + + for (i = 0; i < cred->ncerts; i++) + { + for (j = 0; j < cred->cert_list_length[i]; j++) + { + if ((result = + MHD__gnutls_cert_get_issuer_dn (&cred->cert_list[i][j], + &odn)) != 0) + { + MHD_gnutls_assert (); + return result; + } + + if (odn.size != size) + continue; + + /* If the DN matches and + * the *_SIGN algorithm matches + * the cert is our cert! + */ + cert_pk = cred->cert_list[i][0].subject_pk_algorithm; + + if ((memcmp (odn.data, data, size) == 0) && + (MHD__gnutls_check_pk_algo_in_list + (pk_algos, pk_algos_length, cert_pk) == 0)) + { + *indx = i; + break; + } + } + if (*indx != -1) + break; + } + + if (*indx != -1) + break; + + /* move to next record */ + data += size; + + } + while (1); + + return 0; + +} + +/* Returns the number of issuers in the server's + * certificate request packet. + */ +static int +get_issuers_num (MHD_gtls_session_t session, opaque * data, ssize_t data_size) +{ + int issuers_dn_len = 0, result; + unsigned size; + + /* Count the number of the given issuers; + * This is used to allocate the issuers_dn without + * using realloc(). + */ + + if (data_size == 0 || data == NULL) + return 0; + + if (data_size > 0) + do + { + /* This works like DECR_LEN() + */ + result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + DECR_LENGTH_COM (data_size, 2, goto error); + size = MHD_gtls_read_uint16 (data); + + result = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + DECR_LENGTH_COM (data_size, size, goto error); + + data += 2; + + if (size > 0) + { + issuers_dn_len++; + data += size; + } + + if (data_size == 0) + break; + + } + while (1); + + return issuers_dn_len; + +error: + return result; +} + +/* Returns the issuers in the server's certificate request + * packet. + */ +static int +get_issuers (MHD_gtls_session_t session, + MHD_gnutls_datum_t * issuers_dn, int issuers_len, + opaque * data, size_t data_size) +{ + int i; + unsigned size; + + if (MHD_gnutls_certificate_type_get (session) != MHD_GNUTLS_CRT_X509) + return 0; + + /* put the requested DNs to req_dn, only in case + * of X509 certificates. + */ + if (issuers_len > 0) + { + + for (i = 0; i < issuers_len; i++) + { + /* The checks here for the buffer boundaries + * are not needed since the buffer has been + * parsed above. + */ + data_size -= 2; + + size = MHD_gtls_read_uint16 (data); + + data += 2; + + issuers_dn[i].data = data; + issuers_dn[i].size = size; + + data += size; + } + } + + return 0; +} + +/* Calls the client get callback. + */ +static int +call_get_cert_callback (MHD_gtls_session_t session, + MHD_gnutls_datum_t * issuers_dn, + int issuers_dn_length, + enum MHD_GNUTLS_PublicKeyAlgorithm *pk_algos, + int pk_algos_length) +{ + unsigned i; + MHD_gnutls_cert *local_certs = NULL; + MHD_gnutls_privkey *local_key = NULL; + MHD_gnutls_retr_st st; + int ret; + enum MHD_GNUTLS_CertificateType type = + MHD_gnutls_certificate_type_get (session); + MHD_gtls_cert_credentials_t cred; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + memset (&st, 0, sizeof (st)); + + if (session->security_parameters.entity == GNUTLS_SERVER) + { + ret = cred->server_get_cert_callback (session, &st); + } + else + { /* CLIENT */ + ret = + cred->client_get_cert_callback (session, + issuers_dn, issuers_dn_length, + pk_algos, pk_algos_length, &st); + } + + if (ret < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (st.ncerts == 0) + return 0; /* no certificate was selected */ + + if (type != st.type) + { + MHD_gnutls_assert (); + ret = GNUTLS_E_INVALID_REQUEST; + goto cleanup; + } + + if (type == MHD_GNUTLS_CRT_X509) + { + local_certs = alloc_and_load_x509_certs (st.cert.x509, st.ncerts); + if (local_certs != NULL) + local_key = alloc_and_load_x509_key (st.key.x509); + + } + else + { /* PGP */ + MHD_gnutls_assert (); + ret = GNUTLS_E_INVALID_REQUEST; + goto cleanup; + } + + MHD_gtls_selected_certs_set (session, local_certs, + (local_certs != NULL) ? st.ncerts : 0, + local_key, 1); + + ret = 0; + +cleanup: + + if (st.type == MHD_GNUTLS_CRT_X509) + { + if (st.deinit_all) + { + for (i = 0; i < st.ncerts; i++) + { + MHD_gnutls_x509_crt_deinit (st.cert.x509[i]); + } + MHD_gnutls_free (st.cert.x509); + MHD_gnutls_x509_privkey_deinit (st.key.x509); + } + } + return ret; +} + +/* Finds the appropriate certificate depending on the cA Distinguished name + * advertized by the server. If none matches then returns 0 and -1 as index. + * In case of an error a negative value, is returned. + * + * 20020128: added ability to select a certificate depending on the SIGN + * algorithm (only in automatic mode). + */ +static int +_select_client_cert (MHD_gtls_session_t session, + opaque * _data, size_t _data_size, + enum MHD_GNUTLS_PublicKeyAlgorithm *pk_algos, + int pk_algos_length) +{ + int result; + int indx = -1; + MHD_gtls_cert_credentials_t cred; + opaque *data = _data; + ssize_t data_size = _data_size; + int issuers_dn_length; + MHD_gnutls_datum_t *issuers_dn = NULL; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + if (cred->client_get_cert_callback != NULL) + { + + /* use a callback to get certificate + */ + if (session->security_parameters.cert_type != MHD_GNUTLS_CRT_X509) + issuers_dn_length = 0; + else + { + issuers_dn_length = get_issuers_num (session, data, data_size); + if (issuers_dn_length < 0) + { + MHD_gnutls_assert (); + return issuers_dn_length; + } + + if (issuers_dn_length > 0) + { + issuers_dn = + MHD_gnutls_malloc (sizeof (MHD_gnutls_datum_t) * + issuers_dn_length); + if (issuers_dn == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + result = + get_issuers (session, issuers_dn, issuers_dn_length, + data, data_size); + if (result < 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + } + } + + result = + call_get_cert_callback (session, issuers_dn, issuers_dn_length, + pk_algos, pk_algos_length); + goto cleanup; + + } + else + { + /* If we have no callbacks, try to guess. + */ + result = 0; + + if (session->security_parameters.cert_type == MHD_GNUTLS_CRT_X509) + result = + _find_x509_cert (cred, _data, _data_size, + pk_algos, pk_algos_length, &indx); + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + if (indx >= 0) + { + MHD_gtls_selected_certs_set (session, + &cred->cert_list[indx][0], + cred->cert_list_length[indx], + &cred->pkey[indx], 0); + } + else + { + MHD_gtls_selected_certs_set (session, NULL, 0, NULL, 0); + } + + result = 0; + } + +cleanup: + MHD_gnutls_free (issuers_dn); + return result; + +} + +/* Generate client certificate + */ +static int +MHD_gtls_gen_x509_crt (MHD_gtls_session_t session, opaque ** data) +{ + int ret, i; + opaque *pdata; + MHD_gnutls_cert *apr_cert_list; + MHD_gnutls_privkey *apr_pkey; + int apr_cert_list_length; + + /* find the appropriate certificate + */ + if ((ret = + MHD_gtls_get_selected_cert (session, &apr_cert_list, + &apr_cert_list_length, &apr_pkey)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = 3; + for (i = 0; i < apr_cert_list_length; i++) + { + ret += apr_cert_list[i].raw.size + 3; + /* hold size + * for uint24 */ + } + + /* if no certificates were found then send: + * 0B 00 00 03 00 00 00 // Certificate with no certs + * instead of: + * 0B 00 00 00 // empty certificate handshake + * + * ( the above is the whole handshake message, not + * the one produced here ) + */ + + (*data) = MHD_gnutls_malloc (ret); + pdata = (*data); + + if (pdata == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + MHD_gtls_write_uint24 (ret - 3, pdata); + pdata += 3; + for (i = 0; i < apr_cert_list_length; i++) + { + MHD_gtls_write_datum24 (pdata, apr_cert_list[i].raw); + pdata += (3 + apr_cert_list[i].raw.size); + } + + return ret; +} + +int +MHD_gtls_gen_cert_client_certificate (MHD_gtls_session_t session, + opaque ** data) +{ + switch (session->security_parameters.cert_type) + { + case MHD_GNUTLS_CRT_X509: + return MHD_gtls_gen_x509_crt (session, data); + + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } +} + +int +MHD_gtls_gen_cert_server_certificate (MHD_gtls_session_t session, + opaque ** data) +{ + switch (session->security_parameters.cert_type) + { + case MHD_GNUTLS_CRT_X509: + return MHD_gtls_gen_x509_crt (session, data); + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } +} + +/* Process server certificate + */ + +#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) MHD_gtls_gcert_deinit(&peer_certificate_list[x]) +static int +MHD_gtls_proc_x509_server_certificate (MHD_gtls_session_t session, + opaque * data, size_t data_size) +{ + int size, len, ret; + opaque *p = data; + cert_auth_info_t info; + MHD_gtls_cert_credentials_t cred; + ssize_t dsize = data_size; + int i, j, x; + MHD_gnutls_cert *peer_certificate_list; + int peer_certificate_list_size = 0; + MHD_gnutls_datum_t tmp; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + + if ((ret = + MHD_gtls_auth_info_set (session, MHD_GNUTLS_CRD_CERTIFICATE, + sizeof (cert_auth_info_st), 1)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + info = MHD_gtls_get_auth_info (session); + + if (data == NULL || data_size == 0) + { + MHD_gnutls_assert (); + /* no certificate was sent */ + return GNUTLS_E_NO_CERTIFICATE_FOUND; + } + + DECR_LEN (dsize, 3); + size = MHD_gtls_read_uint24 (p); + p += 3; + + /* some implementations send 0B 00 00 06 00 00 03 00 00 00 + * instead of just 0B 00 00 03 00 00 00 as an empty certificate message. + */ + if (size == 0 || size == 3) + { + MHD_gnutls_assert (); + /* no certificate was sent */ + return GNUTLS_E_NO_CERTIFICATE_FOUND; + } + + i = dsize; + while (i > 0) + { + DECR_LEN (dsize, 3); + len = MHD_gtls_read_uint24 (p); + p += 3; + DECR_LEN (dsize, len); + peer_certificate_list_size++; + p += len; + i -= len + 3; + } + + if (peer_certificate_list_size == 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_NO_CERTIFICATE_FOUND; + } + + /* Ok we now allocate the memory to hold the + * certificate list + */ + + peer_certificate_list = + MHD_gnutls_malloc (sizeof (MHD_gnutls_cert) * + (peer_certificate_list_size)); + + if (peer_certificate_list == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + memset (peer_certificate_list, 0, sizeof (MHD_gnutls_cert) * + peer_certificate_list_size); + + p = data + 3; + + /* Now we start parsing the list (again). + * We don't use DECR_LEN since the list has + * been parsed before. + */ + + for (j = 0; j < peer_certificate_list_size; j++) + { + len = MHD_gtls_read_uint24 (p); + p += 3; + + tmp.size = len; + tmp.data = p; + + if ((ret = + MHD_gtls_x509_raw_cert_to_gcert (&peer_certificate_list + [j], &tmp, + CERT_ONLY_EXTENSIONS)) < 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + + p += len; + } + + + if ((ret = + MHD__gnutls_copy_certificate_auth_info (info, + peer_certificate_list, + peer_certificate_list_size)) < + 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + + if ((ret = + MHD__gnutls_check_key_usage (&peer_certificate_list[0], + MHD_gnutls_kx_get (session))) < 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + + ret = 0; + +cleanup: + CLEAR_CERTS; + MHD_gnutls_free (peer_certificate_list); + return ret; + +} + +#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) MHD_gtls_gcert_deinit(&peer_certificate_list[x]) + +int +MHD_gtls_proc_cert_server_certificate (MHD_gtls_session_t session, + opaque * data, size_t data_size) +{ + switch (session->security_parameters.cert_type) + { + case MHD_GNUTLS_CRT_X509: + return MHD_gtls_proc_x509_server_certificate (session, data, data_size); + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } +} + +#define MAX_SIGN_ALGOS 2 +typedef enum CertificateSigType +{ RSA_SIGN = 1, DSA_SIGN +} CertificateSigType; + +/* Checks if we support the given signature algorithm + * (RSA or DSA). Returns the corresponding enum MHD_GNUTLS_PublicKeyAlgorithm + * if true; + */ +inline static int +MHD__gnutls_check_supported_sign_algo (CertificateSigType algo) +{ + switch (algo) + { + case RSA_SIGN: + return MHD_GNUTLS_PK_RSA; + default: + return -1; + } +} + +int +MHD_gtls_proc_cert_cert_req (MHD_gtls_session_t session, opaque * data, + size_t data_size) +{ + int size, ret; + opaque *p; + MHD_gtls_cert_credentials_t cred; + ssize_t dsize; + int i, j; + enum MHD_GNUTLS_PublicKeyAlgorithm pk_algos[MAX_SIGN_ALGOS]; + int pk_algos_length; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + if ((ret = + MHD_gtls_auth_info_set (session, MHD_GNUTLS_CRD_CERTIFICATE, + sizeof (cert_auth_info_st), 0)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + p = data; + dsize = data_size; + + DECR_LEN (dsize, 1); + size = p[0]; + p++; + /* check if the sign algorithm is supported. + */ + pk_algos_length = j = 0; + for (i = 0; i < size; i++, p++) + { + DECR_LEN (dsize, 1); + if ((ret = MHD__gnutls_check_supported_sign_algo (*p)) > 0) + { + if (j < MAX_SIGN_ALGOS) + { + pk_algos[j++] = ret; + pk_algos_length++; + } + } + } + + if (pk_algos_length == 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_PK_ALGORITHM; + } + + if (ver == MHD_GNUTLS_PROTOCOL_TLS1_2) + { + /* read supported hashes */ + int hash_num; + DECR_LEN (dsize, 1); + + hash_num = p[0] & 0xFF; + p++; + + DECR_LEN (dsize, hash_num); + p += hash_num; + } + + /* read the certificate authorities */ + DECR_LEN (dsize, 2); + size = MHD_gtls_read_uint16 (p); + p += 2; + + DECR_LEN (dsize, size); + + /* now we ask the user to tell which one + * he wants to use. + */ + if ((ret = + _select_client_cert (session, p, size, pk_algos, pk_algos_length)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* We should reply with a certificate message, + * even if we have no certificate to send. + */ + session->key->certificate_requested = 1; + + return 0; +} + +int +MHD_gtls_gen_cert_client_cert_vrfy (MHD_gtls_session_t session, + opaque ** data) +{ + int ret; + MHD_gnutls_cert *apr_cert_list; + MHD_gnutls_privkey *apr_pkey; + int apr_cert_list_length, size; + MHD_gnutls_datum_t signature; + + *data = NULL; + + /* find the appropriate certificate */ + if ((ret = + MHD_gtls_get_selected_cert (session, &apr_cert_list, + &apr_cert_list_length, &apr_pkey)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if (apr_cert_list_length > 0) + { + if ((ret = + MHD_gtls_tls_sign_hdata (session, + &apr_cert_list[0], + apr_pkey, &signature)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + else + { + return 0; + } + + *data = MHD_gnutls_malloc (signature.size + 2); + if (*data == NULL) + { + MHD__gnutls_free_datum (&signature); + return GNUTLS_E_MEMORY_ERROR; + } + size = signature.size; + MHD_gtls_write_uint16 (size, *data); + + memcpy (&(*data)[2], signature.data, size); + + MHD__gnutls_free_datum (&signature); + + return size + 2; +} + +int +MHD_gtls_proc_cert_client_cert_vrfy (MHD_gtls_session_t session, + opaque * data, size_t data_size) +{ + int size, ret; + ssize_t dsize = data_size; + opaque *pdata = data; + MHD_gnutls_datum_t sig; + cert_auth_info_t info = MHD_gtls_get_auth_info (session); + MHD_gnutls_cert peer_cert; + + if (info == NULL || info->ncerts == 0) + { + MHD_gnutls_assert (); + /* we need this in order to get peer's certificate */ + return GNUTLS_E_INTERNAL_ERROR; + } + + DECR_LEN (dsize, 2); + size = MHD_gtls_read_uint16 (pdata); + pdata += 2; + + DECR_LEN (dsize, size); + + sig.data = pdata; + sig.size = size; + + ret = MHD_gtls_raw_cert_to_gcert (&peer_cert, + session->security_parameters.cert_type, + &info->raw_certificate_list[0], + CERT_NO_COPY); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if ((ret = MHD_gtls_verify_sig_hdata (session, &peer_cert, &sig)) < 0) + { + MHD_gnutls_assert (); + MHD_gtls_gcert_deinit (&peer_cert); + return ret; + } + MHD_gtls_gcert_deinit (&peer_cert); + + return 0; +} + +#define CERTTYPE_SIZE 3 +int +MHD_gtls_gen_cert_server_cert_req (MHD_gtls_session_t session, opaque ** data) +{ + MHD_gtls_cert_credentials_t cred; + int size; + opaque *pdata; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + /* Now we need to generate the RDN sequence. This is + * already in the CERTIFICATE_CRED structure, to improve + * performance. + */ + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + size = CERTTYPE_SIZE + 2; /* 2 for enum MHD_GNUTLS_CertificateType + 2 for size of rdn_seq + */ + + if (session->security_parameters.cert_type == MHD_GNUTLS_CRT_X509 && + session->internals.ignore_rdn_sequence == 0) + size += cred->x509_rdn_sequence.size; + + if (ver == MHD_GNUTLS_PROTOCOL_TLS1_2) + /* Need at least one byte to announce the number of supported hash + functions (see below). */ + size += 1; + + (*data) = MHD_gnutls_malloc (size); + pdata = (*data); + + if (pdata == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + pdata[0] = CERTTYPE_SIZE - 1; + + pdata[1] = RSA_SIGN; + pdata[2] = DSA_SIGN; /* only these for now */ + pdata += CERTTYPE_SIZE; + + if (ver == MHD_GNUTLS_PROTOCOL_TLS1_2) + { + /* Supported hashes (nothing for now -- FIXME). */ + *pdata = 0; + pdata++; + } + + if (session->security_parameters.cert_type == MHD_GNUTLS_CRT_X509 && + session->internals.ignore_rdn_sequence == 0) + { + MHD_gtls_write_datum16 (pdata, cred->x509_rdn_sequence); + /* pdata += cred->x509_rdn_sequence.size + 2; */ + } + else + { + MHD_gtls_write_uint16 (0, pdata); + /* pdata+=2; */ + } + + return size; +} + + +/* This function will return the appropriate certificate to use. + * Fills in the apr_cert_list, apr_cert_list_length and apr_pkey. + * The return value is a negative value on error. + * + * It is normal to return 0 with no certificates in client side. + * + */ +int +MHD_gtls_get_selected_cert (MHD_gtls_session_t session, + MHD_gnutls_cert ** apr_cert_list, + int *apr_cert_list_length, + MHD_gnutls_privkey ** apr_pkey) +{ + if (session->security_parameters.entity == GNUTLS_SERVER) + { + + /* select_client_cert() has been called before. + */ + + *apr_cert_list = session->internals.selected_cert_list; + *apr_pkey = session->internals.selected_key; + *apr_cert_list_length = session->internals.selected_cert_list_length; + + if (*apr_cert_list_length == 0 || *apr_cert_list == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + } + else + { /* CLIENT SIDE + */ + + /* we have already decided which certificate + * to send. + */ + *apr_cert_list = session->internals.selected_cert_list; + *apr_cert_list_length = session->internals.selected_cert_list_length; + *apr_pkey = session->internals.selected_key; + + } + + return 0; +} + +/* converts the given x509 certificate to MHD_gnutls_cert* and allocates + * space for them. + */ +static MHD_gnutls_cert * +alloc_and_load_x509_certs (MHD_gnutls_x509_crt_t * certs, unsigned ncerts) +{ + MHD_gnutls_cert *local_certs; + int ret = 0; + unsigned i, j; + + if (certs == NULL) + return NULL; + + local_certs = MHD_gnutls_malloc (sizeof (MHD_gnutls_cert) * ncerts); + if (local_certs == NULL) + { + MHD_gnutls_assert (); + return NULL; + } + + for (i = 0; i < ncerts; i++) + { + ret = MHD_gtls_x509_crt_to_gcert (&local_certs[i], certs[i], 0); + if (ret < 0) + break; + } + + if (ret < 0) + { + MHD_gnutls_assert (); + for (j = 0; j < i; j++) + { + MHD_gtls_gcert_deinit (&local_certs[j]); + } + MHD_gnutls_free (local_certs); + return NULL; + } + + return local_certs; +} + +/* converts the given x509 key to MHD_gnutls_privkey* and allocates + * space for it. + */ +static MHD_gnutls_privkey * +alloc_and_load_x509_key (MHD_gnutls_x509_privkey_t key) +{ + MHD_gnutls_privkey *local_key; + int ret = 0; + + if (key == NULL) + return NULL; + + local_key = MHD_gnutls_malloc (sizeof (MHD_gnutls_privkey)); + if (local_key == NULL) + { + MHD_gnutls_assert (); + return NULL; + } + + ret = MHD__gnutls_x509_privkey_to_gkey (local_key, key); + if (ret < 0) + { + MHD_gnutls_assert (); + return NULL; + } + + return local_key; +} + +void +MHD_gtls_selected_certs_deinit (MHD_gtls_session_t session) +{ + if (session->internals.selected_need_free != 0) + { + int i; + + for (i = 0; i < session->internals.selected_cert_list_length; i++) + { + MHD_gtls_gcert_deinit (&session->internals.selected_cert_list[i]); + } + MHD_gnutls_free (session->internals.selected_cert_list); + session->internals.selected_cert_list = NULL; + session->internals.selected_cert_list_length = 0; + + MHD_gtls_gkey_deinit (session->internals.selected_key); + if (session->internals.selected_key) + { + MHD_gnutls_free (session->internals.selected_key); + session->internals.selected_key = NULL; + } + } + + return; +} + +void +MHD_gtls_selected_certs_set (MHD_gtls_session_t session, + MHD_gnutls_cert * certs, int ncerts, + MHD_gnutls_privkey * key, int need_free) +{ + MHD_gtls_selected_certs_deinit (session); + + session->internals.selected_cert_list = certs; + session->internals.selected_cert_list_length = ncerts; + session->internals.selected_key = key; + session->internals.selected_need_free = need_free; + +} + + +/* finds the most appropriate certificate in the cert list. + * The 'appropriate' is defined by the user. + * + * requested_algo holds the parameters required by the peer (RSA, DSA + * or -1 for any). + * + * Returns 0 on success and a negative value on error. The + * selected certificate will be in session->internals.selected_*. + * + */ +int +MHD_gtls_server_select_cert (MHD_gtls_session_t session, + enum MHD_GNUTLS_PublicKeyAlgorithm + requested_algo) +{ + unsigned i; + int idx, ret; + MHD_gtls_cert_credentials_t cred; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + /* If the callback which retrieves certificate has been set, + * use it and leave. + */ + if (cred->server_get_cert_callback != NULL) + return call_get_cert_callback (session, NULL, 0, NULL, 0); + + /* Otherwise... */ + + ret = 0; + idx = -1; /* default is use no certificate */ + + + for (i = 0; i < cred->ncerts; i++) + { + /* find one compatible certificate + */ + if (requested_algo == GNUTLS_PK_ANY || + requested_algo == cred->cert_list[i][0].subject_pk_algorithm) + { + /* if cert type matches + */ + if (session->security_parameters.cert_type == + cred->cert_list[i][0].cert_type) + { + idx = i; + break; + } + } + } + + /* store the certificate pointer for future use, in the handshake. + * (This will allow not calling this callback again.) + */ + if (idx >= 0 && ret == 0) + { + MHD_gtls_selected_certs_set (session, + &cred->cert_list[idx][0], + cred->cert_list_length[idx], + &cred->pkey[idx], 0); + } + else + /* Certificate does not support REQUESTED_ALGO. */ + ret = GNUTLS_E_INSUFFICIENT_CREDENTIALS; + + return ret; +} + +/* Frees the MHD_gtls_rsa_info_st structure. + */ +void +MHD_gtls_free_rsa_info (rsa_info_st * rsa) +{ + MHD__gnutls_free_datum (&rsa->modulus); + MHD__gnutls_free_datum (&rsa->exponent); +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/auth_cert.h b/lib/libmicrohttpd/src/daemon/https/tls/auth_cert.h new file mode 100644 index 0000000000..395fdd29fc --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/auth_cert.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef AUTH_CERT_H +#define AUTH_CERT_H + +#include "gnutls_cert.h" +#include "gnutls_auth.h" +#include "auth_dh_common.h" +#include "x509.h" + +/* This structure may be complex, but it's the only way to + * support a server that has multiple certificates + */ + +typedef struct MHD_gtls_certificate_credentials_st +{ + MHD_gtls_dh_params_t dh_params; + MHD_gtls_rsa_params_t rsa_params; + /* this callback is used to retrieve the DH or RSA + * parameters. + */ + MHD_gnutls_params_function *params_func; + + MHD_gnutls_cert **cert_list; + /* contains a list of a list of certificates. + * eg (X509): [0] certificate1, certificate11, certificate111 + * (if more than one, one certificate certifies the one before) + * [1] certificate2, certificate22, ... + */ + unsigned *cert_list_length; + /* contains the number of the certificates in a + * row (should be 1 for OpenPGP keys). + */ + unsigned ncerts; /* contains the number of columns in cert_list. + * This is the same with the number of pkeys. + */ + + MHD_gnutls_privkey *pkey; + /* private keys. It contains ncerts private + * keys. pkey[i] corresponds to certificate in + * cert_list[i][0]. + */ + + /* OpenPGP specific stuff */ + +#ifndef KEYRING_HACK + MHD_gnutls_openpgp_keyring_t keyring; +#else + MHD_gnutls_datum_t keyring; + int keyring_format; +#endif + + /* X509 specific stuff */ + + MHD_gnutls_x509_crt_t *x509_ca_list; + unsigned x509_ncas; /* number of CAs in the ca_list + */ + + MHD_gnutls_x509_crl_t *x509_crl_list; + unsigned x509_ncrls; /* number of CRLs in the crl_list + */ + + unsigned int verify_flags; /* flags to be used at + * certificate verification. + */ + unsigned int verify_depth; + unsigned int verify_bits; + + /* holds a sequence of the + * RDNs of the CAs above. + * This is better than + * generating on every handshake. + */ + MHD_gnutls_datum_t x509_rdn_sequence; + + MHD_gnutls_certificate_client_retrieve_function *client_get_cert_callback; + MHD_gnutls_certificate_server_retrieve_function *server_get_cert_callback; +} MHD_gtls_cert_credentials_st; + +typedef struct MHD_gtls_rsa_info_st +{ + MHD_gnutls_datum_t modulus; + MHD_gnutls_datum_t exponent; +} rsa_info_st; + +typedef struct MHD_gtls_cert_auth_info_st +{ + int certificate_requested; /* if the peer requested certificate + * this is non zero; + */ + + /* These (dh/rsa) are just copies from the credentials_t structure. + * They must be freed. + */ + MHD_gtls_dh_info_st dh; + rsa_info_st rsa_export; + + MHD_gnutls_datum_t *raw_certificate_list; /* holds the raw certificate of the + * peer. + */ + unsigned int ncerts; /* holds the size of the list above */ +} *cert_auth_info_t; + +typedef struct MHD_gtls_cert_auth_info_st cert_auth_info_st; + +void MHD_gtls_free_rsa_info (rsa_info_st * rsa); + +/* AUTH X509 functions */ +int MHD_gtls_gen_cert_server_certificate (MHD_gtls_session_t, opaque **); +int MHD_gtls_gen_cert_client_certificate (MHD_gtls_session_t, opaque **); +int MHD_gtls_gen_cert_client_cert_vrfy (MHD_gtls_session_t, opaque **); +int MHD_gtls_gen_cert_server_cert_req (MHD_gtls_session_t, opaque **); +int MHD_gtls_proc_cert_cert_req (MHD_gtls_session_t, opaque *, size_t); +int MHD_gtls_proc_cert_client_cert_vrfy (MHD_gtls_session_t, opaque *, + size_t); +int MHD_gtls_proc_cert_server_certificate (MHD_gtls_session_t, opaque *, + size_t); +int MHD_gtls_get_selected_cert (MHD_gtls_session_t session, + MHD_gnutls_cert ** apr_cert_list, + int *apr_cert_list_length, + MHD_gnutls_privkey ** apr_pkey); + +int MHD_gtls_server_select_cert (struct MHD_gtls_session_int *, + enum MHD_GNUTLS_PublicKeyAlgorithm); +void MHD_gtls_selected_certs_deinit (MHD_gtls_session_t session); +void MHD_gtls_selected_certs_set (MHD_gtls_session_t session, + MHD_gnutls_cert * certs, int ncerts, + MHD_gnutls_privkey * key, int need_free); + +#define MHD__gnutls_proc_cert_client_certificate MHD_gtls_proc_cert_server_certificate + +MHD_gtls_rsa_params_t +MHD_gtls_certificate_get_rsa_params (MHD_gtls_rsa_params_t rsa_params, + MHD_gnutls_params_function * func, + MHD_gtls_session_t); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/auth_dh_common.c b/lib/libmicrohttpd/src/daemon/https/tls/auth_dh_common.c new file mode 100644 index 0000000000..8fc6e3914a --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/auth_dh_common.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains common stuff in Ephemeral Diffie Hellman (DHE) and + * Anonymous DH key exchange(DHA). These are used in the handshake procedure + * of the certificate and anoymous authentication. + */ + +#include "gnutls_int.h" +#include "gnutls_auth_int.h" +#include "gnutls_errors.h" +#include "gnutls_dh.h" +#include "gnutls_num.h" +#include "gnutls_sig.h" +#include <gnutls_datum.h> +#include <gnutls_x509.h> +#include <gnutls_state.h> +#include <auth_dh_common.h> +#include <gnutls_algorithms.h> + +/* Frees the MHD_gtls_dh_info_st structure. + */ +void +MHD_gtls_free_dh_info (MHD_gtls_dh_info_st * dh) +{ + dh->secret_bits = 0; + MHD__gnutls_free_datum (&dh->prime); + MHD__gnutls_free_datum (&dh->generator); + MHD__gnutls_free_datum (&dh->public_key); +} + +int +MHD_gtls_proc_dh_common_client_kx (MHD_gtls_session_t session, + opaque * data, size_t _data_size, + mpi_t g, mpi_t p) +{ + uint16_t n_Y; + size_t _n_Y; + int ret; + ssize_t data_size = _data_size; + + + DECR_LEN (data_size, 2); + n_Y = MHD_gtls_read_uint16 (&data[0]); + _n_Y = n_Y; + + DECR_LEN (data_size, n_Y); + if (MHD_gtls_mpi_scan_nz (&session->key->client_Y, &data[2], &_n_Y)) + { + MHD_gnutls_assert (); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + MHD_gtls_dh_set_peer_public (session, session->key->client_Y); + + session->key->KEY = + MHD_gtls_calc_dh_key (session->key->client_Y, session->key->dh_secret, p); + + if (session->key->KEY == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD_gtls_mpi_release (&session->key->client_Y); + MHD_gtls_mpi_release (&session->key->dh_secret); + + ret = MHD_gtls_mpi_dprint (&session->key->key, session->key->KEY); + + MHD_gtls_mpi_release (&session->key->KEY); + + if (ret < 0) + { + return ret; + } + + return 0; +} + +int +MHD_gtls_gen_dh_common_client_kx (MHD_gtls_session_t session, opaque ** data) +{ + mpi_t x = NULL, X = NULL; + size_t n_X; + int ret; + + *data = NULL; + + X = MHD_gtls_calc_dh_secret (&x, session->key->client_g, + session->key->client_p); + if (X == NULL || x == NULL) + { + MHD_gnutls_assert (); + ret = GNUTLS_E_MEMORY_ERROR; + goto error; + } + + MHD_gtls_dh_set_secret_bits (session, MHD__gnutls_mpi_get_nbits (x)); + + MHD_gtls_mpi_print (NULL, &n_X, X); + (*data) = MHD_gnutls_malloc (n_X + 2); + if (*data == NULL) + { + ret = GNUTLS_E_MEMORY_ERROR; + goto error; + } + + MHD_gtls_mpi_print (&(*data)[2], &n_X, X); + MHD_gtls_mpi_release (&X); + + MHD_gtls_write_uint16 (n_X, &(*data)[0]); + + /* calculate the key after calculating the message */ + session->key->KEY = + MHD_gtls_calc_dh_key (session->key->client_Y, x, session->key->client_p); + + MHD_gtls_mpi_release (&x); + if (session->key->KEY == NULL) + { + MHD_gnutls_assert (); + ret = GNUTLS_E_MEMORY_ERROR; + goto error; + } + + /* THESE SHOULD BE DISCARDED */ + MHD_gtls_mpi_release (&session->key->client_Y); + MHD_gtls_mpi_release (&session->key->client_p); + MHD_gtls_mpi_release (&session->key->client_g); + + ret = MHD_gtls_mpi_dprint (&session->key->key, session->key->KEY); + + MHD_gtls_mpi_release (&session->key->KEY); + + if (ret < 0) + { + MHD_gnutls_assert (); + goto error; + } + + return n_X + 2; + +error: + MHD_gtls_mpi_release (&x); + MHD_gtls_mpi_release (&X); + MHD_gnutls_free (*data); + *data = NULL; + return ret; +} + +int +MHD_gtls_proc_dh_common_server_kx (MHD_gtls_session_t session, + opaque * data, size_t _data_size, int psk) +{ + uint16_t n_Y, n_g, n_p; + size_t _n_Y, _n_g, _n_p; + uint8_t *data_p; + uint8_t *data_g; + uint8_t *data_Y; + int i, bits, psk_size, ret; + ssize_t data_size = _data_size; + + i = 0; + + if (psk != 0) + { + DECR_LEN (data_size, 2); + psk_size = MHD_gtls_read_uint16 (&data[i]); + DECR_LEN (data_size, psk_size); + i += 2 + psk_size; + } + + DECR_LEN (data_size, 2); + n_p = MHD_gtls_read_uint16 (&data[i]); + i += 2; + + DECR_LEN (data_size, n_p); + data_p = &data[i]; + i += n_p; + + DECR_LEN (data_size, 2); + n_g = MHD_gtls_read_uint16 (&data[i]); + i += 2; + + DECR_LEN (data_size, n_g); + data_g = &data[i]; + i += n_g; + + DECR_LEN (data_size, 2); + n_Y = MHD_gtls_read_uint16 (&data[i]); + i += 2; + + DECR_LEN (data_size, n_Y); + data_Y = &data[i]; + i += n_Y; + + _n_Y = n_Y; + _n_g = n_g; + _n_p = n_p; + + if (MHD_gtls_mpi_scan_nz (&session->key->client_Y, data_Y, &_n_Y) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + if (MHD_gtls_mpi_scan_nz (&session->key->client_g, data_g, &_n_g) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MPI_SCAN_FAILED; + } + if (MHD_gtls_mpi_scan_nz (&session->key->client_p, data_p, &_n_p) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + bits = MHD_gtls_dh_get_allowed_prime_bits (session); + if (bits < 0) + { + MHD_gnutls_assert (); + return bits; + } + + if (MHD__gnutls_mpi_get_nbits (session->key->client_p) < (size_t) bits) + { + /* the prime used by the peer is not acceptable + */ + MHD_gnutls_assert (); + return GNUTLS_E_DH_PRIME_UNACCEPTABLE; + } + + MHD_gtls_dh_set_group (session, session->key->client_g, + session->key->client_p); + MHD_gtls_dh_set_peer_public (session, session->key->client_Y); + + ret = n_Y + n_p + n_g + 6; + if (psk != 0) + ret += 2; + + return ret; +} + +/* If the psk flag is set, then an empty psk_identity_hint will + * be inserted */ +int +MHD_gtls_dh_common_print_server_kx (MHD_gtls_session_t session, + mpi_t g, mpi_t p, opaque ** data, int psk) +{ + mpi_t x, X; + size_t n_X, n_g, n_p; + int ret, data_size, pos; + uint8_t *pdata; + + X = MHD_gtls_calc_dh_secret (&x, g, p); + if (X == NULL || x == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + session->key->dh_secret = x; + MHD_gtls_dh_set_secret_bits (session, MHD__gnutls_mpi_get_nbits (x)); + + MHD_gtls_mpi_print (NULL, &n_g, g); + MHD_gtls_mpi_print (NULL, &n_p, p); + MHD_gtls_mpi_print (NULL, &n_X, X); + + data_size = n_g + n_p + n_X + 6; + if (psk != 0) + data_size += 2; + + (*data) = MHD_gnutls_malloc (data_size); + if (*data == NULL) + { + MHD_gtls_mpi_release (&X); + return GNUTLS_E_MEMORY_ERROR; + } + + pos = 0; + pdata = *data; + + if (psk != 0) + { + MHD_gtls_write_uint16 (0, &pdata[pos]); + pos += 2; + } + + MHD_gtls_mpi_print (&pdata[pos + 2], &n_p, p); + MHD_gtls_write_uint16 (n_p, &pdata[pos]); + + pos += n_p + 2; + + MHD_gtls_mpi_print (&pdata[pos + 2], &n_g, g); + MHD_gtls_write_uint16 (n_g, &pdata[pos]); + + pos += n_g + 2; + + MHD_gtls_mpi_print (&pdata[pos + 2], &n_X, X); + MHD_gtls_mpi_release (&X); + + MHD_gtls_write_uint16 (n_X, &pdata[pos]); + + ret = data_size; + + return ret; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/auth_dh_common.h b/lib/libmicrohttpd/src/daemon/https/tls/auth_dh_common.h new file mode 100644 index 0000000000..f09ce6dc4b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/auth_dh_common.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef AUTH_DH_COMMON +# define AUTH_DH_COMMON + +typedef struct +{ + int secret_bits; + + MHD_gnutls_datum_t prime; + MHD_gnutls_datum_t generator; + MHD_gnutls_datum_t public_key; +} MHD_gtls_dh_info_st; + +void MHD_gtls_free_dh_info (MHD_gtls_dh_info_st * dh); +int MHD_gtls_gen_dh_common_client_kx (MHD_gtls_session_t, opaque **); +int MHD_gtls_proc_dh_common_client_kx (MHD_gtls_session_t session, + opaque * data, size_t _data_size, + mpi_t p, mpi_t g); +int MHD_gtls_dh_common_print_server_kx (MHD_gtls_session_t, mpi_t g, mpi_t p, + opaque ** data, int psk); +int MHD_gtls_proc_dh_common_server_kx (MHD_gtls_session_t session, + opaque * data, size_t _data_size, + int psk); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/auth_dhe.c b/lib/libmicrohttpd/src/daemon/https/tls/auth_dhe.c new file mode 100644 index 0000000000..38407f9dc2 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/auth_dhe.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains everything for the Ephemeral Diffie Hellman (DHE) + * key exchange. This is used in the handshake procedure of the certificate + * authentication. + */ + +#include "gnutls_int.h" +#include "gnutls_auth_int.h" +#include "gnutls_errors.h" +#include "gnutls_dh.h" +#include "gnutls_num.h" +#include "gnutls_sig.h" +#include <gnutls_datum.h> +#include <auth_cert.h> +#include <gnutls_x509.h> +#include <gnutls_state.h> +#include <auth_dh_common.h> + +static int gen_dhe_server_kx (MHD_gtls_session_t, opaque **); +static int proc_dhe_server_kx (MHD_gtls_session_t, opaque *, size_t); +static int proc_dhe_client_kx (MHD_gtls_session_t, opaque *, size_t); + +const MHD_gtls_mod_auth_st MHD_gtls_dhe_rsa_auth_struct = { + "DHE_RSA", + MHD_gtls_gen_cert_server_certificate, + MHD_gtls_gen_cert_client_certificate, + gen_dhe_server_kx, + MHD_gtls_gen_dh_common_client_kx, + MHD_gtls_gen_cert_client_cert_vrfy, /* gen client cert vrfy */ + MHD_gtls_gen_cert_server_cert_req, /* server cert request */ + + MHD_gtls_proc_cert_server_certificate, + MHD__gnutls_proc_cert_client_certificate, + proc_dhe_server_kx, + proc_dhe_client_kx, + MHD_gtls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */ + MHD_gtls_proc_cert_cert_req /* proc server cert request */ +}; + +const MHD_gtls_mod_auth_st MHD_gtls_dhe_dss_auth_struct = { + "DHE_DSS", + MHD_gtls_gen_cert_server_certificate, + MHD_gtls_gen_cert_client_certificate, + gen_dhe_server_kx, + MHD_gtls_gen_dh_common_client_kx, + MHD_gtls_gen_cert_client_cert_vrfy, /* gen client cert vrfy */ + MHD_gtls_gen_cert_server_cert_req, /* server cert request */ + + MHD_gtls_proc_cert_server_certificate, + MHD__gnutls_proc_cert_client_certificate, + proc_dhe_server_kx, + proc_dhe_client_kx, + MHD_gtls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */ + MHD_gtls_proc_cert_cert_req /* proc server cert request */ +}; + + +static int +gen_dhe_server_kx (MHD_gtls_session_t session, opaque ** data) +{ + mpi_t g, p; + const mpi_t *mpis; + int ret = 0, data_size; + MHD_gnutls_cert *apr_cert_list; + MHD_gnutls_privkey *apr_pkey; + int apr_cert_list_length; + MHD_gnutls_datum_t signature, ddata; + MHD_gtls_cert_credentials_t cred; + MHD_gtls_dh_params_t dh_params; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + /* find the appropriate certificate */ + if ((ret = + MHD_gtls_get_selected_cert (session, &apr_cert_list, + &apr_cert_list_length, &apr_pkey)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + dh_params = + MHD_gtls_get_dh_params (cred->dh_params, cred->params_func, session); + mpis = MHD_gtls_dh_params_to_mpi (dh_params); + if (mpis == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_NO_TEMPORARY_DH_PARAMS; + } + + p = mpis[0]; + g = mpis[1]; + + if ((ret = MHD_gtls_auth_info_set (session, MHD_GNUTLS_CRD_CERTIFICATE, + sizeof (cert_auth_info_st), 0)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD_gtls_dh_set_group (session, g, p); + + ret = MHD_gtls_dh_common_print_server_kx (session, g, p, data, 0); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + data_size = ret; + + /* Generate the signature. */ + + ddata.data = *data; + ddata.size = data_size; + + if (apr_cert_list_length > 0) + { + if ((ret = + MHD_gtls_tls_sign_params (session, &apr_cert_list[0], + apr_pkey, &ddata, &signature)) < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (*data); + return ret; + } + } + else + { + MHD_gnutls_assert (); + return data_size; /* do not put a signature - ILLEGAL! */ + } + + *data = MHD_gtls_realloc_fast (*data, data_size + signature.size + 2); + if (*data == NULL) + { + MHD__gnutls_free_datum (&signature); + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD_gtls_write_datum16 (&(*data)[data_size], signature); + data_size += signature.size + 2; + + MHD__gnutls_free_datum (&signature); + + return data_size; +} + +static int +proc_dhe_server_kx (MHD_gtls_session_t session, opaque * data, + size_t _data_size) +{ + int sigsize; + MHD_gnutls_datum_t vparams, signature; + int ret; + cert_auth_info_t info = MHD_gtls_get_auth_info (session); + ssize_t data_size = _data_size; + MHD_gnutls_cert peer_cert; + + if (info == NULL || info->ncerts == 0) + { + MHD_gnutls_assert (); + /* we need this in order to get peer's certificate */ + return GNUTLS_E_INTERNAL_ERROR; + } + + ret = MHD_gtls_proc_dh_common_server_kx (session, data, _data_size, 0); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* VERIFY SIGNATURE */ + + vparams.size = ret; + vparams.data = data; + + DECR_LEN (data_size, 2); + sigsize = MHD_gtls_read_uint16 (&data[vparams.size]); + + DECR_LEN (data_size, sigsize); + signature.data = &data[vparams.size + 2]; + signature.size = sigsize; + + if ((ret = + MHD_gtls_raw_cert_to_gcert (&peer_cert, + session->security_parameters.cert_type, + &info->raw_certificate_list[0], + CERT_NO_COPY)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = + MHD_gtls_verify_sig_params (session, &peer_cert, &vparams, &signature); + + MHD_gtls_gcert_deinit (&peer_cert); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return ret; +} + + + +static int +proc_dhe_client_kx (MHD_gtls_session_t session, opaque * data, + size_t _data_size) +{ + MHD_gtls_cert_credentials_t cred; + int ret; + mpi_t p, g; + const mpi_t *mpis; + MHD_gtls_dh_params_t dh_params; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + dh_params = + MHD_gtls_get_dh_params (cred->dh_params, cred->params_func, session); + mpis = MHD_gtls_dh_params_to_mpi (dh_params); + if (mpis == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_NO_TEMPORARY_DH_PARAMS; + } + + p = mpis[0]; + g = mpis[1]; + + ret = MHD_gtls_proc_dh_common_client_kx (session, data, _data_size, g, p); + + return ret; + +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/auth_rsa.c b/lib/libmicrohttpd/src/daemon/https/tls/auth_rsa.c new file mode 100644 index 0000000000..9548a8f17b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/auth_rsa.c @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the RSA key exchange part of the certificate + * authentication. + */ + +#include "gnutls_int.h" +#include "gnutls_auth_int.h" +#include "gnutls_errors.h" +#include "gnutls_dh.h" +#include "gnutls_num.h" +#include "gnutls_datum.h" +#include "auth_cert.h" +#include <gnutls_pk.h> +#include <gnutls_algorithms.h> +#include <gnutls_global.h> +#include "debug.h" +#include <gnutls_sig.h> +#include <gnutls_x509.h> +#include <gc.h> + +int MHD__gnutls_gen_rsa_client_kx (MHD_gtls_session_t, opaque **); +int MHD__gnutls_proc_rsa_client_kx (MHD_gtls_session_t, opaque *, size_t); + +const MHD_gtls_mod_auth_st MHD_gtls_rsa_auth_struct = { + "RSA", + MHD_gtls_gen_cert_server_certificate, + MHD_gtls_gen_cert_client_certificate, + NULL, /* gen server kx */ + MHD__gnutls_gen_rsa_client_kx, + MHD_gtls_gen_cert_client_cert_vrfy, /* gen client cert vrfy */ + MHD_gtls_gen_cert_server_cert_req, /* server cert request */ + + MHD_gtls_proc_cert_server_certificate, + MHD__gnutls_proc_cert_client_certificate, + NULL, /* proc server kx */ + MHD__gnutls_proc_rsa_client_kx, /* proc client kx */ + MHD_gtls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */ + MHD_gtls_proc_cert_cert_req /* proc server cert request */ +}; + +/* This function reads the RSA parameters from peer's certificate; + */ +int +MHD__gnutls_get_public_rsa_params (MHD_gtls_session_t session, + mpi_t params[MAX_PUBLIC_PARAMS_SIZE], + int *params_len) +{ + int ret; + cert_auth_info_t info; + MHD_gnutls_cert peer_cert; + int i; + + /* normal non export case */ + + info = MHD_gtls_get_auth_info (session); + + if (info == NULL || info->ncerts == 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + ret = + MHD_gtls_raw_cert_to_gcert (&peer_cert, + session->security_parameters.cert_type, + &info->raw_certificate_list[0], + CERT_ONLY_PUBKEY | CERT_NO_COPY); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + + /* EXPORT case: */ + if (MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters.current_cipher_suite) + == MHD_GNUTLS_KX_RSA_EXPORT + && MHD__gnutls_mpi_get_nbits (peer_cert.params[0]) > 512) + { + + MHD_gtls_gcert_deinit (&peer_cert); + + if (session->key->rsa[0] == NULL || session->key->rsa[1] == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (*params_len < 2) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + *params_len = 2; + for (i = 0; i < *params_len; i++) + { + params[i] = MHD__gnutls_mpi_copy (session->key->rsa[i]); + } + + return 0; + } + + /* end of export case */ + + if (*params_len < peer_cert.params_size) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + *params_len = peer_cert.params_size; + + for (i = 0; i < *params_len; i++) + { + params[i] = MHD__gnutls_mpi_copy (peer_cert.params[i]); + } + MHD_gtls_gcert_deinit (&peer_cert); + + return 0; +} + +/* This function reads the RSA parameters from the private key + */ +int +MHD__gnutls_get_private_rsa_params (MHD_gtls_session_t session, + mpi_t ** params, int *params_size) +{ + int bits; + MHD_gtls_cert_credentials_t cred; + MHD_gtls_rsa_params_t rsa_params; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + if (session->internals.selected_cert_list == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + bits = + MHD__gnutls_mpi_get_nbits (session->internals.selected_cert_list[0]. + params[0]); + + if (MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters.current_cipher_suite) + == MHD_GNUTLS_KX_RSA_EXPORT && bits > 512) + { + + rsa_params = + MHD_gtls_certificate_get_rsa_params (cred->rsa_params, + cred->params_func, session); + /* EXPORT case: */ + if (rsa_params == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS; + } + + /* In the export case, we do use temporary RSA params + * of 512 bits size. The params in the certificate are + * used to sign this temporary stuff. + */ + *params_size = RSA_PRIVATE_PARAMS; + *params = rsa_params->params; + + return 0; + } + + /* non export cipher suites. */ + + *params_size = session->internals.selected_key->params_size; + *params = session->internals.selected_key->params; + + return 0; +} + +int +MHD__gnutls_proc_rsa_client_kx (MHD_gtls_session_t session, opaque * data, + size_t _data_size) +{ + MHD_gnutls_datum_t plaintext; + MHD_gnutls_datum_t ciphertext; + int ret, dsize; + mpi_t *params; + int params_len; + int randomize_key = 0; + ssize_t data_size = _data_size; + + if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3) + { + /* SSL 3.0 + */ + ciphertext.data = data; + ciphertext.size = data_size; + } + else + { + /* TLS 1.0 + */ + DECR_LEN (data_size, 2); + ciphertext.data = &data[2]; + dsize = MHD_gtls_read_uint16 (data); + + if (dsize != data_size) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + ciphertext.size = dsize; + } + + ret = MHD__gnutls_get_private_rsa_params (session, ¶ms, ¶ms_len); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = MHD_gtls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, params_len, 2); /* btype==2 */ + + if (ret < 0 || plaintext.size != TLS_MASTER_SIZE) + { + /* In case decryption fails then don't inform + * the peer. Just use a random key. (in order to avoid + * attack against pkcs-1 formating). + */ + MHD_gnutls_assert (); + MHD__gnutls_x509_log ("auth_rsa: Possible PKCS #1 format attack\n"); + randomize_key = 1; + } + else + { + /* If the secret was properly formatted, then + * check the version number. + */ + if (MHD__gnutls_get_adv_version_major (session) != plaintext.data[0] + || MHD__gnutls_get_adv_version_minor (session) != plaintext.data[1]) + { + /* No error is returned here, if the version number check + * fails. We proceed normally. + * That is to defend against the attack described in the paper + * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima, + * Ondej Pokorny and Tomas Rosa. + */ + MHD_gnutls_assert (); + MHD__gnutls_x509_log + ("auth_rsa: Possible PKCS #1 version check format attack\n"); + } + } + + if (randomize_key != 0) + { + session->key->key.size = TLS_MASTER_SIZE; + session->key->key.data = MHD_gnutls_malloc (session->key->key.size); + if (session->key->key.data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + /* we do not need strong random numbers here. + */ + if (MHD_gc_nonce + ((char *) session->key->key.data, session->key->key.size) != GC_OK) + { + MHD_gnutls_assert (); + return GNUTLS_E_RANDOM_FAILED; + } + + } + else + { + session->key->key.data = plaintext.data; + session->key->key.size = plaintext.size; + } + + /* This is here to avoid the version check attack + * discussed above. + */ + session->key->key.data[0] = MHD__gnutls_get_adv_version_major (session); + session->key->key.data[1] = MHD__gnutls_get_adv_version_minor (session); + + return 0; +} + + + +/* return RSA(random) using the peers public key + */ +int +MHD__gnutls_gen_rsa_client_kx (MHD_gtls_session_t session, opaque ** data) +{ + cert_auth_info_t auth; + MHD_gnutls_datum_t sdata; /* data to send */ + mpi_t params[MAX_PUBLIC_PARAMS_SIZE]; + int params_len = MAX_PUBLIC_PARAMS_SIZE; + int ret, i; + enum MHD_GNUTLS_Protocol ver; + + if (session->key == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + auth = session->key->auth_info; + if (auth == NULL) + { + /* this shouldn't have happened. The proc_certificate + * function should have detected that. + */ + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + session->key->key.size = TLS_MASTER_SIZE; + session->key->key.data = MHD_gnutls_secure_malloc (session->key->key.size); + + if (session->key->key.data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + if (MHD_gc_pseudo_random ((char *) session->key->key.data, + session->key->key.size) != GC_OK) + { + MHD_gnutls_assert (); + return GNUTLS_E_RANDOM_FAILED; + } + + ver = MHD_gtls_get_adv_version (session); + + if (session->internals.rsa_pms_version[0] == 0) + { + session->key->key.data[0] = MHD_gtls_version_get_major (ver); + session->key->key.data[1] = MHD_gtls_version_get_minor (ver); + } + else + { /* use the version provided */ + session->key->key.data[0] = session->internals.rsa_pms_version[0]; + session->key->key.data[1] = session->internals.rsa_pms_version[1]; + } + + /* move RSA parameters to key (session). + */ + if ((ret = + MHD__gnutls_get_public_rsa_params (session, params, ¶ms_len)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if ((ret = + MHD_gtls_pkcs1_rsa_encrypt (&sdata, &session->key->key, + params, params_len, 2)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + for (i = 0; i < params_len; i++) + MHD_gtls_mpi_release (¶ms[i]); + + if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3) + { + /* SSL 3.0 */ + *data = sdata.data; + return sdata.size; + } + else + { /* TLS 1 */ + *data = MHD_gnutls_malloc (sdata.size + 2); + if (*data == NULL) + { + MHD__gnutls_free_datum (&sdata); + return GNUTLS_E_MEMORY_ERROR; + } + MHD_gtls_write_datum16 (*data, sdata); + ret = sdata.size + 2; + MHD__gnutls_free_datum (&sdata); + return ret; + } + +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/auth_rsa_export.c b/lib/libmicrohttpd/src/daemon/https/tls/auth_rsa_export.c new file mode 100644 index 0000000000..575a2b72e1 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/auth_rsa_export.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the RSA key exchange part of the certificate + * authentication. + */ + +#include "gnutls_int.h" +#include "gnutls_auth_int.h" +#include "gnutls_errors.h" +#include "gnutls_dh.h" +#include "gnutls_num.h" +#include "gnutls_datum.h" +#include "auth_cert.h" +#include <gnutls_pk.h> +#include <gnutls_algorithms.h> +#include <gnutls_global.h> +#include "debug.h" +#include <gnutls_sig.h> +#include <gnutls_x509.h> +#include <gnutls_rsa_export.h> +#include <gnutls_state.h> + +int MHD__gnutls_gen_rsa_client_kx (MHD_gtls_session_t, opaque **); +int MHD__gnutls_proc_rsa_client_kx (MHD_gtls_session_t, opaque *, size_t); +static int gen_rsa_export_server_kx (MHD_gtls_session_t, opaque **); +static int proc_rsa_export_server_kx (MHD_gtls_session_t, opaque *, size_t); + +const MHD_gtls_mod_auth_st MHD_rsa_export_auth_struct = { + "RSA EXPORT", + MHD_gtls_gen_cert_server_certificate, + MHD_gtls_gen_cert_client_certificate, + gen_rsa_export_server_kx, + MHD__gnutls_gen_rsa_client_kx, + MHD_gtls_gen_cert_client_cert_vrfy, /* gen client cert vrfy */ + MHD_gtls_gen_cert_server_cert_req, /* server cert request */ + + MHD_gtls_proc_cert_server_certificate, + MHD__gnutls_proc_cert_client_certificate, + proc_rsa_export_server_kx, + MHD__gnutls_proc_rsa_client_kx, /* proc client kx */ + MHD_gtls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */ + MHD_gtls_proc_cert_cert_req /* proc server cert request */ +}; + +static int +gen_rsa_export_server_kx (MHD_gtls_session_t session, opaque ** data) +{ + MHD_gtls_rsa_params_t rsa_params; + const mpi_t *rsa_mpis; + size_t n_e, n_m; + uint8_t *data_e, *data_m; + int ret = 0, data_size; + MHD_gnutls_cert *apr_cert_list; + MHD_gnutls_privkey *apr_pkey; + int apr_cert_list_length; + MHD_gnutls_datum_t signature, ddata; + MHD_gtls_cert_credentials_t cred; + + cred = (MHD_gtls_cert_credentials_t) + MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL); + if (cred == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + /* find the appropriate certificate */ + if ((ret = + MHD_gtls_get_selected_cert (session, &apr_cert_list, + &apr_cert_list_length, &apr_pkey)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* abort sending this message if we have a certificate + * of 512 bits or less. + */ + if (apr_pkey && MHD__gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512) + { + MHD_gnutls_assert (); + return GNUTLS_E_INT_RET_0; + } + + rsa_params = + MHD_gtls_certificate_get_rsa_params (cred->rsa_params, cred->params_func, + session); + rsa_mpis = MHD__gnutls_rsa_params_to_mpi (rsa_params); + if (rsa_mpis == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS; + } + + if ((ret = MHD_gtls_auth_info_set (session, MHD_GNUTLS_CRD_CERTIFICATE, + sizeof (cert_auth_info_st), 0)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD_gtls_rsa_export_set_pubkey (session, rsa_mpis[1], rsa_mpis[0]); + + MHD_gtls_mpi_print (NULL, &n_m, rsa_mpis[0]); + MHD_gtls_mpi_print (NULL, &n_e, rsa_mpis[1]); + + (*data) = MHD_gnutls_malloc (n_e + n_m + 4); + if (*data == NULL) + { + return GNUTLS_E_MEMORY_ERROR; + } + + data_m = &(*data)[0]; + MHD_gtls_mpi_print (&data_m[2], &n_m, rsa_mpis[0]); + + MHD_gtls_write_uint16 (n_m, data_m); + + data_e = &data_m[2 + n_m]; + MHD_gtls_mpi_print (&data_e[2], &n_e, rsa_mpis[1]); + + MHD_gtls_write_uint16 (n_e, data_e); + + data_size = n_m + n_e + 4; + + + /* Generate the signature. */ + + ddata.data = *data; + ddata.size = data_size; + + if (apr_cert_list_length > 0) + { + if ((ret = + MHD_gtls_tls_sign_params (session, &apr_cert_list[0], + apr_pkey, &ddata, &signature)) < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (*data); + *data = NULL; + return ret; + } + } + else + { + MHD_gnutls_assert (); + return data_size; /* do not put a signature - ILLEGAL! */ + } + + *data = MHD_gtls_realloc_fast (*data, data_size + signature.size + 2); + if (*data == NULL) + { + MHD__gnutls_free_datum (&signature); + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD_gtls_write_datum16 (&((*data)[data_size]), signature); + data_size += signature.size + 2; + + MHD__gnutls_free_datum (&signature); + + return data_size; +} + +/* if the peer's certificate is of 512 bits or less, returns non zero. + */ +int +MHD__gnutls_peers_cert_less_512 (MHD_gtls_session_t session) +{ + MHD_gnutls_cert peer_cert; + int ret; + cert_auth_info_t info = MHD_gtls_get_auth_info (session); + + if (info == NULL || info->ncerts == 0) + { + MHD_gnutls_assert (); + /* we need this in order to get peer's certificate */ + return 0; + } + + if ((ret = + MHD_gtls_raw_cert_to_gcert (&peer_cert, + session->security_parameters.cert_type, + &info->raw_certificate_list[0], + CERT_NO_COPY)) < 0) + { + MHD_gnutls_assert (); + return 0; + } + + if (peer_cert.subject_pk_algorithm != MHD_GNUTLS_PK_RSA) + { + MHD_gnutls_assert (); + MHD_gtls_gcert_deinit (&peer_cert); + return 0; + } + + if (MHD__gnutls_mpi_get_nbits (peer_cert.params[0]) <= 512) + { + MHD_gtls_gcert_deinit (&peer_cert); + return 1; + } + + MHD_gtls_gcert_deinit (&peer_cert); + + return 0; +} + +static int +proc_rsa_export_server_kx (MHD_gtls_session_t session, + opaque * data, size_t _data_size) +{ + uint16_t n_m, n_e; + size_t _n_m, _n_e; + uint8_t *data_m; + uint8_t *data_e; + int i, sigsize; + MHD_gnutls_datum_t vparams, signature; + int ret; + ssize_t data_size = _data_size; + cert_auth_info_t info; + MHD_gnutls_cert peer_cert; + + info = MHD_gtls_get_auth_info (session); + if (info == NULL || info->ncerts == 0) + { + MHD_gnutls_assert (); + /* we need this in order to get peer's certificate */ + return GNUTLS_E_INTERNAL_ERROR; + } + + + i = 0; + + DECR_LEN (data_size, 2); + n_m = MHD_gtls_read_uint16 (&data[i]); + i += 2; + + DECR_LEN (data_size, n_m); + data_m = &data[i]; + i += n_m; + + DECR_LEN (data_size, 2); + n_e = MHD_gtls_read_uint16 (&data[i]); + i += 2; + + DECR_LEN (data_size, n_e); + data_e = &data[i]; + i += n_e; + + _n_e = n_e; + _n_m = n_m; + + if (MHD_gtls_mpi_scan_nz (&session->key->rsa[0], data_m, &_n_m) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + if (MHD_gtls_mpi_scan_nz (&session->key->rsa[1], data_e, &_n_e) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + MHD_gtls_rsa_export_set_pubkey (session, session->key->rsa[1], + session->key->rsa[0]); + + /* VERIFY SIGNATURE */ + + vparams.size = n_m + n_e + 4; + vparams.data = data; + + DECR_LEN (data_size, 2); + sigsize = MHD_gtls_read_uint16 (&data[vparams.size]); + + DECR_LEN (data_size, sigsize); + signature.data = &data[vparams.size + 2]; + signature.size = sigsize; + + if ((ret = + MHD_gtls_raw_cert_to_gcert (&peer_cert, + session->security_parameters.cert_type, + &info->raw_certificate_list[0], + CERT_NO_COPY)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = + MHD_gtls_verify_sig_params (session, &peer_cert, &vparams, &signature); + + MHD_gtls_gcert_deinit (&peer_cert); + if (ret < 0) + { + MHD_gnutls_assert (); + } + + return ret; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/debug.c b/lib/libmicrohttpd/src/daemon/https/tls/debug.c new file mode 100644 index 0000000000..e7e41d0bdb --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/debug.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include <stdio.h> +#include <stdlib.h> +#include <gcrypt.h> + +const char * +MHD__gnutls_packet2str (content_type_t packet) +{ + switch (packet) + { + case GNUTLS_CHANGE_CIPHER_SPEC: + return "Change Cipher Spec"; + case GNUTLS_ALERT: + return "Alert"; + case GNUTLS_HANDSHAKE: + return "Handshake"; + case GNUTLS_APPLICATION_DATA: + return "Application Data"; + case GNUTLS_INNER_APPLICATION: + return "Inner Application"; + + default: + return "Unknown Packet"; + } +} + +const char * +MHD__gnutls_handshake2str (MHD_gnutls_handshake_description_t handshake) +{ + + switch (handshake) + { + case GNUTLS_HANDSHAKE_HELLO_REQUEST: + return "HELLO REQUEST"; + break; + case GNUTLS_HANDSHAKE_CLIENT_HELLO: + return "CLIENT HELLO"; + break; + case GNUTLS_HANDSHAKE_SERVER_HELLO: + return "SERVER HELLO"; + break; + case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: + return "CERTIFICATE"; + break; + case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: + return "SERVER KEY EXCHANGE"; + break; + case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: + return "CERTIFICATE REQUEST"; + break; + case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE: + return "SERVER HELLO DONE"; + break; + case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY: + return "CERTIFICATE VERIFY"; + break; + case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE: + return "CLIENT KEY EXCHANGE"; + break; + case GNUTLS_HANDSHAKE_FINISHED: + return "FINISHED"; + break; + case GNUTLS_HANDSHAKE_SUPPLEMENTAL: + return "SUPPLEMENTAL"; + break; + default: + return "Unknown Handshake packet"; + + } +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/debug.h b/lib/libmicrohttpd/src/daemon/https/tls/debug.h new file mode 100644 index 0000000000..ba1f100609 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/debug.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +const char *MHD__gnutls_packet2str (content_type_t packet); +const char *MHD__gnutls_handshake2str (MHD_gnutls_handshake_description_t + handshake); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/defines.h b/lib/libmicrohttpd/src/daemon/https/tls/defines.h new file mode 100644 index 0000000000..9a63636058 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/defines.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef DEFINES_H +# define DEFINES_H + +#ifdef HAVE_CONFIG_H +# include "MHD_config.h" +#endif + +#include <stddef.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <limits.h> +#include <stdint.h> + +#ifdef NO_SSIZE_T +# define HAVE_SSIZE_T +typedef int ssize_t; +#endif + +#include <sys/types.h> +#include <unistd.h> +#include <sys/stat.h> +#ifndef MINGW +#include <sys/socket.h> +#endif +#include <time.h> + +/* TODO check if these should go into config.h */ +#define SIZEOF_UNSIGNED_INT 4 +#define SIZEOF_UNSIGNED_LONG 8 +#define SIZEOF_UNSIGNED_LONG_INT SIZEOF_UNSIGNED_LONG + +/* some systems had problems with long long int, thus, + * it is not used. + */ +typedef struct +{ + unsigned char i[8]; +} uint64; + +#endif /* defines_h */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/ext_cert_type.c b/lib/libmicrohttpd/src/daemon/https/tls/ext_cert_type.c new file mode 100644 index 0000000000..1e7966f454 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/ext_cert_type.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the code the Certificate Type TLS extension. + * This extension is currently gnutls specific. + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "gnutls_num.h" +#include "ext_cert_type.h" +#include "gnutls_state.h" +#include "gnutls_num.h" + +inline static int MHD__gnutls_num2cert_type (int num); +inline static int MHD__gnutls_cert_type2num (int record_size); + +/* + * In case of a server: if a CERT_TYPE extension type is received then it stores + * into the session security parameters the new value. The server may use MHD_gnutls_session_certificate_type_get(), + * to access it. + * + * In case of a client: If a cert_types have been specified then we send the extension. + * + */ + +int +MHD_gtls_cert_type_recv_params (MHD_gtls_session_t session, + const opaque * data, size_t _data_size) +{ + int new_type = -1, ret, i; + ssize_t data_size = _data_size; + +#if MHD_DEBUG_TLS + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + if (data_size > 0) + { + if (data_size != 1) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + new_type = MHD__gnutls_num2cert_type (data[0]); + + if (new_type < 0) + { + MHD_gnutls_assert (); + return new_type; + } + + /* Check if we support this cert_type */ + if ((ret = + MHD_gtls_session_cert_type_supported (session, new_type)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD__gnutls_session_cert_type_set (session, new_type); + } + } + else +#endif + + { /* SERVER SIDE - we must check if the sent cert type is the right one + */ + if (data_size > 1) + { + uint8_t len; + + len = data[0]; + DECR_LEN (data_size, len); + + for (i = 0; i < len; i++) + { + new_type = MHD__gnutls_num2cert_type (data[i + 1]); + + if (new_type < 0) + continue; + + /* Check if we support this cert_type */ + if ((ret = + MHD_gtls_session_cert_type_supported (session, + new_type)) < 0) + { + MHD_gnutls_assert (); + continue; + } + else + break; + /* new_type is ok */ + } + + if (new_type < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + + if ((ret = + MHD_gtls_session_cert_type_supported (session, new_type)) < 0) + { + MHD_gnutls_assert (); + /* The peer has requested unsupported certificate + * types. Instead of failing, procceed normally. + * (the ciphersuite selection would fail, or a + * non certificate ciphersuite will be selected). + */ + return 0; + } + + MHD__gnutls_session_cert_type_set (session, new_type); + } + + + } + + return 0; +} + +/* returns data_size or a negative number on failure + */ +int +MHD_gtls_cert_type_send_params (MHD_gtls_session_t session, opaque * data, + size_t data_size) +{ + unsigned int len; + + /* this function sends the client extension data (dnsname) */ +#if MHD_DEBUG_TLS + unsigned int i; + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + + if (session->internals.priorities.cert_type.num_algorithms > 0) + { + + len = session->internals.priorities.cert_type.num_algorithms; + + if (len == 1 && + session->internals.priorities.cert_type.priority[0] == + MHD_GNUTLS_CRT_X509) + { + /* We don't use this extension if X.509 certificates + * are used. + */ + return 0; + } + + if (data_size < len + 1) + { + MHD_gnutls_assert (); + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + /* this is a vector! + */ + data[0] = (uint8_t) len; + + for (i = 0; i < len; i++) + { + data[i + 1] = + MHD__gnutls_cert_type2num (session->internals. + priorities.cert_type.priority[i]); + } + return len + 1; + } + + } + else +#endif + { /* server side */ + if (session->security_parameters.cert_type != DEFAULT_CERT_TYPE) + { + len = 1; + if (data_size < len) + { + MHD_gnutls_assert (); + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + data[0] = + MHD__gnutls_cert_type2num (session-> + security_parameters.cert_type); + return len; + } + + + } + + return 0; +} + +/* Maps numbers to record sizes according to the + * extensions draft. + */ +inline static int +MHD__gnutls_num2cert_type (int num) +{ + switch (num) + { + case 0: + return MHD_GNUTLS_CRT_X509; + default: + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } +} + +/* Maps record size to numbers according to the + * extensions draft. + */ +inline static int +MHD__gnutls_cert_type2num (int cert_type) +{ + switch (cert_type) + { + case MHD_GNUTLS_CRT_X509: + return 0; + default: + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/ext_cert_type.h b/lib/libmicrohttpd/src/daemon/https/tls/ext_cert_type.h new file mode 100644 index 0000000000..f80f7ba8f5 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/ext_cert_type.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Maps record size to numbers according to the + * extensions draft. + */ +int MHD_gtls_cert_type_recv_params (MHD_gtls_session_t session, + const opaque * data, size_t data_size); +int MHD_gtls_cert_type_send_params (MHD_gtls_session_t session, opaque * data, + size_t); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/ext_max_record.c b/lib/libmicrohttpd/src/daemon/https/tls/ext_max_record.c new file mode 100644 index 0000000000..421a1739a3 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/ext_max_record.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2001, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the code for the Max Record Size TLS extension. + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "gnutls_num.h" +#include <ext_max_record.h> + +/* + * In case of a server: if a MAX_RECORD_SIZE extension type is received then it stores + * into the session the new value. The server may use MHD_gnutls_get_max_record_size(), + * in order to access it. + * + * In case of a client: If a different max record size (than the default) has + * been specified then it sends the extension. + * + */ + +int +MHD_gtls_max_record_recv_params (MHD_gtls_session_t session, + const opaque * data, size_t _data_size) +{ + ssize_t new_size; + ssize_t data_size = _data_size; + + if (session->security_parameters.entity == GNUTLS_SERVER) + { + if (data_size > 0) + { + DECR_LEN (data_size, 1); + + new_size = MHD_gtls_mre_num2record (data[0]); + + if (new_size < 0) + { + MHD_gnutls_assert (); + return new_size; + } + + session->security_parameters.max_record_send_size = new_size; + session->security_parameters.max_record_recv_size = new_size; + } + } + else + { /* CLIENT SIDE - we must check if the sent record size is the right one + */ + if (data_size > 0) + { + + if (data_size != 1) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + new_size = MHD_gtls_mre_num2record (data[0]); + + if (new_size < 0 + || new_size != session->internals.proposed_record_size) + { + MHD_gnutls_assert (); + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + else + { + session->security_parameters.max_record_recv_size = + session->internals.proposed_record_size; + } + + } + + + } + + return 0; +} + +/* returns data_size or a negative number on failure + */ +int +MHD_gtls_max_record_send_params (MHD_gtls_session_t session, opaque * data, + size_t data_size) +{ + uint16_t len; + /* this function sends the client extension data (dnsname) */ +#if MHD_DEBUG_TLS + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + + if (session->internals.proposed_record_size != DEFAULT_MAX_RECORD_SIZE) + { + len = 1; + if (data_size < len) + { + MHD_gnutls_assert (); + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + data[0] = + (uint8_t) MHD_gtls_mre_record2num (session->internals. + proposed_record_size); + return len; + } + + } + else +#endif + { /* server side */ + + if (session->security_parameters.max_record_recv_size != + DEFAULT_MAX_RECORD_SIZE) + { + len = 1; + if (data_size < len) + { + MHD_gnutls_assert (); + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + data[0] = + (uint8_t) + MHD_gtls_mre_record2num + (session->security_parameters.max_record_recv_size); + return len; + } + + + } + + return 0; +} + +/* Maps numbers to record sizes according to the + * extensions draft. + */ +int +MHD_gtls_mre_num2record (int num) +{ + switch (num) + { + case 1: + return 512; + case 2: + return 1024; + case 3: + return 2048; + case 4: + return 4096; + default: + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } +} + +/* Maps record size to numbers according to the + * extensions draft. + */ +int +MHD_gtls_mre_record2num (uint16_t record_size) +{ + switch (record_size) + { + case 512: + return 1; + case 1024: + return 2; + case 2048: + return 3; + case 4096: + return 4; + default: + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/ext_max_record.h b/lib/libmicrohttpd/src/daemon/https/tls/ext_max_record.h new file mode 100644 index 0000000000..1468625308 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/ext_max_record.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Maps record size to numbers according to the + * extensions draft. + */ +int MHD_gtls_mre_num2record (int num); +int MHD_gtls_mre_record2num (uint16_t record_size); +int MHD_gtls_max_record_recv_params (MHD_gtls_session_t session, + const opaque * data, size_t data_size); +int MHD_gtls_max_record_send_params (MHD_gtls_session_t session, + opaque * data, size_t); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/ext_server_name.c b/lib/libmicrohttpd/src/daemon/https/tls/ext_server_name.c new file mode 100644 index 0000000000..911bd5302d --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/ext_server_name.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include "gnutls_int.h" +#include "gnutls_auth_int.h" +#include "gnutls_errors.h" +#include "gnutls_num.h" +#include <ext_server_name.h> + +/* + * In case of a server: if a NAME_DNS extension type is received then it stores + * into the session the value of NAME_DNS. The server may use MHD_gnutls_ext_get_server_name(), + * in order to access it. + * + * In case of a client: If a proper NAME_DNS extension type is found in the session then + * it sends the extension to the peer. + * + */ + +int +MHD_gtls_server_name_recv_params (MHD_gtls_session_t session, + const opaque * data, size_t _data_size) +{ + int i; + const unsigned char *p; + uint16_t len, type; + ssize_t data_size = _data_size; + int server_names = 0; + + DECR_LENGTH_RET (data_size, 2, 0); + len = MHD_gtls_read_uint16 (data); + + if (len != data_size) + { + /* This is unexpected packet length, but + * just ignore it, for now. + */ + MHD_gnutls_assert (); + return 0; + } + + p = data + 2; + + /* Count all server_names in the packet. */ + while (data_size > 0) + { + DECR_LENGTH_RET (data_size, 1, 0); + p++; + + DECR_LEN (data_size, 2); + len = MHD_gtls_read_uint16 (p); + p += 2; + + /* make sure supplied server name is not empty */ + if (len > 0) + { + DECR_LENGTH_RET (data_size, len, 0); + server_names++; + p += len; + } + else + { +#if HAVE_MESSAGES + MHD__gnutls_handshake_log + ("HSK[%x]: Received zero size server name (under attack?)\n", + session); +#endif + } + } + + /* we cannot accept more server names. */ + if (server_names > MAX_SERVER_NAME_EXTENSIONS) + { +#if HAVE_MESSAGES + MHD__gnutls_handshake_log + ("HSK[%x]: Too many server names received (under attack?)\n", + session); +#endif + server_names = MAX_SERVER_NAME_EXTENSIONS; + } + + session->security_parameters.extensions.server_names_size = server_names; + if (server_names == 0) + return 0; /* no names found */ + + p = data + 2; + for (i = 0; i < server_names; i++) + { + type = *p; + p++; + + len = MHD_gtls_read_uint16 (p); + p += 2; + + switch (type) + { + case 0: /* NAME_DNS */ + if (len <= MAX_SERVER_NAME_SIZE) + { + memcpy (session->security_parameters.extensions. + server_names[i].name, p, len); + session->security_parameters.extensions.server_names[i]. + name_length = len; + session->security_parameters.extensions.server_names[i].type = + GNUTLS_NAME_DNS; + break; + } + } + + /* move to next record */ + p += len; + } + return 0; +} + +/* returns data_size or a negative number on failure + */ +int +MHD_gtls_server_name_send_params (MHD_gtls_session_t session, + opaque * data, size_t _data_size) +{ + int total_size = 0; +#if MHD_DEBUG_TLS + uint16_t len; + opaque *p; + unsigned i; + ssize_t data_size = _data_size; + + /* this function sends the client extension data (dnsname) */ + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + + if (session->security_parameters.extensions.server_names_size == 0) + return 0; + + /* uint16_t + */ + total_size = 2; + for (i = 0; + i < session->security_parameters.extensions.server_names_size; i++) + { + /* count the total size + */ + len = + session->security_parameters.extensions.server_names[i]. + name_length; + + /* uint8_t + uint16_t + size + */ + total_size += 1 + 2 + len; + } + + p = data; + + /* UINT16: write total size of all names + */ + DECR_LENGTH_RET (data_size, 2, GNUTLS_E_SHORT_MEMORY_BUFFER); + MHD_gtls_write_uint16 (total_size - 2, p); + p += 2; + + for (i = 0; + i < session->security_parameters.extensions.server_names_size; i++) + { + + switch (session->security_parameters.extensions. + server_names[i].type) + { + case GNUTLS_NAME_DNS: + + len = + session->security_parameters.extensions. + server_names[i].name_length; + if (len == 0) + break; + + /* UINT8: type of this extension + * UINT16: size of the first name + * LEN: the actual server name. + */ + DECR_LENGTH_RET (data_size, len + 3, + GNUTLS_E_SHORT_MEMORY_BUFFER); + + *p = 0; /* NAME_DNS type */ + p++; + + MHD_gtls_write_uint16 (len, p); + p += 2; + + memcpy (p, + session->security_parameters.extensions. + server_names[0].name, len); + p += len; + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + } + } +#endif + return total_size; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/ext_server_name.h b/lib/libmicrohttpd/src/daemon/https/tls/ext_server_name.h new file mode 100644 index 0000000000..f74ce1913c --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/ext_server_name.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +int MHD_gtls_server_name_recv_params (MHD_gtls_session_t session, + const opaque * data, size_t data_size); +int MHD_gtls_server_name_send_params (MHD_gtls_session_t session, + opaque * data, size_t); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_alert.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_alert.c new file mode 100644 index 0000000000..4925f6e731 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_alert.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_record.h> +#include <debug.h> + +typedef struct +{ + MHD_gnutls_alert_description_t alert; + const char *desc; +} MHD_gnutls_alert_entry; + +static const MHD_gnutls_alert_entry MHD_gtls_sup_alerts[] = { + {GNUTLS_A_CLOSE_NOTIFY, "Close notify"}, + {GNUTLS_A_UNEXPECTED_MESSAGE, "Unexpected message"}, + {GNUTLS_A_BAD_RECORD_MAC, "Bad record MAC"}, + {GNUTLS_A_DECRYPTION_FAILED, "Decryption failed"}, + {GNUTLS_A_RECORD_OVERFLOW, "Record overflow"}, + {GNUTLS_A_DECOMPRESSION_FAILURE, "Decompression failed"}, + {GNUTLS_A_HANDSHAKE_FAILURE, "Handshake failed"}, + {GNUTLS_A_BAD_CERTIFICATE, "Certificate is bad"}, + {GNUTLS_A_UNSUPPORTED_CERTIFICATE, "Certificate is not supported"}, + {GNUTLS_A_CERTIFICATE_REVOKED, "Certificate was revoked"}, + {GNUTLS_A_CERTIFICATE_EXPIRED, "Certificate is expired"}, + {GNUTLS_A_CERTIFICATE_UNKNOWN, "Unknown certificate"}, + {GNUTLS_A_ILLEGAL_PARAMETER, "Illegal parameter"}, + {GNUTLS_A_UNKNOWN_CA, "CA is unknown"}, + {GNUTLS_A_ACCESS_DENIED, "Access was denied"}, + {GNUTLS_A_DECODE_ERROR, "Decode error"}, + {GNUTLS_A_DECRYPT_ERROR, "Decrypt error"}, + {GNUTLS_A_EXPORT_RESTRICTION, "Export restriction"}, + {GNUTLS_A_PROTOCOL_VERSION, "Error in protocol version"}, + {GNUTLS_A_INSUFFICIENT_SECURITY, "Insufficient security"}, + {GNUTLS_A_USER_CANCELED, "User canceled"}, + {GNUTLS_A_INTERNAL_ERROR, "Internal error"}, + {GNUTLS_A_NO_RENEGOTIATION, "No renegotiation is allowed"}, + {GNUTLS_A_CERTIFICATE_UNOBTAINABLE, + "Could not retrieve the specified certificate"}, + {GNUTLS_A_UNSUPPORTED_EXTENSION, "An unsupported extension was sent"}, + {GNUTLS_A_UNRECOGNIZED_NAME, + "The server name sent was not recognized"}, + {GNUTLS_A_UNKNOWN_PSK_IDENTITY, + "The SRP/PSK username is missing or not known"}, +}; + +#define GNUTLS_ALERT_LOOP(b) \ + const MHD_gnutls_alert_entry *p; \ + for(p = MHD_gtls_sup_alerts; p->desc != NULL; p++) { b ; } + +#define GNUTLS_ALERT_ID_LOOP(a) \ + GNUTLS_ALERT_LOOP( if(p->alert == alert) { a; break; }) + + +/** + * MHD__gnutls_alert_get_name - Returns a string describing the alert number given + * @alert: is an alert number #MHD_gtls_session_t structure. + * + * This function will return a string that describes the given alert + * number or NULL. See MHD_gnutls_alert_get(). + * + **/ +const char * +MHD__gnutls_alert_get_name (MHD_gnutls_alert_description_t alert) +{ + const char *ret = NULL; + + GNUTLS_ALERT_ID_LOOP (ret = p->desc); + + return ret; +} + +/** + * MHD__gnutls_alert_send - This function sends an alert message to the peer + * @session: is a #MHD_gtls_session_t structure. + * @level: is the level of the alert + * @desc: is the alert description + * + * This function will send an alert to the peer in order to inform + * him of something important (eg. his Certificate could not be verified). + * If the alert level is Fatal then the peer is expected to close the + * connection, otherwise he may ignore the alert and continue. + * + * The error code of the underlying record send function will be returned, + * so you may also receive GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN as well. + * + * Returns 0 on success. + * + **/ +int +MHD__gnutls_alert_send (MHD_gtls_session_t session, + MHD_gnutls_alert_level_t level, + MHD_gnutls_alert_description_t desc) +{ + uint8_t data[2]; + int ret; + const char *name; + + data[0] = (uint8_t) level; + data[1] = (uint8_t) desc; + + name = MHD__gnutls_alert_get_name ((int) data[1]); + if (name == NULL) + name = "(unknown)"; + MHD__gnutls_record_log ("REC: Sending Alert[%d|%d] - %s\n", data[0], + data[1], name); + + if ((ret = MHD_gtls_send_int (session, GNUTLS_ALERT, -1, data, 2)) >= 0) + return 0; + else + return ret; +} + +/** + * MHD_gtls_error_to_alert - This function returns an alert code based on the given error code + * @err: is a negative integer + * @level: the alert level will be stored there + * + * Returns an alert depending on the error code returned by a gnutls + * function. All alerts sent by this function should be considered fatal. + * The only exception is when err == GNUTLS_E_REHANDSHAKE, where a warning + * alert should be sent to the peer indicating that no renegotiation will + * be performed. + * + * If there is no mapping to a valid alert the alert to indicate internal error + * is returned. + * + **/ +int +MHD_gtls_error_to_alert (int err, int *level) +{ + int ret, _level = -1; + + switch (err) + { /* send appropriate alert */ + case GNUTLS_E_DECRYPTION_FAILED: + /* GNUTLS_A_DECRYPTION_FAILED is not sent, because + * it is not defined in SSL3. Note that we must + * not distinguish Decryption failures from mac + * check failures, due to the possibility of some + * attacks. + */ + ret = GNUTLS_A_BAD_RECORD_MAC; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_DECOMPRESSION_FAILED: + ret = GNUTLS_A_DECOMPRESSION_FAILURE; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER: + case GNUTLS_E_ILLEGAL_SRP_USERNAME: + ret = GNUTLS_A_ILLEGAL_PARAMETER; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_ASN1_ELEMENT_NOT_FOUND: + case GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND: + case GNUTLS_E_ASN1_DER_ERROR: + case GNUTLS_E_ASN1_VALUE_NOT_FOUND: + case GNUTLS_E_ASN1_GENERIC_ERROR: + case GNUTLS_E_ASN1_VALUE_NOT_VALID: + case GNUTLS_E_ASN1_TAG_ERROR: + case GNUTLS_E_ASN1_TAG_IMPLICIT: + case GNUTLS_E_ASN1_TYPE_ANY_ERROR: + case GNUTLS_E_ASN1_SYNTAX_ERROR: + case GNUTLS_E_ASN1_DER_OVERFLOW: + ret = GNUTLS_A_BAD_CERTIFICATE; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_UNKNOWN_CIPHER_SUITE: + case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM: + case GNUTLS_E_INSUFFICIENT_CREDENTIALS: + case GNUTLS_E_NO_CIPHER_SUITES: + case GNUTLS_E_NO_COMPRESSION_ALGORITHMS: + ret = GNUTLS_A_HANDSHAKE_FAILURE; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION: + ret = GNUTLS_A_UNSUPPORTED_EXTENSION; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_UNEXPECTED_PACKET: + case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET: + ret = GNUTLS_A_UNEXPECTED_MESSAGE; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_REHANDSHAKE: + ret = GNUTLS_A_NO_RENEGOTIATION; + _level = GNUTLS_AL_WARNING; + break; + case GNUTLS_E_UNSUPPORTED_VERSION_PACKET: + ret = GNUTLS_A_PROTOCOL_VERSION; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE: + ret = GNUTLS_A_UNSUPPORTED_CERTIFICATE; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: + ret = GNUTLS_A_RECORD_OVERFLOW; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_INTERNAL_ERROR: + case GNUTLS_E_NO_TEMPORARY_DH_PARAMS: + case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS: + ret = GNUTLS_A_INTERNAL_ERROR; + _level = GNUTLS_AL_FATAL; + break; + case GNUTLS_E_DH_PRIME_UNACCEPTABLE: + case GNUTLS_E_NO_CERTIFICATE_FOUND: + ret = GNUTLS_A_INSUFFICIENT_SECURITY; + _level = GNUTLS_AL_FATAL; + break; + default: + ret = GNUTLS_A_INTERNAL_ERROR; + _level = GNUTLS_AL_FATAL; + break; + } + + if (level != NULL) + *level = _level; + + return ret; +} + + +/** + * MHD__gnutls_alert_send_appropriate - This function sends an alert to the peer depending on the error code + * @session: is a #MHD_gtls_session_t structure. + * @err: is an integer + * + * Sends an alert to the peer depending on the error code returned by a gnutls + * function. This function will call MHD_gtls_error_to_alert() to determine + * the appropriate alert to send. + * + * This function may also return GNUTLS_E_AGAIN, or GNUTLS_E_INTERRUPTED. + * + * If the return value is GNUTLS_E_INVALID_REQUEST, then no alert has + * been sent to the peer. + * + * Returns zero on success. + */ +int +MHD__gnutls_alert_send_appropriate (MHD_gtls_session_t session, int err) +{ + int alert; + int level; + + alert = MHD_gtls_error_to_alert (err, &level); + if (alert < 0) + { + return alert; + } + + return MHD__gnutls_alert_send (session, level, alert); +} + +/** + * MHD_gnutls_alert_get - Returns the last alert number received. + * @session: is a #MHD_gtls_session_t structure. + * + * This function will return the last alert number received. This + * function should be called if GNUTLS_E_WARNING_ALERT_RECEIVED or + * GNUTLS_E_FATAL_ALERT_RECEIVED has been returned by a gnutls + * function. The peer may send alerts if he thinks some things were + * not right. Check gnutls.h for the available alert descriptions. + * + * If no alert has been received the returned value is undefined. + * + **/ +MHD_gnutls_alert_description_t +MHD_gnutls_alert_get (MHD_gtls_session_t session) +{ + return session->internals.last_alert; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_algorithms.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_algorithms.c new file mode 100644 index 0000000000..f65ccbac9d --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_algorithms.c @@ -0,0 +1,1340 @@ +/* + * Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include "gnutls_int.h" +#include "gnutls_algorithms.h" +#include "gnutls_errors.h" +#include "gnutls_cert.h" +/* x509 */ +#include "common.h" + +/* Cred type mappings to KX algorithms + * FIXME: The mappings are not 1-1. Some KX such as SRP_RSA require + * more than one credentials type. + */ +typedef struct +{ + enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm; + enum MHD_GNUTLS_CredentialsType client_type; + enum MHD_GNUTLS_CredentialsType server_type; /* The type of credentials a server + * needs to set */ +} MHD_gnutls_cred_map; + +static const MHD_gnutls_cred_map MHD_gtls_cred_mappings[] = { + {MHD_GNUTLS_KX_RSA, + MHD_GNUTLS_CRD_CERTIFICATE, + MHD_GNUTLS_CRD_CERTIFICATE}, + {MHD_GNUTLS_KX_RSA_EXPORT, + MHD_GNUTLS_CRD_CERTIFICATE, + MHD_GNUTLS_CRD_CERTIFICATE}, + {0, + 0, + 0} +}; + +#define GNUTLS_KX_MAP_LOOP(b) \ + const MHD_gnutls_cred_map *p; \ + for(p = MHD_gtls_cred_mappings; p->algorithm != 0; p++) { b ; } + +#define GNUTLS_KX_MAP_ALG_LOOP_SERVER(a) \ + GNUTLS_KX_MAP_LOOP( if(p->server_type == type) { a; break; }) + +#define GNUTLS_KX_MAP_ALG_LOOP_CLIENT(a) \ + GNUTLS_KX_MAP_LOOP( if(p->client_type == type) { a; break; }) + +/* KX mappings to PK algorithms */ +typedef struct +{ + enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm; + enum MHD_GNUTLS_PublicKeyAlgorithm pk_algorithm; + enum encipher_type encipher_type; /* CIPHER_ENCRYPT if this algorithm is to be used + * for encryption, CIPHER_SIGN if signature only, + * CIPHER_IGN if this does not apply at all. + * + * This is useful to certificate cipher suites, which check + * against the certificate key usage bits. + */ +} MHD_gnutls_pk_map; + +/* This table maps the Key exchange algorithms to + * the certificate algorithms. Eg. if we have + * RSA algorithm in the certificate then we can + * use GNUTLS_KX_RSA or GNUTLS_KX_DHE_RSA. + */ +static const MHD_gnutls_pk_map MHD_gtls_pk_mappings[] = { + {MHD_GNUTLS_KX_RSA, + MHD_GNUTLS_PK_RSA, + CIPHER_ENCRYPT}, + {MHD_GNUTLS_KX_RSA_EXPORT, + MHD_GNUTLS_PK_RSA, + CIPHER_SIGN}, + {0, + 0, + 0} +}; + +#define GNUTLS_PK_MAP_LOOP(b) \ + const MHD_gnutls_pk_map *p; \ + for(p = MHD_gtls_pk_mappings; p->kx_algorithm != 0; p++) { b } + +#define GNUTLS_PK_MAP_ALG_LOOP(a) \ + GNUTLS_PK_MAP_LOOP( if(p->kx_algorithm == kx_algorithm) { a; break; }) + +/* TLS Versions */ + +typedef struct +{ + const char *name; + enum MHD_GNUTLS_Protocol id; /* gnutls internal version number */ + int major; /* defined by the protocol */ + int minor; /* defined by the protocol */ + int supported; /* 0 not supported, > 0 is supported */ +} MHD_gnutls_version_entry; + +static const MHD_gnutls_version_entry MHD_gtls_sup_versions[] = { + {"SSL3.0", + MHD_GNUTLS_PROTOCOL_SSL3, + 3, + 0, + 1}, + {"TLS1.0", + MHD_GNUTLS_PROTOCOL_TLS1_0, + 3, + 1, + 1}, + {"TLS1.1", + MHD_GNUTLS_PROTOCOL_TLS1_1, + 3, + 2, + 1}, + {"TLS1.2", + MHD_GNUTLS_PROTOCOL_TLS1_2, + 3, + 3, + 1}, + {0, + 0, + 0, + 0, + 0} +}; + +/* Keep the contents of this struct the same as the previous one. */ +static const enum MHD_GNUTLS_Protocol MHD_gtls_supported_protocols[] = +{ MHD_GNUTLS_PROTOCOL_SSL3, + MHD_GNUTLS_PROTOCOL_TLS1_0, + MHD_GNUTLS_PROTOCOL_TLS1_1, + MHD_GNUTLS_PROTOCOL_TLS1_2, + 0 +}; + +#define GNUTLS_VERSION_LOOP(b) \ + const MHD_gnutls_version_entry *p; \ + for(p = MHD_gtls_sup_versions; p->name != NULL; p++) { b ; } + +#define GNUTLS_VERSION_ALG_LOOP(a) \ + GNUTLS_VERSION_LOOP( if(p->id == version) { a; break; }) + +struct MHD_gnutls_cipher_entry +{ + const char *name; + enum MHD_GNUTLS_CipherAlgorithm id; + uint16_t blocksize; + uint16_t keysize; + cipher_type_t block; + uint16_t iv; + int export_flag; /* 0 non export */ +}; +typedef struct MHD_gnutls_cipher_entry MHD_gnutls_cipher_entry; + +/* Note that all algorithms are in CBC or STREAM modes. + * Do not add any algorithms in other modes (avoid modified algorithms). + * View first: "The order of encryption and authentication for + * protecting communications" by Hugo Krawczyk - CRYPTO 2001 + */ +static const MHD_gnutls_cipher_entry MHD_gtls_algorithms[] = { + {"AES-256-CBC", + MHD_GNUTLS_CIPHER_AES_256_CBC, + 16, + 32, + CIPHER_BLOCK, + 16, + 0}, + {"AES-128-CBC", + MHD_GNUTLS_CIPHER_AES_128_CBC, + 16, + 16, + CIPHER_BLOCK, + 16, + 0}, + {"3DES-CBC", + MHD_GNUTLS_CIPHER_3DES_CBC, + 8, + 24, + CIPHER_BLOCK, + 8, + 0}, + {"ARCFOUR-128", + MHD_GNUTLS_CIPHER_ARCFOUR_128, + 1, + 16, + CIPHER_STREAM, + 0, + 0}, + {"NULL", + MHD_GNUTLS_CIPHER_NULL, + 1, + 0, + CIPHER_STREAM, + 0, + 0}, + {0, + 0, + 0, + 0, + 0, + 0, + 0} +}; + +/* Keep the contents of this struct the same as the previous one. */ +static const enum MHD_GNUTLS_CipherAlgorithm MHD_gtls_supported_ciphers[] = +{ MHD_GNUTLS_CIPHER_AES_256_CBC, + MHD_GNUTLS_CIPHER_AES_128_CBC, + MHD_GNUTLS_CIPHER_3DES_CBC, + MHD_GNUTLS_CIPHER_ARCFOUR_128, + MHD_GNUTLS_CIPHER_NULL, + 0 +}; + +#define GNUTLS_LOOP(b) \ + const MHD_gnutls_cipher_entry *p; \ + for(p = MHD_gtls_algorithms; p->name != NULL; p++) { b ; } + +#define GNUTLS_ALG_LOOP(a) \ + GNUTLS_LOOP( if(p->id == algorithm) { a; break; } ) + +struct MHD_gnutls_hash_entry +{ + const char *name; + const char *oid; + enum MHD_GNUTLS_HashAlgorithm id; + size_t key_size; /* in case of mac */ +}; +typedef struct MHD_gnutls_hash_entry MHD_gnutls_hash_entry; + +static const MHD_gnutls_hash_entry MHD_gtls_hash_algorithms[] = { + {"SHA1", + HASH_OID_SHA1, + MHD_GNUTLS_MAC_SHA1, + 20}, + {"MD5", + HASH_OID_MD5, + MHD_GNUTLS_MAC_MD5, + 16}, + {"SHA256", + HASH_OID_SHA256, + MHD_GNUTLS_MAC_SHA256, + 32}, + {"NULL", + NULL, + MHD_GNUTLS_MAC_NULL, + 0}, + {0, + 0, + 0, + 0} +}; + +/* Keep the contents of this struct the same as the previous one. */ +static const enum MHD_GNUTLS_HashAlgorithm MHD_gtls_supported_macs[] = +{ MHD_GNUTLS_MAC_SHA1, + MHD_GNUTLS_MAC_MD5, + MHD_GNUTLS_MAC_SHA256, + MHD_GNUTLS_MAC_NULL, + 0 +}; + +#define GNUTLS_HASH_LOOP(b) \ + const MHD_gnutls_hash_entry *p; \ + for(p = MHD_gtls_hash_algorithms; p->name != NULL; p++) { b ; } + +#define GNUTLS_HASH_ALG_LOOP(a) \ + GNUTLS_HASH_LOOP( if(p->id == algorithm) { a; break; } ) + +/* Compression Section */ +#define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \ + { #name, name, id, wb, ml, cl} + +#define MAX_COMP_METHODS 5 +const int MHD__gnutls_comp_algorithms_size = MAX_COMP_METHODS; + +/* the compression entry is defined in MHD_gnutls_algorithms.h */ + +MHD_gnutls_compression_entry + MHD__gnutls_compression_algorithms[MAX_COMP_METHODS] = +{ + GNUTLS_COMPRESSION_ENTRY (MHD_GNUTLS_COMP_NULL, 0x00, 0, 0, 0), + { + 0, 0, 0, 0, 0, 0} +}; + +static const enum MHD_GNUTLS_CompressionMethod + MHD_gtls_supported_compressions[] = +{ + MHD_GNUTLS_COMP_NULL, + 0 +}; + +#define GNUTLS_COMPRESSION_LOOP(b) \ + const MHD_gnutls_compression_entry *p; \ + for(p = MHD__gnutls_compression_algorithms; p->name != NULL; p++) { b ; } +#define GNUTLS_COMPRESSION_ALG_LOOP(a) \ + GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } ) +#define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \ + GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } ) + +/* Key Exchange Section */ +extern MHD_gtls_mod_auth_st MHD_gtls_rsa_auth_struct; +extern MHD_gtls_mod_auth_st MHD_rsa_export_auth_struct; +extern MHD_gtls_mod_auth_st MHD_gtls_dhe_rsa_auth_struct; +extern MHD_gtls_mod_auth_st MHD_gtls_dhe_dss_auth_struct; +extern MHD_gtls_mod_auth_st srp_auth_struct; +extern MHD_gtls_mod_auth_st psk_auth_struct; +extern MHD_gtls_mod_auth_st dhe_psk_auth_struct; +extern MHD_gtls_mod_auth_st srp_rsa_auth_struct; +extern MHD_gtls_mod_auth_st srp_dss_auth_struct; + +typedef struct MHD_gtls_kx_algo_entry +{ + const char *name; + enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm; + MHD_gtls_mod_auth_st *auth_struct; + int needs_dh_params; + int needs_rsa_params; +} MHD_gtls_kx_algo_entry_t; + +static const MHD_gtls_kx_algo_entry_t MHD_gtls_kx_algorithms[] = { + {"RSA", + MHD_GNUTLS_KX_RSA, + &MHD_gtls_rsa_auth_struct, + 0, + 0}, + {"RSA-EXPORT", + MHD_GNUTLS_KX_RSA_EXPORT, + &MHD_rsa_export_auth_struct, + 0, + 1 /* needs RSA params */ }, + {0, + 0, + 0, + 0, + 0} +}; + +/* Keep the contents of this struct the same as the previous one. */ +static const enum MHD_GNUTLS_KeyExchangeAlgorithm MHD_gtls_supported_kxs[] = +{ + MHD_GNUTLS_KX_RSA, + MHD_GNUTLS_KX_RSA_EXPORT, + 0 +}; + +#define GNUTLS_KX_LOOP(b) \ + const MHD_gtls_kx_algo_entry_t *p; \ + for(p = MHD_gtls_kx_algorithms; p->name != NULL; p++) { b ; } + +#define GNUTLS_KX_ALG_LOOP(a) \ + GNUTLS_KX_LOOP( if(p->algorithm == algorithm) { a; break; } ) + +/* Cipher SUITES */ +#define GNUTLS_CIPHER_SUITE_ENTRY( name, block_algorithm, kx_algorithm, mac_algorithm, version ) \ + { #name, {name}, block_algorithm, kx_algorithm, mac_algorithm, version } + +typedef struct +{ + const char *name; + cipher_suite_st id; + enum MHD_GNUTLS_CipherAlgorithm block_algorithm; + enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm; + enum MHD_GNUTLS_HashAlgorithm mac_algorithm; + enum MHD_GNUTLS_Protocol version; /* this cipher suite is supported + * from 'version' and above; + */ +} MHD_gtls_cipher_suite_entry; + +/* RSA with NULL cipher and MD5 MAC + * for test purposes. + */ +#define GNUTLS_RSA_NULL_MD5 { 0x00, 0x01 } + +/* PSK (not in TLS 1.0) + * draft-ietf-tls-psk: + */ +#define GNUTLS_PSK_SHA_ARCFOUR_SHA1 { 0x00, 0x8A } +#define GNUTLS_PSK_SHA_3DES_EDE_CBC_SHA1 { 0x00, 0x8B } +#define GNUTLS_PSK_SHA_AES_128_CBC_SHA1 { 0x00, 0x8C } +#define GNUTLS_PSK_SHA_AES_256_CBC_SHA1 { 0x00, 0x8D } + +#define GNUTLS_DHE_PSK_SHA_ARCFOUR_SHA1 { 0x00, 0x8E } +#define GNUTLS_DHE_PSK_SHA_3DES_EDE_CBC_SHA1 { 0x00, 0x8F } +#define GNUTLS_DHE_PSK_SHA_AES_128_CBC_SHA1 { 0x00, 0x90 } +#define GNUTLS_DHE_PSK_SHA_AES_256_CBC_SHA1 { 0x00, 0x91 } + +/* SRP (rfc5054) + */ +#define GNUTLS_SRP_SHA_3DES_EDE_CBC_SHA1 { 0xC0, 0x1A } +#define GNUTLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1 { 0xC0, 0x1B } +#define GNUTLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1 { 0xC0, 0x1C } + +#define GNUTLS_SRP_SHA_AES_128_CBC_SHA1 { 0xC0, 0x1D } +#define GNUTLS_SRP_SHA_RSA_AES_128_CBC_SHA1 { 0xC0, 0x1E } +#define GNUTLS_SRP_SHA_DSS_AES_128_CBC_SHA1 { 0xC0, 0x1F } + +#define GNUTLS_SRP_SHA_AES_256_CBC_SHA1 { 0xC0, 0x20 } +#define GNUTLS_SRP_SHA_RSA_AES_256_CBC_SHA1 { 0xC0, 0x21 } +#define GNUTLS_SRP_SHA_DSS_AES_256_CBC_SHA1 { 0xC0, 0x22 } + +/* RSA + */ +#define GNUTLS_RSA_ARCFOUR_SHA1 { 0x00, 0x05 } +#define GNUTLS_RSA_ARCFOUR_MD5 { 0x00, 0x04 } +#define GNUTLS_RSA_3DES_EDE_CBC_SHA1 { 0x00, 0x0A } + +/* rfc3268: + */ +#define GNUTLS_RSA_AES_128_CBC_SHA1 { 0x00, 0x2F } +#define GNUTLS_RSA_AES_256_CBC_SHA1 { 0x00, 0x35 } + +/* rfc4132 */ +#define GNUTLS_RSA_CAMELLIA_128_CBC_SHA1 { 0x00,0x41 } +#define GNUTLS_RSA_CAMELLIA_256_CBC_SHA1 { 0x00,0x84 } + +/* DHE DSS + */ + +#define GNUTLS_DHE_DSS_3DES_EDE_CBC_SHA1 { 0x00, 0x13 } + +/* draft-ietf-tls-56-bit-ciphersuites-01: + */ +#define GNUTLS_DHE_DSS_ARCFOUR_SHA1 { 0x00, 0x66 } + +/* rfc3268: + */ +#define GNUTLS_DHE_DSS_AES_256_CBC_SHA1 { 0x00, 0x38 } +#define GNUTLS_DHE_DSS_AES_128_CBC_SHA1 { 0x00, 0x32 } + +/* rfc4132 */ +#define GNUTLS_DHE_DSS_CAMELLIA_128_CBC_SHA1 { 0x00,0x44 } +#define GNUTLS_DHE_DSS_CAMELLIA_256_CBC_SHA1 { 0x00,0x87 } + +/* DHE RSA + */ +#define GNUTLS_DHE_RSA_3DES_EDE_CBC_SHA1 { 0x00, 0x16 } + +/* rfc3268: + */ +#define GNUTLS_DHE_RSA_AES_128_CBC_SHA1 { 0x00, 0x33 } +#define GNUTLS_DHE_RSA_AES_256_CBC_SHA1 { 0x00, 0x39 } + +/* rfc4132 */ +#define GNUTLS_DHE_RSA_CAMELLIA_128_CBC_SHA1 { 0x00,0x45 } +#define GNUTLS_DHE_RSA_CAMELLIA_256_CBC_SHA1 { 0x00,0x88 } + +#define CIPHER_SUITES_COUNT sizeof(MHD_gtls_cs_algorithms)/sizeof(MHD_gtls_cipher_suite_entry)-1 + +static const MHD_gtls_cipher_suite_entry MHD_gtls_cs_algorithms[] = { + /* RSA */ + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_NULL_MD5, + MHD_GNUTLS_CIPHER_NULL, + MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_MD5, + MHD_GNUTLS_PROTOCOL_SSL3), + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_ARCFOUR_SHA1, + MHD_GNUTLS_CIPHER_ARCFOUR_128, + MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_SHA1, + MHD_GNUTLS_PROTOCOL_SSL3), + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_ARCFOUR_MD5, + MHD_GNUTLS_CIPHER_ARCFOUR_128, + MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_MD5, + MHD_GNUTLS_PROTOCOL_SSL3), + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_3DES_EDE_CBC_SHA1, + MHD_GNUTLS_CIPHER_3DES_CBC, + MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_SHA1, + MHD_GNUTLS_PROTOCOL_SSL3), + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_AES_128_CBC_SHA1, + MHD_GNUTLS_CIPHER_AES_128_CBC, MHD_GNUTLS_KX_RSA, + MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3), + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_AES_256_CBC_SHA1, + MHD_GNUTLS_CIPHER_AES_256_CBC, MHD_GNUTLS_KX_RSA, + MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3), + {0, + { + {0, + 0}}, + 0, + 0, + 0, + 0} +}; + +#define GNUTLS_CIPHER_SUITE_LOOP(b) \ + const MHD_gtls_cipher_suite_entry *p; \ + for(p = MHD_gtls_cs_algorithms; p->name != NULL; p++) { b ; } + +#define GNUTLS_CIPHER_SUITE_ALG_LOOP(a) \ + GNUTLS_CIPHER_SUITE_LOOP( if( (p->id.suite[0] == suite->suite[0]) && (p->id.suite[1] == suite->suite[1])) { a; break; } ) + +/* Generic Functions */ + +int +MHD_gtls_mac_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_HashAlgorithm algorithm) +{ /* actually returns the priority */ + unsigned int i; + for (i = 0; i < session->internals.priorities.mac.num_algorithms; i++) + { + if (session->internals.priorities.mac.priority[i] == algorithm) + return i; + } + return -1; +} + + +int +MHD_gnutls_mac_is_ok (enum MHD_GNUTLS_HashAlgorithm algorithm) +{ + ssize_t ret = -1; + GNUTLS_HASH_ALG_LOOP (ret = p->id); + if (ret >= 0) + ret = 0; + else + ret = 1; + return ret; +} + + +/** + * MHD__gnutls_compression_get_name - Returns a string with the name of the specified compression algorithm + * @algorithm: is a Compression algorithm + * + * Returns: a pointer to a string that contains the name of the + * specified compression algorithm, or %NULL. + **/ +const char * +MHD_gtls_compression_get_name (enum MHD_GNUTLS_CompressionMethod algorithm) +{ + const char *ret = NULL; + + /* avoid prefix */ + GNUTLS_COMPRESSION_ALG_LOOP (ret = p->name + sizeof ("GNUTLS_COMP_") - 1); + + return ret; +} + +/** + * MHD_gtls_compression_get_id - Returns the gnutls id of the specified in string algorithm + * @algorithm: is a compression method name + * + * The names are compared in a case insensitive way. + * + * Returns: an id of the specified in a string compression method, or + * %GNUTLS_COMP_UNKNOWN on error. + * + **/ +enum MHD_GNUTLS_CompressionMethod +MHD_gtls_compression_get_id (const char *name) +{ + enum MHD_GNUTLS_CompressionMethod ret = MHD_GNUTLS_COMP_UNKNOWN; + + GNUTLS_COMPRESSION_LOOP (if + (strcasecmp + (p->name + sizeof ("GNUTLS_COMP_") - 1, + name) == 0) ret = p->id) + ; + + return ret; +} + + +/* return the tls number of the specified algorithm */ +int +MHD_gtls_compression_get_num (enum MHD_GNUTLS_CompressionMethod algorithm) +{ + int ret = -1; + + /* avoid prefix */ + GNUTLS_COMPRESSION_ALG_LOOP (ret = p->num); + + return ret; +} + +int +MHD_gtls_compression_get_wbits (enum MHD_GNUTLS_CompressionMethod algorithm) +{ + int ret = -1; + /* avoid prefix */ + GNUTLS_COMPRESSION_ALG_LOOP (ret = p->window_bits); + return ret; +} + +int +MHD_gtls_compression_get_mem_level (enum MHD_GNUTLS_CompressionMethod + algorithm) +{ + int ret = -1; + /* avoid prefix */ + GNUTLS_COMPRESSION_ALG_LOOP (ret = p->mem_level); + return ret; +} + +int +MHD_gtls_compression_get_comp_level (enum MHD_GNUTLS_CompressionMethod + algorithm) +{ + int ret = -1; + /* avoid prefix */ + GNUTLS_COMPRESSION_ALG_LOOP (ret = p->comp_level); + return ret; +} + +/* returns the gnutls internal ID of the TLS compression + * method num + */ +enum MHD_GNUTLS_CompressionMethod +MHD_gtls_compression_get_id_from_int (int num) +{ + enum MHD_GNUTLS_CompressionMethod ret = -1; + + /* avoid prefix */ + GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret = p->id); + + return ret; +} + +int +MHD_gtls_compression_is_ok (enum MHD_GNUTLS_CompressionMethod algorithm) +{ + ssize_t ret = -1; + GNUTLS_COMPRESSION_ALG_LOOP (ret = p->id); + if (ret >= 0) + ret = 0; + else + ret = 1; + return ret; +} + +/* CIPHER functions */ +int +MHD_gtls_cipher_get_block_size (enum MHD_GNUTLS_CipherAlgorithm algorithm) +{ + size_t ret = 0; + GNUTLS_ALG_LOOP (ret = p->blocksize); + return ret; + +} + +/* returns the priority */ +int +MHD_gtls_cipher_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_CipherAlgorithm algorithm) +{ + unsigned int i; + for (i = 0; i < session->internals.priorities.cipher.num_algorithms; i++) + { + if (session->internals.priorities.cipher.priority[i] == algorithm) + return i; + } + return -1; +} + +int +MHD_gtls_cipher_is_block (enum MHD_GNUTLS_CipherAlgorithm algorithm) +{ + size_t ret = 0; + + GNUTLS_ALG_LOOP (ret = p->block); + return ret; + +} + +/** + * MHD__gnutls_cipher_get_key_size - Returns the length of the cipher's key size + * @algorithm: is an encryption algorithm + * + * Returns: length (in bytes) of the given cipher's key size, o 0 if + * the given cipher is invalid. + **/ +size_t +MHD__gnutls_cipher_get_key_size (enum MHD_GNUTLS_CipherAlgorithm algorithm) +{ /* In bytes */ + size_t ret = 0; + GNUTLS_ALG_LOOP (ret = p->keysize); + return ret; + +} + +int +MHD_gtls_cipher_get_iv_size (enum MHD_GNUTLS_CipherAlgorithm algorithm) +{ /* In bytes */ + size_t ret = 0; + GNUTLS_ALG_LOOP (ret = p->iv); + return ret; + +} + +int +MHD_gtls_cipher_get_export_flag (enum MHD_GNUTLS_CipherAlgorithm algorithm) +{ /* In bytes */ + size_t ret = 0; + GNUTLS_ALG_LOOP (ret = p->export_flag); + return ret; + +} + + +int +MHD_gtls_cipher_is_ok (enum MHD_GNUTLS_CipherAlgorithm algorithm) +{ + ssize_t ret = -1; + GNUTLS_ALG_LOOP (ret = p->id); + if (ret >= 0) + ret = 0; + else + ret = 1; + return ret; +} + +/* Key EXCHANGE functions */ +MHD_gtls_mod_auth_st * +MHD_gtls_kx_auth_struct (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm) +{ + MHD_gtls_mod_auth_st *ret = NULL; + GNUTLS_KX_ALG_LOOP (ret = p->auth_struct); + return ret; + +} + +int +MHD_gtls_kx_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm) +{ + unsigned int i; + for (i = 0; i < session->internals.priorities.kx.num_algorithms; i++) + { + if (session->internals.priorities.kx.priority[i] == algorithm) + return i; + } + return -1; +} + + +int +MHD_gtls_kx_is_ok (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm) +{ + ssize_t ret = -1; + GNUTLS_KX_ALG_LOOP (ret = p->algorithm); + if (ret >= 0) + ret = 0; + else + ret = 1; + return ret; +} + +int +MHD_gtls_kx_needs_rsa_params (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm) +{ + ssize_t ret = 0; + GNUTLS_KX_ALG_LOOP (ret = p->needs_rsa_params); + return ret; +} + +int +MHD_gtls_kx_needs_dh_params (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm) +{ + ssize_t ret = 0; + GNUTLS_KX_ALG_LOOP (ret = p->needs_dh_params); + return ret; +} + +/* Version */ +int +MHD_gtls_version_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_Protocol version) +{ /* actually returns the priority */ + unsigned int i; + + if (session->internals.priorities.protocol.priority == NULL) + { + MHD_gnutls_assert (); + return -1; + } + + for (i = 0; i < session->internals.priorities.protocol.num_algorithms; i++) + { + if (session->internals.priorities.protocol.priority[i] == version) + return i; + } + return -1; +} + + +enum MHD_GNUTLS_Protocol +MHD_gtls_version_max (MHD_gtls_session_t session) +{ /* returns the maximum version supported */ + unsigned int i, max = 0x00; + + if (session->internals.priorities.protocol.priority == NULL) + { + return MHD_GNUTLS_PROTOCOL_VERSION_UNKNOWN; + } + else + for (i = 0; i < session->internals.priorities.protocol.num_algorithms; + i++) + { + if (session->internals.priorities.protocol.priority[i] > max) + max = session->internals.priorities.protocol.priority[i]; + } + + if (max == 0x00) + return MHD_GNUTLS_PROTOCOL_VERSION_UNKNOWN; /* unknown version */ + + return max; +} + +int +MHD_gtls_version_get_minor (enum MHD_GNUTLS_Protocol version) +{ + int ret = -1; + + GNUTLS_VERSION_ALG_LOOP (ret = p->minor); + return ret; +} + +enum MHD_GNUTLS_Protocol +MHD_gtls_version_get (int major, int minor) +{ + int ret = -1; + + GNUTLS_VERSION_LOOP (if ((p->major == major) && (p->minor == minor)) + ret = p->id) + ; + return ret; +} + +int +MHD_gtls_version_get_major (enum MHD_GNUTLS_Protocol version) +{ + int ret = -1; + + GNUTLS_VERSION_ALG_LOOP (ret = p->major); + return ret; +} + +/* Version Functions */ + +int +MHD_gtls_version_is_supported (MHD_gtls_session_t session, + const enum MHD_GNUTLS_Protocol version) +{ + int ret = 0; + + GNUTLS_VERSION_ALG_LOOP (ret = p->supported); + if (ret == 0) + return 0; + + if (MHD_gtls_version_priority (session, version) < 0) + return 0; /* disabled by the user */ + else + return 1; +} + +enum MHD_GNUTLS_CredentialsType +MHD_gtls_map_kx_get_cred (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm, + int server) +{ + enum MHD_GNUTLS_CredentialsType ret = -1; + if (server) + { + GNUTLS_KX_MAP_LOOP (if (p->algorithm == algorithm) ret = p->server_type) + ; + } + else + { + GNUTLS_KX_MAP_LOOP (if (p->algorithm == algorithm) ret = p->client_type) + ; + } + + return ret; +} + +/* Cipher Suite's functions */ +enum MHD_GNUTLS_CipherAlgorithm +MHD_gtls_cipher_suite_get_cipher_algo (const cipher_suite_st * suite) +{ + int ret = 0; + GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->block_algorithm); + return ret; +} + +enum MHD_GNUTLS_Protocol +MHD_gtls_cipher_suite_get_version (const cipher_suite_st * suite) +{ + int ret = 0; + GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->version); + return ret; +} + +enum MHD_GNUTLS_KeyExchangeAlgorithm +MHD_gtls_cipher_suite_get_kx_algo (const cipher_suite_st * suite) +{ + int ret = 0; + + GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->kx_algorithm); + return ret; + +} + +enum MHD_GNUTLS_HashAlgorithm +MHD_gtls_cipher_suite_get_mac_algo (const cipher_suite_st * suite) +{ /* In bytes */ + int ret = 0; + GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->mac_algorithm); + return ret; + +} + +const char * +MHD_gtls_cipher_suite_get_name (cipher_suite_st * suite) +{ + const char *ret = NULL; + + /* avoid prefix */ + GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->name + sizeof ("GNUTLS_") - 1); + + return ret; +} + +static inline int +MHD__gnutls_cipher_suite_is_ok (cipher_suite_st * suite) +{ + size_t ret; + const char *name = NULL; + + GNUTLS_CIPHER_SUITE_ALG_LOOP (name = p->name); + if (name != NULL) + ret = 0; + else + ret = 1; + return ret; + +} + +#define SWAP(x, y) memcpy(tmp,x,size); \ + memcpy(x,y,size); \ + memcpy(y,tmp,size); + +#define MAX_ELEM_SIZE 4 +static inline int +MHD__gnutls_partition (MHD_gtls_session_t session, + void *_base, + size_t nmemb, + size_t size, + int (*compar) (MHD_gtls_session_t, + const void *, const void *)) +{ + uint8_t *base = _base; + uint8_t tmp[MAX_ELEM_SIZE]; + uint8_t ptmp[MAX_ELEM_SIZE]; + unsigned int pivot; + unsigned int i, j; + unsigned int full; + + i = pivot = 0; + j = full = (nmemb - 1) * size; + + memcpy (ptmp, &base[0], size); /* set pivot item */ + + while (i < j) + { + while ((compar (session, &base[i], ptmp) <= 0) && (i < full)) + { + i += size; + } + while ((compar (session, &base[j], ptmp) >= 0) && (j > 0)) + j -= size; + + if (i < j) + { + SWAP (&base[j], &base[i]); + } + } + + if (j > pivot) + { + SWAP (&base[pivot], &base[j]); + pivot = j; + } + else if (i < pivot) + { + SWAP (&base[pivot], &base[i]); + pivot = i; + } + return pivot / size; +} + +static void +MHD__gnutls_qsort (MHD_gtls_session_t session, + void *_base, + size_t nmemb, + size_t size, + int (*compar) (MHD_gtls_session_t, const void *, + const void *)) +{ + unsigned int pivot; + char *base = _base; + size_t snmemb = nmemb; + + if (snmemb <= 1) + return; + pivot = MHD__gnutls_partition (session, _base, nmemb, size, compar); + + MHD__gnutls_qsort (session, base, pivot < nmemb ? pivot + 1 + : pivot, size, compar); + MHD__gnutls_qsort (session, &base[(pivot + 1) * size], nmemb - pivot - 1, + size, compar); +} + +/* a compare function for KX algorithms (using priorities). + * For use with qsort + */ +static int +MHD__gnutls_compare_algo (MHD_gtls_session_t session, + const void *i_A1, const void *i_A2) +{ + enum MHD_GNUTLS_KeyExchangeAlgorithm kA1 = + MHD_gtls_cipher_suite_get_kx_algo ((const cipher_suite_st *) i_A1); + enum MHD_GNUTLS_KeyExchangeAlgorithm kA2 = + MHD_gtls_cipher_suite_get_kx_algo ((const cipher_suite_st *) i_A2); + enum MHD_GNUTLS_CipherAlgorithm cA1 = + MHD_gtls_cipher_suite_get_cipher_algo ((const cipher_suite_st *) i_A1); + enum MHD_GNUTLS_CipherAlgorithm cA2 = + MHD_gtls_cipher_suite_get_cipher_algo ((const cipher_suite_st *) i_A2); + enum MHD_GNUTLS_HashAlgorithm mA1 = + MHD_gtls_cipher_suite_get_mac_algo ((const cipher_suite_st *) i_A1); + enum MHD_GNUTLS_HashAlgorithm mA2 = + MHD_gtls_cipher_suite_get_mac_algo ((const cipher_suite_st *) i_A2); + + int p1 = (MHD_gtls_kx_priority (session, kA1) + 1) * 64; + int p2 = (MHD_gtls_kx_priority (session, kA2) + 1) * 64; + p1 += (MHD_gtls_cipher_priority (session, cA1) + 1) * 8; + p2 += (MHD_gtls_cipher_priority (session, cA2) + 1) * 8; + p1 += MHD_gtls_mac_priority (session, mA1); + p2 += MHD_gtls_mac_priority (session, mA2); + + if (p1 > p2) + { + return 1; + } + else + { + if (p1 == p2) + { + return 0; + } + return -1; + } +} + +int +MHD_gtls_supported_ciphersuites_sorted (MHD_gtls_session_t session, + cipher_suite_st ** ciphers) +{ + + int count; + + count = MHD_gtls_supported_ciphersuites (session, ciphers); + if (count <= 0) + { + MHD_gnutls_assert (); + return count; + } + MHD__gnutls_qsort (session, *ciphers, count, sizeof (cipher_suite_st), + MHD__gnutls_compare_algo); + + return count; +} + +int +MHD_gtls_supported_ciphersuites (MHD_gtls_session_t session, + cipher_suite_st ** _ciphers) +{ + + unsigned int i, ret_count, j; + unsigned int count = CIPHER_SUITES_COUNT; + cipher_suite_st *tmp_ciphers; + cipher_suite_st *ciphers; + enum MHD_GNUTLS_Protocol version; + + if (count == 0) + { + return 0; + } + + tmp_ciphers = MHD_gnutls_alloca (count * sizeof (cipher_suite_st)); + if (tmp_ciphers == NULL) + return GNUTLS_E_MEMORY_ERROR; + + ciphers = MHD_gnutls_malloc (count * sizeof (cipher_suite_st)); + if (ciphers == NULL) + { + MHD_gnutls_afree (tmp_ciphers); + return GNUTLS_E_MEMORY_ERROR; + } + + version = MHD__gnutls_protocol_get_version (session); + + for (i = 0; i < count; i++) + { + memcpy (&tmp_ciphers[i], &MHD_gtls_cs_algorithms[i].id, + sizeof (cipher_suite_st)); + } + + for (i = j = 0; i < count; i++) + { + /* remove private cipher suites, if requested. + */ + if (tmp_ciphers[i].suite[0] == 0xFF) + continue; + + /* remove cipher suites which do not support the + * protocol version used. + */ + if (MHD_gtls_cipher_suite_get_version (&tmp_ciphers[i]) > version) + continue; + + if (MHD_gtls_kx_priority (session, + MHD_gtls_cipher_suite_get_kx_algo + (&tmp_ciphers[i])) < 0) + continue; + if (MHD_gtls_mac_priority (session, + MHD_gtls_cipher_suite_get_mac_algo + (&tmp_ciphers[i])) < 0) + continue; + if (MHD_gtls_cipher_priority (session, + MHD_gtls_cipher_suite_get_cipher_algo + (&tmp_ciphers[i])) < 0) + continue; + + memcpy (&ciphers[j], &tmp_ciphers[i], sizeof (cipher_suite_st)); + j++; + } + + ret_count = j; + + MHD_gnutls_afree (tmp_ciphers); + + /* This function can no longer return 0 cipher suites. + * It returns an error code instead. + */ + if (ret_count == 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (ciphers); + return GNUTLS_E_NO_CIPHER_SUITES; + } + *_ciphers = ciphers; + return ret_count; +} + +/* For compression */ + +#define MIN_PRIVATE_COMP_ALGO 0xEF + +/* returns the TLS numbers of the compression methods we support + */ +#define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.num_algorithms +int +MHD_gtls_supported_compression_methods (MHD_gtls_session_t session, + uint8_t ** comp) +{ + unsigned int i, j; + + *comp = + MHD_gnutls_malloc (sizeof (uint8_t) * SUPPORTED_COMPRESSION_METHODS); + if (*comp == NULL) + return GNUTLS_E_MEMORY_ERROR; + + for (i = j = 0; i < SUPPORTED_COMPRESSION_METHODS; i++) + { + int tmp = + MHD_gtls_compression_get_num (session->internals.priorities. + compression.priority[i]); + + /* remove private compression algorithms, if requested. + */ + if (tmp == -1 || (tmp >= MIN_PRIVATE_COMP_ALGO)) + { + MHD_gnutls_assert (); + continue; + } + + (*comp)[j] = (uint8_t) tmp; + j++; + } + + if (j == 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (*comp); + *comp = NULL; + return GNUTLS_E_NO_COMPRESSION_ALGORITHMS; + } + return j; +} + +static const enum MHD_GNUTLS_CertificateType + MHD_gtls_supported_certificate_types[] = +{ MHD_GNUTLS_CRT_X509, + 0 +}; + + +/* returns the enum MHD_GNUTLS_PublicKeyAlgorithm which is compatible with + * the given enum MHD_GNUTLS_KeyExchangeAlgorithm. + */ +enum MHD_GNUTLS_PublicKeyAlgorithm +MHD_gtls_map_pk_get_pk (enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm) +{ + enum MHD_GNUTLS_PublicKeyAlgorithm ret = -1; + + GNUTLS_PK_MAP_ALG_LOOP (ret = p->pk_algorithm) return ret; +} + +/* Returns the encipher type for the given key exchange algorithm. + * That one of CIPHER_ENCRYPT, CIPHER_SIGN, CIPHER_IGN. + * + * ex. GNUTLS_KX_RSA requires a certificate able to encrypt... so returns CIPHER_ENCRYPT. + */ +enum encipher_type +MHD_gtls_kx_encipher_type (enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm) +{ + int ret = CIPHER_IGN; + GNUTLS_PK_MAP_ALG_LOOP (ret = p->encipher_type) return ret; + +} + +/* signature algorithms; + */ +struct MHD_gnutls_sign_entry +{ + const char *name; + const char *oid; + MHD_gnutls_sign_algorithm_t id; + enum MHD_GNUTLS_PublicKeyAlgorithm pk; + enum MHD_GNUTLS_HashAlgorithm mac; +}; +typedef struct MHD_gnutls_sign_entry MHD_gnutls_sign_entry; + +static const MHD_gnutls_sign_entry MHD_gtls_sign_algorithms[] = { + {"RSA-SHA", + SIG_RSA_SHA1_OID, + GNUTLS_SIGN_RSA_SHA1, + MHD_GNUTLS_PK_RSA, + MHD_GNUTLS_MAC_SHA1}, + {"RSA-SHA256", + SIG_RSA_SHA256_OID, + GNUTLS_SIGN_RSA_SHA256, + MHD_GNUTLS_PK_RSA, + MHD_GNUTLS_MAC_SHA256}, + {"RSA-MD5", + SIG_RSA_MD5_OID, + GNUTLS_SIGN_RSA_MD5, + MHD_GNUTLS_PK_RSA, + MHD_GNUTLS_MAC_MD5}, + {"GOST R 34.10-2001", + SIG_GOST_R3410_2001_OID, + 0, + 0, + 0}, + {"GOST R 34.10-94", + SIG_GOST_R3410_94_OID, + 0, + 0, + 0}, + {0, + 0, + 0, + 0, + 0} +}; + +#define GNUTLS_SIGN_LOOP(b) \ + do { \ + const MHD_gnutls_sign_entry *p; \ + for(p = MHD_gtls_sign_algorithms; p->name != NULL; p++) { b ; } \ + } while (0) + +#define GNUTLS_SIGN_ALG_LOOP(a) \ + GNUTLS_SIGN_LOOP( if(p->id && p->id == sign) { a; break; } ) + +/* pk algorithms; + */ +struct MHD_gnutls_pk_entry +{ + const char *name; + const char *oid; + enum MHD_GNUTLS_PublicKeyAlgorithm id; +}; +typedef struct MHD_gnutls_pk_entry MHD_gnutls_pk_entry; + +static const MHD_gnutls_pk_entry MHD_gtls_pk_algorithms[] = { + {"RSA", + PK_PKIX1_RSA_OID, + MHD_GNUTLS_PK_RSA}, + {"GOST R 34.10-2001", + PK_GOST_R3410_2001_OID, + 0}, + {"GOST R 34.10-94", + PK_GOST_R3410_94_OID, + 0}, + {0, + 0, + 0} +}; + +enum MHD_GNUTLS_PublicKeyAlgorithm +MHD_gtls_x509_oid2pk_algorithm (const char *oid) +{ + enum MHD_GNUTLS_PublicKeyAlgorithm ret = MHD_GNUTLS_PK_UNKNOWN; + const MHD_gnutls_pk_entry *p; + + for (p = MHD_gtls_pk_algorithms; p->name != NULL; p++) + if (strcmp (p->oid, oid) == 0) + { + ret = p->id; + break; + } + + return ret; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_algorithms.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_algorithms.h new file mode 100644 index 0000000000..6a4021c7b3 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_algorithms.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef ALGORITHMS_H +#define ALGORITHMS_H + +#include "gnutls_auth.h" + +/* Functions for version handling. */ +enum MHD_GNUTLS_Protocol MHD_gtls_version_max (MHD_gtls_session_t session); +int MHD_gtls_version_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_Protocol version); +int MHD_gtls_version_is_supported (MHD_gtls_session_t session, + const enum MHD_GNUTLS_Protocol version); +int MHD_gtls_version_get_major (enum MHD_GNUTLS_Protocol ver); +int MHD_gtls_version_get_minor (enum MHD_GNUTLS_Protocol ver); +enum MHD_GNUTLS_Protocol MHD_gtls_version_get (int major, int minor); + +/* Functions for MACs. */ +int MHD_gnutls_mac_is_ok (enum MHD_GNUTLS_HashAlgorithm algorithm); +/* Functions for cipher suites. */ +int MHD_gtls_supported_ciphersuites (MHD_gtls_session_t session, + cipher_suite_st ** ciphers); +int MHD_gtls_supported_ciphersuites_sorted (MHD_gtls_session_t session, + cipher_suite_st ** ciphers); +int MHD_gtls_supported_compression_methods (MHD_gtls_session_t session, + uint8_t ** comp); +const char *MHD_gtls_cipher_suite_get_name (cipher_suite_st * algorithm); +enum MHD_GNUTLS_CipherAlgorithm MHD_gtls_cipher_suite_get_cipher_algo (const + cipher_suite_st + * + algorithm); +enum MHD_GNUTLS_KeyExchangeAlgorithm MHD_gtls_cipher_suite_get_kx_algo (const + cipher_suite_st + * + algorithm); +enum MHD_GNUTLS_HashAlgorithm MHD_gtls_cipher_suite_get_mac_algo (const + cipher_suite_st + * + algorithm); +enum MHD_GNUTLS_Protocol MHD_gtls_cipher_suite_get_version (const + cipher_suite_st * + algorithm); +cipher_suite_st MHD_gtls_cipher_suite_get_suite_name (cipher_suite_st * + algorithm); + +/* Functions for ciphers. */ +int MHD_gtls_cipher_get_block_size (enum MHD_GNUTLS_CipherAlgorithm + algorithm); +int MHD_gtls_cipher_is_block (enum MHD_GNUTLS_CipherAlgorithm algorithm); +int MHD_gtls_cipher_is_ok (enum MHD_GNUTLS_CipherAlgorithm algorithm); +int MHD_gtls_cipher_get_iv_size (enum MHD_GNUTLS_CipherAlgorithm algorithm); +int MHD_gtls_cipher_get_export_flag (enum MHD_GNUTLS_CipherAlgorithm + algorithm); + +/* Functions for key exchange. */ +int MHD_gtls_kx_needs_dh_params (enum MHD_GNUTLS_KeyExchangeAlgorithm + algorithm); +int MHD_gtls_kx_needs_rsa_params (enum MHD_GNUTLS_KeyExchangeAlgorithm + algorithm); +MHD_gtls_mod_auth_st *MHD_gtls_kx_auth_struct (enum + MHD_GNUTLS_KeyExchangeAlgorithm + algorithm); +int MHD_gtls_kx_is_ok (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm); + +/* Functions for compression. */ +int MHD_gtls_compression_is_ok (enum MHD_GNUTLS_CompressionMethod algorithm); +int MHD_gtls_compression_get_num (enum MHD_GNUTLS_CompressionMethod + algorithm); +enum MHD_GNUTLS_CompressionMethod MHD_gtls_compression_get_id_from_int (int + num); +int MHD_gtls_compression_get_mem_level (enum MHD_GNUTLS_CompressionMethod + algorithm); +int MHD_gtls_compression_get_comp_level (enum MHD_GNUTLS_CompressionMethod + algorithm); +int MHD_gtls_compression_get_wbits (enum MHD_GNUTLS_CompressionMethod + algorithm); + +/* Type to KX mappings. */ +enum MHD_GNUTLS_CredentialsType MHD_gtls_map_kx_get_cred (enum + MHD_GNUTLS_KeyExchangeAlgorithm + algorithm, + int server); + +/* KX to PK mapping. */ +enum MHD_GNUTLS_PublicKeyAlgorithm MHD_gtls_map_pk_get_pk (enum + MHD_GNUTLS_KeyExchangeAlgorithm + kx_algorithm); +enum MHD_GNUTLS_PublicKeyAlgorithm MHD_gtls_x509_oid2pk_algorithm (const char + *oid); +enum encipher_type +{ CIPHER_ENCRYPT = 0, CIPHER_SIGN = 1, CIPHER_IGN }; + +enum encipher_type MHD_gtls_kx_encipher_type (enum + MHD_GNUTLS_KeyExchangeAlgorithm + algorithm); + +struct MHD_gtls_compression_entry +{ + const char *name; + enum MHD_GNUTLS_CompressionMethod id; + int num; /* the number reserved in TLS for the specific compression method */ + + /* used in zlib compressor */ + int window_bits; + int mem_level; + int comp_level; +}; +typedef struct MHD_gtls_compression_entry MHD_gnutls_compression_entry; + +/* Functions for sign algorithms. */ + +int MHD_gtls_mac_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_HashAlgorithm algorithm); +int MHD_gtls_cipher_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_CipherAlgorithm algorithm); +int MHD_gtls_kx_priority (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm); + +enum MHD_GNUTLS_HashAlgorithm MHD_gtls_mac_get_id (const char *name); +enum MHD_GNUTLS_CipherAlgorithm MHD_gtls_cipher_get_id (const char *name); +enum MHD_GNUTLS_KeyExchangeAlgorithm MHD_gtls_kx_get_id (const char *name); +enum MHD_GNUTLS_Protocol MHD_gtls_protocol_get_id (const char *name); +enum MHD_GNUTLS_CertificateType MHD_gtls_certificate_type_get_id (const char + *name); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_asn1_tab.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_asn1_tab.c new file mode 100644 index 0000000000..9b51152124 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_asn1_tab.c @@ -0,0 +1,63 @@ +#if HAVE_CONFIG_H +#include "MHD_config.h" +#endif + +#include <libtasn1.h> + +const ASN1_ARRAY_TYPE MHD_gnutlsMHD__asn1_tab[] = { + {"GNUTLS", 536872976, 0}, + {0, 1073741836, 0}, + {"RSAPublicKey", 1610612741, 0}, + {"modulus", 1073741827, 0}, + {"publicExponent", 3, 0}, + {"RSAPrivateKey", 1610612741, 0}, + {"version", 1073741826, "Version"}, + {"modulus", 1073741827, 0}, + {"publicExponent", 1073741827, 0}, + {"privateExponent", 1073741827, 0}, + {"prime1", 1073741827, 0}, + {"prime2", 1073741827, 0}, + {"exponent1", 1073741827, 0}, + {"exponent2", 1073741827, 0}, + {"coefficient", 1073741827, 0}, + {"otherPrimeInfos", 16386, "OtherPrimeInfos"}, + {"Version", 1610874883, 0}, + {"two-prime", 1073741825, "0"}, + {"multi", 1, "1"}, + {"OtherPrimeInfos", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "OtherPrimeInfo"}, + {"OtherPrimeInfo", 1610612741, 0}, + {"prime", 1073741827, 0}, + {"exponent", 1073741827, 0}, + {"coefficient", 3, 0}, + {"AlgorithmIdentifier", 1610612741, 0}, + {"algorithm", 1073741836, 0}, + {"parameters", 541081613, 0}, + {"algorithm", 1, 0}, + {"DigestInfo", 1610612741, 0}, + {"digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"}, + {"digest", 2, "Digest"}, + {"DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, + {"Digest", 1073741831, 0}, + {"DSAPublicKey", 1073741827, 0}, + {"DSAParameters", 1610612741, 0}, + {"p", 1073741827, 0}, + {"q", 1073741827, 0}, + {"g", 3, 0}, + {"DSASignatureValue", 1610612741, 0}, + {"r", 1073741827, 0}, + {"s", 3, 0}, + {"DSAPrivateKey", 1610612741, 0}, + {"version", 1073741827, 0}, + {"p", 1073741827, 0}, + {"q", 1073741827, 0}, + {"g", 1073741827, 0}, + {"Y", 1073741827, 0}, + {"priv", 3, 0}, + {"DHParameter", 536870917, 0}, + {"prime", 1073741827, 0}, + {"base", 1073741827, 0}, + {"privateValueLength", 16387, 0}, + {0, 0, 0} +}; diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth.c new file mode 100644 index 0000000000..7c820c4e66 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "gnutls_auth.h" +#include "gnutls_auth_int.h" +#include "gnutls_algorithms.h" +#include "auth_cert.h" +#include <gnutls_datum.h> + +/* The functions here are used in order for authentication algorithms + * to be able to retrieve the needed credentials eg public and private + * key etc. + */ + +/** + * MHD__gnutls_credentials_clear - Clears all the credentials previously set + * @session: is a #MHD_gtls_session_t structure. + * + * Clears all the credentials previously set in this session. + * + **/ +void +MHD__gnutls_credentials_clear (MHD_gtls_session_t session) +{ + if (session->key && session->key->cred) + { /* beginning of the list */ + auth_cred_st *ccred, *ncred; + ccred = session->key->cred; + while (ccred != NULL) + { + ncred = ccred->next; + MHD_gnutls_free (ccred); + ccred = ncred; + } + session->key->cred = NULL; + } +} + +/* + * This creates a linked list of the form: + * { algorithm, credentials, pointer to next } + */ +/** + * MHD__gnutls_credentials_set - Sets the needed credentials for the specified authentication algorithm. + * @session: is a #MHD_gtls_session_t structure. + * @type: is the type of the credentials + * @cred: is a pointer to a structure. + * + * Sets the needed credentials for the specified type. + * Eg username, password - or public and private keys etc. + * The (void* cred) parameter is a structure that depends on the + * specified type and on the current session (client or server). + * [ In order to minimize memory usage, and share credentials between + * several threads gnutls keeps a pointer to cred, and not the whole cred + * structure. Thus you will have to keep the structure allocated until + * you call MHD__gnutls_deinit(). ] + * + * For GNUTLS_CRD_SRP cred should be MHD_gnutls_srp_client_credentials_t + * in case of a client, and MHD_gnutls_srp_server_credentials_t, in case + * of a server. + * + * For GNUTLS_CRD_CERTIFICATE cred should be MHD_gtls_cert_credentials_t. + * + **/ +int +MHD__gnutls_credentials_set (MHD_gtls_session_t session, + enum MHD_GNUTLS_CredentialsType type, void *cred) +{ + auth_cred_st *ccred = NULL, *pcred = NULL; + int exists = 0; + + if (session->key->cred == NULL) + { /* beginning of the list */ + + session->key->cred = MHD_gnutls_malloc (sizeof (auth_cred_st)); + if (session->key->cred == NULL) + return GNUTLS_E_MEMORY_ERROR; + + /* copy credentials locally */ + session->key->cred->credentials = cred; + + session->key->cred->next = NULL; + session->key->cred->algorithm = type; + } + else + { + ccred = session->key->cred; + while (ccred != NULL) + { + if (ccred->algorithm == type) + { + exists = 1; + break; + } + pcred = ccred; + ccred = ccred->next; + } + /* After this, pcred is not null. + */ + + if (exists == 0) + { /* new entry */ + pcred->next = MHD_gnutls_malloc (sizeof (auth_cred_st)); + if (pcred->next == NULL) + return GNUTLS_E_MEMORY_ERROR; + + ccred = pcred->next; + + /* copy credentials locally */ + ccred->credentials = cred; + + ccred->next = NULL; + ccred->algorithm = type; + } + else + { /* modify existing entry */ + MHD_gnutls_free (ccred->credentials); + ccred->credentials = cred; + } + } + + return 0; +} + +/** + * MHD_gtls_auth_get_type - Returns the type of credentials for the current authentication schema. + * @session: is a #MHD_gtls_session_t structure. + * + * Returns type of credentials for the current authentication schema. + * The returned information is to be used to distinguish the function used + * to access authentication data. + * + * Eg. for CERTIFICATE ciphersuites (key exchange algorithms: KX_RSA, KX_DHE_RSA), + * the same function are to be used to access the authentication data. + **/ +enum MHD_GNUTLS_CredentialsType +MHD_gtls_auth_get_type (MHD_gtls_session_t session) +{ +/* This is not the credentials we must set, but the authentication data + * we get by the peer, so it should be reversed. + */ + int server = session->security_parameters.entity == GNUTLS_SERVER ? 0 : 1; + + return + MHD_gtls_map_kx_get_cred (MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters. + current_cipher_suite), server); +} + +/* + * This returns a pointer to the linked list. Don't + * free that!!! + */ +const void * +MHD_gtls_get_kx_cred (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm algo, int *err) +{ + int server = session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0; + + return MHD_gtls_get_cred (session->key, + MHD_gtls_map_kx_get_cred (algo, server), err); +} + +const void * +MHD_gtls_get_cred (MHD_gtls_key_st key, enum MHD_GNUTLS_CredentialsType type, + int *err) +{ + const void *retval = NULL; + int _err = -1; + auth_cred_st *ccred; + + if (key == NULL) + goto out; + + ccred = key->cred; + while (ccred != NULL) + { + if (ccred->algorithm == type) + { + break; + } + ccred = ccred->next; + } + if (ccred == NULL) + goto out; + + _err = 0; + retval = ccred->credentials; + +out: + if (err != NULL) + *err = _err; + return retval; +} + +/*- + * MHD_gtls_get_auth_info - Returns a pointer to authentication information. + * @session: is a #MHD_gtls_session_t structure. + * + * This function must be called after a succesful MHD__gnutls_handshake(). + * Returns a pointer to authentication information. That information + * is data obtained by the handshake protocol, the key exchange algorithm, + * and the TLS extensions messages. + * + * In case of GNUTLS_CRD_CERTIFICATE returns a type of &cert_auth_info_t; + * In case of GNUTLS_CRD_SRP returns a type of &srp_(server/client)_auth_info_t; + -*/ +void * +MHD_gtls_get_auth_info (MHD_gtls_session_t session) +{ + return session->key->auth_info; +} + +/*- + * MHD_gtls_free_auth_info - Frees the auth info structure + * @session: is a #MHD_gtls_session_t structure. + * + * This function frees the auth info structure and sets it to + * null. It must be called since some structures contain malloced + * elements. + -*/ +void +MHD_gtls_free_auth_info (MHD_gtls_session_t session) +{ + MHD_gtls_dh_info_st *dh_info; + rsa_info_st *rsa_info; + + if (session == NULL || session->key == NULL) + { + MHD_gnutls_assert (); + return; + } + + switch (session->key->auth_info_type) + { + case MHD_GNUTLS_CRD_CERTIFICATE: + { + unsigned int i; + cert_auth_info_t info = MHD_gtls_get_auth_info (session); + + if (info == NULL) + break; + + dh_info = &info->dh; + rsa_info = &info->rsa_export; + for (i = 0; i < info->ncerts; i++) + { + MHD__gnutls_free_datum (&info->raw_certificate_list[i]); + } + + MHD_gnutls_free (info->raw_certificate_list); + info->raw_certificate_list = NULL; + info->ncerts = 0; + + MHD_gtls_free_dh_info (dh_info); + MHD_gtls_free_rsa_info (rsa_info); + } + + + break; + default: + return; + + } + + MHD_gnutls_free (session->key->auth_info); + session->key->auth_info = NULL; + session->key->auth_info_size = 0; + session->key->auth_info_type = 0; + +} + +/* This function will set the auth info structure in the key + * structure. + * If allow change is !=0 then this will allow changing the auth + * info structure to a different type. + */ +int +MHD_gtls_auth_info_set (MHD_gtls_session_t session, + enum MHD_GNUTLS_CredentialsType type, int size, + int allow_change) +{ + if (session->key->auth_info == NULL) + { + session->key->auth_info = MHD_gnutls_calloc (1, size); + if (session->key->auth_info == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + session->key->auth_info_type = type; + session->key->auth_info_size = size; + } + else + { + if (allow_change == 0) + { + /* If the credentials for the current authentication scheme, + * are not the one we want to set, then it's an error. + * This may happen if a rehandshake is performed an the + * ciphersuite which is negotiated has different authentication + * schema. + */ + if (MHD_gtls_auth_get_type (session) != + session->key->auth_info_type) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + } + else + { + /* The new behaviour: Here we reallocate the auth info structure + * in order to be able to negotiate different authentication + * types. Ie. perform an auth_anon and then authenticate again using a + * certificate (in order to prevent revealing the certificate's contents, + * to passive eavesdropers. + */ + if (MHD_gtls_auth_get_type (session) != + session->key->auth_info_type) + { + + MHD_gtls_free_auth_info (session); + + session->key->auth_info = calloc (1, size); + if (session->key->auth_info == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + session->key->auth_info_type = type; + session->key->auth_info_size = size; + } + } + } + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth.h new file mode 100644 index 0000000000..4956268cc8 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_AUTH_H +#define GNUTLS_AUTH_H + +typedef struct MHD_gtls_mod_auth_st_int +{ + const char *name; /* null terminated */ + int (*MHD_gtls_gen_server_certificate) (MHD_gtls_session_t, opaque **); + int (*MHD_gtls_gen_client_certificate) (MHD_gtls_session_t, opaque **); + int (*MHD_gtls_gen_server_kx) (MHD_gtls_session_t, opaque **); + int (*MHD_gtls_gen_client_kx) (MHD_gtls_session_t, opaque **); /* used in SRP */ + int (*MHD_gtls_gen_client_cert_vrfy) (MHD_gtls_session_t, opaque **); + int (*MHD_gtls_gen_server_certificate_request) (MHD_gtls_session_t, + opaque **); + + int (*MHD_gtls_process_server_certificate) (MHD_gtls_session_t, opaque *, + size_t); + int (*MHD_gtls_process_client_certificate) (MHD_gtls_session_t, opaque *, + size_t); + int (*MHD_gtls_process_server_kx) (MHD_gtls_session_t, opaque *, size_t); + int (*MHD_gtls_process_client_kx) (MHD_gtls_session_t, opaque *, size_t); + int (*MHD_gtls_process_client_cert_vrfy) (MHD_gtls_session_t, opaque *, + size_t); + int (*MHD_gtls_process_server_certificate_request) (MHD_gtls_session_t, + opaque *, size_t); +} MHD_gtls_mod_auth_st; + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth_int.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth_int.h new file mode 100644 index 0000000000..425dc8a318 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_auth_int.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +const void *MHD_gtls_get_cred (MHD_gtls_key_st key, + enum MHD_GNUTLS_CredentialsType kx, int *err); +const void *MHD_gtls_get_kx_cred (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm algo, + int *err); +void *MHD_gtls_get_auth_info (MHD_gtls_session_t session); +int MHD_gtls_auth_info_set (MHD_gtls_session_t session, + enum MHD_GNUTLS_CredentialsType type, int size, + int allow_change); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_buffers.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_buffers.c new file mode 100644 index 0000000000..c687cb2313 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_buffers.c @@ -0,0 +1,1111 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This is the only file that uses the berkeley sockets API. + * + * Also holds all the buffering code used in gnutls. + * The buffering code works as: + * + * RECORD LAYER: + * 1. uses a buffer to hold data (application/handshake), + * we got but they were not requested, yet. + * (see MHD_gnutls_record_buffer_put(), MHD_gnutls_record_buffer_get_size() etc.) + * + * 2. uses a buffer to hold data that were incomplete (ie the read/write + * was interrupted) + * (see MHD_gtls_io_read_buffered(), MHD_gtls_io_write_buffered() etc.) + * + * HANDSHAKE LAYER: + * 1. Uses a buffer to hold data that was not sent or received + * complete. (E.g. sent 10 bytes of a handshake packet that is 20 bytes + * long). + * (see MHD__gnutls_handshake_send_int(), MHD__gnutls_handshake_recv_int()) + * + * 2. Uses buffer to hold the last received handshake message. + * (see MHD_gtls_handshake_buffer_put() etc.) + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_num.h> +#include <gnutls_record.h> +#include <gnutls_buffers.h> + +#include <errno.h> + +#ifdef _WIN32 +# include <winsock2.h> +#endif + +#ifndef EAGAIN +# define EAGAIN EWOULDBLOCK +#endif + +/* Buffers received packets of type APPLICATION DATA and + * HANDSHAKE DATA. + */ +int +MHD_gnutls_record_buffer_put (content_type_t type, + MHD_gtls_session_t session, opaque * data, + size_t length) +{ + MHD_gtls_buffer *buf; + + if (length == 0) + return 0; + + switch (type) + { + case GNUTLS_APPLICATION_DATA: + buf = &session->internals.application_data_buffer; + MHD__gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n", + length, type); + break; + + case GNUTLS_HANDSHAKE: + buf = &session->internals.handshake_data_buffer; + MHD__gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n", + length, type); + break; + + case GNUTLS_INNER_APPLICATION: + buf = &session->internals.ia_data_buffer; + MHD__gnutls_buffers_log ("BUF[IA]: Inserted %d bytes of Data(%d)\n", + length, type); + break; + + default: + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + if (MHD_gtls_buffer_append (buf, data, length) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; +} + +int +MHD_gnutls_record_buffer_get_size (content_type_t type, + MHD_gtls_session_t session) +{ + switch (type) + { + case GNUTLS_APPLICATION_DATA: + return session->internals.application_data_buffer.length; + + case GNUTLS_HANDSHAKE: + return session->internals.handshake_data_buffer.length; + + case GNUTLS_INNER_APPLICATION: + return session->internals.ia_data_buffer.length; + + default: + return GNUTLS_E_INVALID_REQUEST; + } +} + +int +MHD_gtls_record_buffer_get (content_type_t type, MHD_gtls_session_t session, + opaque * data, size_t length) +{ + if (length == 0 || data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + switch (type) + { + case GNUTLS_APPLICATION_DATA: + + if (length > session->internals.application_data_buffer.length) + { + length = session->internals.application_data_buffer.length; + } + + MHD__gnutls_buffers_log ("BUFFER[REC][AD]: Read %d bytes of Data(%d)\n", + length, type); + + session->internals.application_data_buffer.length -= length; + memcpy (data, session->internals.application_data_buffer.data, length); + + /* overwrite buffer */ + memmove (session->internals.application_data_buffer.data, + &session->internals.application_data_buffer.data[length], + session->internals.application_data_buffer.length); + + /* we do no longer realloc the application_data_buffer.data, + * since it serves no practical reason. It also decreases + * performance. + */ + break; + + case GNUTLS_HANDSHAKE: + if (length > session->internals.handshake_data_buffer.length) + { + length = session->internals.handshake_data_buffer.length; + } + + MHD__gnutls_buffers_log ("BUF[REC][HD]: Read %d bytes of Data(%d)\n", + length, type); + + session->internals.handshake_data_buffer.length -= length; + memcpy (data, session->internals.handshake_data_buffer.data, length); + + /* overwrite buffer */ + memmove (session->internals.handshake_data_buffer.data, + &session->internals.handshake_data_buffer.data[length], + session->internals.handshake_data_buffer.length); + + break; + + case GNUTLS_INNER_APPLICATION: + if (length > session->internals.ia_data_buffer.length) + length = session->internals.ia_data_buffer.length; + + MHD__gnutls_buffers_log ("BUF[REC][IA]: Read %d bytes of Data(%d)\n", + length, type); + + session->internals.ia_data_buffer.length -= length; + memcpy (data, session->internals.ia_data_buffer.data, length); + + /* overwrite buffer */ + memmove (session->internals.ia_data_buffer.data, + &session->internals.ia_data_buffer.data[length], + session->internals.ia_data_buffer.length); + + break; + + default: + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + return length; +} + +/* This function is like read. But it does not return -1 on error. + * It does return MHD_gnutls_errno instead. + * + * Flags are only used if the default recv() function is being used. + */ +static ssize_t +MHD__gnutls_read (MHD_gtls_session_t session, void *iptr, + size_t sizeOfPtr, int flags) +{ + size_t left; + ssize_t i = 0; + char *ptr = iptr; + MHD_gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr; + + session->internals.direction = 0; + + left = sizeOfPtr; + while (left > 0) + { + session->internals.errnum = 0; + if (session->internals.MHD__gnutls_pull_func == NULL) + { + i = + recv (GNUTLS_POINTER_TO_INT (fd), &ptr[sizeOfPtr - left], left, + flags); +#if HAVE_WINSOCK + if (i < 0) + { + int tmperr = WSAGetLastError (); + switch (tmperr) + { + case WSAEWOULDBLOCK: + session->internals.errnum = EAGAIN; + break; + + case WSAEINTR: + session->internals.errnum = EINTR; + break; + + default: + session->internals.errnum = EIO; + break; + } + WSASetLastError (tmperr); + } +#endif + } + else + i = session->internals.MHD__gnutls_pull_func (fd, + &ptr[sizeOfPtr - left], + left); + if (i < 0) + { + int err = session->internals.errnum ? session->internals.errnum + : errno; + if ( (err == EAGAIN) || (err == EINTR) ) + { + if (sizeOfPtr - left > 0) + goto finish; + MHD_gnutls_assert (); + if (err == EAGAIN) + return GNUTLS_E_AGAIN; + return GNUTLS_E_INTERRUPTED; + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_PULL_ERROR; + } + } + else + { + if (i == 0) + break; /* EOF */ + } + left -= i; + } + +finish: + return (sizeOfPtr - left); +} + +#define RCVLOWAT session->internals.lowat + +/* This function is only used with berkeley style sockets. + * Clears the peeked data (read with MSG_PEEK). + */ +int +MHD_gtls_io_clear_peeked_data (MHD_gtls_session_t session) +{ + char *peekdata; + int ret, sum; + + if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0) + return 0; + + peekdata = MHD_gnutls_alloca (RCVLOWAT); + if (peekdata == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + /* this was already read by using MSG_PEEK - so it shouldn't fail */ + sum = 0; + do + { /* we need this to finish now */ + ret = MHD__gnutls_read (session, peekdata, RCVLOWAT - sum, 0); + if (ret > 0) + sum += ret; + } + while ( (ret == GNUTLS_E_INTERRUPTED) || + (ret == GNUTLS_E_AGAIN) || + (sum < RCVLOWAT) ); + + MHD_gnutls_afree (peekdata); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + session->internals.have_peeked_data = 0; + + return 0; +} + +void +MHD_gtls_io_clear_read_buffer (MHD_gtls_session_t session) +{ + session->internals.record_recv_buffer.length = 0; +} + +/* This function is like recv(with MSG_PEEK). But it does not return -1 on error. + * It does return MHD_gnutls_errno instead. + * This function reads data from the socket and keeps them in a buffer, of up to + * MAX_RECV_SIZE. + * + * This is not a general purpose function. It returns EXACTLY the data requested, + * which are stored in a local (in the session) buffer. A pointer (iptr) to this buffer is returned. + * + */ +ssize_t +MHD_gtls_io_read_buffered (MHD_gtls_session_t session, opaque ** iptr, + size_t sizeOfPtr, content_type_t recv_type) +{ + ssize_t ret = 0, ret2 = 0; + size_t min; + int buf_pos; + opaque *buf; + int recvlowat; + int recvdata, alloc_size; + + *iptr = session->internals.record_recv_buffer.data; + + if (sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0) + { + MHD_gnutls_assert (); /* internal error */ + return GNUTLS_E_INVALID_REQUEST; + } + + /* If an external pull function is used, then do not leave + * any data into the kernel buffer. + */ + if (session->internals.MHD__gnutls_pull_func != NULL) + { + recvlowat = 0; + } + else + { + /* leave peeked data to the kernel space only if application data + * is received and we don't have any peeked + * data in gnutls session. + */ + if (recv_type != GNUTLS_APPLICATION_DATA + && session->internals.have_peeked_data == 0) + recvlowat = 0; + else + recvlowat = RCVLOWAT; + } + + /* calculate the actual size, ie. get the minimum of the + * buffered data and the requested data. + */ + min = MIN (session->internals.record_recv_buffer.length, sizeOfPtr); + if (min > 0) + { + /* if we have enough buffered data + * then just return them. + */ + if (min == sizeOfPtr) + { + return min; + } + } + + /* min is over zero. recvdata is the data we must + * receive in order to return the requested data. + */ + recvdata = sizeOfPtr - min; + + /* Check if the previously read data plus the new data to + * receive are longer than the maximum receive buffer size. + */ + if ((session->internals.record_recv_buffer.length + recvdata) + > MAX_RECV_SIZE) + { + MHD_gnutls_assert (); /* internal error */ + return GNUTLS_E_INVALID_REQUEST; + } + + /* Allocate the data required to store the new packet. + */ + alloc_size = recvdata + session->internals.record_recv_buffer.length; + session->internals.record_recv_buffer.data = + MHD_gtls_realloc_fast (session->internals.record_recv_buffer.data, + alloc_size); + if (session->internals.record_recv_buffer.data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + buf_pos = session->internals.record_recv_buffer.length; + buf = session->internals.record_recv_buffer.data; + *iptr = buf; + + /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer. */ + if (recvdata - recvlowat > 0) + { + ret = + MHD__gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 0); + + /* return immediately if we got an interrupt or eagain + * error. + */ + if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0) + { + return ret; + } + } + + /* copy fresh data to our buffer. + */ + if (ret > 0) + { + MHD__gnutls_read_log + ("RB: Have %d bytes into buffer. Adding %d bytes.\n", + session->internals.record_recv_buffer.length, ret); + MHD__gnutls_read_log ("RB: Requested %d bytes\n", sizeOfPtr); + session->internals.record_recv_buffer.length += ret; + } + + buf_pos = session->internals.record_recv_buffer.length; + + /* This is a hack placed in order for select to work. Just leave recvlowat data, + * into the kernel buffer (using a read with MSG_PEEK), thus making + * select think, that the socket is ready for reading. + * MSG_PEEK is only used with berkeley style sockets. + */ + if (ret == (recvdata - recvlowat) && recvlowat > 0) + { + ret2 = MHD__gnutls_read (session, &buf[buf_pos], recvlowat, MSG_PEEK); + + if (ret2 < 0 && MHD_gtls_error_is_fatal (ret2) == 0) + { + return ret2; + } + + if (ret2 > 0) + { + MHD__gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n", + ret2); + MHD__gnutls_read_log + ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n", + session->internals.record_recv_buffer.length, ret2, sizeOfPtr); + session->internals.have_peeked_data = 1; + session->internals.record_recv_buffer.length += ret2; + + } + } + + if (ret < 0 || ret2 < 0) + { + MHD_gnutls_assert (); + /* that's because they are initialized to 0 */ + return MIN (ret, ret2); + } + + ret += ret2; + + if (ret > 0 && ret < recvlowat) + { + MHD_gnutls_assert (); + return GNUTLS_E_AGAIN; + } + + if (ret == 0) + { /* EOF */ + MHD_gnutls_assert (); + return 0; + } + + ret = session->internals.record_recv_buffer.length; + + if ((ret > 0) && ((size_t) ret < sizeOfPtr)) + { + /* Short Read */ + MHD_gnutls_assert (); + return GNUTLS_E_AGAIN; + } + else + { + return ret; + } +} + +/* These two functions are used to insert data to the send buffer of the handshake or + * record protocol. The send buffer is kept if a send is interrupted and we need to keep + * the data left to sent, in order to send them later. + */ + +#define MEMSUB(x,y) ((ssize_t)((ptrdiff_t)x-(ptrdiff_t)y)) + +inline static int +MHD__gnutls_buffer_insert (MHD_gtls_buffer * buffer, + const opaque * _data, size_t data_size) +{ + + if ((MEMSUB (_data, buffer->data) >= 0) + && (MEMSUB (_data, buffer->data) < (ssize_t) buffer->length)) + { + /* the given _data is part of the buffer. + */ + if (data_size > buffer->length) + { + MHD_gnutls_assert (); + /* this shouldn't have happened */ + return GNUTLS_E_INTERNAL_ERROR; + } + + if (_data == buffer->data) + { /* then don't even memmove */ + buffer->length = data_size; + return 0; + } + + memmove (buffer->data, _data, data_size); + buffer->length = data_size; + + return 0; + + } + + if (MHD_gtls_buffer_append (buffer, _data, data_size) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; +} + +inline static int +MHD__gnutls_buffer_get (MHD_gtls_buffer * buffer, + const opaque ** ptr, size_t * ptr_size) +{ + *ptr_size = buffer->length; + *ptr = buffer->data; + + return 0; +} + +/* This function is like write. But it does not return -1 on error. + * It does return MHD_gnutls_errno instead. + * + * In case of E_AGAIN and E_INTERRUPTED errors, you must call MHD_gnutls_write_flush(), + * until it returns ok (0). + * + * We need to push exactly the data in n, since we cannot send less + * data. In TLS the peer must receive the whole packet in order + * to decrypt and verify the integrity. + * + */ +ssize_t +MHD_gtls_io_write_buffered (MHD_gtls_session_t session, + const void *iptr, size_t n) +{ + size_t left; + unsigned j, x, sum = 0; + ssize_t retval, i; + const opaque *ptr; + int ret; + MHD_gnutls_transport_ptr_t fd = session->internals.transport_send_ptr; + + /* to know where the procedure was interrupted. + */ + session->internals.direction = 1; + + ptr = iptr; + + /* In case the previous write was interrupted, check if the + * iptr != NULL and we have data in the buffer. + * If this is true then return an error. + */ + if (session->internals.record_send_buffer.length > 0 && iptr != NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + /* If data in the buffer exist + */ + if (iptr == NULL) + { + /* checking is handled above */ + ret = + MHD__gnutls_buffer_get (&session->internals.record_send_buffer, &ptr, + &n); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD__gnutls_write_log + ("WRITE: Restoring old write. (%d bytes to send)\n", n); + } + + MHD__gnutls_write_log ("WRITE: Will write %d bytes to %d.\n", n, fd); + + i = 0; + left = n; + while (left > 0) + { + + session->internals.errnum = 0; + + if (session->internals.MHD__gnutls_push_func == NULL) + { + i = send (GNUTLS_POINTER_TO_INT (fd), &ptr[n - left], left, 0); +#if HAVE_WINSOCK + if (i < 0) + { + int tmperr = WSAGetLastError (); + switch (tmperr) + { + case WSAEWOULDBLOCK: + session->internals.errnum = EAGAIN; + break; + + case WSAEINTR: + session->internals.errnum = EINTR; + break; + + default: + session->internals.errnum = EIO; + break; + } + WSASetLastError (tmperr); + } +#endif + } + else + i = session->internals.MHD__gnutls_push_func (fd, &ptr[n - left], left); + if (i == -1) + { + int err = session->internals.errnum ? session->internals.errnum + : errno; + + if ( (err == EAGAIN) || (err == EINTR) ) + { + session->internals.record_send_buffer_prev_size += n - left; + + retval = + MHD__gnutls_buffer_insert (&session-> + internals.record_send_buffer, + &ptr[n - left], left); + if (retval < 0) + { + MHD_gnutls_assert (); + return retval; + } + if (err == EAGAIN) + return GNUTLS_E_AGAIN; + return GNUTLS_E_INTERRUPTED; + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_PUSH_ERROR; + } + } + left -= i; + + if (MHD__gnutls_log_level >= 7) + { + char line[128]; + char tmp[16]; + + MHD__gnutls_write_log + ("WRITE: wrote %d bytes to %d. Left %d bytes. Total %d bytes.\n", + i, fd, left, n); + for (x = 0; x < (unsigned) ((i) / 16) + 1; x++) + { + line[0] = 0; + + if (sum > n - left) + break; + + sprintf (tmp, "%.4x - ", x); + MHD_gtls_str_cat (line, sizeof (line), tmp); + + for (j = 0; j < 16; j++) + { + if (sum < n - left) + { + sprintf (tmp, "%.2x ", ((unsigned char *) ptr)[sum++]); + MHD_gtls_str_cat (line, sizeof (line), tmp); + } + else + break; + } + MHD__gnutls_write_log ("%s\n", line); + } + } + } + + retval = n + session->internals.record_send_buffer_prev_size; + + session->internals.record_send_buffer.length = 0; + session->internals.record_send_buffer_prev_size = 0; + + return retval; + +} + +/* This function writes the data that are left in the + * TLS write buffer (ie. because the previous write was + * interrupted. + */ +ssize_t +MHD_gtls_io_write_flush (MHD_gtls_session_t session) +{ + ssize_t ret; + + if (session->internals.record_send_buffer.length == 0) + return 0; /* done */ + + ret = MHD_gtls_io_write_buffered (session, NULL, 0); + MHD__gnutls_write_log ("WRITE FLUSH: %d [buffer: %d]\n", ret, + session->internals.record_send_buffer.length); + + return ret; +} + +/* This function writes the data that are left in the + * Handshake write buffer (ie. because the previous write was + * interrupted. + */ +ssize_t +MHD_gtls_handshake_io_write_flush (MHD_gtls_session_t session) +{ + ssize_t ret; + ret = MHD_gtls_handshake_io_send_int (session, 0, 0, NULL, 0); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD__gnutls_write_log ("HANDSHAKE_FLUSH: written[1] %d bytes\n", ret); + + if (session->internals.handshake_send_buffer.length == 0) + { + ret = session->internals.handshake_send_buffer_prev_size; /* done */ + session->internals.handshake_send_buffer_prev_size = 0; + } + + return ret; +} + +/* This is a send function for the gnutls handshake + * protocol. Just makes sure that all data have been sent. + */ +ssize_t +MHD_gtls_handshake_io_send_int (MHD_gtls_session_t session, + content_type_t type, + MHD_gnutls_handshake_description_t htype, + const void *iptr, size_t n) +{ + size_t left; + ssize_t ret = 0; + const opaque *ptr; + ssize_t retval = 0; + + ptr = iptr; + + if (session->internals.handshake_send_buffer.length > 0 && ptr == NULL && n + == 0) + { + /* resuming previously interrupted write + */ + MHD_gnutls_assert (); + ret = MHD__gnutls_buffer_get (&session->internals.handshake_send_buffer, + &ptr, &n); + if (ret < 0) + { + MHD_gnutls_assert (); + return retval; + } + + type = session->internals.handshake_send_buffer_type; + htype = session->internals.handshake_send_buffer_htype; + + } + else if (session->internals.handshake_send_buffer.length > 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } +#ifdef WRITE_DEBUG + else + { + size_t sum = 0, x, j; + + MHD__gnutls_write_log ("HWRITE: will write %d bytes to %d.\n", n, + MHD_gnutls_transport_get_ptr (session)); + for (x = 0; x < ((n) / 16) + 1; x++) + { + if (sum > n) + break; + + MHD__gnutls_write_log ("%.4x - ", x); + for (j = 0; j < 16; j++) + { + if (sum < n) + { + MHD__gnutls_write_log ("%.2x ", + ((unsigned char *) ptr)[sum++]); + } + else + break; + } + MHD__gnutls_write_log ("\n"); + } + MHD__gnutls_write_log ("\n"); + } +#endif + + if (n == 0) + { /* if we have no data to send */ + MHD_gnutls_assert (); + return 0; + } + else if (ptr == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + left = n; + while (left > 0) + { + ret = MHD_gtls_send_int (session, type, htype, &ptr[n - left], left); + + if (ret <= 0) + { + if (ret == 0) + { + MHD_gnutls_assert (); + ret = GNUTLS_E_INTERNAL_ERROR; + } + + if (left > 0 && (ret == GNUTLS_E_INTERRUPTED || ret + == GNUTLS_E_AGAIN)) + { + MHD_gnutls_assert (); + + retval = + MHD__gnutls_buffer_insert (&session->internals. + handshake_send_buffer, + &ptr[n - left], left); + if (retval < 0) + { + MHD_gnutls_assert (); + return retval; + } + + session->internals.handshake_send_buffer_prev_size += n - left; + + session->internals.handshake_send_buffer_type = type; + session->internals.handshake_send_buffer_htype = htype; + + } + else + { + session->internals.handshake_send_buffer_prev_size = 0; + session->internals.handshake_send_buffer.length = 0; + } + + MHD_gnutls_assert (); + return ret; + } + left -= ret; + } + + retval = n + session->internals.handshake_send_buffer_prev_size; + + session->internals.handshake_send_buffer.length = 0; + session->internals.handshake_send_buffer_prev_size = 0; + + return retval; + +} + +/* This is a receive function for the gnutls handshake + * protocol. Makes sure that we have received all data. + */ +ssize_t +MHD_gtls_handshake_io_recv_int (MHD_gtls_session_t session, + content_type_t type, + MHD_gnutls_handshake_description_t htype, + void *iptr, size_t sizeOfPtr) +{ + size_t left; + ssize_t i; + opaque *ptr; + size_t dsize; + + ptr = iptr; + left = sizeOfPtr; + + if (sizeOfPtr == 0 || iptr == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + if (session->internals.handshake_recv_buffer.length > 0) + { + /* if we have already received some data */ + if (sizeOfPtr <= session->internals.handshake_recv_buffer.length) + { + /* if requested less data then return it. + */ + MHD_gnutls_assert (); + memcpy (iptr, session->internals.handshake_recv_buffer.data, + sizeOfPtr); + + session->internals.handshake_recv_buffer.length -= sizeOfPtr; + + memmove (session->internals.handshake_recv_buffer.data, + &session->internals.handshake_recv_buffer.data[sizeOfPtr], + session->internals.handshake_recv_buffer.length); + + return sizeOfPtr; + } + MHD_gnutls_assert (); + memcpy (iptr, session->internals.handshake_recv_buffer.data, + session->internals.handshake_recv_buffer.length); + + htype = session->internals.handshake_recv_buffer_htype; + type = session->internals.handshake_recv_buffer_type; + + left -= session->internals.handshake_recv_buffer.length; + + session->internals.handshake_recv_buffer.length = 0; + } + + while (left > 0) + { + dsize = sizeOfPtr - left; + i = MHD_gtls_recv_int (session, type, htype, &ptr[dsize], left); + if (i < 0) + { + + if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN)) + { + MHD_gnutls_assert (); + + session->internals.handshake_recv_buffer.data + = + MHD_gtls_realloc_fast (session->internals. + handshake_recv_buffer.data, dsize); + if (session->internals.handshake_recv_buffer.data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy (session->internals.handshake_recv_buffer.data, iptr, + dsize); + + session->internals.handshake_recv_buffer_htype = htype; + session->internals.handshake_recv_buffer_type = type; + + session->internals.handshake_recv_buffer.length = dsize; + } + else + session->internals.handshake_recv_buffer.length = 0; + + MHD_gnutls_assert (); + + return i; + } + else + { + if (i == 0) + break; /* EOF */ + } + + left -= i; + + } + + session->internals.handshake_recv_buffer.length = 0; + + return sizeOfPtr - left; +} + +/* Buffer for handshake packets. Keeps the packets in order + * for finished messages to use them. Used in HMAC calculation + * and finished messages. + */ +int +MHD_gtls_handshake_buffer_put (MHD_gtls_session_t session, opaque * data, + size_t length) +{ + + if (length == 0) + return 0; + + if ((session->internals.max_handshake_data_buffer_size > 0) && ((length + + + session-> + internals. + handshake_hash_buffer. + length) > + session-> + internals. + max_handshake_data_buffer_size)) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD__gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", length); + + if (MHD_gtls_buffer_append (&session->internals.handshake_hash_buffer, data, + length) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; +} + +/* this function does not touch the buffer + * and returns data from it (peek mode!) + */ +int +MHD_gtls_handshake_buffer_get_ptr (MHD_gtls_session_t session, + opaque ** data_ptr, size_t * length) +{ + if (length != NULL) + *length = session->internals.handshake_hash_buffer.length; + + MHD__gnutls_buffers_log ("BUF[HSK]: Peeked %d bytes of Data\n", + session->internals.handshake_hash_buffer.length); + + if (data_ptr != NULL) + *data_ptr = session->internals.handshake_hash_buffer.data; + + return 0; +} + +/* Does not free the buffer + */ +int +MHD_gtls_handshake_buffer_empty (MHD_gtls_session_t session) +{ + + MHD__gnutls_buffers_log ("BUF[HSK]: Emptied buffer\n"); + + session->internals.handshake_hash_buffer.length = 0; + + return 0; +} + +int +MHD_gtls_handshake_buffer_clear (MHD_gtls_session_t session) +{ + MHD__gnutls_buffers_log ("BUF[HSK]: Cleared Data from buffer\n"); + MHD_gtls_buffer_clear (&session->internals.handshake_hash_buffer); + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_buffers.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_buffers.h new file mode 100644 index 0000000000..e09506ac0d --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_buffers.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +int MHD_gnutls_record_buffer_put (content_type_t type, + MHD_gtls_session_t session, opaque * data, + size_t length); +int MHD_gnutls_record_buffer_get_size (content_type_t type, + MHD_gtls_session_t session); +int MHD_gtls_record_buffer_get (content_type_t type, + MHD_gtls_session_t session, opaque * data, + size_t length); +ssize_t MHD_gtls_io_read_buffered (MHD_gtls_session_t, opaque ** iptr, + size_t n, content_type_t); +void MHD_gtls_io_clear_read_buffer (MHD_gtls_session_t); +int MHD_gtls_io_clear_peeked_data (MHD_gtls_session_t session); + +ssize_t MHD_gtls_io_write_buffered (MHD_gtls_session_t, const void *iptr, + size_t n); +ssize_t MHD_gtls_io_write_buffered2 (MHD_gtls_session_t, const void *iptr, + size_t n, const void *iptr2, size_t n2); + +int MHD_gtls_handshake_buffer_put (MHD_gtls_session_t session, opaque * data, + size_t length); +int MHD_gtls_handshake_buffer_clear (MHD_gtls_session_t session); +int MHD_gtls_handshake_buffer_empty (MHD_gtls_session_t session); +int MHD_gtls_handshake_buffer_get_ptr (MHD_gtls_session_t session, + opaque ** data_ptr, size_t * length); + +#define MHD__gnutls_handshake_io_buffer_clear( session) \ + MHD_gtls_buffer_clear( &session->internals.handshake_send_buffer); \ + MHD_gtls_buffer_clear( &session->internals.handshake_recv_buffer); \ + session->internals.handshake_send_buffer_prev_size = 0 + +ssize_t MHD_gtls_handshake_io_recv_int (MHD_gtls_session_t, content_type_t, + MHD_gnutls_handshake_description_t, + void *, size_t); +ssize_t MHD_gtls_handshake_io_send_int (MHD_gtls_session_t, content_type_t, + MHD_gnutls_handshake_description_t, + const void *, size_t); +ssize_t MHD_gtls_io_write_flush (MHD_gtls_session_t session); +ssize_t MHD_gtls_handshake_io_write_flush (MHD_gtls_session_t session); + +size_t MHD_gtls_record_check_pending (MHD_gtls_session_t session); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cert.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cert.c new file mode 100644 index 0000000000..c546b60766 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cert.c @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Some of the stuff needed for Certificate authentication is contained + * in this file. + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <auth_cert.h> +#include <gnutls_cert.h> +#include <gnutls_datum.h> +#include <gnutls_mpi.h> +#include <gnutls_global.h> +#include <gnutls_algorithms.h> +#include <gnutls_dh.h> +#include <gnutls_str.h> +#include <gnutls_state.h> +#include <gnutls_auth_int.h> +#include <gnutls_x509.h> +/* x509 */ +#include "x509.h" +#include "mpi.h" + +/** + * MHD__gnutls_certificate_free_keys - Used to free all the keys from a MHD_gtls_cert_credentials_t structure + * @sc: is an #MHD_gtls_cert_credentials_t structure. + * + * This function will delete all the keys and the certificates associated + * with the given credentials. This function must not be called when a + * TLS negotiation that uses the credentials is in progress. + * + **/ +void +MHD__gnutls_certificate_free_keys (MHD_gtls_cert_credentials_t sc) +{ + unsigned i, j; + + for (i = 0; i < sc->ncerts; i++) + { + for (j = 0; j < sc->cert_list_length[i]; j++) + { + MHD_gtls_gcert_deinit (&sc->cert_list[i][j]); + } + MHD_gnutls_free (sc->cert_list[i]); + } + + MHD_gnutls_free (sc->cert_list_length); + sc->cert_list_length = NULL; + + MHD_gnutls_free (sc->cert_list); + sc->cert_list = NULL; + + for (i = 0; i < sc->ncerts; i++) + { + MHD_gtls_gkey_deinit (&sc->pkey[i]); + } + + MHD_gnutls_free (sc->pkey); + sc->pkey = NULL; + + sc->ncerts = 0; + +} + +/** + * MHD__gnutls_certificate_free_cas - Used to free all the CAs from a MHD_gtls_cert_credentials_t structure + * @sc: is an #MHD_gtls_cert_credentials_t structure. + * + * This function will delete all the CAs associated + * with the given credentials. Servers that do not use + * MHD_gtls_certificate_verify_peers2() may call this to + * save some memory. + * + **/ +void +MHD__gnutls_certificate_free_cas (MHD_gtls_cert_credentials_t sc) +{ + unsigned j; + + for (j = 0; j < sc->x509_ncas; j++) + { + MHD_gnutls_x509_crt_deinit (sc->x509_ca_list[j]); + } + + sc->x509_ncas = 0; + + MHD_gnutls_free (sc->x509_ca_list); + sc->x509_ca_list = NULL; + +} + +/** + * MHD__gnutls_certificate_free_ca_names - Used to free all the CA names from a MHD_gtls_cert_credentials_t structure + * @sc: is an #MHD_gtls_cert_credentials_t structure. + * + * This function will delete all the CA name in the + * given credentials. Clients may call this to save some memory + * since in client side the CA names are not used. + * + * CA names are used by servers to advertize the CAs they + * support to clients. + * + **/ +void +MHD__gnutls_certificate_free_ca_names (MHD_gtls_cert_credentials_t sc) +{ + MHD__gnutls_free_datum (&sc->x509_rdn_sequence); +} + +/*- + * MHD_gtls_certificate_get_rsa_params - Returns the RSA parameters pointer + * @rsa_params: holds the RSA parameters or NULL. + * @func: function to retrieve the parameters or NULL. + * @session: The session. + * + * This function will return the rsa parameters pointer. + * + -*/ +MHD_gtls_rsa_params_t +MHD_gtls_certificate_get_rsa_params (MHD_gtls_rsa_params_t rsa_params, + MHD_gnutls_params_function * func, + MHD_gtls_session_t session) +{ + MHD_gnutls_params_st params; + int ret; + + if (session->internals.params.rsa_params) + { + return session->internals.params.rsa_params; + } + + if (rsa_params) + { + session->internals.params.rsa_params = rsa_params; + } + else if (func) + { + ret = func (session, GNUTLS_PARAMS_RSA_EXPORT, ¶ms); + if (ret == 0 && params.type == GNUTLS_PARAMS_RSA_EXPORT) + { + session->internals.params.rsa_params = params.params.rsa_export; + session->internals.params.free_rsa_params = params.deinit; + } + } + + return session->internals.params.rsa_params; +} + + +/** + * MHD__gnutls_certificate_free_credentials - Used to free an allocated MHD_gtls_cert_credentials_t structure + * @sc: is an #MHD_gtls_cert_credentials_t structure. + * + * This structure is complex enough to manipulate directly thus + * this helper function is provided in order to free (deallocate) it. + * + * This function does not free any temporary parameters associated + * with this structure (ie RSA and DH parameters are not freed by + * this function). + **/ +void +MHD__gnutls_certificate_free_credentials (MHD_gtls_cert_credentials_t sc) +{ + MHD__gnutls_certificate_free_keys (sc); + MHD__gnutls_certificate_free_cas (sc); + MHD__gnutls_certificate_free_ca_names (sc); +#ifdef KEYRING_HACK + MHD__gnutls_free_datum (&sc->keyring); +#endif + + MHD_gnutls_free (sc); +} + + +/** + * MHD__gnutls_certificate_allocate_credentials - Used to allocate a MHD_gtls_cert_credentials_t structure + * @res: is a pointer to an #MHD_gtls_cert_credentials_t structure. + * + * This structure is complex enough to manipulate directly thus this + * helper function is provided in order to allocate it. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + **/ +int +MHD__gnutls_certificate_allocate_credentials (MHD_gtls_cert_credentials_t * + res) +{ + *res = MHD_gnutls_calloc (1, sizeof (MHD_gtls_cert_credentials_st)); + + if (*res == NULL) + return GNUTLS_E_MEMORY_ERROR; + + (*res)->verify_bits = DEFAULT_VERIFY_BITS; + (*res)->verify_depth = DEFAULT_VERIFY_DEPTH; + + return 0; +} + + +/* returns the KX algorithms that are supported by a + * certificate. (Eg a certificate with RSA params, supports + * GNUTLS_KX_RSA algorithm). + * This function also uses the KeyUsage field of the certificate + * extensions in order to disable unneded algorithms. + */ +int +MHD_gtls_selected_cert_supported_kx (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm + **alg, int *alg_size) +{ + enum MHD_GNUTLS_KeyExchangeAlgorithm kx; + enum MHD_GNUTLS_PublicKeyAlgorithm pk; + enum MHD_GNUTLS_KeyExchangeAlgorithm kxlist[MAX_ALGOS]; + MHD_gnutls_cert *cert; + int i; + + if (session->internals.selected_cert_list_length == 0) + { + *alg_size = 0; + *alg = NULL; + return 0; + } + + cert = &session->internals.selected_cert_list[0]; + i = 0; + + for (kx = 0; kx < MAX_ALGOS; kx++) + { + pk = MHD_gtls_map_pk_get_pk (kx); + if (pk == cert->subject_pk_algorithm) + { + /* then check key usage */ + if (MHD__gnutls_check_key_usage (cert, kx) == 0) + { + kxlist[i] = kx; + i++; + } + } + } + + if (i == 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + *alg = + MHD_gnutls_calloc (1, sizeof (enum MHD_GNUTLS_KeyExchangeAlgorithm) * i); + if (*alg == NULL) + return GNUTLS_E_MEMORY_ERROR; + + *alg_size = i; + + memcpy (*alg, kxlist, i * sizeof (enum MHD_GNUTLS_KeyExchangeAlgorithm)); + + return 0; +} + + + +int +MHD_gtls_raw_cert_to_gcert (MHD_gnutls_cert * gcert, + enum MHD_GNUTLS_CertificateType type, + const MHD_gnutls_datum_t * raw_cert, + int flags /* OR of ConvFlags */ ) +{ + switch (type) + { + case MHD_GNUTLS_CRT_X509: + return MHD_gtls_x509_raw_cert_to_gcert (gcert, raw_cert, flags); + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } +} + +/* This function will convert a der certificate to a format + * (structure) that gnutls can understand and use. Actually the + * important thing on this function is that it extracts the + * certificate's (public key) parameters. + * + * The noext flag is used to complete the handshake even if the + * extensions found in the certificate are unsupported and critical. + * The critical extensions will be catched by the verification functions. + */ +int +MHD_gtls_x509_raw_cert_to_gcert (MHD_gnutls_cert * gcert, + const MHD_gnutls_datum_t * derCert, + int flags /* OR of ConvFlags */ ) +{ + int ret; + MHD_gnutls_x509_crt_t cert; + + ret = MHD_gnutls_x509_crt_init (&cert); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = MHD_gnutls_x509_crt_import (cert, derCert, GNUTLS_X509_FMT_DER); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_x509_crt_deinit (cert); + return ret; + } + + ret = MHD_gtls_x509_crt_to_gcert (gcert, cert, flags); + MHD_gnutls_x509_crt_deinit (cert); + + return ret; +} + +/* Like above but it accepts a parsed certificate instead. + */ +int +MHD_gtls_x509_crt_to_gcert (MHD_gnutls_cert * gcert, + MHD_gnutls_x509_crt_t cert, unsigned int flags) +{ + int ret = 0; + + memset (gcert, 0, sizeof (MHD_gnutls_cert)); + gcert->cert_type = MHD_GNUTLS_CRT_X509; + + if (!(flags & CERT_NO_COPY)) + { +#define SMALL_DER 512 + opaque *der; + size_t der_size = SMALL_DER; + + /* initially allocate a bogus size, just in case the certificate + * fits in it. That way we minimize the DER encodings performed. + */ + der = MHD_gnutls_malloc (SMALL_DER); + if (der == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + ret = + MHD_gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, + &der_size); + if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + MHD_gnutls_assert (); + MHD_gnutls_free (der); + return ret; + } + + if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) + { + der = MHD_gnutls_realloc (der, der_size); + if (der == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + ret = + MHD_gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, + &der_size); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (der); + return ret; + } + } + + gcert->raw.data = der; + gcert->raw.size = der_size; + } + else + /* now we have 0 or a bitwise or of things to decode */ + flags ^= CERT_NO_COPY; + + + if (flags & CERT_ONLY_EXTENSIONS || flags == 0) + { + MHD_gnutls_x509_crt_get_key_usage (cert, &gcert->key_usage, NULL); + gcert->version = MHD_gnutls_x509_crt_get_version (cert); + } + gcert->subject_pk_algorithm = + MHD_gnutls_x509_crt_get_pk_algorithm (cert, NULL); + + if (flags & CERT_ONLY_PUBKEY || flags == 0) + { + gcert->params_size = MAX_PUBLIC_PARAMS_SIZE; + ret = + MHD__gnutls_x509_crt_get_mpis (cert, gcert->params, + &gcert->params_size); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + + return 0; + +} + +void +MHD_gtls_gcert_deinit (MHD_gnutls_cert * cert) +{ + int i; + + if (cert == NULL) + return; + + for (i = 0; i < cert->params_size; i++) + { + MHD_gtls_mpi_release (&cert->params[i]); + } + + MHD__gnutls_free_datum (&cert->raw); +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cert.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cert.h new file mode 100644 index 0000000000..124ac96352 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cert.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_CERT_H +# define GNUTLS_CERT_H + +#include <gnutls_pk.h> +#include "x509.h" + +#define MAX_PUBLIC_PARAMS_SIZE 4 /* ok for RSA and DSA */ + +/* parameters should not be larger than this limit */ +#define DSA_PUBLIC_PARAMS 4 +#define RSA_PUBLIC_PARAMS 2 + +/* For key Usage, test as: + * if (st.key_usage & KEY_DIGITAL_SIGNATURE) ... + */ +#define KEY_DIGITAL_SIGNATURE 128 +#define KEY_NON_REPUDIATION 64 +#define KEY_KEY_ENCIPHERMENT 32 +#define KEY_DATA_ENCIPHERMENT 16 +#define KEY_KEY_AGREEMENT 8 +#define KEY_KEY_CERT_SIGN 4 +#define KEY_CRL_SIGN 2 +#define KEY_ENCIPHER_ONLY 1 +#define KEY_DECIPHER_ONLY 32768 + +typedef struct MHD_gnutls_cert +{ + mpi_t params[MAX_PUBLIC_PARAMS_SIZE]; /* the size of params depends on the public + * key algorithm + * RSA: [0] is modulus + * [1] is public exponent + * DSA: [0] is p + * [1] is q + * [2] is g + * [3] is public key + */ + int params_size; /* holds the size of MPI params */ + + enum MHD_GNUTLS_PublicKeyAlgorithm subject_pk_algorithm; + + unsigned int key_usage; /* bits from KEY_* + */ + + unsigned int version; + /* holds the type (PGP, X509) + */ + enum MHD_GNUTLS_CertificateType cert_type; + + MHD_gnutls_datum_t raw; + +} MHD_gnutls_cert; + +typedef struct MHD_gnutls_privkey_int +{ + mpi_t params[MAX_PRIV_PARAMS_SIZE]; /* the size of params depends on the public + * key algorithm + */ + /* + * RSA: [0] is modulus + * [1] is public exponent + * [2] is private exponent + * [3] is prime1 (p) + * [4] is prime2 (q) + * [5] is coefficient (u == inverse of p mod q) + * DSA: [0] is p + * [1] is q + * [2] is g + * [3] is y (public key) + * [4] is x (private key) + */ + int params_size; /* holds the number of params */ + + enum MHD_GNUTLS_PublicKeyAlgorithm pk_algorithm; +} MHD_gnutls_privkey; + +struct MHD_gtls_session_int; /* because MHD_gtls_session_t is not defined when this file is included */ + +typedef enum ConvFlags +{ + CERT_NO_COPY = 2, + CERT_ONLY_PUBKEY = 4, + CERT_ONLY_EXTENSIONS = 16 +} ConvFlags; + +int MHD_gtls_x509_raw_cert_to_gcert (MHD_gnutls_cert * gcert, + const MHD_gnutls_datum_t * derCert, + int flags); +int MHD_gtls_x509_crt_to_gcert (MHD_gnutls_cert * gcert, + MHD_gnutls_x509_crt_t cert, + unsigned int flags); + +void MHD_gtls_gkey_deinit (MHD_gnutls_privkey * key); +void MHD_gtls_gcert_deinit (MHD_gnutls_cert * cert); + +int MHD_gtls_selected_cert_supported_kx (struct MHD_gtls_session_int *session, + enum MHD_GNUTLS_KeyExchangeAlgorithm + **alg, int *alg_size); + +int MHD_gtls_raw_cert_to_gcert (MHD_gnutls_cert * gcert, + enum MHD_GNUTLS_CertificateType type, + const MHD_gnutls_datum_t * raw_cert, + int flags /* OR of ConvFlags */ ); +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher.c new file mode 100644 index 0000000000..5004d13ce7 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher.c @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Some high level functions to be used in the record encryption are + * included here. + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "gnutls_cipher.h" +#include "gnutls_algorithms.h" +#include "gnutls_hash_int.h" +#include "gnutls_cipher_int.h" +#include "debug.h" +#include "gnutls_num.h" +#include "gnutls_datum.h" +#include "gnutls_kx.h" +#include "gnutls_record.h" +#include "gnutls_constate.h" +#include <gc.h> + +/* returns ciphertext which contains the headers too. This also + * calculates the size in the header field. + * + * If random pad != 0 then the random pad data will be appended. + */ +int +MHD_gtls_encrypt (MHD_gtls_session_t session, const opaque * headers, + size_t headers_size, const opaque * data, + size_t data_size, opaque * ciphertext, + size_t ciphertext_size, content_type_t type, int random_pad) +{ + MHD_gnutls_datum_t plain; + MHD_gnutls_datum_t comp; + int ret; + int free_comp = 1; + + plain.data = (opaque *) data; + plain.size = data_size; + + comp = plain; + free_comp = 0; + ret = MHD_gtls_compressed2ciphertext (session, &ciphertext[headers_size], + ciphertext_size - headers_size, + comp, type, random_pad); + + if (free_comp) + MHD__gnutls_free_datum (&comp); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + + /* copy the headers */ + memcpy (ciphertext, headers, headers_size); + MHD_gtls_write_uint16 (ret, &ciphertext[3]); + + return ret + headers_size; +} + +/* Decrypts the given data. + * Returns the decrypted data length. + */ +int +MHD_gtls_decrypt (MHD_gtls_session_t session, opaque * ciphertext, + size_t ciphertext_size, uint8_t * data, + size_t max_data_size, content_type_t type) +{ + MHD_gnutls_datum_t gcipher; + + if (ciphertext_size == 0) + return 0; + + gcipher.size = ciphertext_size; + gcipher.data = ciphertext; + + return + MHD_gtls_ciphertext2compressed (session, data, max_data_size, + gcipher, type); +} + +inline static mac_hd_t +mac_init (enum MHD_GNUTLS_HashAlgorithm mac, opaque * secret, int secret_size, + int ver) +{ + mac_hd_t td; + + if (mac == MHD_GNUTLS_MAC_NULL) + return GNUTLS_MAC_FAILED; + + if (ver == MHD_GNUTLS_PROTOCOL_SSL3) + { /* SSL 3.0 */ + td = MHD_gnutls_mac_init_ssl3 (mac, secret, secret_size); + } + else + { /* TLS 1.x */ + td = MHD_gtls_MHD_hmac_init (mac, secret, secret_size); + } + + return td; +} + +inline static void +mac_deinit (mac_hd_t td, opaque * res, int ver) +{ + if (ver == MHD_GNUTLS_PROTOCOL_SSL3) + { /* SSL 3.0 */ + MHD_gnutls_mac_deinit_ssl3 (td, res); + } + else + { + MHD_gnutls_MHD_hmac_deinit (td, res); + } +} + +inline static int +calc_enc_length (MHD_gtls_session_t session, int data_size, + int hash_size, uint8_t * pad, int random_pad, + cipher_type_t block_algo, uint16_t blocksize) +{ + uint8_t rnd; + int length; + + *pad = 0; + + switch (block_algo) + { + case CIPHER_STREAM: + length = data_size + hash_size; + + break; + case CIPHER_BLOCK: + if (MHD_gc_nonce ((char *) &rnd, 1) != GC_OK) + { + MHD_gnutls_assert (); + return GNUTLS_E_RANDOM_FAILED; + } + + /* make rnd a multiple of blocksize */ + if (session->security_parameters.version == MHD_GNUTLS_PROTOCOL_SSL3 || + random_pad == 0) + { + rnd = 0; + } + else + { + rnd = (rnd / blocksize) * blocksize; + /* added to avoid the case of pad calculated 0 + * seen below for pad calculation. + */ + if (rnd > blocksize) + rnd -= blocksize; + } + + length = data_size + hash_size; + + *pad = (uint8_t) (blocksize - (length % blocksize)) + rnd; + + length += *pad; + if (session->security_parameters.version >= MHD_GNUTLS_PROTOCOL_TLS1_1) + length += blocksize; /* for the IV */ + + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + return length; +} + +/* This is the actual encryption + * Encrypts the given compressed datum, and puts the result to cipher_data, + * which has cipher_size size. + * return the actual encrypted data length. + */ +int +MHD_gtls_compressed2ciphertext (MHD_gtls_session_t session, + opaque * cipher_data, int cipher_size, + MHD_gnutls_datum_t compressed, + content_type_t _type, int random_pad) +{ + uint8_t MAC[MAX_HASH_SIZE]; + uint16_t c_length; + uint8_t pad; + int length, ret; + mac_hd_t td; + uint8_t type = _type; + uint8_t major, minor; + int hash_size = + MHD_gnutls_hash_get_algo_len (session->security_parameters. + write_mac_algorithm); + enum MHD_GNUTLS_Protocol ver; + int blocksize = + MHD_gtls_cipher_get_block_size (session->security_parameters. + write_bulk_cipher_algorithm); + cipher_type_t block_algo = + MHD_gtls_cipher_is_block (session->security_parameters. + write_bulk_cipher_algorithm); + opaque *data_ptr; + + + ver = MHD__gnutls_protocol_get_version (session); + minor = MHD_gtls_version_get_minor (ver); + major = MHD_gtls_version_get_major (ver); + + + /* Initialize MAC */ + td = mac_init (session->security_parameters.write_mac_algorithm, + session->connection_state.write_mac_secret.data, + session->connection_state.write_mac_secret.size, ver); + + if (td == GNUTLS_MAC_FAILED + && session->security_parameters.write_mac_algorithm != + MHD_GNUTLS_MAC_NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + c_length = MHD_gtls_conv_uint16 (compressed.size); + + if (td != GNUTLS_MAC_FAILED) + { /* actually when the algorithm in not the NULL one */ + MHD_gnutls_hash (td, + UINT64DATA (session->connection_state. + write_sequence_number), 8); + + MHD_gnutls_hash (td, &type, 1); + if (ver >= MHD_GNUTLS_PROTOCOL_TLS1_0) + { /* TLS 1.0 or higher */ + MHD_gnutls_hash (td, &major, 1); + MHD_gnutls_hash (td, &minor, 1); + } + MHD_gnutls_hash (td, &c_length, 2); + MHD_gnutls_hash (td, compressed.data, compressed.size); + mac_deinit (td, MAC, ver); + } + + + /* Calculate the encrypted length (padding etc.) + */ + length = + calc_enc_length (session, compressed.size, hash_size, &pad, + random_pad, block_algo, blocksize); + if (length < 0) + { + MHD_gnutls_assert (); + return length; + } + + /* copy the encrypted data to cipher_data. + */ + if (cipher_size < length) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + data_ptr = cipher_data; + if (block_algo == CIPHER_BLOCK && + session->security_parameters.version >= MHD_GNUTLS_PROTOCOL_TLS1_1) + { + /* copy the random IV. + */ + if (MHD_gc_nonce ((char *) data_ptr, blocksize) != GC_OK) + { + MHD_gnutls_assert (); + return GNUTLS_E_RANDOM_FAILED; + } + data_ptr += blocksize; + } + + memcpy (data_ptr, compressed.data, compressed.size); + data_ptr += compressed.size; + + if (hash_size > 0) + { + memcpy (data_ptr, MAC, hash_size); + data_ptr += hash_size; + } + if (block_algo == CIPHER_BLOCK && pad > 0) + { + memset (data_ptr, pad - 1, pad); + } + + + /* Actual encryption (inplace). + */ + ret = + MHD_gtls_cipher_encrypt (session->connection_state.write_cipher_state, + cipher_data, length); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return length; +} + +/* Deciphers the ciphertext packet, and puts the result to compress_data, of compress_size. + * Returns the actual compressed packet size. + */ +int +MHD_gtls_ciphertext2compressed (MHD_gtls_session_t session, + opaque * compress_data, + int compress_size, + MHD_gnutls_datum_t ciphertext, uint8_t type) +{ + uint8_t MAC[MAX_HASH_SIZE]; + uint16_t c_length; + uint8_t pad; + int length; + mac_hd_t td; + uint16_t blocksize; + int ret, i, pad_failed = 0; + uint8_t major, minor; + enum MHD_GNUTLS_Protocol ver; + int hash_size = + MHD_gnutls_hash_get_algo_len (session->security_parameters. + read_mac_algorithm); + + ver = MHD__gnutls_protocol_get_version (session); + minor = MHD_gtls_version_get_minor (ver); + major = MHD_gtls_version_get_major (ver); + + blocksize = + MHD_gtls_cipher_get_block_size (session->security_parameters. + read_bulk_cipher_algorithm); + + /* initialize MAC + */ + td = mac_init (session->security_parameters.read_mac_algorithm, + session->connection_state.read_mac_secret.data, + session->connection_state.read_mac_secret.size, ver); + + if (td == GNUTLS_MAC_FAILED + && session->security_parameters.read_mac_algorithm != + MHD_GNUTLS_MAC_NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + + /* actual decryption (inplace) + */ + switch (MHD_gtls_cipher_is_block + (session->security_parameters.read_bulk_cipher_algorithm)) + { + case CIPHER_STREAM: + if ((ret = + MHD_gtls_cipher_decrypt (session->connection_state. + read_cipher_state, ciphertext.data, + ciphertext.size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + length = ciphertext.size - hash_size; + + break; + case CIPHER_BLOCK: + if ((ciphertext.size < blocksize) || (ciphertext.size % blocksize != 0)) + { + MHD_gnutls_assert (); + return GNUTLS_E_DECRYPTION_FAILED; + } + + if ((ret = + MHD_gtls_cipher_decrypt (session->connection_state. + read_cipher_state, ciphertext.data, + ciphertext.size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* ignore the IV in TLS 1.1. + */ + if (session->security_parameters.version >= MHD_GNUTLS_PROTOCOL_TLS1_1) + { + ciphertext.size -= blocksize; + ciphertext.data += blocksize; + + if (ciphertext.size == 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_DECRYPTION_FAILED; + } + } + + pad = ciphertext.data[ciphertext.size - 1] + 1; /* pad */ + + length = ciphertext.size - hash_size - pad; + + if (pad > ciphertext.size - hash_size) + { + MHD_gnutls_assert (); + /* We do not fail here. We check below for the + * the pad_failed. If zero means success. + */ + pad_failed = GNUTLS_E_DECRYPTION_FAILED; + } + + /* Check the pading bytes (TLS 1.x) + */ + if (ver >= MHD_GNUTLS_PROTOCOL_TLS1_0 && pad_failed == 0) + for (i = 2; i < pad; i++) + { + if (ciphertext.data[ciphertext.size - i] != + ciphertext.data[ciphertext.size - 1]) + pad_failed = GNUTLS_E_DECRYPTION_FAILED; + } + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (length < 0) + length = 0; + c_length = MHD_gtls_conv_uint16 ((uint16_t) length); + + /* Pass the type, version, length and compressed through + * MAC. + */ + if (td != GNUTLS_MAC_FAILED) + { + MHD_gnutls_hash (td, + UINT64DATA (session->connection_state. + read_sequence_number), 8); + + MHD_gnutls_hash (td, &type, 1); + if (ver >= MHD_GNUTLS_PROTOCOL_TLS1_0) + { /* TLS 1.x */ + MHD_gnutls_hash (td, &major, 1); + MHD_gnutls_hash (td, &minor, 1); + } + MHD_gnutls_hash (td, &c_length, 2); + + if (length > 0) + MHD_gnutls_hash (td, ciphertext.data, length); + + mac_deinit (td, MAC, ver); + } + + /* This one was introduced to avoid a timing attack against the TLS + * 1.0 protocol. + */ + if (pad_failed != 0) + return pad_failed; + + /* HMAC was not the same. + */ + if ( (td != GNUTLS_MAC_FAILED) && + (memcmp (MAC, &ciphertext.data[length], hash_size) != 0) ) + { + MHD_gnutls_assert (); + return GNUTLS_E_DECRYPTION_FAILED; + } + + /* copy the decrypted stuff to compress_data. + */ + if (compress_size < length) + { + MHD_gnutls_assert (); + return GNUTLS_E_DECOMPRESSION_FAILED; + } + memcpy (compress_data, ciphertext.data, length); + + return length; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher.h new file mode 100644 index 0000000000..b8dc00701e --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +int MHD_gtls_encrypt (MHD_gtls_session_t session, const opaque * headers, + size_t headers_size, const opaque * data, + size_t data_size, opaque * ciphertext, + size_t ciphertext_size, content_type_t type, + int random_pad); + +int MHD_gtls_decrypt (MHD_gtls_session_t session, opaque * ciphertext, + size_t ciphertext_size, uint8_t * data, + size_t data_size, content_type_t type); +int MHD_gtls_compressed2ciphertext (MHD_gtls_session_t session, + opaque * cipher_data, int cipher_size, + MHD_gnutls_datum_t compressed, + content_type_t _type, int random_pad); +int MHD_gtls_ciphertext2compressed (MHD_gtls_session_t session, + opaque * compress_data, int compress_size, + MHD_gnutls_datum_t ciphertext, + uint8_t type); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher_int.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher_int.c new file mode 100644 index 0000000000..7349436a06 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher_int.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2000, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_cipher_int.h> +#include <gnutls_datum.h> + +cipher_hd_t +MHD_gtls_cipher_init (enum MHD_GNUTLS_CipherAlgorithm cipher, + const MHD_gnutls_datum_t * key, + const MHD_gnutls_datum_t * iv) +{ + cipher_hd_t ret = NULL; + int err = GC_INVALID_CIPHER; /* doesn't matter */ + + switch (cipher) + { + case MHD_GNUTLS_CIPHER_AES_128_CBC: + err = MHD_gc_cipher_open (GC_AES128, GC_CBC, &ret); + break; + case MHD_GNUTLS_CIPHER_AES_256_CBC: + err = MHD_gc_cipher_open (GC_AES256, GC_CBC, &ret); + break; + case MHD_GNUTLS_CIPHER_3DES_CBC: + err = MHD_gc_cipher_open (GC_3DES, GC_CBC, &ret); + break; + case MHD_GNUTLS_CIPHER_ARCFOUR_128: + err = MHD_gc_cipher_open (GC_ARCFOUR128, GC_STREAM, &ret); + break; + default: + return NULL; + } + + if (err == 0) + { + MHD_gc_cipher_setkey (ret, key->size, (const char *) key->data); + if (iv->data != NULL && iv->size > 0) + MHD_gc_cipher_setiv (ret, iv->size, (const char *) iv->data); + } + else if (cipher != MHD_GNUTLS_CIPHER_NULL) + { + MHD_gnutls_assert (); + MHD__gnutls_x509_log ("Crypto cipher[%d] error: %d\n", cipher, err); + /* FIXME: MHD_gc_strerror */ + } + + return ret; +} + +int +MHD_gtls_cipher_encrypt (cipher_hd_t handle, void *text, int textlen) +{ + if (handle != GNUTLS_CIPHER_FAILED) + { + if (MHD_gc_cipher_encrypt_inline (handle, textlen, text) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + } + return 0; +} + +int +MHD_gtls_cipher_decrypt (cipher_hd_t handle, void *ciphertext, + int ciphertextlen) +{ + if (handle != GNUTLS_CIPHER_FAILED) + { + if (MHD_gc_cipher_decrypt_inline (handle, ciphertextlen, ciphertext) != + 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + } + return 0; +} + +void +MHD_gnutls_cipher_deinit (cipher_hd_t handle) +{ + if (handle != GNUTLS_CIPHER_FAILED) + { + MHD_gc_cipher_close (handle); + } +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher_int.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher_int.h new file mode 100644 index 0000000000..f00f945f74 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_cipher_int.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_CIPHER_INT +# define GNUTLS_CIPHER_INT + +#define cipher_hd_t MHD_gc_cipher_handle +#define GNUTLS_CIPHER_FAILED NULL + +// TODO MHD_gc_cipher_handle -> void * x3 +void *MHD_gtls_cipher_init (enum MHD_GNUTLS_CipherAlgorithm cipher, + const MHD_gnutls_datum_t * key, + const MHD_gnutls_datum_t * iv); + +int MHD_gtls_cipher_encrypt (void *handle, void *text, int textlen); + +int MHD_gtls_cipher_decrypt (void *handle, + void *ciphertext, int ciphertextlen); + +void MHD_gnutls_cipher_deinit (void *handle); + +#endif /* GNUTLS_CIPHER_INT */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_constate.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_constate.c new file mode 100644 index 0000000000..845abfe957 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_constate.c @@ -0,0 +1,999 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions that are supposed to run after the handshake procedure is + * finished. These functions activate the established security parameters. + */ + +#include "MHD_config.h" +#include <gnutls_int.h> +#include <gnutls_constate.h> +#include <gnutls_errors.h> +#include <gnutls_kx.h> +#include <gnutls_algorithms.h> +#include <gnutls_num.h> +#include <gnutls_datum.h> +#include <gnutls_state.h> + +static const char keyexp[] = "key expansion"; +static const int keyexp_length = sizeof (keyexp) - 1; + +static const char ivblock[] = "IV block"; +static const int ivblock_length = sizeof (ivblock) - 1; + +static const char cliwrite[] = "client write key"; +static const int cliwrite_length = sizeof (cliwrite) - 1; + +static const char servwrite[] = "server write key"; +static const int servwrite_length = sizeof (servwrite) - 1; + +#define EXPORT_FINAL_KEY_SIZE 16 + +/* This function is to be called after handshake, when master_secret, + * client_random and server_random have been initialized. + * This function creates the keys and stores them into pending session. + * (session->cipher_specs) + */ +int +MHD__gnutls_set_keys (MHD_gtls_session_t session, int hash_size, int IV_size, + int key_size, int export_flag) +{ + opaque *key_block; + opaque rnd[2 * TLS_RANDOM_SIZE]; + opaque rrnd[2 * TLS_RANDOM_SIZE]; + int pos, ret; + int block_size; + char buf[65]; + + if (session->cipher_specs.generated_keys != 0) + { + /* keys have already been generated. + * reset generated_keys and exit normally. + */ + session->cipher_specs.generated_keys = 0; + return 0; + } + + block_size = 2 * hash_size + 2 * key_size; + if (export_flag == 0) + block_size += 2 * IV_size; + + key_block = MHD_gnutls_secure_malloc (block_size); + if (key_block == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy (rnd, session->security_parameters.server_random, TLS_RANDOM_SIZE); + memcpy (&rnd[TLS_RANDOM_SIZE], + session->security_parameters.client_random, TLS_RANDOM_SIZE); + + memcpy (rrnd, session->security_parameters.client_random, TLS_RANDOM_SIZE); + memcpy (&rrnd[TLS_RANDOM_SIZE], + session->security_parameters.server_random, TLS_RANDOM_SIZE); + + if (session->security_parameters.version == MHD_GNUTLS_PROTOCOL_SSL3) + { /* SSL 3 */ + ret = + MHD_gnutls_ssl3_generate_random + (session->security_parameters.master_secret, TLS_MASTER_SIZE, rnd, + 2 * TLS_RANDOM_SIZE, block_size, key_block); + } + else + { /* TLS 1.0 */ + ret = + MHD_gtls_PRF (session, + (const unsigned char *) session-> + security_parameters.master_secret, TLS_MASTER_SIZE, + keyexp, keyexp_length, rnd, 2 * TLS_RANDOM_SIZE, + block_size, key_block); + } + + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (key_block); + return ret; + } + + MHD__gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size, + MHD_gtls_bin2hex (key_block, block_size, buf, + sizeof (buf))); + + pos = 0; + if (hash_size > 0) + { + if (MHD__gnutls_sset_datum + (&session->cipher_specs.client_write_mac_secret, + &key_block[pos], hash_size) < 0) + { + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + pos += hash_size; + + if (MHD__gnutls_sset_datum + (&session->cipher_specs.server_write_mac_secret, + &key_block[pos], hash_size) < 0) + { + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + pos += hash_size; + } + + if (key_size > 0) + { + opaque *client_write_key, *server_write_key; + int client_write_key_size, server_write_key_size; + int free_keys = 0; + + if (export_flag == 0) + { + client_write_key = &key_block[pos]; + client_write_key_size = key_size; + + pos += key_size; + + server_write_key = &key_block[pos]; + server_write_key_size = key_size; + + pos += key_size; + + } + else + { /* export */ + free_keys = 1; + + client_write_key = MHD_gnutls_secure_malloc (EXPORT_FINAL_KEY_SIZE); + if (client_write_key == NULL) + { + MHD_gnutls_assert (); + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + + server_write_key = MHD_gnutls_secure_malloc (EXPORT_FINAL_KEY_SIZE); + if (server_write_key == NULL) + { + MHD_gnutls_assert (); + MHD_gnutls_free (key_block); + MHD_gnutls_free (client_write_key); + return GNUTLS_E_MEMORY_ERROR; + } + + /* generate the final keys */ + + if (session->security_parameters.version == + MHD_GNUTLS_PROTOCOL_SSL3) + { /* SSL 3 */ + ret = + MHD_gnutls_ssl3_hash_md5 (&key_block[pos], + key_size, rrnd, + 2 * TLS_RANDOM_SIZE, + EXPORT_FINAL_KEY_SIZE, + client_write_key); + + } + else + { /* TLS 1.0 */ + ret = + MHD_gtls_PRF (session, &key_block[pos], key_size, + cliwrite, cliwrite_length, + rrnd, + 2 * TLS_RANDOM_SIZE, + EXPORT_FINAL_KEY_SIZE, client_write_key); + } + + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (key_block); + MHD_gnutls_free (server_write_key); + MHD_gnutls_free (client_write_key); + return ret; + } + + client_write_key_size = EXPORT_FINAL_KEY_SIZE; + pos += key_size; + + if (session->security_parameters.version == + MHD_GNUTLS_PROTOCOL_SSL3) + { /* SSL 3 */ + ret = + MHD_gnutls_ssl3_hash_md5 (&key_block[pos], key_size, + rnd, 2 * TLS_RANDOM_SIZE, + EXPORT_FINAL_KEY_SIZE, + server_write_key); + } + else + { /* TLS 1.0 */ + ret = + MHD_gtls_PRF (session, &key_block[pos], key_size, + servwrite, servwrite_length, + rrnd, 2 * TLS_RANDOM_SIZE, + EXPORT_FINAL_KEY_SIZE, server_write_key); + } + + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (key_block); + MHD_gnutls_free (server_write_key); + MHD_gnutls_free (client_write_key); + return ret; + } + + server_write_key_size = EXPORT_FINAL_KEY_SIZE; + pos += key_size; + } + + if (MHD__gnutls_sset_datum + (&session->cipher_specs.client_write_key, + client_write_key, client_write_key_size) < 0) + { + MHD_gnutls_free (key_block); + MHD_gnutls_free (server_write_key); + MHD_gnutls_free (client_write_key); + return GNUTLS_E_MEMORY_ERROR; + } + MHD__gnutls_hard_log ("INT: CLIENT WRITE KEY [%d]: %s\n", + client_write_key_size, + MHD_gtls_bin2hex (client_write_key, + client_write_key_size, buf, + sizeof (buf))); + + if (MHD__gnutls_sset_datum + (&session->cipher_specs.server_write_key, + server_write_key, server_write_key_size) < 0) + { + MHD_gnutls_free (key_block); + MHD_gnutls_free (server_write_key); + MHD_gnutls_free (client_write_key); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD__gnutls_hard_log ("INT: SERVER WRITE KEY [%d]: %s\n", + server_write_key_size, + MHD_gtls_bin2hex (server_write_key, + server_write_key_size, buf, + sizeof (buf))); + + if (free_keys != 0) + { + MHD_gnutls_free (server_write_key); + MHD_gnutls_free (client_write_key); + } + } + + + /* IV generation in export and non export ciphers. + */ + if (IV_size > 0 && export_flag == 0) + { + if (MHD__gnutls_sset_datum + (&session->cipher_specs.client_write_IV, &key_block[pos], + IV_size) < 0) + { + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + pos += IV_size; + + if (MHD__gnutls_sset_datum + (&session->cipher_specs.server_write_IV, &key_block[pos], + IV_size) < 0) + { + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + pos += IV_size; + + } + else if (IV_size > 0 && export_flag != 0) + { + opaque *iv_block = MHD_gnutls_alloca (IV_size * 2); + if (iv_block == NULL) + { + MHD_gnutls_assert (); + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + + if (session->security_parameters.version == MHD_GNUTLS_PROTOCOL_SSL3) + { /* SSL 3 */ + ret = MHD_gnutls_ssl3_hash_md5 ("", 0, + rrnd, TLS_RANDOM_SIZE * 2, + IV_size, iv_block); + + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (key_block); + MHD_gnutls_afree (iv_block); + return ret; + } + + ret = MHD_gnutls_ssl3_hash_md5 ("", 0, rnd, + TLS_RANDOM_SIZE * 2, + IV_size, &iv_block[IV_size]); + + } + else + { /* TLS 1.0 */ + ret = MHD_gtls_PRF (session, (const unsigned char *) "", 0, + ivblock, ivblock_length, rrnd, + 2 * TLS_RANDOM_SIZE, IV_size * 2, iv_block); + } + + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (iv_block); + MHD_gnutls_free (key_block); + return ret; + } + + if (MHD__gnutls_sset_datum + (&session->cipher_specs.client_write_IV, iv_block, IV_size) < 0) + { + MHD_gnutls_afree (iv_block); + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + + if (MHD__gnutls_sset_datum + (&session->cipher_specs.server_write_IV, + &iv_block[IV_size], IV_size) < 0) + { + MHD_gnutls_afree (iv_block); + MHD_gnutls_free (key_block); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD_gnutls_afree (iv_block); + } + + MHD_gnutls_free (key_block); + + session->cipher_specs.generated_keys = 1; + + return 0; +} + +int +MHD__gnutls_set_read_keys (MHD_gtls_session_t session) +{ + int hash_size; + int IV_size; + int key_size, export_flag; + enum MHD_GNUTLS_CipherAlgorithm algo; + enum MHD_GNUTLS_HashAlgorithm mac_algo; + + mac_algo = session->security_parameters.read_mac_algorithm; + algo = session->security_parameters.read_bulk_cipher_algorithm; + + hash_size = MHD_gnutls_hash_get_algo_len (mac_algo); + IV_size = MHD_gtls_cipher_get_iv_size (algo); + key_size = MHD__gnutls_cipher_get_key_size (algo); + export_flag = MHD_gtls_cipher_get_export_flag (algo); + + return MHD__gnutls_set_keys (session, hash_size, IV_size, key_size, + export_flag); +} + +int +MHD__gnutls_set_write_keys (MHD_gtls_session_t session) +{ + int hash_size; + int IV_size; + int key_size, export_flag; + enum MHD_GNUTLS_CipherAlgorithm algo; + enum MHD_GNUTLS_HashAlgorithm mac_algo; + + mac_algo = session->security_parameters.write_mac_algorithm; + algo = session->security_parameters.write_bulk_cipher_algorithm; + + hash_size = MHD_gnutls_hash_get_algo_len (mac_algo); + IV_size = MHD_gtls_cipher_get_iv_size (algo); + key_size = MHD__gnutls_cipher_get_key_size (algo); + export_flag = MHD_gtls_cipher_get_export_flag (algo); + + return MHD__gnutls_set_keys (session, hash_size, IV_size, key_size, + export_flag); +} + +#define CPY_COMMON dst->entity = src->entity; \ + dst->kx_algorithm = src->kx_algorithm; \ + memcpy( &dst->current_cipher_suite, &src->current_cipher_suite, sizeof(cipher_suite_st)); \ + memcpy( dst->master_secret, src->master_secret, TLS_MASTER_SIZE); \ + memcpy( dst->client_random, src->client_random, TLS_RANDOM_SIZE); \ + memcpy( dst->server_random, src->server_random, TLS_RANDOM_SIZE); \ + memcpy( dst->session_id, src->session_id, TLS_MAX_SESSION_ID_SIZE); \ + dst->session_id_size = src->session_id_size; \ + dst->cert_type = src->cert_type; \ + dst->timestamp = src->timestamp; \ + dst->max_record_recv_size = src->max_record_recv_size; \ + dst->max_record_send_size = src->max_record_send_size; \ + dst->version = src->version; \ + memcpy( &dst->extensions, &src->extensions, sizeof(MHD_gtls_ext_st)); \ + memcpy( &dst->inner_secret, &src->inner_secret, TLS_MASTER_SIZE); + +static void +MHD__gnutls_cpy_read_security_parameters (MHD_gtls_security_param_st * + dst, + MHD_gtls_security_param_st * src) +{ + CPY_COMMON; + + dst->read_bulk_cipher_algorithm = src->read_bulk_cipher_algorithm; + dst->read_mac_algorithm = src->read_mac_algorithm; + dst->read_compression_algorithm = src->read_compression_algorithm; +} + +static void +MHD__gnutls_cpy_write_security_parameters (MHD_gtls_security_param_st * + dst, + MHD_gtls_security_param_st * src) +{ + CPY_COMMON; + + dst->write_bulk_cipher_algorithm = src->write_bulk_cipher_algorithm; + dst->write_mac_algorithm = src->write_mac_algorithm; + dst->write_compression_algorithm = src->write_compression_algorithm; +} + +/* Sets the current connection session to conform with the + * Security parameters(pending session), and initializes encryption. + * Actually it initializes and starts encryption ( so it needs + * secrets and random numbers to have been negotiated) + * This is to be called after sending the Change Cipher Spec packet. + */ +int +MHD_gtls_connection_state_init (MHD_gtls_session_t session) +{ + int ret; + +/* Setup the master secret + */ + if ((ret = MHD_gtls_generate_master (session, 0), 0) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + + return 0; +} + + +/* Initializes the read connection session + * (read encrypted data) + */ +int +MHD_gtls_read_connection_state_init (MHD_gtls_session_t session) +{ + int mac_size; + int rc; + + MHD__gnutls_uint64zero (session->connection_state.read_sequence_number); + +/* Update internals from CipherSuite selected. + * If we are resuming just copy the connection session + */ + if (session->internals.resumed == RESUME_FALSE) + { + rc = MHD_gtls_set_read_cipher (session, + MHD_gtls_cipher_suite_get_cipher_algo + (&session->security_parameters. + current_cipher_suite)); + if (rc < 0) + return rc; + rc = MHD_gtls_set_read_mac (session, + MHD_gtls_cipher_suite_get_mac_algo + (&session->security_parameters. + current_cipher_suite)); + if (rc < 0) + return rc; + + rc = MHD_gtls_set_kx (session, + MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters. + current_cipher_suite)); + if (rc < 0) + return rc; + + rc = MHD_gtls_set_read_compression (session, + session->internals. + compression_method); + if (rc < 0) + return rc; + } + else + { /* RESUME_TRUE */ + MHD__gnutls_cpy_read_security_parameters (&session->security_parameters, + &session->internals. + resumed_security_parameters); + } + + + rc = MHD__gnutls_set_read_keys (session); + if (rc < 0) + return rc; + + MHD__gnutls_handshake_log ("HSK[%x]: Cipher Suite: %s\n", + session, + MHD_gtls_cipher_suite_get_name + (&session->security_parameters. + current_cipher_suite)); + + if (MHD_gtls_compression_is_ok + (session->security_parameters.read_compression_algorithm) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; + } + + if (MHD_gnutls_mac_is_ok + (session->security_parameters.read_mac_algorithm) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* Free all the previous keys/ sessions etc. + */ + if (session->connection_state.read_mac_secret.data != NULL) + MHD__gnutls_free_datum (&session->connection_state.read_mac_secret); + + if (session->connection_state.read_cipher_state != NULL) + MHD_gnutls_cipher_deinit (session->connection_state.read_cipher_state); + + mac_size = + MHD_gnutls_hash_get_algo_len (session->security_parameters. + read_mac_algorithm); + + MHD__gnutls_handshake_log + ("HSK[%x]: Initializing internal [read] cipher sessions\n", session); + + switch (session->security_parameters.entity) + { + case GNUTLS_SERVER: + /* initialize cipher session + */ + session->connection_state.read_cipher_state = + MHD_gtls_cipher_init (session->security_parameters. + read_bulk_cipher_algorithm, + &session->cipher_specs.client_write_key, + &session->cipher_specs.client_write_IV); + if (session->connection_state.read_cipher_state == GNUTLS_CIPHER_FAILED + && session->security_parameters.read_bulk_cipher_algorithm != + MHD_GNUTLS_CIPHER_NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* copy mac secrets from cipherspecs, to connection + * session. + */ + if (mac_size > 0) + { + if (MHD__gnutls_sset_datum + (&session->connection_state.read_mac_secret, + session->cipher_specs.client_write_mac_secret.data, + session->cipher_specs.client_write_mac_secret.size) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + } + + break; +#if MHD_DEBUG_TLS + case GNUTLS_CLIENT: + session->connection_state.read_cipher_state = + MHD_gtls_cipher_init (session->security_parameters. + read_bulk_cipher_algorithm, + &session->cipher_specs.server_write_key, + &session->cipher_specs.server_write_IV); + + if (session->connection_state.read_cipher_state == + GNUTLS_CIPHER_FAILED + && session->security_parameters.read_bulk_cipher_algorithm != + MHD_GNUTLS_CIPHER_NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + + /* copy mac secret to connection session + */ + if (mac_size > 0) + { + if (MHD__gnutls_sset_datum + (&session->connection_state.read_mac_secret, + session->cipher_specs.server_write_mac_secret.data, + session->cipher_specs.server_write_mac_secret.size) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + } + + break; +#endif + default: /* this check is useless */ + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + return 0; +} + + + +/* Initializes the write connection session + * (write encrypted data) + */ +int +MHD_gtls_write_connection_state_init (MHD_gtls_session_t session) +{ + int mac_size; + int rc; + + MHD__gnutls_uint64zero (session->connection_state.write_sequence_number); + +/* Update internals from CipherSuite selected. + * If we are resuming just copy the connection session + */ + if (session->internals.resumed == RESUME_FALSE) + { + rc = MHD_gtls_set_write_cipher (session, + MHD_gtls_cipher_suite_get_cipher_algo + (&session->security_parameters. + current_cipher_suite)); + if (rc < 0) + return rc; + rc = MHD_gtls_set_write_mac (session, + MHD_gtls_cipher_suite_get_mac_algo + (&session->security_parameters. + current_cipher_suite)); + if (rc < 0) + return rc; + + rc = MHD_gtls_set_kx (session, + MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters. + current_cipher_suite)); + if (rc < 0) + return rc; + + rc = MHD_gtls_set_write_compression (session, + session->internals. + compression_method); + if (rc < 0) + return rc; + } + else + { /* RESUME_TRUE */ + MHD__gnutls_cpy_write_security_parameters + (&session->security_parameters, + &session->internals.resumed_security_parameters); + } + + rc = MHD__gnutls_set_write_keys (session); + if (rc < 0) + return rc; + + MHD__gnutls_handshake_log ("HSK[%x]: Cipher Suite: %s\n", session, + MHD_gtls_cipher_suite_get_name + (&session->security_parameters. + current_cipher_suite)); + + if (MHD_gtls_compression_is_ok + (session->security_parameters.write_compression_algorithm) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; + } + + if (MHD_gnutls_mac_is_ok + (session->security_parameters.write_mac_algorithm) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + + + /* Free all the previous keys/ sessions etc. + */ + if (session->connection_state.write_mac_secret.data != NULL) + MHD__gnutls_free_datum (&session->connection_state.write_mac_secret); + + if (session->connection_state.write_cipher_state != NULL) + MHD_gnutls_cipher_deinit (session->connection_state.write_cipher_state); + + mac_size = + MHD_gnutls_hash_get_algo_len (session->security_parameters. + write_mac_algorithm); + + MHD__gnutls_handshake_log + ("HSK[%x]: Initializing internal [write] cipher sessions\n", session); + + switch (session->security_parameters.entity) + { + case GNUTLS_SERVER: + /* initialize cipher session + */ + session->connection_state.write_cipher_state = + MHD_gtls_cipher_init (session->security_parameters. + write_bulk_cipher_algorithm, + &session->cipher_specs.server_write_key, + &session->cipher_specs.server_write_IV); + + if (session->connection_state.write_cipher_state == + GNUTLS_CIPHER_FAILED + && session->security_parameters.write_bulk_cipher_algorithm != + MHD_GNUTLS_CIPHER_NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + + /* copy mac secrets from cipherspecs, to connection + * session. + */ + if (mac_size > 0) + { + if (MHD__gnutls_sset_datum + (&session->connection_state.write_mac_secret, + session->cipher_specs.server_write_mac_secret.data, + session->cipher_specs.server_write_mac_secret.size) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + } + + + break; +#if MHD_DEBUG_TLS + case GNUTLS_CLIENT: + session->connection_state.write_cipher_state = + MHD_gtls_cipher_init (session->security_parameters. + write_bulk_cipher_algorithm, + &session->cipher_specs.client_write_key, + &session->cipher_specs.client_write_IV); + + if (session->connection_state.write_cipher_state == + GNUTLS_CIPHER_FAILED + && session->security_parameters.write_bulk_cipher_algorithm != + MHD_GNUTLS_CIPHER_NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* copy mac secret to connection session + */ + if (mac_size > 0) + { + if (MHD__gnutls_sset_datum + (&session->connection_state.write_mac_secret, + session->cipher_specs.client_write_mac_secret.data, + session->cipher_specs.client_write_mac_secret.size) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + } + + break; +#endif + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + + return 0; +} + +/* Sets the specified cipher into the pending session + */ +int +MHD_gtls_set_read_cipher (MHD_gtls_session_t session, + enum MHD_GNUTLS_CipherAlgorithm algo) +{ + + if (MHD_gtls_cipher_is_ok (algo) == 0) + { + if (MHD_gtls_cipher_priority (session, algo) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNWANTED_ALGORITHM; + } + + session->security_parameters.read_bulk_cipher_algorithm = algo; + + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + return 0; + +} + +int +MHD_gtls_set_write_cipher (MHD_gtls_session_t session, + enum MHD_GNUTLS_CipherAlgorithm algo) +{ + + if (MHD_gtls_cipher_is_ok (algo) == 0) + { + if (MHD_gtls_cipher_priority (session, algo) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNWANTED_ALGORITHM; + } + + session->security_parameters.write_bulk_cipher_algorithm = algo; + + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + return 0; + +} + + +/* Sets the specified algorithm into pending compression session + */ +int +MHD_gtls_set_read_compression (MHD_gtls_session_t session, + enum MHD_GNUTLS_CompressionMethod algo) +{ + + if (MHD_gtls_compression_is_ok (algo) == 0) + { + session->security_parameters.read_compression_algorithm = algo; + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; + } + return 0; + +} + +int +MHD_gtls_set_write_compression (MHD_gtls_session_t session, + enum MHD_GNUTLS_CompressionMethod algo) +{ + + if (MHD_gtls_compression_is_ok (algo) == 0) + { + session->security_parameters.write_compression_algorithm = algo; + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; + } + return 0; + +} + +/* Sets the specified kx algorithm into pending session + */ +int +MHD_gtls_set_kx (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm algo) +{ + + if (MHD_gtls_kx_is_ok (algo) == 0) + { + session->security_parameters.kx_algorithm = algo; + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + if (MHD_gtls_kx_priority (session, algo) < 0) + { + MHD_gnutls_assert (); + /* we shouldn't get here */ + return GNUTLS_E_UNWANTED_ALGORITHM; + } + + return 0; + +} + +/* Sets the specified mac algorithm into pending session */ +int +MHD_gtls_set_read_mac (MHD_gtls_session_t session, + enum MHD_GNUTLS_HashAlgorithm algo) +{ + + if (MHD_gnutls_mac_is_ok (algo) == 0) + { + session->security_parameters.read_mac_algorithm = algo; + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + if (MHD_gtls_mac_priority (session, algo) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNWANTED_ALGORITHM; + } + + + return 0; + +} + +int +MHD_gtls_set_write_mac (MHD_gtls_session_t session, + enum MHD_GNUTLS_HashAlgorithm algo) +{ + + if (MHD_gnutls_mac_is_ok (algo) == 0) + { + session->security_parameters.write_mac_algorithm = algo; + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + if (MHD_gtls_mac_priority (session, algo) < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNWANTED_ALGORITHM; + } + + + return 0; + +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_constate.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_constate.h new file mode 100644 index 0000000000..59b67249d4 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_constate.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +int MHD_gtls_connection_state_init (MHD_gtls_session_t session); +int MHD_gtls_read_connection_state_init (MHD_gtls_session_t session); +int MHD_gtls_write_connection_state_init (MHD_gtls_session_t session); +int MHD_gtls_set_write_cipher (MHD_gtls_session_t session, + enum MHD_GNUTLS_CipherAlgorithm algo); +int MHD_gtls_set_write_mac (MHD_gtls_session_t session, + enum MHD_GNUTLS_HashAlgorithm algo); +int MHD_gtls_set_read_cipher (MHD_gtls_session_t session, + enum MHD_GNUTLS_CipherAlgorithm algo); +int MHD_gtls_set_read_mac (MHD_gtls_session_t session, + enum MHD_GNUTLS_HashAlgorithm algo); +int MHD_gtls_set_read_compression (MHD_gtls_session_t session, + enum MHD_GNUTLS_CompressionMethod algo); +int MHD_gtls_set_write_compression (MHD_gtls_session_t session, + enum MHD_GNUTLS_CompressionMethod algo); +int MHD_gtls_set_kx (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm algo); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_datum.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_datum.c new file mode 100644 index 0000000000..2f03da3bf2 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_datum.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* contains functions that make it easier to + * write vectors of <size|data>. The destination size + * should be preallocated (datum.size+(bits/8)) + */ + +#include <gnutls_int.h> +#include <gnutls_num.h> +#include <gnutls_datum.h> +#include <gnutls_errors.h> + + +void +MHD_gtls_write_datum16 (opaque * dest, MHD_gnutls_datum_t dat) +{ + MHD_gtls_write_uint16 (dat.size, dest); + if (dat.data != NULL) + memcpy (&dest[2], dat.data, dat.size); +} + +void +MHD_gtls_write_datum24 (opaque * dest, MHD_gnutls_datum_t dat) +{ + MHD_gtls_write_uint24 (dat.size, dest); + if (dat.data != NULL) + memcpy (&dest[3], dat.data, dat.size); +} + +int +MHD_gtls_set_datum_m (MHD_gnutls_datum_t * dat, const void *data, + size_t data_size, MHD_gnutls_alloc_function galloc_func) +{ + if (data_size == 0 || data == NULL) + { + dat->data = NULL; + dat->size = 0; + return 0; + } + + dat->data = galloc_func (data_size); + if (dat->data == NULL) + return GNUTLS_E_MEMORY_ERROR; + + dat->size = data_size; + memcpy (dat->data, data, data_size); + + return 0; +} + +void +MHD_gtls_free_datum_m (MHD_gnutls_datum_t * dat, + MHD_gnutls_free_function gfree_func) +{ + if (dat->data != NULL) + gfree_func (dat->data); + + dat->data = NULL; + dat->size = 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_datum.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_datum.h new file mode 100644 index 0000000000..c6813216f8 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_datum.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ +#include "gnutls_int.h" + +void MHD_gtls_write_datum16 (opaque * dest, MHD_gnutls_datum_t dat); +void MHD_gtls_write_datum24 (opaque * dest, MHD_gnutls_datum_t dat); + +int MHD_gtls_set_datum_m (MHD_gnutls_datum_t * dat, const void *data, + size_t data_size, MHD_gnutls_alloc_function); +#define MHD__gnutls_set_datum( x, y, z) MHD_gtls_set_datum_m(x,y,z, MHD_gnutls_malloc) +#define MHD__gnutls_sset_datum( x, y, z) MHD_gtls_set_datum_m(x,y,z, MHD_gnutls_secure_malloc) + +#define MHD__gnutls_datum_append(x,y,z) MHD_gtls_datum_append_m(x,y,z, MHD_gnutls_realloc) + +void MHD_gtls_free_datum_m (MHD_gnutls_datum_t * dat, + MHD_gnutls_free_function); +#define MHD__gnutls_free_datum(x) MHD_gtls_free_datum_m(x, MHD_gnutls_free) diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh.c new file mode 100644 index 0000000000..d9dd43442c --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> + + +/* + --Example-- + you: X = g ^ x mod p; + peer:Y = g ^ y mod p; + + your_key = Y ^ x mod p; + his_key = X ^ y mod p; + +// generate our secret and the public value (X) for it + X = MHD_gtls_calc_dh_secret(&x, g, p); +// now we can calculate the shared secret + key = MHD_gtls_calc_dh_key(Y, x, g, p); + MHD_gtls_mpi_release(x); + MHD_gtls_mpi_release(g); +*/ + +#define MAX_BITS 18000 + +/* returns the public value (X), and the secret (ret_x). + */ +mpi_t +MHD_gtls_calc_dh_secret (mpi_t * ret_x, mpi_t g, mpi_t prime) +{ + mpi_t e, x; + int x_size = MHD__gnutls_mpi_get_nbits (prime) - 1; + /* The size of the secret key is less than + * prime/2 + */ + + if (x_size > MAX_BITS || x_size <= 0) + { + MHD_gnutls_assert (); + return NULL; + } + + x = MHD__gnutls_mpi_new (x_size); + if (x == NULL) + { + MHD_gnutls_assert (); + if (ret_x) + *ret_x = NULL; + + return NULL; + } + + /* FIXME: (x_size/8)*8 is there to overcome a bug in libgcrypt + * which does not really check the bits given but the bytes. + */ + do + { + MHD__gnutls_mpi_randomize (x, (x_size / 8) * 8, GCRY_STRONG_RANDOM); + /* Check whether x is zero. + */ + } + while (MHD__gnutls_mpi_cmp_ui (x, 0) == 0); + + e = MHD__gnutls_mpi_alloc_like (prime); + if (e == NULL) + { + MHD_gnutls_assert (); + if (ret_x) + *ret_x = NULL; + + MHD_gtls_mpi_release (&x); + return NULL; + } + + MHD__gnutls_mpi_powm (e, g, x, prime); + + if (ret_x) + *ret_x = x; + else + MHD_gtls_mpi_release (&x); + return e; +} + + +mpi_t +MHD_gtls_calc_dh_key (mpi_t f, mpi_t x, mpi_t prime) +{ + mpi_t k; + int bits; + + bits = MHD__gnutls_mpi_get_nbits (prime); + if (bits <= 0 || bits > MAX_BITS) + { + MHD_gnutls_assert (); + return NULL; + } + + k = MHD__gnutls_mpi_alloc_like (prime); + if (k == NULL) + return NULL; + MHD__gnutls_mpi_powm (k, f, x, prime); + return k; +} + +/*- + * MHD_gtls_get_dh_params - Returns the DH parameters pointer + * @dh_params: is an DH parameters structure, or NULL. + * @func: is a callback function to receive the parameters or NULL. + * @session: a gnutls session. + * + * This function will return the dh parameters pointer. + * + -*/ +MHD_gtls_dh_params_t +MHD_gtls_get_dh_params (MHD_gtls_dh_params_t dh_params, + MHD_gnutls_params_function * func, + MHD_gtls_session_t session) +{ + MHD_gnutls_params_st params; + int ret; + + /* if cached return the cached */ + if (session->internals.params.dh_params) + return session->internals.params.dh_params; + + if (dh_params) + { + session->internals.params.dh_params = dh_params; + } + else if (func) + { + ret = func (session, GNUTLS_PARAMS_DH, ¶ms); + if (ret == 0 && params.type == GNUTLS_PARAMS_DH) + { + session->internals.params.dh_params = params.params.dh; + session->internals.params.free_dh_params = params.deinit; + } + } + + return session->internals.params.dh_params; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh.h new file mode 100644 index 0000000000..5d7341fc42 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_DH_H +# define GNUTLS_DH_H + +const mpi_t *MHD_gtls_dh_params_to_mpi (MHD_gtls_dh_params_t); +mpi_t MHD_gtls_calc_dh_secret (mpi_t * ret_x, mpi_t g, mpi_t prime); +mpi_t MHD_gtls_calc_dh_key (mpi_t f, mpi_t x, mpi_t prime); +int MHD_gtls_dh_generate_prime (mpi_t * ret_g, mpi_t * ret_n, unsigned bits); + +MHD_gtls_dh_params_t +MHD_gtls_get_dh_params (MHD_gtls_dh_params_t dh_params, + MHD_gnutls_params_function * func, + MHD_gtls_session_t session); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh_primes.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh_primes.c new file mode 100644 index 0000000000..a25759b0a5 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_dh_primes.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_datum.h> +#include <x509_b64.h> /* for PKCS3 PEM decoding */ +#include <gnutls_global.h> +#include <gnutls_dh.h> +#include "debug.h" +/* x509 */ +#include "mpi.h" + + +/* returns the prime and the generator of DH params. + */ +const mpi_t * +MHD_gtls_dh_params_to_mpi (MHD_gtls_dh_params_t dh_primes) +{ + if (dh_primes == NULL || dh_primes->params[1] == NULL + || dh_primes->params[0] == NULL) + { + return NULL; + } + + return dh_primes->params; +} + +int +MHD_gtls_dh_generate_prime (mpi_t * ret_g, mpi_t * ret_n, unsigned int bits) +{ + mpi_t g = NULL, prime = NULL; + gcry_error_t err; + int result, times = 0, qbits; + mpi_t *factors = NULL; + + /* Calculate the size of a prime factor of (prime-1)/2. + * This is an emulation of the values in "Selecting Cryptographic Key Sizes" paper. + */ + if (bits < 256) + qbits = bits / 2; + else + { + qbits = (bits / 40) + 105; + } + + if (qbits & 1) /* better have an even number */ + qbits++; + + /* find a prime number of size bits. + */ + do + { + + if (times) + { + MHD_gtls_mpi_release (&prime); + gcry_prime_release_factors (factors); + } + + err = gcry_prime_generate (&prime, bits, qbits, &factors, NULL, NULL, + GCRY_STRONG_RANDOM, + GCRY_PRIME_FLAG_SPECIAL_FACTOR); + + if (err != 0) + { + MHD_gnutls_assert (); + result = GNUTLS_E_INTERNAL_ERROR; + goto cleanup; + } + + err = gcry_prime_check (prime, 0); + + times++; + } + while (err != 0 && times < 10); + + if (err != 0) + { + MHD_gnutls_assert (); + result = GNUTLS_E_INTERNAL_ERROR; + goto cleanup; + } + + /* generate the group generator. + */ + err = gcry_prime_group_generator (&g, prime, factors, NULL); + if (err != 0) + { + MHD_gnutls_assert (); + result = GNUTLS_E_INTERNAL_ERROR; + goto cleanup; + } + + gcry_prime_release_factors (factors); + factors = NULL; + + if (ret_g) + *ret_g = g; + else + MHD_gtls_mpi_release (&g); + if (ret_n) + *ret_n = prime; + else + MHD_gtls_mpi_release (&prime); + + return 0; + +cleanup:gcry_prime_release_factors (factors); + MHD_gtls_mpi_release (&g); + MHD_gtls_mpi_release (&prime); + + return result; + +} + +/* Replaces the prime in the static DH parameters, with a randomly + * generated one. + */ +/** + * MHD__gnutls_dh_params_init - This function will initialize the DH parameters + * @dh_params: Is a structure that will hold the prime numbers + * + * This function will initialize the DH parameters structure. + * + **/ +int +MHD__gnutls_dh_params_init (MHD_gtls_dh_params_t * dh_params) +{ + + (*dh_params) = MHD_gnutls_calloc (1, sizeof (MHD_gtls_dh_params_st)); + if (*dh_params == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; + +} + +/** + * MHD__gnutls_dh_params_deinit - This function will deinitialize the DH parameters + * @dh_params: Is a structure that holds the prime numbers + * + * This function will deinitialize the DH parameters structure. + * + **/ +void +MHD__gnutls_dh_params_deinit (MHD_gtls_dh_params_t dh_params) +{ + if (dh_params == NULL) + return; + + MHD_gtls_mpi_release (&dh_params->params[0]); + MHD_gtls_mpi_release (&dh_params->params[1]); + + MHD_gnutls_free (dh_params); + +} + +/** + * MHD__gnutls_dh_params_generate2 - This function will generate new DH parameters + * @params: Is the structure that the DH parameters will be stored + * @bits: is the prime's number of bits + * + * This function will generate a new pair of prime and generator for use in + * the Diffie-Hellman key exchange. The new parameters will be allocated using + * MHD_gnutls_malloc() and will be stored in the appropriate datum. + * This function is normally slow. + * + * Note that the bits value should be one of 768, 1024, 2048, 3072 or 4096. + * Also note that the DH parameters are only useful to servers. + * Since clients use the parameters sent by the server, it's of + * no use to call this in client side. + * + **/ +int +MHD__gnutls_dh_params_generate2 (MHD_gtls_dh_params_t params, + unsigned int bits) +{ + int ret; + + ret = + MHD_gtls_dh_generate_prime (¶ms->params[1], ¶ms->params[0], bits); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_errors.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_errors.c new file mode 100644 index 0000000000..48b8a562da --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_errors.c @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include "gnutls_errors.h" +#include <libtasn1.h> +#ifdef STDC_HEADERS +# include <stdarg.h> +#endif + +/* I18n of error codes. */ +#define _(String) (String) +#define N_(String) (String) + +extern LOG_FUNC MHD__gnutls_log_func; + +#define ERROR_ENTRY(desc, name, fatal) \ + { desc, #name, name, fatal} + +struct MHD_gnutls_error_entry +{ + const char *desc; + const char *_name; + int number; + int fatal; +}; +typedef struct MHD_gnutls_error_entry MHD_gnutls_error_entry; + +static const MHD_gnutls_error_entry MHD_gtls_error_algorithms[] = { + /* "Short Description", Error code define, critical (0,1) -- 1 in most cases */ + ERROR_ENTRY (N_("Success."), GNUTLS_E_SUCCESS, 0), + ERROR_ENTRY (N_("Could not negotiate a supported cipher suite."), + GNUTLS_E_UNKNOWN_CIPHER_SUITE, 1), + ERROR_ENTRY (N_("The cipher type is unsupported."), + GNUTLS_E_UNKNOWN_CIPHER_TYPE, 1), + ERROR_ENTRY (N_("The certificate and the given key do not match."), + GNUTLS_E_CERTIFICATE_KEY_MISMATCH, 1), + ERROR_ENTRY (N_("Could not negotiate a supported compression method."), + GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM, 1), + ERROR_ENTRY (N_("An unknown public key algorithm was encountered."), + GNUTLS_E_UNKNOWN_PK_ALGORITHM, 1), + + ERROR_ENTRY (N_("An algorithm that is not enabled was negotiated."), + GNUTLS_E_UNWANTED_ALGORITHM, 1), + ERROR_ENTRY (N_("A large TLS record packet was received."), + GNUTLS_E_LARGE_PACKET, 1), + ERROR_ENTRY (N_("A record packet with illegal version was received."), + GNUTLS_E_UNSUPPORTED_VERSION_PACKET, 1), + ERROR_ENTRY (N_ + ("The Diffie Hellman prime sent by the server is not acceptable (not long enough)."), + GNUTLS_E_DH_PRIME_UNACCEPTABLE, 1), + ERROR_ENTRY (N_("A TLS packet with unexpected length was received."), + GNUTLS_E_UNEXPECTED_PACKET_LENGTH, 1), + ERROR_ENTRY (N_ + ("The specified session has been invalidated for some reason."), + GNUTLS_E_INVALID_SESSION, 1), + + ERROR_ENTRY (N_("GnuTLS internal error."), GNUTLS_E_INTERNAL_ERROR, 1), + ERROR_ENTRY (N_("An illegal TLS extension was received."), + GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION, 1), + ERROR_ENTRY (N_("A TLS fatal alert has been received."), + GNUTLS_E_FATAL_ALERT_RECEIVED, 1), + ERROR_ENTRY (N_("An unexpected TLS packet was received."), + GNUTLS_E_UNEXPECTED_PACKET, 1), + ERROR_ENTRY (N_("A TLS warning alert has been received."), + GNUTLS_E_WARNING_ALERT_RECEIVED, 0), + ERROR_ENTRY (N_ + ("An error was encountered at the TLS Finished packet calculation."), + GNUTLS_E_ERROR_IN_FINISHED_PACKET, 1), + ERROR_ENTRY (N_("The peer did not send any certificate."), + GNUTLS_E_NO_CERTIFICATE_FOUND, 1), + + ERROR_ENTRY (N_("No temporary RSA parameters were found."), + GNUTLS_E_NO_TEMPORARY_RSA_PARAMS, 1), + ERROR_ENTRY (N_("No temporary DH parameters were found."), + GNUTLS_E_NO_TEMPORARY_DH_PARAMS, 1), + ERROR_ENTRY (N_("An unexpected TLS handshake packet was received."), + GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET, 1), + ERROR_ENTRY (N_("The scanning of a large integer has failed."), + GNUTLS_E_MPI_SCAN_FAILED, 1), + ERROR_ENTRY (N_("Could not export a large integer."), + GNUTLS_E_MPI_PRINT_FAILED, 1), + ERROR_ENTRY (N_("Decryption has failed."), GNUTLS_E_DECRYPTION_FAILED, 1), + ERROR_ENTRY (N_("Encryption has failed."), GNUTLS_E_ENCRYPTION_FAILED, 1), + ERROR_ENTRY (N_("Public key decryption has failed."), + GNUTLS_E_PK_DECRYPTION_FAILED, 1), + ERROR_ENTRY (N_("Public key encryption has failed."), + GNUTLS_E_PK_ENCRYPTION_FAILED, 1), + ERROR_ENTRY (N_("Public key signing has failed."), GNUTLS_E_PK_SIGN_FAILED, + 1), + ERROR_ENTRY (N_("Public key signature verification has failed."), + GNUTLS_E_PK_SIG_VERIFY_FAILED, 1), + ERROR_ENTRY (N_("Decompression of the TLS record packet has failed."), + GNUTLS_E_DECOMPRESSION_FAILED, 1), + ERROR_ENTRY (N_("Compression of the TLS record packet has failed."), + GNUTLS_E_COMPRESSION_FAILED, 1), + + ERROR_ENTRY (N_("Internal error in memory allocation."), + GNUTLS_E_MEMORY_ERROR, 1), + ERROR_ENTRY (N_("An unimplemented or disabled feature has been requested."), + GNUTLS_E_UNIMPLEMENTED_FEATURE, 1), + ERROR_ENTRY (N_("Insufficient credentials for that request."), + GNUTLS_E_INSUFFICIENT_CREDENTIALS, 1), + ERROR_ENTRY (N_("Error in password file."), GNUTLS_E_SRP_PWD_ERROR, 1), + ERROR_ENTRY (N_("Wrong padding in PKCS1 packet."), GNUTLS_E_PKCS1_WRONG_PAD, + 1), + ERROR_ENTRY (N_("The requested session has expired."), GNUTLS_E_EXPIRED, 1), + ERROR_ENTRY (N_("Hashing has failed."), GNUTLS_E_HASH_FAILED, 1), + ERROR_ENTRY (N_("Base64 decoding error."), GNUTLS_E_BASE64_DECODING_ERROR, + 1), + ERROR_ENTRY (N_("Base64 unexpected header error."), + GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR, + 1), + ERROR_ENTRY (N_("Base64 encoding error."), GNUTLS_E_BASE64_ENCODING_ERROR, + 1), + ERROR_ENTRY (N_("Parsing error in password file."), + GNUTLS_E_SRP_PWD_PARSING_ERROR, 1), + ERROR_ENTRY (N_("The requested data were not available."), + GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE, 0), + ERROR_ENTRY (N_("Error in the pull function."), GNUTLS_E_PULL_ERROR, 1), + ERROR_ENTRY (N_("Error in the push function."), GNUTLS_E_PUSH_ERROR, 1), + ERROR_ENTRY (N_ + ("The upper limit of record packet sequence numbers has been reached. Wow!"), + GNUTLS_E_RECORD_LIMIT_REACHED, 1), + ERROR_ENTRY (N_("Error in the certificate."), GNUTLS_E_CERTIFICATE_ERROR, + 1), + ERROR_ENTRY (N_("Unknown Subject Alternative name in X.509 certificate."), + GNUTLS_E_X509_UNKNOWN_SAN, 1), + + ERROR_ENTRY (N_("Unsupported critical extension in X.509 certificate."), + GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION, 1), + ERROR_ENTRY (N_("Key usage violation in certificate has been detected."), + GNUTLS_E_KEY_USAGE_VIOLATION, 1), + ERROR_ENTRY (N_("Function was interrupted."), GNUTLS_E_AGAIN, 0), + ERROR_ENTRY (N_("Function was interrupted."), GNUTLS_E_INTERRUPTED, 0), + ERROR_ENTRY (N_("Rehandshake was requested by the peer."), + GNUTLS_E_REHANDSHAKE, 0), + ERROR_ENTRY (N_ + ("TLS Application data were received, while expecting handshake data."), + GNUTLS_E_GOT_APPLICATION_DATA, 1), + ERROR_ENTRY (N_("Error in Database backend."), GNUTLS_E_DB_ERROR, 1), + ERROR_ENTRY (N_("The certificate type is not supported."), + GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE, 1), + ERROR_ENTRY (N_("The given memory buffer is too short to hold parameters."), + GNUTLS_E_SHORT_MEMORY_BUFFER, 1), + ERROR_ENTRY (N_("The request is invalid."), GNUTLS_E_INVALID_REQUEST, 1), + ERROR_ENTRY (N_("An illegal parameter has been received."), + GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1), + ERROR_ENTRY (N_("Error while reading file."), GNUTLS_E_FILE_ERROR, 1), + + ERROR_ENTRY (N_("ASN1 parser: Element was not found."), + GNUTLS_E_ASN1_ELEMENT_NOT_FOUND, 1), + ERROR_ENTRY (N_("ASN1 parser: Identifier was not found"), + GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND, 1), + ERROR_ENTRY (N_("ASN1 parser: Error in DER parsing."), + GNUTLS_E_ASN1_DER_ERROR, 1), + ERROR_ENTRY (N_("ASN1 parser: Value was not found."), + GNUTLS_E_ASN1_VALUE_NOT_FOUND, 1), + ERROR_ENTRY (N_("ASN1 parser: Generic parsing error."), + GNUTLS_E_ASN1_GENERIC_ERROR, 1), + ERROR_ENTRY (N_("ASN1 parser: Value is not valid."), + GNUTLS_E_ASN1_VALUE_NOT_VALID, 1), + ERROR_ENTRY (N_("ASN1 parser: Error in TAG."), GNUTLS_E_ASN1_TAG_ERROR, 1), + ERROR_ENTRY (N_("ASN1 parser: error in implicit tag"), + GNUTLS_E_ASN1_TAG_IMPLICIT, 1), + ERROR_ENTRY (N_("ASN1 parser: Error in type 'ANY'."), + GNUTLS_E_ASN1_TYPE_ANY_ERROR, 1), + ERROR_ENTRY (N_("ASN1 parser: Syntax error."), GNUTLS_E_ASN1_SYNTAX_ERROR, + 1), + ERROR_ENTRY (N_("ASN1 parser: Overflow in DER parsing."), + GNUTLS_E_ASN1_DER_OVERFLOW, 1), + + ERROR_ENTRY (N_("Too many empty record packets have been received."), + GNUTLS_E_TOO_MANY_EMPTY_PACKETS, 1), + ERROR_ENTRY (N_("The initialization of GnuTLS-extra has failed."), + GNUTLS_E_INIT_LIBEXTRA, 1), + ERROR_ENTRY (N_ + ("The GnuTLS library version does not match the GnuTLS-extra library version."), + GNUTLS_E_LIBRARY_VERSION_MISMATCH, 1), + ERROR_ENTRY (N_("The gcrypt library version is too old."), + GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY, 1), + + ERROR_ENTRY (N_("The tasn1 library version is too old."), + GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY, 1), + + ERROR_ENTRY (N_("The initialization of LZO has failed."), + GNUTLS_E_LZO_INIT_FAILED, 1), + ERROR_ENTRY (N_("No supported compression algorithms have been found."), + GNUTLS_E_NO_COMPRESSION_ALGORITHMS, 1), + ERROR_ENTRY (N_("No supported cipher suites have been found."), + GNUTLS_E_NO_CIPHER_SUITES, 1), + ERROR_ENTRY (N_("The SRP username supplied is illegal."), + GNUTLS_E_ILLEGAL_SRP_USERNAME, 1), + + ERROR_ENTRY (N_("The certificate has unsupported attributes."), + GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE, 1), + ERROR_ENTRY (N_("The OID is not supported."), GNUTLS_E_X509_UNSUPPORTED_OID, + 1), + ERROR_ENTRY (N_("The hash algorithm is unknown."), + GNUTLS_E_UNKNOWN_HASH_ALGORITHM, 1), + ERROR_ENTRY (N_("The PKCS structure's content type is unknown."), + GNUTLS_E_UNKNOWN_PKCS_CONTENT_TYPE, 1), + ERROR_ENTRY (N_("The PKCS structure's bag type is unknown."), + GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE, 1), + ERROR_ENTRY (N_("The given password contains invalid characters."), + GNUTLS_E_INVALID_PASSWORD, 1), + ERROR_ENTRY (N_("The Message Authentication Code verification failed."), + GNUTLS_E_MAC_VERIFY_FAILED, 1), + ERROR_ENTRY (N_("Some constraint limits were reached."), + GNUTLS_E_CONSTRAINT_ERROR, 1), + ERROR_ENTRY (N_("Failed to acquire random data."), GNUTLS_E_RANDOM_FAILED, + 1), + + ERROR_ENTRY (N_("Received a TLS/IA Intermediate Phase Finished message"), + GNUTLS_E_WARNING_IA_IPHF_RECEIVED, 0), + ERROR_ENTRY (N_("Received a TLS/IA Final Phase Finished message"), + GNUTLS_E_WARNING_IA_FPHF_RECEIVED, 0), + ERROR_ENTRY (N_("Verifying TLS/IA phase checksum failed"), + GNUTLS_E_IA_VERIFY_FAILED, 1), + + ERROR_ENTRY (N_("The specified algorithm or protocol is unknown."), + GNUTLS_E_UNKNOWN_ALGORITHM, 1), + + {NULL, NULL, 0, 0} +}; + +#define GNUTLS_ERROR_LOOP(b) \ + const MHD_gnutls_error_entry *p; \ + for(p = MHD_gtls_error_algorithms; p->desc != NULL; p++) { b ; } + +#define GNUTLS_ERROR_ALG_LOOP(a) \ + GNUTLS_ERROR_LOOP( if(p->number == error) { a; break; } ) + + + +/** + * MHD_gtls_error_is_fatal - Returns non-zero in case of a fatal error + * @error: is an error returned by a gnutls function. Error should be a negative value. + * + * If a function returns a negative value you may feed that value + * to this function to see if it is fatal. Returns 1 for a fatal + * error 0 otherwise. However you may want to check the + * error code manually, since some non-fatal errors to the protocol + * may be fatal for you (your program). + * + * This is only useful if you are dealing with errors from the + * record layer or the handshake layer. + * + * For positive @error values, 0 is returned. + * + **/ +int +MHD_gtls_error_is_fatal (int error) +{ + int ret = 1; + + /* Input sanitzation. Positive values are not errors at all, and + definitely not fatal. */ + if (error > 0) + return 0; + + GNUTLS_ERROR_ALG_LOOP (ret = p->fatal); + + return ret; +} + +/** + * MHD_gtls_perror - prints a string to stderr with a description of an error + * @error: is an error returned by a gnutls function. Error is always a negative value. + * + * This function is like perror(). The only difference is that it accepts an + * error number returned by a gnutls function. + **/ +void +MHD_gtls_perror (int error) +{ + const char *ret = NULL; + + /* avoid prefix */ + GNUTLS_ERROR_ALG_LOOP (ret = p->desc); + if (ret == NULL) + ret = "(unknown)"; + fprintf (stderr, "GNUTLS ERROR: %s\n", _(ret)); +} + + +/** + * MHD_gtls_strerror - Returns a string with a description of an error + * @error: is an error returned by a gnutls function. Error is always a negative value. + * + * This function is similar to strerror(). Differences: it accepts an error + * number returned by a gnutls function; In case of an unknown error + * a descriptive string is sent instead of NULL. + **/ +const char * +MHD_gtls_strerror (int error) +{ + const char *ret = NULL; + + /* avoid prefix */ + GNUTLS_ERROR_ALG_LOOP (ret = p->desc); + if (ret == NULL) + return "(unknown error code)"; + return _(ret); +} + +/* This will print the actual define of the + * given error code. + */ +const char * +MHD__gnutls_strerror (int error) +{ + const char *ret = NULL; + + /* avoid prefix */ + GNUTLS_ERROR_ALG_LOOP (ret = p->_name); + + return _(ret); +} + +int +MHD_gtls_asn2err (int asn_err) +{ + switch (asn_err) + { + case ASN1_FILE_NOT_FOUND: + return GNUTLS_E_FILE_ERROR; + case ASN1_ELEMENT_NOT_FOUND: + return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND; + case ASN1_IDENTIFIER_NOT_FOUND: + return GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND; + case ASN1_DER_ERROR: + return GNUTLS_E_ASN1_DER_ERROR; + case ASN1_VALUE_NOT_FOUND: + return GNUTLS_E_ASN1_VALUE_NOT_FOUND; + case ASN1_GENERIC_ERROR: + return GNUTLS_E_ASN1_GENERIC_ERROR; + case ASN1_VALUE_NOT_VALID: + return GNUTLS_E_ASN1_VALUE_NOT_VALID; + case ASN1_TAG_ERROR: + return GNUTLS_E_ASN1_TAG_ERROR; + case ASN1_TAG_IMPLICIT: + return GNUTLS_E_ASN1_TAG_IMPLICIT; + case ASN1_ERROR_TYPE_ANY: + return GNUTLS_E_ASN1_TYPE_ANY_ERROR; + case ASN1_SYNTAX_ERROR: + return GNUTLS_E_ASN1_SYNTAX_ERROR; + case ASN1_MEM_ERROR: + return GNUTLS_E_SHORT_MEMORY_BUFFER; + case ASN1_MEM_ALLOC_ERROR: + return GNUTLS_E_MEMORY_ERROR; + case ASN1_DER_OVERFLOW: + return GNUTLS_E_ASN1_DER_OVERFLOW; + default: + return GNUTLS_E_ASN1_GENERIC_ERROR; + } +} + + +/* this function will output a message using the + * caller provided function + */ +void +MHD_gtls_log (int level, const char *fmt, ...) +{ + va_list args; + char str[MAX_LOG_SIZE]; + void (*log_func) (int, const char *) = MHD__gnutls_log_func; + + if (MHD__gnutls_log_func == NULL) + return; + + va_start (args, fmt); + vsnprintf (str, MAX_LOG_SIZE - 1, fmt, args); /* Flawfinder: ignore */ + va_end (args); + + log_func (level, str); +} + +void +MHD__gnutls_null_log (void *n, ...) +{ +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_errors.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_errors.h new file mode 100644 index 0000000000..ecde580b11 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_errors.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <defines.h> + +#define GNUTLS_E_INT_RET_0 -1251 + +#ifdef __FILE__ +# ifdef __LINE__ +# define MHD_gnutls_assert() MHD__gnutls_debug_log( "ASSERT: %s:%d\n", __FILE__,__LINE__); +# else +# define MHD_gnutls_assert() +# endif +#else /* __FILE__ not defined */ +# define MHD_gnutls_assert() +#endif + +int MHD_gtls_asn2err (int asn_err); +void MHD_gtls_log (int, const char *fmt, ...); + +extern int MHD__gnutls_log_level; + +#ifdef C99_MACROS +#define LEVEL(l, ...) if (MHD__gnutls_log_level >= l || MHD__gnutls_log_level > 9) \ + MHD_gtls_log( l, __VA_ARGS__) + +#define LEVEL_EQ(l, ...) if (MHD__gnutls_log_level == l || MHD__gnutls_log_level > 9) \ + MHD_gtls_log( l, __VA_ARGS__) + +# define MHD__gnutls_debug_log(...) LEVEL(2, __VA_ARGS__) +# define MHD__gnutls_handshake_log(...) LEVEL(3, __VA_ARGS__) +# define MHD__gnutls_buffers_log(...) LEVEL_EQ(6, __VA_ARGS__) +# define MHD__gnutls_hard_log(...) LEVEL(9, __VA_ARGS__) +# define MHD__gnutls_record_log(...) LEVEL(4, __VA_ARGS__) +# define MHD__gnutls_read_log(...) LEVEL_EQ(7, __VA_ARGS__) +# define MHD__gnutls_write_log(...) LEVEL_EQ(7, __VA_ARGS__) +# define MHD__gnutls_x509_log(...) LEVEL(1, __VA_ARGS__) +#else +# define MHD__gnutls_debug_log MHD__gnutls_null_log +# define MHD__gnutls_handshake_log MHD__gnutls_null_log +# define MHD__gnutls_buffers_log MHD__gnutls_null_log +# define MHD__gnutls_hard_log MHD__gnutls_null_log +# define MHD__gnutls_record_log MHD__gnutls_null_log +# define MHD__gnutls_read_log MHD__gnutls_null_log +# define MHD__gnutls_write_log MHD__gnutls_null_log +# define MHD__gnutls_x509_log MHD__gnutls_null_log + +void MHD__gnutls_null_log (void *, ...); + +#endif /* C99_MACROS */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_extensions.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_extensions.c new file mode 100644 index 0000000000..8ee96c6594 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_extensions.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions that relate to the TLS hello extension parsing. + * Hello extensions are packets appended in the TLS hello packet, and + * allow for extra functionality. + */ + +#include "MHD_config.h" +#include "gnutls_int.h" +#include "gnutls_extensions.h" +#include "gnutls_errors.h" +#include "ext_max_record.h" +#include <ext_cert_type.h> +#include <ext_server_name.h> +#include <gnutls_num.h> + +/* Key Exchange Section */ +#define GNUTLS_EXTENSION_ENTRY(type, parse_type, ext_func_recv, ext_func_send) \ + { #type, type, parse_type, ext_func_recv, ext_func_send } + + +#define MAX_EXT_SIZE 10 +const int MHD_gtls_extensions_size = MAX_EXT_SIZE; + +MHD_gtls_extension_entry MHD_gtls_extensions[MAX_EXT_SIZE] = { + GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_MAX_RECORD_SIZE, + EXTENSION_TLS, + MHD_gtls_max_record_recv_params, + MHD_gtls_max_record_send_params), + GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_CERT_TYPE, + EXTENSION_TLS, + MHD_gtls_cert_type_recv_params, + MHD_gtls_cert_type_send_params), + GNUTLS_EXTENSION_ENTRY (GNUTLS_EXTENSION_SERVER_NAME, + EXTENSION_APPLICATION, + MHD_gtls_server_name_recv_params, + MHD_gtls_server_name_send_params), + {0, 0, 0, 0} +}; + +#define GNUTLS_EXTENSION_LOOP2(b) \ + MHD_gtls_extension_entry *p; \ + for(p = MHD_gtls_extensions; p->name != NULL; p++) { b ; } + +#define GNUTLS_EXTENSION_LOOP(a) \ + GNUTLS_EXTENSION_LOOP2( if(p->type == type) { a; break; } ) + + +/* EXTENSION functions */ + +MHD_gtls_ext_recv_func +MHD_gtls_ext_func_recv (uint16_t type, MHD_gtls_ext_parse_type_t parse_type) +{ + MHD_gtls_ext_recv_func ret = NULL; + GNUTLS_EXTENSION_LOOP (if + (parse_type == EXTENSION_ANY + || p->parse_type == parse_type) ret = + p->MHD_gnutls_ext_func_recv); + return ret; + +} + +MHD_gtls_ext_send_func +MHD_gtls_ext_func_send (uint16_t type) +{ + MHD_gtls_ext_send_func ret = NULL; + GNUTLS_EXTENSION_LOOP (ret = p->MHD_gnutls_ext_func_send); + return ret; + +} + +const char * +MHD_gtls_extension_get_name (uint16_t type) +{ + const char *ret = NULL; + + /* avoid prefix */ + GNUTLS_EXTENSION_LOOP (ret = p->name + sizeof ("GNUTLS_EXTENSION_") - 1); + + return ret; +} + +/* Checks if the extension we just received is one of the + * requested ones. Otherwise it's a fatal error. + */ +static int +MHD__gnutls_extension_list_check (MHD_gtls_session_t session, uint16_t type) +{ +#if MHD_DEBUG_TLS + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + int i; + for (i = 0; i < session->internals.extensions_sent_size; i++) + { + if (type == session->internals.extensions_sent[i]) + return 0; /* ok found */ + } + return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION; + } +#endif + return 0; +} + +int +MHD_gtls_parse_extensions (MHD_gtls_session_t session, + MHD_gtls_ext_parse_type_t parse_type, + const opaque * data, int data_size) +{ + int next, ret; + int pos = 0; + uint16_t type; + const opaque *sdata; + MHD_gtls_ext_recv_func ext_recv; + uint16_t size; + +#if MHD_DEBUG_TLS + int i; + if (session->security_parameters.entity == GNUTLS_CLIENT) + for (i = 0; i < session->internals.extensions_sent_size; i++) + { + MHD__gnutls_debug_log ("EXT[%d]: expecting extension '%s'\n", + session, + MHD_gtls_extension_get_name + (session->internals.extensions_sent[i])); + } +#endif + + DECR_LENGTH_RET (data_size, 2, 0); + next = MHD_gtls_read_uint16 (data); + pos += 2; + + DECR_LENGTH_RET (data_size, next, 0); + + do + { + DECR_LENGTH_RET (next, 2, 0); + type = MHD_gtls_read_uint16 (&data[pos]); + pos += 2; + + MHD__gnutls_debug_log ("EXT[%x]: Received extension '%s/%d'\n", session, + MHD_gtls_extension_get_name (type), type); + + if ((ret = MHD__gnutls_extension_list_check (session, type)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + DECR_LENGTH_RET (next, 2, 0); + size = MHD_gtls_read_uint16 (&data[pos]); + pos += 2; + + DECR_LENGTH_RET (next, size, 0); + sdata = &data[pos]; + pos += size; + + ext_recv = MHD_gtls_ext_func_recv (type, parse_type); + if (ext_recv == NULL) + continue; + if ((ret = ext_recv (session, sdata, size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + } + while (next > 2); + + return 0; + +} + +/* Adds the extension we want to send in the extensions list. + * This list is used to check whether the (later) received + * extensions are the ones we requested. + */ +static void +MHD__gnutls_extension_list_add (MHD_gtls_session_t session, uint16_t type) +{ +#if MHD_DEBUG_TLS + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + if (session->internals.extensions_sent_size < MAX_EXT_TYPES) + { + session->internals.extensions_sent[session->internals. + extensions_sent_size] = type; + session->internals.extensions_sent_size++; + } + else + { + MHD__gnutls_debug_log ("extensions: Increase MAX_EXT_TYPES\n"); + } + } +#endif +} + +int +MHD_gtls_gen_extensions (MHD_gtls_session_t session, opaque * data, + size_t data_size) +{ + int size; + uint16_t pos = 0; + opaque *sdata; + int sdata_size; + MHD_gtls_ext_send_func ext_send; + MHD_gtls_extension_entry *p; + + if (data_size < 2) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* allocate enough data for each extension. + */ + sdata_size = data_size; + sdata = MHD_gnutls_malloc (sdata_size); + if (sdata == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + pos += 2; + for (p = MHD_gtls_extensions; p->name != NULL; p++) + { + ext_send = MHD_gtls_ext_func_send (p->type); + if (ext_send == NULL) + continue; + size = ext_send (session, sdata, sdata_size); + if (size > 0) + { + if (data_size < pos + (size_t) size + 4) + { + MHD_gnutls_assert (); + MHD_gnutls_free (sdata); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* write extension type */ + MHD_gtls_write_uint16 (p->type, &data[pos]); + pos += 2; + + /* write size */ + MHD_gtls_write_uint16 (size, &data[pos]); + pos += 2; + + memcpy (&data[pos], sdata, size); + pos += size; + + /* add this extension to the extension list + */ + MHD__gnutls_extension_list_add (session, p->type); + + MHD__gnutls_debug_log ("EXT[%x]: Sending extension %s\n", session, + MHD_gtls_extension_get_name (p->type)); + } + else if (size < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (sdata); + return size; + } + } + + size = pos; + pos -= 2; /* remove the size of the size header! */ + + MHD_gtls_write_uint16 (pos, data); + + if (size == 2) + { /* empty */ + size = 0; + } + + MHD_gnutls_free (sdata); + return size; + +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_extensions.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_extensions.h new file mode 100644 index 0000000000..9623b39b43 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_extensions.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> + +const char *MHD_gtls_extension_get_name (uint16_t type); +int MHD_gtls_parse_extensions (MHD_gtls_session_t, MHD_gtls_ext_parse_type_t, + const opaque *, int); +int MHD_gtls_gen_extensions (MHD_gtls_session_t session, opaque * data, + size_t data_size); + +typedef int (*MHD_gtls_ext_recv_func) (MHD_gtls_session_t, const opaque *, size_t); /* recv data */ +typedef int (*MHD_gtls_ext_send_func) (MHD_gtls_session_t, opaque *, size_t); /* send data */ + +MHD_gtls_ext_send_func MHD_gtls_ext_func_send (uint16_t type); +MHD_gtls_ext_recv_func MHD_gtls_ext_func_recv (uint16_t type, + MHD_gtls_ext_parse_type_t); + +typedef struct +{ + const char *name; + uint16_t type; + MHD_gtls_ext_parse_type_t parse_type; + MHD_gtls_ext_recv_func MHD_gnutls_ext_func_recv; + MHD_gtls_ext_send_func MHD_gnutls_ext_func_send; +} MHD_gtls_extension_entry; diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_global.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_global.c new file mode 100644 index 0000000000..818a92a100 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_global.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <libtasn1.h> +#include <gnutls_dh.h> + +/* this is used in order to make the multi-threaded initialization call to libgcrypt */ +#include <pthread.h> +#include <gcrypt.h> + +/* used to set the MHD_tls logging function */ +#include "internal.h" + +/* TODO fix : needed by GCRY_THREAD_OPTION_PTHREAD_IMPL but missing otherwise */ +#define ENOMEM 12 /* Out of memory */ + +#ifdef HAVE_WINSOCK +# include <winsock2.h> +#endif + + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +#define MHD_gnutls_log_func LOG_FUNC + +/* created by asn1c */ +extern const ASN1_ARRAY_TYPE MHD_gnutlsMHD__asn1_tab[]; +extern const ASN1_ARRAY_TYPE MHD_pkix_asn1_tab[]; + +LOG_FUNC MHD__gnutls_log_func; +int MHD__gnutls_log_level = 0; /* default log level */ + +ASN1_TYPE MHD__gnutls_pkix1_asn; +ASN1_TYPE MHD__gnutlsMHD__gnutls_asn; + +/** + * MHD_gtls_global_set_log_function - This function sets the logging function + * @log_func: it's a log function + * + * This is the function where you set the logging function gnutls + * is going to use. This function only accepts a character array. + * Normally you may not use this function since it is only used + * for debugging purposes. + * + * MHD_gnutls_log_func is of the form, + * void (*MHD_gnutls_log_func)( int level, const char*); + **/ +void +MHD_gtls_global_set_log_function (MHD_gnutls_log_func log_func) +{ + MHD__gnutls_log_func = log_func; +} + +/** + * MHD_gtls_global_set_log_level - This function sets the logging level + * @level: it's an integer from 0 to 9. + * + * This is the function that allows you to set the log level. + * The level is an integer between 0 and 9. Higher values mean + * more verbosity. The default value is 0. Larger values should + * only be used with care, since they may reveal sensitive information. + * + * Use a log level over 10 to enable all debugging options. + * + **/ +void +MHD_gtls_global_set_log_level (int level) +{ + MHD__gnutls_log_level = level; +} + +int MHD__gnutls_is_secure_mem_null (const void *); + +static int MHD__gnutls_init_level = 0; + +/** + * MHD__gnutls_global_init - This function initializes the global data to defaults. + * + * This function initializes the global data to defaults. + * Every gnutls application has a global data which holds common parameters + * shared by gnutls session structures. + * You must call MHD__gnutls_global_deinit() when gnutls usage is no longer needed + * Returns zero on success. + * + * Note that this function will also initialize libgcrypt, if it has not + * been initialized before. Thus if you want to manually initialize libgcrypt + * you must do it before calling this function. This is useful in cases you + * want to disable libgcrypt's internal lockings etc. + * + * This function increment a global counter, so that + * MHD__gnutls_global_deinit() only releases resources when it has been + * called as many times as MHD__gnutls_global_init(). This is useful when + * GnuTLS is used by more than one library in an application. This + * function can be called many times, but will only do something the + * first time. + * + * Note! This function is not thread safe. If two threads call this + * function simultaneously, they can cause a race between checking + * the global counter and incrementing it, causing both threads to + * execute the library initialization code. That would lead to a + * memory leak. To handle this, your application could invoke this + * function after aquiring a thread mutex. To ignore the potential + * memory leak is also an option. + * + **/ +int +MHD__gnutls_global_init () +{ + int result = 0; + int res; + + if (MHD__gnutls_init_level++) + return 0; + +#if HAVE_WINSOCK + { + WORD requested; + WSADATA data; + int err; + + requested = MAKEWORD (1, 1); + err = WSAStartup (requested, &data); + if (err != 0) + { + MHD__gnutls_debug_log ("WSAStartup failed: %d.\n", err); + return GNUTLS_E_LIBRARY_VERSION_MISMATCH; + } + + if (data.wVersion < requested) + { + MHD__gnutls_debug_log ("WSAStartup version check failed (%d < %d).\n", + data.wVersion, requested); + WSACleanup (); + return GNUTLS_E_LIBRARY_VERSION_MISMATCH; + } + } +#endif + + /* bindtextdomain("mhd", "./"); */ + + if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0) + { + const char *p; + + /* to enable multi-threading this call must precede any other call made to libgcrypt */ + gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + + /* set p to point at the required version of gcrypt */ + p = strchr (MHD_GCRYPT_VERSION, ':'); + if (p == NULL) + p = MHD_GCRYPT_VERSION; + else + p++; + + /* this call initializes libgcrypt */ + if (gcry_check_version (p) == NULL) + { + MHD_gnutls_assert (); + MHD__gnutls_debug_log ("Checking for libgcrypt failed '%s'\n", p); + return GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY; + } + + /* for gcrypt in order to be able to allocate memory */ + gcry_set_allocation_handler (MHD_gnutls_malloc, + MHD_gnutls_secure_malloc, + MHD__gnutls_is_secure_memory, + MHD_gnutls_realloc, MHD_gnutls_free); + + /* gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING, NULL, 0); */ + + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0); + + } + + if (MHD_gc_init () != GC_OK) + { + MHD_gnutls_assert (); + MHD__gnutls_debug_log ("Initializing crypto backend failed\n"); + return GNUTLS_E_INCOMPATIBLE_CRYPTO_LIBRARY; + } + + /* initialize parser + * This should not deal with files in the final + * version. + */ + res = + MHD__asn1_array2tree (MHD_pkix_asn1_tab, &MHD__gnutls_pkix1_asn, NULL); + if (res != ASN1_SUCCESS) + { + result = MHD_gtls_asn2err (res); + return result; + } + + res = + MHD__asn1_array2tree (MHD_gnutlsMHD__asn1_tab, + &MHD__gnutlsMHD__gnutls_asn, NULL); + if (res != ASN1_SUCCESS) + { + MHD__asn1_delete_structure (&MHD__gnutls_pkix1_asn); + result = MHD_gtls_asn2err (res); + return result; + } + + return result; +} + +/** + * MHD__gnutls_global_deinit - This function deinitializes the global data + * + * This function deinitializes the global data, that were initialized + * using MHD__gnutls_global_init(). + * + * Note! This function is not thread safe. See the discussion for + * MHD__gnutls_global_init() for more information. + * + **/ +void +MHD__gnutls_global_deinit () +{ + if (MHD__gnutls_init_level == 1) + { +#if HAVE_WINSOCK + WSACleanup (); +#endif + MHD__asn1_delete_structure (&MHD__gnutlsMHD__gnutls_asn); + MHD__asn1_delete_structure (&MHD__gnutls_pkix1_asn); + MHD_gc_done (); + } + MHD__gnutls_init_level--; +} + +/* These functions should be elsewere. Kept here for + * historical reasons. + */ + +/** + * MHD__gnutls_transport_set_pull_function - This function sets a read like function + * @pull_func: a callback function similar to read() + * @session: gnutls session + * + * This is the function where you set a function for gnutls + * to receive data. Normally, if you use berkeley style sockets, + * do not need to use this function since the default (recv(2)) will + * probably be ok. + * + * PULL_FUNC is of the form, + * ssize_t (*MHD_gtls_pull_func)(MHD_gnutls_transport_ptr_t, void*, size_t); + **/ +void +MHD__gnutls_transport_set_pull_function (MHD_gtls_session_t session, + MHD_gtls_pull_func pull_func) +{ + session->internals.MHD__gnutls_pull_func = pull_func; +} + +/** + * MHD__gnutls_transport_set_push_function - This function sets the function to send data + * @push_func: a callback function similar to write() + * @session: gnutls session + * + * This is the function where you set a push function for gnutls + * to use in order to send data. If you are going to use berkeley style + * sockets, you do not need to use this function since + * the default (send(2)) will probably be ok. Otherwise you should + * specify this function for gnutls to be able to send data. + * + * PUSH_FUNC is of the form, + * ssize_t (*MHD_gtls_push_func)(MHD_gnutls_transport_ptr_t, const void*, size_t); + **/ +void +MHD__gnutls_transport_set_push_function (MHD_gtls_session_t session, + MHD_gtls_push_func push_func) +{ + session->internals.MHD__gnutls_push_func = push_func; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_global.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_global.h new file mode 100644 index 0000000000..50d6131c3d --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_global.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_GLOBAL_H +#define GNUTLS_GLOBAL_H + +#include "MHD_config.h" +#include <libtasn1.h> +#undef HAVE_CONFIG_H +#include <pthread.h> +#define HAVE_CONFIG_H 1 + +/* this mutex is used to synchronize threads attempting to call MHD__gnutls_global_init / MHD__gnutls_global_deinit */ +extern pthread_mutex_t MHD_gnutls_init_mutex; + +int MHD_gnutls_is_secure_memory (const void *mem); + +extern ASN1_TYPE MHD__gnutls_pkix1_asn; +extern ASN1_TYPE MHD__gnutlsMHD__gnutls_asn; + +#if !HAVE_MEMMEM +extern void *memmem (void const *__haystack, size_t __haystack_len, + void const *__needle, size_t __needle_len); +#endif + +/* removed const from node_asn* to + * prevent warnings, since libtasn1 doesn't + * use the const keywork in its functions. + */ +#define MHD__gnutls_getMHD__gnutls_asn() ((node_asn*) MHD__gnutlsMHD__gnutls_asn) +#define MHD__gnutls_get_pkix() ((node_asn*) MHD__gnutls_pkix1_asn) + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_handshake.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_handshake.c new file mode 100644 index 0000000000..f12f4015c0 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_handshake.c @@ -0,0 +1,2804 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions that relate to the TLS handshake procedure. + */ + +#include "MHD_config.h" +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "gnutls_dh.h" +#include "debug.h" +#include "gnutls_algorithms.h" +#include "gnutls_cipher.h" +#include "gnutls_buffers.h" +#include "gnutls_kx.h" +#include "gnutls_handshake.h" +#include "gnutls_num.h" +#include "gnutls_hash_int.h" +#include "gnutls_extensions.h" +#include "gnutls_supplemental.h" +#include "gnutls_auth_int.h" +#include "auth_cert.h" +#include "gnutls_cert.h" +#include "gnutls_constate.h" +#include "gnutls_record.h" +#include "gnutls_state.h" +#include "gnutls_rsa_export.h" /* for MHD_gnutls_get_rsa_params() */ +#include "gc.h" + +#ifdef HANDSHAKE_DEBUG +#define ERR(x, y) MHD__gnutls_handshake_log( "HSK[%x]: %s (%d)\n", session, x,y) +#else +#define ERR(x, y) +#endif + +#define TRUE 1 +#define FALSE 0 + + +/* This should be sufficient by now. It should hold all the extensions + * plus the headers in a hello message. + */ +#define MAX_EXT_DATA_LENGTH 1024 + + +static int MHD_gtls_remove_unwanted_ciphersuites (MHD_gtls_session_t session, + cipher_suite_st ** + cipherSuites, + int numCipherSuites, + enum + MHD_GNUTLS_PublicKeyAlgorithm); +static int MHD_gtls_server_select_suite (MHD_gtls_session_t session, + opaque * data, int datalen); + +static int MHD_gtls_generate_session_id (opaque * session_id, uint8_t * len); + +static int MHD_gtls_handshake_common (MHD_gtls_session_t session); + +static int MHD_gtls_handshake_server (MHD_gtls_session_t session); + +#if MHD_DEBUG_TLS +static int MHD_gtls_handshake_client (MHD_gtls_session_t session); +#endif + + +static int MHD__gnutls_server_select_comp_method (MHD_gtls_session_t session, + opaque * data, int datalen); + + +/* Clears the handshake hash buffers and handles. + */ +static void +MHD__gnutls_handshake_hash_buffers_clear (MHD_gtls_session_t session) +{ + MHD_gnutls_hash_deinit (session->internals.handshake_mac_handle_md5, NULL); + MHD_gnutls_hash_deinit (session->internals.handshake_mac_handle_sha, NULL); + session->internals.handshake_mac_handle_md5 = NULL; + session->internals.handshake_mac_handle_sha = NULL; + MHD_gtls_handshake_buffer_clear (session); +} + +/** + * gnutls_handshake_set_max_packet_length - This function will set the maximum length of a handshake message + * @session: is a #gnutls_session_t structure. + * @max: is the maximum number. + * + * This function will set the maximum size of a handshake message. + * Handshake messages over this size are rejected. + * The default value is 16kb which is large enough. Set this to 0 if you do not want + * to set an upper limit. + * + **/ +void +MHD__gnutls_handshake_set_max_packet_length (MHD_gtls_session_t session, + size_t max) +{ + session->internals.max_handshake_data_buffer_size = max; +} + + +static void +MHD_gtls_set_server_random (MHD_gtls_session_t session, uint8_t * rnd) +{ + memcpy (session->security_parameters.server_random, rnd, TLS_RANDOM_SIZE); +} + +static void +MHD_gtls_set_client_random (MHD_gtls_session_t session, uint8_t * rnd) +{ + memcpy (session->security_parameters.client_random, rnd, TLS_RANDOM_SIZE); +} + +/* Calculate The SSL3 Finished message */ +#define SSL3_CLIENT_MSG "CLNT" +#define SSL3_SERVER_MSG "SRVR" +#define SSL_MSG_LEN 4 +static int +MHD__gnutls_ssl3_finished (MHD_gtls_session_t session, int type, opaque * ret) +{ + const int siz = SSL_MSG_LEN; + mac_hd_t td_md5; + mac_hd_t td_sha; + const char *mesg; + + td_md5 = MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_md5); + if (td_md5 == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + td_sha = MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_sha); + if (td_sha == NULL) + { + MHD_gnutls_assert (); + MHD_gnutls_hash_deinit (td_md5, NULL); + return GNUTLS_E_HASH_FAILED; + } + + if (type == GNUTLS_SERVER) + { + mesg = SSL3_SERVER_MSG; + } + else + { + mesg = SSL3_CLIENT_MSG; + } + + MHD_gnutls_hash (td_md5, mesg, siz); + MHD_gnutls_hash (td_sha, mesg, siz); + + MHD_gnutls_mac_deinit_ssl3_handshake (td_md5, ret, + session->security_parameters. + master_secret, TLS_MASTER_SIZE); + MHD_gnutls_mac_deinit_ssl3_handshake (td_sha, &ret[16], + session->security_parameters. + master_secret, TLS_MASTER_SIZE); + + return 0; +} + +/* Hash the handshake messages as required by TLS 1.0 */ +#define SERVER_MSG "server finished" +#define CLIENT_MSG "client finished" +#define TLS_MSG_LEN 15 +static int +MHD__gnutls_finished (MHD_gtls_session_t session, int type, void *ret) +{ + const int siz = TLS_MSG_LEN; + opaque concat[36]; + size_t len; + const char *mesg; + mac_hd_t td_md5 = NULL; + mac_hd_t td_sha; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + if (ver < MHD_GNUTLS_PROTOCOL_TLS1_2) + { + td_md5 = + MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_md5); + if (td_md5 == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + } + + td_sha = MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_sha); + if (td_sha == NULL) + { + MHD_gnutls_assert (); + if (td_md5 != NULL) + MHD_gnutls_hash_deinit (td_md5, NULL); + return GNUTLS_E_HASH_FAILED; + } + + if (ver < MHD_GNUTLS_PROTOCOL_TLS1_2) + { + MHD_gnutls_hash_deinit (td_md5, concat); + MHD_gnutls_hash_deinit (td_sha, &concat[16]); + len = 20 + 16; + } + else + { + MHD_gnutls_hash_deinit (td_sha, concat); + len = 20; + } + + if (type == GNUTLS_SERVER) + { + mesg = SERVER_MSG; + } + else + { + mesg = CLIENT_MSG; + } + + return MHD_gtls_PRF (session, session->security_parameters.master_secret, + TLS_MASTER_SIZE, mesg, siz, concat, len, 12, ret); +} + +/* this function will produce TLS_RANDOM_SIZE==32 bytes of random data + * and put it to dst. + */ +static int +MHD_gtls_tls_create_random (opaque * dst) +{ + uint32_t tim; + + /* Use weak random numbers for the most of the + * buffer except for the first 4 that are the + * system's time. + */ + + tim = time (NULL); + /* generate server random value */ + MHD_gtls_write_uint32 (tim, dst); + + if (MHD_gc_nonce ((char *) &dst[4], TLS_RANDOM_SIZE - 4) != GC_OK) + { + MHD_gnutls_assert (); + return GNUTLS_E_RANDOM_FAILED; + } + + return 0; +} + +/* returns the 0 on success or a negative value. + */ +static int +MHD_gtls_negotiate_version (MHD_gtls_session_t session, + enum MHD_GNUTLS_Protocol adv_version) +{ + int ret; + + /* if we do not support that version */ + if (MHD_gtls_version_is_supported (session, adv_version) == 0) + { + /* If he requested something we do not support + * then we send him the highest we support. + */ + ret = MHD_gtls_version_max (session); + } + else + { + ret = adv_version; + } + MHD_gtls_set_current_version (session, ret); + + return ret; +} + +/* Read a client hello packet. + * A client hello must be a known version client hello + * or version 2.0 client hello (only for compatibility + * since SSL version 2.0 is not supported). + */ +static int +MHD__gnutls_read_client_hello (MHD_gtls_session_t session, opaque * data, + int datalen) +{ + uint8_t session_id_len; + int pos = 0, ret = 0; + uint16_t suite_size, comp_size; + enum MHD_GNUTLS_Protocol adv_version; + int neg_version; + int len = datalen; + opaque rnd[TLS_RANDOM_SIZE], *suite_ptr, *comp_ptr; + + DECR_LEN (len, 2); + + MHD__gnutls_handshake_log ("HSK[%x]: Client's version: %d.%d\n", session, + data[pos], data[pos + 1]); + + adv_version = MHD_gtls_version_get (data[pos], data[pos + 1]); + set_adv_version (session, data[pos], data[pos + 1]); + pos += 2; + + neg_version = MHD_gtls_negotiate_version (session, adv_version); + if (neg_version < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* Read client random value. + */ + DECR_LEN (len, TLS_RANDOM_SIZE); + MHD_gtls_set_client_random (session, &data[pos]); + pos += TLS_RANDOM_SIZE; + + MHD_gtls_tls_create_random (rnd); + MHD_gtls_set_server_random (session, rnd); + + session->security_parameters.timestamp = time (NULL); + + DECR_LEN (len, 1); + session_id_len = data[pos++]; + + /* RESUME SESSION */ + if (session_id_len > TLS_MAX_SESSION_ID_SIZE) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + DECR_LEN (len, session_id_len); + + pos += session_id_len; + + MHD_gtls_generate_session_id (session->security_parameters.session_id, + &session->security_parameters. + session_id_size); + + session->internals.resumed = RESUME_FALSE; + /* Remember ciphersuites for later + */ + DECR_LEN (len, 2); + suite_size = MHD_gtls_read_uint16 (&data[pos]); + pos += 2; + + DECR_LEN (len, suite_size); + suite_ptr = &data[pos]; + pos += suite_size; + + /* Point to the compression methods + */ + DECR_LEN (len, 1); + comp_size = data[pos++]; /* z is the number of compression methods */ + + DECR_LEN (len, comp_size); + comp_ptr = &data[pos]; + pos += comp_size; + + /* Parse the extensions (if any) + */ + if (neg_version >= MHD_GNUTLS_PROTOCOL_TLS1_0) + { + ret = MHD_gtls_parse_extensions (session, EXTENSION_APPLICATION, &data[pos], len); /* len is the rest of the parsed length */ + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + + if (neg_version >= MHD_GNUTLS_PROTOCOL_TLS1_0) + { + ret = MHD_gtls_parse_extensions (session, EXTENSION_TLS, &data[pos], len); /* len is the rest of the parsed length */ + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + + /* select an appropriate cipher suite + */ + ret = MHD_gtls_server_select_suite (session, suite_ptr, suite_size); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* select appropriate compression method */ + ret = MHD__gnutls_server_select_comp_method (session, comp_ptr, comp_size); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return 0; +} + +/* here we hash all pending data. + */ +static int +MHD__gnutls_handshake_hash_pending (MHD_gtls_session_t session) +{ + size_t siz; + int ret; + opaque *data; + + if (session->internals.handshake_mac_handle_sha == NULL || + session->internals.handshake_mac_handle_md5 == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* We check if there are pending data to hash. + */ + if ((ret = MHD_gtls_handshake_buffer_get_ptr (session, &data, &siz)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if (siz > 0) + { + MHD_gnutls_hash (session->internals.handshake_mac_handle_sha, data, + siz); + MHD_gnutls_hash (session->internals.handshake_mac_handle_md5, data, + siz); + } + + MHD_gtls_handshake_buffer_empty (session); + + return 0; +} + + +/* This is to be called after sending CHANGE CIPHER SPEC packet + * and initializing encryption. This is the first encrypted message + * we send. + */ +static int +MHD__gnutls_send_finished (MHD_gtls_session_t session, int again) +{ + uint8_t data[36]; + int ret; + int data_size = 0; + + + if (again == 0) + { + + /* This is needed in order to hash all the required + * messages. + */ + if ((ret = MHD__gnutls_handshake_hash_pending (session)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if (MHD__gnutls_protocol_get_version (session) == + MHD_GNUTLS_PROTOCOL_SSL3) + { + ret = + MHD__gnutls_ssl3_finished (session, + session->security_parameters.entity, + data); + data_size = 36; + } + else + { /* TLS 1.0 */ + ret = + MHD__gnutls_finished (session, + session->security_parameters.entity, data); + data_size = 12; + } + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + } + + ret = + MHD_gtls_send_handshake (session, data, data_size, + GNUTLS_HANDSHAKE_FINISHED); + + return ret; +} + +/* This is to be called after sending our finished message. If everything + * went fine we have negotiated a secure connection + */ +static int +MHD__gnutls_recv_finished (MHD_gtls_session_t session) +{ + uint8_t data[36], *vrfy; + int data_size; + int ret; + int vrfysize; + + ret = + MHD_gtls_recv_handshake (session, &vrfy, &vrfysize, + GNUTLS_HANDSHAKE_FINISHED, MANDATORY_PACKET); + if (ret < 0) + { + ERR ("recv finished int", ret); + MHD_gnutls_assert (); + return ret; + } + + + if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3) + { + data_size = 36; + } + else + { + data_size = 12; + } + + if (vrfysize != data_size) + { + MHD_gnutls_assert (); + MHD_gnutls_free (vrfy); + return GNUTLS_E_ERROR_IN_FINISHED_PACKET; + } + + if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3) + { + ret = + MHD__gnutls_ssl3_finished (session, + (session->security_parameters.entity + + 1) % 2, data); + } + else + { /* TLS 1.0 */ + ret = + MHD__gnutls_finished (session, + (session->security_parameters.entity + + 1) % 2, data); + } + + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (vrfy); + return ret; + } + + if (memcmp (vrfy, data, data_size) != 0) + { + MHD_gnutls_assert (); + ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET; + } + MHD_gnutls_free (vrfy); + + return ret; +} + +/* returns PK_RSA if the given cipher suite list only supports, + * RSA algorithms, PK_DSA if DSS, and PK_ANY for both or PK_NONE for none. + */ +static int +MHD__gnutls_server_find_pk_algos_in_ciphersuites (const opaque * + data, int datalen) +{ + int j; + enum MHD_GNUTLS_PublicKeyAlgorithm algo = GNUTLS_PK_NONE, prev_algo = 0; + enum MHD_GNUTLS_KeyExchangeAlgorithm kx; + cipher_suite_st cs; + + if (datalen % 2 != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + for (j = 0; j < datalen; j += 2) + { + memcpy (&cs.suite, &data[j], 2); + kx = MHD_gtls_cipher_suite_get_kx_algo (&cs); + + if (MHD_gtls_map_kx_get_cred (kx, 1) == MHD_GNUTLS_CRD_CERTIFICATE) + { + algo = MHD_gtls_map_pk_get_pk (kx); + + if (algo != prev_algo && prev_algo != 0) + return GNUTLS_PK_ANY; + prev_algo = algo; + } + } + + return algo; +} + + +/* This selects the best supported ciphersuite from the given ones. Then + * it adds the suite to the session and performs some checks. + */ +static int +MHD_gtls_server_select_suite (MHD_gtls_session_t session, opaque * data, + int datalen) +{ + int x, i, j; + cipher_suite_st *ciphers, cs; + int retval, err; + enum MHD_GNUTLS_PublicKeyAlgorithm pk_algo; /* will hold the pk algorithms + * supported by the peer. + */ + + pk_algo = MHD__gnutls_server_find_pk_algos_in_ciphersuites (data, datalen); + + x = MHD_gtls_supported_ciphersuites (session, &ciphers); + if (x < 0) + { /* the case x==0 is handled within the function. */ + MHD_gnutls_assert (); + return x; + } + + /* Here we remove any ciphersuite that does not conform + * the certificate requested, or to the + * authentication requested (e.g. SRP). + */ + x = MHD_gtls_remove_unwanted_ciphersuites (session, &ciphers, x, pk_algo); + if (x <= 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (ciphers); + if (x < 0) + return x; + else + return GNUTLS_E_UNKNOWN_CIPHER_SUITE; + } + + /* Data length should be zero mod 2 since + * every ciphersuite is 2 bytes. (this check is needed + * see below). + */ + if (datalen % 2 != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + memset (session->security_parameters.current_cipher_suite.suite, '\0', 2); + + retval = GNUTLS_E_UNKNOWN_CIPHER_SUITE; + + for (j = 0; j < datalen; j += 2) + { + for (i = 0; i < x; i++) + { + if (memcmp (ciphers[i].suite, &data[j], 2) == 0) + { + memcpy (&cs.suite, &data[j], 2); + + MHD__gnutls_handshake_log + ("HSK[%x]: Selected cipher suite: %s\n", session, + MHD_gtls_cipher_suite_get_name (&cs)); + memcpy (session->security_parameters.current_cipher_suite.suite, + ciphers[i].suite, 2); + retval = 0; + goto finish; + } + } + } + +finish: + MHD_gnutls_free (ciphers); + + if (retval != 0) + { + MHD_gnutls_assert (); + return retval; + } + + /* check if the credentials (username, public key etc.) are ok + */ + if (MHD_gtls_get_kx_cred + (session, + MHD_gtls_cipher_suite_get_kx_algo (&session->security_parameters. + current_cipher_suite), &err) == NULL + && err != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + + /* set the MHD_gtls_mod_auth_st to the appropriate struct + * according to the KX algorithm. This is needed since all the + * handshake functions are read from there; + */ + session->internals.auth_struct = + MHD_gtls_kx_auth_struct (MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters. + current_cipher_suite)); + if (session->internals.auth_struct == NULL) + { + + MHD__gnutls_handshake_log + ("HSK[%x]: Cannot find the appropriate handler for the KX algorithm\n", + session); + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + return 0; + +} + + +/* This selects the best supported compression method from the ones provided + */ +static int +MHD__gnutls_server_select_comp_method (MHD_gtls_session_t session, + opaque * data, int datalen) +{ + int x, i, j; + uint8_t *comps; + + x = MHD_gtls_supported_compression_methods (session, &comps); + if (x < 0) + { + MHD_gnutls_assert (); + return x; + } + + memset (&session->internals.compression_method, 0, + sizeof (enum MHD_GNUTLS_CompressionMethod)); + + for (j = 0; j < datalen; j++) + { + for (i = 0; i < x; i++) + { + if (comps[i] == data[j]) + { + enum MHD_GNUTLS_CompressionMethod method = + MHD_gtls_compression_get_id_from_int (comps[i]); + + session->internals.compression_method = method; + MHD_gnutls_free (comps); + return 0; + } + } + } + + /* we were not able to find a compatible compression + * algorithm + */ + MHD_gnutls_free (comps); + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; + +} + +/* This function sends an empty handshake packet. (like hello request). + * If the previous MHD__gnutls_send_empty_handshake() returned + * GNUTLS_E_AGAIN or GNUTLS_E_INTERRUPTED, then it must be called again + * (until it returns ok), with NULL parameters. + */ +static int +MHD__gnutls_send_empty_handshake (MHD_gtls_session_t session, + MHD_gnutls_handshake_description_t type, + int again) +{ + opaque data = 0; + opaque *ptr; + + if (again == 0) + ptr = &data; + else + ptr = NULL; + + return MHD_gtls_send_handshake (session, ptr, 0, type); +} + + +/* This function will hash the handshake message we sent. */ +static int +MHD__gnutls_handshake_hash_add_sent (MHD_gtls_session_t session, + MHD_gnutls_handshake_description_t type, + opaque * dataptr, uint32_t datalen) +{ + int ret; + + if ((ret = MHD__gnutls_handshake_hash_pending (session)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if (type != GNUTLS_HANDSHAKE_HELLO_REQUEST) + { + MHD_gnutls_hash (session->internals.handshake_mac_handle_sha, dataptr, + datalen); + MHD_gnutls_hash (session->internals.handshake_mac_handle_md5, dataptr, + datalen); + } + + return 0; +} + + +/* This function sends a handshake message of type 'type' containing the + * data specified here. If the previous MHD_gtls_send_handshake() returned + * GNUTLS_E_AGAIN or GNUTLS_E_INTERRUPTED, then it must be called again + * (until it returns ok), with NULL parameters. + */ +int +MHD_gtls_send_handshake (MHD_gtls_session_t session, void *i_data, + uint32_t i_datasize, + MHD_gnutls_handshake_description_t type) +{ + int ret; + uint8_t *data; + uint32_t datasize; + int pos = 0; + + if (i_data == NULL && i_datasize == 0) + { + /* we are resuming a previously interrupted + * send. + */ + ret = MHD_gtls_handshake_io_write_flush (session); + return ret; + + } + + if (i_data == NULL && i_datasize > 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + /* first run */ + datasize = i_datasize + HANDSHAKE_HEADER_SIZE; + data = MHD_gnutls_alloca (datasize); + if (data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + data[pos++] = (uint8_t) type; + MHD_gtls_write_uint24 (i_datasize, &data[pos]); + pos += 3; + + if (i_datasize > 0) + memcpy (&data[pos], i_data, i_datasize); + + /* Here we keep the handshake messages in order to hash them... + */ + if (type != GNUTLS_HANDSHAKE_HELLO_REQUEST) + if ((ret = + MHD__gnutls_handshake_hash_add_sent (session, type, data, + datasize)) < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (data); + return ret; + } + + session->internals.last_handshake_out = type; + + ret = + MHD_gtls_handshake_io_send_int (session, GNUTLS_HANDSHAKE, type, + data, datasize); + + MHD__gnutls_handshake_log ("HSK[%x]: %s was sent [%ld bytes]\n", + session, MHD__gnutls_handshake2str (type), + (long) datasize); + + MHD_gnutls_afree (data); + + return ret; +} + +/* This function will read the handshake header and return it to the caller. If the + * received handshake packet is not the one expected then it buffers the header, and + * returns UNEXPECTED_HANDSHAKE_PACKET. + * + * FIXME: This function is complex. + */ +#define SSL2_HEADERS 1 +static int +MHD__gnutls_recv_handshake_header (MHD_gtls_session_t session, + MHD_gnutls_handshake_description_t type, + MHD_gnutls_handshake_description_t * + recv_type) +{ + int ret; + uint32_t length32 = 0; + uint8_t *dataptr = NULL; /* for realloc */ + size_t handshake_header_size = HANDSHAKE_HEADER_SIZE; + + /* if we have data into the buffer then return them, do not read the next packet. + * In order to return we need a full TLS handshake header, or in case of a version 2 + * packet, then we return the first byte. + */ + if (session->internals.handshake_header_buffer.header_size == + handshake_header_size || (session->internals.v2_hello != 0 + && type == GNUTLS_HANDSHAKE_CLIENT_HELLO + && session->internals. + handshake_header_buffer.packet_length > 0)) + { + + *recv_type = session->internals.handshake_header_buffer.recv_type; + + return session->internals.handshake_header_buffer.packet_length; + } + + /* Note: SSL2_HEADERS == 1 */ + + dataptr = session->internals.handshake_header_buffer.header; + + /* If we haven't already read the handshake headers. + */ + if (session->internals.handshake_header_buffer.header_size < SSL2_HEADERS) + { + ret = + MHD_gtls_handshake_io_recv_int (session, GNUTLS_HANDSHAKE, + type, dataptr, SSL2_HEADERS); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* The case ret==0 is caught here. + */ + if (ret != SSL2_HEADERS) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + session->internals.handshake_header_buffer.header_size = SSL2_HEADERS; + } + + if (session->internals.v2_hello == 0 + || type != GNUTLS_HANDSHAKE_CLIENT_HELLO) + { + ret = + MHD_gtls_handshake_io_recv_int (session, GNUTLS_HANDSHAKE, + type, + &dataptr + [session->internals. + handshake_header_buffer.header_size], + HANDSHAKE_HEADER_SIZE - + session->internals. + handshake_header_buffer.header_size); + if (ret <= 0) + { + MHD_gnutls_assert (); + return (ret < 0) ? ret : GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + if ((size_t) ret != + HANDSHAKE_HEADER_SIZE - + session->internals.handshake_header_buffer.header_size) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + *recv_type = dataptr[0]; + + /* we do not use DECR_LEN because we know + * that the packet has enough data. + */ + length32 = MHD_gtls_read_uint24 (&dataptr[1]); + handshake_header_size = HANDSHAKE_HEADER_SIZE; + + MHD__gnutls_handshake_log ("HSK[%x]: %s was received [%ld bytes]\n", + session, + MHD__gnutls_handshake2str (dataptr[0]), + length32 + HANDSHAKE_HEADER_SIZE); + + } + else + { /* v2 hello */ + length32 = session->internals.v2_hello - SSL2_HEADERS; /* we've read the first byte */ + + handshake_header_size = SSL2_HEADERS; /* we've already read one byte */ + + *recv_type = dataptr[0]; + + MHD__gnutls_handshake_log ("HSK[%x]: %s(v2) was received [%ld bytes]\n", + session, + MHD__gnutls_handshake2str (*recv_type), + length32 + handshake_header_size); + + if (*recv_type != GNUTLS_HANDSHAKE_CLIENT_HELLO) + { /* it should be one or nothing */ + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET; + } + } + + /* put the packet into the buffer */ + session->internals.handshake_header_buffer.header_size = + handshake_header_size; + session->internals.handshake_header_buffer.packet_length = length32; + session->internals.handshake_header_buffer.recv_type = *recv_type; + + if (*recv_type != type) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET; + } + + return length32; +} + +#define MHD__gnutls_handshake_header_buffer_clear( session) session->internals.handshake_header_buffer.header_size = 0 + +/* This function will hash the handshake headers and the + * handshake data. + */ +static int +MHD__gnutls_handshake_hash_add_recvd (MHD_gtls_session_t session, + MHD_gnutls_handshake_description_t + recv_type, opaque * header, + uint16_t header_size, opaque * dataptr, + uint32_t datalen) +{ + int ret; + + /* The idea here is to hash the previous message we received, + * and add the one we just received into the handshake_hash_buffer. + */ + + if ((ret = MHD__gnutls_handshake_hash_pending (session)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* here we buffer the handshake messages - needed at Finished message */ + if (recv_type != GNUTLS_HANDSHAKE_HELLO_REQUEST) + { + + if ((ret = + MHD_gtls_handshake_buffer_put (session, header, header_size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if (datalen > 0) + { + if ((ret = + MHD_gtls_handshake_buffer_put (session, dataptr, datalen)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + } + + return 0; +} + +/* This function will receive handshake messages of the given types, + * and will pass the message to the right place in order to be processed. + * E.g. for the SERVER_HELLO message (if it is expected), it will be + * passed to MHD_gtls_recv_hello(). + */ +int +MHD_gtls_recv_handshake (MHD_gtls_session_t session, uint8_t ** data, + int *datalen, + MHD_gnutls_handshake_description_t type, + Optional optional) +{ + int ret; + uint32_t length32 = 0; + opaque *dataptr = NULL; + MHD_gnutls_handshake_description_t recv_type; + + ret = MHD__gnutls_recv_handshake_header (session, type, &recv_type); + if (ret < 0) + { + + if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET + && optional == OPTIONAL_PACKET) + { + if (datalen != NULL) + *datalen = 0; + if (data != NULL) + *data = NULL; + return 0; /* ok just ignore the packet */ + } + + return ret; + } + + session->internals.last_handshake_in = recv_type; + + length32 = ret; + + if (length32 > 0) + dataptr = MHD_gnutls_malloc (length32); + else if (recv_type != GNUTLS_HANDSHAKE_SERVER_HELLO_DONE) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + if (dataptr == NULL && length32 > 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + if (datalen != NULL) + *datalen = length32; + + if (length32 > 0) + { + ret = + MHD_gtls_handshake_io_recv_int (session, GNUTLS_HANDSHAKE, + type, dataptr, length32); + if (ret <= 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (dataptr); + return (ret == 0) ? GNUTLS_E_UNEXPECTED_PACKET_LENGTH : ret; + } + } + + if (data != NULL && length32 > 0) + *data = dataptr; + + + ret = MHD__gnutls_handshake_hash_add_recvd (session, recv_type, + session->internals. + handshake_header_buffer.header, + session->internals. + handshake_header_buffer.header_size, + dataptr, length32); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD__gnutls_handshake_header_buffer_clear (session); + return ret; + } + + /* If we fail before this then we will reuse the handshake header + * have have received above. if we get here the we clear the handshake + * header we received. + */ + MHD__gnutls_handshake_header_buffer_clear (session); + + switch (recv_type) + { + case GNUTLS_HANDSHAKE_CLIENT_HELLO: + case GNUTLS_HANDSHAKE_SERVER_HELLO: + ret = MHD_gtls_recv_hello (session, dataptr, length32); + /* dataptr is freed because the caller does not + * need it */ + MHD_gnutls_free (dataptr); + if (data != NULL) + *data = NULL; + break; + case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE: + if (length32 == 0) + ret = 0; + else + ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + break; + case GNUTLS_HANDSHAKE_CERTIFICATE_PKT: + case GNUTLS_HANDSHAKE_FINISHED: + case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE: + case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE: + case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST: + case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY: + case GNUTLS_HANDSHAKE_SUPPLEMENTAL: + ret = length32; + break; + default: + MHD_gnutls_assert (); + MHD_gnutls_free (dataptr); + if (data != NULL) + *data = NULL; + ret = GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET; + } + + return ret; +} + +#if MHD_DEBUG_TLS +/* This function checks if the given cipher suite is supported, and sets it + * to the session; + */ +static int +MHD__gnutls_client_set_ciphersuite (MHD_gtls_session_t session, + opaque suite[2]) +{ + uint8_t z; + cipher_suite_st *cipher_suites; + int cipher_suite_num; + int i, err; + + z = 1; + cipher_suite_num = + MHD_gtls_supported_ciphersuites (session, &cipher_suites); + if (cipher_suite_num < 0) + { + MHD_gnutls_assert (); + return cipher_suite_num; + } + + for (i = 0; i < cipher_suite_num; i++) + { + if (memcmp (&cipher_suites[i], suite, 2) == 0) + { + z = 0; + break; + } + } + + MHD_gnutls_free (cipher_suites); + + if (z != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_CIPHER_SUITE; + } + + memcpy (session->security_parameters.current_cipher_suite.suite, suite, 2); + + MHD__gnutls_handshake_log ("HSK[%x]: Selected cipher suite: %s\n", session, + MHD_gtls_cipher_suite_get_name + (&session->security_parameters. + current_cipher_suite)); + + + /* check if the credentials (username, public key etc.) are ok. + * Actually checks if they exist. + */ + if (MHD_gtls_get_kx_cred + (session, + MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters.current_cipher_suite), &err) == NULL + && err != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + + /* set the MHD_gtls_mod_auth_st to the appropriate struct + * according to the KX algorithm. This is needed since all the + * handshake functions are read from there; + */ + session->internals.auth_struct = + MHD_gtls_kx_auth_struct (MHD_gtls_cipher_suite_get_kx_algo + (&session->security_parameters. + current_cipher_suite)); + + if (session->internals.auth_struct == NULL) + { + + MHD__gnutls_handshake_log + ("HSK[%x]: Cannot find the appropriate handler for the KX algorithm\n", + session); + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + + return 0; +} + + +/* This function sets the given comp method to the session. + */ +static int +MHD__gnutls_client_set_comp_method (MHD_gtls_session_t session, + opaque comp_method) +{ + int comp_methods_num; + uint8_t *compression_methods; + int i; + + comp_methods_num = MHD_gtls_supported_compression_methods (session, + &compression_methods); + if (comp_methods_num < 0) + { + MHD_gnutls_assert (); + return comp_methods_num; + } + + for (i = 0; i < comp_methods_num; i++) + { + if (compression_methods[i] == comp_method) + { + comp_methods_num = 0; + break; + } + } + + MHD_gnutls_free (compression_methods); + + if (comp_methods_num != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; + } + + session->internals.compression_method = + MHD_gtls_compression_get_id_from_int (comp_method); + + + return 0; +} + +/* This function returns 0 if we are resuming a session or -1 otherwise. + * This also sets the variables in the session. Used only while reading a server + * hello. + */ +static int +MHD__gnutls_client_check_if_resuming (MHD_gtls_session_t session, + opaque * session_id, int session_id_len) +{ + opaque buf[2 * TLS_MAX_SESSION_ID_SIZE + 1]; + + MHD__gnutls_handshake_log ("HSK[%x]: SessionID length: %d\n", session, + session_id_len); + MHD__gnutls_handshake_log ("HSK[%x]: SessionID: %s\n", session, + MHD_gtls_bin2hex (session_id, session_id_len, + (char *) buf, sizeof (buf))); + + if (session_id_len > 0 && + session->internals.resumed_security_parameters.session_id_size == + session_id_len + && memcmp (session_id, + session->internals.resumed_security_parameters.session_id, + session_id_len) == 0) + { + /* resume session */ + memcpy (session->internals.resumed_security_parameters.server_random, + session->security_parameters.server_random, TLS_RANDOM_SIZE); + memcpy (session->internals.resumed_security_parameters.client_random, + session->security_parameters.client_random, TLS_RANDOM_SIZE); + session->internals.resumed = RESUME_TRUE; /* we are resuming */ + + return 0; + } + else + { + /* keep the new session id */ + session->internals.resumed = RESUME_FALSE; /* we are not resuming */ + session->security_parameters.session_id_size = session_id_len; + memcpy (session->security_parameters.session_id, + session_id, session_id_len); + + return -1; + } +} + +/* This function reads and parses the server hello handshake message. + * This function also restores resumed parameters if we are resuming a + * session. + */ +static int +MHD__gnutls_read_server_hello (MHD_gtls_session_t session, + opaque * data, int datalen) +{ + uint8_t session_id_len = 0; + int pos = 0; + int ret = 0; + enum MHD_GNUTLS_Protocol version; + int len = datalen; + + if (datalen < 38) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + MHD__gnutls_handshake_log ("HSK[%x]: Server's version: %d.%d\n", + session, data[pos], data[pos + 1]); + + DECR_LEN (len, 2); + version = MHD_gtls_version_get (data[pos], data[pos + 1]); + if (MHD_gtls_version_is_supported (session, version) == 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; + } + else + { + MHD_gtls_set_current_version (session, version); + } + + pos += 2; + + DECR_LEN (len, TLS_RANDOM_SIZE); + MHD_gtls_set_server_random (session, &data[pos]); + pos += TLS_RANDOM_SIZE; + + + /* Read session ID + */ + DECR_LEN (len, 1); + session_id_len = data[pos++]; + + if (len < session_id_len) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; + } + DECR_LEN (len, session_id_len); + + + /* check if we are resuming and set the appropriate + * values; + */ + if (MHD__gnutls_client_check_if_resuming + (session, &data[pos], session_id_len) == 0) + return 0; + pos += session_id_len; + + + /* Check if the given cipher suite is supported and copy + * it to the session. + */ + + DECR_LEN (len, 2); + ret = MHD__gnutls_client_set_ciphersuite (session, &data[pos]); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + pos += 2; + + + + /* move to compression */ + DECR_LEN (len, 1); + + ret = MHD__gnutls_client_set_comp_method (session, data[pos++]); + if (ret < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM; + } + + /* Parse extensions. + */ + if (version >= MHD_GNUTLS_PROTOCOL_TLS1_0) + { + ret = MHD_gtls_parse_extensions (session, EXTENSION_ANY, &data[pos], len); /* len is the rest of the parsed length */ + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + return ret; +} + + +/* This function copies the appropriate ciphersuites to a locally allocated buffer + * Needed in client hello messages. Returns the new data length. + */ +int +MHD__gnutls_copy_ciphersuites (MHD_gtls_session_t session, + opaque * ret_data, size_t ret_data_size) +{ + int ret, i; + cipher_suite_st *cipher_suites; + uint16_t cipher_num; + int datalen, pos; + + ret = MHD_gtls_supported_ciphersuites_sorted (session, &cipher_suites); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* Here we remove any ciphersuite that does not conform + * the certificate requested, or to the + * authentication requested (eg SRP). + */ + ret = + MHD_gtls_remove_unwanted_ciphersuites (session, &cipher_suites, ret, -1); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (cipher_suites); + return ret; + } + + /* If no cipher suites were enabled. + */ + if (ret == 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (cipher_suites); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + cipher_num = ret; + + cipher_num *= sizeof (uint16_t); /* in order to get bytes */ + + datalen = pos = 0; + + datalen += sizeof (uint16_t) + cipher_num; + + if ((size_t) datalen > ret_data_size) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + MHD_gtls_write_uint16 (cipher_num, ret_data); + pos += 2; + + for (i = 0; i < (cipher_num / 2); i++) + { + memcpy (&ret_data[pos], cipher_suites[i].suite, 2); + pos += 2; + } + MHD_gnutls_free (cipher_suites); + + return datalen; +} + +/* This function copies the appropriate compression methods, to a locally allocated buffer + * Needed in hello messages. Returns the new data length. + */ +static int +MHD__gnutls_copy_comp_methods (MHD_gtls_session_t session, + opaque * ret_data, size_t ret_data_size) +{ + int ret, i; + uint8_t *compression_methods, comp_num; + int datalen, pos; + + ret = + MHD_gtls_supported_compression_methods (session, &compression_methods); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + comp_num = ret; + + datalen = pos = 0; + datalen += comp_num + 1; + + if ((size_t) datalen > ret_data_size) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + ret_data[pos++] = comp_num; /* put the number of compression methods */ + + for (i = 0; i < comp_num; i++) + { + ret_data[pos++] = compression_methods[i]; + } + + MHD_gnutls_free (compression_methods); + + return datalen; +} + +static void +MHD_gtls_set_adv_version (MHD_gtls_session_t session, + enum MHD_GNUTLS_Protocol ver) +{ + set_adv_version (session, MHD_gtls_version_get_major (ver), + MHD_gtls_version_get_minor (ver)); +} + +/* This function sends the client hello handshake message. + */ +static int +MHD__gnutls_send_client_hello (MHD_gtls_session_t session, int again) +{ + opaque *data = NULL; + int extdatalen; + int pos = 0; + int datalen = 0, ret = 0; + opaque rnd[TLS_RANDOM_SIZE]; + enum MHD_GNUTLS_Protocol hver; + opaque extdata[MAX_EXT_DATA_LENGTH]; + + opaque *SessionID = + session->internals.resumed_security_parameters.session_id; + uint8_t session_id_len = + session->internals.resumed_security_parameters.session_id_size; + + if (SessionID == NULL) + session_id_len = 0; + else if (session_id_len == 0) + SessionID = NULL; + + if (again == 0) + { + + datalen = 2 + (session_id_len + 1) + TLS_RANDOM_SIZE; + /* 2 for version, (4 for unix time + 28 for random bytes==TLS_RANDOM_SIZE) + */ + + data = MHD_gnutls_malloc (datalen); + if (data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + /* if we are resuming a session then we set the + * version number to the previously established. + */ + if (SessionID == NULL) + hver = MHD_gtls_version_max (session); + else + { /* we are resuming a session */ + hver = session->internals.resumed_security_parameters.version; + } + + if (hver == MHD_GNUTLS_PROTOCOL_VERSION_UNKNOWN || hver == 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (data); + return GNUTLS_E_INTERNAL_ERROR; + } + + data[pos++] = MHD_gtls_version_get_major (hver); + data[pos++] = MHD_gtls_version_get_minor (hver); + + /* Set the version we advertized as maximum + * (RSA uses it). + */ + MHD_gtls_set_adv_version (session, hver); + + /* Some old implementations do not interoperate if we send a + * different version in the record layer. + * It seems they prefer to read the record's version + * as the one we actually requested. + * The proper behaviour is to use the one in the client hello + * handshake packet and ignore the one in the packet's record + * header. + */ + MHD_gtls_set_current_version (session, hver); + + /* In order to know when this session was initiated. + */ + session->security_parameters.timestamp = time (NULL); + + /* Generate random data + */ + MHD_gtls_tls_create_random (rnd); + MHD_gtls_set_client_random (session, rnd); + + memcpy (&data[pos], rnd, TLS_RANDOM_SIZE); + pos += TLS_RANDOM_SIZE; + + /* Copy the Session ID */ + data[pos++] = session_id_len; + + if (session_id_len > 0) + { + memcpy (&data[pos], SessionID, session_id_len); + pos += session_id_len; + } + + + /* Copy the ciphersuites. + */ + extdatalen = + MHD__gnutls_copy_ciphersuites (session, extdata, sizeof (extdata)); + if (extdatalen > 0) + { + datalen += extdatalen; + data = MHD_gtls_realloc_fast (data, datalen); + if (data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy (&data[pos], extdata, extdatalen); + pos += extdatalen; + + } + else + { + if (extdatalen == 0) + extdatalen = GNUTLS_E_INTERNAL_ERROR; + MHD_gnutls_free (data); + MHD_gnutls_assert (); + return extdatalen; + } + + + /* Copy the compression methods. + */ + extdatalen = + MHD__gnutls_copy_comp_methods (session, extdata, sizeof (extdata)); + if (extdatalen > 0) + { + datalen += extdatalen; + data = MHD_gtls_realloc_fast (data, datalen); + if (data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy (&data[pos], extdata, extdatalen); + pos += extdatalen; + + } + else + { + if (extdatalen == 0) + extdatalen = GNUTLS_E_INTERNAL_ERROR; + MHD_gnutls_free (data); + MHD_gnutls_assert (); + return extdatalen; + } + + /* Generate and copy TLS extensions. + */ + if (hver >= MHD_GNUTLS_PROTOCOL_TLS1_0) + { + extdatalen = + MHD_gtls_gen_extensions (session, extdata, sizeof (extdata)); + + if (extdatalen > 0) + { + datalen += extdatalen; + data = MHD_gtls_realloc_fast (data, datalen); + if (data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + memcpy (&data[pos], extdata, extdatalen); + } + else if (extdatalen < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_free (data); + return extdatalen; + } + } + } + + ret = + MHD_gtls_send_handshake (session, data, datalen, + GNUTLS_HANDSHAKE_CLIENT_HELLO); + MHD_gnutls_free (data); + + return ret; +} +#endif + +static int +MHD__gnutls_send_server_hello (MHD_gtls_session_t session, int again) +{ + opaque *data = NULL; + opaque extdata[MAX_EXT_DATA_LENGTH]; + int extdatalen; + int pos = 0; + int datalen, ret = 0; + uint8_t comp; + opaque *SessionID = session->security_parameters.session_id; + uint8_t session_id_len = session->security_parameters.session_id_size; + opaque buf[2 * TLS_MAX_SESSION_ID_SIZE + 1]; + + if (SessionID == NULL) + session_id_len = 0; + + datalen = 0; + + if (again == 0) + { + datalen = 2 + session_id_len + 1 + TLS_RANDOM_SIZE + 3; + extdatalen = + MHD_gtls_gen_extensions (session, extdata, sizeof (extdata)); + + if (extdatalen < 0) + { + MHD_gnutls_assert (); + return extdatalen; + } + + data = MHD_gnutls_alloca (datalen + extdatalen); + if (data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + data[pos++] = + MHD_gtls_version_get_major (session->security_parameters.version); + data[pos++] = + MHD_gtls_version_get_minor (session->security_parameters.version); + + memcpy (&data[pos], + session->security_parameters.server_random, TLS_RANDOM_SIZE); + pos += TLS_RANDOM_SIZE; + + data[pos++] = session_id_len; + if (session_id_len > 0) + { + memcpy (&data[pos], SessionID, session_id_len); + } + pos += session_id_len; + + MHD__gnutls_handshake_log ("HSK[%x]: SessionID: %s\n", session, + MHD_gtls_bin2hex (SessionID, session_id_len, + (char *) buf, + sizeof (buf))); + + memcpy (&data[pos], + session->security_parameters.current_cipher_suite.suite, 2); + pos += 2; + + comp = + (uint8_t) MHD_gtls_compression_get_num (session-> + internals.compression_method); + data[pos++] = comp; + + + if (extdatalen > 0) + { + datalen += extdatalen; + + memcpy (&data[pos], extdata, extdatalen); + } + } + + ret = + MHD_gtls_send_handshake (session, data, datalen, + GNUTLS_HANDSHAKE_SERVER_HELLO); + MHD_gnutls_afree (data); + + return ret; +} + +int +MHD_gtls_send_hello (MHD_gtls_session_t session, int again) +{ + int ret; +#if MHD_DEBUG_TLS + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + ret = MHD__gnutls_send_client_hello (session, again); + + } + else +#endif + { /* SERVER */ + ret = MHD__gnutls_send_server_hello (session, again); + } + + return ret; +} + +/* RECEIVE A HELLO MESSAGE. This should be called from MHD_gnutls_recv_handshake_int only if a + * hello message is expected. It uses the security_parameters.current_cipher_suite + * and internals.compression_method. + */ +int +MHD_gtls_recv_hello (MHD_gtls_session_t session, opaque * data, int datalen) +{ + int ret; +#if MHD_DEBUG_TLS + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + ret = MHD__gnutls_read_server_hello (session, data, datalen); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + else +#endif + { /* Server side reading a client hello */ + + ret = MHD__gnutls_read_client_hello (session, data, datalen); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + + return ret; +} + +/* The packets in MHD__gnutls_handshake (it's more broad than original TLS handshake) + * + * Client Server + * + * ClientHello --------> + * <-------- ServerHello + * + * Certificate* + * ServerKeyExchange* + * <-------- CertificateRequest* + * + * <-------- ServerHelloDone + * Certificate* + * ClientKeyExchange + * CertificateVerify* + * [ChangeCipherSpec] + * Finished --------> + * [ChangeCipherSpec] + * <-------- Finished + * + * (*): means optional packet. + */ + +/** + * MHD__gnutls_rehandshake - This function will renegotiate security parameters + * @session: is a #MHD_gtls_session_t structure. + * + * This function will renegotiate security parameters with the + * client. This should only be called in case of a server. + * + * This message informs the peer that we want to renegotiate + * parameters (perform a handshake). + * + * If this function succeeds (returns 0), you must call the + * MHD__gnutls_handshake() function in order to negotiate the new + * parameters. + * + * If the client does not wish to renegotiate parameters he will + * should with an alert message, thus the return code will be + * %GNUTLS_E_WARNING_ALERT_RECEIVED and the alert will be + * %GNUTLS_A_NO_RENEGOTIATION. A client may also choose to ignore + * this message. + * + * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error. + * + **/ +int +MHD__gnutls_rehandshake (MHD_gtls_session_t session) +{ + int ret; + + ret = + MHD__gnutls_send_empty_handshake (session, GNUTLS_HANDSHAKE_HELLO_REQUEST, + AGAIN (STATE50)); + STATE = STATE50; + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + STATE = STATE0; + + return 0; +} + +inline static int +MHD__gnutls_abort_handshake (MHD_gtls_session_t session, int ret) +{ + if (((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) && + (MHD_gnutls_alert_get (session) == GNUTLS_A_NO_RENEGOTIATION)) + || ret == GNUTLS_E_GOT_APPLICATION_DATA) + return 0; + + /* this doesn't matter */ + return GNUTLS_E_INTERNAL_ERROR; +} + +/* This function initialized the handshake hash session. + * required for finished messages. + */ +inline static int +MHD__gnutls_handshake_hash_init (MHD_gtls_session_t session) +{ + + if (session->internals.handshake_mac_handle_md5 == NULL) + { + session->internals.handshake_mac_handle_md5 = + MHD_gtls_hash_init (MHD_GNUTLS_MAC_MD5); + + if (session->internals.handshake_mac_handle_md5 == GNUTLS_HASH_FAILED) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + } + + if (session->internals.handshake_mac_handle_sha == NULL) + { + session->internals.handshake_mac_handle_sha = + MHD_gtls_hash_init (MHD_GNUTLS_MAC_SHA1); + if (session->internals.handshake_mac_handle_sha == GNUTLS_HASH_FAILED) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + } + + return 0; +} + +static int +MHD__gnutls_send_supplemental (MHD_gtls_session_t session, int again) +{ + int ret = 0; + + MHD__gnutls_debug_log ("EXT[%x]: Sending supplemental data\n", session); + + if (again) + ret = MHD_gtls_send_handshake (session, NULL, 0, + GNUTLS_HANDSHAKE_SUPPLEMENTAL); + else + { + MHD_gtls_buffer buf; + MHD_gtls_buffer_init (&buf); + + ret = MHD__gnutls_gen_supplemental (session, &buf); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = MHD_gtls_send_handshake (session, buf.data, buf.length, + GNUTLS_HANDSHAKE_SUPPLEMENTAL); + MHD_gtls_buffer_clear (&buf); + } + + return ret; +} + +static int +MHD__gnutls_recv_supplemental (MHD_gtls_session_t session) +{ + uint8_t *data = NULL; + int datalen = 0; + int ret; + + MHD__gnutls_debug_log ("EXT[%x]: Expecting supplemental data\n", session); + + ret = MHD_gtls_recv_handshake (session, &data, &datalen, + GNUTLS_HANDSHAKE_SUPPLEMENTAL, + OPTIONAL_PACKET); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = MHD__gnutls_parse_supplemental (session, data, datalen); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD_gnutls_free (data); + + return ret; +} + +/** + * MHD__gnutls_handshake - This is the main function in the handshake protocol. + * @session: is a #MHD_gtls_session_t structure. + * + * This function does the handshake of the TLS/SSL protocol, and + * initializes the TLS connection. + * + * This function will fail if any problem is encountered, and will + * return a negative error code. In case of a client, if the client + * has asked to resume a session, but the server couldn't, then a + * full handshake will be performed. + * + * The non-fatal errors such as %GNUTLS_E_AGAIN and + * %GNUTLS_E_INTERRUPTED interrupt the handshake procedure, which + * should be later be resumed. Call this function again, until it + * returns 0; cf. MHD__gnutls_record_get_direction() and + * MHD_gtls_error_is_fatal(). + * + * If this function is called by a server after a rehandshake request + * then %GNUTLS_E_GOT_APPLICATION_DATA or + * %GNUTLS_E_WARNING_ALERT_RECEIVED may be returned. Note that these + * are non fatal errors, only in the specific case of a rehandshake. + * Their meaning is that the client rejected the rehandshake request. + * + * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error. + * + **/ +int +MHD__gnutls_handshake (MHD_gtls_session_t session) +{ + int ret; + + if ((ret = MHD__gnutls_handshake_hash_init (session)) < 0) + { + MHD_gnutls_assert (); + return ret; + } +#if MHD_DEBUG_TLS + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + ret = MHD_gtls_handshake_client (session); + } + else +#endif + { + ret = MHD_gtls_handshake_server (session); + } + + if (ret < 0) + { + /* In the case of a rehandshake abort + * we should reset the handshake's internal state. + */ + if (MHD__gnutls_abort_handshake (session, ret) == 0) + STATE = STATE0; + + return ret; + } + + ret = MHD_gtls_handshake_common (session); + + if (ret < 0) + { + if (MHD__gnutls_abort_handshake (session, ret) == 0) + STATE = STATE0; + + return ret; + } + + STATE = STATE0; + + MHD__gnutls_handshake_io_buffer_clear (session); + MHD_gtls_handshake_internal_state_clear (session); + + return 0; +} + +#define IMED_RET( str, ret) do { \ + if (ret < 0) { \ + if (MHD_gtls_error_is_fatal(ret)==0) return ret; \ + MHD_gnutls_assert(); \ + ERR( str, ret); \ + MHD__gnutls_handshake_hash_buffers_clear(session); \ + return ret; \ + } } while (0) + + +#if MHD_DEBUG_TLS +/* + * MHD_gtls_handshake_client + * This function performs the client side of the handshake of the TLS/SSL protocol. + */ +static int +MHD_gtls_handshake_client (MHD_gtls_session_t session) +{ + int ret = 0; + + switch (STATE) + { + case STATE0: + case STATE1: + ret = MHD_gtls_send_hello (session, AGAIN (STATE1)); + STATE = STATE1; + IMED_RET ("send hello", ret); + + case STATE2: + /* receive the server hello */ + ret = + MHD_gtls_recv_handshake (session, NULL, NULL, + GNUTLS_HANDSHAKE_SERVER_HELLO, + MANDATORY_PACKET); + STATE = STATE2; + IMED_RET ("recv hello", ret); + + case STATE70: + if (session->security_parameters.extensions.do_recv_supplemental) + { + ret = MHD__gnutls_recv_supplemental (session); + STATE = STATE70; + IMED_RET ("recv supplemental", ret); + } + + case STATE3: + /* RECV CERTIFICATE */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_recv_server_certificate (session); + STATE = STATE3; + IMED_RET ("recv server certificate", ret); + + case STATE4: + /* receive the server key exchange */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_recv_server_kx_message (session); + STATE = STATE4; + IMED_RET ("recv server kx message", ret); + + case STATE5: + /* receive the server certificate request - if any + */ + + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_recv_server_certificate_request (session); + STATE = STATE5; + IMED_RET ("recv server certificate request message", ret); + + case STATE6: + /* receive the server hello done */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = + MHD_gtls_recv_handshake (session, NULL, NULL, + GNUTLS_HANDSHAKE_SERVER_HELLO_DONE, + MANDATORY_PACKET); + STATE = STATE6; + IMED_RET ("recv server hello done", ret); + + case STATE71: + if (session->security_parameters.extensions.do_send_supplemental) + { + ret = MHD__gnutls_send_supplemental (session, AGAIN (STATE71)); + STATE = STATE71; + IMED_RET ("send supplemental", ret); + } + + case STATE7: + /* send our certificate - if any and if requested + */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_send_client_certificate (session, AGAIN (STATE7)); + STATE = STATE7; + IMED_RET ("send client certificate", ret); + + case STATE8: + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_send_client_kx_message (session, AGAIN (STATE8)); + STATE = STATE8; + IMED_RET ("send client kx", ret); + + case STATE9: + /* send client certificate verify */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = + MHD_gtls_send_client_certificate_verify (session, AGAIN (STATE9)); + STATE = STATE9; + IMED_RET ("send client certificate verify", ret); + + STATE = STATE0; + default: + break; + } + + + return 0; +} +#endif + +/* This function sends the final handshake packets and initializes connection + */ +static int +MHD__gnutls_send_handshake_final (MHD_gtls_session_t session, int init) +{ + int ret = 0; + + /* Send the CHANGE CIPHER SPEC PACKET */ + + switch (STATE) + { + case STATE0: + case STATE20: + ret = MHD_gtls_send_change_cipher_spec (session, AGAIN (STATE20)); + STATE = STATE20; + if (ret < 0) + { + ERR ("send ChangeCipherSpec", ret); + MHD_gnutls_assert (); + return ret; + } + + /* Initialize the connection session (start encryption) - in case of client + */ + if (init == TRUE) + { + ret = MHD_gtls_connection_state_init (session); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + + ret = MHD_gtls_write_connection_state_init (session); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + case STATE21: + /* send the finished message */ + ret = MHD__gnutls_send_finished (session, AGAIN (STATE21)); + STATE = STATE21; + if (ret < 0) + { + ERR ("send Finished", ret); + MHD_gnutls_assert (); + return ret; + } + + STATE = STATE0; + default: + break; + } + + return 0; +} + +/* This function receives the final handshake packets + * And executes the appropriate function to initialize the + * read session. + */ +static int +MHD__gnutls_recv_handshake_final (MHD_gtls_session_t session, int init) +{ + int ret = 0; + uint8_t ch; + + switch (STATE) + { + case STATE0: + case STATE30: + ret = + MHD_gtls_recv_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, &ch, 1); + STATE = STATE30; + if (ret <= 0) + { + ERR ("recv ChangeCipherSpec", ret); + MHD_gnutls_assert (); + return (ret < 0) ? ret : GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + /* Initialize the connection session (start encryption) - in case of server */ + if (init == TRUE) + { + ret = MHD_gtls_connection_state_init (session); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + + ret = MHD_gtls_read_connection_state_init (session); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + case STATE31: + ret = MHD__gnutls_recv_finished (session); + STATE = STATE31; + if (ret < 0) + { + ERR ("recv finished", ret); + MHD_gnutls_assert (); + return ret; + } + STATE = STATE0; + default: + break; + } + + + return 0; +} + + /* + * MHD_gtls_handshake_server + * This function does the server stuff of the handshake protocol. + */ + +static int +MHD_gtls_handshake_server (MHD_gtls_session_t session) +{ + int ret = 0; + + switch (STATE) + { + case STATE0: + case STATE1: + ret = + MHD_gtls_recv_handshake (session, NULL, NULL, + GNUTLS_HANDSHAKE_CLIENT_HELLO, + MANDATORY_PACKET); + STATE = STATE1; + IMED_RET ("recv hello", ret); + + case STATE2: + ret = MHD_gtls_send_hello (session, AGAIN (STATE2)); + STATE = STATE2; + IMED_RET ("send hello", ret); + + case STATE70: + if (session->security_parameters.extensions.do_send_supplemental) + { + ret = MHD__gnutls_send_supplemental (session, AGAIN (STATE70)); + STATE = STATE70; + IMED_RET ("send supplemental data", ret); + } + + /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */ + case STATE3: + /* NOTE: these should not be send if we are resuming */ + + if (session->internals.resumed == RESUME_FALSE) + ret = MHD_gtls_send_server_certificate (session, AGAIN (STATE3)); + STATE = STATE3; + IMED_RET ("send server certificate", ret); + + case STATE4: + /* send server key exchange (A) */ + if (session->internals.resumed == RESUME_FALSE) + ret = MHD_gtls_send_server_kx_message (session, AGAIN (STATE4)); + STATE = STATE4; + IMED_RET ("send server kx", ret); + + case STATE5: + /* Send certificate request - if requested to */ + if (session->internals.resumed == RESUME_FALSE) + ret = + MHD_gtls_send_server_certificate_request (session, AGAIN (STATE5)); + STATE = STATE5; + IMED_RET ("send server cert request", ret); + + case STATE6: + /* send the server hello done */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = + MHD__gnutls_send_empty_handshake (session, + GNUTLS_HANDSHAKE_SERVER_HELLO_DONE, + AGAIN (STATE6)); + STATE = STATE6; + IMED_RET ("send server hello done", ret); + + case STATE71: + if (session->security_parameters.extensions.do_recv_supplemental) + { + ret = MHD__gnutls_recv_supplemental (session); + STATE = STATE71; + IMED_RET ("recv client supplemental", ret); + } + + /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */ + case STATE7: + /* receive the client certificate message */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_recv_client_certificate (session); + STATE = STATE7; + IMED_RET ("recv client certificate", ret); + + case STATE8: + /* receive the client key exchange message */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_recv_client_kx_message (session); + STATE = STATE8; + IMED_RET ("recv client kx", ret); + + case STATE9: + /* receive the client certificate verify message */ + if (session->internals.resumed == RESUME_FALSE) /* if we are not resuming */ + ret = MHD_gtls_recv_client_certificate_verify_message (session); + STATE = STATE9; + IMED_RET ("recv client certificate verify", ret); + + STATE = STATE0; /* finished thus clear session */ + default: + break; + } + + return 0; +} + +static int +MHD_gtls_handshake_common (MHD_gtls_session_t session) +{ + int ret = 0; + + /* send and recv the change cipher spec and finished messages */ + if ((session->internals.resumed == RESUME_TRUE + && session->security_parameters.entity == GNUTLS_CLIENT) + || (session->internals.resumed == RESUME_FALSE + && session->security_parameters.entity == GNUTLS_SERVER)) + { + /* if we are a client resuming - or we are a server not resuming */ + + ret = MHD__gnutls_recv_handshake_final (session, TRUE); + IMED_RET ("recv handshake final", ret); + + ret = MHD__gnutls_send_handshake_final (session, FALSE); + IMED_RET ("send handshake final", ret); + } + else + { /* if we are a client not resuming - or we are a server resuming */ + + ret = MHD__gnutls_send_handshake_final (session, TRUE); + IMED_RET ("send handshake final 2", ret); + + ret = MHD__gnutls_recv_handshake_final (session, FALSE); + IMED_RET ("recv handshake final 2", ret); + } + + /* clear handshake buffer */ + MHD__gnutls_handshake_hash_buffers_clear (session); + return ret; + +} + +static int +MHD_gtls_generate_session_id (opaque * session_id, uint8_t * len) +{ + *len = TLS_MAX_SESSION_ID_SIZE; + + if (MHD_gc_nonce ((char *) session_id, *len) != GC_OK) + { + MHD_gnutls_assert (); + return GNUTLS_E_RANDOM_FAILED; + } + + return 0; +} + +int +MHD_gtls_recv_hello_request (MHD_gtls_session_t session, void *data, + uint32_t data_size) +{ + uint8_t type; + + if (session->security_parameters.entity == GNUTLS_SERVER) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET; + } + if (data_size < 1) + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + type = ((uint8_t *) data)[0]; + if (type == GNUTLS_HANDSHAKE_HELLO_REQUEST) + return GNUTLS_E_REHANDSHAKE; + else + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET; + } +} + +/* Returns 1 if the given KX has not the corresponding parameters + * (DH or RSA) set up. Otherwise returns 0. + */ +inline static int +check_server_params (MHD_gtls_session_t session, + enum MHD_GNUTLS_KeyExchangeAlgorithm kx, + enum MHD_GNUTLS_KeyExchangeAlgorithm *alg, int alg_size) +{ + int cred_type; + MHD_gtls_dh_params_t dh_params = NULL; + MHD_gtls_rsa_params_t rsa_params = NULL; + int j; + + cred_type = MHD_gtls_map_kx_get_cred (kx, 1); + + /* Read the Diffie Hellman parameters, if any. + */ + if (cred_type == MHD_GNUTLS_CRD_CERTIFICATE) + { + int delete; + MHD_gtls_cert_credentials_t x509_cred = + (MHD_gtls_cert_credentials_t) MHD_gtls_get_cred (session->key, + cred_type, NULL); + + if (x509_cred != NULL) + { + dh_params = + MHD_gtls_get_dh_params (x509_cred->dh_params, + x509_cred->params_func, session); + rsa_params = + MHD_gtls_certificate_get_rsa_params (x509_cred->rsa_params, + x509_cred->params_func, + session); + } + + /* Check also if the certificate supports the + * KX method. + */ + delete = 1; + for (j = 0; j < alg_size; j++) + { + if (alg[j] == kx) + { + delete = 0; + break; + } + } + + if (delete == 1) + return 1; + + } + else + return 0; /* no need for params */ + + + /* If the key exchange method needs RSA or DH params, + * but they are not set then remove it. + */ + if (MHD_gtls_kx_needs_rsa_params (kx) != 0) + { + /* needs rsa params. */ + if (MHD__gnutls_rsa_params_to_mpi (rsa_params) == NULL) + { + MHD_gnutls_assert (); + return 1; + } + } + + if (MHD_gtls_kx_needs_dh_params (kx) != 0) + { + /* needs DH params. */ + if (MHD_gtls_dh_params_to_mpi (dh_params) == NULL) + { + MHD_gnutls_assert (); + return 1; + } + } + + return 0; +} + +/* This function will remove algorithms that are not supported by + * the requested authentication method. We remove an algorithm if + * we have a certificate with keyUsage bits set. + * + * This does a more high level check than MHD_gnutls_supported_ciphersuites(), + * by checking certificates etc. + */ +static int +MHD_gtls_remove_unwanted_ciphersuites (MHD_gtls_session_t session, + cipher_suite_st ** cipherSuites, + int numCipherSuites, + enum MHD_GNUTLS_PublicKeyAlgorithm + requested_pk_algo) +{ + + int ret = 0; + cipher_suite_st *newSuite, cs; + int newSuiteSize = 0, i; + MHD_gtls_cert_credentials_t cert_cred; + enum MHD_GNUTLS_KeyExchangeAlgorithm kx; + int server = session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0; + enum MHD_GNUTLS_KeyExchangeAlgorithm *alg = NULL; + int alg_size = 0; + + /* if we should use a specific certificate, + * we should remove all algorithms that are not supported + * by that certificate and are on the same authentication + * method (CERTIFICATE). + */ + + cert_cred = + (MHD_gtls_cert_credentials_t) MHD_gtls_get_cred (session->key, + MHD_GNUTLS_CRD_CERTIFICATE, + NULL); + + /* If there are certificate credentials, find an appropriate certificate + * or disable them; + */ + if (session->security_parameters.entity == GNUTLS_SERVER + && cert_cred != NULL) + { + ret = MHD_gtls_server_select_cert (session, requested_pk_algo); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD__gnutls_x509_log + ("Could not find an appropriate certificate: %s\n", + MHD_gtls_strerror (ret)); + cert_cred = NULL; + } + } + + /* get all the key exchange algorithms that are + * supported by the X509 certificate parameters. + */ + if ((ret = + MHD_gtls_selected_cert_supported_kx (session, &alg, &alg_size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + newSuite = MHD_gnutls_malloc (numCipherSuites * sizeof (cipher_suite_st)); + if (newSuite == NULL) + { + MHD_gnutls_assert (); + MHD_gnutls_free (alg); + return GNUTLS_E_MEMORY_ERROR; + } + + /* now removes ciphersuites based on the KX algorithm + */ + for (i = 0; i < numCipherSuites; i++) + { + int delete = 0; + + /* finds the key exchange algorithm in + * the ciphersuite + */ + kx = MHD_gtls_cipher_suite_get_kx_algo (&(*cipherSuites)[i]); + + /* if it is defined but had no credentials + */ + if (MHD_gtls_get_kx_cred (session, kx, NULL) == NULL) + { + delete = 1; + } + else + { + delete = 0; + + if (server) + delete = check_server_params (session, kx, alg, alg_size); + } + memcpy (&cs.suite, &(*cipherSuites)[i].suite, 2); + + if (delete == 0) + { + + MHD__gnutls_handshake_log ("HSK[%x]: Keeping ciphersuite: %s\n", + session, + MHD_gtls_cipher_suite_get_name (&cs)); + + memcpy (newSuite[newSuiteSize].suite, (*cipherSuites)[i].suite, 2); + newSuiteSize++; + } + else + { + MHD__gnutls_handshake_log ("HSK[%x]: Removing ciphersuite: %s\n", + session, + MHD_gtls_cipher_suite_get_name (&cs)); + + } + } + + MHD_gnutls_free (alg); + MHD_gnutls_free (*cipherSuites); + *cipherSuites = newSuite; + + ret = newSuiteSize; + + return ret; + +} + +enum MHD_GNUTLS_Protocol +MHD_gtls_get_adv_version (MHD_gtls_session_t session) +{ + return MHD_gtls_version_get (MHD__gnutls_get_adv_version_major (session), + MHD__gnutls_get_adv_version_minor (session)); +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_handshake.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_handshake.h new file mode 100644 index 0000000000..58c95a84fe --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_handshake.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +typedef enum Optional +{ OPTIONAL_PACKET, MANDATORY_PACKET } Optional; + +int MHD_gtls_send_handshake (MHD_gtls_session_t session, void *i_data, + uint32_t i_datasize, + MHD_gnutls_handshake_description_t type); +int MHD_gtls_recv_hello_request (MHD_gtls_session_t session, void *data, + uint32_t data_size); +int MHD_gtls_send_hello (MHD_gtls_session_t session, int again); +int MHD_gtls_recv_hello (MHD_gtls_session_t session, opaque * data, + int datalen); +int MHD_gtls_recv_handshake (MHD_gtls_session_t session, uint8_t **, int *, + MHD_gnutls_handshake_description_t, + Optional optional); +void +MHD__gnutls_handshake_set_max_packet_length (MHD_gtls_session_t session, + size_t max); + +#define STATE session->internals.handshake_state +/* This returns true if we have got there + * before (and not finished due to an interrupt). + */ +#define AGAIN(target) STATE==target?1:0 diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_hash_int.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_hash_int.c new file mode 100644 index 0000000000..cc61203d11 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_hash_int.c @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2000, 2001, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file handles all the internal functions that cope with hashes + * and HMACs. + */ + +#include <gnutls_int.h> +#include <gnutls_hash_int.h> +#include <gnutls_errors.h> + +static inline Gc_hash +MHD__gnutls_mac2gc (enum MHD_GNUTLS_HashAlgorithm mac) +{ + switch (mac) + { + case MHD_GNUTLS_MAC_NULL: + return -1; + break; + case MHD_GNUTLS_MAC_SHA1: + return GC_SHA1; + break; + case MHD_GNUTLS_MAC_SHA256: + return GC_SHA256; + break; + case MHD_GNUTLS_MAC_MD5: + return GC_MD5; + break; + default: + MHD_gnutls_assert (); + return -1; + } + return -1; +} + +GNUTLS_HASH_HANDLE +MHD_gtls_hash_init (enum MHD_GNUTLS_HashAlgorithm algorithm) +{ + mac_hd_t ret; + int result; + + ret = MHD_gnutls_malloc (sizeof (mac_hd_st)); + if (ret == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_HASH_FAILED; + } + + ret->algorithm = algorithm; + + result = MHD_gc_hash_open (MHD__gnutls_mac2gc (algorithm), 0, &ret->handle); + if (result) + { + MHD_gnutls_assert (); + MHD_gnutls_free (ret); + ret = GNUTLS_HASH_FAILED; + } + + return ret; +} + +int +MHD_gnutls_hash_get_algo_len (enum MHD_GNUTLS_HashAlgorithm algorithm) +{ + int ret; + + ret = MHD_gc_hash_digest_length (MHD__gnutls_mac2gc (algorithm)); + + return ret; + +} + +int +MHD_gnutls_hash (GNUTLS_HASH_HANDLE handle, const void *text, size_t textlen) +{ + if (textlen > 0) + MHD_gc_hash_write (handle->handle, textlen, text); + return 0; +} + +GNUTLS_HASH_HANDLE +MHD_gnutls_hash_copy (GNUTLS_HASH_HANDLE handle) +{ + GNUTLS_HASH_HANDLE ret; + int result; + + ret = MHD_gnutls_malloc (sizeof (mac_hd_st)); + + if (ret == NULL) + return GNUTLS_HASH_FAILED; + + ret->algorithm = handle->algorithm; + ret->key = NULL; /* it's a hash anyway */ + ret->keysize = 0; + + result = MHD_gc_hash_clone (handle->handle, &ret->handle); + + if (result) + { + MHD_gnutls_free (ret); + return GNUTLS_HASH_FAILED; + } + + return ret; +} + +void +MHD_gnutls_hash_deinit (GNUTLS_HASH_HANDLE handle, void *digest) +{ + const opaque *mac; + int maclen; + + maclen = MHD_gnutls_hash_get_algo_len (handle->algorithm); + + mac = (unsigned char *) MHD_gc_hash_read (handle->handle); + if (digest != NULL) + memcpy (digest, mac, maclen); + + MHD_gc_hash_close (handle->handle); + + MHD_gnutls_free (handle); +} + + +mac_hd_t +MHD_gtls_MHD_hmac_init (enum MHD_GNUTLS_HashAlgorithm algorithm, + const void *key, int keylen) +{ + mac_hd_t ret; + int result; + + ret = MHD_gnutls_malloc (sizeof (mac_hd_st)); + if (ret == NULL) + return GNUTLS_MAC_FAILED; + + result = + MHD_gc_hash_open (MHD__gnutls_mac2gc (algorithm), GC_HMAC, &ret->handle); + if (result) + { + MHD_gnutls_free (ret); + return GNUTLS_MAC_FAILED; + } + + MHD_gc_hash_MHD_hmac_setkey (ret->handle, keylen, key); + + ret->algorithm = algorithm; + ret->key = key; + ret->keysize = keylen; + + return ret; +} + +void +MHD_gnutls_MHD_hmac_deinit (mac_hd_t handle, void *digest) +{ + const opaque *mac; + int maclen; + + maclen = MHD_gnutls_hash_get_algo_len (handle->algorithm); + + mac = (unsigned char *) MHD_gc_hash_read (handle->handle); + + if (digest != NULL) + memcpy (digest, mac, maclen); + + MHD_gc_hash_close (handle->handle); + + MHD_gnutls_free (handle); +} + +inline static int +get_padsize (enum MHD_GNUTLS_HashAlgorithm algorithm) +{ + switch (algorithm) + { + case MHD_GNUTLS_MAC_MD5: + return 48; + case MHD_GNUTLS_MAC_SHA1: + return 40; + default: + return 0; + } +} + +mac_hd_t +MHD_gnutls_mac_init_ssl3 (enum MHD_GNUTLS_HashAlgorithm algorithm, void *key, + int keylen) +{ + mac_hd_t ret; + opaque ipad[48]; + int padsize; + + padsize = get_padsize (algorithm); + if (padsize == 0) + { + MHD_gnutls_assert (); + return GNUTLS_MAC_FAILED; + } + + memset (ipad, 0x36, padsize); + + ret = MHD_gtls_hash_init (algorithm); + if (ret != GNUTLS_HASH_FAILED) + { + ret->key = key; + ret->keysize = keylen; + + if (keylen > 0) + MHD_gnutls_hash (ret, key, keylen); + MHD_gnutls_hash (ret, ipad, padsize); + } + + return ret; +} + +void +MHD_gnutls_mac_deinit_ssl3 (mac_hd_t handle, void *digest) +{ + opaque ret[MAX_HASH_SIZE]; + mac_hd_t td; + opaque opad[48]; + int padsize; + int block; + + padsize = get_padsize (handle->algorithm); + if (padsize == 0) + { + MHD_gnutls_assert (); + return; + } + + memset (opad, 0x5C, padsize); + + td = MHD_gtls_hash_init (handle->algorithm); + if (td != GNUTLS_MAC_FAILED) + { + if (handle->keysize > 0) + MHD_gnutls_hash (td, handle->key, handle->keysize); + + MHD_gnutls_hash (td, opad, padsize); + block = MHD_gnutls_hash_get_algo_len (handle->algorithm); + MHD_gnutls_hash_deinit (handle, ret); /* get the previous hash */ + MHD_gnutls_hash (td, ret, block); + + MHD_gnutls_hash_deinit (td, digest); + } +} + +void +MHD_gnutls_mac_deinit_ssl3_handshake (mac_hd_t handle, + void *digest, opaque * key, + uint32_t key_size) +{ + opaque ret[MAX_HASH_SIZE]; + mac_hd_t td; + opaque opad[48]; + opaque ipad[48]; + int padsize; + int block; + + padsize = get_padsize (handle->algorithm); + if (padsize == 0) + { + MHD_gnutls_assert (); + return; + } + + memset (opad, 0x5C, padsize); + memset (ipad, 0x36, padsize); + + td = MHD_gtls_hash_init (handle->algorithm); + if (td != GNUTLS_HASH_FAILED) + { + if (key_size > 0) + MHD_gnutls_hash (td, key, key_size); + + MHD_gnutls_hash (td, opad, padsize); + block = MHD_gnutls_hash_get_algo_len (handle->algorithm); + + if (key_size > 0) + MHD_gnutls_hash (handle, key, key_size); + MHD_gnutls_hash (handle, ipad, padsize); + MHD_gnutls_hash_deinit (handle, ret); /* get the previous hash */ + + MHD_gnutls_hash (td, ret, block); + + MHD_gnutls_hash_deinit (td, digest); + } +} + +static int +ssl3_sha (int i, opaque * secret, int secret_len, + opaque * rnd, int rnd_len, void *digest) +{ + int j; + opaque text1[26]; + + GNUTLS_HASH_HANDLE td; + + for (j = 0; j < i + 1; j++) + { + text1[j] = 65 + i; /* A==65 */ + } + + td = MHD_gtls_hash_init (MHD_GNUTLS_MAC_SHA1); + if (td == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + MHD_gnutls_hash (td, text1, i + 1); + MHD_gnutls_hash (td, secret, secret_len); + MHD_gnutls_hash (td, rnd, rnd_len); + + MHD_gnutls_hash_deinit (td, digest); + return 0; +} + +static int +ssl3_md5 (int i, opaque * secret, int secret_len, + opaque * rnd, int rnd_len, void *digest) +{ + opaque tmp[MAX_HASH_SIZE]; + mac_hd_t td; + int ret; + + td = MHD_gtls_hash_init (MHD_GNUTLS_MAC_MD5); + if (td == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + MHD_gnutls_hash (td, secret, secret_len); + + ret = ssl3_sha (i, secret, secret_len, rnd, rnd_len, tmp); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_hash_deinit (td, digest); + return ret; + } + + MHD_gnutls_hash (td, tmp, + MHD_gnutls_hash_get_algo_len (MHD_GNUTLS_MAC_SHA1)); + + MHD_gnutls_hash_deinit (td, digest); + return 0; +} + +int +MHD_gnutls_ssl3_hash_md5 (void *first, int first_len, + void *second, int second_len, int ret_len, + opaque * ret) +{ + opaque digest[MAX_HASH_SIZE]; + mac_hd_t td; + int block = MHD_gnutls_hash_get_algo_len (MHD_GNUTLS_MAC_MD5); + + td = MHD_gtls_hash_init (MHD_GNUTLS_MAC_MD5); + if (td == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + MHD_gnutls_hash (td, first, first_len); + MHD_gnutls_hash (td, second, second_len); + + MHD_gnutls_hash_deinit (td, digest); + + if (ret_len > block) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + memcpy (ret, digest, ret_len); + + return 0; + +} + +int +MHD_gnutls_ssl3_generate_random (void *secret, int secret_len, + void *rnd, int rnd_len, + int ret_bytes, opaque * ret) +{ + int i = 0, copy, output_bytes; + opaque digest[MAX_HASH_SIZE]; + int block = MHD_gnutls_hash_get_algo_len (MHD_GNUTLS_MAC_MD5); + int result, times; + + output_bytes = 0; + do + { + output_bytes += block; + } + while (output_bytes < ret_bytes); + + times = output_bytes / block; + + for (i = 0; i < times; i++) + { + + result = ssl3_md5 (i, secret, secret_len, rnd, rnd_len, digest); + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + if ((1 + i) * block < ret_bytes) + { + copy = block; + } + else + { + copy = ret_bytes - (i) * block; + } + + memcpy (&ret[i * block], digest, copy); + } + + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_hash_int.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_hash_int.h new file mode 100644 index 0000000000..bd3dec2987 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_hash_int.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_HASH_INT_H +# define GNUTLS_HASH_INT_H + +#include <gnutls_int.h> + +/* for message digests */ + +typedef struct +{ + MHD_gc_hash_handle handle; + enum MHD_GNUTLS_HashAlgorithm algorithm; + const void *key; + int keysize; +} mac_hd_st; +typedef mac_hd_st *mac_hd_t; +typedef mac_hd_t GNUTLS_HASH_HANDLE; + +#define GNUTLS_HASH_FAILED NULL +#define GNUTLS_MAC_FAILED NULL + +mac_hd_t MHD_gtls_MHD_hmac_init (enum MHD_GNUTLS_HashAlgorithm algorithm, + const void *key, int keylen); + +void MHD_gnutls_MHD_hmac_deinit (mac_hd_t handle, void *digest); + +mac_hd_t MHD_gnutls_mac_init_ssl3 (enum MHD_GNUTLS_HashAlgorithm algorithm, + void *key, int keylen); +void MHD_gnutls_mac_deinit_ssl3 (mac_hd_t handle, void *digest); + +GNUTLS_HASH_HANDLE MHD_gtls_hash_init (enum MHD_GNUTLS_HashAlgorithm + algorithm); +int MHD_gnutls_hash_get_algo_len (enum MHD_GNUTLS_HashAlgorithm algorithm); +int MHD_gnutls_hash (GNUTLS_HASH_HANDLE handle, const void *text, + size_t textlen); +void MHD_gnutls_hash_deinit (GNUTLS_HASH_HANDLE handle, void *digest); + +int MHD_gnutls_ssl3_generate_random (void *secret, int secret_len, + void *rnd, int random_len, int bytes, + opaque * ret); +int MHD_gnutls_ssl3_hash_md5 (void *first, int first_len, void *second, + int second_len, int ret_len, opaque * ret); + +void MHD_gnutls_mac_deinit_ssl3_handshake (mac_hd_t handle, void *digest, + opaque * key, uint32_t key_size); + +GNUTLS_HASH_HANDLE MHD_gnutls_hash_copy (GNUTLS_HASH_HANDLE handle); + +#endif /* GNUTLS_HASH_INT_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_int.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_int.h new file mode 100644 index 0000000000..25a861ed21 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_int.h @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_INT_H +#define GNUTLS_INT_H + +#include <defines.h> + +#include "gnutls.h" +#include "microhttpd.h" + +#include "gnutls_mem.h" + +/* FIXME: delete this once opencdk has reentrant keyring functions + */ +#define KEYRING_HACK + +#ifndef MAX +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) +#endif + +#define MAX32 4294967295 +#define MAX24 16777215 +#define MAX16 65535 + +/* The size of a handshake message should not + * be larger than this value. + */ +#define MAX_HANDSHAKE_PACKET_SIZE 48*1024 + +#define TLS_RANDOM_SIZE 32 +#define TLS_MAX_SESSION_ID_SIZE 32 +#define TLS_MASTER_SIZE 48 + +/* The maximum digest size of hash algorithms. + */ +#define MAX_HASH_SIZE 64 + +#define MAX_LOG_SIZE 1024 /* maximum size of log message */ +#define MAX_SERVER_NAME_SIZE 128 + +/* we can receive up to MAX_EXT_TYPES extensions. + */ +#define MAX_EXT_TYPES 64 + +/* The initial size of the receive + * buffer size. This will grow if larger + * packets are received. + */ +#define INITIAL_RECV_BUFFER_SIZE 256 + +/* the default for TCP */ +#define DEFAULT_LOWAT 1 + +/* expire time for resuming sessions */ +#define DEFAULT_EXPIRE_TIME 3600 + +/* the maximum size of encrypted packets */ +#define DEFAULT_MAX_RECORD_SIZE 16384 +#define RECORD_HEADER_SIZE 5 +#define MAX_RECORD_SEND_SIZE (size_t)session->security_parameters.max_record_send_size +#define MAX_RECORD_RECV_SIZE (size_t)session->security_parameters.max_record_recv_size +#define MAX_PAD_SIZE 255 +#define EXTRA_COMP_SIZE 2048 +#define MAX_RECORD_OVERHEAD MAX_PAD_SIZE+EXTRA_COMP_SIZE +#define MAX_RECV_SIZE MAX_RECORD_OVERHEAD+MAX_RECORD_RECV_SIZE+RECORD_HEADER_SIZE + +#define HANDSHAKE_HEADER_SIZE 4 + +/* defaults for verification functions + */ +#define DEFAULT_VERIFY_DEPTH 32 +#define DEFAULT_VERIFY_BITS 16*1024 + +#define DECR_LEN(len, x) do { len-=x; if (len<0) {MHD_gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;} } while (0) +#define DECR_LENGTH_RET(len, x, RET) do { len-=x; if (len<0) {MHD_gnutls_assert(); return RET;} } while (0) +#define DECR_LENGTH_COM(len, x, COM) do { len-=x; if (len<0) {MHD_gnutls_assert(); COM;} } while (0) + +#define HASH2MAC(x) ((enum MHD_GNUTLS_HashAlgorithm)x) + +/* TODO rm */ +/* Additional cast to bring void* to a type castable to int. */ +#define GNUTLS_POINTER_TO_INT_CAST (long) + +#define GNUTLS_POINTER_TO_INT(_) ((int) GNUTLS_POINTER_TO_INT_CAST (_)) +#define GNUTLS_INT_TO_POINTER(_) ((void*) GNUTLS_POINTER_TO_INT_CAST (_)) + +typedef unsigned char opaque; +typedef struct +{ + opaque pint[3]; +} uint24; + +#include <gnutls_mpi.h> + +typedef enum change_cipher_spec_t +{ + GNUTLS_TYPE_CHANGE_CIPHER_SPEC = 1 +} change_cipher_spec_t; + +typedef enum handshake_state_t +{ + STATE0 = 0, STATE1, STATE2, + STATE3, STATE4, STATE5, + STATE6, STATE7, STATE8, STATE9, STATE20 = 20, STATE21, + STATE30 = 30, STATE31, STATE50 = 50, STATE60 = 60, STATE61, STATE62, + STATE70, STATE71 +} handshake_state_t; + +#include <gnutls_str.h> + +typedef MHD_gtls_string MHD_gtls_buffer; + +#define MHD_gtls_buffer_init(buf) MHD_gtls_string_init(buf, MHD_gnutls_malloc, MHD_gnutls_realloc, MHD_gnutls_free); +#define MHD_gtls_buffer_clear MHD_gtls_string_clear +#define MHD_gtls_buffer_append MHD_gtls_string_append_data + +/* This is the maximum number of algorithms (ciphers or macs etc). + * keep it synced with GNUTLS_MAX_ALGORITHM_NUM in gnutls.h + */ +#define MAX_ALGOS 16 + +#define MAX_CIPHERSUITES 256 + +typedef enum extensions_t +{ GNUTLS_EXTENSION_SERVER_NAME = 0, + GNUTLS_EXTENSION_MAX_RECORD_SIZE = 1, + GNUTLS_EXTENSION_CERT_TYPE = 9, + GNUTLS_EXTENSION_SRP = 12, + GNUTLS_EXTENSION_INNER_APPLICATION = 37703 +} extensions_t; + +typedef enum +{ CIPHER_STREAM, CIPHER_BLOCK } cipher_type_t; + +typedef enum valid_session_t +{ VALID_TRUE, VALID_FALSE } valid_session_t; +typedef enum resumable_session_t +{ RESUME_TRUE, + RESUME_FALSE +} resumable_session_t; + +/* Record Protocol */ +typedef enum content_type_t +{ + GNUTLS_CHANGE_CIPHER_SPEC = 20, GNUTLS_ALERT, + GNUTLS_HANDSHAKE, GNUTLS_APPLICATION_DATA, + GNUTLS_INNER_APPLICATION = 24 +} content_type_t; + +#define GNUTLS_PK_ANY (enum MHD_GNUTLS_PublicKeyAlgorithm)-1 +#define GNUTLS_PK_NONE (enum MHD_GNUTLS_PublicKeyAlgorithm)-2 + +/* STATE (stop) */ + +typedef void (*LOG_FUNC) (int, const char *); + +/* Store & Retrieve functions defines: */ +typedef struct MHD_gtls_auth_cred_st +{ + enum MHD_GNUTLS_CredentialsType algorithm; + + /* the type of credentials depends on algorithm + */ + void *credentials; + struct MHD_gtls_auth_cred_st *next; +} auth_cred_st; + +struct MHD_gtls_key +{ + /* For DH KX */ + MHD_gnutls_datum_t key; + mpi_t KEY; + mpi_t client_Y; + mpi_t client_g; + mpi_t client_p; + mpi_t dh_secret; + /* for SRP */ + mpi_t A; + mpi_t B; + mpi_t u; + mpi_t b; + mpi_t a; + mpi_t x; + /* RSA: e, m + */ + mpi_t rsa[2]; + + /* this is used to hold the peers authentication data + */ + /* auth_info_t structures SHOULD NOT contain malloced + * elements. Check MHD_gnutls_session_pack.c, and MHD_gnutls_auth.c. + * Rememember that this should be calloced! + */ + void *auth_info; + enum MHD_GNUTLS_CredentialsType auth_info_type; + int auth_info_size; /* needed in order to store to db for restoring + */ + uint8_t crypt_algo; + + auth_cred_st *cred; /* used to specify keys/certificates etc */ + + int certificate_requested; + /* some ciphersuites use this + * to provide client authentication. + * 1 if client auth was requested + * by the peer, 0 otherwise + *** In case of a server this + * holds 1 if we should wait + * for a client certificate verify + */ +}; +typedef struct MHD_gtls_key *MHD_gtls_key_st; + +/* STATE (cont) */ +#include <gnutls_hash_int.h> +#include <gnutls_cipher_int.h> +#include <gnutls_cert.h> + +typedef struct +{ + uint8_t suite[2]; +} cipher_suite_st; + +/* This structure holds parameters got from TLS extension + * mechanism. (some extensions may hold parameters in auth_info_t + * structures also - see SRP). + */ +typedef struct +{ + opaque name[MAX_SERVER_NAME_SIZE]; + unsigned name_length; + MHD_gnutls_server_name_type_t type; +} server_name_st; + +#define MAX_SERVER_NAME_EXTENSIONS 3 +typedef struct +{ + server_name_st server_names[MAX_SERVER_NAME_EXTENSIONS]; + /* limit server_name extensions */ + unsigned server_names_size; + + /* TLS/IA data. */ + int MHD_gnutls_ia_enable, MHD_gnutls_ia_peer_enable; + int MHD_gnutls_ia_allowskip, MHD_gnutls_ia_peer_allowskip; + + /* Used by extensions that enable supplemental data. */ + int do_recv_supplemental, do_send_supplemental; + +} MHD_gtls_ext_st; + +/* This flag indicates for an extension whether + * it is useful to application level or TLS level only. + * This is used to parse the application level extensions + * before the user_hello callback is called. + */ +typedef enum tls_ext_parse_type_t +{ + EXTENSION_ANY, + EXTENSION_APPLICATION, + EXTENSION_TLS +} MHD_gtls_ext_parse_type_t; + +/* auth_info_t structures now MAY contain malloced + * elements. + */ + +/* This structure and auth_info_t, are stored in the resume database, + * and are restored, in case of resume. + * Holds all the required parameters to resume the current + * session. + */ + +/* if you add anything in Security_Parameters struct, then + * also modify CPY_COMMON in MHD_gnutls_constate.c + */ + +/* Note that the security parameters structure is set up after the + * handshake has finished. The only value you may depend on while + * the handshake is in progress is the cipher suite value. + */ +typedef struct +{ + MHD_gnutls_connection_end_t entity; + enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm; + /* we've got separate write/read bulk/macs because + * there is a time in handshake where the peer has + * null cipher and we don't + */ + enum MHD_GNUTLS_CipherAlgorithm read_bulk_cipher_algorithm; + enum MHD_GNUTLS_HashAlgorithm read_mac_algorithm; + enum MHD_GNUTLS_CompressionMethod read_compression_algorithm; + + enum MHD_GNUTLS_CipherAlgorithm write_bulk_cipher_algorithm; + enum MHD_GNUTLS_HashAlgorithm write_mac_algorithm; + enum MHD_GNUTLS_CompressionMethod write_compression_algorithm; + + /* this is the ciphersuite we are going to use + * moved here from internals in order to be restored + * on resume; + */ + cipher_suite_st current_cipher_suite; + opaque master_secret[TLS_MASTER_SIZE]; + opaque client_random[TLS_RANDOM_SIZE]; + opaque server_random[TLS_RANDOM_SIZE]; + opaque session_id[TLS_MAX_SESSION_ID_SIZE]; + uint8_t session_id_size; + time_t timestamp; + MHD_gtls_ext_st extensions; + + /* The send size is the one requested by the programmer. + * The recv size is the one negotiated with the peer. + */ + uint16_t max_record_send_size; + uint16_t max_record_recv_size; + /* holds the negotiated certificate type */ + enum MHD_GNUTLS_CertificateType cert_type; + enum MHD_GNUTLS_Protocol version; /* moved here */ + /* For TLS/IA. XXX: Move to IA credential? */ + opaque inner_secret[TLS_MASTER_SIZE]; +} MHD_gtls_security_param_st; + +/* This structure holds the generated keys + */ +typedef struct +{ + MHD_gnutls_datum_t server_write_mac_secret; + MHD_gnutls_datum_t client_write_mac_secret; + MHD_gnutls_datum_t server_write_IV; + MHD_gnutls_datum_t client_write_IV; + MHD_gnutls_datum_t server_write_key; + MHD_gnutls_datum_t client_write_key; + int generated_keys; /* zero if keys have not + * been generated. Non zero + * otherwise. + */ +} MHD_gtls_cipher_specs_st; + +typedef struct +{ + cipher_hd_t write_cipher_state; + cipher_hd_t read_cipher_state; + MHD_gnutls_datum_t read_mac_secret; + MHD_gnutls_datum_t write_mac_secret; + uint64 read_sequence_number; + uint64 write_sequence_number; +} MHD_gtls_conn_stat_st; + +typedef struct +{ + unsigned int priority[MAX_ALGOS]; + unsigned int num_algorithms; +} MHD_gtls_priority_st; + +/* For the external api */ +struct MHD_gtls_priority_st +{ + MHD_gtls_priority_st cipher; + MHD_gtls_priority_st mac; + MHD_gtls_priority_st kx; + MHD_gtls_priority_st compression; + MHD_gtls_priority_st protocol; + + /* certificate type : x509, OpenPGP, etc. */ + MHD_gtls_priority_st cert_type; + + /* to disable record padding */ + int no_padding; +}; + +/* DH and RSA parameters types. + */ +typedef struct MHD_gtls_dh_params_int +{ + /* [0] is the prime, [1] is the generator. + */ + mpi_t params[2]; +} MHD_gtls_dh_params_st; + +typedef struct +{ + MHD_gtls_dh_params_t dh_params; + int free_dh_params; + MHD_gtls_rsa_params_t rsa_params; + int free_rsa_params; +} MHD_gtls_internal_params_st; + +typedef struct +{ + opaque header[HANDSHAKE_HEADER_SIZE]; + /* this holds the number of bytes in the handshake_header[] */ + size_t header_size; + /* this holds the length of the handshake packet */ + size_t packet_length; + MHD_gnutls_handshake_description_t recv_type; +} MHD_gtls_handshake_header_buffer_st; + +typedef struct +{ + MHD_gtls_buffer application_data_buffer; /* holds data to be delivered to application layer */ + MHD_gtls_buffer handshake_hash_buffer; /* used to keep the last received handshake + * message */ + mac_hd_t handshake_mac_handle_sha; /* hash of the handshake messages */ + mac_hd_t handshake_mac_handle_md5; /* hash of the handshake messages */ + + MHD_gtls_buffer handshake_data_buffer; /* this is a buffer that holds the current handshake message */ + MHD_gtls_buffer ia_data_buffer; /* holds inner application data (TLS/IA) */ + resumable_session_t resumable; /* TRUE or FALSE - if we can resume that session */ + handshake_state_t handshake_state; /* holds + * a number which indicates where + * the handshake procedure has been + * interrupted. If it is 0 then + * no interruption has happened. + */ + + valid_session_t valid_connection; /* true or FALSE - if this session is valid */ + + int may_not_read; /* if it's 0 then we can read/write, otherwise it's forbiden to read/write + */ + int may_not_write; + int read_eof; /* non-zero if we have received a closure alert. */ + + int last_alert; /* last alert received */ + int last_alert_level; /* last alert level */ + + /* The last handshake messages sent or received. + */ + int last_handshake_in; + int last_handshake_out; + + /* this is the compression method we are going to use */ + enum MHD_GNUTLS_CompressionMethod compression_method; + + /* priorities */ + struct MHD_gtls_priority_st priorities; + + /* resumed session */ + resumable_session_t resumed; /* RESUME_TRUE or FALSE - if we are resuming a session */ + MHD_gtls_security_param_st resumed_security_parameters; + + /* sockets internals */ + int lowat; + + /* These buffers are used in the handshake + * protocol only. freed using MHD__gnutls_handshake_io_buffer_clear(); + */ + MHD_gtls_buffer handshake_send_buffer; + size_t handshake_send_buffer_prev_size; + content_type_t handshake_send_buffer_type; + MHD_gnutls_handshake_description_t handshake_send_buffer_htype; + content_type_t handshake_recv_buffer_type; + MHD_gnutls_handshake_description_t handshake_recv_buffer_htype; + MHD_gtls_buffer handshake_recv_buffer; + + /* this buffer holds a record packet -mostly used for + * non blocking IO. + */ + MHD_gtls_buffer record_recv_buffer; + MHD_gtls_buffer record_send_buffer; /* holds cached data + * for the MHD_gnutls_io_write_buffered() + * function. + */ + size_t record_send_buffer_prev_size; /* holds the + * data written in the previous runs. + */ + size_t record_send_buffer_user_size; /* holds the + * size of the user specified data to + * send. + */ + + /* 0 if no peeked data was kept, 1 otherwise. + */ + int have_peeked_data; + + int expire_time; /* after expire_time seconds this session will expire */ + struct MHD_gtls_mod_auth_st_int *auth_struct; /* used in handshake packets and KX algorithms */ + + /* TODO rm */ + int v2_hello; /* 0 if the client hello is v3+. + * non-zero if we got a v2 hello. + */ + /* keeps the headers of the handshake packet + */ + MHD_gtls_handshake_header_buffer_st handshake_header_buffer; + + /* this is the highest version available + * to the peer. (advertized version). + * This is obtained by the Handshake Client Hello + * message. (some implementations read the Record version) + */ + uint8_t adv_version_major; + uint8_t adv_version_minor; + + /* if this is non zero a certificate request message + * will be sent to the client. - only if the ciphersuite + * supports it. + */ + int send_cert_req; + + /* bits to use for DHE and DHA + * use MHD__gnutls_dh_get_prime_bits() and MHD__gnutls_dh_set_prime_bits() + * to access it. + */ + uint16_t dh_prime_bits; + + size_t max_handshake_data_buffer_size; + + /* PUSH & PULL functions. + */ + MHD_gtls_pull_func MHD__gnutls_pull_func; + MHD_gtls_push_func MHD__gnutls_push_func; + /* Holds the first argument of PUSH and PULL + * functions; + */ + MHD_gnutls_transport_ptr_t transport_recv_ptr; + MHD_gnutls_transport_ptr_t transport_send_ptr; + + /* Holds the record size requested by the + * user. + */ + uint16_t proposed_record_size; + + /* holds the selected certificate and key. + * use MHD_gtls_selected_certs_deinit() and MHD_gtls_selected_certs_set() + * to change them. + */ + MHD_gnutls_cert *selected_cert_list; + int selected_cert_list_length; + MHD_gnutls_privkey *selected_key; + int selected_need_free; + + /* holds the extensions we sent to the peer + * (in case of a client) + */ + uint16_t extensions_sent[MAX_EXT_TYPES]; + uint16_t extensions_sent_size; + + /* This holds the default version that our first + * record packet will have. */ + opaque default_record_version[2]; + + void *user_ptr; + + /* Holds 0 if the last called function was interrupted while + * receiving, and non zero otherwise. + */ + int direction; + + /* If non zero the server will not advertize the CA's he + * trusts (do not send an RDN sequence). + */ + int ignore_rdn_sequence; + + /* This is used to set an arbitary version in the RSA + * PMS secret. Can be used by clients to test whether the + * server checks that version. (** only used in gnutls-cli-debug) + */ + opaque rsa_pms_version[2]; + + /* Here we cache the DH or RSA parameters got from the + * credentials structure, or from a callback. That is to + * minimize external calls. + */ + MHD_gtls_internal_params_st params; + + /* This buffer is used by the record recv functions, + * as a temporary store buffer. + */ + MHD_gnutls_datum_t recv_buffer; + + /* To avoid using global variables, and especially on Windows where + * the application may use a different errno variable than GnuTLS, + * it is possible to use MHD__gnutls_transport_set_errno to set a + * session-specific errno variable in the user-replaceable push/pull + * functions. This value is used by the send/recv functions. (The + * strange name of this variable is because 'errno' is typically + * #define'd.) + */ + int errnum; + + /* Function used to perform public-key signing operation during + handshake. Used by MHD_gnutls_sig.c:MHD__gnutls_tls_sign(), see also + MHD_gtls_sign_callback_set(). */ + MHD_gnutls_sign_func sign_func; + void *sign_func_userdata; + + /* If you add anything here, check MHD_gtls_handshake_internal_state_clear(). + */ +} MHD_gtls_internals_st; + +struct MHD_gtls_session_int +{ + MHD_gtls_security_param_st security_parameters; + MHD_gtls_cipher_specs_st cipher_specs; + MHD_gtls_conn_stat_st connection_state; + MHD_gtls_internals_st internals; + MHD_gtls_key_st key; +}; + +/* functions */ +void MHD_gtls_set_current_version (MHD_gtls_session_t session, + enum MHD_GNUTLS_Protocol version); + +void MHD_gtls_free_auth_info (MHD_gtls_session_t session); + +/* These two macros return the advertized TLS version of + * the peer. + */ +#define MHD__gnutls_get_adv_version_major( session) \ + session->internals.adv_version_major + +#define MHD__gnutls_get_adv_version_minor( session) \ + session->internals.adv_version_minor + +#define set_adv_version( session, major, minor) \ + session->internals.adv_version_major = major; \ + session->internals.adv_version_minor = minor + +enum MHD_GNUTLS_Protocol MHD_gtls_get_adv_version (MHD_gtls_session_t); + +#endif /* GNUTLS_INT_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_kx.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_kx.c new file mode 100644 index 0000000000..a4041e390a --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_kx.c @@ -0,0 +1,726 @@ +/* + * Copyright (C) 2000, 2001, 2004, 2005, 2006 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains functions which are wrappers for the key exchange + * part of TLS. They are called by the handshake functions (MHD__gnutls_handshake) + */ + +#include "gnutls_int.h" +#include "gnutls_handshake.h" +#include "gnutls_kx.h" +#include "gnutls_dh.h" +#include "gnutls_errors.h" +#include "gnutls_algorithms.h" +#include "debug.h" +#include "gnutls_mpi.h" +#include <gnutls_state.h> +#include <gnutls_datum.h> +#include <gnutls_rsa_export.h> + +/* This file contains important thing for the TLS handshake procedure. + */ + +#define MASTER_SECRET "master secret" +static int generate_normal_master (MHD_gtls_session_t session, int); + +int +MHD_gtls_generate_master (MHD_gtls_session_t session, int keep_premaster) +{ + if (session->internals.resumed == RESUME_FALSE) + return generate_normal_master (session, keep_premaster); + return 0; +} + +/* here we generate the TLS Master secret. + */ +#define PREMASTER session->key->key +static int +generate_normal_master (MHD_gtls_session_t session, int keep_premaster) +{ + int ret = 0; + char buf[512]; + + MHD__gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size, + MHD_gtls_bin2hex (PREMASTER.data, PREMASTER.size, buf, + sizeof (buf))); + MHD__gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32, + MHD_gtls_bin2hex (session->security_parameters. + client_random, 32, buf, + sizeof (buf))); + MHD__gnutls_hard_log ("INT: SERVER RANDOM[%d]: %s\n", 32, + MHD_gtls_bin2hex (session->security_parameters. + server_random, 32, buf, + sizeof (buf))); + + if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3) + { + opaque rnd[2 * TLS_RANDOM_SIZE + 1]; + + memcpy (rnd, session->security_parameters.client_random, + TLS_RANDOM_SIZE); + memcpy (&rnd[TLS_RANDOM_SIZE], + session->security_parameters.server_random, TLS_RANDOM_SIZE); + + ret = + MHD_gnutls_ssl3_generate_random (PREMASTER.data, PREMASTER.size, + rnd, 2 * TLS_RANDOM_SIZE, + TLS_MASTER_SIZE, + session->security_parameters. + master_secret); + + } + else + { + opaque rnd[2 * TLS_RANDOM_SIZE + 1]; + + memcpy (rnd, session->security_parameters.client_random, + TLS_RANDOM_SIZE); + memcpy (&rnd[TLS_RANDOM_SIZE], + session->security_parameters.server_random, TLS_RANDOM_SIZE); + + ret = + MHD_gtls_PRF (session, PREMASTER.data, PREMASTER.size, + MASTER_SECRET, strlen (MASTER_SECRET), + rnd, 2 * TLS_RANDOM_SIZE, TLS_MASTER_SIZE, + session->security_parameters.master_secret); + } + + /* TLS/IA inner secret is derived from the master secret. */ + memcpy (session->security_parameters.inner_secret, + session->security_parameters.master_secret, TLS_MASTER_SIZE); + + if (!keep_premaster) + MHD__gnutls_free_datum (&PREMASTER); + + if (ret < 0) + return ret; + + MHD__gnutls_hard_log ("INT: MASTER SECRET: %s\n", + MHD_gtls_bin2hex (session->security_parameters. + master_secret, TLS_MASTER_SIZE, buf, + sizeof (buf))); + + return ret; +} + + +/* This is called when we want to receive the key exchange message of the + * server. It does nothing if this type of message is not required + * by the selected ciphersuite. + */ +int +MHD_gtls_send_server_kx_message (MHD_gtls_session_t session, int again) +{ + uint8_t *data = NULL; + int data_size = 0; + int ret = 0; + + if (session->internals.auth_struct->MHD_gtls_gen_server_kx == NULL) + return 0; + + data = NULL; + data_size = 0; + + if (again == 0) + { + data_size = + session->internals.auth_struct->MHD_gtls_gen_server_kx (session, + &data); + + if (data_size == GNUTLS_E_INT_RET_0) + { + MHD_gnutls_assert (); + return 0; + } + + if (data_size < 0) + { + MHD_gnutls_assert (); + return data_size; + } + } + + ret = + MHD_gtls_send_handshake (session, data, data_size, + GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE); + MHD_gnutls_free (data); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + return data_size; +} + +/* This function sends a certificate request message to the + * client. + */ +int +MHD_gtls_send_server_certificate_request (MHD_gtls_session_t session, + int again) +{ + uint8_t *data = NULL; + int data_size = 0; + int ret = 0; + + if (session->internals.auth_struct-> + MHD_gtls_gen_server_certificate_request == NULL) + return 0; + + if (session->internals.send_cert_req <= 0) + return 0; + + data = NULL; + data_size = 0; + + if (again == 0) + { + data_size = + session->internals.auth_struct-> + MHD_gtls_gen_server_certificate_request (session, &data); + + if (data_size < 0) + { + MHD_gnutls_assert (); + return data_size; + } + } + ret = + MHD_gtls_send_handshake (session, data, data_size, + GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST); + MHD_gnutls_free (data); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + return data_size; +} + + +/* This is the function for the client to send the key + * exchange message + */ +int +MHD_gtls_send_client_kx_message (MHD_gtls_session_t session, int again) +{ + uint8_t *data; + int data_size; + int ret = 0; + + if (session->internals.auth_struct->MHD_gtls_gen_client_kx == NULL) + return 0; + + + data = NULL; + data_size = 0; + + if (again == 0) + { + data_size = + session->internals.auth_struct->MHD_gtls_gen_client_kx (session, + &data); + if (data_size < 0) + { + MHD_gnutls_assert (); + return data_size; + } + } + ret = + MHD_gtls_send_handshake (session, data, data_size, + GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE); + MHD_gnutls_free (data); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return ret; +} + + +/* This is the function for the client to send the certificate + * verify message + */ +int +MHD_gtls_send_client_certificate_verify (MHD_gtls_session_t session, + int again) +{ + uint8_t *data; + int ret = 0; + int data_size; + + /* This is a packet that is only sent by the client + */ + if (session->security_parameters.entity == GNUTLS_SERVER) + return 0; + + /* if certificate verify is not needed just exit + */ + if (session->key->certificate_requested == 0) + return 0; + + if (session->internals.auth_struct->MHD_gtls_gen_client_cert_vrfy == NULL) + { + MHD_gnutls_assert (); + return 0; /* this algorithm does not support cli_cert_vrfy + */ + } + + data = NULL; + data_size = 0; + + if (again == 0) + { + data_size = + session->internals.auth_struct-> + MHD_gtls_gen_client_cert_vrfy (session, &data); + if (data_size < 0) + { + MHD_gnutls_assert (); + return data_size; + } + if (data_size == 0) + return 0; + + } + ret = + MHD_gtls_send_handshake (session, data, + data_size, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY); + MHD_gnutls_free (data); + + return ret; +} + + +int +MHD_gtls_recv_server_kx_message (MHD_gtls_session_t session) +{ + uint8_t *data = NULL; + int datasize; + int ret = 0; + + if (session->internals.auth_struct->MHD_gtls_process_server_kx != NULL) + { + + /* EXCEPTION FOR RSA_EXPORT cipher suite + */ + if (MHD_gtls_session_is_export (session) != 0 && + MHD__gnutls_peers_cert_less_512 (session) != 0) + { + MHD_gnutls_assert (); + return 0; + } + + ret = + MHD_gtls_recv_handshake (session, &data, + &datasize, + GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE, + MANDATORY_PACKET); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = + session->internals.auth_struct->MHD_gtls_process_server_kx (session, + data, + datasize); + MHD_gnutls_free (data); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + } + return ret; +} + +int +MHD_gtls_recv_server_certificate_request (MHD_gtls_session_t session) +{ + uint8_t *data; + int datasize; + int ret = 0; + + if (session->internals.auth_struct-> + MHD_gtls_process_server_certificate_request != NULL) + { + + ret = + MHD_gtls_recv_handshake (session, &data, + &datasize, + GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST, + OPTIONAL_PACKET); + if (ret < 0) + return ret; + + if (ret == 0 && datasize == 0) + return 0; /* ignored */ + + ret = + session->internals.auth_struct-> + MHD_gtls_process_server_certificate_request (session, data, datasize); + MHD_gnutls_free (data); + if (ret < 0) + return ret; + + } + return ret; +} + +int +MHD_gtls_recv_client_kx_message (MHD_gtls_session_t session) +{ + uint8_t *data; + int datasize; + int ret = 0; + + + /* Do key exchange only if the algorithm permits it */ + if (session->internals.auth_struct->MHD_gtls_process_client_kx != NULL) + { + + ret = + MHD_gtls_recv_handshake (session, &data, + &datasize, + GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE, + MANDATORY_PACKET); + if (ret < 0) + return ret; + + ret = + session->internals.auth_struct->MHD_gtls_process_client_kx (session, + data, + datasize); + MHD_gnutls_free (data); + if (ret < 0) + return ret; + + } + + return ret; +} + + +/* This is called when we want send our certificate + */ +int +MHD_gtls_send_client_certificate (MHD_gtls_session_t session, int again) +{ + uint8_t *data = NULL; + int data_size = 0; + int ret = 0; + + + if (session->key->certificate_requested == 0) + return 0; + + if (session->internals.auth_struct->MHD_gtls_gen_client_certificate == NULL) + return 0; + + data = NULL; + data_size = 0; + + if (again == 0) + { + if (MHD__gnutls_protocol_get_version (session) != + MHD_GNUTLS_PROTOCOL_SSL3 + || session->internals.selected_cert_list_length > 0) + { + /* TLS 1.0 or SSL 3.0 with a valid certificate + */ + data_size = + session->internals.auth_struct-> + MHD_gtls_gen_client_certificate (session, &data); + + if (data_size < 0) + { + MHD_gnutls_assert (); + return data_size; + } + } + } + + /* In the SSL 3.0 protocol we need to send a + * no certificate alert instead of an + * empty certificate. + */ + if (MHD__gnutls_protocol_get_version (session) == MHD_GNUTLS_PROTOCOL_SSL3 + && session->internals.selected_cert_list_length == 0) + { + ret = + MHD__gnutls_alert_send (session, GNUTLS_AL_WARNING, + GNUTLS_A_SSL3_NO_CERTIFICATE); + + } + else + { /* TLS 1.0 or SSL 3.0 with a valid certificate + */ + ret = + MHD_gtls_send_handshake (session, data, data_size, + GNUTLS_HANDSHAKE_CERTIFICATE_PKT); + MHD_gnutls_free (data); + } + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return data_size; +} + + +/* This is called when we want send our certificate + */ +int +MHD_gtls_send_server_certificate (MHD_gtls_session_t session, int again) +{ + uint8_t *data = NULL; + int data_size = 0; + int ret = 0; + + + if (session->internals.auth_struct->MHD_gtls_gen_server_certificate == NULL) + return 0; + + data = NULL; + data_size = 0; + + if (again == 0) + { + data_size = + session->internals.auth_struct-> + MHD_gtls_gen_server_certificate (session, &data); + + if (data_size < 0) + { + MHD_gnutls_assert (); + return data_size; + } + } + ret = + MHD_gtls_send_handshake (session, data, data_size, + GNUTLS_HANDSHAKE_CERTIFICATE_PKT); + MHD_gnutls_free (data); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return data_size; +} + + +int +MHD_gtls_recv_client_certificate (MHD_gtls_session_t session) +{ + int datasize; + opaque *data; + int ret = 0; + int optional; + + if (session->internals.auth_struct->MHD_gtls_process_client_certificate != + NULL) + { + + /* if we have not requested a certificate then just return + */ + if (session->internals.send_cert_req == 0) + { + return 0; + } + + if (session->internals.send_cert_req == GNUTLS_CERT_REQUIRE) + optional = MANDATORY_PACKET; + else + optional = OPTIONAL_PACKET; + + ret = + MHD_gtls_recv_handshake (session, &data, + &datasize, + GNUTLS_HANDSHAKE_CERTIFICATE_PKT, optional); + + if (ret < 0) + { + /* Handle the case of old SSL3 clients who send + * a warning alert instead of an empty certificate to indicate + * no certificate. + */ + if (optional == OPTIONAL_PACKET && + ret == GNUTLS_E_WARNING_ALERT_RECEIVED && + MHD__gnutls_protocol_get_version (session) == + MHD_GNUTLS_PROTOCOL_SSL3 + && MHD_gnutls_alert_get (session) == + GNUTLS_A_SSL3_NO_CERTIFICATE) + { + + /* SSL3 does not send an empty certificate, + * but this alert. So we just ignore it. + */ + MHD_gnutls_assert (); + return 0; + } + + /* certificate was required + */ + if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED + || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) + && optional == MANDATORY_PACKET) + { + MHD_gnutls_assert (); + return GNUTLS_E_NO_CERTIFICATE_FOUND; + } + + return ret; + } + + if (ret == 0 && datasize == 0 && optional == OPTIONAL_PACKET) + { + /* Client has not sent the certificate message. + * well I'm not sure we should accept this + * behaviour. + */ + MHD_gnutls_assert (); + return 0; + } + ret = + session->internals.auth_struct-> + MHD_gtls_process_client_certificate (session, data, datasize); + + MHD_gnutls_free (data); + if (ret < 0 && ret != GNUTLS_E_NO_CERTIFICATE_FOUND) + { + MHD_gnutls_assert (); + return ret; + } + + /* ok we should expect a certificate verify message now + */ + if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND && optional == OPTIONAL_PACKET) + ret = 0; + else + session->key->certificate_requested = 1; + + } + + return ret; +} + +int +MHD_gtls_recv_server_certificate (MHD_gtls_session_t session) +{ + int datasize; + opaque *data; + int ret = 0; + + if (session->internals.auth_struct->MHD_gtls_process_server_certificate != + NULL) + { + + ret = + MHD_gtls_recv_handshake (session, &data, + &datasize, + GNUTLS_HANDSHAKE_CERTIFICATE_PKT, + MANDATORY_PACKET); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = + session->internals.auth_struct-> + MHD_gtls_process_server_certificate (session, data, datasize); + MHD_gnutls_free (data); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + + return ret; +} + + +/* Recv the client certificate verify. This packet may not + * arrive if the peer did not send us a certificate. + */ +int +MHD_gtls_recv_client_certificate_verify_message (MHD_gtls_session_t session) +{ + uint8_t *data; + int datasize; + int ret = 0; + + + if (session->internals.auth_struct->MHD_gtls_process_client_cert_vrfy != + NULL) + { + + if (session->internals.send_cert_req == 0 || + session->key->certificate_requested == 0) + { + return 0; + } + + ret = + MHD_gtls_recv_handshake (session, &data, + &datasize, + GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY, + OPTIONAL_PACKET); + if (ret < 0) + return ret; + + if (ret == 0 && datasize == 0 + && session->internals.send_cert_req == GNUTLS_CERT_REQUIRE) + { + /* certificate was required */ + MHD_gnutls_assert (); + return GNUTLS_E_NO_CERTIFICATE_FOUND; + } + + ret = + session->internals.auth_struct-> + MHD_gtls_process_client_cert_vrfy (session, data, datasize); + MHD_gnutls_free (data); + if (ret < 0) + return ret; + + } + + return ret; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_kx.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_kx.h new file mode 100644 index 0000000000..92144615f5 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_kx.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +int MHD_gtls_send_server_kx_message (MHD_gtls_session_t session, int again); +int MHD_gtls_send_client_kx_message (MHD_gtls_session_t session, int again); +int MHD_gtls_recv_server_kx_message (MHD_gtls_session_t session); +int MHD_gtls_recv_client_kx_message (MHD_gtls_session_t session); +int MHD_gtls_send_client_certificate_verify (MHD_gtls_session_t session, + int again); +int MHD_gtls_send_server_certificate (MHD_gtls_session_t session, int again); +int MHD_gtls_generate_master (MHD_gtls_session_t session, int keep_premaster); +int MHD_gtls_recv_client_certificate (MHD_gtls_session_t session); +int MHD_gtls_recv_server_certificate (MHD_gtls_session_t session); +int MHD_gtls_send_client_certificate (MHD_gtls_session_t session, int again); +int MHD_gtls_recv_server_certificate_request (MHD_gtls_session_t session); +int MHD_gtls_send_server_certificate_request (MHD_gtls_session_t session, + int again); +int MHD_gtls_recv_client_certificate_verify_message (MHD_gtls_session_t + session); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mem.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mem.c new file mode 100644 index 0000000000..44f1ccf5fc --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mem.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_num.h> + +MHD_gnutls_alloc_function MHD_gnutls_secure_malloc = malloc; +MHD_gnutls_alloc_function MHD_gnutls_malloc = malloc; +MHD_gnutls_free_function MHD_gnutls_free = free; +MHD_gnutls_realloc_function MHD_gnutls_realloc = realloc; + +void *(*MHD_gnutls_calloc) (size_t, size_t) = calloc; + +int +MHD__gnutls_is_secure_mem_null (const void *ign) +{ + return 0; +} + +int (*MHD__gnutls_is_secure_memory) (const void *) = + MHD__gnutls_is_secure_mem_null; + + + +/* This realloc will free ptr in case realloc + * fails. + */ +void * +MHD_gtls_realloc_fast (void *ptr, size_t size) +{ + void *ret; + + if (size == 0) + return ptr; + + ret = MHD_gnutls_realloc (ptr, size); + if (ret == NULL) + { + MHD_gnutls_free (ptr); + } + + return ret; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mem.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mem.h new file mode 100644 index 0000000000..0ea84a1089 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mem.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_MEM_H +# define GNUTLS_MEM_H + +#ifdef USE_DMALLOC +# include <dmalloc.h> +#endif + +typedef void svoid; /* for functions that allocate using MHD_gnutls_secure_malloc */ + +#ifdef HAVE_ALLOCA +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# endif +# ifndef MHD_gnutls_alloca +# define MHD_gnutls_alloca alloca +# define MHD_gnutls_afree(x) +# endif +#else +# ifndef MHD_gnutls_alloca +# define MHD_gnutls_alloca MHD_gnutls_malloc +# define MHD_gnutls_afree MHD_gnutls_free +# endif +#endif /* HAVE_ALLOCA */ + +extern int (*MHD__gnutls_is_secure_memory) (const void *); + +/* this realloc function will return ptr if size==0, and + * will free the ptr if the new allocation failed. + */ +void *MHD_gtls_realloc_fast (void *ptr, size_t size); + +svoid *MHD_gtls_secure_calloc (size_t nmemb, size_t size); + +void *MHD_gtls_calloc (size_t nmemb, size_t size); +char *MHD_gtls_strdup (const char *); + +#endif /* GNUTLS_MEM_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mpi.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mpi.c new file mode 100644 index 0000000000..5a4e25a4c4 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mpi.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Here lie everything that has to do with large numbers, libgcrypt and + * other stuff that didn't fit anywhere else. + */ + +#include <gnutls_int.h> +#include <libtasn1.h> +#include <gnutls_errors.h> +#include <gnutls_num.h> + +/* Functions that refer to the libgcrypt library. + */ + +void +MHD_gtls_mpi_release (mpi_t * x) +{ + if (*x == NULL) + return; + gcry_mpi_release (*x); + *x = NULL; +} + +/* returns zero on success + */ +int +MHD_gtls_mpi_scan (mpi_t * ret_mpi, const opaque * buffer, size_t * nbytes) +{ + int ret; + + ret = gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, buffer, *nbytes, nbytes); + if (ret) + return GNUTLS_E_MPI_SCAN_FAILED; + + return 0; +} + +/* returns zero on success. Fails if the number is zero. + */ +int +MHD_gtls_mpi_scan_nz (mpi_t * ret_mpi, const opaque * buffer, size_t * nbytes) +{ + int ret; + + ret = gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, buffer, *nbytes, nbytes); + if (ret) + return GNUTLS_E_MPI_SCAN_FAILED; + + /* MPIs with 0 bits are illegal + */ + if (MHD__gnutls_mpi_get_nbits (*ret_mpi) == 0) + { + MHD_gtls_mpi_release (ret_mpi); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + return 0; +} + +int +MHD_gtls_mpi_print (void *buffer, size_t * nbytes, const mpi_t a) +{ + int ret; + + if (nbytes == NULL || a == NULL) + return GNUTLS_E_INVALID_REQUEST; + + ret = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, *nbytes, nbytes, a); + if (!ret) + return 0; + + return GNUTLS_E_MPI_PRINT_FAILED; +} + +/* Always has the first bit zero */ +static int +MHD_gtls_mpi_print_lz (void *buffer, size_t * nbytes, const mpi_t a) +{ + int ret; + + if (nbytes == NULL || a == NULL) + return GNUTLS_E_INVALID_REQUEST; + + ret = gcry_mpi_print (GCRYMPI_FMT_STD, buffer, *nbytes, nbytes, a); + if (!ret) + return 0; + + return GNUTLS_E_MPI_PRINT_FAILED; +} + +/* Always has the first bit zero */ +int +MHD_gtls_mpi_dprint_lz (MHD_gnutls_datum_t * dest, const mpi_t a) +{ + int ret; + opaque *buf = NULL; + size_t bytes = 0; + + if (dest == NULL || a == NULL) + return GNUTLS_E_INVALID_REQUEST; + + gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &bytes, a); + + if (bytes != 0) + buf = MHD_gnutls_malloc (bytes); + if (buf == NULL) + return GNUTLS_E_MEMORY_ERROR; + + ret = gcry_mpi_print (GCRYMPI_FMT_STD, buf, bytes, &bytes, a); + if (!ret) + { + dest->data = buf; + dest->size = bytes; + return 0; + } + + MHD_gnutls_free (buf); + return GNUTLS_E_MPI_PRINT_FAILED; +} + +int +MHD_gtls_mpi_dprint (MHD_gnutls_datum_t * dest, const mpi_t a) +{ + int ret; + opaque *buf = NULL; + size_t bytes = 0; + + if (dest == NULL || a == NULL) + return GNUTLS_E_INVALID_REQUEST; + + gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &bytes, a); + + if (bytes != 0) + buf = MHD_gnutls_malloc (bytes); + if (buf == NULL) + return GNUTLS_E_MEMORY_ERROR; + + ret = gcry_mpi_print (GCRYMPI_FMT_USG, buf, bytes, &bytes, a); + if (!ret) + { + dest->data = buf; + dest->size = bytes; + return 0; + } + + MHD_gnutls_free (buf); + return GNUTLS_E_MPI_PRINT_FAILED; +} + + +/* this function reads an integer + * from asn1 structs. Combines the read and mpi_scan + * steps. + */ +int +MHD__gnutls_x509_read_int (ASN1_TYPE node, const char *value, mpi_t * ret_mpi) +{ + int result; + size_t s_len; + opaque *tmpstr = NULL; + int tmpstr_size; + + tmpstr_size = 0; + result = MHD__asn1_read_value (node, value, NULL, &tmpstr_size); + if (result != ASN1_MEM_ERROR) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + tmpstr = MHD_gnutls_alloca (tmpstr_size); + if (tmpstr == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + result = MHD__asn1_read_value (node, value, tmpstr, &tmpstr_size); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (tmpstr); + return MHD_gtls_asn2err (result); + } + + s_len = tmpstr_size; + if (MHD_gtls_mpi_scan (ret_mpi, tmpstr, &s_len) != 0) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (tmpstr); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + MHD_gnutls_afree (tmpstr); + + return 0; +} + +/* Writes the specified integer into the specified node. + */ +int +MHD__gnutls_x509_write_int (ASN1_TYPE node, const char *value, mpi_t mpi, + int lz) +{ + opaque *tmpstr; + size_t s_len; + int result; + + s_len = 0; + if (lz) + result = MHD_gtls_mpi_print_lz (NULL, &s_len, mpi); + else + result = MHD_gtls_mpi_print (NULL, &s_len, mpi); + + tmpstr = MHD_gnutls_alloca (s_len); + if (tmpstr == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + if (lz) + result = MHD_gtls_mpi_print_lz (tmpstr, &s_len, mpi); + else + result = MHD_gtls_mpi_print (tmpstr, &s_len, mpi); + + if (result != 0) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (tmpstr); + return GNUTLS_E_MPI_PRINT_FAILED; + } + + result = MHD__asn1_write_value (node, value, tmpstr, s_len); + + MHD_gnutls_afree (tmpstr); + + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mpi.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mpi.h new file mode 100644 index 0000000000..77b7c9e4ac --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_mpi.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_MPI_H +#define GNUTLS_MPI_H + +# include <gnutls_int.h> +# include <gcrypt.h> +# include "gc.h" + +typedef gcry_mpi_t mpi_t; + +#define MHD__gnutls_mpi_cmp gcry_mpi_cmp +#define MHD__gnutls_mpi_cmp_ui gcry_mpi_cmp_ui +#define MHD__gnutls_mpi_new gcry_mpi_new +#define MHD__gnutls_mpi_snew gcry_mpi_snew +#define MHD__gnutls_mpi_copy gcry_mpi_copy +#define MHD__gnutls_mpi_randomize gcry_mpi_randomize +#define MHD__gnutls_mpi_get_nbits gcry_mpi_get_nbits +#define MHD__gnutls_mpi_powm gcry_mpi_powm +#define MHD__gnutls_mpi_invm gcry_mpi_invm +#define MHD__gnutls_mpi_alloc_like(x) MHD__gnutls_mpi_new(MHD__gnutls_mpi_get_nbits(x)) + +void MHD_gtls_mpi_release (mpi_t * x); + +int MHD_gtls_mpi_scan_nz (mpi_t * ret_mpi, const opaque * buffer, + size_t * nbytes); +int MHD_gtls_mpi_scan (mpi_t * ret_mpi, const opaque * buffer, + size_t * nbytes); +int MHD_gtls_mpi_print (void *buffer, size_t * nbytes, const mpi_t a); +int MHD_gtls_mpi_dprint_lz (MHD_gnutls_datum_t * dest, const mpi_t a); +int MHD_gtls_mpi_dprint (MHD_gnutls_datum_t * dest, const mpi_t a); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_num.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_num.c new file mode 100644 index 0000000000..06d2e4eb20 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_num.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the functions needed for 64 bit integer support in + * TLS, and functions which ease the access to TLS vectors (data of given size). + */ + +#include <gnutls_int.h> +#include <gnutls_num.h> +#include <gnutls_errors.h> + +/* This function will add one to uint64 x. + * Returns 0 on success, or -1 if the uint64 max limit + * has been reached. + */ +int +MHD_gtls_uint64pp (uint64 * x) +{ + register int i, y = 0; + + for (i = 7; i >= 0; i--) + { + y = 0; + if (x->i[i] == 0xff) + { + x->i[i] = 0; + y = 1; + } + else + x->i[i]++; + + if (y == 0) + break; + } + if (y != 0) + return -1; /* over 64 bits! WOW */ + + return 0; +} + +uint32_t +MHD_gtls_uint24touint32 (uint24 num) +{ + uint32_t ret = 0; + + ((uint8_t *) & ret)[1] = num.pint[0]; + ((uint8_t *) & ret)[2] = num.pint[1]; + ((uint8_t *) & ret)[3] = num.pint[2]; + return ret; +} + +uint24 +MHD_gtls_uint32touint24 (uint32_t num) +{ + uint24 ret; + + ret.pint[0] = ((uint8_t *) & num)[1]; + ret.pint[1] = ((uint8_t *) & num)[2]; + ret.pint[2] = ((uint8_t *) & num)[3]; + return ret; + +} + +/* data should be at least 3 bytes */ +uint32_t +MHD_gtls_read_uint24 (const opaque * data) +{ + uint32_t res; + uint24 num; + + num.pint[0] = data[0]; + num.pint[1] = data[1]; + num.pint[2] = data[2]; + + res = MHD_gtls_uint24touint32 (num); +#ifndef WORDS_BIGENDIAN + res = byteswap32 (res); +#endif + return res; +} + +void +MHD_gtls_write_uint24 (uint32_t num, opaque * data) +{ + uint24 tmp; + +#ifndef WORDS_BIGENDIAN + num = byteswap32 (num); +#endif + tmp = MHD_gtls_uint32touint24 (num); + + data[0] = tmp.pint[0]; + data[1] = tmp.pint[1]; + data[2] = tmp.pint[2]; +} + +uint32_t +MHD_gtls_read_uint32 (const opaque * data) +{ + uint32_t res; + + memcpy (&res, data, sizeof (uint32_t)); +#ifndef WORDS_BIGENDIAN + res = byteswap32 (res); +#endif + return res; +} + +void +MHD_gtls_write_uint32 (uint32_t num, opaque * data) +{ + +#ifndef WORDS_BIGENDIAN + num = byteswap32 (num); +#endif + memcpy (data, &num, sizeof (uint32_t)); +} + +uint16_t +MHD_gtls_read_uint16 (const opaque * data) +{ + uint16_t res; + memcpy (&res, data, sizeof (uint16_t)); +#ifndef WORDS_BIGENDIAN + res = byteswap16 (res); +#endif + return res; +} + +void +MHD_gtls_write_uint16 (uint16_t num, opaque * data) +{ + +#ifndef WORDS_BIGENDIAN + num = byteswap16 (num); +#endif + memcpy (data, &num, sizeof (uint16_t)); +} + +uint32_t +MHD_gtls_conv_uint32 (uint32_t data) +{ +#ifndef WORDS_BIGENDIAN + return byteswap32 (data); +#else + return data; +#endif +} + +uint16_t +MHD_gtls_conv_uint16 (uint16_t data) +{ +#ifndef WORDS_BIGENDIAN + return byteswap16 (data); +#else + return data; +#endif +} + +uint32_t +MHD_gtls_uint64touint32 (const uint64 * num) +{ + uint32_t ret; + + memcpy (&ret, &num->i[4], 4); +#ifndef WORDS_BIGENDIAN + ret = byteswap32 (ret); +#endif + + return ret; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_num.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_num.h new file mode 100644 index 0000000000..3a0f1f88d5 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_num.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> + +#define rotl32(x,n) (((x) << ((uint16_t)(n))) | ((x) >> (32 - (uint16_t)(n)))) +#define rotr32(x,n) (((x) >> ((uint16_t)(n))) | ((x) << (32 - (uint16_t)(n)))) +#define rotl16(x,n) (((x) << ((uint16_t)(n))) | ((x) >> (16 - (uint16_t)(n)))) +#define rotr16(x,n) (((x) >> ((uint16_t)(n))) | ((x) << (16 - (uint16_t)(n)))) + +#define byteswap16(x) ((rotl16(x, 8) & 0x00ff) | (rotr16(x, 8) & 0xff00)) +#define byteswap32(x) ((rotl32(x, 8) & 0x00ff00ffUL) | (rotr32(x, 8) & 0xff00ff00UL)) + +uint32_t MHD_gtls_uint24touint32 (uint24 num); +uint24 MHD_gtls_uint32touint24 (uint32_t num); +uint32_t MHD_gtls_read_uint32 (const opaque * data); +uint16_t MHD_gtls_read_uint16 (const opaque * data); +uint32_t MHD_gtls_conv_uint32 (uint32_t data); +uint16_t MHD_gtls_conv_uint16 (uint16_t data); +uint32_t MHD_gtls_read_uint24 (const opaque * data); +void MHD_gtls_write_uint24 (uint32_t num, opaque * data); +void MHD_gtls_write_uint32 (uint32_t num, opaque * data); +void MHD_gtls_write_uint16 (uint16_t num, opaque * data); +uint32_t MHD_gtls_uint64touint32 (const uint64 *); + +int MHD_gtls_uint64pp (uint64 *); +#define MHD__gnutls_uint64zero(x) x.i[0] = x.i[1] = x.i[2] = x.i[3] = x.i[4] = x.i[5] = x.i[6] = x.i[7] = 0 +#define UINT64DATA(x) x.i diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_pk.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_pk.c new file mode 100644 index 0000000000..f8514cae8a --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_pk.c @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the functions needed for RSA/DSA public key + * encryption and signatures. + */ + +#include <gnutls_int.h> +#include <gnutls_mpi.h> +#include <gnutls_pk.h> +#include <gnutls_errors.h> +#include <gnutls_datum.h> +#include <gnutls_global.h> +#include <gnutls_num.h> +#include "debug.h" +#include <gc.h> + +/* x509 */ +#include "common.h" +#include "mpi.h" + +static int MHD__gnutls_pk_encrypt (int algo, mpi_t * resarr, mpi_t data, + mpi_t * pkey, int pkey_len); +static int MHD__gnutls_pk_sign (int algo, mpi_t * data, mpi_t hash, + mpi_t * pkey, int); +static int MHD__gnutls_pk_decrypt (int algo, mpi_t * resarr, mpi_t data, + mpi_t * pkey, int); + + +/* Do PKCS-1 RSA encryption. + * params is modulus, public exp. + */ +int +MHD_gtls_pkcs1_rsa_encrypt (MHD_gnutls_datum_t * ciphertext, + const MHD_gnutls_datum_t * plaintext, + mpi_t * params, unsigned params_len, + unsigned btype) +{ + unsigned int i, pad; + int ret; + mpi_t m, res; + opaque *edata, *ps; + size_t k, psize; + size_t mod_bits; + + mod_bits = MHD__gnutls_mpi_get_nbits (params[0]); + k = mod_bits / 8; + if (mod_bits % 8 != 0) + k++; + + if (plaintext->size > k - 11) + { + MHD_gnutls_assert (); + return GNUTLS_E_PK_ENCRYPTION_FAILED; + } + + edata = MHD_gnutls_alloca (k); + if (edata == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + /* EB = 00||BT||PS||00||D + * (use block type 'btype') + */ + + edata[0] = 0; + edata[1] = btype; + psize = k - 3 - plaintext->size; + + ps = &edata[2]; + switch (btype) + { + case 2: + /* using public key */ + if (params_len < RSA_PUBLIC_PARAMS) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (MHD_gc_pseudo_random ((char *) ps, psize) != GC_OK) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_RANDOM_FAILED; + } + for (i = 0; i < psize; i++) + while (ps[i] == 0) + { + if (MHD_gc_pseudo_random ((char *) &ps[i], 1) != GC_OK) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_RANDOM_FAILED; + } + } + break; + case 1: + /* using private key */ + + if (params_len < RSA_PRIVATE_PARAMS) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_INTERNAL_ERROR; + } + + for (i = 0; i < psize; i++) + ps[i] = 0xff; + break; + default: + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_INTERNAL_ERROR; + } + + ps[psize] = 0; + memcpy (&ps[psize + 1], plaintext->data, plaintext->size); + + if (MHD_gtls_mpi_scan_nz (&m, edata, &k) != 0) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_MPI_SCAN_FAILED; + } + MHD_gnutls_afree (edata); + + if (btype == 2) /* encrypt */ + ret = MHD__gnutls_pk_encrypt (GCRY_PK_RSA, &res, m, params, params_len); + else /* sign */ + ret = MHD__gnutls_pk_sign (GCRY_PK_RSA, &res, m, params, params_len); + + MHD_gtls_mpi_release (&m); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD_gtls_mpi_print (NULL, &psize, res); + + if (psize < k) + { + /* padding psize */ + pad = k - psize; + psize = k; + } + else if (psize == k) + { + pad = 0; + } + else + { /* psize > k !!! */ + /* This is an impossible situation */ + MHD_gnutls_assert (); + MHD_gtls_mpi_release (&res); + return GNUTLS_E_INTERNAL_ERROR; + } + + ciphertext->data = MHD_gnutls_malloc (psize); + if (ciphertext->data == NULL) + { + MHD_gnutls_assert (); + MHD_gtls_mpi_release (&res); + return GNUTLS_E_MEMORY_ERROR; + } + MHD_gtls_mpi_print (&ciphertext->data[pad], &psize, res); + for (i = 0; i < pad; i++) + ciphertext->data[i] = 0; + + ciphertext->size = k; + + MHD_gtls_mpi_release (&res); + + return 0; +} + + +/* Do PKCS-1 RSA decryption. + * params is modulus, public exp., private key + * Can decrypt block type 1 and type 2 packets. + */ +int +MHD_gtls_pkcs1_rsa_decrypt (MHD_gnutls_datum_t * plaintext, + const MHD_gnutls_datum_t * ciphertext, + mpi_t * params, unsigned params_len, + unsigned btype) +{ + unsigned k, i; + int ret; + mpi_t c, res; + opaque *edata; + size_t esize, mod_bits; + + mod_bits = MHD__gnutls_mpi_get_nbits (params[0]); + k = mod_bits / 8; + if (mod_bits % 8 != 0) + k++; + + esize = ciphertext->size; + + if (esize != k) + { + MHD_gnutls_assert (); + return GNUTLS_E_PK_DECRYPTION_FAILED; + } + + if (MHD_gtls_mpi_scan_nz (&c, ciphertext->data, &esize) != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + /* we can use btype to see if the private key is + * available. + */ + if (btype == 2) + ret = MHD__gnutls_pk_decrypt (GCRY_PK_RSA, &res, c, params, params_len); + else + { + ret = MHD__gnutls_pk_encrypt (GCRY_PK_RSA, &res, c, params, params_len); + } + MHD_gtls_mpi_release (&c); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD_gtls_mpi_print (NULL, &esize, res); + edata = MHD_gnutls_alloca (esize + 1); + if (edata == NULL) + { + MHD_gnutls_assert (); + MHD_gtls_mpi_release (&res); + return GNUTLS_E_MEMORY_ERROR; + } + MHD_gtls_mpi_print (&edata[1], &esize, res); + + MHD_gtls_mpi_release (&res); + + /* EB = 00||BT||PS||00||D + * (use block type 'btype') + * + * From now on, return GNUTLS_E_DECRYPTION_FAILED on errors, to + * avoid attacks similar to the one described by Bleichenbacher in: + * "Chosen Ciphertext Attacks against Protocols Based on RSA + * Encryption Standard PKCS #1". + */ + + + edata[0] = 0; + esize++; + + if (edata[0] != 0 || edata[1] != btype) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_DECRYPTION_FAILED; + } + + ret = GNUTLS_E_DECRYPTION_FAILED; + switch (btype) + { + case 2: + for (i = 2; i < esize; i++) + { + if (edata[i] == 0) + { + ret = 0; + break; + } + } + break; + case 1: + for (i = 2; i < esize; i++) + { + if (edata[i] == 0 && i > 2) + { + ret = 0; + break; + } + if (edata[i] != 0xff) + { + MHD__gnutls_handshake_log ("PKCS #1 padding error"); + /* PKCS #1 padding error. Don't use + GNUTLS_E_PKCS1_WRONG_PAD here. */ + break; + } + } + break; + default: + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_DECRYPTION_FAILED; + } + i++; + + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_DECRYPTION_FAILED; + } + + if (MHD__gnutls_sset_datum (plaintext, &edata[i], esize - i) < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_afree (edata); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD_gnutls_afree (edata); + + return 0; +} + + +int +MHD_gtls_rsa_verify (const MHD_gnutls_datum_t * vdata, + const MHD_gnutls_datum_t * ciphertext, mpi_t * params, + int params_len, int btype) +{ + + MHD_gnutls_datum_t plain; + int ret; + + /* decrypt signature */ + if ((ret = + MHD_gtls_pkcs1_rsa_decrypt (&plain, ciphertext, params, params_len, + btype)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if (plain.size != vdata->size) + { + MHD_gnutls_assert (); + MHD__gnutls_free_datum (&plain); + return GNUTLS_E_PK_SIG_VERIFY_FAILED; + } + + if (memcmp (plain.data, vdata->data, plain.size) != 0) + { + MHD_gnutls_assert (); + MHD__gnutls_free_datum (&plain); + return GNUTLS_E_PK_SIG_VERIFY_FAILED; + } + + MHD__gnutls_free_datum (&plain); + + return 0; /* ok */ +} + + +/* this is taken from gnupg + */ + +/**************** + * Emulate our old PK interface here - sometime in the future we might + * change the internal design to directly fit to libgcrypt. + */ +static int +MHD__gnutls_pk_encrypt (int algo, mpi_t * resarr, mpi_t data, + mpi_t * pkey, int pkey_len) +{ + gcry_sexp_t s_ciph, s_data, s_pkey; + int rc = -1; + + /* make a sexp from pkey */ + switch (algo) + { + case GCRY_PK_RSA: + if (pkey_len >= 2) + rc = gcry_sexp_build (&s_pkey, NULL, + "(public-key(rsa(n%m)(e%m)))", + pkey[0], pkey[1]); + break; + + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (rc != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* put the data into a simple list */ + if (gcry_sexp_build (&s_data, NULL, "%m", data)) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_pkey); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* pass it to libgcrypt */ + rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey); + gcry_sexp_release (s_data); + gcry_sexp_release (s_pkey); + + if (rc != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_PK_ENCRYPTION_FAILED; + + } + else + { /* add better error handling or make gnupg use S-Exp directly */ + gcry_sexp_t list = gcry_sexp_find_token (s_ciph, "a", 0); + if (list == NULL) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_ciph); + return GNUTLS_E_INTERNAL_ERROR; + } + + resarr[0] = gcry_sexp_nth_mpi (list, 1, 0); + gcry_sexp_release (list); + + if (resarr[0] == NULL) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_ciph); + return GNUTLS_E_INTERNAL_ERROR; + } + } + + gcry_sexp_release (s_ciph); + return rc; +} + +static int +MHD__gnutls_pk_decrypt (int algo, mpi_t * resarr, mpi_t data, mpi_t * pkey, + int pkey_len) +{ + gcry_sexp_t s_plain, s_data, s_pkey; + int rc = -1; + + /* make a sexp from pkey */ + switch (algo) + { + case GCRY_PK_RSA: + if (pkey_len >= 6) + rc = gcry_sexp_build (&s_pkey, NULL, + "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", + pkey[0], pkey[1], pkey[2], pkey[3], + pkey[4], pkey[5]); + break; + + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (rc != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* put the data into a simple list */ + if (gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data)) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_pkey); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* pass it to libgcrypt */ + rc = gcry_pk_decrypt (&s_plain, s_data, s_pkey); + gcry_sexp_release (s_data); + gcry_sexp_release (s_pkey); + + if (rc != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_PK_DECRYPTION_FAILED; + + } + else + { /* add better error handling or make gnupg use S-Exp directly */ + resarr[0] = gcry_sexp_nth_mpi (s_plain, 0, 0); + + if (resarr[0] == NULL) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_plain); + return GNUTLS_E_INTERNAL_ERROR; + } + } + + gcry_sexp_release (s_plain); + return rc; +} + + +/* in case of DSA puts into data, r,s + */ +static int +MHD__gnutls_pk_sign (int algo, mpi_t * data, mpi_t hash, mpi_t * pkey, + int pkey_len) +{ + gcry_sexp_t s_hash, s_key, s_sig; + int rc = -1; + + /* make a sexp from pkey */ + switch (algo) + { + case GCRY_PK_DSA: + if (pkey_len >= 5) + rc = gcry_sexp_build (&s_key, NULL, + "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", + pkey[0], pkey[1], pkey[2], pkey[3], pkey[4]); + else + { + MHD_gnutls_assert (); + } + + break; + case GCRY_PK_RSA: + if (pkey_len >= 6) + rc = gcry_sexp_build (&s_key, NULL, + "(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", + pkey[0], pkey[1], pkey[2], pkey[3], + pkey[4], pkey[5]); + else + { + MHD_gnutls_assert (); + } + break; + + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (rc != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* put the data into a simple list */ + if (gcry_sexp_build (&s_hash, NULL, "%m", hash)) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* pass it to libgcrypt */ + rc = gcry_pk_sign (&s_sig, s_hash, s_key); + gcry_sexp_release (s_hash); + gcry_sexp_release (s_key); + + if (rc != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_PK_SIGN_FAILED; + + } + else + { + gcry_sexp_t list; + + if (algo == GCRY_PK_DSA) + { + list = gcry_sexp_find_token (s_sig, "r", 0); + if (list == NULL) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_sig); + return GNUTLS_E_INTERNAL_ERROR; + } + + data[0] = gcry_sexp_nth_mpi (list, 1, 0); + gcry_sexp_release (list); + + list = gcry_sexp_find_token (s_sig, "s", 0); + if (list == NULL) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_sig); + return GNUTLS_E_INTERNAL_ERROR; + } + + data[1] = gcry_sexp_nth_mpi (list, 1, 0); + gcry_sexp_release (list); + } + else + { /* GCRY_PK_RSA */ + list = gcry_sexp_find_token (s_sig, "s", 0); + if (list == NULL) + { + MHD_gnutls_assert (); + gcry_sexp_release (s_sig); + return GNUTLS_E_INTERNAL_ERROR; + } + + data[0] = gcry_sexp_nth_mpi (list, 1, 0); + gcry_sexp_release (list); + } + } + + gcry_sexp_release (s_sig); + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_pk.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_pk.h new file mode 100644 index 0000000000..4653e76e1c --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_pk.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_PK_H +#define GNUTLS_PK_H + +int MHD_gtls_pkcs1_rsa_encrypt (MHD_gnutls_datum_t * ciphertext, + const MHD_gnutls_datum_t * plaintext, + mpi_t * params, unsigned params_len, + unsigned btype); +int MHD_gtls_pkcs1_rsa_decrypt (MHD_gnutls_datum_t * plaintext, + const MHD_gnutls_datum_t * ciphertext, + mpi_t * params, unsigned params_len, + unsigned btype); +int MHD_gtls_rsa_verify (const MHD_gnutls_datum_t * vdata, + const MHD_gnutls_datum_t * ciphertext, + mpi_t * params, int params_len, int btype); + +#endif /* GNUTLS_PK_H */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_priority.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_priority.c new file mode 100644 index 0000000000..035c53dc4c --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_priority.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Here lies the code of the MHD_gnutls_*_set_priority() functions. + */ + +#include "gnutls_int.h" +#include "gnutls_algorithms.h" +#include "gnutls_errors.h" +#include <gnutls_num.h> + +#define MAX_ELEMENTS 48 + +static int +_set_priority (MHD_gtls_priority_st * st, const int *list) +{ + int num = 0; + + while ((list[num] != 0) && (num < MAX_ALGOS)) + num++; + st->num_algorithms = num; + memcpy (st->priority, list, num * sizeof (int)); + return 0; +} + +static const int MHD_gtls_protocol_priority[] = { MHD_GNUTLS_PROTOCOL_TLS1_1, + MHD_GNUTLS_PROTOCOL_TLS1_0, + MHD_GNUTLS_PROTOCOL_SSL3, + 0 +}; + +static const int MHD_gtls_cipher_priority_secure256[] = + { MHD_GNUTLS_CIPHER_AES_256_CBC, + 0 +}; + +static const int MHD_gtls_kx_priority_secure[] = { MHD_GNUTLS_KX_RSA, + 0 +}; + +static const int MHD_gtls_mac_priority_secure[] = { MHD_GNUTLS_MAC_SHA1, + 0 +}; + +static int MHD_gtls_cert_type_priority[] = { MHD_GNUTLS_CRT_X509, + 0 +}; + +static const int MHD_gtls_comp_priority[] = { MHD_GNUTLS_COMP_NULL, + 0 +}; + +/** + * MHD__gnutls_priority_set - Sets priorities for the cipher suites supported by gnutls. + * @session: is a #MHD_gtls_session_t structure. + * @priority: is a #MHD_gnutls_priority_t structure. + * + * Sets the priorities to use on the ciphers, key exchange methods, + * macs and compression methods. + * + * On success 0 is returned. + * + **/ +int +MHD__gnutls_priority_set (MHD_gtls_session_t session, + MHD_gnutls_priority_t priority) +{ + if (priority == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_NO_CIPHER_SUITES; + } + + memcpy (&session->internals.priorities, priority, + sizeof (struct MHD_gtls_priority_st)); + + return 0; +} + +/** + * MHD_tls_set_default_priority - Sets priorities for the cipher suites supported by gnutls. + * @priority_cache: is a #MHD_gnutls_prioritity_t structure. + * @priorities: is a string describing priorities + * @err_pos: In case of an error this will have the position in the string the error occured + * + * Sets priorities for the ciphers, key exchange methods, macs and + * compression methods. This is to avoid using the + * MHD_gnutls_*_priority() functions. + * + * The #priorities option allows you to specify a semi-colon + * separated list of the cipher priorities to enable. + * + * Unless the first keyword is "NONE" the defaults are: + * Protocols: TLS1.1, TLS1.0, and SSL3.0. + * Compression: NULL. + * Certificate types: X.509, OpenPGP. + * + * You can also use predefined sets of ciphersuites: "PERFORMANCE" + * all the "secure" ciphersuites are enabled, limited to 128 bit + * ciphers and sorted by terms of speed performance. + * + * "NORMAL" option enables all "secure" ciphersuites. The 256-bit ciphers + * are included as a fallback only. The ciphers are sorted by security margin. + * + * "SECURE128" flag enables all "secure" ciphersuites with ciphers up to + * 128 bits, sorted by security margin. + * + * "SECURE256" flag enables all "secure" ciphersuites including the 256 bit + * ciphers, sorted by security margin. + * + * "EXPORT" all the ciphersuites are enabled, including the + * low-security 40 bit ciphers. + * + * "NONE" nothing is enabled. This disables even protocols and + * compression methods. + * + * Special keywords: + * '!' or '-' appended with an algorithm will remove this algorithm. + * '+' appended with an algorithm will add this algorithm. + * '%COMPAT' will enable compatibility features for a server. + * + * To avoid collisions in order to specify a compression algorithm in + * this string you have to prefix it with "COMP-", protocol versions + * with "VERS-" and certificate types with "CTYPE-". All other + * algorithms don't need a prefix. + * + * For key exchange algorithms when in NORMAL or SECURE levels the + * perfect forward secrecy algorithms take precendence of the other + * protocols. In all cases all the supported key exchange algorithms + * are enabled (except for the RSA-EXPORT which is only enabled in + * EXPORT level). + * + * Note that although one can select very long key sizes (such as 256 bits) + * for symmetric algorithms, to actually increase security the public key + * algorithms have to use longer key sizes as well. + * + * Examples: "NORMAL:!AES-128-CBC", + * "EXPORT:!VERS-TLS1.0:+COMP-DEFLATE:+CTYPE-OPENPGP", + * "NONE:+VERS-TLS1.0:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL", "NORMAL", + * "NORMAL:%COMPAT". + * + * Returns: On syntax error GNUTLS_E_INVALID_REQUEST is returned and + * 0 on success. + **/ +int +MHD_tls_set_default_priority (MHD_gnutls_priority_t * priority_cache, + const char *priorities, const char **err_pos) +{ + *priority_cache = + MHD_gnutls_calloc (1, sizeof (struct MHD_gtls_priority_st)); + if (*priority_cache == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + /* set mode to "SECURE256" */ + _set_priority (&(*priority_cache)->protocol, MHD_gtls_protocol_priority); + _set_priority (&(*priority_cache)->cipher, + MHD_gtls_cipher_priority_secure256); + _set_priority (&(*priority_cache)->kx, MHD_gtls_kx_priority_secure); + _set_priority (&(*priority_cache)->mac, MHD_gtls_mac_priority_secure); + _set_priority (&(*priority_cache)->cert_type, MHD_gtls_cert_type_priority); + _set_priority (&(*priority_cache)->compression, MHD_gtls_comp_priority); + + (*priority_cache)->no_padding = 0; + return 0; +} + +/** + * MHD__gnutls_priority_deinit - Deinitialize the priorities cache for the cipher suites supported by gnutls. + * @priority_cache: is a #MHD_gnutls_prioritity_t structure. + * + * Deinitializes the priority cache. + * + **/ +void +MHD__gnutls_priority_deinit (MHD_gnutls_priority_t priority_cache) +{ + MHD_gnutls_free (priority_cache); +} + +/** + * MHD__gnutls_priority_set_direct - Sets priorities for the cipher suites supported by gnutls. + * @session: is a #MHD_gtls_session_t structure. + * @priorities: is a string describing priorities + * @err_pos: In case of an error this will have the position in the string the error occured + * + * Sets the priorities to use on the ciphers, key exchange methods, + * macs and compression methods. This function avoids keeping a + * priority cache and is used to directly set string priorities to a + * TLS session. For documentation check the MHD_tls_set_default_priority(). + * + * On syntax error GNUTLS_E_INVALID_REQUEST is returned and 0 on success. + * + **/ +int +MHD__gnutls_priority_set_direct (MHD_gtls_session_t session, + const char *priorities, const char **err_pos) +{ + MHD_gnutls_priority_t prio; + int ret; + + ret = MHD_tls_set_default_priority (&prio, priorities, err_pos); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = MHD__gnutls_priority_set (session, prio); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD__gnutls_priority_deinit (prio); + + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_record.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_record.c new file mode 100644 index 0000000000..07a7b46c47 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_record.c @@ -0,0 +1,1087 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions that are record layer specific, are included in this file. + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "debug.h" +#include "gnutls_cipher.h" +#include "gnutls_buffers.h" +#include "gnutls_handshake.h" +#include "gnutls_hash_int.h" +#include "gnutls_cipher_int.h" +#include "gnutls_algorithms.h" +#include "gnutls_auth_int.h" +#include "gnutls_num.h" +#include "gnutls_record.h" +#include "gnutls_datum.h" +#include "ext_max_record.h" +#include <gnutls_state.h> +#include <gnutls_dh.h> + +/** + * MHD__gnutls_protocol_get_version - Returns the version of the currently used protocol + * @session: is a #MHD_gtls_session_t structure. + * + * Returns: the version of the currently used protocol. + **/ +enum MHD_GNUTLS_Protocol +MHD__gnutls_protocol_get_version (MHD_gtls_session_t session) +{ + return session->security_parameters.version; +} + +void +MHD_gtls_set_current_version (MHD_gtls_session_t session, + enum MHD_GNUTLS_Protocol version) +{ + session->security_parameters.version = version; +} + +/** + * MHD__gnutls_transport_set_lowat - Used to set the lowat value in order for select to check for pending data. + * @session: is a #MHD_gtls_session_t structure. + * @num: is the low water value. + * + * Used to set the lowat value in order for select to check if there + * are pending data to socket buffer. Used only if you have changed + * the default low water value (default is 1). Normally you will not + * need that function. This function is only useful if using + * berkeley style sockets. Otherwise it must be called and set lowat + * to zero. + **/ +void +MHD__gnutls_transport_set_lowat (MHD_gtls_session_t session, int num) +{ + session->internals.lowat = num; +} + +/** + * MHD__gnutls_transport_set_ptr - Used to set first argument of the transport functions + * @session: is a #MHD_gtls_session_t structure. + * @ptr: is the value. + * + * Used to set the first argument of the transport function (like + * PUSH and PULL). In berkeley style sockets this function will set + * the connection handle. + **/ +void +MHD__gnutls_transport_set_ptr (MHD_gtls_session_t session, + MHD_gnutls_transport_ptr_t ptr) +{ + session->internals.transport_recv_ptr = ptr; + session->internals.transport_send_ptr = ptr; +} + +/** + * MHD__gnutls_bye - This function terminates the current TLS/SSL connection. + * @session: is a #MHD_gtls_session_t structure. + * @how: is an integer + * + * Terminates the current TLS/SSL connection. The connection should + * have been initiated using MHD__gnutls_handshake(). @how should be one + * of %GNUTLS_SHUT_RDWR, %GNUTLS_SHUT_WR. + * + * In case of %GNUTLS_SHUT_RDWR then the TLS connection gets + * terminated and further receives and sends will be disallowed. If + * the return value is zero you may continue using the connection. + * %GNUTLS_SHUT_RDWR actually sends an alert containing a close + * request and waits for the peer to reply with the same message. + * + * In case of %GNUTLS_SHUT_WR then the TLS connection gets terminated + * and further sends will be disallowed. In order to reuse the + * connection you should wait for an EOF from the peer. + * %GNUTLS_SHUT_WR sends an alert containing a close request. + * + * Note that not all implementations will properly terminate a TLS + * connection. Some of them, usually for performance reasons, will + * terminate only the underlying transport layer, thus causing a + * transmission error to the peer. This error cannot be + * distinguished from a malicious party prematurely terminating the + * session, thus this behavior is not recommended. + * + * This function may also return %GNUTLS_E_AGAIN or + * %GNUTLS_E_INTERRUPTED; cf. MHD__gnutls_record_get_direction(). + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code, see + * function documentation for entire semantics. + **/ +int +MHD__gnutls_bye (MHD_gtls_session_t session, MHD_gnutls_close_request_t how) +{ + int ret = 0; + + switch (STATE) + { + case STATE0: + case STATE60: + ret = MHD_gtls_io_write_flush (session); + STATE = STATE60; + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + case STATE61: + ret = + MHD__gnutls_alert_send (session, GNUTLS_AL_WARNING, + GNUTLS_A_CLOSE_NOTIFY); + STATE = STATE61; + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + case STATE62: + STATE = STATE62; + if (how == GNUTLS_SHUT_RDWR) + { + do + { + MHD_gtls_io_clear_peeked_data (session); + ret = MHD_gtls_recv_int (session, GNUTLS_ALERT, -1, NULL, 0); + } + while (ret == GNUTLS_E_GOT_APPLICATION_DATA); + + if (ret >= 0) + session->internals.may_not_read = 1; + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + STATE = STATE62; + + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + STATE = STATE0; + + session->internals.may_not_write = 1; + return 0; +} + +inline static void +session_invalidate (MHD_gtls_session_t session) +{ + session->internals.valid_connection = VALID_FALSE; +} + +inline static void +session_unresumable (MHD_gtls_session_t session) +{ + session->internals.resumable = RESUME_FALSE; +} + +/* returns 0 if session is valid + */ +inline static int +session_is_valid (MHD_gtls_session_t session) +{ + if (session->internals.valid_connection == VALID_FALSE) + return GNUTLS_E_INVALID_SESSION; + + return 0; +} + +/* Copies the record version into the headers. The + * version must have 2 bytes at least. + */ +inline static void +copy_record_version (MHD_gtls_session_t session, + MHD_gnutls_handshake_description_t htype, + opaque version[2]) +{ + enum MHD_GNUTLS_Protocol lver; + + if (htype != GNUTLS_HANDSHAKE_CLIENT_HELLO + || session->internals.default_record_version[0] == 0) + { + lver = MHD__gnutls_protocol_get_version (session); + + version[0] = MHD_gtls_version_get_major (lver); + version[1] = MHD_gtls_version_get_minor (lver); + } + else + { + version[0] = session->internals.default_record_version[0]; + version[1] = session->internals.default_record_version[1]; + } +} + +/* This function behaves exactly like write(). The only difference is + * that it accepts, the MHD_gtls_session_t and the content_type_t of data to + * send (if called by the user the Content is specific) + * It is intended to transfer data, under the current session. + * + * Oct 30 2001: Removed capability to send data more than MAX_RECORD_SIZE. + * This makes the function much easier to read, and more error resistant + * (there were cases were the old function could mess everything up). + * --nmav + * + * This function may accept a NULL pointer for data, and 0 for size, if + * and only if the previous send was interrupted for some reason. + * + */ +ssize_t +MHD_gtls_send_int (MHD_gtls_session_t session, + content_type_t type, + MHD_gnutls_handshake_description_t htype, + const void *_data, size_t sizeofdata) +{ + uint8_t *cipher; + int cipher_size; + int retval, ret; + int data2send_size; + uint8_t headers[5]; + const uint8_t *data = _data; + + /* Do not allow null pointer if the send buffer is empty. + * If the previous send was interrupted then a null pointer is + * ok, and means to resume. + */ + if (session->internals.record_send_buffer.length == 0 && (sizeofdata == 0 + && _data == NULL)) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + if (type != GNUTLS_ALERT) /* alert messages are sent anyway */ + if (session_is_valid (session) || session->internals.may_not_write != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_SESSION; + } + + headers[0] = type; + + /* Use the default record version, if it is + * set. + */ + copy_record_version (session, htype, &headers[1]); + + MHD__gnutls_record_log + ("REC[%x]: Sending Packet[%d] %s(%d) with length: %d\n", session, + (int) MHD_gtls_uint64touint32 (&session->connection_state. + write_sequence_number), + MHD__gnutls_packet2str (type), type, sizeofdata); + + if (sizeofdata > MAX_RECORD_SEND_SIZE) + data2send_size = MAX_RECORD_SEND_SIZE; + else + data2send_size = sizeofdata; + + /* Only encrypt if we don't have data to send + * from the previous run. - probably interrupted. + */ + if (session->internals.record_send_buffer.length > 0) + { + ret = MHD_gtls_io_write_flush (session); + if (ret > 0) + cipher_size = ret; + else + cipher_size = 0; + + cipher = NULL; + + retval = session->internals.record_send_buffer_user_size; + } + else + { + /* now proceed to packet encryption + */ + cipher_size = data2send_size + MAX_RECORD_OVERHEAD; + cipher = MHD_gnutls_malloc (cipher_size); + if (cipher == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + cipher_size = + MHD_gtls_encrypt (session, headers, RECORD_HEADER_SIZE, data, + data2send_size, cipher, cipher_size, type, + (session->internals.priorities.no_padding == + 0) ? 1 : 0); + if (cipher_size <= 0) + { + MHD_gnutls_assert (); + if (cipher_size == 0) + cipher_size = GNUTLS_E_ENCRYPTION_FAILED; + MHD_gnutls_free (cipher); + return cipher_size; /* error */ + } + + retval = data2send_size; + session->internals.record_send_buffer_user_size = data2send_size; + + /* increase sequence number + */ + if (MHD_gtls_uint64pp + (&session->connection_state.write_sequence_number) != 0) + { + session_invalidate (session); + MHD_gnutls_assert (); + MHD_gnutls_free (cipher); + return GNUTLS_E_RECORD_LIMIT_REACHED; + } + + ret = MHD_gtls_io_write_buffered (session, cipher, cipher_size); + MHD_gnutls_free (cipher); + } + + if (ret != cipher_size) + { + if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0) + { + /* If we have sent any data then just return + * the error value. Do not invalidate the session. + */ + MHD_gnutls_assert (); + return ret; + } + + if (ret > 0) + { + MHD_gnutls_assert (); + ret = GNUTLS_E_INTERNAL_ERROR; + } + session_unresumable (session); + session->internals.may_not_write = 1; + MHD_gnutls_assert (); + return ret; + } + + session->internals.record_send_buffer_user_size = 0; + + MHD__gnutls_record_log ("REC[%x]: Sent Packet[%d] %s(%d) with length: %d\n", + session, + (int) + MHD_gtls_uint64touint32 + (&session->connection_state.write_sequence_number), + MHD__gnutls_packet2str (type), type, cipher_size); + + return retval; +} + +/* This function is to be called if the handshake was successfully + * completed. This sends a Change Cipher Spec packet to the peer. + */ +ssize_t +MHD_gtls_send_change_cipher_spec (MHD_gtls_session_t session, int again) +{ + static const opaque data[1] = { + GNUTLS_TYPE_CHANGE_CIPHER_SPEC + }; + + MHD__gnutls_handshake_log ("REC[%x]: Sent ChangeCipherSpec\n", session); + + if (again == 0) + return MHD_gtls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1, data, + 1); + else + { + return MHD_gtls_io_write_flush (session); + } +} + +inline static int +check_recv_type (content_type_t recv_type) +{ + switch (recv_type) + { + case GNUTLS_CHANGE_CIPHER_SPEC: + case GNUTLS_ALERT: + case GNUTLS_HANDSHAKE: + case GNUTLS_APPLICATION_DATA: + case GNUTLS_INNER_APPLICATION: + return 0; + default: + MHD_gnutls_assert (); + return GNUTLS_A_UNEXPECTED_MESSAGE; + } + +} + +/* Checks if there are pending data in the record buffers. If there are + * then it copies the data. + */ +static int +check_buffers (MHD_gtls_session_t session, + content_type_t type, opaque * data, int sizeofdata) +{ + if ((type == GNUTLS_APPLICATION_DATA || type == GNUTLS_HANDSHAKE || type + == GNUTLS_INNER_APPLICATION) + && MHD_gnutls_record_buffer_get_size (type, session) > 0) + { + int ret, ret2; + ret = MHD_gtls_record_buffer_get (type, session, data, sizeofdata); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* if the buffer just got empty */ + if (MHD_gnutls_record_buffer_get_size (type, session) == 0) + { + if ((ret2 = MHD_gtls_io_clear_peeked_data (session)) < 0) + { + MHD_gnutls_assert (); + return ret2; + } + } + + return ret; + } + + return 0; +} + +/* Checks the record headers and returns the length, version and + * content type. + */ +static int +record_check_headers (MHD_gtls_session_t session, + uint8_t headers[RECORD_HEADER_SIZE], + content_type_t type, + MHD_gnutls_handshake_description_t htype, + /*output */ content_type_t * recv_type, + opaque version[2], + uint16_t * length, uint16_t * header_size) +{ + + /* Read the first two bytes to determine if this is a + * version 2 message + */ + + if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO && type == GNUTLS_HANDSHAKE + && headers[0] > 127) + { + + /* if msb set and expecting handshake message + * it should be SSL 2 hello + */ + version[0] = 3; /* assume SSL 3.0 */ + version[1] = 0; + + *length = (((headers[0] & 0x7f) << 8)) | headers[1]; + + /* SSL 2.0 headers */ + *header_size = 2; + *recv_type = GNUTLS_HANDSHAKE; /* we accept only v2 client hello + */ + + /* in order to assist the handshake protocol. + * V2 compatibility is a mess. + */ + session->internals.v2_hello = *length; + + MHD__gnutls_record_log ("REC[%x]: V2 packet received. Length: %d\n", + session, *length); + + } + else + { + /* version 3.x */ + *recv_type = headers[0]; + version[0] = headers[1]; + version[1] = headers[2]; + + /* No DECR_LEN, since headers has enough size. + */ + *length = MHD_gtls_read_uint16 (&headers[3]); + } + + return 0; +} + +/* Here we check if the advertized version is the one we + * negotiated in the handshake. + */ +inline static int +record_check_version (MHD_gtls_session_t session, + MHD_gnutls_handshake_description_t htype, + opaque version[2]) +{ + if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO) + { + /* Reject hello packets with major version higher than 3. + */ + if (version[0] > 3) + { + MHD_gnutls_assert (); + MHD__gnutls_record_log + ("REC[%x]: INVALID VERSION PACKET: (%d) %d.%d\n", session, + htype, version[0], version[1]); + return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; + } + } + else if (htype != GNUTLS_HANDSHAKE_SERVER_HELLO + && MHD__gnutls_protocol_get_version (session) + != MHD_gtls_version_get (version[0], version[1])) + { + /* Reject record packets that have a different version than the + * one negotiated. Note that this version is not protected by any + * mac. I don't really think that this check serves any purpose. + */ + MHD_gnutls_assert (); + MHD__gnutls_record_log ("REC[%x]: INVALID VERSION PACKET: (%d) %d.%d\n", + session, htype, version[0], version[1]); + + return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; + } + + return 0; +} + +/* This function will check if the received record type is + * the one we actually expect. + */ +static int +record_check_type (MHD_gtls_session_t session, + content_type_t recv_type, + content_type_t type, + MHD_gnutls_handshake_description_t htype, + opaque * data, int data_size) +{ + + int ret; + + if ((recv_type == type) && (type == GNUTLS_APPLICATION_DATA || type + == GNUTLS_HANDSHAKE + || type == GNUTLS_INNER_APPLICATION)) + { + MHD_gnutls_record_buffer_put (type, session, (void *) data, data_size); + } + else + { + switch (recv_type) + { + case GNUTLS_ALERT: + + MHD__gnutls_record_log + ("REC[%x]: Alert[%d|%d] - %s - was received\n", session, + data[0], data[1], MHD__gnutls_alert_get_name ((int) data[1])); + + session->internals.last_alert = data[1]; + session->internals.last_alert_level = data[0]; + + /* if close notify is received and + * the alert is not fatal + */ + if (data[1] == GNUTLS_A_CLOSE_NOTIFY && data[0] != GNUTLS_AL_FATAL) + { + /* If we have been expecting for an alert do + */ + session->internals.read_eof = 1; + return GNUTLS_E_INT_RET_0; /* EOF */ + } + else + { + + /* if the alert is FATAL or WARNING + * return the apropriate message + */ + MHD_gnutls_assert (); + ret = GNUTLS_E_WARNING_ALERT_RECEIVED; + if (data[0] == GNUTLS_AL_FATAL) + { + session_unresumable (session); + session_invalidate (session); + ret = GNUTLS_E_FATAL_ALERT_RECEIVED; + } + + return ret; + } + break; + + case GNUTLS_CHANGE_CIPHER_SPEC: + /* this packet is now handled in the recv_int() + * function + */ + MHD_gnutls_assert (); + + return GNUTLS_E_UNEXPECTED_PACKET; + + case GNUTLS_APPLICATION_DATA: + /* even if data is unexpected put it into the buffer */ + if ((ret = + MHD_gnutls_record_buffer_put (recv_type, session, + (void *) data, data_size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* the got_application data is only returned + * if expecting client hello (for rehandshake + * reasons). Otherwise it is an unexpected packet + */ + if (type == GNUTLS_ALERT || (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO + && type == GNUTLS_HANDSHAKE)) + return GNUTLS_E_GOT_APPLICATION_DATA; + else + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET; + } + + break; + case GNUTLS_HANDSHAKE: + /* This is legal if HELLO_REQUEST is received - and we are a client. + * If we are a server, a client may initiate a renegotiation at any time. + */ + if (session->security_parameters.entity == GNUTLS_SERVER) + { + MHD_gnutls_assert (); + return GNUTLS_E_REHANDSHAKE; + } + + /* If we are already in a handshake then a Hello + * Request is illegal. But here we don't really care + * since this message will never make it up here. + */ + + /* So we accept it */ + return MHD_gtls_recv_hello_request (session, data, data_size); + + break; + case GNUTLS_INNER_APPLICATION: + /* even if data is unexpected put it into the buffer */ + if ((ret = + MHD_gnutls_record_buffer_put (recv_type, session, + (void *) data, data_size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET; + break; + default: + + MHD__gnutls_record_log + ("REC[%x]: Received Unknown packet %d expecting %d\n", + session, recv_type, type); + + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + } + + return 0; + +} + +/* This function will return the internal (per session) temporary + * recv buffer. If the buffer was not initialized before it will + * also initialize it. + */ +inline static int +get_temp_recv_buffer (MHD_gtls_session_t session, MHD_gnutls_datum_t * tmp) +{ + size_t max_record_size; + + max_record_size = MAX_RECORD_RECV_SIZE; + + /* We allocate MAX_RECORD_RECV_SIZE length + * because we cannot predict the output data by the record + * packet length (due to compression). + */ + + if (max_record_size > session->internals.recv_buffer.size + || session->internals.recv_buffer.data == NULL) + { + + /* Initialize the internal buffer. + */ + session->internals.recv_buffer.data + = + MHD_gnutls_realloc (session->internals.recv_buffer.data, + max_record_size); + + if (session->internals.recv_buffer.data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + session->internals.recv_buffer.size = max_record_size; + } + + tmp->data = session->internals.recv_buffer.data; + tmp->size = session->internals.recv_buffer.size; + + return 0; +} + +#define MAX_EMPTY_PACKETS_SEQUENCE 4 + +/* This function behaves exactly like read(). The only difference is + * that it accepts the MHD_gtls_session_t and the content_type_t of data to + * receive (if called by the user the Content is Userdata only) + * It is intended to receive data, under the current session. + * + * The MHD_gnutls_handshake_description_t was introduced to support SSL V2.0 client hellos. + */ +ssize_t +MHD_gtls_recv_int (MHD_gtls_session_t session, + content_type_t type, + MHD_gnutls_handshake_description_t htype, + opaque * data, size_t sizeofdata) +{ + MHD_gnutls_datum_t tmp; + int decrypted_length; + opaque version[2]; + uint8_t *headers; + content_type_t recv_type; + uint16_t length; + uint8_t *ciphertext; + uint8_t *recv_data; + int ret, ret2; + uint16_t header_size; + int empty_packet = 0; + + if (type != GNUTLS_ALERT && (sizeofdata == 0 || data == NULL)) + { + return GNUTLS_E_INVALID_REQUEST; + } + +begin: + + if (empty_packet > MAX_EMPTY_PACKETS_SEQUENCE) + { + MHD_gnutls_assert (); + return GNUTLS_E_TOO_MANY_EMPTY_PACKETS; + } + + if (session->internals.read_eof != 0) + { + /* if we have already read an EOF + */ + return 0; + } + else if (session_is_valid (session) != 0 || session->internals.may_not_read + != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_SESSION; + } + + /* If we have enough data in the cache do not bother receiving + * a new packet. (in order to flush the cache) + */ + ret = check_buffers (session, type, data, sizeofdata); + if (ret != 0) + return ret; + + /* default headers for TLS 1.0 + */ + header_size = RECORD_HEADER_SIZE; + + if ((ret = MHD_gtls_io_read_buffered (session, &headers, header_size, -1)) + != header_size) + { + if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0) + return ret; + + session_invalidate (session); + if (type == GNUTLS_ALERT) + { + MHD_gnutls_assert (); + return 0; /* we were expecting close notify */ + } + session_unresumable (session); + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + if ((ret = record_check_headers (session, headers, type, htype, &recv_type, + version, &length, &header_size)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* Here we check if the Type of the received packet is + * ok. + */ + if ((ret = check_recv_type (recv_type)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* Here we check if the advertized version is the one we + * negotiated in the handshake. + */ + if ((ret = record_check_version (session, htype, version)) < 0) + { + MHD_gnutls_assert (); + session_invalidate (session); + return ret; + } + + MHD__gnutls_record_log + ("REC[%x]: Expected Packet[%d] %s(%d) with length: %d\n", session, + (int) MHD_gtls_uint64touint32 (&session->connection_state. + read_sequence_number), + MHD__gnutls_packet2str (type), type, sizeofdata); + MHD__gnutls_record_log + ("REC[%x]: Received Packet[%d] %s(%d) with length: %d\n", session, + (int) MHD_gtls_uint64touint32 (&session->connection_state. + read_sequence_number), + MHD__gnutls_packet2str (recv_type), recv_type, length); + + if (length > MAX_RECV_SIZE) + { + MHD__gnutls_record_log + ("REC[%x]: FATAL ERROR: Received packet with length: %d\n", + session, length); + + session_unresumable (session); + session_invalidate (session); + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + /* check if we have that data into buffer. + */ + if ((ret = MHD_gtls_io_read_buffered (session, &recv_data, + header_size + length, recv_type)) + != header_size + length) + { + if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0) + return ret; + + session_unresumable (session); + session_invalidate (session); + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + + /* ok now we are sure that we can read all the data - so + * move on ! + */ + MHD_gtls_io_clear_read_buffer (session); + ciphertext = &recv_data[header_size]; + + ret = get_temp_recv_buffer (session, &tmp); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* decrypt the data we got. */ + ret = MHD_gtls_decrypt (session, ciphertext, length, tmp.data, tmp.size, + recv_type); + if (ret < 0) + { + session_unresumable (session); + session_invalidate (session); + MHD_gnutls_assert (); + return ret; + } + decrypted_length = ret; + + /* Check if this is a CHANGE_CIPHER_SPEC + */ + if (type == GNUTLS_CHANGE_CIPHER_SPEC && recv_type + == GNUTLS_CHANGE_CIPHER_SPEC) + { + + MHD__gnutls_record_log + ("REC[%x]: ChangeCipherSpec Packet was received\n", session); + + if ((size_t) ret != sizeofdata) + { /* sizeofdata should be 1 */ + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; + } + memcpy (data, tmp.data, sizeofdata); + + return ret; + } + + MHD__gnutls_record_log + ("REC[%x]: Decrypted Packet[%d] %s(%d) with length: %d\n", session, + (int) MHD_gtls_uint64touint32 (&session->connection_state. + read_sequence_number), + MHD__gnutls_packet2str (recv_type), recv_type, decrypted_length); + + /* increase sequence number + */ + if (MHD_gtls_uint64pp (&session->connection_state.read_sequence_number) != + 0) + { + session_invalidate (session); + MHD_gnutls_assert (); + return GNUTLS_E_RECORD_LIMIT_REACHED; + } + + /* check type - this will also invalidate sessions if a fatal alert has been received */ + ret = record_check_type (session, recv_type, type, htype, tmp.data, + decrypted_length); + if (ret < 0) + { + if (ret == GNUTLS_E_INT_RET_0) + return 0; + MHD_gnutls_assert (); + return ret; + } + + /* Get Application data from buffer + */ + if ((recv_type == type) && (type == GNUTLS_APPLICATION_DATA || type + == GNUTLS_HANDSHAKE + || type == GNUTLS_INNER_APPLICATION)) + { + + ret = MHD_gtls_record_buffer_get (type, session, data, sizeofdata); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* if the buffer just got empty + */ + if (MHD_gnutls_record_buffer_get_size (type, session) == 0) + { + if ((ret2 = MHD_gtls_io_clear_peeked_data (session)) < 0) + { + MHD_gnutls_assert (); + return ret2; + } + } + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_UNEXPECTED_PACKET; + /* we didn't get what we wanted to + */ + } + + /* (originally for) TLS 1.0 CBC protection. + * Actually this code is called if we just received + * an empty packet. An empty TLS packet is usually + * sent to protect some vulnerabilities in the CBC mode. + * In that case we go to the beginning and start reading + * the next packet. + */ + if (ret == 0) + { + empty_packet++; + goto begin; + } + + return ret; +} + +/** + * MHD__gnutls_record_send - sends to the peer the specified data + * @session: is a #MHD_gtls_session_t structure. + * @data: contains the data to send + * @sizeofdata: is the length of the data + * + * This function has the similar semantics with send(). The only + * difference is that is accepts a GNUTLS session, and uses different + * error codes. + * + * Note that if the send buffer is full, send() will block this + * function. See the send() documentation for full information. You + * can replace the default push function by using + * MHD__gnutls_transport_set_ptr2() with a call to send() with a + * MSG_DONTWAIT flag if blocking is a problem. + * + * If the EINTR is returned by the internal push function (the + * default is send()} then %GNUTLS_E_INTERRUPTED will be returned. If + * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must + * call this function again, with the same parameters; alternatively + * you could provide a %NULL pointer for data, and 0 for + * size. cf. MHD__gnutls_record_get_direction(). + * + * Returns: the number of bytes sent, or a negative error code. The + * number of bytes sent might be less than @sizeofdata. The maximum + * number of bytes this function can send in a single call depends on + * the negotiated maximum record size. + **/ +ssize_t +MHD__gnutls_record_send (MHD_gtls_session_t session, + const void *data, size_t sizeofdata) +{ + return MHD_gtls_send_int (session, GNUTLS_APPLICATION_DATA, -1, data, + sizeofdata); +} + +/** + * MHD__gnutls_record_recv - reads data from the TLS record protocol + * @session: is a #MHD_gtls_session_t structure. + * @data: the buffer that the data will be read into + * @sizeofdata: the number of requested bytes + * + * This function has the similar semantics with recv(). The only + * difference is that is accepts a GNUTLS session, and uses different + * error codes. + * + * In the special case that a server requests a renegotiation, the + * client may receive an error code of %GNUTLS_E_REHANDSHAKE. This + * message may be simply ignored, replied with an alert containing + * NO_RENEGOTIATION, or replied with a new handshake, depending on + * the client's will. + * + * If %EINTR is returned by the internal push function (the default + * is recv()) then %GNUTLS_E_INTERRUPTED will be returned. If + * %GNUTLS_E_INTERRUPTED or %GNUTLS_E_AGAIN is returned, you must + * call this function again to get the data. See also + * MHD__gnutls_record_get_direction(). + * + * A server may also receive %GNUTLS_E_REHANDSHAKE when a client has + * initiated a handshake. In that case the server can only initiate a + * handshake or terminate the connection. + * + * Returns: the number of bytes received and zero on EOF. A negative + * error code is returned in case of an error. The number of bytes + * received might be less than @sizeofdata. + **/ +ssize_t +MHD__gnutls_record_recv (MHD_gtls_session_t session, void *data, + size_t sizeofdata) +{ + return MHD_gtls_recv_int (session, GNUTLS_APPLICATION_DATA, -1, data, + sizeofdata); +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_record.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_record.h new file mode 100644 index 0000000000..fe7300b62b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_record.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +ssize_t MHD_gtls_send_int (MHD_gtls_session_t session, content_type_t type, + MHD_gnutls_handshake_description_t htype, + const void *data, size_t sizeofdata); +ssize_t MHD_gtls_recv_int (MHD_gtls_session_t session, content_type_t type, + MHD_gnutls_handshake_description_t, opaque * data, + size_t sizeofdata); +ssize_t MHD_gtls_send_change_cipher_spec (MHD_gtls_session_t session, + int again); +void MHD__gnutls_transport_set_lowat (MHD_gtls_session_t session, int num); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_rsa_export.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_rsa_export.c new file mode 100644 index 0000000000..65f97c76a1 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_rsa_export.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains code for RSA temporary keys. These keys are + * only used in export cipher suites. + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_datum.h> +#include <gnutls_rsa_export.h> +#include "debug.h" +/* x509 */ +#include "x509.h" +#include "privkey.h" + +/* returns e and m, depends on the requested bits. + * We only support limited key sizes. + */ +const mpi_t * +MHD__gnutls_rsa_params_to_mpi (MHD_gtls_rsa_params_t rsa_params) +{ + if (rsa_params == NULL) + { + return NULL; + } + return rsa_params->params; +} + + +/** + * MHD__gnutls_rsa_params_deinit - This function will deinitialize the RSA parameters + * @rsa_params: Is a structure that holds the parameters + * + * This function will deinitialize the RSA parameters structure. + * + **/ +void +MHD__gnutls_rsa_params_deinit (MHD_gtls_rsa_params_t rsa_params) +{ + MHD_gnutls_x509_privkey_deinit (rsa_params); +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_rsa_export.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_rsa_export.h new file mode 100644 index 0000000000..a28f429733 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_rsa_export.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +const mpi_t *MHD__gnutls_rsa_params_to_mpi (MHD_gtls_rsa_params_t); +int MHD__gnutls_peers_cert_less_512 (MHD_gtls_session_t session); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_sig.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_sig.c new file mode 100644 index 0000000000..e27c468413 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_sig.c @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2001, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <x509_b64.h> +#include <auth_cert.h> +#include <gnutls_cert.h> +#include <gnutls_datum.h> +#include <gnutls_mpi.h> +#include <gnutls_global.h> +#include <gnutls_pk.h> +#include <debug.h> +#include <gnutls_buffers.h> +#include <gnutls_sig.h> +#include <gnutls_kx.h> + +static int MHD__gnutls_tls_sign (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_privkey * pkey, + const MHD_gnutls_datum_t * hash_concat, + MHD_gnutls_datum_t * signature); + +/* Generates a signature of all the previous sent packets in the + * handshake procedure. (20040227: now it works for SSL 3.0 as well) + */ +int +MHD_gtls_tls_sign_hdata (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_privkey * pkey, + MHD_gnutls_datum_t * signature) +{ + MHD_gnutls_datum_t dconcat; + int ret; + opaque concat[36]; + mac_hd_t td_md5; + mac_hd_t td_sha; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + td_sha = MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_sha); + if (td_sha == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + if (ver == MHD_GNUTLS_PROTOCOL_SSL3) + { + ret = MHD_gtls_generate_master (session, 1); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD_gnutls_mac_deinit_ssl3_handshake (td_sha, &concat[16], + session->security_parameters. + master_secret, TLS_MASTER_SIZE); + } + else + MHD_gnutls_hash_deinit (td_sha, &concat[16]); + + switch (cert->subject_pk_algorithm) + { + case MHD_GNUTLS_PK_RSA: + td_md5 = + MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_md5); + if (td_md5 == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + if (ver == MHD_GNUTLS_PROTOCOL_SSL3) + MHD_gnutls_mac_deinit_ssl3_handshake (td_md5, concat, + session->security_parameters. + master_secret, TLS_MASTER_SIZE); + else + MHD_gnutls_hash_deinit (td_md5, concat); + + dconcat.data = concat; + dconcat.size = 36; + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + ret = MHD__gnutls_tls_sign (session, cert, pkey, &dconcat, signature); + if (ret < 0) + { + MHD_gnutls_assert (); + } + + return ret; +} + +/* Generates a signature of all the random data and the parameters. + * Used in DHE_* ciphersuites. + */ +int +MHD_gtls_tls_sign_params (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_privkey * pkey, + MHD_gnutls_datum_t * params, + MHD_gnutls_datum_t * signature) +{ + MHD_gnutls_datum_t dconcat; + int ret; + mac_hd_t td_sha; + opaque concat[36]; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + td_sha = MHD_gtls_hash_init (MHD_GNUTLS_MAC_SHA1); + if (td_sha == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + MHD_gnutls_hash (td_sha, session->security_parameters.client_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_sha, session->security_parameters.server_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_sha, params->data, params->size); + + switch (cert->subject_pk_algorithm) + { + case MHD_GNUTLS_PK_RSA: + if (ver < MHD_GNUTLS_PROTOCOL_TLS1_2) + { + mac_hd_t td_md5 = MHD_gtls_hash_init (MHD_GNUTLS_MAC_MD5); + if (td_md5 == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + MHD_gnutls_hash (td_md5, session->security_parameters.client_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_md5, session->security_parameters.server_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_md5, params->data, params->size); + + MHD_gnutls_hash_deinit (td_md5, concat); + MHD_gnutls_hash_deinit (td_sha, &concat[16]); + + dconcat.size = 36; + } + else + { +#if 1 + /* Use NULL parameters. */ + memcpy (concat, + "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14", + 15); + MHD_gnutls_hash_deinit (td_sha, &concat[15]); + dconcat.size = 35; +#else + /* No parameters field. */ + memcpy (concat, + "\x30\x1f\x30\x07\x06\x05\x2b\x0e\x03\x02\x1a\x04\x14", 13); + MHD_gnutls_hash_deinit (td_sha, &concat[13]); + dconcat.size = 33; +#endif + } + dconcat.data = concat; + break; + default: + MHD_gnutls_assert (); + MHD_gnutls_hash_deinit (td_sha, NULL); + return GNUTLS_E_INTERNAL_ERROR; + } + ret = MHD__gnutls_tls_sign (session, cert, pkey, &dconcat, signature); + if (ret < 0) + { + MHD_gnutls_assert (); + } + + return ret; + +} + +/* This will create a PKCS1 or DSA signature, using the given parameters, and the + * given data. The output will be allocated and be put in signature. + */ +static int +MHD_gtls_sign (enum MHD_GNUTLS_PublicKeyAlgorithm algo, + mpi_t * params, + int params_size, + const MHD_gnutls_datum_t * data, + MHD_gnutls_datum_t * signature) +{ + int ret; + + switch (algo) + { + case MHD_GNUTLS_PK_RSA: + /* encrypt */ + if ((ret = + MHD_gtls_pkcs1_rsa_encrypt (signature, data, params, params_size, + 1)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + break; + } + + return 0; +} + +/* This will create a PKCS1 or DSA signature, as defined in the TLS protocol. + * Cert is the certificate of the corresponding private key. It is only checked if + * it supports signing. + */ +static int +MHD__gnutls_tls_sign (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_privkey * pkey, + const MHD_gnutls_datum_t * hash_concat, + MHD_gnutls_datum_t * signature) +{ + + /* If our certificate supports signing + */ + + if (cert != NULL) + if (cert->key_usage != 0) + if (!(cert->key_usage & KEY_DIGITAL_SIGNATURE)) + { + MHD_gnutls_assert (); + return GNUTLS_E_KEY_USAGE_VIOLATION; + } + + /* External signing. */ + if (!pkey || pkey->params_size == 0) + { + if (!session->internals.sign_func) + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + + return (*session->internals.sign_func) (session, + session->internals. + sign_func_userdata, + cert->cert_type, &cert->raw, + hash_concat, signature); + } + + return MHD_gtls_sign (pkey->pk_algorithm, pkey->params, pkey->params_size, + hash_concat, signature); +} + +static int +MHD__gnutls_verify_sig (MHD_gnutls_cert * cert, + const MHD_gnutls_datum_t * hash_concat, + MHD_gnutls_datum_t * signature, size_t sha1pos) +{ + int ret; + MHD_gnutls_datum_t vdata; + + if ((cert == NULL) || (cert->version == 0)) + { /* this is the only way to check + * if it is initialized + */ + MHD_gnutls_assert (); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + /* If the certificate supports signing continue. + */ + if (cert != NULL) + if (cert->key_usage != 0) + if (!(cert->key_usage & KEY_DIGITAL_SIGNATURE)) + { + MHD_gnutls_assert (); + return GNUTLS_E_KEY_USAGE_VIOLATION; + } + + switch (cert->subject_pk_algorithm) + { + case MHD_GNUTLS_PK_RSA: + + vdata.data = hash_concat->data; + vdata.size = hash_concat->size; + + /* verify signature */ + if ((ret = MHD_gtls_rsa_verify (&vdata, signature, cert->params, + cert->params_size, 1)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + return 0; +} + +/* Verifies a TLS signature (like the one in the client certificate + * verify message). + */ +int +MHD_gtls_verify_sig_hdata (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_datum_t * signature) +{ + int ret; + opaque concat[36]; + mac_hd_t td_md5; + mac_hd_t td_sha; + MHD_gnutls_datum_t dconcat; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + td_md5 = MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_md5); + if (td_md5 == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + td_sha = MHD_gnutls_hash_copy (session->internals.handshake_mac_handle_sha); + if (td_sha == NULL) + { + MHD_gnutls_assert (); + MHD_gnutls_hash_deinit (td_md5, NULL); + return GNUTLS_E_HASH_FAILED; + } + + if (ver == MHD_GNUTLS_PROTOCOL_SSL3) + { + ret = MHD_gtls_generate_master (session, 1); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + MHD_gnutls_mac_deinit_ssl3_handshake (td_md5, concat, + session->security_parameters. + master_secret, TLS_MASTER_SIZE); + MHD_gnutls_mac_deinit_ssl3_handshake (td_sha, &concat[16], + session->security_parameters. + master_secret, TLS_MASTER_SIZE); + } + else + { + MHD_gnutls_hash_deinit (td_md5, concat); + MHD_gnutls_hash_deinit (td_sha, &concat[16]); + } + + dconcat.data = concat; + dconcat.size = 20 + 16; /* md5+ sha */ + + ret = MHD__gnutls_verify_sig (cert, &dconcat, signature, 16); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return ret; + +} + +/* Generates a signature of all the random data and the parameters. + * Used in DHE_* ciphersuites. + */ +int +MHD_gtls_verify_sig_params (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + const MHD_gnutls_datum_t * params, + MHD_gnutls_datum_t * signature) +{ + MHD_gnutls_datum_t dconcat; + int ret; + mac_hd_t td_md5 = NULL; + mac_hd_t td_sha; + opaque concat[36]; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + if (ver < MHD_GNUTLS_PROTOCOL_TLS1_2) + { + td_md5 = MHD_gtls_hash_init (MHD_GNUTLS_MAC_MD5); + if (td_md5 == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_HASH_FAILED; + } + + MHD_gnutls_hash (td_md5, session->security_parameters.client_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_md5, session->security_parameters.server_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_md5, params->data, params->size); + } + + td_sha = MHD_gtls_hash_init (MHD_GNUTLS_MAC_SHA1); + if (td_sha == NULL) + { + MHD_gnutls_assert (); + if (td_md5) + MHD_gnutls_hash_deinit (td_md5, NULL); + return GNUTLS_E_HASH_FAILED; + } + + MHD_gnutls_hash (td_sha, session->security_parameters.client_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_sha, session->security_parameters.server_random, + TLS_RANDOM_SIZE); + MHD_gnutls_hash (td_sha, params->data, params->size); + + if (ver < MHD_GNUTLS_PROTOCOL_TLS1_2) + { + MHD_gnutls_hash_deinit (td_md5, concat); + MHD_gnutls_hash_deinit (td_sha, &concat[16]); + dconcat.size = 36; + } + else + { +#if 1 + /* Use NULL parameters. */ + memcpy (concat, + "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14", + 15); + MHD_gnutls_hash_deinit (td_sha, &concat[15]); + dconcat.size = 35; +#else + /* No parameters field. */ + memcpy (concat, + "\x30\x1f\x30\x07\x06\x05\x2b\x0e\x03\x02\x1a\x04\x14", 13); + MHD_gnutls_hash_deinit (td_sha, &concat[13]); + dconcat.size = 33; +#endif + } + + dconcat.data = concat; + + ret = MHD__gnutls_verify_sig (cert, &dconcat, signature, dconcat.size - 20); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return ret; + +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_sig.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_sig.h new file mode 100644 index 0000000000..020ef48988 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_sig.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_SIG_H +# define GNUTLS_SIG_H + +int MHD_gtls_tls_sign_hdata (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_privkey * pkey, + MHD_gnutls_datum_t * signature); + +int MHD_gtls_tls_sign_params (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_privkey * pkey, + MHD_gnutls_datum_t * params, + MHD_gnutls_datum_t * signature); + +int MHD_gtls_verify_sig_hdata (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + MHD_gnutls_datum_t * signature); + +int MHD_gtls_verify_sig_params (MHD_gtls_session_t session, + MHD_gnutls_cert * cert, + const MHD_gnutls_datum_t * params, + MHD_gnutls_datum_t * signature); + + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_state.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_state.c new file mode 100644 index 0000000000..01f51abc7d --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_state.c @@ -0,0 +1,804 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions to manipulate the session (MHD_gnutls_int.h), and some other stuff + * are included here. The file's name is traditionally MHD_gnutls_state even if the + * state has been renamed to session. + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_auth_int.h> +#include <gnutls_num.h> +#include <gnutls_datum.h> +#include <gnutls_record.h> +#include <gnutls_handshake.h> +#include <gnutls_dh.h> +#include <gnutls_buffers.h> +#include <gnutls_state.h> +#include <auth_cert.h> +#include <gnutls_algorithms.h> +#include <gnutls_rsa_export.h> + +void +MHD__gnutls_session_cert_type_set (MHD_gtls_session_t session, + enum MHD_GNUTLS_CertificateType ct) +{ + session->security_parameters.cert_type = ct; +} + +/** + * MHD_gnutls_cipher_get - Returns the currently used cipher. + * @session: is a #MHD_gtls_session_t structure. + * + * Returns: the currently used cipher. + **/ +enum MHD_GNUTLS_CipherAlgorithm +MHD_gnutls_cipher_get (MHD_gtls_session_t session) +{ + return session->security_parameters.read_bulk_cipher_algorithm; +} + +/** + * MHD_gnutls_certificate_type_get - Returns the currently used certificate type. + * @session: is a #MHD_gtls_session_t structure. + * + * The certificate type is by default X.509, unless it is negotiated + * as a TLS extension. + * + * Returns: the currently used %enum MHD_GNUTLS_CertificateType certificate + * type. + **/ +enum MHD_GNUTLS_CertificateType +MHD_gnutls_certificate_type_get (MHD_gtls_session_t session) +{ + return session->security_parameters.cert_type; +} + +/** + * MHD_gnutls_kx_get - Returns the key exchange algorithm. + * @session: is a #MHD_gtls_session_t structure. + * + * Returns: the key exchange algorithm used in the last handshake. + **/ +enum MHD_GNUTLS_KeyExchangeAlgorithm +MHD_gnutls_kx_get (MHD_gtls_session_t session) +{ + return session->security_parameters.kx_algorithm; +} + +/* Check if the given certificate type is supported. + * This means that it is enabled by the priority functions, + * and a matching certificate exists. + */ +int +MHD_gtls_session_cert_type_supported (MHD_gtls_session_t session, + enum MHD_GNUTLS_CertificateType + cert_type) +{ + unsigned i; + unsigned cert_found = 0; + MHD_gtls_cert_credentials_t cred; + + if (session->security_parameters.entity == GNUTLS_SERVER) + { + cred + = (MHD_gtls_cert_credentials_t) MHD_gtls_get_cred (session->key, + MHD_GNUTLS_CRD_CERTIFICATE, + NULL); + + if (cred == NULL) + return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE; + + if (cred->server_get_cert_callback == NULL) + { + for (i = 0; i < cred->ncerts; i++) + { + if (cred->cert_list[i][0].cert_type == cert_type) + { + cert_found = 1; + break; + } + } + + if (cert_found == 0) + /* no certificate is of that type. + */ + return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE; + } + } + + if (session->internals.priorities.cert_type.num_algorithms == 0 && cert_type + == DEFAULT_CERT_TYPE) + return 0; + + for (i = 0; i < session->internals.priorities.cert_type.num_algorithms; i++) + { + if (session->internals.priorities.cert_type.priority[i] == cert_type) + { + return 0; /* ok */ + } + } + + return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE; +} + +/* this function deinitializes all the internal parameters stored + * in a session struct. + */ +inline static void +deinit_internal_params (MHD_gtls_session_t session) +{ + if (session->internals.params.free_dh_params) + MHD__gnutls_dh_params_deinit (session->internals.params.dh_params); + + if (session->internals.params.free_rsa_params) + MHD__gnutls_rsa_params_deinit (session->internals.params.rsa_params); + + memset (&session->internals.params, 0, sizeof (session->internals.params)); +} + +/* This function will clear all the variables in internals + * structure within the session, which depend on the current handshake. + * This is used to allow further handshakes. + */ +void +MHD_gtls_handshake_internal_state_clear (MHD_gtls_session_t session) +{ + session->internals.extensions_sent_size = 0; + + /* by default no selected certificate */ + session->internals.proposed_record_size = DEFAULT_MAX_RECORD_SIZE; + session->internals.adv_version_major = 0; + session->internals.adv_version_minor = 0; + session->internals.v2_hello = 0; + memset (&session->internals.handshake_header_buffer, 0, + sizeof (MHD_gtls_handshake_header_buffer_st)); + session->internals.adv_version_minor = 0; + session->internals.adv_version_minor = 0; + session->internals.direction = 0; + + /* use out of band data for the last + * handshake messages received. + */ + session->internals.last_handshake_in = -1; + session->internals.last_handshake_out = -1; + + session->internals.resumable = RESUME_TRUE; + MHD__gnutls_free_datum (&session->internals.recv_buffer); + + deinit_internal_params (session); + +} + +#define MIN_DH_BITS 727 +/** + * MHD__gnutls_init - This function initializes the session to null (null encryption etc...). + * @con_end: indicate if this session is to be used for server or client. + * @session: is a pointer to a #MHD_gtls_session_t structure. + * + * This function initializes the current session to null. Every + * session must be initialized before use, so internal structures can + * be allocated. This function allocates structures which can only + * be free'd by calling MHD__gnutls_deinit(). Returns zero on success. + * + * @con_end can be one of %GNUTLS_CLIENT and %GNUTLS_SERVER. + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + **/ + +/* TODO rm redundent pointer ref */ +int +MHD__gnutls_init (MHD_gtls_session_t * session, + MHD_gnutls_connection_end_t con_end) +{ + *session = MHD_gnutls_calloc (1, sizeof (struct MHD_gtls_session_int)); + if (*session == NULL) + return GNUTLS_E_MEMORY_ERROR; + + (*session)->security_parameters.entity = con_end; + + /* the default certificate type for TLS */ + (*session)->security_parameters.cert_type = DEFAULT_CERT_TYPE; + + /* Set the defaults for initial handshake */ + (*session)->security_parameters.read_bulk_cipher_algorithm = + (*session)->security_parameters.write_bulk_cipher_algorithm = + MHD_GNUTLS_CIPHER_NULL; + + (*session)->security_parameters.read_mac_algorithm = + (*session)->security_parameters.write_mac_algorithm = MHD_GNUTLS_MAC_NULL; + + /* Initialize buffers */ + MHD_gtls_buffer_init (&(*session)->internals.application_data_buffer); + MHD_gtls_buffer_init (&(*session)->internals.handshake_data_buffer); + MHD_gtls_buffer_init (&(*session)->internals.handshake_hash_buffer); + MHD_gtls_buffer_init (&(*session)->internals.ia_data_buffer); + + MHD_gtls_buffer_init (&(*session)->internals.record_send_buffer); + MHD_gtls_buffer_init (&(*session)->internals.record_recv_buffer); + + MHD_gtls_buffer_init (&(*session)->internals.handshake_send_buffer); + MHD_gtls_buffer_init (&(*session)->internals.handshake_recv_buffer); + + (*session)->key = MHD_gnutls_calloc (1, sizeof (struct MHD_gtls_key)); + if ((*session)->key == NULL) + { + cleanup_session:MHD_gnutls_free (*session); + *session = NULL; + return GNUTLS_E_MEMORY_ERROR; + } + + (*session)->internals.expire_time = DEFAULT_EXPIRE_TIME; /* one hour default */ + + MHD__gnutls_dh_set_prime_bits ((*session), MIN_DH_BITS); + + MHD__gnutls_transport_set_lowat ((*session), DEFAULT_LOWAT); /* the default for tcp */ + + MHD__gnutls_handshake_set_max_packet_length ((*session), + MAX_HANDSHAKE_PACKET_SIZE); + + /* Allocate a minimum size for recv_data + * This is allocated in order to avoid small messages, making + * the receive procedure slow. + */ + (*session)->internals.record_recv_buffer.data + = MHD_gnutls_malloc (INITIAL_RECV_BUFFER_SIZE); + if ((*session)->internals.record_recv_buffer.data == NULL) + { + MHD_gnutls_free ((*session)->key); + goto cleanup_session; + } + + /* set the socket pointers to -1; */ + (*session)->internals.transport_recv_ptr = (MHD_gnutls_transport_ptr_t) - 1; + (*session)->internals.transport_send_ptr = (MHD_gnutls_transport_ptr_t) - 1; + + /* set the default maximum record size for TLS + */ + (*session)->security_parameters.max_record_recv_size + = DEFAULT_MAX_RECORD_SIZE; + (*session)->security_parameters.max_record_send_size + = DEFAULT_MAX_RECORD_SIZE; + + /* everything else not initialized here is initialized + * as NULL or 0. This is why calloc is used. + */ + + MHD_gtls_handshake_internal_state_clear (*session); + + return 0; +} + + +/** + * MHD__gnutls_deinit - This function clears all buffers associated with a session + * @session: is a #MHD_gtls_session_t structure. + * + * This function clears all buffers associated with the @session. + * This function will also remove session data from the session + * database if the session was terminated abnormally. + **/ +void +MHD__gnutls_deinit (MHD_gtls_session_t session) +{ + + if (session == NULL) + return; + + /* remove auth info firstly */ + MHD_gtls_free_auth_info (session); + + MHD_gtls_handshake_internal_state_clear (session); + MHD__gnutls_handshake_io_buffer_clear (session); + + MHD__gnutls_free_datum (&session->connection_state.read_mac_secret); + MHD__gnutls_free_datum (&session->connection_state.write_mac_secret); + + MHD_gtls_buffer_clear (&session->internals.ia_data_buffer); + MHD_gtls_buffer_clear (&session->internals.handshake_hash_buffer); + MHD_gtls_buffer_clear (&session->internals.handshake_data_buffer); + MHD_gtls_buffer_clear (&session->internals.application_data_buffer); + MHD_gtls_buffer_clear (&session->internals.record_recv_buffer); + MHD_gtls_buffer_clear (&session->internals.record_send_buffer); + + MHD__gnutls_credentials_clear (session); + MHD_gtls_selected_certs_deinit (session); + + if (session->connection_state.read_cipher_state != NULL) + MHD_gnutls_cipher_deinit (session->connection_state.read_cipher_state); + if (session->connection_state.write_cipher_state != NULL) + MHD_gnutls_cipher_deinit (session->connection_state.write_cipher_state); + + MHD__gnutls_free_datum (&session->cipher_specs.server_write_mac_secret); + MHD__gnutls_free_datum (&session->cipher_specs.client_write_mac_secret); + MHD__gnutls_free_datum (&session->cipher_specs.server_write_IV); + MHD__gnutls_free_datum (&session->cipher_specs.client_write_IV); + MHD__gnutls_free_datum (&session->cipher_specs.server_write_key); + MHD__gnutls_free_datum (&session->cipher_specs.client_write_key); + + if (session->key != NULL) + { + MHD_gtls_mpi_release (&session->key->KEY); + MHD_gtls_mpi_release (&session->key->client_Y); + MHD_gtls_mpi_release (&session->key->client_p); + MHD_gtls_mpi_release (&session->key->client_g); + + MHD_gtls_mpi_release (&session->key->u); + MHD_gtls_mpi_release (&session->key->a); + MHD_gtls_mpi_release (&session->key->x); + MHD_gtls_mpi_release (&session->key->A); + MHD_gtls_mpi_release (&session->key->B); + MHD_gtls_mpi_release (&session->key->b); + + /* RSA */ + MHD_gtls_mpi_release (&session->key->rsa[0]); + MHD_gtls_mpi_release (&session->key->rsa[1]); + + MHD_gtls_mpi_release (&session->key->dh_secret); + MHD_gnutls_free (session->key); + + session->key = NULL; + } + + memset (session, 0, sizeof (struct MHD_gtls_session_int)); + MHD_gnutls_free (session); +} + +/* Returns the minimum prime bits that are acceptable. + */ +int +MHD_gtls_dh_get_allowed_prime_bits (MHD_gtls_session_t session) +{ + return session->internals.dh_prime_bits; +} + +int +MHD_gtls_dh_set_peer_public (MHD_gtls_session_t session, mpi_t public) +{ + MHD_gtls_dh_info_st *dh; + int ret; + + switch (MHD_gtls_auth_get_type (session)) + { + case MHD_GNUTLS_CRD_CERTIFICATE: + { + cert_auth_info_t info; + + info = MHD_gtls_get_auth_info (session); + if (info == NULL) + return GNUTLS_E_INTERNAL_ERROR; + + dh = &info->dh; + break; + } + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + ret = MHD_gtls_mpi_dprint_lz (&dh->public_key, public); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return 0; +} + +int +MHD_gtls_dh_set_secret_bits (MHD_gtls_session_t session, unsigned bits) +{ + switch (MHD_gtls_auth_get_type (session)) + { + case MHD_GNUTLS_CRD_CERTIFICATE: + { + cert_auth_info_t info; + + info = MHD_gtls_get_auth_info (session); + if (info == NULL) + return GNUTLS_E_INTERNAL_ERROR; + + info->dh.secret_bits = bits; + break; + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + } + + return 0; +} + +/* This function will set in the auth info structure the + * RSA exponent and the modulus. + */ +int +MHD_gtls_rsa_export_set_pubkey (MHD_gtls_session_t session, + mpi_t exponent, mpi_t modulus) +{ + cert_auth_info_t info; + int ret; + + info = MHD_gtls_get_auth_info (session); + if (info == NULL) + return GNUTLS_E_INTERNAL_ERROR; + + ret = MHD_gtls_mpi_dprint_lz (&info->rsa_export.modulus, modulus); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = MHD_gtls_mpi_dprint_lz (&info->rsa_export.exponent, exponent); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD__gnutls_free_datum (&info->rsa_export.modulus); + return ret; + } + + return 0; +} + +/* Sets the prime and the generator in the auth info structure. + */ +int +MHD_gtls_dh_set_group (MHD_gtls_session_t session, mpi_t gen, mpi_t prime) +{ + MHD_gtls_dh_info_st *dh; + int ret; + + switch (MHD_gtls_auth_get_type (session)) + { + case MHD_GNUTLS_CRD_CERTIFICATE: + { + cert_auth_info_t info; + + info = MHD_gtls_get_auth_info (session); + if (info == NULL) + return GNUTLS_E_INTERNAL_ERROR; + + dh = &info->dh; + break; + } + default: + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* prime + */ + ret = MHD_gtls_mpi_dprint_lz (&dh->prime, prime); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* generator + */ + ret = MHD_gtls_mpi_dprint_lz (&dh->generator, gen); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD__gnutls_free_datum (&dh->prime); + return ret; + } + + return 0; +} + +/** + * MHD__gnutls_certificate_send_x509_rdn_sequence - This function will order gnutls to send or not the x.509 rdn sequence + * @session: is a pointer to a #MHD_gtls_session_t structure. + * @status: is 0 or 1 + * + * If status is non zero, this function will order gnutls not to send + * the rdnSequence in the certificate request message. That is the + * server will not advertize it's trusted CAs to the peer. If status + * is zero then the default behaviour will take effect, which is to + * advertize the server's trusted CAs. + * + * This function has no effect in clients, and in authentication + * methods other than certificate with X.509 certificates. + **/ +void +MHD__gnutls_certificate_send_x509_rdn_sequence (MHD_gtls_session_t session, + int status) +{ + session->internals.ignore_rdn_sequence = status; +} + +/*- + * MHD__gnutls_record_set_default_version - Used to set the default version for the first record packet + * @session: is a #MHD_gtls_session_t structure. + * @major: is a tls major version + * @minor: is a tls minor version + * + * This function sets the default version that we will use in the first + * record packet (client hello). This function is only useful to people + * that know TLS internals and want to debug other implementations. + * + -*/ +void +MHD__gnutls_record_set_default_version (MHD_gtls_session_t session, + unsigned char major, + unsigned char minor) +{ + session->internals.default_record_version[0] = major; + session->internals.default_record_version[1] = minor; +} + +inline static int +MHD__gnutls_cal_PRF_A (enum MHD_GNUTLS_HashAlgorithm algorithm, + const void *secret, + int secret_size, + const void *seed, int seed_size, void *result) +{ + mac_hd_t td1; + + td1 = MHD_gtls_MHD_hmac_init (algorithm, secret, secret_size); + if (td1 == GNUTLS_MAC_FAILED) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + MHD_gnutls_hash (td1, seed, seed_size); + MHD_gnutls_MHD_hmac_deinit (td1, result); + + return 0; +} + +#define MAX_SEED_SIZE 200 + +/* Produces "total_bytes" bytes using the hash algorithm specified. + * (used in the PRF function) + */ +static int +MHD__gnutls_P_hash (enum MHD_GNUTLS_HashAlgorithm algorithm, + const opaque * secret, + int secret_size, + const opaque * seed, + int seed_size, int total_bytes, opaque * ret) +{ + + mac_hd_t td2; + int i, times, how, blocksize, A_size; + opaque final[20], Atmp[MAX_SEED_SIZE]; + int output_bytes, result; + + if (seed_size > MAX_SEED_SIZE || total_bytes <= 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + blocksize = MHD_gnutls_hash_get_algo_len (algorithm); + + output_bytes = 0; + do + { + output_bytes += blocksize; + } + while (output_bytes < total_bytes); + + /* calculate A(0) */ + + memcpy (Atmp, seed, seed_size); + A_size = seed_size; + + times = output_bytes / blocksize; + + for (i = 0; i < times; i++) + { + td2 = MHD_gtls_MHD_hmac_init (algorithm, secret, secret_size); + if (td2 == GNUTLS_MAC_FAILED) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + /* here we calculate A(i+1) */ + if ((result = + MHD__gnutls_cal_PRF_A (algorithm, secret, secret_size, Atmp, + A_size, Atmp)) < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_MHD_hmac_deinit (td2, final); + return result; + } + + A_size = blocksize; + + MHD_gnutls_hash (td2, Atmp, A_size); + MHD_gnutls_hash (td2, seed, seed_size); + MHD_gnutls_MHD_hmac_deinit (td2, final); + + if ((1 + i) * blocksize < total_bytes) + { + how = blocksize; + } + else + { + how = total_bytes - (i) * blocksize; + } + + if (how > 0) + { + memcpy (&ret[i * blocksize], final, how); + } + } + + return 0; +} + +/* Xor's two buffers and puts the output in the first one. + */ +inline static void +MHD__gnutls_xor (opaque * o1, opaque * o2, int length) +{ + int i; + for (i = 0; i < length; i++) + { + o1[i] ^= o2[i]; + } +} + +#define MAX_PRF_BYTES 200 + +/* The PRF function expands a given secret + * needed by the TLS specification. ret must have a least total_bytes + * available. + */ +int +MHD_gtls_PRF (MHD_gtls_session_t session, + const opaque * secret, + int secret_size, + const char *label, + int label_size, + const opaque * seed, int seed_size, int total_bytes, void *ret) +{ + int l_s, s_seed_size; + const opaque *s1, *s2; + opaque s_seed[MAX_SEED_SIZE]; + opaque o1[MAX_PRF_BYTES], o2[MAX_PRF_BYTES]; + int result; + enum MHD_GNUTLS_Protocol ver = MHD__gnutls_protocol_get_version (session); + + if (total_bytes > MAX_PRF_BYTES) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + /* label+seed = s_seed */ + s_seed_size = seed_size + label_size; + + if (s_seed_size > MAX_SEED_SIZE) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + memcpy (s_seed, label, label_size); + memcpy (&s_seed[label_size], seed, seed_size); + + if (ver >= MHD_GNUTLS_PROTOCOL_TLS1_2) + { + result = + MHD__gnutls_P_hash (MHD_GNUTLS_MAC_SHA1, secret, secret_size, s_seed, + s_seed_size, total_bytes, ret); + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + } + else + { + l_s = secret_size / 2; + + s1 = &secret[0]; + s2 = &secret[l_s]; + + if (secret_size % 2 != 0) + { + l_s++; + } + + result = + MHD__gnutls_P_hash (MHD_GNUTLS_MAC_MD5, s1, l_s, s_seed, s_seed_size, + total_bytes, o1); + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + result = + MHD__gnutls_P_hash (MHD_GNUTLS_MAC_SHA1, s2, l_s, s_seed, s_seed_size, + total_bytes, o2); + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + MHD__gnutls_xor (o1, o2, total_bytes); + + memcpy (ret, o1, total_bytes); + } + + return 0; /* ok */ + +} + + +/*- + * MHD_gtls_session_is_export - Used to check whether this session is of export grade + * @session: is a #MHD_gtls_session_t structure. + * + * This function will return non zero if this session is of export grade. + * + -*/ +int +MHD_gtls_session_is_export (MHD_gtls_session_t session) +{ + enum MHD_GNUTLS_CipherAlgorithm cipher; + + cipher = + MHD_gtls_cipher_suite_get_cipher_algo (&session->security_parameters. + current_cipher_suite); + + if (MHD_gtls_cipher_get_export_flag (cipher) != 0) + return 1; + + return 0; +} + +/** + * MHD__gnutls_record_get_direction - This function will return the direction of the last interrupted function call + * @session: is a #MHD_gtls_session_t structure. + * + * This function provides information about the internals of the + * record protocol and is only useful if a prior gnutls function call + * (e.g. MHD__gnutls_handshake()) was interrupted for some reason, that + * is, if a function returned %GNUTLS_E_INTERRUPTED or + * %GNUTLS_E_AGAIN. In such a case, you might want to call select() + * or poll() before calling the interrupted gnutls function again. + * To tell you whether a file descriptor should be selected for + * either reading or writing, MHD__gnutls_record_get_direction() returns 0 + * if the interrupted function was trying to read data, and 1 if it + * was trying to write data. + * + * Returns: 0 if trying to read data, 1 if trying to write data. + **/ +int +MHD__gnutls_record_get_direction (MHD_gtls_session_t session) +{ + return session->internals.direction; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_state.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_state.h new file mode 100644 index 0000000000..a6ff58929f --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_state.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_STATE_H +# define GNUTLS_STATE_H + +#include <gnutls_int.h> + +void MHD__gnutls_session_cert_type_set (MHD_gtls_session_t session, + enum MHD_GNUTLS_CertificateType); +enum MHD_GNUTLS_KeyExchangeAlgorithm MHD_gnutls_kx_get (MHD_gtls_session_t + session); +enum MHD_GNUTLS_CipherAlgorithm MHD_gnutls_cipher_get (MHD_gtls_session_t + session); +enum MHD_GNUTLS_CertificateType +MHD_gnutls_certificate_type_get (MHD_gtls_session_t); + +#include <gnutls_auth_int.h> + +#define CHECK_AUTH(auth, ret) if (MHD_gtls_auth_get_type(session) != auth) { \ + MHD_gnutls_assert(); \ + return ret; \ + } + +#endif + +int MHD_gtls_session_cert_type_supported (MHD_gtls_session_t, + enum MHD_GNUTLS_CertificateType); + +int MHD_gtls_dh_set_secret_bits (MHD_gtls_session_t session, unsigned bits); + +int MHD_gtls_dh_set_peer_public (MHD_gtls_session_t session, mpi_t public); +int MHD_gtls_dh_set_group (MHD_gtls_session_t session, mpi_t gen, + mpi_t prime); + +int MHD_gtls_dh_get_allowed_prime_bits (MHD_gtls_session_t session); +void MHD_gtls_handshake_internal_state_clear (MHD_gtls_session_t); + +int MHD_gtls_rsa_export_set_pubkey (MHD_gtls_session_t session, + mpi_t exponent, mpi_t modulus); + +int MHD_gtls_session_is_resumable (MHD_gtls_session_t session); +int MHD_gtls_session_is_export (MHD_gtls_session_t session); + +int MHD_gtls_openpgp_send_fingerprint (MHD_gtls_session_t session); + +int MHD_gtls_PRF (MHD_gtls_session_t session, + const opaque * secret, int secret_size, + const char *label, int label_size, + const opaque * seed, int seed_size, + int total_bytes, void *ret); + +int MHD__gnutls_init (MHD_gtls_session_t * session, + MHD_gnutls_connection_end_t con_end); + +#define DEFAULT_CERT_TYPE MHD_GNUTLS_CRT_X509 diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_str.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_str.c new file mode 100644 index 0000000000..c8f17c2558 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_str.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_num.h> +#include <gnutls_str.h> + +/* These function are like strcat, strcpy. They only + * do bound checking (they shouldn't cause buffer overruns), + * and they always produce null terminated strings. + * + * They should be used only with null terminated strings. + */ +void +MHD_gtls_str_cat (char *dest, size_t dest_tot_size, const char *src) +{ + size_t str_size = strlen (src); + size_t dest_size = strlen (dest); + + if (dest_tot_size - dest_size > str_size) + { + strcat (dest, src); + } + else + { + if (dest_tot_size - dest_size > 0) + { + strncat (dest, src, (dest_tot_size - dest_size) - 1); + dest[dest_tot_size - 1] = 0; + } + } +} + +void +MHD_gtls_str_cpy (char *dest, size_t dest_tot_size, const char *src) +{ + size_t str_size = strlen (src); + + if (dest_tot_size > str_size) + { + strcpy (dest, src); + } + else + { + if (dest_tot_size > 0) + { + strncpy (dest, src, (dest_tot_size) - 1); + dest[dest_tot_size - 1] = 0; + } + } +} + +void +MHD_gtls_string_init (MHD_gtls_string * str, + MHD_gnutls_alloc_function alloc_func, + MHD_gnutls_realloc_function realloc_func, + MHD_gnutls_free_function free_func) +{ + str->data = NULL; + str->max_length = 0; + str->length = 0; + + str->alloc_func = alloc_func; + str->free_func = free_func; + str->realloc_func = realloc_func; +} + +void +MHD_gtls_string_clear (MHD_gtls_string * str) +{ + if (str == NULL || str->data == NULL) + return; + str->free_func (str->data); + + str->data = NULL; + str->max_length = 0; + str->length = 0; +} + +#define MIN_CHUNK 256 + + +int +MHD_gtls_string_append_data (MHD_gtls_string * dest, + const void *data, size_t data_size) +{ + size_t tot_len = data_size + dest->length; + + if (dest->max_length >= tot_len) + { + memcpy (&dest->data[dest->length], data, data_size); + dest->length = tot_len; + + return tot_len; + } + else + { + size_t new_len = + MAX (data_size, MIN_CHUNK) + MAX (dest->max_length, MIN_CHUNK); + dest->data = dest->realloc_func (dest->data, new_len); + if (dest->data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + dest->max_length = new_len; + + memcpy (&dest->data[dest->length], data, data_size); + dest->length = tot_len; + + return tot_len; + } +} + +/* Converts the given string (old) to hex. A buffer must be provided + * to hold the new hex string. The new string will be null terminated. + * If the buffer does not have enough space to hold the string, a + * truncated hex string is returned (always null terminated). + */ +char * +MHD_gtls_bin2hex (const void *_old, + size_t oldlen, char *buffer, size_t buffer_size) +{ + unsigned int i, j; + const opaque *old = _old; + + for (i = j = 0; i < oldlen && j + 2 < buffer_size; j += 2) + { + sprintf (&buffer[j], "%.2x", old[i]); + i++; + } + buffer[j] = '\0'; + + return buffer; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_str.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_str.h new file mode 100644 index 0000000000..51ed1bd155 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_str.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef GNUTLS_STR_H +#define GNUTLS_STR_H + +#include <gnutls_int.h> + +void MHD_gtls_str_cpy (char *dest, size_t dest_tot_size, const char *src); +void MHD_gtls_str_cat (char *dest, size_t dest_tot_size, const char *src); + +typedef struct +{ + opaque *data; + size_t max_length; + size_t length; + MHD_gnutls_realloc_function realloc_func; + MHD_gnutls_alloc_function alloc_func; + MHD_gnutls_free_function free_func; +} MHD_gtls_string; + +void MHD_gtls_string_init (MHD_gtls_string *, MHD_gnutls_alloc_function, + MHD_gnutls_realloc_function, + MHD_gnutls_free_function); +void MHD_gtls_string_clear (MHD_gtls_string *); + +int MHD_gtls_string_append_data (MHD_gtls_string *, const void *data, + size_t data_size); +char *MHD_gtls_bin2hex (const void *old, size_t oldlen, char *buffer, + size_t buffer_size); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_supplemental.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_supplemental.c new file mode 100644 index 0000000000..3b9641d4e4 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_supplemental.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2007 Free Software Foundation + * + * Author: Simon Josefsson + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains support functions for 'TLS Handshake Message for + * Supplemental Data' (RFC 4680). + * + * The idea here is simple. MHD__gnutls_handshake() in gnuts_handshake.c + * will call MHD__gnutls_gen_supplemental and MHD__gnutls_parse_supplemental + * when some extension requested that supplemental data be sent or + * received. Extension request this by setting the flags + * do_recv_supplemental or do_send_supplemental in the session. + * + * The functions in this file iterate through the MHD__gnutls_supplemental + * array, and calls the send/recv functions for each respective data + * type. + * + * The receive function of each data type is responsible for decoding + * its own data. If the extension did not expect to receive + * supplemental data, it should return GNUTLS_E_UNEXPECTED_PACKET. + * Otherwise, it just parse the data as normal. + * + * The send function needs to append the 2-byte data format type, and + * append the 2-byte length of its data, and the data. If it doesn't + * want to send any data, it is fine to return without doing anything. + */ + +#include "gnutls_int.h" +#include "gnutls_supplemental.h" +#include "gnutls_errors.h" +#include "gnutls_num.h" + +typedef int (*supp_recv_func) (MHD_gtls_session_t session, + const opaque * data, size_t data_size); +typedef int (*supp_send_func) (MHD_gtls_session_t session, + MHD_gtls_buffer * buf); + +typedef struct +{ + const char *name; + MHD_gnutls_supplemental_data_format_type_t type; + supp_recv_func supp_recv_func; + supp_send_func supp_send_func; +} MHD_gnutls_supplemental_entry; + +MHD_gnutls_supplemental_entry MHD__gnutls_supplemental[] = { + {0, 0, 0, 0} +}; + + +static supp_recv_func +get_supp_func_recv (MHD_gnutls_supplemental_data_format_type_t type) +{ + MHD_gnutls_supplemental_entry *p; + + for (p = MHD__gnutls_supplemental; p->name != NULL; p++) + if (p->type == type) + return p->supp_recv_func; + + return NULL; +} + +int +MHD__gnutls_gen_supplemental (MHD_gtls_session_t session, + MHD_gtls_buffer * buf) +{ + MHD_gnutls_supplemental_entry *p; + int ret; + + /* Make room for 3 byte length field. */ + ret = MHD_gtls_buffer_append (buf, "\0\0\0", 3); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + for (p = MHD__gnutls_supplemental; p->name; p++) + { + supp_send_func supp_send = p->supp_send_func; + size_t sizepos = buf->length; + int ret; + + /* Make room for supplement type and length byte length field. */ + ret = MHD_gtls_buffer_append (buf, "\0\0\0\0", 4); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = supp_send (session, buf); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + /* If data were added, store type+length, otherwise reset. */ + if (buf->length > sizepos + 4) + { + buf->data[sizepos] = 0; + buf->data[sizepos + 1] = p->type; + buf->data[sizepos + 2] = ((buf->length - sizepos - 4) >> 8) & 0xFF; + buf->data[sizepos + 3] = (buf->length - sizepos - 4) & 0xFF; + } + else + buf->length -= 4; + } + + buf->data[0] = ((buf->length - 3) >> 16) & 0xFF; + buf->data[1] = ((buf->length - 3) >> 8) & 0xFF; + buf->data[2] = (buf->length - 3) & 0xFF; + + MHD__gnutls_debug_log ("EXT[%x]: Sending %d bytes of supplemental data\n", + session, buf->length); + + return buf->length; +} + +int +MHD__gnutls_parse_supplemental (MHD_gtls_session_t session, + const uint8_t * data, int datalen) +{ + const opaque *p = data; + ssize_t dsize = datalen; + size_t total_size; + + DECR_LEN (dsize, 3); + total_size = MHD_gtls_read_uint24 (p); + p += 3; + + if (dsize != total_size) + { + MHD_gnutls_assert (); + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + + do + { + uint16_t supp_data_type; + uint16_t supp_data_length; + supp_recv_func recv_func; + + DECR_LEN (dsize, 2); + supp_data_type = MHD_gtls_read_uint16 (p); + p += 2; + + DECR_LEN (dsize, 2); + supp_data_length = MHD_gtls_read_uint16 (p); + p += 2; + + MHD__gnutls_debug_log + ("EXT[%x]: Got supplemental type=%02x length=%d\n", session, + supp_data_type, supp_data_length); + + recv_func = get_supp_func_recv (supp_data_type); + if (recv_func) + { + int ret = recv_func (session, p, supp_data_length); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + else + { + MHD_gnutls_assert (); + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + + DECR_LEN (dsize, supp_data_length); + p += supp_data_length; + } + while (dsize > 0); + + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_supplemental.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_supplemental.h new file mode 100644 index 0000000000..b7ad0c2923 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_supplemental.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007 Free Software Foundation + * + * Author: Simon Josefsson + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> + +int MHD__gnutls_parse_supplemental (MHD_gtls_session_t session, + const uint8_t * data, int data_size); +int MHD__gnutls_gen_supplemental (MHD_gtls_session_t session, + MHD_gtls_buffer * buf); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_ui.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_ui.c new file mode 100644 index 0000000000..5a1bfd3d18 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_ui.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains certificate authentication functions to be exported in the + * API and did not fit elsewhere. + */ + +#include <gnutls_int.h> +#include <auth_cert.h> +#include <gnutls_errors.h> +#include <gnutls_auth_int.h> +#include <gnutls_state.h> +#include <gnutls_datum.h> + +/* ANON & DHE */ + +/** + * MHD__gnutls_dh_set_prime_bits - Used to set the bits for a DH ciphersuite + * @session: is a #MHD_gtls_session_t structure. + * @bits: is the number of bits + * + * This function sets the number of bits, for use in an + * Diffie Hellman key exchange. This is used both in DH ephemeral and + * DH anonymous cipher suites. This will set the + * minimum size of the prime that will be used for the handshake. + * + * In the client side it sets the minimum accepted number of bits. + * If a server sends a prime with less bits than that + * GNUTLS_E_DH_PRIME_UNACCEPTABLE will be returned by the + * handshake. + * + **/ +void +MHD__gnutls_dh_set_prime_bits (MHD_gtls_session_t session, unsigned int bits) +{ + session->internals.dh_prime_bits = bits; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_x509.c b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_x509.c new file mode 100644 index 0000000000..685c9642bf --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_x509.c @@ -0,0 +1,604 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include "gnutls_auth_int.h" +#include "gnutls_errors.h" +#include <gnutls_cert.h> +#include <auth_cert.h> +#include "gnutls_dh.h" +#include "gnutls_num.h" +#include "gnutls_datum.h" +#include <gnutls_pk.h> +#include <gnutls_algorithms.h> +#include <gnutls_global.h> +#include <gnutls_record.h> +#include <gnutls_sig.h> +#include <gnutls_state.h> +#include <gnutls_pk.h> +#include <gnutls_str.h> +#include <debug.h> +#include <x509_b64.h> +#include <gnutls_x509.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +/* x509 */ +#include "common.h" +#include "x509.h" +#include "mpi.h" +#include "privkey.h" + + +/* + * some x509 certificate parsing functions. + */ + +/* Check if the number of bits of the key in the certificate + * is unacceptable. + */ +inline static int +check_bits (MHD_gnutls_x509_crt_t crt, unsigned int max_bits) +{ + int ret; + unsigned int bits; + + ret = MHD_gnutls_x509_crt_get_pk_algorithm (crt, &bits); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + if (bits > max_bits && max_bits > 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_CONSTRAINT_ERROR; + } + + return 0; +} + + +#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) { \ + if (peer_certificate_list[x]) \ + MHD_gnutls_x509_crt_deinit(peer_certificate_list[x]); \ + } \ + MHD_gnutls_free( peer_certificate_list) + +/* + * Read certificates and private keys, from memory etc. + */ + +/* returns error if the certificate has different algorithm than + * the given key parameters. + */ +static int +MHD__gnutls_check_key_cert_match (MHD_gtls_cert_credentials_t res) +{ + MHD_gnutls_datum_t cid; + MHD_gnutls_datum_t kid; + unsigned pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm; + + if (res->pkey[res->ncerts - 1].pk_algorithm != pk) + { + MHD_gnutls_assert (); + return GNUTLS_E_CERTIFICATE_KEY_MISMATCH; + } + + MHD__gnutls_x509_write_rsa_params (res->pkey[res->ncerts - 1].params, + res->pkey[res->ncerts - + 1].params_size, &kid); + + + MHD__gnutls_x509_write_rsa_params (res-> + cert_list[res->ncerts - 1][0].params, + res->cert_list[res->ncerts - + 1][0].params_size, &cid); + + if (cid.size != kid.size) + { + MHD_gnutls_assert (); + MHD__gnutls_free_datum (&kid); + MHD__gnutls_free_datum (&cid); + return GNUTLS_E_CERTIFICATE_KEY_MISMATCH; + } + + if (memcmp (kid.data, cid.data, kid.size) != 0) + { + MHD_gnutls_assert (); + MHD__gnutls_free_datum (&kid); + MHD__gnutls_free_datum (&cid); + return GNUTLS_E_CERTIFICATE_KEY_MISMATCH; + } + + MHD__gnutls_free_datum (&kid); + MHD__gnutls_free_datum (&cid); + return 0; +} + +/* Reads a DER encoded certificate list from memory and stores it to + * a MHD_gnutls_cert structure. + * Returns the number of certificates parsed. + */ +static int +parse_crt_mem (MHD_gnutls_cert ** cert_list, unsigned *ncerts, + MHD_gnutls_x509_crt_t cert) +{ + int i; + int ret; + + i = *ncerts + 1; + + *cert_list = + (MHD_gnutls_cert *) MHD_gtls_realloc_fast (*cert_list, + i * sizeof (MHD_gnutls_cert)); + + if (*cert_list == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + ret = MHD_gtls_x509_crt_to_gcert (&cert_list[0][i - 1], cert, 0); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + *ncerts = i; + + return 1; /* one certificate parsed */ +} + +/* Reads a DER encoded certificate list from memory and stores it to + * a MHD_gnutls_cert structure. + * Returns the number of certificates parsed. + */ +static int +parse_der_cert_mem (MHD_gnutls_cert ** cert_list, unsigned *ncerts, + const void *input_cert, int input_cert_size) +{ + MHD_gnutls_datum_t tmp; + MHD_gnutls_x509_crt_t cert; + int ret; + + ret = MHD_gnutls_x509_crt_init (&cert); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + tmp.data = (opaque *) input_cert; + tmp.size = input_cert_size; + + ret = MHD_gnutls_x509_crt_import (cert, &tmp, GNUTLS_X509_FMT_DER); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_x509_crt_deinit (cert); + return ret; + } + + ret = parse_crt_mem (cert_list, ncerts, cert); + MHD_gnutls_x509_crt_deinit (cert); + + return ret; +} + +/* Reads a base64 encoded certificate list from memory and stores it to + * a MHD_gnutls_cert structure. Returns the number of certificate parsed. + */ +static int +parse_pem_cert_mem (MHD_gnutls_cert ** cert_list, unsigned *ncerts, + const char *input_cert, int input_cert_size) +{ + int size, siz2, i; + const char *ptr; + opaque *ptr2; + MHD_gnutls_datum_t tmp; + int ret, count; + + /* move to the certificate + */ + ptr = memmem (input_cert, input_cert_size, + PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1); + if (ptr == NULL) + ptr = memmem (input_cert, input_cert_size, + PEM_CERT_SEP2, sizeof (PEM_CERT_SEP2) - 1); + + if (ptr == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + size = input_cert_size - (ptr - input_cert); + + i = *ncerts + 1; + count = 0; + + do + { + + siz2 = + MHD__gnutls_fbase64_decode (NULL, (const unsigned char *) ptr, size, + &ptr2); + + if (siz2 < 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + + *cert_list = + (MHD_gnutls_cert *) MHD_gtls_realloc_fast (*cert_list, + i * + sizeof (MHD_gnutls_cert)); + + if (*cert_list == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + tmp.data = ptr2; + tmp.size = siz2; + + ret = MHD_gtls_x509_raw_cert_to_gcert (&cert_list[0][i - 1], &tmp, 0); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + MHD__gnutls_free_datum (&tmp); /* free ptr2 */ + + /* now we move ptr after the pem header + */ + ptr++; + /* find the next certificate (if any) + */ + size = input_cert_size - (ptr - input_cert); + + if (size > 0) + { + char *ptr3; + + ptr3 = memmem (ptr, size, PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1); + if (ptr3 == NULL) + ptr3 = memmem (ptr, size, PEM_CERT_SEP2, + sizeof (PEM_CERT_SEP2) - 1); + + ptr = ptr3; + } + else + ptr = NULL; + + i++; + count++; + + } + while (ptr != NULL); + + *ncerts = i - 1; + + return count; +} + + + +/* Reads a DER or PEM certificate from memory + */ +static int +read_cert_mem (MHD_gtls_cert_credentials_t res, const void *cert, + int cert_size, MHD_gnutls_x509_crt_fmt_t type) +{ + int ret; + + /* allocate space for the certificate to add + */ + res->cert_list = MHD_gtls_realloc_fast (res->cert_list, + (1 + + res->ncerts) * + sizeof (MHD_gnutls_cert *)); + if (res->cert_list == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + res->cert_list_length = MHD_gtls_realloc_fast (res->cert_list_length, + (1 + + res->ncerts) * + sizeof (int)); + if (res->cert_list_length == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + res->cert_list[res->ncerts] = NULL; /* for realloc */ + res->cert_list_length[res->ncerts] = 0; + + if (type == GNUTLS_X509_FMT_DER) + ret = parse_der_cert_mem (&res->cert_list[res->ncerts], + &res->cert_list_length[res->ncerts], + cert, cert_size); + else + ret = + parse_pem_cert_mem (&res->cert_list[res->ncerts], + &res->cert_list_length[res->ncerts], cert, + cert_size); + + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return ret; +} + + +int +MHD__gnutls_x509_privkey_to_gkey (MHD_gnutls_privkey * dest, + MHD_gnutls_x509_privkey_t src) +{ + int i, ret; + + memset (dest, 0, sizeof (MHD_gnutls_privkey)); + + for (i = 0; i < src->params_size; i++) + { + dest->params[i] = MHD__gnutls_mpi_copy (src->params[i]); + if (dest->params[i] == NULL) + { + MHD_gnutls_assert (); + ret = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + } + + dest->pk_algorithm = src->pk_algorithm; + dest->params_size = src->params_size; + + return 0; + +cleanup: + + for (i = 0; i < src->params_size; i++) + { + MHD_gtls_mpi_release (&dest->params[i]); + } + return ret; +} + +void +MHD_gtls_gkey_deinit (MHD_gnutls_privkey * key) +{ + int i; + if (key == NULL) + return; + + for (i = 0; i < key->params_size; i++) + { + MHD_gtls_mpi_release (&key->params[i]); + } +} + +int +MHD__gnutls_x509_raw_privkey_to_gkey (MHD_gnutls_privkey * privkey, + const MHD_gnutls_datum_t * raw_key, + MHD_gnutls_x509_crt_fmt_t type) +{ + MHD_gnutls_x509_privkey_t tmpkey; + int ret; + + ret = MHD_gnutls_x509_privkey_init (&tmpkey); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + + ret = MHD_gnutls_x509_privkey_import (tmpkey, raw_key, type); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_x509_privkey_deinit (tmpkey); + return ret; + } + + ret = MHD__gnutls_x509_privkey_to_gkey (privkey, tmpkey); + if (ret < 0) + { + MHD_gnutls_assert (); + MHD_gnutls_x509_privkey_deinit (tmpkey); + return ret; + } + + MHD_gnutls_x509_privkey_deinit (tmpkey); + + return 0; +} + +/* Reads a PEM encoded PKCS-1 RSA/DSA private key from memory. Type + * indicates the certificate format. KEY can be NULL, to indicate + * that GnuTLS doesn't know the private key. + */ +static int +read_key_mem (MHD_gtls_cert_credentials_t res, + const void *key, int key_size, MHD_gnutls_x509_crt_fmt_t type) +{ + int ret; + MHD_gnutls_datum_t tmp; + + /* allocate space for the pkey list + */ + res->pkey = + MHD_gtls_realloc_fast (res->pkey, + (res->ncerts + 1) * sizeof (MHD_gnutls_privkey)); + if (res->pkey == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + if (key) + { + tmp.data = (opaque *) key; + tmp.size = key_size; + + ret = + MHD__gnutls_x509_raw_privkey_to_gkey (&res->pkey[res->ncerts], &tmp, + type); + if (ret < 0) + { + MHD_gnutls_assert (); + return ret; + } + } + else + memset (&res->pkey[res->ncerts], 0, sizeof (MHD_gnutls_privkey)); + + return 0; +} + +/** + * MHD__gnutls_certificate_set_x509_key_mem - Used to set keys in a MHD_gtls_cert_credentials_t structure + * @res: is an #MHD_gtls_cert_credentials_t structure. + * @cert: contains a certificate list (path) for the specified private key + * @key: is the private key, or %NULL + * @type: is PEM or DER + * + * This function sets a certificate/private key pair in the + * MHD_gtls_cert_credentials_t structure. This function may be called + * more than once (in case multiple keys/certificates exist for the + * server). + * + * Currently are supported: RSA PKCS-1 encoded private keys, + * DSA private keys. + * + * DSA private keys are encoded the OpenSSL way, which is an ASN.1 + * DER sequence of 6 INTEGERs - version, p, q, g, pub, priv. + * + * Note that the keyUsage (2.5.29.15) PKIX extension in X.509 certificates + * is supported. This means that certificates intended for signing cannot + * be used for ciphersuites that require encryption. + * + * If the certificate and the private key are given in PEM encoding + * then the strings that hold their values must be null terminated. + * + * The @key may be %NULL if you are using a sign callback, see + * MHD_gtls_sign_callback_set(). + * + * Returns: %GNUTLS_E_SUCCESS on success, or an error code. + **/ +int +MHD__gnutls_certificate_set_x509_key_mem (MHD_gtls_cert_credentials_t + res, + const MHD_gnutls_datum_t * cert, + const MHD_gnutls_datum_t * key, + MHD_gnutls_x509_crt_fmt_t type) +{ + int ret; + + /* this should be first + */ + if ((ret = read_key_mem (res, key ? key->data : NULL, + key ? key->size : 0, type)) < 0) + return ret; + + if ((ret = read_cert_mem (res, cert->data, cert->size, type)) < 0) + return ret; + + res->ncerts++; + + if (key && (ret = MHD__gnutls_check_key_cert_match (res)) < 0) + { + MHD_gnutls_assert (); + return ret; + } + + return 0; +} + +/* Returns 0 if it's ok to use the enum MHD_GNUTLS_KeyExchangeAlgorithm with this + * certificate (uses the KeyUsage field). + */ +int +MHD__gnutls_check_key_usage (const MHD_gnutls_cert * cert, + enum MHD_GNUTLS_KeyExchangeAlgorithm alg) +{ + unsigned int key_usage = 0; + int encipher_type; + + if (cert == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if (MHD_gtls_map_kx_get_cred (alg, 1) == MHD_GNUTLS_CRD_CERTIFICATE || + MHD_gtls_map_kx_get_cred (alg, 0) == MHD_GNUTLS_CRD_CERTIFICATE) + { + + key_usage = cert->key_usage; + + encipher_type = MHD_gtls_kx_encipher_type (alg); + + if (key_usage != 0 && encipher_type != CIPHER_IGN) + { + /* If key_usage has been set in the certificate + */ + + if (encipher_type == CIPHER_ENCRYPT) + { + /* If the key exchange method requires an encipher + * type algorithm, and key's usage does not permit + * encipherment, then fail. + */ + if (!(key_usage & KEY_KEY_ENCIPHERMENT)) + { + MHD_gnutls_assert (); + return GNUTLS_E_KEY_USAGE_VIOLATION; + } + } + + if (encipher_type == CIPHER_SIGN) + { + /* The same as above, but for sign only keys + */ + if (!(key_usage & KEY_DIGITAL_SIGNATURE)) + { + MHD_gnutls_assert (); + return GNUTLS_E_KEY_USAGE_VIOLATION; + } + } + } + } + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/gnutls_x509.h b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_x509.h new file mode 100644 index 0000000000..0726932807 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/gnutls_x509.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <libtasn1.h> + +int MHD__gnutls_x509_cert_verify_peers (MHD_gtls_session_t session, + unsigned int *status); + +#define PEM_CERT_SEP2 "-----BEGIN X509 CERTIFICATE" +#define PEM_CERT_SEP "-----BEGIN CERTIFICATE" + +#define PEM_CRL_SEP "-----BEGIN X509 CRL" + +#define PEM_KEY_RSA_SEP "-----BEGIN RSA" +#define PEM_KEY_DSA_SEP "-----BEGIN DSA" + +int MHD__gnutls_check_key_usage (const MHD_gnutls_cert * cert, + enum MHD_GNUTLS_KeyExchangeAlgorithm alg); + +int MHD__gnutls_x509_read_rsa_params (opaque * der, int dersize, + mpi_t * params); +int MHD__gnutls_x509_read_dsa_pubkey (opaque * der, int dersize, + mpi_t * params); + +int MHD__gnutls_x509_raw_privkey_to_gkey (MHD_gnutls_privkey * privkey, + const MHD_gnutls_datum_t * raw_key, + MHD_gnutls_x509_crt_fmt_t type); +int MHD__gnutls_x509_privkey_to_gkey (MHD_gnutls_privkey * privkey, + MHD_gnutls_x509_privkey_t); diff --git a/lib/libmicrohttpd/src/daemon/https/tls/memmem.c b/lib/libmicrohttpd/src/daemon/https/tls/memmem.c new file mode 100644 index 0000000000..77143a7e1f --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/memmem.c @@ -0,0 +1,78 @@ +/* Copyright (C) 1991,92,93,94,96,97,98,2000,2004,2007,2008 Free Software + Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, or (at your option) + any later version. + + 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This particular implementation was written by Eric Blake, 2008. */ + +/* Specification of memmem. */ +#include "gnutls_global.h" +#include <string.h> + +#if !HAVE_MEMMEM + +#ifndef _LIBC +# define __builtin_expect(expr, val) (expr) +#endif + +#define RETURN_TYPE void * +#define AVAILABLE(h, h_l, j, n_l) ((j) <= (h_l) - (n_l)) +#include "str-two-way.h" + +/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK + if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in + HAYSTACK. */ +void * +memmem (const void *haystack_start, size_t haystack_len, + const void *needle_start, size_t needle_len) +{ + /* Abstract memory is considered to be an array of 'unsigned char' values, + not an array of 'char' values. See ISO C 99 section 6.2.6.1. */ + const unsigned char *haystack = (const unsigned char *) haystack_start; + const unsigned char *needle = (const unsigned char *) needle_start; + + if (needle_len == 0) + /* The first occurrence of the empty string is deemed to occur at + the beginning of the string. */ + return (void *) haystack; + + /* Sanity check, otherwise the loop might search through the whole + memory. */ + if (__builtin_expect (haystack_len < needle_len, 0)) + return NULL; + + /* Use optimizations in memchr when possible, to reduce the search + size of haystack using a linear algorithm with a smaller + coefficient. However, avoid memchr for long needles, since we + can often achieve sublinear performance. */ + if (needle_len < LONG_NEEDLE_THRESHOLD) + { + haystack = memchr (haystack, *needle, haystack_len); + if (!haystack || __builtin_expect (needle_len == 1, 0)) + return (void *) haystack; + haystack_len -= haystack - (const unsigned char *) haystack_start; + if (haystack_len < needle_len) + return NULL; + return two_way_short_needle (haystack, haystack_len, needle, + needle_len); + } + else + return two_way_long_needle (haystack, haystack_len, needle, needle_len); +} + +#undef LONG_NEEDLE_THRESHOLD + +#endif /* !HAVE_MEMMEM */ diff --git a/lib/libmicrohttpd/src/daemon/https/tls/pkix_asn1_tab.c b/lib/libmicrohttpd/src/daemon/https/tls/pkix_asn1_tab.c new file mode 100644 index 0000000000..30b5ddd1c1 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/pkix_asn1_tab.c @@ -0,0 +1,1130 @@ +#if HAVE_CONFIG_H +#include "MHD_config.h" +#endif + +#include <libtasn1.h> + +const ASN1_ARRAY_TYPE MHD_pkix_asn1_tab[] = { + {"PKIX1", 536875024, 0}, + {0, 1073741836, 0}, + {"id-ce", 1879048204, 0}, + {"joint-iso-ccitt", 1073741825, "2"}, + {"ds", 1073741825, "5"}, + {0, 1, "29"}, + {"id-ce-authorityKeyIdentifier", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "35"}, + {"AuthorityKeyIdentifier", 1610612741, 0}, + {"keyIdentifier", 1610637314, "KeyIdentifier"}, + {0, 4104, "0"}, + {"authorityCertIssuer", 1610637314, "GeneralNames"}, + {0, 4104, "1"}, + {"authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, + {0, 4104, "2"}, + {"KeyIdentifier", 1073741831, 0}, + {"id-ce-subjectKeyIdentifier", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "14"}, + {"SubjectKeyIdentifier", 1073741826, "KeyIdentifier"}, + {"id-ce-keyUsage", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "15"}, + {"KeyUsage", 1610874886, 0}, + {"digitalSignature", 1073741825, "0"}, + {"nonRepudiation", 1073741825, "1"}, + {"keyEncipherment", 1073741825, "2"}, + {"dataEncipherment", 1073741825, "3"}, + {"keyAgreement", 1073741825, "4"}, + {"keyCertSign", 1073741825, "5"}, + {"cRLSign", 1073741825, "6"}, + {"encipherOnly", 1073741825, "7"}, + {"decipherOnly", 1, "8"}, + {"id-ce-privateKeyUsagePeriod", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "16"}, + {"PrivateKeyUsagePeriod", 1610612741, 0}, + {"notBefore", 1619025937, 0}, + {0, 4104, "0"}, + {"notAfter", 545284113, 0}, + {0, 4104, "1"}, + {"id-ce-certificatePolicies", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "32"}, + {"CertificatePolicies", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "PolicyInformation"}, + {"PolicyInformation", 1610612741, 0}, + {"policyIdentifier", 1073741826, "CertPolicyId"}, + {"policyQualifiers", 538984459, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "PolicyQualifierInfo"}, + {"CertPolicyId", 1073741836, 0}, + {"PolicyQualifierInfo", 1610612741, 0}, + {"policyQualifierId", 1073741826, "PolicyQualifierId"}, + {"qualifier", 541065229, 0}, + {"policyQualifierId", 1, 0}, + {"PolicyQualifierId", 1073741836, 0}, + {"CPSuri", 1073741826, "IA5String"}, + {"UserNotice", 1610612741, 0}, + {"noticeRef", 1073758210, "NoticeReference"}, + {"explicitText", 16386, "DisplayText"}, + {"NoticeReference", 1610612741, 0}, + {"organization", 1073741826, "DisplayText"}, + {"noticeNumbers", 536870923, 0}, + {0, 3, 0}, + {"DisplayText", 1610612754, 0}, + {"visibleString", 1612709890, "VisibleString"}, + {"200", 524298, "1"}, + {"bmpString", 1612709890, "BMPString"}, + {"200", 524298, "1"}, + {"utf8String", 538968066, "UTF8String"}, + {"200", 524298, "1"}, + {"id-ce-policyMappings", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "33"}, + {"PolicyMappings", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 536870917, 0}, + {"issuerDomainPolicy", 1073741826, "CertPolicyId"}, + {"subjectDomainPolicy", 2, "CertPolicyId"}, + {"DirectoryString", 1610612754, 0}, + {"teletexString", 1612709890, "TeletexString"}, + {"MAX", 524298, "1"}, + {"printableString", 1612709890, "PrintableString"}, + {"MAX", 524298, "1"}, + {"universalString", 1612709890, "UniversalString"}, + {"MAX", 524298, "1"}, + {"utf8String", 1612709890, "UTF8String"}, + {"MAX", 524298, "1"}, + {"bmpString", 1612709890, "BMPString"}, + {"MAX", 524298, "1"}, + {"ia5String", 538968066, "IA5String"}, + {"MAX", 524298, "1"}, + {"id-ce-subjectAltName", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "17"}, + {"SubjectAltName", 1073741826, "GeneralNames"}, + {"GeneralNames", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "GeneralName"}, + {"GeneralName", 1610612754, 0}, + {"otherName", 1610620930, "AnotherName"}, + {0, 4104, "0"}, + {"rfc822Name", 1610620930, "IA5String"}, + {0, 4104, "1"}, + {"dNSName", 1610620930, "IA5String"}, + {0, 4104, "2"}, + {"x400Address", 1610620930, "ORAddress"}, + {0, 4104, "3"}, + {"directoryName", 1610620930, "RDNSequence"}, + {0, 2056, "4"}, + {"ediPartyName", 1610620930, "EDIPartyName"}, + {0, 4104, "5"}, + {"uniformResourceIdentifier", 1610620930, "IA5String"}, + {0, 4104, "6"}, + {"iPAddress", 1610620935, 0}, + {0, 4104, "7"}, + {"registeredID", 536879116, 0}, + {0, 4104, "8"}, + {"AnotherName", 1610612741, 0}, + {"type-id", 1073741836, 0}, + {"value", 541073421, 0}, + {0, 1073743880, "0"}, + {"type-id", 1, 0}, + {"EDIPartyName", 1610612741, 0}, + {"nameAssigner", 1610637314, "DirectoryString"}, + {0, 4104, "0"}, + {"partyName", 536879106, "DirectoryString"}, + {0, 4104, "1"}, + {"id-ce-issuerAltName", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "18"}, + {"IssuerAltName", 1073741826, "GeneralNames"}, + {"id-ce-subjectDirectoryAttributes", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "9"}, + {"SubjectDirectoryAttributes", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "Attribute"}, + {"id-ce-basicConstraints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "19"}, + {"BasicConstraints", 1610612741, 0}, + {"cA", 1610645508, 0}, + {0, 131081, 0}, + {"pathLenConstraint", 537411587, 0}, + {"0", 10, "MAX"}, + {"id-ce-nameConstraints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "30"}, + {"NameConstraints", 1610612741, 0}, + {"permittedSubtrees", 1610637314, "GeneralSubtrees"}, + {0, 4104, "0"}, + {"excludedSubtrees", 536895490, "GeneralSubtrees"}, + {0, 4104, "1"}, + {"GeneralSubtrees", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "GeneralSubtree"}, + {"GeneralSubtree", 1610612741, 0}, + {"base", 1073741826, "GeneralName"}, + {"minimum", 1610653698, "BaseDistance"}, + {0, 1073741833, "0"}, + {0, 4104, "0"}, + {"maximum", 536895490, "BaseDistance"}, + {0, 4104, "1"}, + {"BaseDistance", 1611137027, 0}, + {"0", 10, "MAX"}, + {"id-ce-policyConstraints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "36"}, + {"PolicyConstraints", 1610612741, 0}, + {"requireExplicitPolicy", 1610637314, "SkipCerts"}, + {0, 4104, "0"}, + {"inhibitPolicyMapping", 536895490, "SkipCerts"}, + {0, 4104, "1"}, + {"SkipCerts", 1611137027, 0}, + {"0", 10, "MAX"}, + {"id-ce-cRLDistributionPoints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "31"}, + {"CRLDistributionPoints", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "DistributionPoint"}, + {"DistributionPoint", 1610612741, 0}, + {"distributionPoint", 1610637314, "DistributionPointName"}, + {0, 2056, "0"}, + {"reasons", 1610637314, "ReasonFlags"}, + {0, 4104, "1"}, + {"cRLIssuer", 536895490, "GeneralNames"}, + {0, 4104, "2"}, + {"DistributionPointName", 1610612754, 0}, + {"fullName", 1610620930, "GeneralNames"}, + {0, 4104, "0"}, + {"nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"}, + {0, 4104, "1"}, + {"ReasonFlags", 1610874886, 0}, + {"unused", 1073741825, "0"}, + {"keyCompromise", 1073741825, "1"}, + {"cACompromise", 1073741825, "2"}, + {"affiliationChanged", 1073741825, "3"}, + {"superseded", 1073741825, "4"}, + {"cessationOfOperation", 1073741825, "5"}, + {"certificateHold", 1073741825, "6"}, + {"privilegeWithdrawn", 1073741825, "7"}, + {"aACompromise", 1, "8"}, + {"id-ce-extKeyUsage", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "37"}, + {"ExtKeyUsageSyntax", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "KeyPurposeId"}, + {"KeyPurposeId", 1073741836, 0}, + {"id-kp-serverAuth", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "1"}, + {"id-kp-clientAuth", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "2"}, + {"id-kp-codeSigning", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "3"}, + {"id-kp-emailProtection", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "4"}, + {"id-kp-ipsecEndSystem", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "5"}, + {"id-kp-ipsecTunnel", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "6"}, + {"id-kp-ipsecUser", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "7"}, + {"id-kp-timeStamping", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "8"}, + {"id-pe-authorityInfoAccess", 1879048204, 0}, + {0, 1073741825, "id-pe"}, + {0, 1, "1"}, + {"AuthorityInfoAccessSyntax", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "AccessDescription"}, + {"AccessDescription", 1610612741, 0}, + {"accessMethod", 1073741836, 0}, + {"accessLocation", 2, "GeneralName"}, + {"id-ce-cRLNumber", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "20"}, + {"CRLNumber", 1611137027, 0}, + {"0", 10, "MAX"}, + {"id-ce-issuingDistributionPoint", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "28"}, + {"IssuingDistributionPoint", 1610612741, 0}, + {"distributionPoint", 1610637314, "DistributionPointName"}, + {0, 4104, "0"}, + {"onlyContainsUserCerts", 1610653700, 0}, + {0, 1073872905, 0}, + {0, 4104, "1"}, + {"onlyContainsCACerts", 1610653700, 0}, + {0, 1073872905, 0}, + {0, 4104, "2"}, + {"onlySomeReasons", 1610637314, "ReasonFlags"}, + {0, 4104, "3"}, + {"indirectCRL", 536911876, 0}, + {0, 1073872905, 0}, + {0, 4104, "4"}, + {"id-ce-deltaCRLIndicator", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "27"}, + {"BaseCRLNumber", 1073741826, "CRLNumber"}, + {"id-ce-cRLReasons", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "21"}, + {"CRLReason", 1610874901, 0}, + {"unspecified", 1073741825, "0"}, + {"keyCompromise", 1073741825, "1"}, + {"cACompromise", 1073741825, "2"}, + {"affiliationChanged", 1073741825, "3"}, + {"superseded", 1073741825, "4"}, + {"cessationOfOperation", 1073741825, "5"}, + {"certificateHold", 1073741825, "6"}, + {"removeFromCRL", 1, "8"}, + {"id-ce-certificateIssuer", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "29"}, + {"CertificateIssuer", 1073741826, "GeneralNames"}, + {"id-ce-holdInstructionCode", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "23"}, + {"HoldInstructionCode", 1073741836, 0}, + {"holdInstruction", 1879048204, 0}, + {"joint-iso-itu-t", 1073741825, "2"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"x9cm", 1073741825, "10040"}, + {0, 1, "2"}, + {"id-holdinstruction-none", 1879048204, 0}, + {0, 1073741825, "holdInstruction"}, + {0, 1, "1"}, + {"id-holdinstruction-callissuer", 1879048204, 0}, + {0, 1073741825, "holdInstruction"}, + {0, 1, "2"}, + {"id-holdinstruction-reject", 1879048204, 0}, + {0, 1073741825, "holdInstruction"}, + {0, 1, "3"}, + {"id-ce-invalidityDate", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "24"}, + {"InvalidityDate", 1082130449, 0}, + {"VisibleString", 1610620935, 0}, + {0, 4360, "26"}, + {"NumericString", 1610620935, 0}, + {0, 4360, "18"}, + {"IA5String", 1610620935, 0}, + {0, 4360, "22"}, + {"TeletexString", 1610620935, 0}, + {0, 4360, "20"}, + {"PrintableString", 1610620935, 0}, + {0, 4360, "19"}, + {"UniversalString", 1610620935, 0}, + {0, 4360, "28"}, + {"BMPString", 1610620935, 0}, + {0, 4360, "30"}, + {"UTF8String", 1610620935, 0}, + {0, 4360, "12"}, + {"id-pkix", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"identified-organization", 1073741825, "3"}, + {"dod", 1073741825, "6"}, + {"internet", 1073741825, "1"}, + {"security", 1073741825, "5"}, + {"mechanisms", 1073741825, "5"}, + {"pkix", 1, "7"}, + {"id-pe", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "1"}, + {"id-qt", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "2"}, + {"id-kp", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "3"}, + {"id-ad", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "48"}, + {"id-qt-cps", 1879048204, 0}, + {0, 1073741825, "id-qt"}, + {0, 1, "1"}, + {"id-qt-unotice", 1879048204, 0}, + {0, 1073741825, "id-qt"}, + {0, 1, "2"}, + {"id-ad-ocsp", 1879048204, 0}, + {0, 1073741825, "id-ad"}, + {0, 1, "1"}, + {"id-ad-caIssuers", 1879048204, 0}, + {0, 1073741825, "id-ad"}, + {0, 1, "2"}, + {"Attribute", 1610612741, 0}, + {"type", 1073741826, "AttributeType"}, + {"values", 536870927, 0}, + {0, 2, "AttributeValue"}, + {"AttributeType", 1073741836, 0}, + {"AttributeValue", 1614807053, 0}, + {"type", 1, 0}, + {"AttributeTypeAndValue", 1610612741, 0}, + {"type", 1073741826, "AttributeType"}, + {"value", 2, "AttributeValue"}, + {"id-at", 1879048204, 0}, + {"joint-iso-ccitt", 1073741825, "2"}, + {"ds", 1073741825, "5"}, + {0, 1, "4"}, + {"id-at-initials", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "43"}, + {"X520initials", 1073741826, "DirectoryString"}, + {"id-at-generationQualifier", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "44"}, + {"X520generationQualifier", 1073741826, "DirectoryString"}, + {"id-at-surname", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "4"}, + {"X520surName", 1073741826, "DirectoryString"}, + {"id-at-givenName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "42"}, + {"X520givenName", 1073741826, "DirectoryString"}, + {"id-at-name", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "41"}, + {"X520name", 1073741826, "DirectoryString"}, + {"id-at-commonName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "3"}, + {"X520CommonName", 1073741826, "DirectoryString"}, + {"id-at-localityName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "7"}, + {"X520LocalityName", 1073741826, "DirectoryString"}, + {"id-at-stateOrProvinceName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "8"}, + {"X520StateOrProvinceName", 1073741826, "DirectoryString"}, + {"id-at-organizationName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "10"}, + {"X520OrganizationName", 1073741826, "DirectoryString"}, + {"id-at-organizationalUnitName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "11"}, + {"X520OrganizationalUnitName", 1073741826, "DirectoryString"}, + {"id-at-title", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "12"}, + {"X520Title", 1073741826, "DirectoryString"}, + {"id-at-description", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "13"}, + {"X520Description", 1073741826, "DirectoryString"}, + {"id-at-dnQualifier", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "46"}, + {"X520dnQualifier", 1073741826, "PrintableString"}, + {"id-at-countryName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "6"}, + {"X520countryName", 1612709890, "PrintableString"}, + {0, 1048586, "2"}, + {"id-at-serialNumber", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "5"}, + {"X520serialNumber", 1073741826, "PrintableString"}, + {"id-at-telephoneNumber", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "20"}, + {"X520telephoneNumber", 1073741826, "PrintableString"}, + {"id-at-facsimileTelephoneNumber", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "23"}, + {"X520facsimileTelephoneNumber", 1073741826, "PrintableString"}, + {"id-at-pseudonym", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "65"}, + {"X520pseudonym", 1073741826, "DirectoryString"}, + {"id-at-name", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "41"}, + {"X520name", 1073741826, "DirectoryString"}, + {"id-at-streetAddress", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "9"}, + {"X520streetAddress", 1073741826, "DirectoryString"}, + {"id-at-postalAddress", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "16"}, + {"X520postalAddress", 1073741826, "PostalAddress"}, + {"PostalAddress", 1610612747, 0}, + {0, 2, "DirectoryString"}, + {"pkcs", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {"pkcs", 1, "1"}, + {"pkcs-9", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "9"}, + {"emailAddress", 1880096780, "AttributeType"}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "1"}, + {"Pkcs9email", 1612709890, "IA5String"}, + {"ub-emailaddress-length", 524298, "1"}, + {"Name", 1610612754, 0}, + {"rdnSequence", 2, "RDNSequence"}, + {"RDNSequence", 1610612747, 0}, + {0, 2, "RelativeDistinguishedName"}, + {"DistinguishedName", 1073741826, "RDNSequence"}, + {"RelativeDistinguishedName", 1612709903, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "AttributeTypeAndValue"}, + {"Certificate", 1610612741, 0}, + {"tbsCertificate", 1073741826, "TBSCertificate"}, + {"signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"signature", 6, 0}, + {"TBSCertificate", 1610612741, 0}, + {"version", 1610653698, "Version"}, + {0, 1073741833, "v1"}, + {0, 2056, "0"}, + {"serialNumber", 1073741826, "CertificateSerialNumber"}, + {"signature", 1073741826, "AlgorithmIdentifier"}, + {"issuer", 1073741826, "Name"}, + {"validity", 1073741826, "Validity"}, + {"subject", 1073741826, "Name"}, + {"subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, + {"issuerUniqueID", 1610637314, "UniqueIdentifier"}, + {0, 4104, "1"}, + {"subjectUniqueID", 1610637314, "UniqueIdentifier"}, + {0, 4104, "2"}, + {"extensions", 536895490, "Extensions"}, + {0, 2056, "3"}, + {"Version", 1610874883, 0}, + {"v1", 1073741825, "0"}, + {"v2", 1073741825, "1"}, + {"v3", 1, "2"}, + {"CertificateSerialNumber", 1073741827, 0}, + {"Validity", 1610612741, 0}, + {"notBefore", 1073741826, "Time"}, + {"notAfter", 2, "Time"}, + {"Time", 1610612754, 0}, + {"utcTime", 1090519057, 0}, + {"generalTime", 8388625, 0}, + {"UniqueIdentifier", 1073741830, 0}, + {"SubjectPublicKeyInfo", 1610612741, 0}, + {"algorithm", 1073741826, "AlgorithmIdentifier"}, + {"subjectPublicKey", 6, 0}, + {"Extensions", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "Extension"}, + {"Extension", 1610612741, 0}, + {"extnID", 1073741836, 0}, + {"critical", 1610645508, 0}, + {0, 131081, 0}, + {"extnValue", 7, 0}, + {"CertificateList", 1610612741, 0}, + {"tbsCertList", 1073741826, "TBSCertList"}, + {"signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"signature", 6, 0}, + {"TBSCertList", 1610612741, 0}, + {"version", 1073758210, "Version"}, + {"signature", 1073741826, "AlgorithmIdentifier"}, + {"issuer", 1073741826, "Name"}, + {"thisUpdate", 1073741826, "Time"}, + {"nextUpdate", 1073758210, "Time"}, + {"revokedCertificates", 1610629131, 0}, + {0, 536870917, 0}, + {"userCertificate", 1073741826, "CertificateSerialNumber"}, + {"revocationDate", 1073741826, "Time"}, + {"crlEntryExtensions", 16386, "Extensions"}, + {"crlExtensions", 536895490, "Extensions"}, + {0, 2056, "0"}, + {"AlgorithmIdentifier", 1610612741, 0}, + {"algorithm", 1073741836, 0}, + {"parameters", 541081613, 0}, + {"algorithm", 1, 0}, + {"pkcs-1", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "1"}, + {"rsaEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "1"}, + {"md2WithRSAEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "2"}, + {"md5WithRSAEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "4"}, + {"sha1WithRSAEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "5"}, + {"id-dsa-with-sha1", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"x9-57", 1073741825, "10040"}, + {"x9algorithm", 1073741825, "4"}, + {0, 1, "3"}, + {"Dss-Sig-Value", 1610612741, 0}, + {"r", 1073741827, 0}, + {"s", 3, 0}, + {"dhpublicnumber", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"ansi-x942", 1073741825, "10046"}, + {"number-type", 1073741825, "2"}, + {0, 1, "1"}, + {"DomainParameters", 1610612741, 0}, + {"p", 1073741827, 0}, + {"g", 1073741827, 0}, + {"q", 1073741827, 0}, + {"j", 1073758211, 0}, + {"validationParms", 16386, "ValidationParms"}, + {"ValidationParms", 1610612741, 0}, + {"seed", 1073741830, 0}, + {"pgenCounter", 3, 0}, + {"id-dsa", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"x9-57", 1073741825, "10040"}, + {"x9algorithm", 1073741825, "4"}, + {0, 1, "1"}, + {"Dss-Parms", 1610612741, 0}, + {"p", 1073741827, 0}, + {"q", 1073741827, 0}, + {"g", 3, 0}, + {"ORAddress", 1610612741, 0}, + {"built-in-standard-attributes", 1073741826, "BuiltInStandardAttributes"}, + {"built-in-domain-defined-attributes", 1073758210, + "BuiltInDomainDefinedAttributes"}, + {"extension-attributes", 16386, "ExtensionAttributes"}, + {"BuiltInStandardAttributes", 1610612741, 0}, + {"country-name", 1073758210, "CountryName"}, + {"administration-domain-name", 1073758210, "AdministrationDomainName"}, + {"network-address", 1610637314, "NetworkAddress"}, + {0, 2056, "0"}, + {"terminal-identifier", 1610637314, "TerminalIdentifier"}, + {0, 2056, "1"}, + {"private-domain-name", 1610637314, "PrivateDomainName"}, + {0, 2056, "2"}, + {"organization-name", 1610637314, "OrganizationName"}, + {0, 2056, "3"}, + {"numeric-user-identifier", 1610637314, "NumericUserIdentifier"}, + {0, 2056, "4"}, + {"personal-name", 1610637314, "PersonalName"}, + {0, 2056, "5"}, + {"organizational-unit-names", 536895490, "OrganizationalUnitNames"}, + {0, 2056, "6"}, + {"CountryName", 1610620946, 0}, + {0, 1073746952, "1"}, + {"x121-dcc-code", 1612709890, "NumericString"}, + {0, 1048586, "ub-country-name-numeric-length"}, + {"iso-3166-alpha2-code", 538968066, "PrintableString"}, + {0, 1048586, "ub-country-name-alpha-length"}, + {"AdministrationDomainName", 1610620946, 0}, + {0, 1073744904, "2"}, + {"numeric", 1612709890, "NumericString"}, + {"ub-domain-name-length", 524298, "0"}, + {"printable", 538968066, "PrintableString"}, + {"ub-domain-name-length", 524298, "0"}, + {"NetworkAddress", 1073741826, "X121Address"}, + {"X121Address", 1612709890, "NumericString"}, + {"ub-x121-address-length", 524298, "1"}, + {"TerminalIdentifier", 1612709890, "PrintableString"}, + {"ub-terminal-id-length", 524298, "1"}, + {"PrivateDomainName", 1610612754, 0}, + {"numeric", 1612709890, "NumericString"}, + {"ub-domain-name-length", 524298, "1"}, + {"printable", 538968066, "PrintableString"}, + {"ub-domain-name-length", 524298, "1"}, + {"OrganizationName", 1612709890, "PrintableString"}, + {"ub-organization-name-length", 524298, "1"}, + {"NumericUserIdentifier", 1612709890, "NumericString"}, + {"ub-numeric-user-id-length", 524298, "1"}, + {"PersonalName", 1610612750, 0}, + {"surname", 1814044674, "PrintableString"}, + {0, 1073745928, "0"}, + {"ub-surname-length", 524298, "1"}, + {"given-name", 1814061058, "PrintableString"}, + {0, 1073745928, "1"}, + {"ub-given-name-length", 524298, "1"}, + {"initials", 1814061058, "PrintableString"}, + {0, 1073745928, "2"}, + {"ub-initials-length", 524298, "1"}, + {"generation-qualifier", 740319234, "PrintableString"}, + {0, 1073745928, "3"}, + {"ub-generation-qualifier-length", 524298, "1"}, + {"OrganizationalUnitNames", 1612709899, 0}, + {"ub-organizational-units", 1074266122, "1"}, + {0, 2, "OrganizationalUnitName"}, + {"OrganizationalUnitName", 1612709890, "PrintableString"}, + {"ub-organizational-unit-name-length", 524298, "1"}, + {"BuiltInDomainDefinedAttributes", 1612709899, 0}, + {"ub-domain-defined-attributes", 1074266122, "1"}, + {0, 2, "BuiltInDomainDefinedAttribute"}, + {"BuiltInDomainDefinedAttribute", 1610612741, 0}, + {"type", 1612709890, "PrintableString"}, + {"ub-domain-defined-attribute-type-length", 524298, "1"}, + {"value", 538968066, "PrintableString"}, + {"ub-domain-defined-attribute-value-length", 524298, "1"}, + {"ExtensionAttributes", 1612709903, 0}, + {"ub-extension-attributes", 1074266122, "1"}, + {0, 2, "ExtensionAttribute"}, + {"ExtensionAttribute", 1610612741, 0}, + {"extension-attribute-type", 1611145219, 0}, + {0, 1073743880, "0"}, + {"0", 10, "ub-extension-attributes"}, + {"extension-attribute-value", 541073421, 0}, + {0, 1073743880, "1"}, + {"extension-attribute-type", 1, 0}, + {"common-name", 1342177283, "1"}, + {"CommonName", 1612709890, "PrintableString"}, + {"ub-common-name-length", 524298, "1"}, + {"teletex-common-name", 1342177283, "2"}, + {"TeletexCommonName", 1612709890, "TeletexString"}, + {"ub-common-name-length", 524298, "1"}, + {"teletex-organization-name", 1342177283, "3"}, + {"TeletexOrganizationName", 1612709890, "TeletexString"}, + {"ub-organization-name-length", 524298, "1"}, + {"teletex-personal-name", 1342177283, "4"}, + {"TeletexPersonalName", 1610612750, 0}, + {"surname", 1814044674, "TeletexString"}, + {0, 1073743880, "0"}, + {"ub-surname-length", 524298, "1"}, + {"given-name", 1814061058, "TeletexString"}, + {0, 1073743880, "1"}, + {"ub-given-name-length", 524298, "1"}, + {"initials", 1814061058, "TeletexString"}, + {0, 1073743880, "2"}, + {"ub-initials-length", 524298, "1"}, + {"generation-qualifier", 740319234, "TeletexString"}, + {0, 1073743880, "3"}, + {"ub-generation-qualifier-length", 524298, "1"}, + {"teletex-organizational-unit-names", 1342177283, "5"}, + {"TeletexOrganizationalUnitNames", 1612709899, 0}, + {"ub-organizational-units", 1074266122, "1"}, + {0, 2, "TeletexOrganizationalUnitName"}, + {"TeletexOrganizationalUnitName", 1612709890, "TeletexString"}, + {"ub-organizational-unit-name-length", 524298, "1"}, + {"pds-name", 1342177283, "7"}, + {"PDSName", 1612709890, "PrintableString"}, + {"ub-pds-name-length", 524298, "1"}, + {"physical-delivery-country-name", 1342177283, "8"}, + {"PhysicalDeliveryCountryName", 1610612754, 0}, + {"x121-dcc-code", 1612709890, "NumericString"}, + {0, 1048586, "ub-country-name-numeric-length"}, + {"iso-3166-alpha2-code", 538968066, "PrintableString"}, + {0, 1048586, "ub-country-name-alpha-length"}, + {"postal-code", 1342177283, "9"}, + {"PostalCode", 1610612754, 0}, + {"numeric-code", 1612709890, "NumericString"}, + {"ub-postal-code-length", 524298, "1"}, + {"printable-code", 538968066, "PrintableString"}, + {"ub-postal-code-length", 524298, "1"}, + {"physical-delivery-office-name", 1342177283, "10"}, + {"PhysicalDeliveryOfficeName", 1073741826, "PDSParameter"}, + {"physical-delivery-office-number", 1342177283, "11"}, + {"PhysicalDeliveryOfficeNumber", 1073741826, "PDSParameter"}, + {"extension-OR-address-components", 1342177283, "12"}, + {"ExtensionORAddressComponents", 1073741826, "PDSParameter"}, + {"physical-delivery-personal-name", 1342177283, "13"}, + {"PhysicalDeliveryPersonalName", 1073741826, "PDSParameter"}, + {"physical-delivery-organization-name", 1342177283, "14"}, + {"PhysicalDeliveryOrganizationName", 1073741826, "PDSParameter"}, + {"extension-physical-delivery-address-components", 1342177283, "15"}, + {"ExtensionPhysicalDeliveryAddressComponents", 1073741826, "PDSParameter"}, + {"unformatted-postal-address", 1342177283, "16"}, + {"UnformattedPostalAddress", 1610612750, 0}, + {"printable-address", 1814052875, 0}, + {"ub-pds-physical-address-lines", 1074266122, "1"}, + {0, 538968066, "PrintableString"}, + {"ub-pds-parameter-length", 524298, "1"}, + {"teletex-string", 740311042, "TeletexString"}, + {"ub-unformatted-address-length", 524298, "1"}, + {"street-address", 1342177283, "17"}, + {"StreetAddress", 1073741826, "PDSParameter"}, + {"post-office-box-address", 1342177283, "18"}, + {"PostOfficeBoxAddress", 1073741826, "PDSParameter"}, + {"poste-restante-address", 1342177283, "19"}, + {"PosteRestanteAddress", 1073741826, "PDSParameter"}, + {"unique-postal-name", 1342177283, "20"}, + {"UniquePostalName", 1073741826, "PDSParameter"}, + {"local-postal-attributes", 1342177283, "21"}, + {"LocalPostalAttributes", 1073741826, "PDSParameter"}, + {"PDSParameter", 1610612750, 0}, + {"printable-string", 1814052866, "PrintableString"}, + {"ub-pds-parameter-length", 524298, "1"}, + {"teletex-string", 740311042, "TeletexString"}, + {"ub-pds-parameter-length", 524298, "1"}, + {"extended-network-address", 1342177283, "22"}, + {"ExtendedNetworkAddress", 1610612754, 0}, + {"e163-4-address", 1610612741, 0}, + {"number", 1612718082, "NumericString"}, + {0, 1073743880, "0"}, + {"ub-e163-4-number-length", 524298, "1"}, + {"sub-address", 538992642, "NumericString"}, + {0, 1073743880, "1"}, + {"ub-e163-4-sub-address-length", 524298, "1"}, + {"psap-address", 536879106, "PresentationAddress"}, + {0, 2056, "0"}, + {"PresentationAddress", 1610612741, 0}, + {"pSelector", 1610637319, 0}, + {0, 2056, "0"}, + {"sSelector", 1610637319, 0}, + {0, 2056, "1"}, + {"tSelector", 1610637319, 0}, + {0, 2056, "2"}, + {"nAddresses", 538976271, 0}, + {0, 1073743880, "3"}, + {"MAX", 1074266122, "1"}, + {0, 7, 0}, + {"terminal-type", 1342177283, "23"}, + {"TerminalType", 1610874883, 0}, + {"telex", 1073741825, "3"}, + {"teletex", 1073741825, "4"}, + {"g3-facsimile", 1073741825, "5"}, + {"g4-facsimile", 1073741825, "6"}, + {"ia5-terminal", 1073741825, "7"}, + {"videotex", 1, "8"}, + {"teletex-domain-defined-attributes", 1342177283, "6"}, + {"TeletexDomainDefinedAttributes", 1612709899, 0}, + {"ub-domain-defined-attributes", 1074266122, "1"}, + {0, 2, "TeletexDomainDefinedAttribute"}, + {"TeletexDomainDefinedAttribute", 1610612741, 0}, + {"type", 1612709890, "TeletexString"}, + {"ub-domain-defined-attribute-type-length", 524298, "1"}, + {"value", 538968066, "TeletexString"}, + {"ub-domain-defined-attribute-value-length", 524298, "1"}, + {"ub-name", 1342177283, "32768"}, + {"ub-common-name", 1342177283, "64"}, + {"ub-locality-name", 1342177283, "128"}, + {"ub-state-name", 1342177283, "128"}, + {"ub-organization-name", 1342177283, "64"}, + {"ub-organizational-unit-name", 1342177283, "64"}, + {"ub-title", 1342177283, "64"}, + {"ub-match", 1342177283, "128"}, + {"ub-emailaddress-length", 1342177283, "128"}, + {"ub-common-name-length", 1342177283, "64"}, + {"ub-country-name-alpha-length", 1342177283, "2"}, + {"ub-country-name-numeric-length", 1342177283, "3"}, + {"ub-domain-defined-attributes", 1342177283, "4"}, + {"ub-domain-defined-attribute-type-length", 1342177283, "8"}, + {"ub-domain-defined-attribute-value-length", 1342177283, "128"}, + {"ub-domain-name-length", 1342177283, "16"}, + {"ub-extension-attributes", 1342177283, "256"}, + {"ub-e163-4-number-length", 1342177283, "15"}, + {"ub-e163-4-sub-address-length", 1342177283, "40"}, + {"ub-generation-qualifier-length", 1342177283, "3"}, + {"ub-given-name-length", 1342177283, "16"}, + {"ub-initials-length", 1342177283, "5"}, + {"ub-integer-options", 1342177283, "256"}, + {"ub-numeric-user-id-length", 1342177283, "32"}, + {"ub-organization-name-length", 1342177283, "64"}, + {"ub-organizational-unit-name-length", 1342177283, "32"}, + {"ub-organizational-units", 1342177283, "4"}, + {"ub-pds-name-length", 1342177283, "16"}, + {"ub-pds-parameter-length", 1342177283, "30"}, + {"ub-pds-physical-address-lines", 1342177283, "6"}, + {"ub-postal-code-length", 1342177283, "16"}, + {"ub-surname-length", 1342177283, "40"}, + {"ub-terminal-id-length", 1342177283, "24"}, + {"ub-unformatted-address-length", 1342177283, "180"}, + {"ub-x121-address-length", 1342177283, "16"}, + {"pkcs-7-ContentInfo", 1610612741, 0}, + {"contentType", 1073741826, "pkcs-7-ContentType"}, + {"content", 541073421, 0}, + {0, 1073743880, "0"}, + {"contentType", 1, 0}, + {"pkcs-7-DigestInfo", 1610612741, 0}, + {"digestAlgorithm", 1073741826, "pkcs-7-DigestAlgorithmIdentifier"}, + {"digest", 2, "pkcs-7-Digest"}, + {"pkcs-7-Digest", 1073741831, 0}, + {"pkcs-7-ContentType", 1073741836, 0}, + {"pkcs-7-SignedData", 1610612741, 0}, + {"version", 1073741826, "pkcs-7-CMSVersion"}, + {"digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"}, + {"encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"}, + {"certificates", 1610637314, "pkcs-7-CertificateSet"}, + {0, 4104, "0"}, + {"crls", 1610637314, "pkcs-7-CertificateRevocationLists"}, + {0, 4104, "1"}, + {"signerInfos", 2, "pkcs-7-SignerInfos"}, + {"pkcs-7-CMSVersion", 1610874883, 0}, + {"v0", 1073741825, "0"}, + {"v1", 1073741825, "1"}, + {"v2", 1073741825, "2"}, + {"v3", 1073741825, "3"}, + {"v4", 1, "4"}, + {"pkcs-7-DigestAlgorithmIdentifiers", 1610612751, 0}, + {0, 2, "pkcs-7-DigestAlgorithmIdentifier"}, + {"pkcs-7-DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, + {"pkcs-7-EncapsulatedContentInfo", 1610612741, 0}, + {"eContentType", 1073741826, "pkcs-7-ContentType"}, + {"eContent", 536895495, 0}, + {0, 2056, "0"}, + {"pkcs-7-CertificateRevocationLists", 1610612751, 0}, + {0, 13, 0}, + {"pkcs-7-CertificateChoices", 1610612754, 0}, + {"certificate", 13, 0}, + {"pkcs-7-CertificateSet", 1610612751, 0}, + {0, 2, "pkcs-7-CertificateChoices"}, + {"pkcs-7-SignerInfos", 1610612751, 0}, + {0, 13, 0}, + {"pkcs-10-CertificationRequestInfo", 1610612741, 0}, + {"version", 1610874883, 0}, + {"v1", 1, "0"}, + {"subject", 1073741826, "Name"}, + {"subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"}, + {"attributes", 536879106, "Attributes"}, + {0, 4104, "0"}, + {"Attributes", 1610612751, 0}, + {0, 2, "Attribute"}, + {"pkcs-10-CertificationRequest", 1610612741, 0}, + {"certificationRequestInfo", 1073741826, + "pkcs-10-CertificationRequestInfo"}, + {"signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"signature", 6, 0}, + {"pkcs-9-ub-challengePassword", 1342177283, "255"}, + {"pkcs-9-certTypes", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "22"}, + {"pkcs-9-crlTypes", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "23"}, + {"pkcs-9-at-challengePassword", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "7"}, + {"pkcs-9-challengePassword", 1610612754, 0}, + {"printableString", 1612709890, "PrintableString"}, + {"pkcs-9-ub-challengePassword", 524298, "1"}, + {"utf8String", 538968066, "UTF8String"}, + {"pkcs-9-ub-challengePassword", 524298, "1"}, + {"pkcs-9-at-localKeyId", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "21"}, + {"pkcs-9-localKeyId", 1073741831, 0}, + {"pkcs-9-at-friendlyName", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "20"}, + {"pkcs-9-friendlyName", 1612709890, "BMPString"}, + {"255", 524298, "1"}, + {"pkcs-8-PrivateKeyInfo", 1610612741, 0}, + {"version", 1073741826, "pkcs-8-Version"}, + {"privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"privateKey", 1073741826, "pkcs-8-PrivateKey"}, + {"attributes", 536895490, "Attributes"}, + {0, 4104, "0"}, + {"pkcs-8-Version", 1610874883, 0}, + {"v1", 1, "0"}, + {"pkcs-8-PrivateKey", 1073741831, 0}, + {"pkcs-8-Attributes", 1610612751, 0}, + {0, 2, "Attribute"}, + {"pkcs-8-EncryptedPrivateKeyInfo", 1610612741, 0}, + {"encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"encryptedData", 2, "pkcs-8-EncryptedData"}, + {"pkcs-8-EncryptedData", 1073741831, 0}, + {"pkcs-5", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "5"}, + {"pkcs-5-encryptionAlgorithm", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {0, 1, "3"}, + {"pkcs-5-des-EDE3-CBC", 1879048204, 0}, + {0, 1073741825, "pkcs-5-encryptionAlgorithm"}, + {0, 1, "7"}, + {"pkcs-5-des-EDE3-CBC-params", 1612709895, 0}, + {0, 1048586, "8"}, + {"pkcs-5-id-PBES2", 1879048204, 0}, + {0, 1073741825, "pkcs-5"}, + {0, 1, "13"}, + {"pkcs-5-PBES2-params", 1610612741, 0}, + {"keyDerivationFunc", 1073741826, "AlgorithmIdentifier"}, + {"encryptionScheme", 2, "AlgorithmIdentifier"}, + {"pkcs-5-id-PBKDF2", 1879048204, 0}, + {0, 1073741825, "pkcs-5"}, + {0, 1, "12"}, + {"pkcs-5-PBKDF2-params", 1610612741, 0}, + {"salt", 1610612754, 0}, + {"specified", 1073741831, 0}, + {"otherSource", 2, "AlgorithmIdentifier"}, + {"iterationCount", 1611137027, 0}, + {"1", 10, "MAX"}, + {"keyLength", 1611153411, 0}, + {"1", 10, "MAX"}, + {"prf", 16386, "AlgorithmIdentifier"}, + {"pkcs-12", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "12"}, + {"pkcs-12-PFX", 1610612741, 0}, + {"version", 1610874883, 0}, + {"v3", 1, "3"}, + {"authSafe", 1073741826, "pkcs-7-ContentInfo"}, + {"macData", 16386, "pkcs-12-MacData"}, + {"pkcs-12-PbeParams", 1610612741, 0}, + {"salt", 1073741831, 0}, + {"iterations", 3, 0}, + {"pkcs-12-MacData", 1610612741, 0}, + {"mac", 1073741826, "pkcs-7-DigestInfo"}, + {"macSalt", 1073741831, 0}, + {"iterations", 536903683, 0}, + {0, 9, "1"}, + {"pkcs-12-AuthenticatedSafe", 1610612747, 0}, + {0, 2, "pkcs-7-ContentInfo"}, + {"pkcs-12-SafeContents", 1610612747, 0}, + {0, 2, "pkcs-12-SafeBag"}, + {"pkcs-12-SafeBag", 1610612741, 0}, + {"bagId", 1073741836, 0}, + {"bagValue", 1614815245, 0}, + {0, 1073743880, "0"}, + {"badId", 1, 0}, + {"bagAttributes", 536887311, 0}, + {0, 2, "pkcs-12-PKCS12Attribute"}, + {"pkcs-12-bagtypes", 1879048204, 0}, + {0, 1073741825, "pkcs-12"}, + {0, 1073741825, "10"}, + {0, 1, "1"}, + {"pkcs-12-keyBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "1"}, + {"pkcs-12-pkcs8ShroudedKeyBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "2"}, + {"pkcs-12-certBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "3"}, + {"pkcs-12-crlBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "4"}, + {"pkcs-12-KeyBag", 1073741826, "pkcs-8-PrivateKeyInfo"}, + {"pkcs-12-PKCS8ShroudedKeyBag", 1073741826, + "pkcs-8-EncryptedPrivateKeyInfo"}, + {"pkcs-12-CertBag", 1610612741, 0}, + {"certId", 1073741836, 0}, + {"certValue", 541073421, 0}, + {0, 1073743880, "0"}, + {"certId", 1, 0}, + {"pkcs-12-CRLBag", 1610612741, 0}, + {"crlId", 1073741836, 0}, + {"crlValue", 541073421, 0}, + {0, 1073743880, "0"}, + {"crlId", 1, 0}, + {"pkcs-12-PKCS12Attribute", 1073741826, "Attribute"}, + {"pkcs-7-data", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {"pkcs", 1073741825, "1"}, + {"pkcs7", 1073741825, "7"}, + {0, 1, "1"}, + {"pkcs-7-encryptedData", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {"pkcs", 1073741825, "1"}, + {"pkcs7", 1073741825, "7"}, + {0, 1, "6"}, + {"pkcs-7-Data", 1073741831, 0}, + {"pkcs-7-EncryptedData", 1610612741, 0}, + {"version", 1073741826, "pkcs-7-CMSVersion"}, + {"encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"}, + {"unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"}, + {0, 4104, "1"}, + {"pkcs-7-EncryptedContentInfo", 1610612741, 0}, + {"contentType", 1073741826, "pkcs-7-ContentType"}, + {"contentEncryptionAlgorithm", 1073741826, + "pkcs-7-ContentEncryptionAlgorithmIdentifier"}, + {"encryptedContent", 536895490, "pkcs-7-EncryptedContent"}, + {0, 4104, "0"}, + {"pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, + "AlgorithmIdentifier"}, + {"pkcs-7-EncryptedContent", 1073741831, 0}, + {"pkcs-7-UnprotectedAttributes", 1612709903, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "Attribute"}, + {"id-at-ldap-DC", 1880096780, "AttributeType"}, + {0, 1073741825, "0"}, + {0, 1073741825, "9"}, + {0, 1073741825, "2342"}, + {0, 1073741825, "19200300"}, + {0, 1073741825, "100"}, + {0, 1073741825, "1"}, + {0, 1, "25"}, + {"ldap-DC", 1073741826, "IA5String"}, + {"id-at-ldap-UID", 1880096780, "AttributeType"}, + {0, 1073741825, "0"}, + {0, 1073741825, "9"}, + {0, 1073741825, "2342"}, + {0, 1073741825, "19200300"}, + {0, 1073741825, "100"}, + {0, 1073741825, "1"}, + {0, 1, "1"}, + {"ldap-UID", 1073741826, "DirectoryString"}, + {"id-pda", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "9"}, + {"id-pda-dateOfBirth", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "1"}, + {"DateOfBirth", 1082130449, 0}, + {"id-pda-placeOfBirth", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "2"}, + {"PlaceOfBirth", 1073741826, "DirectoryString"}, + {"id-pda-gender", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "3"}, + {"Gender", 1612709890, "PrintableString"}, + {0, 1048586, "1"}, + {"id-pda-countryOfCitizenship", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "4"}, + {"CountryOfCitizenship", 1612709890, "PrintableString"}, + {0, 1048586, "2"}, + {"id-pda-countryOfResidence", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "5"}, + {"CountryOfResidence", 1612709890, "PrintableString"}, + {0, 1048586, "2"}, + {"id-pe-proxyCertInfo", 1879048204, 0}, + {0, 1073741825, "id-pe"}, + {0, 1, "14"}, + {"id-ppl-inheritAll", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1073741825, "21"}, + {0, 1, "1"}, + {"id-ppl-independent", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1073741825, "21"}, + {0, 1, "2"}, + {"ProxyCertInfo", 1610612741, 0}, + {"pCPathLenConstraint", 1611153411, 0}, + {"0", 10, "MAX"}, + {"proxyPolicy", 2, "ProxyPolicy"}, + {"ProxyPolicy", 1610612741, 0}, + {"policyLanguage", 1073741836, 0}, + {"policy", 16391, 0}, + {"id-on", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "8"}, + {"id-on-xmppAddr", 1879048204, 0}, + {0, 1073741825, "id-on"}, + {0, 1, "5"}, + {"XmppAddr", 2, "UTF8String"}, + {0, 0, 0} +}; diff --git a/lib/libmicrohttpd/src/daemon/https/tls/str-two-way.h b/lib/libmicrohttpd/src/daemon/https/tls/str-two-way.h new file mode 100644 index 0000000000..29bb09f6a0 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/str-two-way.h @@ -0,0 +1,429 @@ +/* Byte-wise substring search, using the Two-Way algorithm. + Copyright (C) 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Eric Blake <ebb9@byu.net>, 2008. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, or (at your option) + any later version. + + 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Before including this file, you need to include <config.h> and + <string.h>, and define: + RESULT_TYPE A macro that expands to the return type. + AVAILABLE(h, h_l, j, n_l) + A macro that returns nonzero if there are + at least N_L bytes left starting at H[J]. + H is 'unsigned char *', H_L, J, and N_L + are 'size_t'; H_L is an lvalue. For + NUL-terminated searches, H_L can be + modified each iteration to avoid having + to compute the end of H up front. + + For case-insensitivity, you may optionally define: + CMP_FUNC(p1, p2, l) A macro that returns 0 iff the first L + characters of P1 and P2 are equal. + CANON_ELEMENT(c) A macro that canonicalizes an element right after + it has been fetched from one of the two strings. + The argument is an 'unsigned char'; the result + must be an 'unsigned char' as well. + + This file undefines the macros documented above, and defines + LONG_NEEDLE_THRESHOLD. +*/ + +#include <limits.h> +#include <stdint.h> + +/* We use the Two-Way string matching algorithm, which guarantees + linear complexity with constant space. Additionally, for long + needles, we also use a bad character shift table similar to the + Boyer-Moore algorithm to achieve improved (potentially sub-linear) + performance. + + See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260 + and http://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm +*/ + +/* Point at which computing a bad-byte shift table is likely to be + worthwhile. Small needles should not compute a table, since it + adds (1 << CHAR_BIT) + NEEDLE_LEN computations of preparation for a + speedup no greater than a factor of NEEDLE_LEN. The larger the + needle, the better the potential performance gain. On the other + hand, on non-POSIX systems with CHAR_BIT larger than eight, the + memory required for the table is prohibitive. */ +#if CHAR_BIT < 10 +# define LONG_NEEDLE_THRESHOLD 32U +#else +# define LONG_NEEDLE_THRESHOLD SIZE_MAX +#endif + +#ifndef MAX +# define MAX(a, b) ((a < b) ? (b) : (a)) +#endif + +#ifndef CANON_ELEMENT +# define CANON_ELEMENT(c) c +#endif +#ifndef CMP_FUNC +# define CMP_FUNC memcmp +#endif + +/* Perform a critical factorization of NEEDLE, of length NEEDLE_LEN. + Return the index of the first byte in the right half, and set + *PERIOD to the global period of the right half. + + The global period of a string is the smallest index (possibly its + length) at which all remaining bytes in the string are repetitions + of the prefix (the last repetition may be a subset of the prefix). + + When NEEDLE is factored into two halves, a local period is the + length of the smallest word that shares a suffix with the left half + and shares a prefix with the right half. All factorizations of a + non-empty NEEDLE have a local period of at least 1 and no greater + than NEEDLE_LEN. + + A critical factorization has the property that the local period + equals the global period. All strings have at least one critical + factorization with the left half smaller than the global period. + + Given an ordered alphabet, a critical factorization can be computed + in linear time, with 2 * NEEDLE_LEN comparisons, by computing the + larger of two ordered maximal suffixes. The ordered maximal + suffixes are determined by lexicographic comparison of + periodicity. */ +static size_t +critical_factorization (const unsigned char *needle, size_t needle_len, + size_t * period) +{ + /* Index of last byte of left half, or SIZE_MAX. */ + size_t max_suffix, max_suffix_rev; + size_t j; /* Index into NEEDLE for current candidate suffix. */ + size_t k; /* Offset into current period. */ + size_t p; /* Intermediate period. */ + unsigned char a, b; /* Current comparison bytes. */ + + /* Invariants: + 0 <= j < NEEDLE_LEN - 1 + -1 <= max_suffix{,_rev} < j (treating SIZE_MAX as if it were signed) + min(max_suffix, max_suffix_rev) < global period of NEEDLE + 1 <= p <= global period of NEEDLE + p == global period of the substring NEEDLE[max_suffix{,_rev}+1...j] + 1 <= k <= p + */ + + /* Perform lexicographic search. */ + max_suffix = SIZE_MAX; + j = 0; + k = p = 1; + while (j + k < needle_len) + { + a = CANON_ELEMENT (needle[j + k]); + b = CANON_ELEMENT (needle[max_suffix + k]); + if (a < b) + { + /* Suffix is smaller, period is entire prefix so far. */ + j += k; + k = 1; + p = j - max_suffix; + } + else if (a == b) + { + /* Advance through repetition of the current period. */ + if (k != p) + ++k; + else + { + j += p; + k = 1; + } + } + else /* b < a */ + { + /* Suffix is larger, start over from current location. */ + max_suffix = j++; + k = p = 1; + } + } + *period = p; + + /* Perform reverse lexicographic search. */ + max_suffix_rev = SIZE_MAX; + j = 0; + k = p = 1; + while (j + k < needle_len) + { + a = CANON_ELEMENT (needle[j + k]); + b = CANON_ELEMENT (needle[max_suffix_rev + k]); + if (b < a) + { + /* Suffix is smaller, period is entire prefix so far. */ + j += k; + k = 1; + p = j - max_suffix_rev; + } + else if (a == b) + { + /* Advance through repetition of the current period. */ + if (k != p) + ++k; + else + { + j += p; + k = 1; + } + } + else /* a < b */ + { + /* Suffix is larger, start over from current location. */ + max_suffix_rev = j++; + k = p = 1; + } + } + + /* Choose the longer suffix. Return the first byte of the right + half, rather than the last byte of the left half. */ + if (max_suffix_rev + 1 < max_suffix + 1) + return max_suffix + 1; + *period = p; + return max_suffix_rev + 1; +} + +/* Return the first location of non-empty NEEDLE within HAYSTACK, or + NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This + method is optimized for NEEDLE_LEN < LONG_NEEDLE_THRESHOLD. + Performance is guaranteed to be linear, with an initialization cost + of 2 * NEEDLE_LEN comparisons. + + If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */ +static RETURN_TYPE +two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) +{ + size_t i; /* Index into current byte of NEEDLE. */ + size_t j; /* Index into current window of HAYSTACK. */ + size_t period; /* The period of the right half of needle. */ + size_t suffix; /* The index of the right half of needle. */ + + /* Factor the needle into two halves, such that the left half is + smaller than the global period, and the right half is + periodic (with a period as large as NEEDLE_LEN - suffix). */ + suffix = critical_factorization (needle, needle_len, &period); + + /* Perform the search. Each iteration compares the right half + first. */ + if (CMP_FUNC (needle, needle + period, suffix) == 0) + { + /* Entire needle is periodic; a mismatch can only advance by the + period, so use memory to avoid rescanning known occurrences + of the period. */ + size_t memory = 0; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Scan for matches in right half. */ + i = MAX (suffix, memory); + while (i < needle_len && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (memory < i + 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i + 1 < memory + 1) + return (RETURN_TYPE) (haystack + j); + /* No match, so remember how many repetitions of period + on the right half were scanned. */ + j += period; + memory = needle_len - period; + } + else + { + j += i - suffix + 1; + memory = 0; + } + } + } + else + { + /* The two halves of needle are distinct; no extra memory is + required, and any mismatch results in a maximal shift. */ + period = MAX (suffix, needle_len - suffix) + 1; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Scan for matches in right half. */ + i = suffix; + while (i < needle_len && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (i != SIZE_MAX && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i == SIZE_MAX) + return (RETURN_TYPE) (haystack + j); + j += period; + } + else + j += i - suffix + 1; + } + } + return NULL; +} + +/* Return the first location of non-empty NEEDLE within HAYSTACK, or + NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This + method is optimized for LONG_NEEDLE_THRESHOLD <= NEEDLE_LEN. + Performance is guaranteed to be linear, with an initialization cost + of 3 * NEEDLE_LEN + (1 << CHAR_BIT) operations. + + If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, + and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and + sublinear performance is not possible. */ +static RETURN_TYPE +two_way_long_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) +{ + size_t i; /* Index into current byte of NEEDLE. */ + size_t j; /* Index into current window of HAYSTACK. */ + size_t period; /* The period of the right half of needle. */ + size_t suffix; /* The index of the right half of needle. */ + size_t shift_table[1U << CHAR_BIT]; /* See below. */ + + /* Factor the needle into two halves, such that the left half is + smaller than the global period, and the right half is + periodic (with a period as large as NEEDLE_LEN - suffix). */ + suffix = critical_factorization (needle, needle_len, &period); + + /* Populate shift_table. For each possible byte value c, + shift_table[c] is the distance from the last occurrence of c to + the end of NEEDLE, or NEEDLE_LEN if c is absent from the NEEDLE. + shift_table[NEEDLE[NEEDLE_LEN - 1]] contains the only 0. */ + for (i = 0; i < 1U << CHAR_BIT; i++) + shift_table[i] = needle_len; + for (i = 0; i < needle_len; i++) + shift_table[CANON_ELEMENT (needle[i])] = needle_len - i - 1; + + /* Perform the search. Each iteration compares the right half + first. */ + if (CMP_FUNC (needle, needle + period, suffix) == 0) + { + /* Entire needle is periodic; a mismatch can only advance by the + period, so use memory to avoid rescanning known occurrences + of the period. */ + size_t memory = 0; + size_t shift; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Check the last byte first; if it does not match, then + shift to the next possible match location. */ + shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; + if (0 < shift) + { + if (memory && shift < period) + { + /* Since needle is periodic, but the last period has + a byte out of place, there can be no match until + after the mismatch. */ + shift = needle_len - period; + memory = 0; + } + j += shift; + continue; + } + /* Scan for matches in right half. The last byte has + already been matched, by virtue of the shift table. */ + i = MAX (suffix, memory); + while (i < needle_len - 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len - 1 <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (memory < i + 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i + 1 < memory + 1) + return (RETURN_TYPE) (haystack + j); + /* No match, so remember how many repetitions of period + on the right half were scanned. */ + j += period; + memory = needle_len - period; + } + else + { + j += i - suffix + 1; + memory = 0; + } + } + } + else + { + /* The two halves of needle are distinct; no extra memory is + required, and any mismatch results in a maximal shift. */ + size_t shift; + period = MAX (suffix, needle_len - suffix) + 1; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + /* Check the last byte first; if it does not match, then + shift to the next possible match location. */ + shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; + if (0 < shift) + { + j += shift; + continue; + } + /* Scan for matches in right half. The last byte has + already been matched, by virtue of the shift table. */ + i = suffix; + while (i < needle_len - 1 && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + ++i; + if (needle_len - 1 <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + while (i != SIZE_MAX && (CANON_ELEMENT (needle[i]) + == CANON_ELEMENT (haystack[i + j]))) + --i; + if (i == SIZE_MAX) + return (RETURN_TYPE) (haystack + j); + j += period; + } + else + j += i - suffix + 1; + } + } + return NULL; +} + +#undef AVAILABLE +#undef CANON_ELEMENT +#undef CMP_FUNC +#undef MAX +#undef RETURN_TYPE diff --git a/lib/libmicrohttpd/src/daemon/https/tls/x509_b64.c b/lib/libmicrohttpd/src/daemon/https/tls/x509_b64.c new file mode 100644 index 0000000000..152f740943 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/x509_b64.c @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions that relate to base64 encoding and decoding. + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include <gnutls_datum.h> +#include <x509_b64.h> + +static const uint8_t b64table[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const uint8_t asciitable[128] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, + 0xff, 0xf1, 0xff, 0xff, 0xff, 0x00, /* 0xf1 for '=' */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, + 0xff, 0xff +}; + +#define INCR(what, size) \ + do { \ + what+=size; \ + if (what > ret) { \ + MHD_gnutls_assert(); \ + MHD_gnutls_free( (*result)); *result = NULL; \ + return GNUTLS_E_INTERNAL_ERROR; \ + } \ + } while(0) + + +inline static int +encode (char *result, const uint8_t * data, int left) +{ + + int data_len; + + if (left > 3) + data_len = 3; + else + data_len = left; + + switch (data_len) + { + case 3: + result[0] = b64table[(data[0] >> 2)]; + result[1] = + b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) | + (data[1] >> 4))]; + result[2] = + b64table[((((data[1] & 0x0f) << 2) & 0xff) | (data[2] >> 6))]; + result[3] = b64table[(((data[2] << 2) & 0xff) >> 2)]; + break; + case 2: + result[0] = b64table[(data[0] >> 2)]; + result[1] = + b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) | + (data[1] >> 4))]; + result[2] = b64table[(((data[1] << 4) & 0xff) >> 2)]; + result[3] = '='; + break; + case 1: + result[0] = b64table[(data[0] >> 2)]; + result[1] = b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff))]; + result[2] = '='; + result[3] = '='; + break; + default: + return -1; + } + + return 4; + +} + +/* data must be 4 bytes + * result should be 3 bytes + */ +#define TOASCII(c) (c < 127 ? asciitable[c] : 0xff) +inline static int +decode (uint8_t * result, const opaque * data) +{ + uint8_t a1, a2; + int ret = 3; + + a1 = TOASCII (data[0]); + a2 = TOASCII (data[1]); + if (a1 == 0xff || a2 == 0xff) + return -1; + result[0] = ((a1 << 2) & 0xff) | ((a2 >> 4) & 0xff); + + a1 = a2; + a2 = TOASCII (data[2]); + if (a2 == 0xff) + return -1; + result[1] = ((a1 << 4) & 0xff) | ((a2 >> 2) & 0xff); + + a1 = a2; + a2 = TOASCII (data[3]); + if (a2 == 0xff) + return -1; + result[2] = ((a1 << 6) & 0xff) | (a2 & 0xff); + + if (data[2] == '=') + ret--; + + if (data[3] == '=') + ret--; + return ret; +} + +/* encodes data and puts the result into result (locally allocated) + * The result_size (including the null terminator) is the return value. + */ +int +MHD__gnutls_fbase64_encode (const char *msg, const uint8_t * data, + int data_size, uint8_t ** result) +{ + int i, ret, tmp, j; + char tmpres[4]; + uint8_t *ptr; + uint8_t top[80]; + uint8_t bottom[80]; + int pos, bytes, top_len, bottom_len; + size_t msglen = strlen (msg); + + if (msglen > 50) + { + MHD_gnutls_assert (); + return GNUTLS_E_BASE64_ENCODING_ERROR; + } + + memset (bottom, 0, sizeof (bottom)); + memset (top, 0, sizeof (top)); + + strcat ((char *) top, "-----BEGIN "); /* Flawfinder: ignore */ + strcat ((char *) top, msg); /* Flawfinder: ignore */ + strcat ((char *) top, "-----"); /* Flawfinder: ignore */ + + strcat ((char *) bottom, "\n-----END "); /* Flawfinder: ignore */ + strcat ((char *) bottom, msg); /* Flawfinder: ignore */ + strcat ((char *) bottom, "-----\n"); /* Flawfinder: ignore */ + + top_len = strlen ((char *) top); + bottom_len = strlen ((char *) bottom); + + ret = B64FSIZE (msglen, data_size); + + (*result) = MHD_gnutls_calloc (1, ret + 1); + if ((*result) == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + bytes = pos = 0; + INCR (bytes, top_len); + pos = top_len; + + strcpy ((char *) *result, (char *) top); /* Flawfinder: ignore */ + + for (i = j = 0; i < data_size; i += 3, j += 4) + { + + tmp = encode (tmpres, &data[i], data_size - i); + if (tmp == -1) + { + MHD_gnutls_assert (); + MHD_gnutls_free ((*result)); + *result = NULL; + return GNUTLS_E_BASE64_ENCODING_ERROR; + } + + INCR (bytes, 4); + ptr = &(*result)[j + pos]; + + if ((j) % 64 == 0) + { + INCR (bytes, 1); + pos++; + *ptr++ = '\n'; + } + *ptr++ = tmpres[0]; + + if ((j + 1) % 64 == 0) + { + INCR (bytes, 1); + pos++; + *ptr++ = '\n'; + } + *ptr++ = tmpres[1]; + + if ((j + 2) % 64 == 0) + { + INCR (bytes, 1); + pos++; + *ptr++ = '\n'; + } + *ptr++ = tmpres[2]; + + if ((j + 3) % 64 == 0) + { + INCR (bytes, 1); + pos++; + *ptr++ = '\n'; + } + *ptr++ = tmpres[3]; + } + + INCR (bytes, bottom_len); + + memcpy (&(*result)[bytes - bottom_len], bottom, bottom_len); + (*result)[bytes] = 0; + + return ret + 1; +} + +/* decodes data and puts the result into result (locally allocated) + * The result_size is the return value + */ +int +MHD__gnutls_base64_decode (const uint8_t * data, size_t data_size, + uint8_t ** result) +{ + unsigned int i, j; + int ret, tmp, est; + uint8_t tmpres[3]; + + est = ((data_size * 3) / 4) + 1; + (*result) = MHD_gnutls_malloc (est); + if ((*result) == NULL) + return GNUTLS_E_MEMORY_ERROR; + + ret = 0; + for (i = j = 0; i < data_size; i += 4, j += 3) + { + tmp = decode (tmpres, &data[i]); + if (tmp < 0) + { + MHD_gnutls_free (*result); + *result = NULL; + return tmp; + } + memcpy (&(*result)[j], tmpres, tmp); + ret += tmp; + } + return ret; +} + +/* copies data to result but removes newlines and <CR> + * returns the size of the data copied. + */ +inline static int +cpydata (const uint8_t * data, int data_size, uint8_t ** result) +{ + int i, j; + + (*result) = MHD_gnutls_malloc (data_size); + if (*result == NULL) + return GNUTLS_E_MEMORY_ERROR; + + for (j = i = 0; i < data_size; i++) + { + if (data[i] == '\n' || data[i] == '\r') + continue; + (*result)[j] = data[i]; + j++; + } + return j; +} + +/* Searches the given string for ONE PEM encoded certificate, and + * stores it in the result. + * + * The result_size is the return value + */ +#define ENDSTR "-----\n" +#define ENDSTR2 "-----\r" +int +MHD__gnutls_fbase64_decode (const char *header, const opaque * data, + size_t data_size, uint8_t ** result) +{ + int ret; + static const char top[] = "-----BEGIN "; + static const char bottom[] = "\n-----END "; + uint8_t *rdata; + int rdata_size; + uint8_t *kdata; + int kdata_size; + char pem_header[128]; + + MHD_gtls_str_cpy (pem_header, sizeof (pem_header), top); + if (header != NULL) + MHD_gtls_str_cat (pem_header, sizeof (pem_header), header); + + rdata = memmem (data, data_size, pem_header, strlen (pem_header)); + + if (rdata == NULL) + { + MHD_gnutls_assert (); + MHD__gnutls_debug_log ("Could not find '%s'\n", pem_header); + return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR; + } + + data_size -= (unsigned long int) rdata - (unsigned long int) data; + + if (data_size < 4 + strlen (bottom)) + { + MHD_gnutls_assert (); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + + kdata = memmem (rdata, data_size, ENDSTR, sizeof (ENDSTR) - 1); + /* allow CR as well. + */ + if (kdata == NULL) + kdata = memmem (rdata, data_size, ENDSTR2, sizeof (ENDSTR2) - 1); + + if (kdata == NULL) + { + MHD_gnutls_assert (); + MHD__gnutls_x509_log ("Could not find '%s'\n", ENDSTR); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + data_size -= strlen (ENDSTR); + data_size -= (unsigned long int) kdata - (unsigned long int) rdata; + + rdata = kdata + strlen (ENDSTR); + + /* position is now after the ---BEGIN--- headers */ + + kdata = memmem (rdata, data_size, bottom, strlen (bottom)); + if (kdata == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + + /* position of kdata is before the ----END--- footer + */ + rdata_size = (unsigned long int) kdata - (unsigned long int) rdata; + + if (rdata_size < 4) + { + MHD_gnutls_assert (); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + + kdata_size = cpydata (rdata, rdata_size, &kdata); + + if (kdata_size < 0) + { + MHD_gnutls_assert (); + return kdata_size; + } + + if (kdata_size < 4) + { + MHD_gnutls_assert (); + MHD_gnutls_free (kdata); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + + if ((ret = MHD__gnutls_base64_decode (kdata, kdata_size, result)) < 0) + { + MHD_gnutls_free (kdata); + MHD_gnutls_assert (); + return GNUTLS_E_BASE64_DECODING_ERROR; + } + MHD_gnutls_free (kdata); + + return ret; +} diff --git a/lib/libmicrohttpd/src/daemon/https/tls/x509_b64.h b/lib/libmicrohttpd/src/daemon/https/tls/x509_b64.h new file mode 100644 index 0000000000..ebb48639f9 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/tls/x509_b64.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +int MHD__gnutls_fbase64_encode (const char *msg, const uint8_t * data, + int data_size, uint8_t ** result); +int MHD__gnutls_base64_decode (const uint8_t * data, size_t data_size, + uint8_t ** result); +int MHD__gnutls_fbase64_decode (const char *header, const uint8_t * data, + size_t data_size, uint8_t ** result); + +#define B64SIZE( data_size) ((data_size%3==0)?((data_size*4)/3):(4+((data_size/3)*4))) + +/* The size for B64 encoding + newlines plus header + */ + +#define HEADSIZE( hsize) \ + sizeof("-----BEGIN ")-1+sizeof("-----")-1+ \ + sizeof("\n-----END ")-1+sizeof("-----\n")-1+hsize+hsize + +#define B64FSIZE( hsize, dsize) \ + (B64SIZE(dsize) + HEADSIZE(hsize) + /*newlines*/ \ + B64SIZE(dsize)/64 + (((B64SIZE(dsize) % 64) > 0) ? 1 : 0)) diff --git a/lib/libmicrohttpd/src/daemon/https/x509/Makefile.am b/lib/libmicrohttpd/src/daemon/https/x509/Makefile.am new file mode 100644 index 0000000000..78844a11e0 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/Makefile.am @@ -0,0 +1,24 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https \ + -I$(top_srcdir)/src/daemon/https/minitasn1 \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/tls \ + -I$(top_srcdir)/src/daemon/https/x509 \ + @LIBGCRYPT_CFLAGS@ + +noinst_LTLIBRARIES = libx509.la + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + + +libx509_la_SOURCES = \ + common.c common.h \ + extensions.c extensions.h \ + mpi.c mpi.h \ + x509_privkey.c privkey.h \ + x509.c x509.h +libx509_la_LIBADD = @LIBGCRYPT_LIBS@ + diff --git a/lib/libmicrohttpd/src/daemon/https/x509/Makefile.in b/lib/libmicrohttpd/src/daemon/https/x509/Makefile.in new file mode 100644 index 0000000000..3cba9132d6 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/Makefile.in @@ -0,0 +1,509 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/daemon/https/x509 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libx509_la_DEPENDENCIES = +am_libx509_la_OBJECTS = common.lo extensions.lo mpi.lo x509_privkey.lo \ + x509.lo +libx509_la_OBJECTS = $(am_libx509_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libx509_la_SOURCES) +DIST_SOURCES = $(libx509_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https \ + -I$(top_srcdir)/src/daemon/https/minitasn1 \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/tls \ + -I$(top_srcdir)/src/daemon/https/x509 \ + @LIBGCRYPT_CFLAGS@ + +noinst_LTLIBRARIES = libx509.la +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +libx509_la_SOURCES = \ + common.c common.h \ + extensions.c extensions.h \ + mpi.c mpi.h \ + x509_privkey.c privkey.h \ + x509.c x509.h + +libx509_la_LIBADD = @LIBGCRYPT_LIBS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/daemon/https/x509/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/daemon/https/x509/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libx509.la: $(libx509_la_OBJECTS) $(libx509_la_DEPENDENCIES) + $(LINK) $(libx509_la_OBJECTS) $(libx509_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extensions.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509_privkey.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/daemon/https/x509/common.c b/lib/libmicrohttpd/src/daemon/https/x509/common.c new file mode 100644 index 0000000000..0c8410d1b3 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/common.c @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <libtasn1.h> +#include <gnutls_datum.h> +#include <gnutls_global.h> +#include <gnutls_errors.h> +#include <gnutls_str.h> +#include <gnutls_x509.h> +#include <gnutls_num.h> +#include <x509_b64.h> +#include <common.h> +#include <mpi.h> +#include <time.h> + +/* A generic export function. Will export the given ASN.1 encoded data + * to PEM or DER raw data. + */ +int +MHD__gnutls_x509_export_int (ASN1_TYPE MHD__asn1_data, + MHD_gnutls_x509_crt_fmt_t format, + char *pem_header, + unsigned char *output_data, + size_t * output_data_size) +{ + int result, len; + + if (format == GNUTLS_X509_FMT_DER) + { + + if (output_data == NULL) + *output_data_size = 0; + + len = *output_data_size; + + if ((result = + MHD__asn1_der_coding (MHD__asn1_data, "", output_data, &len, + NULL)) != ASN1_SUCCESS) + { + *output_data_size = len; + if (result == ASN1_MEM_ERROR) + { + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + *output_data_size = len; + + } + else + { /* PEM */ + opaque *out; + MHD_gnutls_datum_t tmp; + + result = MHD__gnutls_x509_der_encode (MHD__asn1_data, "", &tmp, 0); + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + result = + MHD__gnutls_fbase64_encode (pem_header, tmp.data, tmp.size, &out); + + MHD__gnutls_free_datum (&tmp); + + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + if (result == 0) + { /* oooops */ + MHD_gnutls_assert (); + return GNUTLS_E_INTERNAL_ERROR; + } + + if ((unsigned) result > *output_data_size) + { + MHD_gnutls_assert (); + MHD_gnutls_free (out); + *output_data_size = result; + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } + + *output_data_size = result; + + if (output_data) + { + memcpy (output_data, out, result); + + /* do not include the null character into output size. + */ + *output_data_size = result - 1; + } + MHD_gnutls_free (out); + + } + + return 0; +} + +/* Decodes an octet string. Leave string_type null for a normal + * octet string. Otherwise put something like BMPString, PrintableString + * etc. + */ +static int +MHD__gnutls_x509_decode_octet_string (const char *string_type, + const opaque * der, + size_t der_size, + opaque * output, size_t * output_size) +{ + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + int result, tmp_output_size; + char strname[64]; + + if (string_type == NULL) + MHD_gtls_str_cpy (strname, sizeof (strname), "PKIX1.pkcs-7-Data"); + else + { + MHD_gtls_str_cpy (strname, sizeof (strname), "PKIX1."); + MHD_gtls_str_cat (strname, sizeof (strname), string_type); + } + + if ((result = + MHD__asn1_create_element (MHD__gnutls_get_pkix (), strname, + &c2)) != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + result = MHD__asn1_der_decoding (&c2, der, der_size, NULL); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + tmp_output_size = *output_size; + result = MHD__asn1_read_value (c2, "", output, &tmp_output_size); + *output_size = tmp_output_size; + + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + return 0; + +cleanup:if (c2) + MHD__asn1_delete_structure (&c2); + + return result; +} + +/* Reads a value from an ASN1 tree, and puts the output + * in an allocated variable in the given datum. + * flags == 0 do nothing with the DER output + * flags == 1 parse the DER output as OCTET STRING + * flags == 2 the value is a BIT STRING + */ +int +MHD__gnutls_x509_read_value (ASN1_TYPE c, + const char *root, MHD_gnutls_datum_t * ret, + int flags) +{ + int len = 0, result; + size_t slen; + opaque *tmp = NULL; + + result = MHD__asn1_read_value (c, root, NULL, &len); + if (result != ASN1_MEM_ERROR) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + return result; + } + + if (flags == 2) + len /= 8; + + tmp = MHD_gnutls_malloc (len); + if (tmp == NULL) + { + MHD_gnutls_assert (); + result = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + result = MHD__asn1_read_value (c, root, tmp, &len); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + if (flags == 2) + len /= 8; + + /* Extract the OCTET STRING. + */ + + if (flags == 1) + { + slen = len; + result = + MHD__gnutls_x509_decode_octet_string (NULL, tmp, slen, tmp, &slen); + if (result < 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + len = slen; + } + + ret->data = tmp; + ret->size = len; + + return 0; + +cleanup:MHD_gnutls_free (tmp); + return result; + +} + +/* DER Encodes the src ASN1_TYPE and stores it to + * the given datum. If str is non null then the data are encoded as + * an OCTET STRING. + */ +int +MHD__gnutls_x509_der_encode (ASN1_TYPE src, + const char *src_name, MHD_gnutls_datum_t * res, + int str) +{ + int size, result; + int asize; + opaque *data = NULL; + ASN1_TYPE c2 = ASN1_TYPE_EMPTY; + + size = 0; + result = MHD__asn1_der_coding (src, src_name, NULL, &size, NULL); + if (result != ASN1_MEM_ERROR) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + /* allocate data for the der + */ + + if (str) + size += 16; /* for later to include the octet tags */ + asize = size; + + data = MHD_gnutls_malloc (size); + if (data == NULL) + { + MHD_gnutls_assert (); + result = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + result = MHD__asn1_der_coding (src, src_name, data, &size, NULL); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + if (str) + { + if ((result = + MHD__asn1_create_element (MHD__gnutls_get_pkix (), + "PKIX1.pkcs-7-Data", + &c2)) != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + result = MHD__asn1_write_value (c2, "", data, size); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + result = MHD__asn1_der_coding (c2, "", data, &asize, NULL); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + result = MHD_gtls_asn2err (result); + goto cleanup; + } + + size = asize; + + MHD__asn1_delete_structure (&c2); + } + + res->data = data; + res->size = size; + return 0; + +cleanup:MHD_gnutls_free (data); + MHD__asn1_delete_structure (&c2); + return result; + +} + +/* Reads and returns the PK algorithm of the given certificate-like + * ASN.1 structure. src_name should be something like "tbsCertificate.subjectPublicKeyInfo". + */ +int +MHD__gnutls_x509_get_pk_algorithm (ASN1_TYPE src, + const char *src_name, unsigned int *bits) +{ + int result; + opaque *str = NULL; + int algo; + char oid[64]; + int len; + mpi_t params[MAX_PUBLIC_PARAMS_SIZE]; + char name[128]; + + MHD_gtls_str_cpy (name, sizeof (name), src_name); + MHD_gtls_str_cat (name, sizeof (name), ".algorithm.algorithm"); + + len = sizeof (oid); + result = MHD__asn1_read_value (src, name, oid, &len); + + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + algo = MHD_gtls_x509_oid2pk_algorithm (oid); + + if (bits == NULL) + { + MHD_gnutls_free (str); + return algo; + } + + /* Now read the parameters' bits + */ + MHD_gtls_str_cpy (name, sizeof (name), src_name); + MHD_gtls_str_cat (name, sizeof (name), ".subjectPublicKey"); + + len = 0; + result = MHD__asn1_read_value (src, name, NULL, &len); + if (result != ASN1_MEM_ERROR) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + if (len % 8 != 0) + { + MHD_gnutls_assert (); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + len /= 8; + + str = MHD_gnutls_malloc (len); + if (str == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_MEMORY_ERROR; + } + + MHD_gtls_str_cpy (name, sizeof (name), src_name); + MHD_gtls_str_cat (name, sizeof (name), ".subjectPublicKey"); + + result = MHD__asn1_read_value (src, name, str, &len); + + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + MHD_gnutls_free (str); + return MHD_gtls_asn2err (result); + } + + len /= 8; + + switch (algo) + { + case MHD_GNUTLS_PK_RSA: + { + if ((result = + MHD__gnutls_x509_read_rsa_params (str, len, params)) < 0) + { + MHD_gnutls_assert (); + return result; + } + + bits[0] = MHD__gnutls_mpi_get_nbits (params[0]); + + MHD_gtls_mpi_release (¶ms[0]); + MHD_gtls_mpi_release (¶ms[1]); + } + break; + default: + MHD__gnutls_x509_log + ("MHD__gnutls_x509_get_pk_algorithm: unhandled algorithm %d\n", algo); + } + + MHD_gnutls_free (str); + return algo; +} diff --git a/lib/libmicrohttpd/src/daemon/https/x509/common.h b/lib/libmicrohttpd/src/daemon/https/x509/common.h new file mode 100644 index 0000000000..d78c7cc28b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/common.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef COMMON_H +# define COMMON_H + +#include <gnutls.h> +#include <gnutls_algorithms.h> + +#define MAX_STRING_LEN 512 + +#define GNUTLS_XML_SHOW_ALL 1 + +#define PEM_CRL "X509 CRL" +#define PEM_X509_CERT "X509 CERTIFICATE" +#define PEM_X509_CERT2 "CERTIFICATE" +#define PEM_PKCS7 "PKCS7" +#define PEM_PKCS12 "PKCS12" + +/* public key algorithm's OIDs + */ +#define PK_PKIX1_RSA_OID "1.2.840.113549.1.1.1" +#define PK_DSA_OID "1.2.840.10040.4.1" +#define PK_GOST_R3410_94_OID "1.2.643.2.2.20" +#define PK_GOST_R3410_2001_OID "1.2.643.2.2.19" + +/* signature OIDs + */ +#define SIG_DSA_SHA1_OID "1.2.840.10040.4.3" +#define SIG_RSA_MD5_OID "1.2.840.113549.1.1.4" +#define SIG_RSA_MD2_OID "1.2.840.113549.1.1.2" +#define SIG_RSA_SHA1_OID "1.2.840.113549.1.1.5" +#define SIG_RSA_SHA256_OID "1.2.840.113549.1.1.11" +#define SIG_RSA_SHA384_OID "1.2.840.113549.1.1.12" +#define SIG_RSA_SHA512_OID "1.2.840.113549.1.1.13" +#define SIG_RSA_RMD160_OID "1.3.36.3.3.1.2" +#define SIG_GOST_R3410_94_OID "1.2.643.2.2.4" +#define SIG_GOST_R3410_2001_OID "1.2.643.2.2.3" + +int MHD__gnutls_x509_der_encode (ASN1_TYPE src, const char *src_name, + MHD_gnutls_datum_t * res, int str); + +int MHD__gnutls_x509_export_int (ASN1_TYPE MHD__asn1_data, + MHD_gnutls_x509_crt_fmt_t format, + char *pem_header, unsigned char *output_data, + size_t * output_data_size); + +int MHD__gnutls_x509_read_value (ASN1_TYPE c, const char *root, + MHD_gnutls_datum_t * ret, int str); + +int MHD__gnutls_x509_decode_and_read_attribute (ASN1_TYPE MHD__asn1_struct, + const char *where, char *oid, + int oid_size, + MHD_gnutls_datum_t * value, + int multi, int octet); + +int MHD__gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const char *src_name, + unsigned int *bits); + +int MHD__gnutls_asn1_copy_node (ASN1_TYPE * dst, const char *dst_name, + ASN1_TYPE src, const char *src_name); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/x509/extensions.c b/lib/libmicrohttpd/src/daemon/https/x509/extensions.c new file mode 100644 index 0000000000..82fddc5d78 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/extensions.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions that relate to the X.509 extension parsing. + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_global.h> +#include <mpi.h> +#include <libtasn1.h> +#include <common.h> +#include <x509.h> +#include <extensions.h> +#include <gnutls_datum.h> + +/* This function will attempt to return the requested extension found in + * the given X509v3 certificate. The return value is allocated and stored into + * ret. + * + * Critical will be either 0 or 1. + * + * If the extension does not exist, GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will + * be returned. + */ +int +MHD__gnutls_x509_crt_get_extension (MHD_gnutls_x509_crt_t cert, + const char *extension_id, int indx, + MHD_gnutls_datum_t * ret, + unsigned int *_critical) +{ + int k, result, len; + char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE]; + char str[1024]; + char str_critical[10]; + int critical = 0; + char extnID[128]; + MHD_gnutls_datum_t value; + int indx_counter = 0; + + ret->data = NULL; + ret->size = 0; + + k = 0; + do + { + k++; + + snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u", k); + + len = sizeof (str) - 1; + result = MHD__asn1_read_value (cert->cert, name, str, &len); + + /* move to next + */ + + if (result == ASN1_ELEMENT_NOT_FOUND) + { + break; + } + + do + { + + MHD_gtls_str_cpy (name2, sizeof (name2), name); + MHD_gtls_str_cat (name2, sizeof (name2), ".extnID"); + + len = sizeof (extnID) - 1; + result = MHD__asn1_read_value (cert->cert, name2, extnID, &len); + + if (result == ASN1_ELEMENT_NOT_FOUND) + { + MHD_gnutls_assert (); + break; + } + else if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + /* Handle Extension + */ + if (strcmp (extnID, extension_id) == 0 && indx == indx_counter++) + { + /* extension was found + */ + + /* read the critical status. + */ + MHD_gtls_str_cpy (name2, sizeof (name2), name); + MHD_gtls_str_cat (name2, sizeof (name2), ".critical"); + + len = sizeof (str_critical); + result = + MHD__asn1_read_value (cert->cert, name2, str_critical, &len); + + if (result == ASN1_ELEMENT_NOT_FOUND) + { + MHD_gnutls_assert (); + break; + } + else if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + if (str_critical[0] == 'T') + critical = 1; + else + critical = 0; + + /* read the value. + */ + MHD_gtls_str_cpy (name2, sizeof (name2), name); + MHD_gtls_str_cat (name2, sizeof (name2), ".extnValue"); + + result = + MHD__gnutls_x509_read_value (cert->cert, name2, &value, 0); + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + ret->data = value.data; + ret->size = value.size; + + if (_critical) + *_critical = critical; + + return 0; + } + + + } + while (0); + } + while (1); + + if (result == ASN1_ELEMENT_NOT_FOUND) + { + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + else + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } +} + +/* Here we only extract the KeyUsage field, from the DER encoded + * extension. + */ +int +MHD__gnutls_x509_ext_extract_keyUsage (uint16_t * keyUsage, + opaque * extnValue, int extnValueLen) +{ + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + int len, result; + uint8_t str[2]; + + str[0] = str[1] = 0; + *keyUsage = 0; + + if ((result = MHD__asn1_create_element + (MHD__gnutls_get_pkix (), "PKIX1.KeyUsage", &ext)) != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + result = MHD__asn1_der_decoding (&ext, extnValue, extnValueLen, NULL); + + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + MHD__asn1_delete_structure (&ext); + return MHD_gtls_asn2err (result); + } + + len = sizeof (str); + result = MHD__asn1_read_value (ext, "", str, &len); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + MHD__asn1_delete_structure (&ext); + return 0; + } + + *keyUsage = str[0] | (str[1] << 8); + + MHD__asn1_delete_structure (&ext); + + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/https/x509/extensions.h b/lib/libmicrohttpd/src/daemon/https/x509/extensions.h new file mode 100644 index 0000000000..5a945cb15b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/extensions.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +int MHD__gnutls_x509_crt_get_extension (MHD_gnutls_x509_crt_t cert, + const char *extension_id, int indx, + MHD_gnutls_datum_t * ret, + unsigned int *critical); + +int MHD__gnutls_x509_crt_get_extension_oid (MHD_gnutls_x509_crt_t cert, + int indx, void *ret, + size_t * ret_size); +int MHD__gnutls_x509_ext_extract_keyUsage (uint16_t * keyUsage, + opaque * extnValue, + int extnValueLen); diff --git a/lib/libmicrohttpd/src/daemon/https/x509/mpi.c b/lib/libmicrohttpd/src/daemon/https/x509/mpi.c new file mode 100644 index 0000000000..4a54070204 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/mpi.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <gnutls_global.h> +#include <libtasn1.h> +#include <gnutls_datum.h> +#include "common.h" +#include "x509.h" +#include <gnutls_num.h> +#include "mpi.h" + +/* + * some x509 certificate parsing functions that relate to MPI parameter + * extraction. This reads the BIT STRING subjectPublicKey. + * Returns 2 parameters (m,e). + */ +int +MHD__gnutls_x509_read_rsa_params (opaque * der, int dersize, mpi_t * params) +{ + int result; + ASN1_TYPE spk = ASN1_TYPE_EMPTY; + + if ((result = + MHD__asn1_create_element (MHD__gnutls_getMHD__gnutls_asn (), + "GNUTLS.RSAPublicKey", + &spk)) != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + result = MHD__asn1_der_decoding (&spk, der, dersize, NULL); + + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + MHD__asn1_delete_structure (&spk); + return MHD_gtls_asn2err (result); + } + + if ((result = MHD__gnutls_x509_read_int (spk, "modulus", ¶ms[0])) < 0) + { + MHD_gnutls_assert (); + MHD__asn1_delete_structure (&spk); + return GNUTLS_E_ASN1_GENERIC_ERROR; + } + + if ((result = + MHD__gnutls_x509_read_int (spk, "publicExponent", ¶ms[1])) < 0) + { + MHD_gnutls_assert (); + MHD_gtls_mpi_release (¶ms[0]); + MHD__asn1_delete_structure (&spk); + return GNUTLS_E_ASN1_GENERIC_ERROR; + } + + MHD__asn1_delete_structure (&spk); + + return 0; + +} + + +/* Extracts DSA and RSA parameters from a certificate. + */ +int +MHD__gnutls_x509_crt_get_mpis (MHD_gnutls_x509_crt_t cert, + mpi_t * params, int *params_size) +{ + int result; + int pk_algorithm; + MHD_gnutls_datum_t tmp = { NULL, 0 }; + + /* Read the algorithm's OID + */ + pk_algorithm = MHD_gnutls_x509_crt_get_pk_algorithm (cert, NULL); + + /* Read the algorithm's parameters + */ + result + = MHD__gnutls_x509_read_value (cert->cert, + "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", + &tmp, 2); + + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + switch (pk_algorithm) + { + case MHD_GNUTLS_PK_RSA: + /* params[0] is the modulus, + * params[1] is the exponent + */ + if (*params_size < RSA_PUBLIC_PARAMS) + { + MHD_gnutls_assert (); + /* internal error. Increase the mpi_ts in params */ + result = GNUTLS_E_INTERNAL_ERROR; + goto error; + } + + if ((result = + MHD__gnutls_x509_read_rsa_params (tmp.data, tmp.size, params)) < 0) + { + MHD_gnutls_assert (); + goto error; + } + *params_size = RSA_PUBLIC_PARAMS; + + break; + default: + /* other types like DH + * currently not supported + */ + MHD_gnutls_assert (); + result = GNUTLS_E_X509_CERTIFICATE_ERROR; + goto error; + } + + result = 0; + +error:MHD__gnutls_free_datum (&tmp); + return result; +} + +/* + * some x509 certificate functions that relate to MPI parameter + * setting. This writes the BIT STRING subjectPublicKey. + * Needs 2 parameters (m,e). + * + * Allocates the space used to store the DER data. + */ +int +MHD__gnutls_x509_write_rsa_params (mpi_t * params, + int params_size, MHD_gnutls_datum_t * der) +{ + int result; + ASN1_TYPE spk = ASN1_TYPE_EMPTY; + + der->data = NULL; + der->size = 0; + + if (params_size < 2) + { + MHD_gnutls_assert (); + result = GNUTLS_E_INVALID_REQUEST; + goto cleanup; + } + + if ((result = + MHD__asn1_create_element (MHD__gnutls_getMHD__gnutls_asn (), + "GNUTLS.RSAPublicKey", + &spk)) != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + result = MHD__gnutls_x509_write_int (spk, "modulus", params[0], 0); + if (result < 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + + result = MHD__gnutls_x509_write_int (spk, "publicExponent", params[1], 0); + if (result < 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + + result = MHD__gnutls_x509_der_encode (spk, "", der, 0); + if (result < 0) + { + MHD_gnutls_assert (); + goto cleanup; + } + + MHD__asn1_delete_structure (&spk); + return 0; + +cleanup:MHD__asn1_delete_structure (&spk); + + return result; +} diff --git a/lib/libmicrohttpd/src/daemon/https/x509/mpi.h b/lib/libmicrohttpd/src/daemon/https/x509/mpi.h new file mode 100644 index 0000000000..ff9fdc1912 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/mpi.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include "x509.h" + +int MHD__gnutls_x509_crt_get_mpis (MHD_gnutls_x509_crt_t cert, + mpi_t * params, int *params_size); +int MHD__gnutls_x509_read_rsa_params (opaque * der, int dersize, + mpi_t * params); +int MHD__gnutls_x509_write_rsa_params (mpi_t * params, int params_size, + MHD_gnutls_datum_t * der); +int MHD__gnutls_x509_read_int (ASN1_TYPE node, const char *value, + mpi_t * ret_mpi); +int MHD__gnutls_x509_write_int (ASN1_TYPE node, const char *value, mpi_t mpi, + int lz); diff --git a/lib/libmicrohttpd/src/daemon/https/x509/privkey.h b/lib/libmicrohttpd/src/daemon/https/x509/privkey.h new file mode 100644 index 0000000000..37c6870350 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/privkey.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2003, 2004, 2005 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include "x509.h" + +ASN1_TYPE MHD__gnutls_privkey_decode_pkcs1_rsa_key (const MHD_gnutls_datum_t * + raw_key, + MHD_gnutls_x509_privkey_t + pkey); + +int MHD__gnutls_asn1_encode_dsa (ASN1_TYPE * c2, mpi_t * params); diff --git a/lib/libmicrohttpd/src/daemon/https/x509/x509.c b/lib/libmicrohttpd/src/daemon/https/x509/x509.c new file mode 100644 index 0000000000..ff0d21e816 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/x509.c @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation + * Author: Nikos Mavrogiannopoulos, Simon Josefsson, Howard Chu + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Functions on X.509 Certificate parsing + */ + +#include <gnutls_int.h> +#include <gnutls_datum.h> +#include <gnutls_global.h> +#include <gnutls_errors.h> +#include <common.h> +#include <gnutls_x509.h> +#include <x509_b64.h> +#include <x509.h> +#include <extensions.h> +#include <libtasn1.h> +#include <mpi.h> +#include <privkey.h> + +/** + * MHD_gnutls_x509_crt_init - This function initializes a MHD_gnutls_x509_crt_t structure + * @cert: The structure to be initialized + * + * This function will initialize an X.509 certificate structure. + * + * Returns 0 on success. + * + **/ +int +MHD_gnutls_x509_crt_init (MHD_gnutls_x509_crt_t * cert) +{ + MHD_gnutls_x509_crt_t tmp = + MHD_gnutls_calloc (1, sizeof (MHD_gnutls_x509_crt_int)); + int result; + + if (!tmp) + return GNUTLS_E_MEMORY_ERROR; + + result = MHD__asn1_create_element (MHD__gnutls_get_pkix (), + "PKIX1.Certificate", &tmp->cert); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + MHD_gnutls_free (tmp); + return MHD_gtls_asn2err (result); + } + + *cert = tmp; + + return 0; /* success */ +} + +/** + * MHD_gnutls_x509_crt_deinit - This function deinitializes memory used by a MHD_gnutls_x509_crt_t structure + * @cert: The structure to be initialized + * + * This function will deinitialize a CRL structure. + * + **/ +void +MHD_gnutls_x509_crt_deinit (MHD_gnutls_x509_crt_t cert) +{ + if (!cert) + return; + + if (cert->cert) + MHD__asn1_delete_structure (&cert->cert); + + MHD_gnutls_free (cert); +} + +/** + * MHD_gnutls_x509_crt_import - This function will import a DER or PEM encoded Certificate + * @cert: The structure to store the parsed certificate. + * @data: The DER or PEM encoded certificate. + * @format: One of DER or PEM + * + * This function will convert the given DER or PEM encoded Certificate + * to the native MHD_gnutls_x509_crt_t format. The output will be stored in @cert. + * + * If the Certificate is PEM encoded it should have a header of "X509 CERTIFICATE", or + * "CERTIFICATE". + * + * Returns 0 on success. + * + **/ +int +MHD_gnutls_x509_crt_import (MHD_gnutls_x509_crt_t cert, + const MHD_gnutls_datum_t * data, + MHD_gnutls_x509_crt_fmt_t format) +{ + int result = 0, need_free = 0; + MHD_gnutls_datum_t _data; + opaque *signature = NULL; + + if (cert == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + _data.data = data->data; + _data.size = data->size; + + /* If the Certificate is in PEM format then decode it + */ + if (format == GNUTLS_X509_FMT_PEM) + { + opaque *out; + + /* Try the first header */ + result = + MHD__gnutls_fbase64_decode (PEM_X509_CERT2, data->data, data->size, + &out); + + if (result <= 0) + { + /* try for the second header */ + result = MHD__gnutls_fbase64_decode (PEM_X509_CERT, data->data, + data->size, &out); + + if (result <= 0) + { + if (result == 0) + result = GNUTLS_E_INTERNAL_ERROR; + MHD_gnutls_assert (); + return result; + } + } + + _data.data = out; + _data.size = result; + + need_free = 1; + } + + result = MHD__asn1_der_decoding (&cert->cert, _data.data, _data.size, NULL); + if (result != ASN1_SUCCESS) + { + result = MHD_gtls_asn2err (result); + MHD_gnutls_assert (); + goto cleanup; + } + + /* Since we do not want to disable any extension + */ + cert->use_extensions = 1; + if (need_free) + MHD__gnutls_free_datum (&_data); + + return 0; + +cleanup:MHD_gnutls_free (signature); + if (need_free) + MHD__gnutls_free_datum (&_data); + return result; +} + +/** + * MHD_gnutls_x509_crt_get_version - This function returns the Certificate's version number + * @cert: should contain a MHD_gnutls_x509_crt_t structure + * + * This function will return the version of the specified Certificate. + * + * Returns a negative value on error. + * + **/ +int +MHD_gnutls_x509_crt_get_version (MHD_gnutls_x509_crt_t cert) +{ + opaque version[5]; + int len, result; + + if (cert == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + len = sizeof (version); + if ((result = + MHD__asn1_read_value (cert->cert, "tbsCertificate.version", version, + &len)) != ASN1_SUCCESS) + { + + if (result == ASN1_ELEMENT_NOT_FOUND) + return 1; /* the DEFAULT version */ + MHD_gnutls_assert (); + return MHD_gtls_asn2err (result); + } + + return (int) version[0] + 1; +} + +/** + * MHD_gnutls_x509_crt_get_pk_algorithm - This function returns the certificate's PublicKey algorithm + * @cert: should contain a MHD_gnutls_x509_crt_t structure + * @bits: if bits is non null it will hold the size of the parameters' in bits + * + * This function will return the public key algorithm of an X.509 + * certificate. + * + * If bits is non null, it should have enough size to hold the parameters + * size in bits. For RSA the bits returned is the modulus. + * For DSA the bits returned are of the public + * exponent. + * + * Returns a member of the enum MHD_GNUTLS_PublicKeyAlgorithm enumeration on success, + * or a negative value on error. + * + **/ +int +MHD_gnutls_x509_crt_get_pk_algorithm (MHD_gnutls_x509_crt_t cert, + unsigned int *bits) +{ + int result; + + if (cert == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + result = MHD__gnutls_x509_get_pk_algorithm (cert->cert, + "tbsCertificate.subjectPublicKeyInfo", + bits); + + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + return result; + +} + +inline static int +is_type_printable (int type) +{ + if (type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME || type + == GNUTLS_SAN_URI) + return 1; + else + return 0; +} + +/** + * MHD_gnutls_x509_crt_get_key_usage - This function returns the certificate's key usage + * @cert: should contain a MHD_gnutls_x509_crt_t structure + * @key_usage: where the key usage bits will be stored + * @critical: will be non zero if the extension is marked as critical + * + * This function will return certificate's key usage, by reading the + * keyUsage X.509 extension (2.5.29.15). The key usage value will ORed values of the: + * GNUTLS_KEY_DIGITAL_SIGNATURE, GNUTLS_KEY_NON_REPUDIATION, + * GNUTLS_KEY_KEY_ENCIPHERMENT, GNUTLS_KEY_DATA_ENCIPHERMENT, + * GNUTLS_KEY_KEY_AGREEMENT, GNUTLS_KEY_KEY_CERT_SIGN, + * GNUTLS_KEY_CRL_SIGN, GNUTLS_KEY_ENCIPHER_ONLY, + * GNUTLS_KEY_DECIPHER_ONLY. + * + * A negative value may be returned in case of parsing error. + * If the certificate does not contain the keyUsage extension + * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned. + * + **/ +int +MHD_gnutls_x509_crt_get_key_usage (MHD_gnutls_x509_crt_t cert, + unsigned int *key_usage, + unsigned int *critical) +{ + int result; + MHD_gnutls_datum_t keyUsage; + uint16_t _usage; + + if (cert == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + if ((result = + MHD__gnutls_x509_crt_get_extension (cert, "2.5.29.15", 0, &keyUsage, + critical)) < 0) + { + return result; + } + + if (keyUsage.size == 0 || keyUsage.data == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + result = MHD__gnutls_x509_ext_extract_keyUsage (&_usage, keyUsage.data, + keyUsage.size); + MHD__gnutls_free_datum (&keyUsage); + + *key_usage = _usage; + + if (result < 0) + { + MHD_gnutls_assert (); + return result; + } + + return 0; +} + + +/** + * MHD_gnutls_x509_crt_export - This function will export the certificate + * @cert: Holds the certificate + * @format: the format of output params. One of PEM or DER. + * @output_data: will contain a certificate PEM or DER encoded + * @output_data_size: holds the size of output_data (and will be + * replaced by the actual size of parameters) + * + * This function will export the certificate to DER or PEM format. + * + * If the buffer provided is not long enough to hold the output, then + * *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will + * be returned. + * + * If the structure is PEM encoded, it will have a header + * of "BEGIN CERTIFICATE". + * + * Return value: In case of failure a negative value will be + * returned, and 0 on success. + **/ +int +MHD_gnutls_x509_crt_export (MHD_gnutls_x509_crt_t cert, + MHD_gnutls_x509_crt_fmt_t format, + void *output_data, size_t * output_data_size) +{ + if (cert == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + return MHD__gnutls_x509_export_int (cert->cert, format, "CERTIFICATE", + output_data, output_data_size); +} diff --git a/lib/libmicrohttpd/src/daemon/https/x509/x509.h b/lib/libmicrohttpd/src/daemon/https/x509/x509.h new file mode 100644 index 0000000000..9a01d95b93 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/x509.h @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef X509_H +#define X509_H + +#ifndef MIN +#define MIN(X,Y) ((X) > (Y) ? (Y) : (X)); +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <gnutls.h> +#include <libtasn1.h> +#include "gnutls_mpi.h" + +/* Some OIDs usually found in Distinguished names, or + * in Subject Directory Attribute extensions. + */ +#define GNUTLS_OID_X520_COUNTRY_NAME "2.5.4.6" +#define GNUTLS_OID_X520_ORGANIZATION_NAME "2.5.4.10" +#define GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME "2.5.4.11" +#define GNUTLS_OID_X520_COMMON_NAME "2.5.4.3" +#define GNUTLS_OID_X520_LOCALITY_NAME "2.5.4.7" +#define GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME "2.5.4.8" + +#define GNUTLS_OID_X520_INITIALS "2.5.4.43" +#define GNUTLS_OID_X520_GENERATION_QUALIFIER "2.5.4.44" +#define GNUTLS_OID_X520_SURNAME "2.5.4.4" +#define GNUTLS_OID_X520_GIVEN_NAME "2.5.4.42" +#define GNUTLS_OID_X520_TITLE "2.5.4.12" +#define GNUTLS_OID_X520_DN_QUALIFIER "2.5.4.46" +#define GNUTLS_OID_X520_PSEUDONYM "2.5.4.65" + +#define GNUTLS_OID_LDAP_DC "0.9.2342.19200300.100.1.25" +#define GNUTLS_OID_LDAP_UID "0.9.2342.19200300.100.1.1" + +/* The following should not be included in DN. + */ +#define GNUTLS_OID_PKCS9_EMAIL "1.2.840.113549.1.9.1" + +#define GNUTLS_OID_PKIX_DATE_OF_BIRTH "1.3.6.1.5.5.7.9.1" +#define GNUTLS_OID_PKIX_PLACE_OF_BIRTH "1.3.6.1.5.5.7.9.2" +#define GNUTLS_OID_PKIX_GENDER "1.3.6.1.5.5.7.9.3" +#define GNUTLS_OID_PKIX_COUNTRY_OF_CITIZENSHIP "1.3.6.1.5.5.7.9.4" +#define GNUTLS_OID_PKIX_COUNTRY_OF_RESIDENCE "1.3.6.1.5.5.7.9.5" + +/* Key purpose Object Identifiers. + */ +#define GNUTLS_KP_TLS_WWW_SERVER "1.3.6.1.5.5.7.3.1" +#define GNUTLS_KP_TLS_WWW_CLIENT "1.3.6.1.5.5.7.3.2" +#define GNUTLS_KP_CODE_SIGNING "1.3.6.1.5.5.7.3.3" +#define GNUTLS_KP_EMAIL_PROTECTION "1.3.6.1.5.5.7.3.4" +#define GNUTLS_KP_TIME_STAMPING "1.3.6.1.5.5.7.3.8" +#define GNUTLS_KP_OCSP_SIGNING "1.3.6.1.5.5.7.3.9" +#define GNUTLS_KP_ANY "2.5.29.37.0" + +/* Certificate handling functions. + */ + typedef enum MHD_gnutls_certificate_import_flags + { + /* Fail if the certificates in the buffer are more than the space + * allocated for certificates. The error code will be + * GNUTLS_E_SHORT_MEMORY_BUFFER. + */ + GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED = 1 + } MHD_gnutls_certificate_import_flags; + + int MHD_gnutls_x509_crt_init (MHD_gnutls_x509_crt_t * cert); + void MHD_gnutls_x509_crt_deinit (MHD_gnutls_x509_crt_t cert); + int MHD_gnutls_x509_crt_import (MHD_gnutls_x509_crt_t cert, + const MHD_gnutls_datum_t * data, + MHD_gnutls_x509_crt_fmt_t format); + int MHD_gnutls_x509_crt_export (MHD_gnutls_x509_crt_t cert, + MHD_gnutls_x509_crt_fmt_t format, + void *output_data, + size_t * output_data_size); + int MHD_gnutls_x509_crt_get_version (MHD_gnutls_x509_crt_t cert); + +#define GNUTLS_CRL_REASON_UNUSED 128 +#define GNUTLS_CRL_REASON_KEY_COMPROMISE 64 +#define GNUTLS_CRL_REASON_CA_COMPROMISE 32 +#define GNUTLS_CRL_REASON_AFFILIATION_CHANGED 16 +#define GNUTLS_CRL_REASON_SUPERSEEDED 8 +#define GNUTLS_CRL_REASON_CESSATION_OF_OPERATION 4 +#define GNUTLS_CRL_REASON_CERTIFICATE_HOLD 2 +#define GNUTLS_CRL_REASON_PRIVILEGE_WITHDRAWN 1 +#define GNUTLS_CRL_REASON_AA_COMPROMISE 32768 + + int MHD_gnutls_x509_crt_get_pk_algorithm (MHD_gnutls_x509_crt_t cert, + unsigned int *bits); + int MHD_gnutls_x509_crt_get_ca_status (MHD_gnutls_x509_crt_t cert, + unsigned int *critical); +/* The key_usage flags are defined in gnutls.h. They are the + * GNUTLS_KEY_* definitions. + */ + int MHD_gnutls_x509_crt_get_key_usage (MHD_gnutls_x509_crt_t cert, + unsigned int *key_usage, + unsigned int *critical); + int MHD_gnutls_x509_crt_set_key_usage (MHD_gnutls_x509_crt_t crt, + unsigned int usage); + +/* Read extensions by sequence number. */ + int MHD_gnutls_x509_crt_set_extension_by_oid (MHD_gnutls_x509_crt_t crt, + const char *oid, + const void *buf, + size_t sizeof_buf, + unsigned int critical); + +/* X.509 Certificate writing. + */ + int MHD_gnutls_x509_crt_set_dn_by_oid (MHD_gnutls_x509_crt_t crt, + const char *oid, + unsigned int raw_flag, + const void *name, + unsigned int sizeof_name); + int MHD_gnutls_x509_crt_set_issuer_dn_by_oid (MHD_gnutls_x509_crt_t crt, + const char *oid, + unsigned int raw_flag, + const void *name, + unsigned int sizeof_name); + int MHD_gnutls_x509_crt_set_version (MHD_gnutls_x509_crt_t crt, + unsigned int version); + int MHD_gnutls_x509_crt_set_key (MHD_gnutls_x509_crt_t crt, + MHD_gnutls_x509_privkey_t key); + int MHD_gnutls_x509_crt_set_ca_status (MHD_gnutls_x509_crt_t crt, + unsigned int ca); + int MHD_gnutls_x509_crt_set_basic_constraints (MHD_gnutls_x509_crt_t crt, + unsigned int ca, + int pathLenConstraint); + int MHD_gnutls_x509_crt_set_subject_alternative_name (MHD_gnutls_x509_crt_t + crt, + MHD_gnutls_x509_subject_alt_name_t + type, + const char + *data_string); + int MHD_gnutls_x509_crt_sign (MHD_gnutls_x509_crt_t crt, + MHD_gnutls_x509_crt_t issuer, + MHD_gnutls_x509_privkey_t issuer_key); + int MHD_gnutls_x509_crt_sign2 (MHD_gnutls_x509_crt_t crt, + MHD_gnutls_x509_crt_t issuer, + MHD_gnutls_x509_privkey_t issuer_key, + enum MHD_GNUTLS_HashAlgorithm, + unsigned int flags); + int MHD_gnutls_x509_crt_set_serial (MHD_gnutls_x509_crt_t cert, + const void *serial, size_t serial_size); + + int MHD_gnutls_x509_crt_set_subject_key_id (MHD_gnutls_x509_crt_t cert, + const void *id, size_t id_size); + + int MHD_gnutls_x509_crt_set_proxy_dn (MHD_gnutls_x509_crt_t crt, + MHD_gnutls_x509_crt_t eecrt, + unsigned int raw_flag, + const void *name, + unsigned int sizeof_name); + int MHD_gnutls_x509_crt_set_proxy (MHD_gnutls_x509_crt_t crt, + int pathLenConstraint, + const char *policyLanguage, + const char *policy, + size_t sizeof_policy); + + typedef enum MHD_gnutls_certificate_print_formats + { + GNUTLS_X509_CRT_FULL, + GNUTLS_X509_CRT_ONELINE, + GNUTLS_X509_CRT_UNSIGNED_FULL + } MHD_gnutls_certificate_print_formats_t; + + int MHD_gnutls_x509_crt_print (MHD_gnutls_x509_crt_t cert, + MHD_gnutls_certificate_print_formats_t + format, MHD_gnutls_datum_t * out); +/* Access to internal Certificate fields. + */ + + typedef void *MHD_gnutls_x509_dn_t; + +/* X.509 Certificate verification functions. + */ + typedef enum MHD_gnutls_certificate_verify_flags + { + /* If set a signer does not have to be a certificate authority. This + * flag should normaly be disabled, unless you know what this means. + */ + GNUTLS_VERIFY_DISABLE_CA_SIGN = 1, + + /* Allow only trusted CA certificates that have version 1. This is + * safer than GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT, and should be + * used instead. That way only signers in your trusted list will be + * allowed to have certificates of version 1. + */ + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT = 2, + + /* If a certificate is not signed by anyone trusted but exists in + * the trusted CA list do not treat it as trusted. + */ + GNUTLS_VERIFY_DO_NOT_ALLOW_SAME = 4, + + /* Allow CA certificates that have version 1 (both root and + * intermediate). This might be dangerous since those haven't the + * basicConstraints extension. Must be used in combination with + * GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT. + */ + GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT = 8, + + /* Allow certificates to be signed using the broken MD2 algorithm. + */ + GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2 = 16, + + /* Allow certificates to be signed using the broken MD5 algorithm. + */ + GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5 = 32 + } MHD_gnutls_certificate_verify_flags; + + +/* Flags for the MHD_gnutls_x509_privkey_export_pkcs8() function. + */ + typedef enum MHD_gnutls_pkcs_encrypt_flags_t + { + GNUTLS_PKCS_PLAIN = 1, /* if set the private key will not + * be encrypted. + */ + GNUTLS_PKCS_USE_PKCS12_3DES = 2, + GNUTLS_PKCS_USE_PKCS12_ARCFOUR = 4, + GNUTLS_PKCS_USE_PKCS12_RC2_40 = 8, + GNUTLS_PKCS_USE_PBES2_3DES = 16 + } MHD_gnutls_pkcs_encrypt_flags_t; + +#define GNUTLS_PKCS8_PLAIN GNUTLS_PKCS_PLAIN +#define GNUTLS_PKCS8_USE_PKCS12_3DES GNUTLS_PKCS_USE_PKCS12_3DES +#define GNUTLS_PKCS8_USE_PKCS12_ARCFOUR GNUTLS_PKCS_USE_PKCS12_ARCFOUR +#define GNUTLS_PKCS8_USE_PKCS12_RC2_40 GNUTLS_PKCS_USE_PKCS12_RC2_40 + + int MHD_gnutls_x509_privkey_init (MHD_gnutls_x509_privkey_t * key); + void MHD_gnutls_x509_privkey_deinit (MHD_gnutls_x509_privkey_t key); + int MHD_gnutls_x509_privkey_import (MHD_gnutls_x509_privkey_t key, + const MHD_gnutls_datum_t * data, + MHD_gnutls_x509_crt_fmt_t format); + int MHD_gnutls_x509_privkey_get_key_id (MHD_gnutls_x509_privkey_t key, + unsigned int flags, + unsigned char *output_data, + size_t * output_data_size); + + int MHD_gnutls_x509_privkey_export (MHD_gnutls_x509_privkey_t key, + MHD_gnutls_x509_crt_fmt_t format, + void *output_data, + size_t * output_data_size); + int MHD_gnutls_x509_privkey_export_pkcs8 (MHD_gnutls_x509_privkey_t key, + MHD_gnutls_x509_crt_fmt_t format, + const char *password, + unsigned int flags, + void *output_data, + size_t * output_data_size); + int MHD_gnutls_x509_privkey_export_rsa_raw (MHD_gnutls_x509_privkey_t key, + MHD_gnutls_datum_t * m, + MHD_gnutls_datum_t * e, + MHD_gnutls_datum_t * d, + MHD_gnutls_datum_t * p, + MHD_gnutls_datum_t * q, + MHD_gnutls_datum_t * u); + + int MHD_gnutls_x509_privkey_verify_data (MHD_gnutls_x509_privkey_t key, + unsigned int flags, + const MHD_gnutls_datum_t * data, + const MHD_gnutls_datum_t * + signature); + +#ifdef __cplusplus +} +#endif + +#define HASH_OID_SHA1 "1.3.14.3.2.26" +#define HASH_OID_MD5 "1.2.840.113549.2.5" +#define HASH_OID_MD2 "1.2.840.113549.2.2" +#define HASH_OID_RMD160 "1.3.36.3.2.1" +#define HASH_OID_SHA256 "2.16.840.1.101.3.4.2.1" +#define HASH_OID_SHA384 "2.16.840.1.101.3.4.2.2" +#define HASH_OID_SHA512 "2.16.840.1.101.3.4.2.3" + +typedef struct MHD_gnutls_x509_crt_int +{ + ASN1_TYPE cert; + int use_extensions; +} MHD_gnutls_x509_crt_int; + +#define MAX_PRIV_PARAMS_SIZE 6 /* ok for RSA and DSA */ + +/* parameters should not be larger than this limit */ +#define DSA_PRIVATE_PARAMS 5 +#define DSA_PUBLIC_PARAMS 4 +#define RSA_PRIVATE_PARAMS 6 +#define RSA_PUBLIC_PARAMS 2 + +#if MAX_PRIV_PARAMS_SIZE - RSA_PRIVATE_PARAMS < 0 +# error INCREASE MAX_PRIV_PARAMS +#endif + +#if MAX_PRIV_PARAMS_SIZE - DSA_PRIVATE_PARAMS < 0 +# error INCREASE MAX_PRIV_PARAMS +#endif + +typedef struct MHD_gtls_x509_privkey_int +{ + mpi_t params[MAX_PRIV_PARAMS_SIZE]; /* the size of params depends on the public + * key algorithm + */ + /* + * RSA: [0] is modulus + * [1] is public exponent + * [2] is private exponent + * [3] is prime1 (p) + * [4] is prime2 (q) + * [5] is coefficient (u == inverse of p mod q) + * note that other packages used inverse of q mod p, + * so we need to perform conversions. + * DSA: [0] is p + * [1] is q + * [2] is g + * [3] is y (public key) + * [4] is x (private key) + */ + int params_size; /* holds the number of params */ + + enum MHD_GNUTLS_PublicKeyAlgorithm pk_algorithm; + + int crippled; /* The crippled keys will not use the ASN1_TYPE key. + * The encoding will only be performed at the export + * phase, to optimize copying etc. Cannot be used with + * the exported API (used internally only). + */ + ASN1_TYPE key; +} MHD_gnutls_x509_privkey_int; + +int MHD_gnutls_x509_crt_get_pk_algorithm (MHD_gnutls_x509_crt_t cert, + unsigned int *bits); + +int MHD_gnutls_x509_crt_get_serial (MHD_gnutls_x509_crt_t cert, + void *result, size_t * result_size); + +int MHD_gnutls_x509_crt_init (MHD_gnutls_x509_crt_t * cert); +void MHD_gnutls_x509_crt_deinit (MHD_gnutls_x509_crt_t cert); +int MHD_gnutls_x509_crt_import (MHD_gnutls_x509_crt_t cert, + const MHD_gnutls_datum_t * data, + MHD_gnutls_x509_crt_fmt_t format); +int MHD_gnutls_x509_crt_export (MHD_gnutls_x509_crt_t cert, + MHD_gnutls_x509_crt_fmt_t format, + void *output_data, size_t * output_data_size); + +int MHD_gnutls_x509_crt_get_key_usage (MHD_gnutls_x509_crt_t cert, + unsigned int *key_usage, + unsigned int *critical); +int MHD_gnutls_x509_crt_get_version (MHD_gnutls_x509_crt_t cert); + +int MHD_gnutls_x509_privkey_init (MHD_gnutls_x509_privkey_t * key); +void MHD_gnutls_x509_privkey_deinit (MHD_gnutls_x509_privkey_t key); + +int MHD_gnutls_x509_privkey_generate (MHD_gnutls_x509_privkey_t key, + enum MHD_GNUTLS_PublicKeyAlgorithm algo, + unsigned int bits, unsigned int flags); + +int MHD_gnutls_x509_privkey_import (MHD_gnutls_x509_privkey_t key, + const MHD_gnutls_datum_t * data, + MHD_gnutls_x509_crt_fmt_t format); +int MHD_gnutls_x509_privkey_export_rsa_raw (MHD_gnutls_x509_privkey_t key, + MHD_gnutls_datum_t * m, + MHD_gnutls_datum_t * e, + MHD_gnutls_datum_t * d, + MHD_gnutls_datum_t * p, + MHD_gnutls_datum_t * q, + MHD_gnutls_datum_t * u); +int MHD_gnutls_x509_privkey_export (MHD_gnutls_x509_privkey_t key, + MHD_gnutls_x509_crt_fmt_t format, + void *output_data, + size_t * output_data_size); + +#define GNUTLS_CRL_REASON_UNUSED 128 +#define GNUTLS_CRL_REASON_KEY_COMPROMISE 64 +#define GNUTLS_CRL_REASON_CA_COMPROMISE 32 +#define GNUTLS_CRL_REASON_AFFILIATION_CHANGED 16 +#define GNUTLS_CRL_REASON_SUPERSEEDED 8 +#define GNUTLS_CRL_REASON_CESSATION_OF_OPERATION 4 +#define GNUTLS_CRL_REASON_CERTIFICATE_HOLD 2 +#define GNUTLS_CRL_REASON_PRIVILEGE_WITHDRAWN 1 +#define GNUTLS_CRL_REASON_AA_COMPROMISE 32768 + +#endif diff --git a/lib/libmicrohttpd/src/daemon/https/x509/x509_privkey.c b/lib/libmicrohttpd/src/daemon/https/x509/x509_privkey.c new file mode 100644 index 0000000000..e22da040b0 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/https/x509/x509_privkey.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GNUTLS. + * + * The GNUTLS library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#include <gnutls_int.h> +#include <gnutls_datum.h> +#include <gnutls_global.h> +#include <gnutls_errors.h> +#include <gnutls_rsa_export.h> +#include <gnutls_sig.h> +#include <common.h> +#include <gnutls_x509.h> +#include <x509_b64.h> +#include <x509.h> +#include <mpi.h> +#include <extensions.h> + +/* remove this when libgcrypt can handle the PKCS #1 coefficients from + * rsa keys + */ +#define CALC_COEFF 1 + +/** + * MHD_gnutls_x509_privkey_init - This function initializes a MHD_gnutls_crl structure + * @key: The structure to be initialized + * + * This function will initialize an private key structure. + * + * Returns 0 on success. + * + **/ +int +MHD_gnutls_x509_privkey_init (MHD_gnutls_x509_privkey_t * key) +{ + *key = MHD_gnutls_calloc (1, sizeof (MHD_gnutls_x509_privkey_int)); + + if (*key) + { + (*key)->key = ASN1_TYPE_EMPTY; + (*key)->pk_algorithm = MHD_GNUTLS_PK_UNKNOWN; + return 0; /* success */ + } + + return GNUTLS_E_MEMORY_ERROR; +} + +/** + * MHD_gnutls_x509_privkey_deinit - This function deinitializes memory used by a MHD_gnutls_x509_privkey_t structure + * @key: The structure to be initialized + * + * This function will deinitialize a private key structure. + * + **/ +void +MHD_gnutls_x509_privkey_deinit (MHD_gnutls_x509_privkey_t key) +{ + int i; + + if (!key) + return; + + for (i = 0; i < key->params_size; i++) + { + MHD_gtls_mpi_release (&key->params[i]); + } + + MHD__asn1_delete_structure (&key->key); + MHD_gnutls_free (key); +} + + +/* Converts an RSA PKCS#1 key to + * an internal structure (MHD_gnutls_private_key) + */ +ASN1_TYPE +MHD__gnutls_privkey_decode_pkcs1_rsa_key (const MHD_gnutls_datum_t * raw_key, + MHD_gnutls_x509_privkey_t pkey) +{ + int result; + ASN1_TYPE pkey_asn; + + if ((result = MHD__asn1_create_element (MHD__gnutls_getMHD__gnutls_asn (), + "GNUTLS.RSAPrivateKey", + &pkey_asn)) != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + return NULL; + } + + if ((sizeof (pkey->params) / sizeof (mpi_t)) < RSA_PRIVATE_PARAMS) + { + MHD_gnutls_assert (); + /* internal error. Increase the mpi_ts in params */ + return NULL; + } + + result = + MHD__asn1_der_decoding (&pkey_asn, raw_key->data, raw_key->size, NULL); + if (result != ASN1_SUCCESS) + { + MHD_gnutls_assert (); + goto error; + } + + if ((result = + MHD__gnutls_x509_read_int (pkey_asn, "modulus", &pkey->params[0])) < 0) + { + MHD_gnutls_assert (); + goto error; + } + + if ((result = MHD__gnutls_x509_read_int (pkey_asn, "publicExponent", + &pkey->params[1])) < 0) + { + MHD_gnutls_assert (); + goto error; + } + + if ((result = MHD__gnutls_x509_read_int (pkey_asn, "privateExponent", + &pkey->params[2])) < 0) + { + MHD_gnutls_assert (); + goto error; + } + + if ((result = + MHD__gnutls_x509_read_int (pkey_asn, "prime1", &pkey->params[3])) < 0) + { + MHD_gnutls_assert (); + goto error; + } + + if ((result = + MHD__gnutls_x509_read_int (pkey_asn, "prime2", &pkey->params[4])) < 0) + { + MHD_gnutls_assert (); + goto error; + } + +#ifdef CALC_COEFF + /* Calculate the coefficient. This is because the gcrypt + * library is uses the p,q in the reverse order. + */ + pkey->params[5] = + MHD__gnutls_mpi_snew (MHD__gnutls_mpi_get_nbits (pkey->params[0])); + + if (pkey->params[5] == NULL) + { + MHD_gnutls_assert (); + goto error; + } + + MHD__gnutls_mpi_invm (pkey->params[5], pkey->params[3], pkey->params[4]); + /* p, q */ +#else + if ((result = MHD__gnutls_x509_read_int (pkey_asn, "coefficient", + &pkey->params[5])) < 0) + { + MHD_gnutls_assert (); + goto error; + } +#endif + pkey->params_size = 6; + + return pkey_asn; + +error:MHD__asn1_delete_structure (&pkey_asn); + MHD_gtls_mpi_release (&pkey->params[0]); + MHD_gtls_mpi_release (&pkey->params[1]); + MHD_gtls_mpi_release (&pkey->params[2]); + MHD_gtls_mpi_release (&pkey->params[3]); + MHD_gtls_mpi_release (&pkey->params[4]); + MHD_gtls_mpi_release (&pkey->params[5]); + return NULL; + +} + +#define PEM_KEY_RSA "RSA PRIVATE KEY" + +/** + * MHD_gnutls_x509_privkey_import - This function will import a DER or PEM encoded key + * @key: The structure to store the parsed key + * @data: The DER or PEM encoded certificate. + * @format: One of DER or PEM + * + * This function will convert the given DER or PEM encoded key + * to the native MHD_gnutls_x509_privkey_t format. The output will be stored in @key . + * + * If the key is PEM encoded it should have a header of "RSA PRIVATE KEY", or + * "DSA PRIVATE KEY". + * + * Returns 0 on success. + * + **/ +int +MHD_gnutls_x509_privkey_import (MHD_gnutls_x509_privkey_t key, + const MHD_gnutls_datum_t * data, + MHD_gnutls_x509_crt_fmt_t format) +{ + int result = 0, need_free = 0; + MHD_gnutls_datum_t _data; + + if (key == NULL) + { + MHD_gnutls_assert (); + return GNUTLS_E_INVALID_REQUEST; + } + + _data.data = data->data; + _data.size = data->size; + + key->pk_algorithm = MHD_GNUTLS_PK_UNKNOWN; + + /* If the Certificate is in PEM format then decode it */ + if (format == GNUTLS_X509_FMT_PEM) + { + opaque *out; + + /* Try the first header */ + result + = + MHD__gnutls_fbase64_decode (PEM_KEY_RSA, data->data, data->size, + &out); + key->pk_algorithm = MHD_GNUTLS_PK_RSA; + + _data.data = out; + _data.size = result; + + need_free = 1; + } + + if (key->pk_algorithm == MHD_GNUTLS_PK_RSA) + { + key->key = MHD__gnutls_privkey_decode_pkcs1_rsa_key (&_data, key); + if (key->key == NULL) + MHD_gnutls_assert (); + } + else + { + /* Try decoding with both, and accept the one that succeeds. */ + key->pk_algorithm = MHD_GNUTLS_PK_RSA; + key->key = MHD__gnutls_privkey_decode_pkcs1_rsa_key (&_data, key); + + // TODO rm +// if (key->key == NULL) +// { +// key->pk_algorithm = GNUTLS_PK_DSA; +// key->key = decode_dsa_key(&_data, key); +// if (key->key == NULL) +// MHD_gnutls_assert(); +// } + } + + if (key->key == NULL) + { + MHD_gnutls_assert (); + result = GNUTLS_E_ASN1_DER_ERROR; + key->pk_algorithm = MHD_GNUTLS_PK_UNKNOWN; + return result; + } + + if (need_free) + MHD__gnutls_free_datum (&_data); + + /* The key has now been decoded. + */ + + return 0; +} diff --git a/lib/libmicrohttpd/src/daemon/internal.c b/lib/libmicrohttpd/src/daemon/internal.c new file mode 100644 index 0000000000..f30cc09a3a --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/internal.c @@ -0,0 +1,159 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file internal.h + * @brief internal shared structures + * @author Daniel Pittman + * @author Christian Grothoff + */ + +#include "internal.h" + +#if HAVE_MESSAGES +/** + * State to string dictionary. + */ +char * +MHD_state_to_string (enum MHD_CONNECTION_STATE state) +{ + switch (state) + { + case MHD_CONNECTION_INIT: + return "connection init"; + case MHD_CONNECTION_URL_RECEIVED: + return "connection url received"; + case MHD_CONNECTION_HEADER_PART_RECEIVED: + return "header partially received"; + case MHD_CONNECTION_HEADERS_RECEIVED: + return "headers received"; + case MHD_CONNECTION_HEADERS_PROCESSED: + return "headers processed"; + case MHD_CONNECTION_CONTINUE_SENDING: + return "continue sending"; + case MHD_CONNECTION_CONTINUE_SENT: + return "continue sent"; + case MHD_CONNECTION_BODY_RECEIVED: + return "body received"; + case MHD_CONNECTION_FOOTER_PART_RECEIVED: + return "footer partially received"; + case MHD_CONNECTION_FOOTERS_RECEIVED: + return "footers received"; + case MHD_CONNECTION_HEADERS_SENDING: + return "headers sending"; + case MHD_CONNECTION_HEADERS_SENT: + return "headers sent"; + case MHD_CONNECTION_NORMAL_BODY_READY: + return "normal body ready"; + case MHD_CONNECTION_NORMAL_BODY_UNREADY: + return "normal body unready"; + case MHD_CONNECTION_CHUNKED_BODY_READY: + return "chunked body ready"; + case MHD_CONNECTION_CHUNKED_BODY_UNREADY: + return "chunked body unready"; + case MHD_CONNECTION_BODY_SENT: + return "body sent"; + case MHD_CONNECTION_FOOTERS_SENDING: + return "footers sending"; + case MHD_CONNECTION_FOOTERS_SENT: + return "footers sent"; + case MHD_CONNECTION_CLOSED: + return "closed"; + case MHD_TLS_CONNECTION_INIT: + return "secure connection init"; + case MHD_TLS_HELLO_REQUEST: + return "secure hello request"; + case MHD_TLS_HANDSHAKE_FAILED: + return "secure handshake failed"; + case MHD_TLS_HANDSHAKE_COMPLETE: + return "secure handshake _complete"; + default: + return "unrecognized connection state"; + } +} +#endif + +#if HAVE_MESSAGES +/** + * fprintf-like helper function for logging debug + * messages. + */ +void +MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...) +{ + va_list va; + + if ((daemon->options & MHD_USE_DEBUG) == 0) + return; + va_start (va, format); + daemon->custom_error_log (daemon->custom_error_log_cls, format, va); + va_end (va); +} +#endif + +void +MHD_tls_log_func (int level, const char *str) +{ +#ifdef HAVE_MESSAGES + FPRINTF (stderr, "|<%d>| %s", level, str); +#endif +} + +/** + * Process escape sequences ('+'=space, %HH) + */ +size_t +MHD_http_unescape (char *val) +{ + char *rpos = val; + char *wpos = val; + unsigned int num; + + while ('\0' != *rpos) + { + switch (*rpos) + { + case '+': + *wpos = ' '; + wpos++; + rpos++; + break; + case '%': + if ( (1 == SSCANF (&rpos[1], + "%2x", &num)) || + (1 == SSCANF (&rpos[1], + "%2X", &num)) ) + { + *wpos = (unsigned char) num; + wpos++; + rpos += 3; + break; + } + /* intentional fall through! */ + default: + *wpos = *rpos; + wpos++; + rpos++; + } + } + *wpos = '\0'; /* add 0-terminator */ + return wpos - val; /* = strlen(val) */ +} + +/* end of internal.c */ diff --git a/lib/libmicrohttpd/src/daemon/internal.h b/lib/libmicrohttpd/src/daemon/internal.h new file mode 100644 index 0000000000..4c1feba06b --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/internal.h @@ -0,0 +1,855 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file internal.h + * @brief internal shared structures + * @author Daniel Pittman + * @author Christian Grothoff + */ + +#ifndef INTERNAL_H +#define INTERNAL_H + +#include "platform.h" +#include "microhttpd.h" +#if HTTPS_SUPPORT +#include "gnutls.h" +#endif + +#define EXTRA_CHECKS MHD_YES + +#define MHD_MAX(a,b) ((a)<(b)) ? (b) : (a) +#define MHD_MIN(a,b) ((a)<(b)) ? (a) : (b) + +/** + * Size by which MHD usually tries to increment read/write buffers. + * TODO: we should probably get rid of this magic constant and + * put in code to automatically determine a good value. + */ +#define MHD_BUF_INC_SIZE 2048 + +/** + * Handler for fatal errors. + */ +extern MHD_PanicCallback mhd_panic; + +/** + * Closure argument for "mhd_panic". + */ +extern void *mhd_panic_cls; + +/** + * Events we care about with respect to poll/select + * for file descriptors. + */ +enum MHD_PollActions + { + /** + * No event interests us. + */ + MHD_POLL_ACTION_NOTHING = 0, + + /** + * We would like to read. + */ + MHD_POLL_ACTION_IN = 1, + + /** + * We would like to write. + */ + MHD_POLL_ACTION_OUT = 2 + }; + + +/** + * Socket descriptor and events we care about. + */ +struct MHD_Pollfd { + /** + * Socket descriptor. + */ + int fd; + + /** + * Which events do we care about for this socket? + */ + enum MHD_PollActions events; +}; + + +#if HAVE_MESSAGES +/** + * fprintf-like helper function for logging debug + * messages. + */ +void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...); + +#endif +void MHD_tls_log_func (int level, const char *str); + +/** + * Process escape sequences ('+'=space, %HH). + * Updates val in place. + * + * @return length of the resulting val (strlen(val) maybe + * shorter afterwards due to elimination of escape sequences) + */ +size_t MHD_http_unescape (char *val); + +/** + * Header or cookie in HTTP request or response. + */ +struct MHD_HTTP_Header +{ + /** + * Headers are kept in a linked list. + */ + struct MHD_HTTP_Header *next; + + /** + * The name of the header (key), without + * the colon. + */ + char *header; + + /** + * The value of the header. + */ + char *value; + + /** + * Type of the header (where in the HTTP + * protocol is this header from). + */ + enum MHD_ValueKind kind; + +}; + +/** + * Representation of a response. + */ +struct MHD_Response +{ + + /** + * Headers to send for the response. Initially + * the linked list is created in inverse order; + * the order should be inverted before sending! + */ + struct MHD_HTTP_Header *first_header; + + /** + * Buffer pointing to data that we are supposed + * to send as a response. + */ + char *data; + + /** + * Closure to give to the content reader + * free callback. + */ + void *crc_cls; + + /** + * How do we get more data? NULL if we are + * given all of the data up front. + */ + MHD_ContentReaderCallback crc; + + /** + * NULL if data must not be freed, otherwise + * either user-specified callback or "&free". + */ + MHD_ContentReaderFreeCallback crfc; + + /** + * Mutex to synchronize access to data/size and + * reference counts. + */ + pthread_mutex_t mutex; + + /** + * Reference count for this response. Free + * once the counter hits zero. + */ + unsigned int reference_count; + + /** + * Set to -1 if size is not known. + */ + uint64_t total_size; + + /** + * Size of data. + */ + size_t data_size; + + /** + * Size of the data buffer. + */ + size_t data_buffer_size; + + /** + * At what offset in the stream is the + * beginning of data located? + */ + uint64_t data_start; + +}; + +/** + * States in a state machine for a connection. + * + * Transitions are any-state to CLOSED, any state to state+1, + * FOOTERS_SENT to INIT. CLOSED is the terminal state and + * INIT the initial state. + * + * Note that transitions for *reading* happen only after + * the input has been processed; transitions for + * *writing* happen after the respective data has been + * put into the write buffer (the write does not have + * to be completed yet). A transition to CLOSED or INIT + * requires the write to be complete. + */ +enum MHD_CONNECTION_STATE +{ + /** + * Connection just started (no headers received). + * Waiting for the line with the request type, URL and version. + */ + MHD_CONNECTION_INIT = 0, + + /** + * 1: We got the URL (and request type and version). Wait for a header line. + */ + MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1, + + /** + * 2: We got part of a multi-line request header. Wait for the rest. + */ + MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1, + + /** + * 3: We got the request headers. Process them. + */ + MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1, + + /** + * 4: We have processed the request headers. Send 100 continue. + */ + MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1, + + /** + * 5: We have processed the headers and need to send 100 CONTINUE. + */ + MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1, + + /** + * 6: We have sent 100 CONTINUE (or do not need to). Read the message body. + */ + MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1, + + /** + * 7: We got the request body. Wait for a line of the footer. + */ + MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1, + + /** + * 8: We got part of a line of the footer. Wait for the + * rest. + */ + MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1, + + /** + * 9: We received the entire footer. Wait for a response to be queued + * and prepare the response headers. + */ + MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1, + + /** + * 10: We have prepared the response headers in the writ buffer. + * Send the response headers. + */ + MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1, + + /** + * 11: We have sent the response headers. Get ready to send the body. + */ + MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1, + + /** + * 12: We are ready to send a part of a non-chunked body. Send it. + */ + MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1, + + /** + * 13: We are waiting for the client to provide more + * data of a non-chunked body. + */ + MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1, + + /** + * 14: We are ready to send a chunk. + */ + MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1, + + /** + * 15: We are waiting for the client to provide a chunk of the body. + */ + MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1, + + /** + * 16: We have sent the response body. Prepare the footers. + */ + MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1, + + /** + * 17: We have prepared the response footer. Send it. + */ + MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1, + + /** + * 18: We have sent the response footer. Shutdown or restart. + */ + MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1, + + /** + * 19: This connection is closed (no more activity + * allowed). + */ + MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1, + + /* + * SSL/TLS connection states + */ + + /** + * The initial connection state for all secure connectoins + * Handshake messages will be processed in this state & while + * in the 'MHD_TLS_HELLO_REQUEST' state + */ + MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_CLOSED + 1, + + /** + * This state indicates the server has send a 'Hello Request' to + * the client & a renegotiation of the handshake is in progress. + * + * Handshake messages will processed in this state & while + * in the 'MHD_TLS_CONNECTION_INIT' state + */ + MHD_TLS_HELLO_REQUEST, + + MHD_TLS_HANDSHAKE_FAILED, + + MHD_TLS_HANDSHAKE_COMPLETE + +}; + +/** + * Should all state transitions be printed to stderr? + */ +#define DEBUG_STATES MHD_NO + +#if HAVE_MESSAGES +char *MHD_state_to_string (enum MHD_CONNECTION_STATE state); +#endif + +/** + * Function to receive plaintext data. + * + * @param conn the connection struct + * @param write_to where to write received data + * @param max_bytes maximum number of bytes to receive + * @return number of bytes written to write_to + */ +typedef ssize_t (*ReceiveCallback) (struct MHD_Connection * conn, + void *write_to, size_t max_bytes); + + +/** + * Function to transmit plaintext data. + * + * @param conn the connection struct + * @param read_from where to read data to transmit + * @param max_bytes maximum number of bytes to transmit + * @return number of bytes transmitted + */ +typedef ssize_t (*TransmitCallback) (struct MHD_Connection * conn, + const void *write_to, size_t max_bytes); + + +/** + * State kept for each HTTP request. + */ +struct MHD_Connection +{ + + /** + * This is a linked list. + */ + struct MHD_Connection *next; + + /** + * Reference to the MHD_Daemon struct. + */ + struct MHD_Daemon *daemon; + + /** + * Linked list of parsed headers. + */ + struct MHD_HTTP_Header *headers_received; + + /** + * Response to transmit (initially NULL). + */ + struct MHD_Response *response; + + /** + * The memory pool is created whenever we first read + * from the TCP stream and destroyed at the end of + * each request (and re-created for the next request). + * In the meantime, this pointer is NULL. The + * pool is used for all connection-related data + * except for the response (which maybe shared between + * connections) and the IP address (which persists + * across individual requests). + */ + struct MemoryPool *pool; + + /** + * We allow the main application to associate some + * pointer with the connection. Here is where we + * store it. (MHD does not know or care what it + * is). + */ + void *client_context; + + /** + * Request method. Should be GET/POST/etc. Allocated + * in pool. + */ + char *method; + + /** + * Requested URL (everything after "GET" only). Allocated + * in pool. + */ + char *url; + + /** + * HTTP version string (i.e. http/1.1). Allocated + * in pool. + */ + char *version; + + /** + * Buffer for reading requests. Allocated + * in pool. Actually one byte larger than + * read_buffer_size (if non-NULL) to allow for + * 0-termination. + */ + char *read_buffer; + + /** + * Buffer for writing response (headers only). Allocated + * in pool. + */ + char *write_buffer; + + /** + * Last incomplete header line during parsing of headers. + * Allocated in pool. Only valid if state is + * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED. + */ + char *last; + + /** + * Position after the colon on the last incomplete header + * line during parsing of headers. + * Allocated in pool. Only valid if state is + * either HEADER_PART_RECEIVED or FOOTER_PART_RECEIVED. + */ + char *colon; + + /** + * Foreign address (of length addr_len). MALLOCED (not + * in pool!). + */ + struct sockaddr_in *addr; + + /** + * Thread for this connection (if we are using + * one thread per connection). + */ + pthread_t pid; + + /** + * Size of read_buffer (in bytes). This value indicates + * how many bytes we're willing to read into the buffer; + * the real buffer is one byte longer to allow for + * adding zero-termination (when needed). + */ + size_t read_buffer_size; + + /** + * Position where we currently append data in + * read_buffer (last valid position). + */ + size_t read_buffer_offset; + + /** + * Size of write_buffer (in bytes). + */ + size_t write_buffer_size; + + /** + * Offset where we are with sending from write_buffer. + */ + size_t write_buffer_send_offset; + + /** + * Last valid location in write_buffer (where do we + * append and up to where is it safe to send?) + */ + size_t write_buffer_append_offset; + + /** + * How many more bytes of the body do we expect + * to read? "-1" for unknown. + */ + uint64_t remaining_upload_size; + + /** + * Current write position in the actual response + * (excluding headers, content only; should be 0 + * while sending headers). + */ + uint64_t response_write_position; + + /** + * Position in the 100 CONTINUE message that + * we need to send when receiving http 1.1 requests. + */ + size_t continue_message_write_offset; + + /** + * Length of the foreign address. + */ + socklen_t addr_len; + + /** + * Last time this connection had any activity + * (reading or writing). + */ + time_t last_activity; + + /** + * Did we ever call the "default_handler" on this connection? + * (this flag will determine if we call the 'notify_completed' + * handler when the connection closes down). + */ + int client_aware; + + /** + * Socket for this connection. Set to -1 if + * this connection has died (daemon should clean + * up in that case). + */ + int socket_fd; + + /** + * Has this socket been closed for reading (i.e. + * other side closed the connection)? If so, + * we must completely close the connection once + * we are done sending our response (and stop + * trying to read from this socket). + */ + int read_closed; + + /** + * State in the FSM for this connection. + */ + enum MHD_CONNECTION_STATE state; + + /** + * HTTP response code. Only valid if response object + * is already set. + */ + unsigned int responseCode; + + /** + * Set to MHD_YES if the response's content reader + * callback failed to provide data the last time + * we tried to read from it. In that case, the + * write socket should be marked as unready until + * the CRC call succeeds. + */ + int response_unready; + + /** + * Are we sending with chunked encoding? + */ + int have_chunked_response; + + /** + * Are we receiving with chunked encoding? This will be set to + * MHD_YES after we parse the headers and are processing the body + * with chunks. After we are done with the body and we are + * processing the footers; once the footers are also done, this will + * be set to MHD_NO again (before the final call to the handler). + */ + int have_chunked_upload; + + /** + * If we are receiving with chunked encoding, where are we right + * now? Set to 0 if we are waiting to receive the chunk size; + * otherwise, this is the size of the current chunk. A value of + * zero is also used when we're at the end of the chunks. + */ + unsigned int current_chunk_size; + + /** + * If we are receiving with chunked encoding, where are we currently + * with respect to the current chunk (at what offset / position)? + */ + unsigned int current_chunk_offset; + + /** + * Handler used for processing read connection operations + */ + int (*read_handler) (struct MHD_Connection * connection); + + /** + * Handler used for processing write connection operations + */ + int (*write_handler) (struct MHD_Connection * connection); + + /** + * Handler used for processing idle connection operations + */ + int (*idle_handler) (struct MHD_Connection * connection); + + /** + * Function used for reading HTTP request stream. + */ + ReceiveCallback recv_cls; + + /** + * Function used for writing HTTP response stream. + */ + TransmitCallback send_cls; + +#if HTTPS_SUPPORT + /** + * State required for HTTPS/SSL/TLS support. + */ + MHD_gtls_session_t tls_session; +#endif +}; + +typedef void * (*LogCallback)(void * cls, const char * uri); + +/** + * State kept for each MHD daemon. + */ +struct MHD_Daemon +{ + + /** + * Callback function for all requests. + */ + MHD_AccessHandlerCallback default_handler; + + /** + * Closure argument to default_handler. + */ + void *default_handler_cls; + + /** + * Linked list of our current connections. + */ + struct MHD_Connection *connections; + + /** + * Function to call to check if we should + * accept or reject an incoming request. + * May be NULL. + */ + MHD_AcceptPolicyCallback apc; + + /** + * Closure argument to apc. + */ + void *apc_cls; + + /** + * Function to call when we are done processing + * a particular request. May be NULL. + */ + MHD_RequestCompletedCallback notify_completed; + + /** + * Closure argument to notify_completed. + */ + void *notify_completed_cls; + + /** + * Function to call with the full URI at the + * beginning of request processing. May be NULL. + * <p> + * Returns the initial pointer to internal state + * kept by the client for the request. + */ + LogCallback uri_log_callback; + + /** + * Closure argument to uri_log_callback. + */ + void *uri_log_callback_cls; + +#if HAVE_MESSAGES + /** + * Function for logging error messages (if we + * support error reporting). + */ + void (*custom_error_log) (void *cls, const char *fmt, va_list va); + + /** + * Closure argument to custom_error_log. + */ + void *custom_error_log_cls; +#endif + + /** + * PID of the select thread (if we have internal select) + */ + pthread_t pid; + + /** + * Listen socket. + */ + int socket_fd; + + /** + * Are we shutting down? + */ + int shutdown; + + /** + * Size of the per-connection memory pools. + */ + size_t pool_size; + + /** + * Limit on the number of parallel connections. + */ + unsigned int max_connections; + + /** + * After how many seconds of inactivity should + * connections time out? Zero for no timeout. + */ + unsigned int connection_timeout; + + /** + * Maximum number of connections per IP, or 0 for + * unlimited. + */ + unsigned int per_ip_connection_limit; + + /** + * Table storing number of connections per IP + */ + void *per_ip_connection_count; + + /** + * Mutex for per-IP connection counts + */ + pthread_mutex_t per_ip_connection_mutex; + + /** + * Daemon's options. + */ + enum MHD_OPTION options; + + /** + * Listen port. + */ + unsigned short port; + +#if HTTPS_SUPPORT + /** + * What kind of credentials are we offering + * for SSL/TLS? + */ + enum MHD_GNUTLS_CredentialsType cred_type; + + /** + * Server x509 credentials + */ + MHD_gtls_cert_credentials_t x509_cred; + + /** + * Cipher priority cache + */ + MHD_gnutls_priority_t priority_cache; + + /** + * Diffie-Hellman parameters + */ + MHD_gtls_dh_params_t dh_params; + + /** + * Pointer to our SSL/TLS key (in ASCII) in memory. + */ + const char *https_mem_key; + + /** + * Pointer to our SSL/TLS certificate (in ASCII) in memory. + */ + const char *https_mem_cert; +#endif + + /** + * Pointer to master daemon (NULL if this is the master) + */ + struct MHD_Daemon *master; + + /** + * Worker daemons (one per thread) + */ + struct MHD_Daemon *worker_pool; + + /** + * Number of worker daemons + */ + unsigned int worker_pool_size; +}; + + +#if EXTRA_CHECKS +#define EXTRA_CHECK(a) if (!(a)) abort(); +#else +#define EXTRA_CHECK(a) +#endif + + + +#endif diff --git a/lib/libmicrohttpd/src/daemon/memorypool.c b/lib/libmicrohttpd/src/daemon/memorypool.c new file mode 100644 index 0000000000..6df5cb5fd8 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/memorypool.c @@ -0,0 +1,241 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2009, 2010 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file memorypool.c + * @brief memory pool + * @author Christian Grothoff + */ +#include "memorypool.h" + +/* define MAP_ANONYMOUS for Mac OS X */ +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif +#ifndef MAP_FAILED +#define MAP_FAILED ((void*)-1) +#endif + +/** + * Align to 2x word size (as GNU libc does). + */ +#define ALIGN_SIZE (2 * sizeof(void*)) + +/** + * Round up 'n' to a multiple of ALIGN_SIZE. + */ +#define ROUND_TO_ALIGN(n) ((n+(ALIGN_SIZE-1)) & (~(ALIGN_SIZE-1))) + +struct MemoryPool +{ + + /** + * Pointer to the pool's memory + */ + char *memory; + + /** + * Size of the pool. + */ + size_t size; + + /** + * Offset of the first unallocated byte. + */ + size_t pos; + + /** + * Offset of the last unallocated byte. + */ + size_t end; + + /** + * MHD_NO if pool was malloc'ed, MHD_YES if mmapped. + */ + int is_mmap; +}; + +/** + * Create a memory pool. + * + * @param max maximum size of the pool + */ +struct MemoryPool * +MHD_pool_create (size_t max) +{ + struct MemoryPool *pool; + + pool = malloc (sizeof (struct MemoryPool)); + if (pool == NULL) + return NULL; +#ifdef MAP_ANONYMOUS + pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS, -1, 0); +#else + pool->memory = MAP_FAILED; +#endif + if ((pool->memory == MAP_FAILED) || (pool->memory == NULL)) + { + pool->memory = malloc (max); + if (pool->memory == NULL) + { + free (pool); + return NULL; + } + pool->is_mmap = MHD_NO; + } + else + { + pool->is_mmap = MHD_YES; + } + pool->pos = 0; + pool->end = max; + pool->size = max; + return pool; +} + +/** + * Destroy a memory pool. + */ +void +MHD_pool_destroy (struct MemoryPool *pool) +{ + if (pool == NULL) + return; + if (pool->is_mmap == MHD_NO) + free (pool->memory); + else + MUNMAP (pool->memory, pool->size); + free (pool); +} + +/** + * Allocate size bytes from the pool. + * @return NULL if the pool cannot support size more + * bytes + */ +void * +MHD_pool_allocate (struct MemoryPool *pool, + size_t size, int from_end) +{ + void *ret; + + size = ROUND_TO_ALIGN (size); + if ((pool->pos + size > pool->end) || (pool->pos + size < pool->pos)) + return NULL; + if (from_end == MHD_YES) + { + ret = &pool->memory[pool->end - size]; + pool->end -= size; + } + else + { + ret = &pool->memory[pool->pos]; + pool->pos += size; + } + return ret; +} + +/** + * Reallocate a block of memory obtained from the pool. + * This is particularly efficient when growing or + * shrinking the block that was last (re)allocated. + * If the given block is not the most recenlty + * (re)allocated block, the memory of the previous + * allocation may be leaked until the pool is + * destroyed (and copying the data maybe required). + * + * @param old the existing block + * @param old_size the size of the existing block + * @param new_size the new size of the block + * @return new address of the block, or + * NULL if the pool cannot support new_size + * bytes (old continues to be valid for old_size) + */ +void * +MHD_pool_reallocate (struct MemoryPool *pool, + void *old, + size_t old_size, + size_t new_size) +{ + void *ret; + + new_size = ROUND_TO_ALIGN (new_size); + if ((pool->end < old_size) || (pool->end < new_size)) + return NULL; /* unsatisfiable or bogus request */ + + if ((pool->pos >= old_size) && (&pool->memory[pool->pos - old_size] == old)) + { + /* was the previous allocation - optimize! */ + if (pool->pos + new_size - old_size <= pool->end) + { + /* fits */ + pool->pos += new_size - old_size; + if (new_size < old_size) /* shrinking - zero again! */ + memset (&pool->memory[pool->pos], 0, old_size - new_size); + return old; + } + /* does not fit */ + return NULL; + } + if (new_size <= old_size) + return old; /* cannot shrink, no need to move */ + if ((pool->pos + new_size >= pool->pos) && + (pool->pos + new_size <= pool->end)) + { + /* fits */ + ret = &pool->memory[pool->pos]; + memcpy (ret, old, old_size); + pool->pos += new_size; + return ret; + } + /* does not fit */ + return NULL; +} + +/** + * Clear all entries from the memory pool except + * for "keep" of the given "size". + * + * @param keep pointer to the entry to keep (maybe NULL) + * @param size how many bytes need to be kept at this address + * @return addr new address of "keep" (if it had to change) + */ +void * +MHD_pool_reset (struct MemoryPool *pool, + void *keep, + size_t size) +{ + size = ROUND_TO_ALIGN (size); + if (keep != NULL) + { + if (keep != pool->memory) + { + memmove (pool->memory, keep, size); + keep = pool->memory; + } + pool->pos = size; + } + pool->end = pool->size; + return keep; +} + + + +/* end of memorypool.c */ diff --git a/lib/libmicrohttpd/src/daemon/memorypool.h b/lib/libmicrohttpd/src/daemon/memorypool.h new file mode 100644 index 0000000000..51f8167489 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/memorypool.h @@ -0,0 +1,97 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2009 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file memorypool.h + * @brief memory pool; mostly used for efficient (de)allocation + * for each connection and bounding memory use for each + * request + * @author Christian Grothoff + */ + +#ifndef MEMORYPOOL_H +#define MEMORYPOOL_H + +#include "internal.h" + +/** + * Opaque handle for a memory pool. + * Pools are not reentrant and must not be used + * by multiple threads. + */ +struct MemoryPool; + +/** + * Create a memory pool. + * + * @param max maximum size of the pool + */ +struct MemoryPool *MHD_pool_create (size_t max); + +/** + * Destroy a memory pool. + */ +void MHD_pool_destroy (struct MemoryPool *pool); + +/** + * Allocate size bytes from the pool. + * + * @param from_end allocate from end of pool (set to MHD_YES); + * use this for small, persistent allocations that + * will never be reallocated + * @return NULL if the pool cannot support size more + * bytes + */ +void *MHD_pool_allocate (struct MemoryPool *pool, + size_t size, int from_end); + +/** + * Reallocate a block of memory obtained from the pool. + * This is particularly efficient when growing or + * shrinking the block that was last (re)allocated. + * If the given block is not the most recenlty + * (re)allocated block, the memory of the previous + * allocation may be leaked until the pool is + * destroyed (and copying the data maybe required). + * + * @param old the existing block + * @param old_size the size of the existing block + * @param new_size the new size of the block + * @return new address of the block, or + * NULL if the pool cannot support new_size + * bytes (old continues to be valid for old_size) + */ +void *MHD_pool_reallocate (struct MemoryPool *pool, + void *old, + size_t old_size, + size_t new_size); + +/** + * Clear all entries from the memory pool except + * for "keep" of the given "size". + * + * @param keep pointer to the entry to keep (maybe NULL) + * @param size how many bytes need to be kept at this address + * @return addr new address of "keep" (if it had to change) + */ +void *MHD_pool_reset (struct MemoryPool *pool, + void *keep, + size_t size); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/postprocessor.c b/lib/libmicrohttpd/src/daemon/postprocessor.c new file mode 100644 index 0000000000..735c8d3687 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/postprocessor.c @@ -0,0 +1,1044 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2009 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file postprocessor.c + * @brief Methods for parsing POST data + * @author Christian Grothoff + */ + +#include "internal.h" + +/** + * Size of on-stack buffer that we use for un-escaping of the value. + */ +#define XBUF_SIZE 1024 + +/** + * States in the PP parser's state machine. + */ +enum PP_State +{ + /* general states */ + PP_Error, + PP_Done, + PP_Init, + + /* url encoding-states */ + PP_ProcessValue, + PP_ExpectNewLine, + + /* post encoding-states */ + PP_ProcessEntryHeaders, + PP_PerformCheckMultipart, + PP_ProcessValueToBoundary, + PP_PerformCleanup, + + /* nested post-encoding states */ + PP_Nested_Init, + PP_Nested_PerformMarking, + PP_Nested_ProcessEntryHeaders, + PP_Nested_ProcessValueToBoundary, + PP_Nested_PerformCleanup, + +}; + +enum RN_State +{ + /** + * No RN-preprocessing in this state. + */ + RN_Inactive = 0, + + /** + * If the next character is '\n', skip it. Otherwise, + * just go inactive. + */ + RN_OptN = 1, + + /** + * Expect '\r\n' (and only '\r\n'). As always, we also + * expect only '\r' or only '\n'. + */ + RN_Full = 2, + + /** + * Expect either '\r\n' or '--\r\n'. If '--\r\n', transition into dash-state + * for the main state machine + */ + RN_Dash = 3, + + /** + * Got a single dash, expect second dash. + */ + RN_Dash2 = 4, +}; + +/** + * Bits for the globally known fields that + * should not be deleted when we exit the + * nested state. + */ +enum NE_State +{ + NE_none = 0, + NE_content_name = 1, + NE_content_type = 2, + NE_content_filename = 4, + NE_content_transfer_encoding = 8, +}; + +/** + * Internal state of the post-processor. Note that the fields + * are sorted by type to enable optimal packing by the compiler. + */ +struct MHD_PostProcessor +{ + + /** + * The connection for which we are doing + * POST processing. + */ + struct MHD_Connection *connection; + + /** + * Function to call with POST data. + */ + MHD_PostDataIterator ikvi; + + /** + * Extra argument to ikvi. + */ + void *cls; + + /** + * Encoding as given by the headers of the + * connection. + */ + const char *encoding; + + /** + * Primary boundary (points into encoding string) + */ + const char *boundary; + + /** + * Nested boundary (if we have multipart/mixed encoding). + */ + char *nested_boundary; + + /** + * Pointer to the name given in disposition. + */ + char *content_name; + + /** + * Pointer to the (current) content type. + */ + char *content_type; + + /** + * Pointer to the (current) filename. + */ + char *content_filename; + + /** + * Pointer to the (current) encoding. + */ + char *content_transfer_encoding; + + /** + * Unprocessed value bytes due to escape + * sequences (URL-encoding only). + */ + char xbuf[8]; + + /** + * Size of our buffer for the key. + */ + size_t buffer_size; + + /** + * Current position in the key buffer. + */ + size_t buffer_pos; + + /** + * Current position in xbuf. + */ + size_t xbuf_pos; + + /** + * Current offset in the value being processed. + */ + uint64_t value_offset; + + /** + * strlen(boundary) -- if boundary != NULL. + */ + size_t blen; + + /** + * strlen(nested_boundary) -- if nested_boundary != NULL. + */ + size_t nlen; + + /** + * State of the parser. + */ + enum PP_State state; + + /** + * Side-state-machine: skip '\r\n' (or just '\n'). + * Set to 0 if we are not in skip mode. Set to 2 + * if a '\r\n' is expected, set to 1 if a '\n' should + * be skipped if it is the next character. + */ + enum RN_State skip_rn; + + /** + * If we are in skip_rn with "dash" mode and + * do find 2 dashes, what state do we go into? + */ + enum PP_State dash_state; + + /** + * Which headers are global? (used to tell which + * headers were only valid for the nested multipart). + */ + enum NE_State have; + +}; + + +/** + * Create a PostProcessor. + * + * A PostProcessor can be used to (incrementally) + * parse the data portion of a POST request. + * + * @param connection the connection on which the POST is + * happening (used to determine the POST format) + * @param buffer_size maximum number of bytes to use for + * internal buffering (used only for the parsing, + * specifically the parsing of the keys). A + * tiny value (256-1024) should be sufficient. + * Do NOT use 0. + * @param ikvi iterator to be called with the parsed data + * @param cls first argument to ikvi + * @return NULL on error (out of memory, unsupported encoding), + * otherwise a PP handle + */ +struct MHD_PostProcessor * +MHD_create_post_processor (struct MHD_Connection *connection, + size_t buffer_size, + MHD_PostDataIterator ikvi, void *cls) +{ + struct MHD_PostProcessor *ret; + const char *encoding; + const char *boundary; + size_t blen; + + if ((buffer_size < 256) || (connection == NULL) || (ikvi == NULL)) + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); + encoding = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONTENT_TYPE); + if (encoding == NULL) + return NULL; + boundary = NULL; + if (0 != strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, encoding, + strlen (MHD_HTTP_POST_ENCODING_FORM_URLENCODED))) + { + if (0 != + strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, encoding, + strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) + return NULL; + boundary = + &encoding[strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA)]; + /* Q: should this be "strcasestr"? */ + if (NULL != strstr (boundary, "boundary=")) + boundary = strstr (boundary, "boundary=") + strlen ("boundary="); + else + return NULL; /* failed to determine boundary */ + blen = strlen (boundary); + if ((blen == 0) || (blen * 2 + 2 > buffer_size)) + return NULL; /* (will be) out of memory or invalid boundary */ + } + else + blen = 0; + ret = malloc (sizeof (struct MHD_PostProcessor) + buffer_size + 1); + if (ret == NULL) + return NULL; + memset (ret, 0, sizeof (struct MHD_PostProcessor) + buffer_size + 1); + ret->connection = connection; + ret->ikvi = ikvi; + ret->cls = cls; + ret->encoding = encoding; + ret->buffer_size = buffer_size; + ret->state = PP_Init; + ret->blen = blen; + ret->boundary = boundary; + ret->skip_rn = RN_Inactive; + return ret; +} + +/** + * Process url-encoded POST data. + */ +static int +post_process_urlencoded (struct MHD_PostProcessor *pp, + const char *post_data, + size_t post_data_len) +{ + size_t equals; + size_t amper; + size_t poff; + size_t xoff; + size_t delta; + int end_of_value_found; + char *buf; + char xbuf[XBUF_SIZE + 1]; + + buf = (char *) &pp[1]; + poff = 0; + while (poff < post_data_len) + { + switch (pp->state) + { + case PP_Error: + return MHD_NO; + case PP_Done: + /* did not expect to receive more data */ + pp->state = PP_Error; + return MHD_NO; + case PP_Init: + equals = 0; + while ((equals + poff < post_data_len) && + (post_data[equals + poff] != '=')) + equals++; + if (equals + pp->buffer_pos > pp->buffer_size) + { + pp->state = PP_Error; /* out of memory */ + return MHD_NO; + } + memcpy (&buf[pp->buffer_pos], &post_data[poff], equals); + pp->buffer_pos += equals; + if (equals + poff == post_data_len) + return MHD_YES; /* no '=' yet */ + buf[pp->buffer_pos] = '\0'; /* 0-terminate key */ + pp->buffer_pos = 0; /* reset for next key */ + MHD_http_unescape (buf); + poff += equals + 1; + pp->state = PP_ProcessValue; + pp->value_offset = 0; + break; + case PP_ProcessValue: + /* obtain rest of value from previous iteration */ + memcpy (xbuf, pp->xbuf, pp->xbuf_pos); + xoff = pp->xbuf_pos; + pp->xbuf_pos = 0; + + /* find last position in input buffer that is part of the value */ + amper = 0; + while ((amper + poff < post_data_len) && + (amper < XBUF_SIZE) && + (post_data[amper + poff] != '&') && + (post_data[amper + poff] != '\n') && + (post_data[amper + poff] != '\r')) + amper++; + end_of_value_found = ((amper + poff < post_data_len) && + ((post_data[amper + poff] == '&') || + (post_data[amper + poff] == '\n') || + (post_data[amper + poff] == '\r'))); + /* compute delta, the maximum number of bytes that we will be able to + process right now (either amper-limited of xbuf-size limited) */ + delta = amper; + if (delta > XBUF_SIZE - xoff) + delta = XBUF_SIZE - xoff; + + /* move input into processing buffer */ + memcpy (&xbuf[xoff], &post_data[poff], delta); + xoff += delta; + poff += delta; + + /* find if escape sequence is at the end of the processing buffer; + if so, exclude those from processing (reduce delta to point at + end of processed region) */ + delta = xoff; + if ((delta > 0) && (xbuf[delta - 1] == '%')) + delta--; + else if ((delta > 1) && (xbuf[delta - 2] == '%')) + delta -= 2; + + /* if we have an incomplete escape sequence, save it to + pp->xbuf for later */ + if (delta < xoff) + { + memcpy (pp->xbuf, &xbuf[delta], xoff - delta); + pp->xbuf_pos = xoff - delta; + xoff = delta; + } + + /* If we have nothing to do (delta == 0) and + not just because the value is empty (are + waiting for more data), go for next iteration */ + if ((xoff == 0) && (poff == post_data_len)) + continue; + + /* unescape */ + xbuf[xoff] = '\0'; /* 0-terminate in preparation */ + xoff = MHD_http_unescape (xbuf); + /* finally: call application! */ + if (MHD_NO == pp->ikvi (pp->cls, MHD_POSTDATA_KIND, (const char *) &pp[1], /* key */ + NULL, NULL, NULL, xbuf, pp->value_offset, + xoff)) + { + pp->state = PP_Error; + return MHD_NO; + } + pp->value_offset += xoff; + + /* are we done with the value? */ + if (end_of_value_found) + { + /* we found the end of the value! */ + if ((post_data[poff] == '\n') || (post_data[poff] == '\r')) + { + pp->state = PP_ExpectNewLine; + } + else + { + poff++; /* skip '&' */ + pp->state = PP_Init; + } + } + break; + case PP_ExpectNewLine: + if ((post_data[poff] == '\n') || (post_data[poff] == '\r')) + { + poff++; + /* we are done, report error if we receive any more... */ + pp->state = PP_Done; + return MHD_YES; + } + return MHD_NO; + default: + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); /* should never happen! */ + } + } + return MHD_YES; +} + +/** + * If the given line matches the prefix, strdup the + * rest of the line into the suffix ptr. + * + * @return MHD_YES if there was a match, MHD_NO if not + */ +static int +try_match_header (const char *prefix, char *line, char **suffix) +{ + if (NULL != *suffix) + return MHD_NO; + while (*line != 0) + { + if (0 == strncasecmp (prefix, line, strlen (prefix))) + { + *suffix = strdup (&line[strlen (prefix)]); + return MHD_YES; + } + ++line; + } + return MHD_NO; +} + +static int +find_boundary (struct MHD_PostProcessor *pp, + const char *boundary, + size_t blen, + size_t *ioffptr, + enum PP_State next_state, enum PP_State next_dash_state) +{ + char *buf = (char *) &pp[1]; + + if (pp->buffer_pos < 2 + blen) + { + if (pp->buffer_pos == pp->buffer_size) + pp->state = PP_Error; /* out of memory */ + return MHD_NO; /* not enough data */ + } + if ((0 != memcmp ("--", buf, 2)) || (0 != memcmp (&buf[2], boundary, blen))) + { + pp->state = PP_Error; + return MHD_NO; /* expected boundary */ + } + /* remove boundary from buffer */ + (*ioffptr) += 2 + blen; + /* next: start with headers */ + pp->skip_rn = RN_Dash; + pp->state = next_state; + pp->dash_state = next_dash_state; + return MHD_YES; +} + +/** + * In buf, there maybe an expression + * '$key="$value"'. If that is the case, + * copy a copy of $value to destination. + * + * If destination is already non-NULL, + * do nothing. + */ +static void +try_get_value (const char *buf, const char *key, char **destination) +{ + const char *spos; + const char *bpos; + const char *endv; + size_t klen; + size_t vlen; + + if (NULL != *destination) + return; + bpos = buf; + klen = strlen (key); + while (NULL != (spos = strstr (bpos, key))) + { + if ((spos[klen] != '=') || ((spos != buf) && (spos[-1] != ' '))) + { + /* no match */ + bpos = spos + 1; + continue; + } + if (spos[klen + 1] != '"') + return; /* not quoted */ + if (NULL == (endv = strstr (&spos[klen + 2], "\""))) + return; /* no end-quote */ + vlen = endv - spos - klen - 1; + *destination = malloc (vlen); + if (NULL == *destination) + return; /* out of memory */ + (*destination)[vlen - 1] = '\0'; + memcpy (*destination, &spos[klen + 2], vlen - 1); + return; /* success */ + } +} + +/** + * Go over the headers of the part and update + * the fields in "pp" according to what we find. + * If we are at the end of the headers (as indicated + * by an empty line), transition into next_state. + * + * @param ioffptr set to how many bytes have been + * processed + * @return MHD_YES if we can continue processing, + * MHD_NO on error or if we do not have + * enough data yet + */ +static int +process_multipart_headers (struct MHD_PostProcessor *pp, + size_t *ioffptr, enum PP_State next_state) +{ + char *buf = (char *) &pp[1]; + size_t newline; + + newline = 0; + while ((newline < pp->buffer_pos) && + (buf[newline] != '\r') && (buf[newline] != '\n')) + newline++; + if (newline == pp->buffer_size) + { + pp->state = PP_Error; + return MHD_NO; /* out of memory */ + } + if (newline == pp->buffer_pos) + return MHD_NO; /* will need more data */ + if (newline == 0) + { + /* empty line - end of headers */ + pp->skip_rn = RN_Full; + pp->state = next_state; + return MHD_YES; + } + /* got an actual header */ + if (buf[newline] == '\r') + pp->skip_rn = RN_OptN; + buf[newline] = '\0'; + if (0 == strncasecmp ("Content-disposition: ", + buf, strlen ("Content-disposition: "))) + { + try_get_value (&buf[strlen ("Content-disposition: ")], + "name", &pp->content_name); + try_get_value (&buf[strlen ("Content-disposition: ")], + "filename", &pp->content_filename); + } + else + { + try_match_header ("Content-type: ", buf, &pp->content_type); + try_match_header ("Content-Transfer-Encoding: ", + buf, &pp->content_transfer_encoding); + } + (*ioffptr) += newline + 1; + return MHD_YES; +} + +/** + * We have the value until we hit the given boundary; + * process accordingly. + * + * @param boundary the boundary to look for + * @param blen strlen(boundary) + * @param next_state what state to go into after the + * boundary was found + * @param next_dash_state state to go into if the next + * boundary ends with "--" + * @return MHD_YES if we can continue processing, + * MHD_NO on error or if we do not have + * enough data yet + */ +static int +process_value_to_boundary (struct MHD_PostProcessor *pp, + size_t *ioffptr, + const char *boundary, + size_t blen, + enum PP_State next_state, + enum PP_State next_dash_state) +{ + char *buf = (char *) &pp[1]; + size_t newline; + + /* all data in buf until the boundary + (\r\n--+boundary) is part of the value */ + newline = 0; + while (1) + { + while ((newline + 4 < pp->buffer_pos) && + (0 != memcmp ("\r\n--", &buf[newline], 4))) + newline++; + if (newline + pp->blen + 4 <= pp->buffer_pos) + { + /* can check boundary */ + if (0 != memcmp (&buf[newline + 4], boundary, pp->blen)) + { + /* no boundary, "\r\n--" is part of content, skip */ + newline += 4; + continue; + } + else + { + /* boundary found, process until newline then + skip boundary and go back to init */ + pp->skip_rn = RN_Dash; + pp->state = next_state; + pp->dash_state = next_dash_state; + (*ioffptr) += pp->blen + 4; /* skip boundary as well */ + break; + } + } + else + { + /* cannot check for boundary, process content that + we have and check again later; except, if we have + no content, abort (out of memory) */ + if ((newline == 0) && (pp->buffer_pos == pp->buffer_size)) + { + pp->state = PP_Error; + return MHD_NO; + } + break; + } + } + /* newline is either at beginning of boundary or + at least at the last character that we are sure + is not part of the boundary */ + if (MHD_NO == pp->ikvi (pp->cls, + MHD_POSTDATA_KIND, + pp->content_name, + pp->content_filename, + pp->content_type, + pp->content_transfer_encoding, + buf, pp->value_offset, newline)) + { + pp->state = PP_Error; + return MHD_NO; + } + pp->value_offset += newline; + (*ioffptr) += newline; + return MHD_YES; +} + +static void +free_unmarked (struct MHD_PostProcessor *pp) +{ + if ((pp->content_name != NULL) && (0 == (pp->have & NE_content_name))) + { + free (pp->content_name); + pp->content_name = NULL; + } + if ((pp->content_type != NULL) && (0 == (pp->have & NE_content_type))) + { + free (pp->content_type); + pp->content_type = NULL; + } + if ((pp->content_filename != NULL) && + (0 == (pp->have & NE_content_filename))) + { + free (pp->content_filename); + pp->content_filename = NULL; + } + if ((pp->content_transfer_encoding != NULL) && + (0 == (pp->have & NE_content_transfer_encoding))) + { + free (pp->content_transfer_encoding); + pp->content_transfer_encoding = NULL; + } +} + +/** + * Decode multipart POST data. + */ +static int +post_process_multipart (struct MHD_PostProcessor *pp, + const char *post_data, + size_t post_data_len) +{ + char *buf; + size_t max; + size_t ioff; + size_t poff; + int state_changed; + + buf = (char *) &pp[1]; + ioff = 0; + poff = 0; + state_changed = 1; + while ((poff < post_data_len) || + ((pp->buffer_pos > 0) && (state_changed != 0))) + { + /* first, move as much input data + as possible to our internal buffer */ + max = pp->buffer_size - pp->buffer_pos; + if (max > post_data_len - poff) + max = post_data_len - poff; + memcpy (&buf[pp->buffer_pos], &post_data[poff], max); + poff += max; + pp->buffer_pos += max; + if ((max == 0) && (state_changed == 0) && (poff < post_data_len)) + { + pp->state = PP_Error; + return MHD_NO; /* out of memory */ + } + state_changed = 0; + + /* first state machine for '\r'-'\n' and '--' handling */ + switch (pp->skip_rn) + { + case RN_Inactive: + break; + case RN_OptN: + if (buf[0] == '\n') + { + ioff++; + pp->skip_rn = RN_Inactive; + goto AGAIN; + } + case RN_Dash: + if (buf[0] == '-') + { + ioff++; + pp->skip_rn = RN_Dash2; + goto AGAIN; + } + pp->skip_rn = RN_Full; + /* fall-through! */ + case RN_Full: + if (buf[0] == '\r') + { + if ((pp->buffer_pos > 1) && (buf[1] == '\n')) + { + pp->skip_rn = RN_Inactive; + ioff += 2; + } + else + { + pp->skip_rn = RN_OptN; + ioff++; + } + goto AGAIN; + } + if (buf[0] == '\n') + { + ioff++; + pp->skip_rn = RN_Inactive; + goto AGAIN; + } + pp->skip_rn = RN_Inactive; + pp->state = PP_Error; + return MHD_NO; /* no '\r\n' */ + case RN_Dash2: + if (buf[0] == '-') + { + ioff++; + pp->skip_rn = RN_Full; + pp->state = pp->dash_state; + goto AGAIN; + } + pp->state = PP_Error; + break; + } + + /* main state engine */ + switch (pp->state) + { + case PP_Error: + return MHD_NO; + case PP_Done: + /* did not expect to receive more data */ + pp->state = PP_Error; + return MHD_NO; + case PP_Init: + if (MHD_NO == find_boundary (pp, + pp->boundary, + pp->blen, + &ioff, + PP_ProcessEntryHeaders, PP_Done)) + { + if (pp->state == PP_Error) + return MHD_NO; + goto END; + } + break; + case PP_ProcessEntryHeaders: + if (MHD_NO == + process_multipart_headers (pp, &ioff, PP_PerformCheckMultipart)) + { + if (pp->state == PP_Error) + return MHD_NO; + else + goto END; + } + state_changed = 1; + break; + case PP_PerformCheckMultipart: + if ((pp->content_type != NULL) && + (0 == strncasecmp (pp->content_type, + "multipart/mixed", + strlen ("multipart/mixed")))) + { + pp->nested_boundary = strstr (pp->content_type, "boundary="); + if (pp->nested_boundary == NULL) + { + pp->state = PP_Error; + return MHD_NO; + } + pp->nested_boundary = + strdup (&pp->nested_boundary[strlen ("boundary=")]); + if (pp->nested_boundary == NULL) + { + /* out of memory */ + pp->state = PP_Error; + return MHD_NO; + } + /* free old content type, we will need that field + for the content type of the nested elements */ + free (pp->content_type); + pp->content_type = NULL; + pp->nlen = strlen (pp->nested_boundary); + pp->state = PP_Nested_Init; + state_changed = 1; + break; + } + pp->state = PP_ProcessValueToBoundary; + pp->value_offset = 0; + state_changed = 1; + break; + case PP_ProcessValueToBoundary: + if (MHD_NO == process_value_to_boundary (pp, + &ioff, + pp->boundary, + pp->blen, + PP_PerformCleanup, + PP_Done)) + { + if (pp->state == PP_Error) + return MHD_NO; + break; + } + break; + case PP_PerformCleanup: + /* clean up state of one multipart form-data element! */ + pp->have = NE_none; + free_unmarked (pp); + if (pp->nested_boundary != NULL) + { + free (pp->nested_boundary); + pp->nested_boundary = NULL; + } + pp->state = PP_ProcessEntryHeaders; + state_changed = 1; + break; + case PP_Nested_Init: + if (pp->nested_boundary == NULL) + { + pp->state = PP_Error; + return MHD_NO; + } + if (MHD_NO == find_boundary (pp, + pp->nested_boundary, + pp->nlen, + &ioff, + PP_Nested_PerformMarking, + PP_Init /* or PP_Error? */ )) + { + if (pp->state == PP_Error) + return MHD_NO; + goto END; + } + break; + case PP_Nested_PerformMarking: + /* remember what headers were given + globally */ + pp->have = NE_none; + if (pp->content_name != NULL) + pp->have |= NE_content_name; + if (pp->content_type != NULL) + pp->have |= NE_content_type; + if (pp->content_filename != NULL) + pp->have |= NE_content_filename; + if (pp->content_transfer_encoding != NULL) + pp->have |= NE_content_transfer_encoding; + pp->state = PP_Nested_ProcessEntryHeaders; + state_changed = 1; + break; + case PP_Nested_ProcessEntryHeaders: + pp->value_offset = 0; + if (MHD_NO == + process_multipart_headers (pp, &ioff, + PP_Nested_ProcessValueToBoundary)) + { + if (pp->state == PP_Error) + return MHD_NO; + else + goto END; + } + state_changed = 1; + break; + case PP_Nested_ProcessValueToBoundary: + if (MHD_NO == process_value_to_boundary (pp, + &ioff, + pp->nested_boundary, + pp->nlen, + PP_Nested_PerformCleanup, + PP_Init)) + { + if (pp->state == PP_Error) + return MHD_NO; + break; + } + break; + case PP_Nested_PerformCleanup: + free_unmarked (pp); + pp->state = PP_Nested_ProcessEntryHeaders; + state_changed = 1; + break; + default: + mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); /* should never happen! */ + } + AGAIN: + if (ioff > 0) + { + memmove (buf, &buf[ioff], pp->buffer_pos - ioff); + pp->buffer_pos -= ioff; + ioff = 0; + state_changed = 1; + } + } +END: + if (ioff != 0) + { + memmove (buf, &buf[ioff], pp->buffer_pos - ioff); + pp->buffer_pos -= ioff; + } + if (poff < post_data_len) + { + pp->state = PP_Error; + return MHD_NO; /* serious error */ + } + return MHD_YES; +} + +/** + * Parse and process POST data. + * Call this function when POST data is available + * (usually during an MHD_AccessHandlerCallback) + * with the upload_data and upload_data_size. + * Whenever possible, this will then cause calls + * to the MHD_IncrementalKeyValueIterator. + * + * @param pp the post processor + * @param post_data post_data_len bytes of POST data + * @param post_data_len length of post_data + * @return MHD_YES on success, MHD_NO on error + * (out-of-memory, iterator aborted, parse error) + */ +int +MHD_post_process (struct MHD_PostProcessor *pp, + const char *post_data, size_t post_data_len) +{ + if (post_data_len == 0) + return MHD_YES; + if (pp == NULL) + return MHD_NO; + if (0 == strncasecmp (MHD_HTTP_POST_ENCODING_FORM_URLENCODED, pp->encoding, + strlen(MHD_HTTP_POST_ENCODING_FORM_URLENCODED))) + return post_process_urlencoded (pp, post_data, post_data_len); + if (0 == + strncasecmp (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA, pp->encoding, + strlen (MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))) + return post_process_multipart (pp, post_data, post_data_len); + /* this should never be reached */ + return MHD_NO; +} + +/** + * Release PostProcessor resources. + */ +int +MHD_destroy_post_processor (struct MHD_PostProcessor *pp) +{ + int ret; + + /* These internal strings need cleaning up since + the post-processing may have been interrupted + at any stage */ + if ((pp->xbuf_pos > 0) || (pp->state != PP_Done)) + ret = MHD_NO; + else + ret = MHD_YES; + pp->have = NE_none; + free_unmarked (pp); + if (pp->nested_boundary != NULL) + free (pp->nested_boundary); + free (pp); + return ret; +} + +/* end of postprocessor.c */ diff --git a/lib/libmicrohttpd/src/daemon/postprocessor_large_test.c b/lib/libmicrohttpd/src/daemon/postprocessor_large_test.c new file mode 100644 index 0000000000..6c1ea14566 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/postprocessor_large_test.c @@ -0,0 +1,105 @@ +/* + This file is part of libmicrohttpd + (C) 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file postprocessor_large_test.c + * @brief Testcase with very large input for postprocessor + * @author Christian Grothoff + */ + +#include "platform.h" +#include "microhttpd.h" +#include "internal.h" + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int +value_checker (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *data, uint64_t off, size_t size) +{ + unsigned int *pos = cls; +#if 0 + fprintf (stderr, + "VC: %llu %u `%s' `%s' `%s' `%s' `%.*s'\n", + off, size, + key, filename, content_type, transfer_encoding, size, data); +#endif + if (size == 0) + return MHD_YES; + *pos += size; + return MHD_YES; + +} + + +static int +test_simple_large () +{ + struct MHD_Connection connection; + struct MHD_HTTP_Header header; + struct MHD_PostProcessor *pp; + int i; + int delta; + size_t size; + char data[102400]; + unsigned int pos; + + pos = 0; + memset (data, 'A', sizeof (data)); + memcpy (data, "key=", 4); + data[sizeof (data) - 1] = '\0'; + memset (&connection, 0, sizeof (struct MHD_Connection)); + memset (&header, 0, sizeof (struct MHD_HTTP_Header)); + connection.headers_received = &header; + header.header = MHD_HTTP_HEADER_CONTENT_TYPE; + header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; + header.kind = MHD_HEADER_KIND; + pp = MHD_create_post_processor (&connection, 1024, &value_checker, &pos); + i = 0; + size = strlen (data); + while (i < size) + { + delta = 1 + RANDOM () % (size - i); + MHD_post_process (pp, &data[i], delta); + i += delta; + } + MHD_destroy_post_processor (pp); + if (pos != sizeof (data) - 5) /* minus 0-termination and 'key=' */ + return 1; + return 0; +} + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + errorCount += test_simple_large (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/daemon/postprocessor_test.c b/lib/libmicrohttpd/src/daemon/postprocessor_test.c new file mode 100644 index 0000000000..f476dae6b8 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/postprocessor_test.c @@ -0,0 +1,226 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file postprocessor_test.c + * @brief Testcase for postprocessor + * @author Christian Grothoff + */ + +#include "platform.h" +#include "microhttpd.h" +#include "internal.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +/** + * Array of values that the value checker "wants". + * Each series of checks should be terminated by + * five NULL-entries. + */ +const char *want[] = { +#define URL_DATA "abc=def&x=5" +#define URL_START 0 + "abc", NULL, NULL, NULL, "def", + "x", NULL, NULL, NULL, "5", +#define URL_END (URL_START + 10) + NULL, NULL, NULL, NULL, NULL, +#define FORM_DATA "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\nJoe Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: binary\r\n\r\nfiledata\r\n--AaB03x--\r\n" +#define FORM_START (URL_END + 5) + "field1", NULL, NULL, NULL, "Joe Blow", + "pics", "file1.txt", "text/plain", "binary", "filedata", +#define FORM_END (FORM_START + 10) + NULL, NULL, NULL, NULL, NULL, +#define FORM_NESTED_DATA "--AaB03x\r\ncontent-disposition: form-data; name=\"field1\"\r\n\r\nJane Blow\r\n--AaB03x\r\ncontent-disposition: form-data; name=\"pics\"\r\nContent-type: multipart/mixed, boundary=BbC04y\r\n\r\n--BbC04y\r\nContent-disposition: attachment; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\n\r\nfiledata1\r\n--BbC04y\r\nContent-disposition: attachment; filename=\"file2.gif\"\r\nContent-type: image/gif\r\nContent-Transfer-Encoding: binary\r\n\r\nfiledata2\r\n--BbC04y--\r\n--AaB03x--" +#define FORM_NESTED_START (FORM_END + 5) + "field1", NULL, NULL, NULL, "Jane Blow", + "pics", "file1.txt", "text/plain", NULL, "filedata1", + "pics", "file2.gif", "image/gif", "binary", "filedata2", +#define FORM_NESTED_END (FORM_NESTED_START + 15) + NULL, NULL, NULL, NULL, NULL, +}; + +static int +mismatch (const char *a, const char *b) +{ + if (a == b) + return 0; + if ((a == NULL) || (b == NULL)) + return 1; + return 0 != strcmp (a, b); +} + +static int +value_checker (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *data, uint64_t off, size_t size) +{ + int *want_off = cls; + int idx = *want_off; + +#if 0 + fprintf (stderr, + "VC: `%s' `%s' `%s' `%s' `%.*s'\n", + key, filename, content_type, transfer_encoding, size, data); +#endif + if (size == 0) + return MHD_YES; + if ((idx < 0) || + (want[idx] == NULL) || + (0 != strcmp (key, want[idx])) || + (mismatch (filename, want[idx + 1])) || + (mismatch (content_type, want[idx + 2])) || + (mismatch (transfer_encoding, want[idx + 3])) || + (0 != memcmp (data, &want[idx + 4][off], size))) + { + *want_off = -1; + return MHD_NO; + } + if (off + size == strlen (want[idx + 4])) + *want_off = idx + 5; + return MHD_YES; + +} + + +static int +test_urlencoding () +{ + struct MHD_Connection connection; + struct MHD_HTTP_Header header; + struct MHD_PostProcessor *pp; + unsigned int want_off = URL_START; + int i; + int delta; + size_t size; + + memset (&connection, 0, sizeof (struct MHD_Connection)); + memset (&header, 0, sizeof (struct MHD_HTTP_Header)); + connection.headers_received = &header; + header.header = MHD_HTTP_HEADER_CONTENT_TYPE; + header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED; + header.kind = MHD_HEADER_KIND; + pp = MHD_create_post_processor (&connection, + 1024, &value_checker, &want_off); + i = 0; + size = strlen (URL_DATA); + while (i < size) + { + delta = 1 + RANDOM () % (size - i); + MHD_post_process (pp, &URL_DATA[i], delta); + i += delta; + } + MHD_destroy_post_processor (pp); + if (want_off != URL_END) + return 1; + return 0; +} + + +static int +test_multipart () +{ + struct MHD_Connection connection; + struct MHD_HTTP_Header header; + struct MHD_PostProcessor *pp; + unsigned int want_off = FORM_START; + int i; + int delta; + size_t size; + + memset (&connection, 0, sizeof (struct MHD_Connection)); + memset (&header, 0, sizeof (struct MHD_HTTP_Header)); + connection.headers_received = &header; + header.header = MHD_HTTP_HEADER_CONTENT_TYPE; + header.value = + MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; + header.kind = MHD_HEADER_KIND; + pp = MHD_create_post_processor (&connection, + 1024, &value_checker, &want_off); + i = 0; + size = strlen (FORM_DATA); + while (i < size) + { + delta = 1 + RANDOM () % (size - i); + MHD_post_process (pp, &FORM_DATA[i], delta); + i += delta; + } + MHD_destroy_post_processor (pp); + if (want_off != FORM_END) + return 2; + return 0; +} + + +static int +test_nested_multipart () +{ + struct MHD_Connection connection; + struct MHD_HTTP_Header header; + struct MHD_PostProcessor *pp; + unsigned int want_off = FORM_NESTED_START; + int i; + int delta; + size_t size; + + memset (&connection, 0, sizeof (struct MHD_Connection)); + memset (&header, 0, sizeof (struct MHD_HTTP_Header)); + connection.headers_received = &header; + header.header = MHD_HTTP_HEADER_CONTENT_TYPE; + header.value = + MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x"; + header.kind = MHD_HEADER_KIND; + pp = MHD_create_post_processor (&connection, + 1024, &value_checker, &want_off); + i = 0; + size = strlen (FORM_NESTED_DATA); + while (i < size) + { + delta = 1 + RANDOM () % (size - i); + MHD_post_process (pp, &FORM_NESTED_DATA[i], delta); + i += delta; + } + MHD_destroy_post_processor (pp); + if (want_off != FORM_NESTED_END) + return 4; + return 0; +} + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + errorCount += test_urlencoding (); + errorCount += test_multipart (); + errorCount += test_nested_multipart (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/daemon/reason_phrase.c b/lib/libmicrohttpd/src/daemon/reason_phrase.c new file mode 100644 index 0000000000..c02a0965da --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/reason_phrase.c @@ -0,0 +1,128 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Lymba + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +/** + * @file reason_phrase.c + * @brief Tables of the string response phrases + * @author Elliot Glaysher + * @author Christian Grothoff (minor code clean up) + */ + +#include "reason_phrase.h" + +#ifndef NULL +#define NULL (void*)0 +#endif // !NULL + +static const char *invalid_hundred[] = { NULL }; + +static const char *one_hundred[] = { + "Continue", + "Switching Protocols", + "Processing" +}; + +static const char *two_hundred[] = { + "OK", + "Created", + "Accepted", + "Non-Authoritative Information", + "No Content", + "Reset Content", + "Partial Content", + "Multi Status" +}; + +static const char *three_hundred[] = { + "Multiple Choices", + "Moved Permanently", + "Moved Temporarily", + "See Other", + "Not Modified", + "Use Proxy", + "Switch Proxy", + "Temporary Redirect" +}; + +static const char *four_hundred[] = { + "Bad Request", + "Unauthorized", + "Payment Required", + "Forbidden", + "Not Found", + "Method Not Allowed", + "Not Acceptable", + "Proxy Authentication Required", + "Request Time-out", + "Conflict", + "Gone", + "Length Required", + "Precondition Failed", + "Request Entity Too Large", + "Request-URI Too Large", + "Unsupported Media Type", + "Requested Range Not Satisfiable", + "Expectation Failed", + "Unprocessable Entity", + "Locked", + "Failed Dependency", + "Unordered Collection", + "Upgrade Required", + "Retry With" +}; + +static const char *five_hundred[] = { + "Internal Server Error", + "Not Implemented", + "Bad Gateway", + "Service Unavailable", + "Gateway Time-out", + "HTTP Version not supported", + "Variant Also Negotiates", + "Insufficient Storage", + "Bandwidth Limit Exceeded", + "Not Extended" +}; + + +struct MHD_Reason_Block +{ + unsigned int max; + const char **data; +}; + +#define BLOCK(m) { (sizeof(m) / sizeof(char*)), m } + +static const struct MHD_Reason_Block reasons[] = { + BLOCK (invalid_hundred), + BLOCK (one_hundred), + BLOCK (two_hundred), + BLOCK (three_hundred), + BLOCK (four_hundred), + BLOCK (five_hundred), +}; + +const char * +MHD_get_reason_phrase_for (unsigned int code) +{ + if ((code >= 100 && code < 600) && (reasons[code / 100].max > code % 100)) + return reasons[code / 100].data[code % 100]; + return "Unknown"; +} diff --git a/lib/libmicrohttpd/src/daemon/reason_phrase.h b/lib/libmicrohttpd/src/daemon/reason_phrase.h new file mode 100644 index 0000000000..20c11d52c7 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/reason_phrase.h @@ -0,0 +1,37 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Lymba + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file reason_phrase.c + * @brief Tables of the string response phrases + * @author Elliot Glaysher + */ + +#ifndef REASON_PHRASE_H +#define REASON_PHRASE_H + +/** + * Returns the string reason phrase for a response code. + * + * If we don't have a string for a status code, we give the first + * message in that status code class. + */ +const char *MHD_get_reason_phrase_for (unsigned int code); + +#endif diff --git a/lib/libmicrohttpd/src/daemon/response.c b/lib/libmicrohttpd/src/daemon/response.c new file mode 100644 index 0000000000..a10dbc4fd0 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/response.c @@ -0,0 +1,303 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2009 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file response.c + * @brief Methods for managing response objects + * @author Daniel Pittman + * @author Christian Grothoff + */ + +#include "internal.h" +#include "response.h" + +/** + * Add a header line to the response. + * + * @return MHD_NO on error (i.e. invalid header or content format). + */ +int +MHD_add_response_header (struct MHD_Response *response, + const char *header, const char *content) +{ + struct MHD_HTTP_Header *hdr; + + if ((response == NULL) || + (header == NULL) || + (content == NULL) || + (strlen (header) == 0) || + (strlen (content) == 0) || + (NULL != strstr (header, "\t")) || + (NULL != strstr (header, "\r")) || + (NULL != strstr (header, "\n")) || + (NULL != strstr (content, "\t")) || + (NULL != strstr (content, "\r")) || (NULL != strstr (content, "\n"))) + return MHD_NO; + hdr = malloc (sizeof (struct MHD_HTTP_Header)); + if (hdr == NULL) + return MHD_NO; + hdr->header = strdup (header); + if (hdr->header == NULL) + { + free (hdr); + return MHD_NO; + } + hdr->value = strdup (content); + if (hdr->value == NULL) + { + free (hdr->header); + free (hdr); + return MHD_NO; + } + hdr->kind = MHD_HEADER_KIND; + hdr->next = response->first_header; + response->first_header = hdr; + return MHD_YES; +} + +/** + * Delete a header line from the response. + * + * @return MHD_NO on error (no such header known) + */ +int +MHD_del_response_header (struct MHD_Response *response, + const char *header, const char *content) +{ + struct MHD_HTTP_Header *pos; + struct MHD_HTTP_Header *prev; + + if ((header == NULL) || (content == NULL)) + return MHD_NO; + prev = NULL; + pos = response->first_header; + while (pos != NULL) + { + if ((0 == strcmp (header, pos->header)) && + (0 == strcmp (content, pos->value))) + { + free (pos->header); + free (pos->value); + if (prev == NULL) + response->first_header = pos->next; + else + prev->next = pos->next; + free (pos); + return MHD_YES; + } + prev = pos; + pos = pos->next; + } + return MHD_NO; +} + +/** + * Get all of the headers added to a response. + * + * @param iterator callback to call on each header; + * maybe NULL (then just count headers) + * @param iterator_cls extra argument to iterator + * @return number of entries iterated over + */ +int +MHD_get_response_headers (struct MHD_Response *response, + MHD_KeyValueIterator iterator, void *iterator_cls) +{ + struct MHD_HTTP_Header *pos; + int numHeaders = 0; + pos = response->first_header; + while (pos != NULL) + { + numHeaders++; + if ((iterator != NULL) && + (MHD_YES != iterator (iterator_cls, + pos->kind, pos->header, pos->value))) + break; + pos = pos->next; + } + return numHeaders; +} + + +/** + * Get a particular header from the response. + * + * @param key which header to get + * @return NULL if header does not exist + */ +const char * +MHD_get_response_header (struct MHD_Response *response, const char *key) +{ + struct MHD_HTTP_Header *pos; + + if (key == NULL) + return NULL; + pos = response->first_header; + while (pos != NULL) + { + if (0 == strcmp (key, pos->header)) + return pos->value; + pos = pos->next; + } + return NULL; +} + + +/** + * Create a response object. The response object can be extended with + * header information and then be used any number of times. + * + * @param size size of the data portion of the response, -1 for unknown + * @param block_size preferred block size for querying crc (advisory only, + * MHD may still call crc using smaller chunks); this + * is essentially the buffer size used for IO, clients + * should pick a value that is appropriate for IO and + * memory performance requirements + * @param crc callback to use to obtain response data + * @param crc_cls extra argument to crc + * @param crfc callback to call to free crc_cls resources + * @return NULL on error (i.e. invalid arguments, out of memory) + */ +struct MHD_Response * +MHD_create_response_from_callback (uint64_t size, + size_t block_size, + MHD_ContentReaderCallback crc, + void *crc_cls, + MHD_ContentReaderFreeCallback crfc) +{ + struct MHD_Response *retVal; + + if ((crc == NULL) || (block_size == 0)) + return NULL; + retVal = malloc (sizeof (struct MHD_Response) + block_size); + if (retVal == NULL) + return NULL; + memset (retVal, 0, sizeof (struct MHD_Response)); + retVal->data = (void *) &retVal[1]; + retVal->data_buffer_size = block_size; + if (pthread_mutex_init (&retVal->mutex, NULL) != 0) + { + free (retVal); + return NULL; + } + retVal->crc = crc; + retVal->crfc = crfc; + retVal->crc_cls = crc_cls; + retVal->reference_count = 1; + retVal->total_size = size; + return retVal; +} + +/** + * Create a response object. The response object can be extended with + * header information and then be used any number of times. + * + * @param size size of the data portion of the response + * @param data the data itself + * @param must_free libmicrohttpd should free data when done + * @param must_copy libmicrohttpd must make a copy of data + * right away, the data maybe released anytime after + * this call returns + * @return NULL on error (i.e. invalid arguments, out of memory) + */ +struct MHD_Response * +MHD_create_response_from_data (size_t size, + void *data, int must_free, int must_copy) +{ + struct MHD_Response *retVal; + void *tmp; + + if ((data == NULL) && (size > 0)) + return NULL; + retVal = malloc (sizeof (struct MHD_Response)); + if (retVal == NULL) + return NULL; + memset (retVal, 0, sizeof (struct MHD_Response)); + if (pthread_mutex_init (&retVal->mutex, NULL) != 0) + { + free (retVal); + return NULL; + } + if ((must_copy) && (size > 0)) + { + tmp = malloc (size); + if (tmp == NULL) + { + free (retVal); + return NULL; + } + memcpy (tmp, data, size); + must_free = 1; + data = tmp; + } + retVal->crc = NULL; + retVal->crfc = must_free ? &free : NULL; + retVal->crc_cls = must_free ? data : NULL; + retVal->reference_count = 1; + retVal->total_size = size; + retVal->data = data; + retVal->data_size = size; + return retVal; +} + +/** + * Destroy a response object and associated resources. Note that + * libmicrohttpd may keep some of the resources around if the response + * is still in the queue for some clients, so the memory may not + * necessarily be freed immediatley. + */ +void +MHD_destroy_response (struct MHD_Response *response) +{ + struct MHD_HTTP_Header *pos; + + if (response == NULL) + return; + pthread_mutex_lock (&response->mutex); + if (0 != --response->reference_count) + { + pthread_mutex_unlock (&response->mutex); + return; + } + pthread_mutex_unlock (&response->mutex); + pthread_mutex_destroy (&response->mutex); + if (response->crfc != NULL) + response->crfc (response->crc_cls); + while (response->first_header != NULL) + { + pos = response->first_header; + response->first_header = pos->next; + free (pos->header); + free (pos->value); + free (pos); + } + free (response); +} + + +void +MHD_increment_response_rc (struct MHD_Response *response) +{ + pthread_mutex_lock (&response->mutex); + response->reference_count++; + pthread_mutex_unlock (&response->mutex); +} + + +/* end of response.c */ diff --git a/lib/libmicrohttpd/src/daemon/response.h b/lib/libmicrohttpd/src/daemon/response.h new file mode 100644 index 0000000000..ec1b387805 --- /dev/null +++ b/lib/libmicrohttpd/src/daemon/response.h @@ -0,0 +1,37 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Daniel Pittman and Christian Grothoff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file response.h + * @brief Methods for managing response objects + * @author Daniel Pittman + * @author Christian Grothoff + */ + +#ifndef RESPONSE_H +#define RESPONSE_H + +/** + * Increment response RC. Should this be part of the + * public API? + */ +void MHD_increment_response_rc (struct MHD_Response *response); + + +#endif diff --git a/lib/libmicrohttpd/src/examples/Makefile.am b/lib/libmicrohttpd/src/examples/Makefile.am new file mode 100644 index 0000000000..9ed9aaafe8 --- /dev/null +++ b/lib/libmicrohttpd/src/examples/Makefile.am @@ -0,0 +1,70 @@ +SUBDIRS = . + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https \ + @LIBGCRYPT_CFLAGS@ + +if USE_COVERAGE + AM_CFLAGS = --coverage +endif + +# example programs +noinst_PROGRAMS = \ +authorization_example \ +minimal_example \ +minimal_example_comet \ +querystring_example \ +fileserver_example \ +fileserver_example_dirs \ +fileserver_example_external_select \ +refuse_post_example + +if ENABLE_HTTPS +noinst_PROGRAMS += https_fileserver_example +endif + +minimal_example_SOURCES = \ + minimal_example.c +minimal_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +minimal_example_comet_SOURCES = \ + minimal_example_comet.c +minimal_example_comet_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +authorization_example_SOURCES = \ + authorization_example.c +authorization_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +refuse_post_example_SOURCES = \ + refuse_post_example.c +refuse_post_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +querystring_example_SOURCES = \ + querystring_example.c +querystring_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +fileserver_example_SOURCES = \ + fileserver_example.c +fileserver_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +fileserver_example_dirs_SOURCES = \ + fileserver_example_dirs.c +fileserver_example_dirs_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +fileserver_example_external_select_SOURCES = \ + fileserver_example_external_select.c +fileserver_example_external_select_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +https_fileserver_example_SOURCES = \ +https_fileserver_example.c +https_fileserver_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la diff --git a/lib/libmicrohttpd/src/examples/Makefile.in b/lib/libmicrohttpd/src/examples/Makefile.in new file mode 100644 index 0000000000..26cc59aa99 --- /dev/null +++ b/lib/libmicrohttpd/src/examples/Makefile.in @@ -0,0 +1,791 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = authorization_example$(EXEEXT) \ + minimal_example$(EXEEXT) minimal_example_comet$(EXEEXT) \ + querystring_example$(EXEEXT) fileserver_example$(EXEEXT) \ + fileserver_example_dirs$(EXEEXT) \ + fileserver_example_external_select$(EXEEXT) \ + refuse_post_example$(EXEEXT) $(am__EXEEXT_1) +@ENABLE_HTTPS_TRUE@am__append_1 = https_fileserver_example +subdir = src/examples +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@ENABLE_HTTPS_TRUE@am__EXEEXT_1 = https_fileserver_example$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am_authorization_example_OBJECTS = authorization_example.$(OBJEXT) +authorization_example_OBJECTS = $(am_authorization_example_OBJECTS) +authorization_example_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_fileserver_example_OBJECTS = fileserver_example.$(OBJEXT) +fileserver_example_OBJECTS = $(am_fileserver_example_OBJECTS) +fileserver_example_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_fileserver_example_dirs_OBJECTS = \ + fileserver_example_dirs.$(OBJEXT) +fileserver_example_dirs_OBJECTS = \ + $(am_fileserver_example_dirs_OBJECTS) +fileserver_example_dirs_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_fileserver_example_external_select_OBJECTS = \ + fileserver_example_external_select.$(OBJEXT) +fileserver_example_external_select_OBJECTS = \ + $(am_fileserver_example_external_select_OBJECTS) +fileserver_example_external_select_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_https_fileserver_example_OBJECTS = \ + https_fileserver_example.$(OBJEXT) +https_fileserver_example_OBJECTS = \ + $(am_https_fileserver_example_OBJECTS) +https_fileserver_example_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_minimal_example_OBJECTS = minimal_example.$(OBJEXT) +minimal_example_OBJECTS = $(am_minimal_example_OBJECTS) +minimal_example_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_minimal_example_comet_OBJECTS = minimal_example_comet.$(OBJEXT) +minimal_example_comet_OBJECTS = $(am_minimal_example_comet_OBJECTS) +minimal_example_comet_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_querystring_example_OBJECTS = querystring_example.$(OBJEXT) +querystring_example_OBJECTS = $(am_querystring_example_OBJECTS) +querystring_example_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_refuse_post_example_OBJECTS = refuse_post_example.$(OBJEXT) +refuse_post_example_OBJECTS = $(am_refuse_post_example_OBJECTS) +refuse_post_example_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(authorization_example_SOURCES) \ + $(fileserver_example_SOURCES) \ + $(fileserver_example_dirs_SOURCES) \ + $(fileserver_example_external_select_SOURCES) \ + $(https_fileserver_example_SOURCES) $(minimal_example_SOURCES) \ + $(minimal_example_comet_SOURCES) \ + $(querystring_example_SOURCES) $(refuse_post_example_SOURCES) +DIST_SOURCES = $(authorization_example_SOURCES) \ + $(fileserver_example_SOURCES) \ + $(fileserver_example_dirs_SOURCES) \ + $(fileserver_example_external_select_SOURCES) \ + $(https_fileserver_example_SOURCES) $(minimal_example_SOURCES) \ + $(minimal_example_comet_SOURCES) \ + $(querystring_example_SOURCES) $(refuse_post_example_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https \ + @LIBGCRYPT_CFLAGS@ + +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage +minimal_example_SOURCES = \ + minimal_example.c + +minimal_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +minimal_example_comet_SOURCES = \ + minimal_example_comet.c + +minimal_example_comet_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +authorization_example_SOURCES = \ + authorization_example.c + +authorization_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +refuse_post_example_SOURCES = \ + refuse_post_example.c + +refuse_post_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +querystring_example_SOURCES = \ + querystring_example.c + +querystring_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +fileserver_example_SOURCES = \ + fileserver_example.c + +fileserver_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +fileserver_example_dirs_SOURCES = \ + fileserver_example_dirs.c + +fileserver_example_dirs_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +fileserver_example_external_select_SOURCES = \ + fileserver_example_external_select.c + +fileserver_example_external_select_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +https_fileserver_example_SOURCES = \ +https_fileserver_example.c + +https_fileserver_example_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/examples/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/examples/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +authorization_example$(EXEEXT): $(authorization_example_OBJECTS) $(authorization_example_DEPENDENCIES) + @rm -f authorization_example$(EXEEXT) + $(LINK) $(authorization_example_OBJECTS) $(authorization_example_LDADD) $(LIBS) +fileserver_example$(EXEEXT): $(fileserver_example_OBJECTS) $(fileserver_example_DEPENDENCIES) + @rm -f fileserver_example$(EXEEXT) + $(LINK) $(fileserver_example_OBJECTS) $(fileserver_example_LDADD) $(LIBS) +fileserver_example_dirs$(EXEEXT): $(fileserver_example_dirs_OBJECTS) $(fileserver_example_dirs_DEPENDENCIES) + @rm -f fileserver_example_dirs$(EXEEXT) + $(LINK) $(fileserver_example_dirs_OBJECTS) $(fileserver_example_dirs_LDADD) $(LIBS) +fileserver_example_external_select$(EXEEXT): $(fileserver_example_external_select_OBJECTS) $(fileserver_example_external_select_DEPENDENCIES) + @rm -f fileserver_example_external_select$(EXEEXT) + $(LINK) $(fileserver_example_external_select_OBJECTS) $(fileserver_example_external_select_LDADD) $(LIBS) +https_fileserver_example$(EXEEXT): $(https_fileserver_example_OBJECTS) $(https_fileserver_example_DEPENDENCIES) + @rm -f https_fileserver_example$(EXEEXT) + $(LINK) $(https_fileserver_example_OBJECTS) $(https_fileserver_example_LDADD) $(LIBS) +minimal_example$(EXEEXT): $(minimal_example_OBJECTS) $(minimal_example_DEPENDENCIES) + @rm -f minimal_example$(EXEEXT) + $(LINK) $(minimal_example_OBJECTS) $(minimal_example_LDADD) $(LIBS) +minimal_example_comet$(EXEEXT): $(minimal_example_comet_OBJECTS) $(minimal_example_comet_DEPENDENCIES) + @rm -f minimal_example_comet$(EXEEXT) + $(LINK) $(minimal_example_comet_OBJECTS) $(minimal_example_comet_LDADD) $(LIBS) +querystring_example$(EXEEXT): $(querystring_example_OBJECTS) $(querystring_example_DEPENDENCIES) + @rm -f querystring_example$(EXEEXT) + $(LINK) $(querystring_example_OBJECTS) $(querystring_example_LDADD) $(LIBS) +refuse_post_example$(EXEEXT): $(refuse_post_example_OBJECTS) $(refuse_post_example_DEPENDENCIES) + @rm -f refuse_post_example$(EXEEXT) + $(LINK) $(refuse_post_example_OBJECTS) $(refuse_post_example_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/authorization_example.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileserver_example.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileserver_example_dirs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileserver_example_external_select.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/https_fileserver_example.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minimal_example.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minimal_example_comet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/querystring_example.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refuse_post_example.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + clean-noinstPROGRAMS ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/examples/authorization_example.c b/lib/libmicrohttpd/src/examples/authorization_example.c new file mode 100644 index 0000000000..b271053eee --- /dev/null +++ b/lib/libmicrohttpd/src/examples/authorization_example.c @@ -0,0 +1,102 @@ +/* + This file is part of libmicrohttpd + (C) 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file authorization_example.c + * @brief example for how to use libmicrohttpd with HTTP authentication + * @author Christian Grothoff + */ + +#include "platform.h" +#include <microhttpd.h> + +#define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>" + +#define DENIED "<html><head><title>Access denied</title></head><body>Access denied</body></html>" + + + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + static int aptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + int code; + const char *auth; + + if (0 != strcmp (method, "GET")) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + auth = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_AUTHORIZATION); + if ((auth == NULL) || + (0 != strcmp (auth, "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="))) + { + /* require: "Aladdin" with password "open sesame" */ + response = MHD_create_response_from_data (strlen (DENIED), + (void *) DENIED, MHD_NO, + MHD_NO); + MHD_add_response_header (response, MHD_HTTP_HEADER_WWW_AUTHENTICATE, + "Basic realm=\"TestRealm\""); + code = MHD_HTTP_UNAUTHORIZED; + } + else + { + response = MHD_create_response_from_data (strlen (me), + (void *) me, MHD_NO, MHD_NO); + code = MHD_HTTP_OK; + } + ret = MHD_queue_response (connection, code, response); + MHD_destroy_response (response); + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 3) + { + printf ("%s PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END); + if (d == NULL) + return 1; + sleep (atoi (argv[2])); + MHD_stop_daemon (d); + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/fileserver_example.c b/lib/libmicrohttpd/src/examples/fileserver_example.c new file mode 100644 index 0000000000..76a10f2f09 --- /dev/null +++ b/lib/libmicrohttpd/src/examples/fileserver_example.c @@ -0,0 +1,106 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file fileserver_example.c + * @brief minimal example for how to use libmicrohttpd to serve files + * @author Christian Grothoff + */ + +#include "platform.h" +#include <microhttpd.h> +#include <unistd.h> + +#define PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>" + +static int +file_reader (void *cls, uint64_t pos, char *buf, int max) +{ + FILE *file = cls; + + fseek (file, pos, SEEK_SET); + return fread (buf, 1, max, file); +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, void **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + FILE *file; + struct stat buf; + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + file = fopen (&url[1], "rb"); + if (file == NULL) + { + response = MHD_create_response_from_data (strlen (PAGE), + (void *) PAGE, + MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); + MHD_destroy_response (response); + } + else + { + stat (&url[1], &buf); + response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k page size */ + &file_reader, + file, + (MHD_ContentReaderFreeCallback) + & fclose); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + } + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 3) + { + printf ("%s PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END); + if (d == NULL) + return 1; + sleep (atoi (argv[2])); + MHD_stop_daemon (d); + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/fileserver_example_dirs.c b/lib/libmicrohttpd/src/examples/fileserver_example_dirs.c new file mode 100644 index 0000000000..04519c63ea --- /dev/null +++ b/lib/libmicrohttpd/src/examples/fileserver_example_dirs.c @@ -0,0 +1,129 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file fileserver_example.c + * @brief example for how to use libmicrohttpd to serve files (with directory support) + * @author Christian Grothoff + */ + +#include "platform.h" +#include <dirent.h> +#include <microhttpd.h> +#include <unistd.h> + +#define PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>" + +static int +file_reader (void *cls, uint64_t pos, char *buf, int max) +{ + FILE *file = cls; + + fseek (file, pos, SEEK_SET); + return fread (buf, 1, max, file); +} + + +static int +dir_reader (void *cls, uint64_t pos, char *buf, int max) +{ + struct dirent *e; + if (max < 512) + return 0; + do + { + e = readdir (cls); + if (e == NULL) + return -1; + } while (e->d_name[0] == '.'); + return snprintf (buf, max, + "<a href=\"/%s\">%s</a><br>", + e->d_name, + e->d_name); +} + + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, void **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + FILE *file; + struct stat buf; + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + file = fopen (&url[1], "rb"); + if (file == NULL) + { + response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, + 32 * 1024, + &dir_reader, + opendir ("."), + (MHD_ContentReaderFreeCallback) &closedir); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + } + else + { + stat (&url[1], &buf); + response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k page size */ + &file_reader, + file, + (MHD_ContentReaderFreeCallback) + & fclose); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + } + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 2) + { + printf ("%s PORT\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END); + if (d == NULL) + return 1; + while (1) sleep (1); + MHD_stop_daemon (d); + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/fileserver_example_external_select.c b/lib/libmicrohttpd/src/examples/fileserver_example_external_select.c new file mode 100644 index 0000000000..6867335b1b --- /dev/null +++ b/lib/libmicrohttpd/src/examples/fileserver_example_external_select.c @@ -0,0 +1,136 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file fileserver_example_external_select.c + * @brief minimal example for how to use libmicrohttpd to server files + * @author Christian Grothoff + */ + +#include "platform.h" +#include <microhttpd.h> +#include <sys/stat.h> +#include <unistd.h> + +#define PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>" + +static int +file_reader (void *cls, uint64_t pos, char *buf, int max) +{ + FILE *file = cls; + + fseek (file, pos, SEEK_SET); + return fread (buf, 1, max, file); +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, void **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + FILE *file; + struct stat buf; + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + file = fopen (&url[1], "rb"); + if (file == NULL) + { + response = MHD_create_response_from_data (strlen (PAGE), + (void *) PAGE, + MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); + MHD_destroy_response (response); + } + else + { + stat (&url[1], &buf); + response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k page size */ + &file_reader, + file, + (MHD_ContentReaderFreeCallback) + & fclose); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + } + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + time_t end; + time_t t; + struct timeval tv; + fd_set rs; + fd_set ws; + fd_set es; + int max; + unsigned long long mhd_timeout; + + if (argc != 3) + { + printf ("%s PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END); + if (d == NULL) + return 1; + end = time (NULL) + atoi (argv[2]); + while ((t = time (NULL)) < end) + { + tv.tv_sec = end - t; + tv.tv_usec = 0; + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + break; /* fatal internal error */ + if (MHD_get_timeout (d, &mhd_timeout) == MHD_YES) + + { + if (tv.tv_sec * 1000 < mhd_timeout) + { + tv.tv_sec = mhd_timeout / 1000; + tv.tv_usec = (mhd_timeout - (tv.tv_sec * 1000)) * 1000; + } + } + select (max + 1, &rs, &ws, &es, &tv); + MHD_run (d); + } + MHD_stop_daemon (d); + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/https_fileserver_example.c b/lib/libmicrohttpd/src/examples/https_fileserver_example.c new file mode 100644 index 0000000000..9f9728ddc6 --- /dev/null +++ b/lib/libmicrohttpd/src/examples/https_fileserver_example.c @@ -0,0 +1,194 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file https_server_example.c + * @brief a simple HTTPS file server using TLS. + * + * Usage : + * + * 'http_fileserver_example HTTP-PORT SECONDS-TO-RUN' + * + * The certificate & key are required by the server to operate, Omitting the + * path arguments will cause the server to use the hard coded example certificate & key. + * + * 'certtool' may be used to generate these if required. + * + * @author Sagie Amir + */ + +#include "platform.h" +#include <microhttpd.h> +#include <sys/stat.h> + +#include "gnutls.h" +#include <gcrypt.h> + +#define BUF_SIZE 1024 +#define MAX_URL_LEN 255 + +// TODO remove if unused +#define CAFILE "ca.pem" +#define CRLFILE "crl.pem" + +#define EMPTY_PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>" + +/* Test Certificate */ +const char cert_pem[] = + "-----BEGIN CERTIFICATE-----\n" + "MIICpjCCAZCgAwIBAgIESEPtjjALBgkqhkiG9w0BAQUwADAeFw0wODA2MDIxMjU0\n" + "MzhaFw0wOTA2MDIxMjU0NDZaMAAwggEfMAsGCSqGSIb3DQEBAQOCAQ4AMIIBCQKC\n" + "AQC03TyUvK5HmUAirRp067taIEO4bibh5nqolUoUdo/LeblMQV+qnrv/RNAMTx5X\n" + "fNLZ45/kbM9geF8qY0vsPyQvP4jumzK0LOJYuIwmHaUm9vbXnYieILiwCuTgjaud\n" + "3VkZDoQ9fteIo+6we9UTpVqZpxpbLulBMh/VsvX0cPJ1VFC7rT59o9hAUlFf9jX/\n" + "GmKdYI79MtgVx0OPBjmmSD6kicBBfmfgkO7bIGwlRtsIyMznxbHu6VuoX/eVxrTv\n" + "rmCwgEXLWRZ6ru8MQl5YfqeGXXRVwMeXU961KefbuvmEPccgCxm8FZ1C1cnDHFXh\n" + "siSgAzMBjC/b6KVhNQ4KnUdZAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0O\n" + "BBYEFJcUvpjvE5fF/yzUshkWDpdYiQh/MAsGCSqGSIb3DQEBBQOCAQEARP7eKSB2\n" + "RNd6XjEjK0SrxtoTnxS3nw9sfcS7/qD1+XHdObtDFqGNSjGYFB3Gpx8fpQhCXdoN\n" + "8QUs3/5ZVa5yjZMQewWBgz8kNbnbH40F2y81MHITxxCe1Y+qqHWwVaYLsiOTqj2/\n" + "0S3QjEJ9tvklmg7JX09HC4m5QRYfWBeQLD1u8ZjA1Sf1xJriomFVyRLI2VPO2bNe\n" + "JDMXWuP+8kMC7gEvUnJ7A92Y2yrhu3QI3bjPk8uSpHea19Q77tul1UVBJ5g+zpH3\n" + "OsF5p0MyaVf09GTzcLds5nE/osTdXGUyHJapWReVmPm3Zn6gqYlnzD99z+DPIgIV\n" + "RhZvQx74NQnS6g==\n" "-----END CERTIFICATE-----\n"; + +const char key_pem[] = + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAtN08lLyuR5lAIq0adOu7WiBDuG4m4eZ6qJVKFHaPy3m5TEFf\n" + "qp67/0TQDE8eV3zS2eOf5GzPYHhfKmNL7D8kLz+I7psytCziWLiMJh2lJvb2152I\n" + "niC4sArk4I2rnd1ZGQ6EPX7XiKPusHvVE6VamacaWy7pQTIf1bL19HDydVRQu60+\n" + "faPYQFJRX/Y1/xpinWCO/TLYFcdDjwY5pkg+pInAQX5n4JDu2yBsJUbbCMjM58Wx\n" + "7ulbqF/3lca0765gsIBFy1kWeq7vDEJeWH6nhl10VcDHl1PetSnn27r5hD3HIAsZ\n" + "vBWdQtXJwxxV4bIkoAMzAYwv2+ilYTUOCp1HWQIDAQABAoIBAArOQv3R7gmqDspj\n" + "lDaTFOz0C4e70QfjGMX0sWnakYnDGn6DU19iv3GnX1S072ejtgc9kcJ4e8VUO79R\n" + "EmqpdRR7k8dJr3RTUCyjzf/C+qiCzcmhCFYGN3KRHA6MeEnkvRuBogX4i5EG1k5l\n" + "/5t+YBTZBnqXKWlzQLKoUAiMLPg0eRWh+6q7H4N7kdWWBmTpako7TEqpIwuEnPGx\n" + "u3EPuTR+LN6lF55WBePbCHccUHUQaXuav18NuDkcJmCiMArK9SKb+h0RqLD6oMI/\n" + "dKD6n8cZXeMBkK+C8U/K0sN2hFHACsu30b9XfdnljgP9v+BP8GhnB0nCB6tNBCPo\n" + "32srOwECgYEAxWh3iBT4lWqL6bZavVbnhmvtif4nHv2t2/hOs/CAq8iLAw0oWGZc\n" + "+JEZTUDMvFRlulr0kcaWra+4fN3OmJnjeuFXZq52lfMgXBIKBmoSaZpIh2aDY1Rd\n" + "RbEse7nQl9hTEPmYspiXLGtnAXW7HuWqVfFFP3ya8rUS3t4d07Hig8ECgYEA6ou6\n" + "OHiBRTbtDqLIv8NghARc/AqwNWgEc9PelCPe5bdCOLBEyFjqKiT2MttnSSUc2Zob\n" + "XhYkHC6zN1Mlq30N0e3Q61YK9LxMdU1vsluXxNq2rfK1Scb1oOlOOtlbV3zA3VRF\n" + "hV3t1nOA9tFmUrwZi0CUMWJE/zbPAyhwWotKyZkCgYEAh0kFicPdbABdrCglXVae\n" + "SnfSjVwYkVuGd5Ze0WADvjYsVkYBHTvhgRNnRJMg+/vWz3Sf4Ps4rgUbqK8Vc20b\n" + "AU5G6H6tlCvPRGm0ZxrwTWDHTcuKRVs+pJE8C/qWoklE/AAhjluWVoGwUMbPGuiH\n" + "6Gf1bgHF6oj/Sq7rv/VLZ8ECgYBeq7ml05YyLuJutuwa4yzQ/MXfghzv4aVyb0F3\n" + "QCdXR6o2IYgR6jnSewrZKlA9aPqFJrwHNR6sNXlnSmt5Fcf/RWO/qgJQGLUv3+rG\n" + "7kuLTNDR05azSdiZc7J89ID3Bkb+z2YkV+6JUiPq/Ei1+nDBEXb/m+/HqALU/nyj\n" + "P3gXeQKBgBusb8Rbd+KgxSA0hwY6aoRTPRt8LNvXdsB9vRcKKHUFQvxUWiUSS+L9\n" + "/Qu1sJbrUquKOHqksV5wCnWnAKyJNJlhHuBToqQTgKXjuNmVdYSe631saiI7PHyC\n" + "eRJ6DxULPxABytJrYCRrNqmXi5TCiqR2mtfalEMOPxz8rUU8dYyx\n" + "-----END RSA PRIVATE KEY-----\n"; + +static int +file_reader (void *cls, uint64_t pos, char *buf, int max) +{ + FILE *file = cls; + + fseek (file, pos, SEEK_SET); + return fread (buf, 1, max, file); +} + +/* HTTP access handler call back */ +static int +http_ahc (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, void **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + FILE *file; + struct stat buf; + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + + file = fopen (&url[1], "rb"); + if (file == NULL) + { + response = MHD_create_response_from_data (strlen (EMPTY_PAGE), + (void *) EMPTY_PAGE, + MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); + MHD_destroy_response (response); + } + else + { + stat (url, &buf); + response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k PAGE_NOT_FOUND size */ + &file_reader, file, + (MHD_ContentReaderFreeCallback) + & fclose); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + } + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *TLS_daemon; + + if (argc == 3) + { + /* TODO check if this is truly necessary - disallow usage of the blocking /dev/random */ + /* gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); */ + TLS_daemon = + MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | + MHD_USE_SSL, atoi (argv[1]), NULL, NULL, &http_ahc, + NULL, MHD_OPTION_CONNECTION_TIMEOUT, 256, + MHD_OPTION_HTTPS_MEM_KEY, key_pem, + MHD_OPTION_HTTPS_MEM_CERT, cert_pem, + MHD_OPTION_END); + } + else + { + printf ("Usage: %s HTTP-PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + + if (TLS_daemon == NULL) + { + fprintf (stderr, "Error: failed to start TLS_daemon\n"); + return 1; + } + else + { + printf ("MHD daemon listening on port %d\n", atoi (argv[1])); + } + + sleep (atoi (argv[2])); + + MHD_stop_daemon (TLS_daemon); + + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/minimal_example.c b/lib/libmicrohttpd/src/examples/minimal_example.c new file mode 100644 index 0000000000..4c73d6f216 --- /dev/null +++ b/lib/libmicrohttpd/src/examples/minimal_example.c @@ -0,0 +1,77 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file minimal_example.c + * @brief minimal example for how to use libmicrohttpd + * @author Christian Grothoff + */ + +#include "platform.h" +#include <microhttpd.h> + +#define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>" + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + static int aptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (method, "GET")) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + response = MHD_create_response_from_data (strlen (me), + (void *) me, MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 3) + { + printf ("%s PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END); + if (d == NULL) + return 1; + sleep (atoi (argv[2])); + MHD_stop_daemon (d); + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/minimal_example_comet.c b/lib/libmicrohttpd/src/examples/minimal_example_comet.c new file mode 100644 index 0000000000..03607f325a --- /dev/null +++ b/lib/libmicrohttpd/src/examples/minimal_example_comet.c @@ -0,0 +1,85 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file minimal_example.c + * @brief minimal example for how to generate an infinite stream with libmicrohttpd + * @author Christian Grothoff + */ + +#include "platform.h" +#include <microhttpd.h> + +static int +data_generator (void *cls, uint64_t pos, char *buf, int max) +{ + if (max < 80) + return 0; + memset (buf, 'A', max - 1); + buf[79] = '\n'; + return 80; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (method, "GET")) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + response = MHD_create_response_from_callback (-1, + 80, + &data_generator, NULL, NULL); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 3) + { + printf ("%s PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 1; + sleep (atoi (argv[2])); + MHD_stop_daemon (d); + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/querystring_example.c b/lib/libmicrohttpd/src/examples/querystring_example.c new file mode 100644 index 0000000000..210d9149e4 --- /dev/null +++ b/lib/libmicrohttpd/src/examples/querystring_example.c @@ -0,0 +1,84 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file querystring_example.c + * @brief example for how to get the query string from libmicrohttpd + * Call with an URI ending with something like "?q=QUERY" + * @author Christian Grothoff + */ + +#include "platform.h" +#include <microhttpd.h> + +#define PAGE "<html><head><title>libmicrohttpd demo</title></head><body>Query string for "%s" was "%s"</body></html>" + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + static int aptr; + const char *fmt = cls; + const char *val; + char *me; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (method, "GET")) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + val = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "q"); + me = malloc (snprintf (NULL, 0, fmt, "q", val) + 1); + if (me == NULL) + return MHD_NO; + sprintf (me, fmt, "q", val); + response = MHD_create_response_from_data (strlen (me), me, MHD_YES, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 3) + { + printf ("%s PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, PAGE, MHD_OPTION_END); + if (d == NULL) + return 1; + sleep (atoi (argv[2])); + MHD_stop_daemon (d); + return 0; +} diff --git a/lib/libmicrohttpd/src/examples/refuse_post_example.c b/lib/libmicrohttpd/src/examples/refuse_post_example.c new file mode 100644 index 0000000000..db6a13e922 --- /dev/null +++ b/lib/libmicrohttpd/src/examples/refuse_post_example.c @@ -0,0 +1,99 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file refuse_post_example.c + * @brief example for how to refuse a POST request properly + * @author Christian Grothoff and Sebastian Gerhardt + */ +#include "platform.h" +#include <microhttpd.h> + +const char *askpage = "<html><body>\n\ + Upload a file, please!<br>\n\ + <form action=\"/filepost\" method=\"post\" enctype=\"multipart/form-data\">\n\ + <input name=\"file\" type=\"file\">\n\ + <input type=\"submit\" value=\" Send \"></form>\n\ + </body></html>"; + +#define BUSYPAGE "<html><head><title>Webserver busy</title></head><body>We are too busy to process POSTs right now.</body></html>" + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + static int aptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + + if ((0 != strcmp (method, "GET")) && (0 != strcmp (method, "POST"))) + return MHD_NO; /* unexpected method */ + + if (&aptr != *ptr) + { + *ptr = &aptr; + + /* always to busy for POST requests */ + if (0 == strcmp (method, "POST")) + { + response = MHD_create_response_from_data (strlen (BUSYPAGE), + (void *) BUSYPAGE, MHD_NO, + MHD_NO); + ret = + MHD_queue_response (connection, MHD_HTTP_SERVICE_UNAVAILABLE, + response); + MHD_destroy_response (response); + return ret; + } + } + + *ptr = NULL; /* reset when done */ + response = MHD_create_response_from_data (strlen (me), + (void *) me, MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +int +main (int argc, char *const *argv) +{ + struct MHD_Daemon *d; + + if (argc != 3) + { + printf ("%s PORT SECONDS-TO-RUN\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + atoi (argv[1]), + NULL, NULL, &ahc_echo, (void *) askpage, + MHD_OPTION_END); + if (d == NULL) + return 1; + sleep (atoi (argv[2])); + MHD_stop_daemon (d); + return 0; +} + +/* end of refuse_post_example.c */ diff --git a/lib/libmicrohttpd/src/include/Makefile.am b/lib/libmicrohttpd/src/include/Makefile.am new file mode 100644 index 0000000000..f76fe3b087 --- /dev/null +++ b/lib/libmicrohttpd/src/include/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = . +include_HEADERS = microhttpd.h + +EXTRA_DIST = platform.h plibc.h diff --git a/lib/libmicrohttpd/src/include/Makefile.in b/lib/libmicrohttpd/src/include/Makefile.in new file mode 100644 index 0000000000..d208ee9660 --- /dev/null +++ b/lib/libmicrohttpd/src/include/Makefile.in @@ -0,0 +1,625 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/include +DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(includedir)" +HEADERS = $(include_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +include_HEADERS = microhttpd.h +EXTRA_DIST = platform.h plibc.h +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includedir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-includeHEADERS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-includeHEADERS install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-includeHEADERS + + +# 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/lib/libmicrohttpd/src/include/microhttpd.h b/lib/libmicrohttpd/src/include/microhttpd.h new file mode 100644 index 0000000000..33a33ee0a3 --- /dev/null +++ b/lib/libmicrohttpd/src/include/microhttpd.h @@ -0,0 +1,1312 @@ +/* + This file is part of libmicrohttpd + (C) 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file microhttpd.h + * @brief public interface to libmicrohttpd + * @author Christian Grothoff + * @author Chris GauthierDickey + * + * All symbols defined in this header start with MHD. MHD is a small + * HTTP daemon library. As such, it does not have any API for logging + * errors (you can only enable or disable logging to stderr). Also, + * it may not support all of the HTTP features directly, where + * applicable, portions of HTTP may have to be handled by clients of + * the library.<p> + * + * The library is supposed to handle everything that it must handle + * (because the API would not allow clients to do this), such as basic + * connection management; however, detailed interpretations of headers + * -- such as range requests -- and HTTP methods are left to clients. + * The library does understand HEAD and will only send the headers of + * the response and not the body, even if the client supplied a body. + * The library also understands headers that control connection + * management (specifically, "Connection: close" and "Expect: 100 + * continue" are understood and handled automatically).<p> + * + * MHD understands POST data and is able to decode certain formats + * (at the moment only "application/x-www-form-urlencoded") if the + * entire data fits into the allowed amount of memory for the + * connection. Unsupported encodings and large POST submissions are + * provided as a stream to the main application (and thus can be + * processed, just not conveniently by MHD).<p> + * + * The header file defines various constants used by the HTTP protocol. + * This does not mean that MHD actually interprets all of these + * values. The provided constants are exported as a convenience + * for users of the library. MHD does not verify that transmitted + * HTTP headers are part of the standard specification; users of the + * library are free to define their own extensions of the HTTP + * standard and use those with MHD.<p> + * + * All functions are guaranteed to be completely reentrant and + * thread-safe (with the exception of 'MHD_set_connection_value', + * which must only be used in a particular context).<p> + * + * NEW: Before including "microhttpd.h" you should add the necessary + * includes to define the "uint64_t", "size_t", "fd_set", "socklen_t" + * and "struct sockaddr" data types (which headers are needed may + * depend on your platform; for possible suggestions consult + * "platform.h" in the MHD distribution). + * + */ + +#ifndef MHD_MICROHTTPD_H +#define MHD_MICROHTTPD_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +/** + * Current version of the library. + */ +#define MHD_VERSION 0x00040500 + +/** + * MHD-internal return code for "YES". + */ +#define MHD_YES 1 + +/** + * MHD-internal return code for "NO". + */ +#define MHD_NO 0 + +/** + * Constant used to indicate unknown size (use when + * creating a response). + */ +#define MHD_SIZE_UNKNOWN ((uint64_t) -1LL) + +/** + * HTTP response codes. + */ +#define MHD_HTTP_CONTINUE 100 +#define MHD_HTTP_SWITCHING_PROTOCOLS 101 +#define MHD_HTTP_PROCESSING 102 + +#define MHD_HTTP_OK 200 +#define MHD_HTTP_CREATED 201 +#define MHD_HTTP_ACCEPTED 202 +#define MHD_HTTP_NON_AUTHORITATIVE_INFORMATION 203 +#define MHD_HTTP_NO_CONTENT 204 +#define MHD_HTTP_RESET_CONTENT 205 +#define MHD_HTTP_PARTIAL_CONTENT 206 +#define MHD_HTTP_MULTI_STATUS 207 + +#define MHD_HTTP_MULTIPLE_CHOICES 300 +#define MHD_HTTP_MOVED_PERMANENTLY 301 +#define MHD_HTTP_FOUND 302 +#define MHD_HTTP_SEE_OTHER 303 +#define MHD_HTTP_NOT_MODIFIED 304 +#define MHD_HTTP_USE_PROXY 305 +#define MHD_HTTP_SWITCH_PROXY 306 +#define MHD_HTTP_TEMPORARY_REDIRECT 307 + +#define MHD_HTTP_BAD_REQUEST 400 +#define MHD_HTTP_UNAUTHORIZED 401 +#define MHD_HTTP_PAYMENT_REQUIRED 402 +#define MHD_HTTP_FORBIDDEN 403 +#define MHD_HTTP_NOT_FOUND 404 +#define MHD_HTTP_METHOD_NOT_ALLOWED 405 +#define MHD_HTTP_METHOD_NOT_ACCEPTABLE 406 +#define MHD_HTTP_PROXY_AUTHENTICATION_REQUIRED 407 +#define MHD_HTTP_REQUEST_TIMEOUT 408 +#define MHD_HTTP_CONFLICT 409 +#define MHD_HTTP_GONE 410 +#define MHD_HTTP_LENGTH_REQUIRED 411 +#define MHD_HTTP_PRECONDITION_FAILED 412 +#define MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 413 +#define MHD_HTTP_REQUEST_URI_TOO_LONG 414 +#define MHD_HTTP_UNSUPPORTED_MEDIA_TYPE 415 +#define MHD_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416 +#define MHD_HTTP_EXPECTATION_FAILED 417 +#define MHD_HTTP_UNPROCESSABLE_ENTITY 422 +#define MHD_HTTP_LOCKED 423 +#define MHD_HTTP_FAILED_DEPENDENCY 424 +#define MHD_HTTP_UNORDERED_COLLECTION 425 +#define MHD_HTTP_UPGRADE_REQUIRED 426 +#define MHD_HTTP_RETRY_WITH 449 + +#define MHD_HTTP_INTERNAL_SERVER_ERROR 500 +#define MHD_HTTP_NOT_IMPLEMENTED 501 +#define MHD_HTTP_BAD_GATEWAY 502 +#define MHD_HTTP_SERVICE_UNAVAILABLE 503 +#define MHD_HTTP_GATEWAY_TIMEOUT 504 +#define MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED 505 +#define MHD_HTTP_VARIANT_ALSO_NEGOTIATES 506 +#define MHD_HTTP_INSUFFICIENT_STORAGE 507 +#define MHD_HTTP_BANDWIDTH_LIMIT_EXCEEDED 509 +#define MHD_HTTP_NOT_EXTENDED 510 + +/* See also: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html */ +#define MHD_HTTP_HEADER_ACCEPT "Accept" +#define MHD_HTTP_HEADER_ACCEPT_CHARSET "Accept-Charset" +#define MHD_HTTP_HEADER_ACCEPT_ENCODING "Accept-Encoding" +#define MHD_HTTP_HEADER_ACCEPT_LANGUAGE "Accept-Language" +#define MHD_HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges" +#define MHD_HTTP_HEADER_AGE "Age" +#define MHD_HTTP_HEADER_ALLOW "Allow" +#define MHD_HTTP_HEADER_AUTHORIZATION "Authorization" +#define MHD_HTTP_HEADER_CACHE_CONTROL "Cache-Control" +#define MHD_HTTP_HEADER_CONNECTION "Connection" +#define MHD_HTTP_HEADER_CONTENT_ENCODING "Content-Encoding" +#define MHD_HTTP_HEADER_CONTENT_LANGUAGE "Content-Language" +#define MHD_HTTP_HEADER_CONTENT_LENGTH "Content-Length" +#define MHD_HTTP_HEADER_CONTENT_LOCATION "Content-Location" +#define MHD_HTTP_HEADER_CONTENT_MD5 "Content-MD5" +#define MHD_HTTP_HEADER_CONTENT_RANGE "Content-Range" +#define MHD_HTTP_HEADER_CONTENT_TYPE "Content-Type" +#define MHD_HTTP_HEADER_COOKIE "Cookie" +#define MHD_HTTP_HEADER_DATE "Date" +#define MHD_HTTP_HEADER_ETAG "ETag" +#define MHD_HTTP_HEADER_EXPECT "Expect" +#define MHD_HTTP_HEADER_EXPIRES "Expires" +#define MHD_HTTP_HEADER_FROM "From" +#define MHD_HTTP_HEADER_HOST "Host" +#define MHD_HTTP_HEADER_IF_MATCH "If-Match" +#define MHD_HTTP_HEADER_IF_MODIFIED_SINCE "If-Modified-Since" +#define MHD_HTTP_HEADER_IF_NONE_MATCH "If-None-Match" +#define MHD_HTTP_HEADER_IF_RANGE "If-Range" +#define MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE "If-Unmodified-Since" +#define MHD_HTTP_HEADER_LAST_MODIFIED "Last-Modified" +#define MHD_HTTP_HEADER_LOCATION "Location" +#define MHD_HTTP_HEADER_MAX_FORWARDS "Max-Forwards" +#define MHD_HTTP_HEADER_PRAGMA "Pragma" +#define MHD_HTTP_HEADER_PROXY_AUTHENTICATE "Proxy-Authenticate" +#define MHD_HTTP_HEADER_PROXY_AUTHORIZATION "Proxy-Authorization" +#define MHD_HTTP_HEADER_RANGE "Range" +#define MHD_HTTP_HEADER_REFERER "Referer" +#define MHD_HTTP_HEADER_RETRY_AFTER "Retry-After" +#define MHD_HTTP_HEADER_SERVER "Server" +#define MHD_HTTP_HEADER_SET_COOKIE "Set-Cookie" +#define MHD_HTTP_HEADER_SET_COOKIE2 "Set-Cookie2" +#define MHD_HTTP_HEADER_TE "TE" +#define MHD_HTTP_HEADER_TRAILER "Trailer" +#define MHD_HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding" +#define MHD_HTTP_HEADER_UPGRADE "Upgrade" +#define MHD_HTTP_HEADER_USER_AGENT "User-Agent" +#define MHD_HTTP_HEADER_VARY "Vary" +#define MHD_HTTP_HEADER_VIA "Via" +#define MHD_HTTP_HEADER_WARNING "Warning" +#define MHD_HTTP_HEADER_WWW_AUTHENTICATE "WWW-Authenticate" + +/** + * HTTP versions (used to match against the first line of the + * HTTP header as well as in the response code). + */ +#define MHD_HTTP_VERSION_1_0 "HTTP/1.0" +#define MHD_HTTP_VERSION_1_1 "HTTP/1.1" + +/** + * HTTP methods + */ +#define MHD_HTTP_METHOD_CONNECT "CONNECT" +#define MHD_HTTP_METHOD_DELETE "DELETE" +#define MHD_HTTP_METHOD_GET "GET" +#define MHD_HTTP_METHOD_HEAD "HEAD" +#define MHD_HTTP_METHOD_OPTIONS "OPTIONS" +#define MHD_HTTP_METHOD_POST "POST" +#define MHD_HTTP_METHOD_PUT "PUT" +#define MHD_HTTP_METHOD_TRACE "TRACE" + +/** + * HTTP POST encodings, see also + * http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 + */ +#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED "application/x-www-form-urlencoded" +#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data" + +/** + * Options for the MHD daemon. Note that if neither + * MHD_USER_THREAD_PER_CONNECTION nor MHD_USE_SELECT_INTERNALLY are + * used, the client wants control over the process and will call the + * appropriate microhttpd callbacks.<p> + * + * Starting the daemon may also fail if a particular option is not + * implemented or not supported on the target platform (i.e. no + * support for SSL, threads or IPv6). + */ +enum MHD_FLAG +{ + /** + * No options selected. + */ + MHD_NO_FLAG = 0, + + /** + * Run in debug mode. If this flag is used, the + * library should print error messages and warnings + * to stderr. + */ + MHD_USE_DEBUG = 1, + + /** + * Run in https mode. + */ + MHD_USE_SSL = 2, + + /** + * Run using one thread per connection. + */ + MHD_USE_THREAD_PER_CONNECTION = 4, + + /** + * Run using an internal thread doing SELECT. + */ + MHD_USE_SELECT_INTERNALLY = 8, + + /** + * Run using the IPv6 protocol (otherwise, MHD will + * just support IPv4). + */ + MHD_USE_IPv6 = 16, + + /** + * Be pedantic about the protocol (as opposed to as tolerant as + * possible). Specifically, at the moment, this flag causes MHD to + * reject http 1.1 connections without a "Host" header. This is + * required by the standard, but of course in violation of the "be + * as liberal as possible in what you accept" norm. It is + * recommended to turn this ON if you are testing clients against + * MHD, and OFF in production. + */ + MHD_USE_PEDANTIC_CHECKS = 32, + + /** + * Use poll instead of select. This allows sockets with fd >= FD_SETSIZE. + * This option only works in conjunction with MHD_USE_THREAD_PER_CONNECTION + * (at this point). + */ + MHD_USE_POLL = 64 +}; + +/** + * MHD options. Passed in the varargs portion + * of MHD_start_daemon. + */ +enum MHD_OPTION +{ + + /** + * No more options / last option. This is used + * to terminate the VARARGs list. + */ + MHD_OPTION_END = 0, + + /** + * Maximum memory size per connection (followed by a + * size_t). + */ + MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1, + + /** + * Maximum number of concurrent connections to + * accept (followed by an unsigned int). + */ + MHD_OPTION_CONNECTION_LIMIT = 2, + + /** + * After how many seconds of inactivity should a + * connection automatically be timed out? (followed + * by an unsigned int; use zero for no timeout). + */ + MHD_OPTION_CONNECTION_TIMEOUT = 3, + + /** + * Register a function that should be called whenever a request has + * been completed (this can be used for application-specific clean + * up). Requests that have never been presented to the application + * (via MHD_AccessHandlerCallback) will not result in + * notifications.<p> + * + * This option should be followed by TWO pointers. First a pointer + * to a function of type "MHD_RequestCompletedCallback" and second a + * pointer to a closure to pass to the request completed callback. + * The second pointer maybe NULL. + */ + MHD_OPTION_NOTIFY_COMPLETED = 4, + + /** + * Limit on the number of (concurrent) connections made to the + * server from the same IP address. Can be used to prevent one + * IP from taking over all of the allowed connections. If the + * same IP tries to establish more than the specified number of + * connections, they will be immediately rejected. The option + * should be followed by an "unsigned int". The default is + * zero, which means no limit on the number of connections + * from the same IP address. + */ + MHD_OPTION_PER_IP_CONNECTION_LIMIT = 5, + + /** + * Bind daemon to the supplied sockaddr. this option should be followed by a + * 'struct sockaddr *'. If 'MHD_USE_IPv6' is specified, the 'struct sockaddr*' + * should point to a 'struct sockaddr_in6', otherwise to a 'struct sockaddr_in'. + */ + MHD_OPTION_SOCK_ADDR = 6, + + /** + * Specify a function that should be called before parsing the URI from + * the client. The specified callback function can be used for processing + * the URI (including the options) before it is parsed. The URI after + * parsing will no longer contain the options, which maybe inconvenient for + * logging. This option should be followed by two arguments, the first + * one must be of the form + * <pre> + * void * my_logger(void * cls, const char * uri) + * </pre> + * where the return value will be passed as + * (*con_cls) in calls to the MHD_AccessHandlerCallback + * when this request is processed later; returning a + * value of NULL has no special significance (however, + * note that if you return non-NULL, you can no longer + * rely on the first call to the access handler having + * NULL == *con_cls on entry;) + * "cls" will be set to the second argument following + * MHD_OPTION_URI_LOG_CALLBACK. Finally, uri will + * be the 0-terminated URI of the request. + */ + MHD_OPTION_URI_LOG_CALLBACK = 7, + + /** + * Memory pointer for the private key (key.pem) to be used by the + * HTTPS daemon. This option should be followed by an + * "const char*" argument. + * This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_CERT'. + */ + MHD_OPTION_HTTPS_MEM_KEY = 8, + + /** + * Memory pointer for the certificate (cert.pem) to be used by the + * HTTPS daemon. This option should be followed by an + * "const char*" argument. + * This should be used in conjunction with 'MHD_OPTION_HTTPS_MEM_KEY'. + */ + MHD_OPTION_HTTPS_MEM_CERT = 9, + + /** + * Daemon credentials type. + * This option should be followed by one of the values listed in + * "enum MHD_GNUTLS_CredentialsType". + */ + MHD_OPTION_CRED_TYPE = 10, + + /** + * SSL/TLS protocol version. + * + * Memory pointer to a zero (MHD_GNUTLS_PROTOCOL_END) terminated + * (const) array of 'enum MHD_GNUTLS_Protocol' values representing the + * protocol versions to this server should support. Unsupported + * requests will be droped by the server. + */ + MHD_OPTION_PROTOCOL_VERSION = 11, + + /** + * Memory pointer to a zero (MHD_GNUTLS_CIPHER_UNKNOWN) + * terminated (const) array of 'enum MHD_GNUTLS_CipherAlgorithm' + * representing the cipher priority order to which the HTTPS + * daemon should adhere. + */ + MHD_OPTION_CIPHER_ALGORITHM = 12, + + /** + * Use the given function for logging error messages. + * This option must be followed by two arguments; the + * first must be a pointer to a function + * of type "void fun(void * arg, const char * fmt, va_list ap)" + * and the second a pointer "void*" which will + * be passed as the "arg" argument to "fun". + * <p> + * Note that MHD will not generate any log messages + * if it was compiled without the "--enable-messages" + * flag being set. + */ + MHD_OPTION_EXTERNAL_LOGGER = 13, + + /** + * Number (unsigned int) of threads in thread pool. Enable + * thread pooling by setting this value to to something + * greater than 1. Currently, thread model must be + * MHD_USE_SELECT_INTERNALLY if thread pooling is enabled + * (MHD_start_daemon returns NULL for an unsupported thread + * model). + */ + MHD_OPTION_THREAD_POOL_SIZE = 14, + + /** + * Additional options given in an array of "struct MHD_OptionItem". + * The array must be terminated with an entry '{MHD_OPTION_END, 0, NULL}'. + * An example for code using MHD_OPTION_ARRAY is: + * <code> + * struct MHD_OptionItem ops[] = { + * { MHD_OPTION_CONNECTION_LIMIT, 100, NULL }, + * { MHD_OPTION_CONNECTION_TIMEOUT, 10, NULL }, + * { MHD_OPTION_END, 0, NULL } + * }; + * d = MHD_start_daemon(0, 8080, NULL, NULL, dh, NULL, + * MHD_OPTION_ARRAY, ops, + * MHD_OPTION_END); + * </code> + * For options that expect a single pointer argument, the + * second member of the struct MHD_OptionItem is ignored. + * For options that expect two pointer arguments, the first + * argument must be cast to 'intptr_t'. + */ + MHD_OPTION_ARRAY = 15 +}; + + +/** + * Entry in an MHD_OPTION_ARRAY. + */ +struct MHD_OptionItem +{ + /** + * Which option is being given. Use MHD_OPTION_END + * to terminate the array. + */ + enum MHD_OPTION option; + + /** + * Option value (for integer arguments, and for options requiring + * two pointer arguments); should be 0 for options that take no + * arguments or only a single pointer argument. + */ + intptr_t value; + + /** + * Pointer option value (use NULL for options taking no arguments + * or only an integer option). + */ + void *ptr_value; + +}; + + +/** + * The MHD_ValueKind specifies the source of + * the key-value pairs in the HTTP protocol. + */ +enum MHD_ValueKind +{ + + /** + * Response header + */ + MHD_RESPONSE_HEADER_KIND = 0, + + /** + * HTTP header. + */ + MHD_HEADER_KIND = 1, + + /** + * Cookies. Note that the original HTTP header containing + * the cookie(s) will still be available and intact. + */ + MHD_COOKIE_KIND = 2, + + /** + * POST data. This is available only if a content encoding + * supported by MHD is used (currently only URL encoding), + * and only if the posted content fits within the available + * memory pool. Note that in that case, the upload data + * given to the MHD_AccessHandlerCallback will be + * empty (since it has already been processed). + */ + MHD_POSTDATA_KIND = 4, + + /** + * GET (URI) arguments. + */ + MHD_GET_ARGUMENT_KIND = 8, + + /** + * HTTP footer (only for http 1.1 chunked encodings). + */ + MHD_FOOTER_KIND = 16 +}; + +/** + * The MHD_RequestTerminationCode specifies reasons + * why a request has been terminated (or completed). + */ +enum MHD_RequestTerminationCode +{ + + /** + * We finished sending the response. + */ + MHD_REQUEST_TERMINATED_COMPLETED_OK = 0, + + /** + * Error handling the connection (resources + * exhausted, other side closed connection, + * application error accepting request, etc.) + */ + MHD_REQUEST_TERMINATED_WITH_ERROR = 1, + + /** + * No activity on the connection for the number + * of seconds specified using + * MHD_OPTION_CONNECTION_TIMEOUT. + */ + MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 2, + + /** + * We had to close the session since MHD was being + * shut down. + */ + MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3 + +}; + +/** + * List of symmetric ciphers. + * Note that not all listed algorithms are necessarily + * supported by all builds of MHD. + */ +enum MHD_GNUTLS_CipherAlgorithm +{ + MHD_GNUTLS_CIPHER_UNKNOWN = 0, + MHD_GNUTLS_CIPHER_NULL = 1, + MHD_GNUTLS_CIPHER_ARCFOUR_128, + MHD_GNUTLS_CIPHER_3DES_CBC, + MHD_GNUTLS_CIPHER_AES_128_CBC, + MHD_GNUTLS_CIPHER_AES_256_CBC +}; + +/** + * SSL/TLS Protocol types. + * Note that not all listed algorithms are necessarily + * supported by all builds of MHD. + */ +enum MHD_GNUTLS_Protocol +{ + MHD_GNUTLS_PROTOCOL_END = 0, + MHD_GNUTLS_PROTOCOL_SSL3 = 1, + MHD_GNUTLS_PROTOCOL_TLS1_0, + MHD_GNUTLS_PROTOCOL_TLS1_1, + MHD_GNUTLS_PROTOCOL_TLS1_2, + MHD_GNUTLS_PROTOCOL_VERSION_UNKNOWN = 0xff +}; + +/** + * Values of this enum are used to specify what + * information about a connection is desired. + */ +enum MHD_ConnectionInfoType +{ + /** + * What cipher algorithm is being used. + * Takes no extra arguments. + */ + MHD_CONNECTION_INFO_CIPHER_ALGO, + + /** + * + * Takes no extra arguments. + */ + MHD_CONNECTION_INFO_PROTOCOL, + + /** + * Obtain IP address of the client. + * Takes no extra arguments. + */ + MHD_CONNECTION_INFO_CLIENT_ADDRESS +}; + +/** + * Values of this enum are used to specify what + * information about a deamon is desired. + */ +enum MHD_DaemonInfoType +{ + /** + * Request information about the key size for + * a particular cipher algorithm. The cipher + * algorithm should be passed as an extra + * argument (of type 'enum MHD_GNUTLS_CipherAlgorithm'). + */ + MHD_DAEMON_INFO_KEY_SIZE, + + /** + * Request information about the key size for + * a particular cipher algorithm. The cipher + * algorithm should be passed as an extra + * argument (of type 'enum MHD_GNUTLS_HashAlgorithm'). + */ + MHD_DAEMON_INFO_MAC_KEY_SIZE, + + /** + * Request the file descriptor for the listening socket. + * No extra arguments should be passed. + */ + MHD_DAEMON_INFO_LISTEN_FD +}; + + + +/** + * Handle for the daemon (listening on a socket for HTTP traffic). + */ +struct MHD_Daemon; + +/** + * Handle for a connection / HTTP request. With HTTP/1.1, multiple + * requests can be run over the same connection. However, MHD will + * only show one request per TCP connection to the client at any given + * time. + */ +struct MHD_Connection; + +/** + * Handle for a response. + */ +struct MHD_Response; + +/** + * Handle for POST processing. + */ +struct MHD_PostProcessor; + +/** + * Callback for serious error condition. The default action is to abort(). + * @param cls user specified value + * @param file where the error occured + * @param line where the error occured + * @param reason error detail, may be NULL + */ +typedef void (*MHD_PanicCallback) (void *cls, + const char *file, + unsigned int line, + const char *reason); + +/** + * Allow or deny a client to connect. + * + * @param addr address information from the client + * @param addrlen length of the address information + * @return MHD_YES if connection is allowed, MHD_NO if not + */ +typedef int + (*MHD_AcceptPolicyCallback) (void *cls, + const struct sockaddr * addr, + socklen_t addrlen); + +/** + * A client has requested the given url using the given method ("GET", + * "PUT", "DELETE", "POST", etc). The callback must call MHS + * callbacks to provide content to give back to the client and return + * an HTTP status code (i.e. 200 for OK, 404, etc.). + * + * @param cls argument given together with the function + * pointer when the handler was registered with MHD + * @param url the requested url + * @param method the HTTP method used ("GET", "PUT", etc.) + * @param version the HTTP version string (i.e. "HTTP/1.1") + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of MHD_get_connection_values; very large POST + * data *will* be made available incrementally in + * upload_data) + * @param upload_data_size set initially to the size of the + * upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param con_cls pointer that the callback can set to some + * address and that will be preserved by MHD for future + * calls for this request; since the access handler may + * be called many times (i.e., for a PUT/POST operation + * with plenty of upload data) this allows the application + * to easily associate some request-specific state. + * If necessary, this state can be cleaned up in the + * global "MHD_RequestCompleted" callback (which + * can be set with the MHD_OPTION_NOTIFY_COMPLETED). + * Initially, <tt>*con_cls</tt> will be NULL. + * @return MHS_YES if the connection was handled successfully, + * MHS_NO if the socket must be closed due to a serios + * error while handling the request + */ +typedef int + (*MHD_AccessHandlerCallback) (void *cls, + struct MHD_Connection * connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **con_cls); + +/** + * Signature of the callback used by MHD to notify the + * application about completed requests. + * + * @param cls client-defined closure + * @param connection connection handle + * @param con_cls value as set by the last call to + * the MHD_AccessHandlerCallback + * @param toe reason for request termination + * @see MHD_OPTION_NOTIFY_COMPLETED + */ +typedef void + (*MHD_RequestCompletedCallback) (void *cls, + struct MHD_Connection * connection, + void **con_cls, + enum MHD_RequestTerminationCode toe); + +/** + * Iterator over key-value pairs. This iterator + * can be used to iterate over all of the cookies, + * headers, or POST-data fields of a request, and + * also to iterate over the headers that have been + * added to a response. + * + * @return MHD_YES to continue iterating, + * MHD_NO to abort the iteration + */ +typedef int + (*MHD_KeyValueIterator) (void *cls, + enum MHD_ValueKind kind, + const char *key, const char *value); + +/** + * Callback used by libmicrohttpd in order to obtain content. The + * callback is to copy at most "max" bytes of content into "buf". The + * total number of bytes that has been placed into "buf" should be + * returned.<p> + * + * Note that returning zero will cause libmicrohttpd to try again, + * either "immediately" if in multi-threaded mode (in which case the + * callback may want to do blocking operations) or in the next round + * if MHD_run is used. Returning 0 for a daemon that runs in internal + * select mode is an error (since it would result in busy waiting) and + * will cause the program to be aborted (abort()). + * + * @param cls extra argument to the callback + * @param pos position in the datastream to access; + * note that if an MHD_Response object is re-used, + * it is possible for the same content reader to + * be queried multiple times for the same data; + * however, if an MHD_Response is not re-used, + * libmicrohttpd guarantees that "pos" will be + * the sum of all non-negative return values + * obtained from the content reader so far. + * @return -1 for the end of transmission (or on error); + * if a content transfer size was pre-set and the callback + * has provided fewer than that amount of data, + * MHD will close the connection with the client; + * if no content size was specified and this is an + * http 1.1 connection using chunked encoding, MHD will + * interpret "-1" as the normal end of the transfer + * (possibly allowing the client to perform additional + * requests using the same TCP connection). + */ +typedef int + (*MHD_ContentReaderCallback) (void *cls, + uint64_t pos, + char *buf, + int max); + +/** + * This method is called by libmicrohttpd if we + * are done with a content reader. It should + * be used to free resources associated with the + * content reader. + */ +typedef void (*MHD_ContentReaderFreeCallback) (void *cls); + +/** + * Iterator over key-value pairs where the value + * maybe made available in increments and/or may + * not be zero-terminated. Used for processing + * POST data. + * + * @param cls user-specified closure + * @param kind type of the value + * @param key 0-terminated key for the value + * @param filename name of the uploaded file, NULL if not known + * @param content_type mime-type of the data, NULL if not known + * @param transfer_encoding encoding of the data, NULL if not known + * @param data pointer to size bytes of data at the + * specified offset + * @param off offset of data in the overall value + * @param size number of bytes in data available + * @return MHD_YES to continue iterating, + * MHD_NO to abort the iteration + */ +typedef int + (*MHD_PostDataIterator) (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *data, uint64_t off, size_t size); + +/* **************** Daemon handling functions ***************** */ + +/** + * Start a webserver on the given port. + * + * @param flags combination of MHD_FLAG values + * @param port port to bind to + * @param apc callback to call to check which clients + * will be allowed to connect; you can pass NULL + * in which case connections from any IP will be + * accepted + * @param apc_cls extra argument to apc + * @param dh handler called for all requests (repeatedly) + * @param dh_cls extra argument to dh + * @param ... list of options (type-value pairs, + * terminated with MHD_OPTION_END). + * @return NULL on error, handle to daemon on success + */ +struct MHD_Daemon *MHD_start_daemon_va (unsigned int options, + unsigned short port, + MHD_AcceptPolicyCallback apc, + void *apc_cls, + MHD_AccessHandlerCallback dh, + void *dh_cls, va_list ap); + +/** + * Start a webserver on the given port. Variadic version of + * MHD_start_daemon_va. + * + * @param flags combination of MHD_FLAG values + * @param port port to bind to + * @param apc callback to call to check which clients + * will be allowed to connect; you can pass NULL + * in which case connections from any IP will be + * accepted + * @param apc_cls extra argument to apc + * @param dh handler called for all requests (repeatedly) + * @param dh_cls extra argument to dh + * @return NULL on error, handle to daemon on success + */ +struct MHD_Daemon *MHD_start_daemon (unsigned int flags, + unsigned short port, + MHD_AcceptPolicyCallback apc, + void *apc_cls, + MHD_AccessHandlerCallback dh, + void *dh_cls, ...); + +/** + * Shutdown an http daemon. + * + * @param daemon daemon to stop + */ +void MHD_stop_daemon (struct MHD_Daemon *daemon); + + +/** + * Obtain the select sets for this daemon. + * + * @param daemon daemon to get sets from + * @param read_fd_set read set + * @param write_fd_set write set + * @param except_fd_set except set + * @param max_fd increased to largest FD added (if larger + * than existing value) + * @return MHD_YES on success, MHD_NO if this + * daemon was not started with the right + * options for this call. + */ +int +MHD_get_fdset (struct MHD_Daemon *daemon, + fd_set * read_fd_set, + fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd); + +/** + * Obtain timeout value for select for this daemon + * (only needed if connection timeout is used). The + * returned value is how long select should at most + * block, not the timeout value set for connections. + * + * @param daemon daemon to query for timeout + * @param timeout set to the timeout (in milliseconds) + * @return MHD_YES on success, MHD_NO if timeouts are + * not used (or no connections exist that would + * necessiate the use of a timeout right now). + */ +int MHD_get_timeout (struct MHD_Daemon *daemon, unsigned long long *timeout); + + +/** + * Run webserver operations (without blocking unless + * in client callbacks). This method should be called + * by clients in combination with MHD_get_fdset + * if the client-controlled select method is used. + * + * @param daemon daemon to run + * @return MHD_YES on success, MHD_NO if this + * daemon was not started with the right + * options for this call. + */ +int MHD_run (struct MHD_Daemon *daemon); + + +/* **************** Connection handling functions ***************** */ + +/** + * Get all of the headers from the request. + * + * @param connection connection to get values from + * @param kind types of values to iterate over + * @param iterator callback to call on each header; + * maybe NULL (then just count headers) + * @param iterator_cls extra argument to iterator + * @return number of entries iterated over + */ +int +MHD_get_connection_values (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + MHD_KeyValueIterator iterator, void *iterator_cls); + +/** + * This function can be used to add an entry to + * the HTTP headers of a connection (so that the + * MHD_get_connection_values function will return + * them -- and the MHD PostProcessor will also + * see them). This maybe required in certain + * situations (see Mantis #1399) where (broken) + * HTTP implementations fail to supply values needed + * by the post processor (or other parts of the + * application). + * <p> + * This function MUST only be called from within + * the MHD_AccessHandlerCallback (otherwise, access + * maybe improperly synchronized). Furthermore, + * the client must guarantee that the key and + * value arguments are 0-terminated strings that + * are NOT freed until the connection is closed. + * (The easiest way to do this is by passing only + * arguments to permanently allocated strings.). + * + * @param connection the connection for which a + * value should be set + * @param kind kind of the value + * @param key key for the value + * @param value the value itself + * @return MHD_NO if the operation could not be + * performed due to insufficient memory; + * MHD_YES on success + */ +int +MHD_set_connection_value (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + const char *key, const char *value); + +/** + * Sets the global error handler to a different implementation. "cb" + * will only be called in the case of typically fatal, serious + * internal consistency issues. These issues should only arise in the + * case of serious memory corruption or similar problems with the + * architecture. While "cb" is allowed to return and MHD will then + * try to continue, this is never safe. + * + * The default implementation that is used if no panic function is set + * simply calls "abort". Alternative implementations might call + * "exit" or other similar functions. + * + * @param cb new error handler + * @param cls passed to error handler + */ +void MHD_set_panic_func (MHD_PanicCallback cb, void *cls); + +/** + * Get a particular header value. If multiple + * values match the kind, return any one of them. + * + * @param connection connection to get values from + * @param kind what kind of value are we looking for + * @param key the header to look for + * @return NULL if no such item was found + */ +const char *MHD_lookup_connection_value (struct MHD_Connection *connection, + enum MHD_ValueKind kind, + const char *key); + +/** + * Queue a response to be transmitted to the client (as soon as + * possible but after MHD_AccessHandlerCallback returns). + * + * @param connection the connection identifying the client + * @param status_code HTTP status code (i.e. 200 for OK) + * @param response response to transmit + * @return MHD_NO on error (i.e. reply already sent), + * MHD_YES on success or if message has been queued + */ +int +MHD_queue_response (struct MHD_Connection *connection, + unsigned int status_code, struct MHD_Response *response); + + +/* **************** Response manipulation functions ***************** */ + +/** + * Create a response object. The response object can be extended with + * header information and then be used any number of times. + * + * @param size size of the data portion of the response, MHD_SIZE_UNKNOW for unknown + * @param block_size preferred block size for querying crc (advisory only, + * MHD may still call crc using smaller chunks); this + * is essentially the buffer size used for IO, clients + * should pick a value that is appropriate for IO and + * memory performance requirements + * @param crc callback to use to obtain response data + * @param crc_cls extra argument to crc + * @param crfc callback to call to free crc_cls resources + * @return NULL on error (i.e. invalid arguments, out of memory) + */ +struct MHD_Response *MHD_create_response_from_callback (uint64_t size, + size_t block_size, + MHD_ContentReaderCallback + crc, void *crc_cls, + MHD_ContentReaderFreeCallback + crfc); + +/** + * Create a response object. The response object can be extended with + * header information and then be used any number of times. + * + * @param size size of the data portion of the response + * @param data the data itself + * @param must_free libmicrohttpd should free data when done + * @param must_copy libmicrohttpd must make a copy of data + * right away, the data maybe released anytime after + * this call returns + * @return NULL on error (i.e. invalid arguments, out of memory) + */ +struct MHD_Response *MHD_create_response_from_data (size_t size, + void *data, + int must_free, + int must_copy); + +/** + * Destroy a response object and associated resources. Note that + * libmicrohttpd may keep some of the resources around if the response + * is still in the queue for some clients, so the memory may not + * necessarily be freed immediatley. + * + * @param response response to destroy + */ +void MHD_destroy_response (struct MHD_Response *response); + +/** + * Add a header line to the response. + * + * @param response response to add a header to + * @param header the header to add + * @param content value to add + * @return MHD_NO on error (i.e. invalid header or content format), + * or out of memory + */ +int +MHD_add_response_header (struct MHD_Response *response, + const char *header, const char *content); + +/** + * Delete a header line from the response. + * + * @param response response to remove a header from + * @param header the header to delete + * @param content value to delete + * @return MHD_NO on error (no such header known) + */ +int +MHD_del_response_header (struct MHD_Response *response, + const char *header, const char *content); + +/** + * Get all of the headers added to a response. + * + * @param response response to query + * @param iterator callback to call on each header; + * maybe NULL (then just count headers) + * @param iterator_cls extra argument to iterator + * @return number of entries iterated over + */ +int +MHD_get_response_headers (struct MHD_Response *response, + MHD_KeyValueIterator iterator, void *iterator_cls); + + +/** + * Get a particular header from the response. + * + * @param response response to query + * @param key which header to get + * @return NULL if header does not exist + */ +const char *MHD_get_response_header (struct MHD_Response *response, + const char *key); + + +/* ********************** PostProcessor functions ********************** */ + +/** + * Create a PostProcessor. + * + * A PostProcessor can be used to (incrementally) parse the data + * portion of a POST request. Note that some buggy browsers fail to + * set the encoding type. If you want to support those, you may have + * to call 'MHD_set_connection_value' with the proper encoding type + * before creating a post processor (if no supported encoding type is + * set, this function will fail). + * + * @param connection the connection on which the POST is + * happening (used to determine the POST format) + * @param buffer_size maximum number of bytes to use for + * internal buffering (used only for the parsing, + * specifically the parsing of the keys). A + * tiny value (256-1024) should be sufficient. + * Do NOT use a value smaller than 256. + * @param iter iterator to be called with the parsed data, + * Must NOT be NULL. + * @param cls first argument to ikvi + * @return NULL on error (out of memory, unsupported encoding), + otherwise a PP handle + */ +struct MHD_PostProcessor *MHD_create_post_processor (struct MHD_Connection + *connection, + size_t buffer_size, + MHD_PostDataIterator + iter, void *cls); + +/** + * Parse and process POST data. + * Call this function when POST data is available + * (usually during an MHD_AccessHandlerCallback) + * with the upload_data and upload_data_size. + * Whenever possible, this will then cause calls + * to the MHD_IncrementalKeyValueIterator. + * + * @param pp the post processor + * @param post_data post_data_len bytes of POST data + * @param post_data_len length of post_data + * @return MHD_YES on success, MHD_NO on error + * (out-of-memory, iterator aborted, parse error) + */ +int +MHD_post_process (struct MHD_PostProcessor *pp, + const char *post_data, size_t post_data_len); + +/** + * Release PostProcessor resources. + * + * @param pp the PostProcessor to destroy + * @return MHD_YES if processing completed nicely, + * MHD_NO if there were spurious characters / formatting + * problems; it is common to ignore the return + * value of this function + */ +int MHD_destroy_post_processor (struct MHD_PostProcessor *pp); + + + +/* ********************** generic query functions ********************** */ + + +/** + * Information about a connection. + */ +union MHD_ConnectionInfo +{ + enum MHD_GNUTLS_CipherAlgorithm cipher_algorithm; + enum MHD_GNUTLS_Protocol protocol; + /** + * Address information for the client. + */ + struct sockaddr_in * client_addr; +}; + +/** + * Obtain information about the given connection. + * + * @param connection what connection to get information about + * @param infoType what information is desired? + * @param ... depends on infoType + * @return NULL if this information is not available + * (or if the infoType is unknown) + */ +const union MHD_ConnectionInfo *MHD_get_connection_info (struct MHD_Connection + *connection, + enum + MHD_ConnectionInfoType + infoType, ...); + + +/** + * Information about an MHD daemon. + */ +union MHD_DaemonInfo +{ + /** + * Size of the key (unit??) + */ + size_t key_size; + + /** + * Size of the mac key (unit??) + */ + size_t mac_key_size; + + /** + * Listen socket file descriptor + */ + int listen_fd; +}; + +/** + * Obtain information about the given daemon + * (not fully implemented!). + * + * @param daemon what daemon to get information about + * @param infoType what information is desired? + * @param ... depends on infoType + * @return NULL if this information is not available + * (or if the infoType is unknown) + */ +const union MHD_DaemonInfo *MHD_get_daemon_info (struct MHD_Daemon *daemon, + enum MHD_DaemonInfoType + infoType, ...); + +/** + * Obtain the version of this library + * + * @return static version string, e.g. "0.4.1" + */ +const char* MHD_get_version(void); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libmicrohttpd/src/include/platform.h b/lib/libmicrohttpd/src/include/platform.h new file mode 100644 index 0000000000..431ae48017 --- /dev/null +++ b/lib/libmicrohttpd/src/include/platform.h @@ -0,0 +1,115 @@ +/* + This file is part of libmicrohttpd + (C) 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** + * @file platform.h + * @brief platform-specific includes for libmicrohttpd + * @author Christian Grothoff + * + * This file is included by the libmicrohttpd code + * before "microhttpd.h"; it provides the required + * standard headers (which are platform-specific).<p> + * + * Note that this file depends on our configure.ac + * build process and the generated config.h file. + * Hence you cannot include it directly in applications + * that use libmicrohttpd. + */ +#ifndef PLATFORM_H +#define PLATFORM_H + +#include "MHD_config.h" + +#define _XOPEN_SOURCE_EXTENDED 1 +#if OS390 +#define _OPEN_THREADS +#define _OPEN_SYS_SOCK_IPV6 +#define _OPEN_MSGQ_EXT +#define _LP64 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#if !defined(MINGW) && !defined(__SYMBIAN32__) +#include <search.h> +#endif +#include <stddef.h> +#undef HAVE_CONFIG_H +#include <pthread.h> +#define HAVE_CONFIG_H 1 + +/* different OSes have fd_set in + a broad range of header files; + we just include most of them (if they + are available) */ + + +#ifdef OS_VXWORKS +#include <sockLib.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <sys/mman.h> +#define RESTRICT __restrict__ +#endif + +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_SYS_MSG_H +#include <sys/msg.h> +#endif +#if HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#if HAVE_NETDB_H +#include <netdb.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_TIME_H +#include <time.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#include "plibc.h" + + +#endif diff --git a/lib/libmicrohttpd/src/include/plibc.h b/lib/libmicrohttpd/src/include/plibc.h new file mode 100644 index 0000000000..a1d3b13161 --- /dev/null +++ b/lib/libmicrohttpd/src/include/plibc.h @@ -0,0 +1,809 @@ +/* + This file is part of PlibC. + (C) 2005, 2006, 2007, 2008, 2009 Nils Durner (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** + * @file include/plibc.h + * @brief PlibC header + * @attention This file is usually not installed under Unix, + * so ship it with your application + * @version $Revision: 39 $ + */ + +#ifndef _PLIBC_H_ +#define _PLIBC_H_ + +#ifndef SIGALRM +#define SIGALRM 14 +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stddef.h> + +#ifdef Q_OS_WIN32 +#define WINDOWS 1 +#endif + +#define HAVE_PLIBC_FD 0 + +#ifdef WINDOWS + +#if ENABLE_NLS +#include "langinfo.h" +#endif + +#include <windows.h> +#include <Ws2tcpip.h> +#include <time.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <errno.h> +#include <stdarg.h> + +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN + +/* Conflicts with our definitions */ +#define __G_WIN32_H__ + +/* Convert LARGE_INTEGER to double */ +#define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + \ + (double)((x).LowPart)) + +#define socklen_t int +#define ssize_t int +#define off_t int +#define int64_t long long +#define int32_t long + + struct stat64 + { + _dev_t st_dev; + _ino_t st_ino; + _mode_t st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + __int64 st_size; + __time64_t st_atime; + __time64_t st_mtime; + __time64_t st_ctime; + }; + +#ifndef pid_t +#define pid_t int +#endif + +#ifndef WEXITSTATUS +#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +/* Thanks to the Cygwin project */ +#define ENOCSI 43 /* No CSI structure available */ +#define EL2HLT 44 /* Level 2 halted */ +#ifndef EDEADLK +#define EDEADLK 45 /* Deadlock condition */ +#endif +#ifndef ENOLCK +#define ENOLCK 46 /* No record locks available */ +#endif +#define EBADE 50 /* Invalid exchange */ +#define EBADR 51 /* Invalid request descriptor */ +#define EXFULL 52 /* Exchange full */ +#define ENOANO 53 /* No anode */ +#define EBADRQC 54 /* Invalid request code */ +#define EBADSLT 55 /* Invalid slot */ +#ifndef EDEADLOCK +#define EDEADLOCK EDEADLK /* File locking deadlock error */ +#endif +#define EBFONT 57 /* Bad font file fmt */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* The object is remote */ +#define ENOLINK 67 /* The link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#define ELBIN 75 /* Inode is remote (not really error) */ +#define EDOTDOT 76 /* Cross mount point (not really error) */ +#define EBADMSG 77 /* Trying to read unreadable message */ +#define ENOTUNIQ 80 /* Given log. name not unique */ +#define EBADFD 81 /* f.d. invalid for this operation */ +#define EREMCHG 82 /* Remote address changed */ +#define ELIBACC 83 /* Can't access a needed shared lib */ +#define ELIBBAD 84 /* Accessing a corrupted shared lib */ +#define ELIBSCN 85 /* .lib section in a.out corrupted */ +#define ELIBMAX 86 /* Attempting to link in too many libs */ +#define ELIBEXEC 87 /* Attempting to exec a shared library */ +#ifndef ENOSYS +#define ENOSYS 88 /* Function not implemented */ +#endif +#define ENMFILE 89 /* No more files */ +#ifndef ENOTEMPTY +#define ENOTEMPTY 90 /* Directory not empty */ +#endif +#ifndef ENAMETOOLONG +#define ENAMETOOLONG 91 /* File or path name too long */ +#endif +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#define ESHUTDOWN 110 /* Can't send after socket shutdown */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Connection aborted */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#ifndef ETIMEDOUT +#define ETIMEDOUT 116 /* Connection timed out */ +#endif +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 /* Connection aborted by network */ +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 /* Too many references: cannot splice */ +#define EPROCLIM 130 /* Too many processes */ +#define EUSERS 131 /* Too many users */ +#define EDQUOT 132 /* Disk quota exceeded */ +#define ESTALE 133 /* Unknown error */ +#ifndef ENOTSUP +#define ENOTSUP 134 /* Not supported */ +#endif +#define ENOMEDIUM 135 /* No medium (in tape drive) */ +#define ENOSHARE 136 /* No such host or network path */ +#define ECASECLASH 137 /* Filename exists with different case */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EOVERFLOW 139 /* Value too large for defined data type */ + +#undef HOST_NOT_FOUND +#define HOST_NOT_FOUND 1 +#undef TRY_AGAIN +#define TRY_AGAIN 2 +#undef NO_RECOVERY +#define NO_RECOVERY 3 +#undef NO_ADDRESS +#define NO_ADDRESS 4 + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define MAP_SHARED 0x1 +#define MAP_PRIVATE 0x2 /* unsupported */ +#define MAP_FIXED 0x10 +#define MAP_FAILED ((void *)-1) + + struct statfs + { + long f_type; /* type of filesystem (see below) */ + long f_bsize; /* optimal transfer block size */ + long f_blocks; /* total data blocks in file system */ + long f_bfree; /* free blocks in fs */ + long f_bavail; /* free blocks avail to non-superuser */ + long f_files; /* total file nodes in file system */ + long f_ffree; /* free file nodes in fs */ + long f_fsid; /* file system id */ + long f_namelen; /* maximum length of filenames */ + long f_spare[6]; /* spare for later */ + }; + + extern const struct in6_addr in6addr_any; /* :: */ + extern const struct in6_addr in6addr_loopback; /* ::1 */ + +/* Taken from the Wine project <http://www.winehq.org> + /wine/include/winternl.h */ + enum SYSTEM_INFORMATION_CLASS + { + SystemBasicInformation = 0, + Unknown1, + SystemPerformanceInformation = 2, + SystemTimeOfDayInformation = 3, /* was SystemTimeInformation */ + Unknown4, + SystemProcessInformation = 5, + Unknown6, + Unknown7, + SystemProcessorPerformanceInformation = 8, + Unknown9, + Unknown10, + SystemDriverInformation, + Unknown12, + Unknown13, + Unknown14, + Unknown15, + SystemHandleList, + Unknown17, + Unknown18, + Unknown19, + Unknown20, + SystemCacheInformation, + Unknown22, + SystemInterruptInformation = 23, + SystemExceptionInformation = 33, + SystemRegistryQuotaInformation = 37, + SystemLookasideInformation = 45 + }; + + typedef struct + { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER Reserved1[2]; + ULONG Reserved2; + } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +#define sleep(secs) (Sleep(secs * 1000)) + +/*********************** statfs *****************************/ +/* fake block size */ +#define FAKED_BLOCK_SIZE 512 + +/* linux-compatible values for fs type */ +#define MSDOS_SUPER_MAGIC 0x4d44 +#define NTFS_SUPER_MAGIC 0x5346544E + +/*********************** End of statfs ***********************/ + +#define SHUT_RDWR SD_BOTH + +/* Operations for flock() */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +/* Not supported under MinGW */ +#define S_IRGRP 0 +#define S_IWGRP 0 +#define S_IROTH 0 +#define S_IXGRP 0 +#define S_IWOTH 0 +#define S_IXOTH 0 +#define S_ISUID 0 +#define S_ISGID 0 +#define S_ISVTX 0 +#define S_IRWXG 0 +#define S_IRWXO 0 + +#define SHUT_WR SD_SEND +#define SHUT_RD SD_RECEIVE +#define SHUT_RDWR SD_BOTH + +#define SIGKILL 9 +#define SIGTERM 15 + +#define SetErrnoFromWinError(e) _SetErrnoFromWinError(e, __FILE__, __LINE__) + + BOOL _plibc_CreateShortcut (const char *pszSrc, const char *pszDest); + BOOL _plibc_DereferenceShortcut (char *pszShortcut); + char *plibc_ChooseDir (char *pszTitle, unsigned long ulFlags); + char *plibc_ChooseFile (char *pszTitle, unsigned long ulFlags); + long QueryRegistry (HKEY hMainKey, char *pszKey, char *pszSubKey, + char *pszBuffer, long *pdLength); + + BOOL __win_IsHandleMarkedAsBlocking (SOCKET hHandle); + void __win_SetHandleBlockingMode (SOCKET s, BOOL bBlocking); + void __win_DiscardHandleBlockingMode (SOCKET s); + int _win_isSocketValid (int s); + int plibc_conv_to_win_path (const char *pszUnix, char *pszWindows); + unsigned plibc_get_handle_count (); + + typedef void (*TPanicProc) (int, char *); + void plibc_set_panic_proc (TPanicProc proc); + + int flock (int fd, int operation); + int fsync (int fildes); + int inet_pton (int af, const char *src, void *dst); + int inet_pton4 (const char *src, u_char * dst, int pton); +#if USE_IPV6 + int inet_pton6 (const char *src, u_char * dst); +#endif + int truncate (const char *fname, int distance); + int statfs (const char *path, struct statfs *buf); + const char *hstrerror (int err); + int mkstemp (char *tmplate); + char *strptime (const char *buf, const char *format, struct tm *tm); + const char *inet_ntop (int af, const void *src, char *dst, size_t size); + + int plibc_init (char *pszOrg, char *pszApp); + void plibc_shutdown (); + int plibc_initialized (); + int plibc_conv_to_win_path_ex (const char *pszUnix, char *pszWindows, + int derefLinks); + void _SetErrnoFromWinError (long lWinError, char *pszCaller, int iLine); + void SetErrnoFromWinsockError (long lWinError); + void SetHErrnoFromWinError (long lWinError); + void SetErrnoFromHRESULT (HRESULT hRes); + int GetErrnoFromWinsockError (long lWinError); + FILE *_win_fopen (const char *filename, const char *mode); + DIR *_win_opendir (const char *dirname); + int _win_open (const char *filename, int oflag, ...); +#ifdef ENABLE_NLS + char *_win_bindtextdomain (const char *domainname, const char *dirname); +#endif + int _win_chdir (const char *path); + int _win_close (int fd); + int _win_creat (const char *path, mode_t mode); + char *_win_ctime (const time_t * clock); + char *_win_ctime_r (const time_t * clock, char *buf); + int _win_fstat (int handle, struct stat *buffer); + int _win_ftruncate (int fildes, off_t length); + void _win_gettimeofday (struct timeval *tp, void *tzp); + int _win_kill (pid_t pid, int sig); + int _win_pipe (int *phandles); + int _win_rmdir (const char *path); + int _win_access (const char *path, int mode); + int _win_chmod (const char *filename, int pmode); + char *realpath (const char *file_name, char *resolved_name); + long _win_random (void); + int _win_remove (const char *path); + int _win_rename (const char *oldname, const char *newname); + int _win_stat (const char *path, struct stat *buffer); + int _win_stat64 (const char *path, struct stat64 *buffer); + int _win_unlink (const char *filename); + int _win_write (int fildes, const void *buf, size_t nbyte); + int _win_read (int fildes, void *buf, size_t nbyte); + size_t _win_fwrite (const void *buffer, size_t size, size_t count, + FILE * stream); + size_t _win_fread (void *buffer, size_t size, size_t count, FILE * stream); + int _win_symlink (const char *path1, const char *path2); + void *_win_mmap (void *start, size_t len, int access, int flags, int fd, + unsigned long long offset); + int _win_munmap (void *start, size_t length); + int _win_lstat (const char *path, struct stat *buf); + int _win_lstat64 (const char *path, struct stat64 *buf); + int _win_readlink (const char *path, char *buf, size_t bufsize); + int _win_accept (SOCKET s, struct sockaddr *addr, int *addrlen); + int _win_printf (const char *format, ...); + int _win_fprintf (FILE * f, const char *format, ...); + int _win_vprintf (const char *format, va_list ap); + int _win_vfprintf (FILE * stream, const char *format, va_list arg_ptr); + int _win_vsprintf (char *dest, const char *format, va_list arg_ptr); + int _win_vsnprintf (char *str, size_t size, const char *format, + va_list arg_ptr); + int _win_snprintf (char *str, size_t size, const char *format, ...); + int _win_sprintf (char *dest, const char *format, ...); + int _win_vsscanf (const char *str, const char *format, va_list arg_ptr); + int _win_sscanf (const char *str, const char *format, ...); + int _win_vfscanf (FILE * stream, const char *format, va_list arg_ptr); + int _win_vscanf (const char *format, va_list arg_ptr); + int _win_scanf (const char *format, ...); + int _win_fscanf (FILE * stream, const char *format, ...); + pid_t _win_waitpid (pid_t pid, int *stat_loc, int options); + int _win_bind (SOCKET s, const struct sockaddr *name, int namelen); + int _win_connect (SOCKET s, const struct sockaddr *name, int namelen); + int _win_getpeername (SOCKET s, struct sockaddr *name, int *namelen); + int _win_getsockname (SOCKET s, struct sockaddr *name, int *namelen); + int _win_getsockopt (SOCKET s, int level, int optname, char *optval, + int *optlen); + int _win_listen (SOCKET s, int backlog); + int _win_recv (SOCKET s, char *buf, int len, int flags); + int _win_recvfrom (SOCKET s, void *buf, int len, int flags, + struct sockaddr *from, int *fromlen); + int _win_select (int max_fd, fd_set * rfds, fd_set * wfds, fd_set * efds, + const struct timeval *tv); + int _win_send (SOCKET s, const char *buf, int len, int flags); + int _win_sendto (SOCKET s, const char *buf, int len, int flags, + const struct sockaddr *to, int tolen); + int _win_setsockopt (SOCKET s, int level, int optname, const void *optval, + int optlen); + int _win_shutdown (SOCKET s, int how); + SOCKET _win_socket (int af, int type, int protocol); + struct hostent *_win_gethostbyaddr (const char *addr, int len, int type); + struct hostent *_win_gethostbyname (const char *name); + struct hostent *gethostbyname2 (const char *name, int af); + char *_win_strerror (int errnum); + int IsWinNT (); + char *index (const char *s, int c); + +#if !HAVE_STRNDUP + char *strndup (const char *s, size_t n); +#endif +#if !HAVE_STRNLEN + size_t strnlen (const char *str, size_t maxlen); +#endif + +#define strcasecmp(a, b) stricmp(a, b) +#define strncasecmp(a, b, c) strnicmp(a, b, c) + +#endif /* WINDOWS */ + +#ifndef WINDOWS +#define DIR_SEPARATOR '/' +#define DIR_SEPARATOR_STR "/" +#define PATH_SEPARATOR ';' +#define PATH_SEPARATOR_STR ";" +#define NEWLINE "\n" + +#ifdef ENABLE_NLS +#define BINDTEXTDOMAIN(d, n) bindtextdomain(d, n) +#endif +#define CREAT(p, m) creat(p, m) +#define PLIBC_CTIME(c) ctime(c) +#define CTIME_R(c, b) ctime_r(c, b) +#undef FOPEN +#define FOPEN(f, m) fopen(f, m) +#define FTRUNCATE(f, l) ftruncate(f, l) +#define OPENDIR(d) opendir(d) +#define OPEN open +#define CHDIR(d) chdir(d) +#define CLOSE(f) close(f) +#define LSEEK(f, o, w) lseek(f, o, w) +#define RMDIR(f) rmdir(f) +#define ACCESS(p, m) access(p, m) +#define CHMOD(f, p) chmod(f, p) +#define FSTAT(h, b) fstat(h, b) +#define PLIBC_KILL(p, s) kill(p, s) +#define PIPE(h) pipe(h) +#define REMOVE(p) remove(p) +#define RENAME(o, n) rename(o, n) +#define STAT(p, b) stat(p, b) +#define STAT64(p, b) stat64(p, b) +#define UNLINK(f) unlink(f) +#define WRITE(f, b, n) write(f, b, n) +#define READ(f, b, n) read(f, b, n) +#define GN_FREAD(b, s, c, f) fread(b, s, c, f) +#define GN_FWRITE(b, s, c, f) fwrite(b, s, c, f) +#define SYMLINK(a, b) symlink(a, b) +#define MMAP(s, l, p, f, d, o) mmap(s, l, p, f, d, o) +#define MUNMAP(s, l) munmap(s, l) +#define STRERROR(i) strerror(i) +#define RANDOM() random() +#define READLINK(p, b, s) readlink(p, b, s) +#define LSTAT(p, b) lstat(p, b) +#define LSTAT64(p, b) lstat64(p, b) +#define PRINTF printf +#define FPRINTF fprintf +#define VPRINTF(f, a) vprintf(f, a) +#define VFPRINTF(s, f, a) vfprintf(s, f, a) +#define VSPRINTF(d, f, a) vsprintf(d, f, a) +#define VSNPRINTF(str, size, fmt, a) vsnprintf(str, size, fmt, a) +#define _REAL_SNPRINTF snprintf +#define SPRINTF sprintf +#define VSSCANF(s, f, a) vsscanf(s, f, a) +#define SSCANF sscanf +#define VFSCANF(s, f, a) vfscanf(s, f, a) +#define VSCANF(f, a) vscanf(f, a) +#define SCANF scanf +#define FSCANF fscanf +#define WAITPID(p, s, o) waitpid(p, s, o) +#define ACCEPT(s, a, l) accept(s, a, l) +#define BIND(s, n, l) bind(s, n, l) +#define CONNECT(s, n, l) connect(s, n, l) +#define GETPEERNAME(s, n, l) getpeername(s, n, l) +#define GETSOCKNAME(s, n, l) getsockname(s, n, l) +#define GETSOCKOPT(s, l, o, v, p) getsockopt(s, l, o, v, p) +#define LISTEN(s, b) listen(s, b) +#define RECV(s, b, l, f) recv(s, b, l, f) +#define RECVFROM(s, b, l, f, r, o) recvfrom(s, b, l, f, r, o) +#define SELECT(n, r, w, e, t) select(n, r, w, e, t) +#define SEND(s, b, l, f) send(s, b, l, f) +#define SENDTO(s, b, l, f, o, n) sendto(s, b, l, f, o, n) +#define SETSOCKOPT(s, l, o, v, n) setsockopt(s, l, o, v, n) +#define SHUTDOWN(s, h) shutdown(s, h) +#define SOCKET(a, t, p) socket(a, t, p) +#define GETHOSTBYADDR(a, l, t) gethostbyname(a, l, t) +#define GETHOSTBYNAME(n) gethostbyname(n) +#define GETTIMEOFDAY(t, n) gettimeofday(t, n) +#define INSQUE(e, p) insque(e, p) +#define REMQUE(e) remque(e) + +#ifndef __SYMBIAN32__ +#define HSEARCH(i, a) hsearch(i, a) +#define HCREATE(n) hcreate(n) +#define HDESTROY() hdestroy() +#define HSEARCH_R(i, a, r, h) hsearch_r(i, a, r, h) +#define HCREATE_R(n, h) hcreate_r(n, h) +#define HDESTROY_R(h) hdestroy_r(h) +#define TSEARCH(k, r, c) tsearch(k, r, c) +#define TFIND(k, r, c) tfind(k, r, c) +#define TDELETE(k, r, c) tdelete(k, r, c) +#define TWALK(r, a) twalk(r, a) +#define TDESTROY(r, f) tdestroy(r, f) +#define LFIND(k, b, n, s, c) lfind(k, b, n, s, c) +#define LSEARCH(k, b, n, s, c) lsearch(k, b, n, s, c) +#else // __SYMBIAN32__ +#define HSEARCH(i, a) _win_hsearch(i, a) +#define HCREATE(n) _win_hcreate(n) +#define HDESTROY() _win_hdestroy() +#define HSEARCH_R(i, a, r, h) _win_hsearch_r(i, a, r, h) +#define HCREATE_R(n, h) _win_hcreate_r(n, h) +#define HDESTROY_R(h) _win_hdestroy_r(h) +#define TSEARCH(k, r, c) _win_tsearch(k, r, c) +#define TFIND(k, r, c) _win_tfind(k, r, c) +#define TDELETE(k, r, c) _win_tdelete(k, r, c) +#define TWALK(r, a) _win_twalk(r, a) +#define TDESTROY(r, f) _win_tdestroy(r, f) +#define LFIND(k, b, n, s, c) _win_lfind(k, b, n, s, c) +#define LSEARCH(k, b, n, s, c) _win_lsearch(k, b, n, s, c) +#endif // !__SYMBIAN32__ + +#else +#define DIR_SEPARATOR '\\' +#define DIR_SEPARATOR_STR "\\" +#define PATH_SEPARATOR ':' +#define PATH_SEPARATOR_STR ":" +#define NEWLINE "\r\n" + +#ifdef ENABLE_NLS +#define BINDTEXTDOMAIN(d, n) _win_bindtextdomain(d, n) +#endif +#define CREAT(p, m) _win_creat(p, m) +#define PLIBC_CTIME(c) _win_ctime(c) +#define CTIME_R(c, b) _win_ctime_r(c, b) +#define FOPEN(f, m) _win_fopen(f, m) +#define FTRUNCATE(f, l) _win_ftruncate(f, l) +#define OPENDIR(d) _win_opendir(d) +#define OPEN _win_open +#define CHDIR(d) _win_chdir(d) +#define CLOSE(f) _win_close(f) +#define PLIBC_KILL(p, s) _win_kill(p, s) +#define LSEEK(f, o, w) _win_lseek(f, o, w) +#define FSTAT(h, b) _win_fstat(h, b) +#define RMDIR(f) _win_rmdir(f) +#define ACCESS(p, m) _win_access(p, m) +#define CHMOD(f, p) _win_chmod(f, p) +#define PIPE(h) _win_pipe(h) +#define RANDOM() _win_random() +#define REMOVE(p) _win_remove(p) +#define RENAME(o, n) _win_rename(o, n) +#define STAT(p, b) _win_stat(p, b) +#define STAT64(p, b) _win_stat64(p, b) +#define UNLINK(f) _win_unlink(f) +#define WRITE(f, b, n) _win_write(f, b, n) +#define READ(f, b, n) _win_read(f, b, n) +#define GN_FREAD(b, s, c, f) _win_fread(b, s, c, f) +#define GN_FWRITE(b, s, c, f) _win_fwrite(b, s, c, f) +#define SYMLINK(a, b) _win_symlink(a, b) +#define MMAP(s, l, p, f, d, o) _win_mmap(s, l, p, f, d, o) +#define MUNMAP(s, l) _win_munmap(s, l) +#define STRERROR(i) _win_strerror(i) +#define READLINK(p, b, s) _win_readlink(p, b, s) +#define LSTAT(p, b) _win_lstat(p, b) +#define LSTAT64(p, b) _win_lstat64(p, b) +#define PRINTF(f, ...) _win_printf(f , __VA_ARGS__) +#define FPRINTF(fil, fmt, ...) _win_fprintf(fil, fmt, __VA_ARGS__) +#define VPRINTF(f, a) _win_vprintf(f, a) +#define VFPRINTF(s, f, a) _win_vfprintf(s, f, a) +#define VSPRINTF(d, f, a) _win_vsprintf(d, f, a) +#define VSNPRINTF(str, size, fmt, a) _win_vsnprintf(str, size, fmt, a) +#define _REAL_SNPRINTF(str, size, fmt, ...) _win_snprintf(str, size, fmt, __VA_ARGS__) +#define SPRINTF(d, f, ...) _win_sprintf(d, f, __VA_ARGS__) +#define VSSCANF(s, f, a) _win_vsscanf(s, f, a) +#define SSCANF(s, f, ...) _win_sscanf(s, f, __VA_ARGS__) +#define VFSCANF(s, f, a) _win_vfscanf(s, f, a) +#define VSCANF(f, a) _win_vscanf(f, a) +#define SCANF(f, ...) _win_scanf(f, __VA_ARGS__) +#define FSCANF(s, f, ...) _win_fscanf(s, f, __VA_ARGS__) +#define WAITPID(p, s, o) _win_waitpid(p, s, o) +#define ACCEPT(s, a, l) _win_accept(s, a, l) +#define BIND(s, n, l) _win_bind(s, n, l) +#define CONNECT(s, n, l) _win_connect(s, n, l) +#define GETPEERNAME(s, n, l) _win_getpeername(s, n, l) +#define GETSOCKNAME(s, n, l) _win_getsockname(s, n, l) +#define GETSOCKOPT(s, l, o, v, p) _win_getsockopt(s, l, o, v, p) +#define LISTEN(s, b) _win_listen(s, b) +#define RECV(s, b, l, f) _win_recv(s, b, l, f) +#define RECVFROM(s, b, l, f, r, o) _win_recvfrom(s, b, l, f, r, o) +#define SELECT(n, r, w, e, t) _win_select(n, r, w, e, t) +#define SEND(s, b, l, f) _win_send(s, b, l, f) +#define SENDTO(s, b, l, f, o, n) _win_sendto(s, b, l, f, o, n) +#define SETSOCKOPT(s, l, o, v, n) _win_setsockopt(s, l, o, v, n) +#define SHUTDOWN(s, h) _win_shutdown(s, h) +#define SOCKET(a, t, p) _win_socket(a, t, p) +#define GETHOSTBYADDR(a, l, t) _win_gethostbyname(a, l, t) +#define GETHOSTBYNAME(n) _win_gethostbyname(n) +#define GETTIMEOFDAY(t, n) _win_gettimeofday(t, n) +#define INSQUE(e, p) _win_insque(e, p) +#define REMQUE(e) _win_remque(e) +#define HSEARCH(i, a) _win_hsearch(i, a) +#define HCREATE(n) _win_hcreate(n) +#define HDESTROY() _win_hdestroy() +#define HSEARCH_R(i, a, r, h) _win_hsearch_r(i, a, r, h) +#define HCREATE_R(n, h) _win_hcreate_r(n, h) +#define HDESTROY_R(h) _win_hdestroy_r(h) +#define TSEARCH(k, r, c) _win_tsearch(k, r, c) +#define TFIND(k, r, c) _win_tfind(k, r, c) +#define TDELETE(k, r, c) _win_tdelete(k, r, c) +#define TWALK(r, a) _win_twalk(r, a) +#define TDESTROY(r, f) _win_tdestroy(r, f) +#define LFIND(k, b, n, s, c) _win_lfind(k, b, n, s, c) +#define LSEARCH(k, b, n, s, c) _win_lsearch(k, b, n, s, c) +#endif + +/* search.h */ + +/* Prototype structure for a linked-list data structure. + This is the type used by the `insque' and `remque' functions. */ + + struct PLIBC_SEARCH_QELEM + { + struct qelem *q_forw; + struct qelem *q_back; + char q_data[1]; + }; + + +/* Insert ELEM into a doubly-linked list, after PREV. */ + void _win_insque (void *__elem, void *__prev); + +/* Unlink ELEM from the doubly-linked list that it is in. */ + void _win_remque (void *__elem); + + +/* For use with hsearch(3). */ + typedef int (*PLIBC_SEARCH__compar_fn_t) (__const void *, __const void *); + + typedef PLIBC_SEARCH__compar_fn_t _win_comparison_fn_t; + +/* Action which shall be performed in the call the hsearch. */ + typedef enum + { + PLIBC_SEARCH_FIND, + PLIBC_SEARCH_ENTER + } + PLIBC_SEARCH_ACTION; + + typedef struct PLIBC_SEARCH_entry + { + char *key; + void *data; + } + PLIBC_SEARCH_ENTRY; + +/* The reentrant version has no static variables to maintain the state. + Instead the interface of all functions is extended to take an argument + which describes the current status. */ + typedef struct _PLIBC_SEARCH_ENTRY + { + unsigned int used; + PLIBC_SEARCH_ENTRY entry; + } + _PLIBC_SEARCH_ENTRY; + + +/* Family of hash table handling functions. The functions also + have reentrant counterparts ending with _r. The non-reentrant + functions all work on a signle internal hashing table. */ + +/* Search for entry matching ITEM.key in internal hash table. If + ACTION is `FIND' return found entry or signal error by returning + NULL. If ACTION is `ENTER' replace existing data (if any) with + ITEM.data. */ + PLIBC_SEARCH_ENTRY *_win_hsearch (PLIBC_SEARCH_ENTRY __item, + PLIBC_SEARCH_ACTION __action); + +/* Create a new hashing table which will at most contain NEL elements. */ + int _win_hcreate (size_t __nel); + +/* Destroy current internal hashing table. */ + void _win_hdestroy (void); + +/* Data type for reentrant functions. */ + struct PLIBC_SEARCH_hsearch_data + { + struct _PLIBC_SEARCH_ENTRY *table; + unsigned int size; + unsigned int filled; + }; + +/* Reentrant versions which can handle multiple hashing tables at the + same time. */ + int _win_hsearch_r (PLIBC_SEARCH_ENTRY __item, PLIBC_SEARCH_ACTION __action, + PLIBC_SEARCH_ENTRY ** __retval, + struct PLIBC_SEARCH_hsearch_data *__htab); + int _win_hcreate_r (size_t __nel, struct PLIBC_SEARCH_hsearch_data *__htab); + void _win_hdestroy_r (struct PLIBC_SEARCH_hsearch_data *__htab); + + +/* The tsearch routines are very interesting. They make many + assumptions about the compiler. It assumes that the first field + in node must be the "key" field, which points to the datum. + Everything depends on that. */ +/* For tsearch */ + typedef enum + { + PLIBC_SEARCH_preorder, + PLIBC_SEARCH_postorder, + PLIBC_SEARCH_endorder, + PLIBC_SEARCH_leaf + } + PLIBC_SEARCH_VISIT; + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP and insert a new element if not found. */ + void *_win_tsearch (__const void *__key, void **__rootp, + PLIBC_SEARCH__compar_fn_t __compar); + +/* Search for an entry matching the given KEY in the tree pointed to + by *ROOTP. If no matching entry is available return NULL. */ + void *_win_tfind (__const void *__key, void *__const * __rootp, + PLIBC_SEARCH__compar_fn_t __compar); + +/* Remove the element matching KEY from the tree pointed to by *ROOTP. */ + void *_win_tdelete (__const void *__restrict __key, + void **__restrict __rootp, + PLIBC_SEARCH__compar_fn_t __compar); + + typedef void (*PLIBC_SEARCH__action_fn_t) (__const void *__nodep, + PLIBC_SEARCH_VISIT __value, + int __level); + +/* Walk through the whole tree and call the ACTION callback for every node + or leaf. */ + void _win_twalk (__const void *__root, PLIBC_SEARCH__action_fn_t __action); + +/* Callback type for function to free a tree node. If the keys are atomic + data this function should do nothing. */ + typedef void (*PLIBC_SEARCH__free_fn_t) (void *__nodep); + +/* Destroy the whole tree, call FREEFCT for each node or leaf. */ + void _win_tdestroy (void *__root, PLIBC_SEARCH__free_fn_t __freefct); + + +/* Perform linear search for KEY by comparing by COMPAR in an array + [BASE,BASE+NMEMB*SIZE). */ + void *_win_lfind (__const void *__key, __const void *__base, + size_t * __nmemb, size_t __size, + PLIBC_SEARCH__compar_fn_t __compar); + +/* Perform linear search for KEY by comparing by COMPAR function in + array [BASE,BASE+NMEMB*SIZE) and insert entry if not found. */ + void *_win_lsearch (__const void *__key, void *__base, + size_t * __nmemb, size_t __size, + PLIBC_SEARCH__compar_fn_t __compar); + + +#ifdef __cplusplus +} +#endif + + +#endif //_PLIBC_H_ + +/* end of plibc.h */ diff --git a/lib/libmicrohttpd/src/testcurl/Makefile.am b/lib/libmicrohttpd/src/testcurl/Makefile.am new file mode 100644 index 0000000000..a4ed58fb1b --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/Makefile.am @@ -0,0 +1,181 @@ +SUBDIRS = . + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +if ENABLE_HTTPS +if MHD_DEBUG_TLS + SUBDIRS += https +endif +endif + +AM_CPPFLAGS = \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/daemon \ +-I$(top_srcdir)/src/include \ +$(LIBCURL_CPPFLAGS) + +check_PROGRAMS = \ + daemontest_get \ + daemontest_post \ + daemontest_postform \ + daemontest_post_loop \ + daemontest_put \ + daemontest_process_headers \ + daemontest_process_arguments \ + daemontest_parse_cookies \ + daemontest_large_put \ + daemontest_get11 \ + daemontest_post11 \ + daemontest_postform11 \ + daemontest_post_loop11 \ + daemontest_put11 \ + daemontest_large_put11 \ + daemontest_long_header \ + daemontest_long_header11 \ + daemontest_get_chunked \ + daemontest_put_chunked \ + daemontest_iplimit11 \ + daemontest_termination +noinst_PROGRAMS = \ + daemon_options_test + +TESTS = $(check_PROGRAMS) + +noinst_LIBRARIES = libcurl_version_check.a + +libcurl_version_check_a_SOURCES = \ + curl_version_check.c + +daemon_options_test_SOURCES = \ + daemon_options_test.c +daemon_options_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +daemontest_get_SOURCES = \ + daemontest_get.c +daemontest_get_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get_chunked_SOURCES = \ + daemontest_get_chunked.c +daemontest_get_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_SOURCES = \ + daemontest_post.c +daemontest_post_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_process_headers_SOURCES = \ + daemontest_process_headers.c +daemontest_process_headers_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_parse_cookies_SOURCES = \ + daemontest_parse_cookies.c +daemontest_parse_cookies_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_process_arguments_SOURCES = \ + daemontest_process_arguments.c +daemontest_process_arguments_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform_SOURCES = \ + daemontest_postform.c +daemontest_postform_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_loop_SOURCES = \ + daemontest_post_loop.c +daemontest_post_loop_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_SOURCES = \ + daemontest_put.c +daemontest_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_chunked_SOURCES = \ + daemontest_put_chunked.c +daemontest_put_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get11_SOURCES = \ + daemontest_get.c +daemontest_get11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post11_SOURCES = \ + daemontest_post.c +daemontest_post11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform11_SOURCES = \ + daemontest_postform.c +daemontest_postform11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_loop11_SOURCES = \ + daemontest_post_loop.c +daemontest_post_loop11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put11_SOURCES = \ + daemontest_put.c +daemontest_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_large_put_SOURCES = \ + daemontest_large_put.c +daemontest_large_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_large_put11_SOURCES = \ + daemontest_large_put.c +daemontest_large_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_long_header_SOURCES = \ + daemontest_long_header.c +daemontest_long_header_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_long_header11_SOURCES = \ + daemontest_long_header.c +daemontest_long_header11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_iplimit11_SOURCES = \ + daemontest_iplimit.c +daemontest_iplimit11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_termination_SOURCES = \ + daemontest_termination.c +daemontest_termination_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + diff --git a/lib/libmicrohttpd/src/testcurl/Makefile.in b/lib/libmicrohttpd/src/testcurl/Makefile.in new file mode 100644 index 0000000000..7def1d4552 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/Makefile.in @@ -0,0 +1,1147 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@ENABLE_HTTPS_TRUE@@MHD_DEBUG_TLS_TRUE@am__append_1 = https +check_PROGRAMS = daemontest_get$(EXEEXT) daemontest_post$(EXEEXT) \ + daemontest_postform$(EXEEXT) daemontest_post_loop$(EXEEXT) \ + daemontest_put$(EXEEXT) daemontest_process_headers$(EXEEXT) \ + daemontest_process_arguments$(EXEEXT) \ + daemontest_parse_cookies$(EXEEXT) \ + daemontest_large_put$(EXEEXT) daemontest_get11$(EXEEXT) \ + daemontest_post11$(EXEEXT) daemontest_postform11$(EXEEXT) \ + daemontest_post_loop11$(EXEEXT) daemontest_put11$(EXEEXT) \ + daemontest_large_put11$(EXEEXT) \ + daemontest_long_header$(EXEEXT) \ + daemontest_long_header11$(EXEEXT) \ + daemontest_get_chunked$(EXEEXT) \ + daemontest_put_chunked$(EXEEXT) daemontest_iplimit11$(EXEEXT) \ + daemontest_termination$(EXEEXT) +noinst_PROGRAMS = daemon_options_test$(EXEEXT) +subdir = src/testcurl +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libcurl_version_check_a_AR = $(AR) $(ARFLAGS) +libcurl_version_check_a_LIBADD = +am_libcurl_version_check_a_OBJECTS = curl_version_check.$(OBJEXT) +libcurl_version_check_a_OBJECTS = \ + $(am_libcurl_version_check_a_OBJECTS) +PROGRAMS = $(noinst_PROGRAMS) +am_daemon_options_test_OBJECTS = daemon_options_test.$(OBJEXT) +daemon_options_test_OBJECTS = $(am_daemon_options_test_OBJECTS) +daemon_options_test_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_get_OBJECTS = daemontest_get.$(OBJEXT) +daemontest_get_OBJECTS = $(am_daemontest_get_OBJECTS) +daemontest_get_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_get11_OBJECTS = daemontest_get.$(OBJEXT) +daemontest_get11_OBJECTS = $(am_daemontest_get11_OBJECTS) +daemontest_get11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_get_chunked_OBJECTS = daemontest_get_chunked.$(OBJEXT) +daemontest_get_chunked_OBJECTS = $(am_daemontest_get_chunked_OBJECTS) +daemontest_get_chunked_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_iplimit11_OBJECTS = daemontest_iplimit.$(OBJEXT) +daemontest_iplimit11_OBJECTS = $(am_daemontest_iplimit11_OBJECTS) +daemontest_iplimit11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_large_put_OBJECTS = daemontest_large_put.$(OBJEXT) +daemontest_large_put_OBJECTS = $(am_daemontest_large_put_OBJECTS) +daemontest_large_put_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_large_put11_OBJECTS = daemontest_large_put.$(OBJEXT) +daemontest_large_put11_OBJECTS = $(am_daemontest_large_put11_OBJECTS) +daemontest_large_put11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_long_header_OBJECTS = daemontest_long_header.$(OBJEXT) +daemontest_long_header_OBJECTS = $(am_daemontest_long_header_OBJECTS) +daemontest_long_header_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_long_header11_OBJECTS = \ + daemontest_long_header.$(OBJEXT) +daemontest_long_header11_OBJECTS = \ + $(am_daemontest_long_header11_OBJECTS) +daemontest_long_header11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_parse_cookies_OBJECTS = \ + daemontest_parse_cookies.$(OBJEXT) +daemontest_parse_cookies_OBJECTS = \ + $(am_daemontest_parse_cookies_OBJECTS) +daemontest_parse_cookies_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_post_OBJECTS = daemontest_post.$(OBJEXT) +daemontest_post_OBJECTS = $(am_daemontest_post_OBJECTS) +daemontest_post_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_post11_OBJECTS = daemontest_post.$(OBJEXT) +daemontest_post11_OBJECTS = $(am_daemontest_post11_OBJECTS) +daemontest_post11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_post_loop_OBJECTS = daemontest_post_loop.$(OBJEXT) +daemontest_post_loop_OBJECTS = $(am_daemontest_post_loop_OBJECTS) +daemontest_post_loop_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_post_loop11_OBJECTS = daemontest_post_loop.$(OBJEXT) +daemontest_post_loop11_OBJECTS = $(am_daemontest_post_loop11_OBJECTS) +daemontest_post_loop11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_postform_OBJECTS = daemontest_postform.$(OBJEXT) +daemontest_postform_OBJECTS = $(am_daemontest_postform_OBJECTS) +daemontest_postform_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_postform11_OBJECTS = daemontest_postform.$(OBJEXT) +daemontest_postform11_OBJECTS = $(am_daemontest_postform11_OBJECTS) +daemontest_postform11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_process_arguments_OBJECTS = \ + daemontest_process_arguments.$(OBJEXT) +daemontest_process_arguments_OBJECTS = \ + $(am_daemontest_process_arguments_OBJECTS) +daemontest_process_arguments_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_process_headers_OBJECTS = \ + daemontest_process_headers.$(OBJEXT) +daemontest_process_headers_OBJECTS = \ + $(am_daemontest_process_headers_OBJECTS) +daemontest_process_headers_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_put_OBJECTS = daemontest_put.$(OBJEXT) +daemontest_put_OBJECTS = $(am_daemontest_put_OBJECTS) +daemontest_put_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_put11_OBJECTS = daemontest_put.$(OBJEXT) +daemontest_put11_OBJECTS = $(am_daemontest_put11_OBJECTS) +daemontest_put11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_put_chunked_OBJECTS = daemontest_put_chunked.$(OBJEXT) +daemontest_put_chunked_OBJECTS = $(am_daemontest_put_chunked_OBJECTS) +daemontest_put_chunked_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_termination_OBJECTS = daemontest_termination.$(OBJEXT) +daemontest_termination_OBJECTS = $(am_daemontest_termination_OBJECTS) +daemontest_termination_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libcurl_version_check_a_SOURCES) \ + $(daemon_options_test_SOURCES) $(daemontest_get_SOURCES) \ + $(daemontest_get11_SOURCES) $(daemontest_get_chunked_SOURCES) \ + $(daemontest_iplimit11_SOURCES) \ + $(daemontest_large_put_SOURCES) \ + $(daemontest_large_put11_SOURCES) \ + $(daemontest_long_header_SOURCES) \ + $(daemontest_long_header11_SOURCES) \ + $(daemontest_parse_cookies_SOURCES) $(daemontest_post_SOURCES) \ + $(daemontest_post11_SOURCES) $(daemontest_post_loop_SOURCES) \ + $(daemontest_post_loop11_SOURCES) \ + $(daemontest_postform_SOURCES) \ + $(daemontest_postform11_SOURCES) \ + $(daemontest_process_arguments_SOURCES) \ + $(daemontest_process_headers_SOURCES) \ + $(daemontest_put_SOURCES) $(daemontest_put11_SOURCES) \ + $(daemontest_put_chunked_SOURCES) \ + $(daemontest_termination_SOURCES) +DIST_SOURCES = $(libcurl_version_check_a_SOURCES) \ + $(daemon_options_test_SOURCES) $(daemontest_get_SOURCES) \ + $(daemontest_get11_SOURCES) $(daemontest_get_chunked_SOURCES) \ + $(daemontest_iplimit11_SOURCES) \ + $(daemontest_large_put_SOURCES) \ + $(daemontest_large_put11_SOURCES) \ + $(daemontest_long_header_SOURCES) \ + $(daemontest_long_header11_SOURCES) \ + $(daemontest_parse_cookies_SOURCES) $(daemontest_post_SOURCES) \ + $(daemontest_post11_SOURCES) $(daemontest_post_loop_SOURCES) \ + $(daemontest_post_loop11_SOURCES) \ + $(daemontest_postform_SOURCES) \ + $(daemontest_postform11_SOURCES) \ + $(daemontest_process_arguments_SOURCES) \ + $(daemontest_process_headers_SOURCES) \ + $(daemontest_put_SOURCES) $(daemontest_put11_SOURCES) \ + $(daemontest_put_chunked_SOURCES) \ + $(daemontest_termination_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DIST_SUBDIRS = . https +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . $(am__append_1) +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +AM_CPPFLAGS = \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/daemon \ +-I$(top_srcdir)/src/include \ +$(LIBCURL_CPPFLAGS) + +TESTS = $(check_PROGRAMS) +noinst_LIBRARIES = libcurl_version_check.a +libcurl_version_check_a_SOURCES = \ + curl_version_check.c + +daemon_options_test_SOURCES = \ + daemon_options_test.c + +daemon_options_test_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la + +daemontest_get_SOURCES = \ + daemontest_get.c + +daemontest_get_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get_chunked_SOURCES = \ + daemontest_get_chunked.c + +daemontest_get_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_SOURCES = \ + daemontest_post.c + +daemontest_post_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_process_headers_SOURCES = \ + daemontest_process_headers.c + +daemontest_process_headers_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_parse_cookies_SOURCES = \ + daemontest_parse_cookies.c + +daemontest_parse_cookies_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_process_arguments_SOURCES = \ + daemontest_process_arguments.c + +daemontest_process_arguments_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform_SOURCES = \ + daemontest_postform.c + +daemontest_postform_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_loop_SOURCES = \ + daemontest_post_loop.c + +daemontest_post_loop_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_SOURCES = \ + daemontest_put.c + +daemontest_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_chunked_SOURCES = \ + daemontest_put_chunked.c + +daemontest_put_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get11_SOURCES = \ + daemontest_get.c + +daemontest_get11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post11_SOURCES = \ + daemontest_post.c + +daemontest_post11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform11_SOURCES = \ + daemontest_postform.c + +daemontest_postform11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_loop11_SOURCES = \ + daemontest_post_loop.c + +daemontest_post_loop11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put11_SOURCES = \ + daemontest_put.c + +daemontest_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_large_put_SOURCES = \ + daemontest_large_put.c + +daemontest_large_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_large_put11_SOURCES = \ + daemontest_large_put.c + +daemontest_large_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_long_header_SOURCES = \ + daemontest_long_header.c + +daemontest_long_header_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_long_header11_SOURCES = \ + daemontest_long_header.c + +daemontest_long_header11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_iplimit11_SOURCES = \ + daemontest_iplimit.c + +daemontest_iplimit11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_termination_SOURCES = \ + daemontest_termination.c + +daemontest_termination_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/testcurl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/testcurl/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libcurl_version_check.a: $(libcurl_version_check_a_OBJECTS) $(libcurl_version_check_a_DEPENDENCIES) + -rm -f libcurl_version_check.a + $(libcurl_version_check_a_AR) libcurl_version_check.a $(libcurl_version_check_a_OBJECTS) $(libcurl_version_check_a_LIBADD) + $(RANLIB) libcurl_version_check.a + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +daemon_options_test$(EXEEXT): $(daemon_options_test_OBJECTS) $(daemon_options_test_DEPENDENCIES) + @rm -f daemon_options_test$(EXEEXT) + $(LINK) $(daemon_options_test_OBJECTS) $(daemon_options_test_LDADD) $(LIBS) +daemontest_get$(EXEEXT): $(daemontest_get_OBJECTS) $(daemontest_get_DEPENDENCIES) + @rm -f daemontest_get$(EXEEXT) + $(LINK) $(daemontest_get_OBJECTS) $(daemontest_get_LDADD) $(LIBS) +daemontest_get11$(EXEEXT): $(daemontest_get11_OBJECTS) $(daemontest_get11_DEPENDENCIES) + @rm -f daemontest_get11$(EXEEXT) + $(LINK) $(daemontest_get11_OBJECTS) $(daemontest_get11_LDADD) $(LIBS) +daemontest_get_chunked$(EXEEXT): $(daemontest_get_chunked_OBJECTS) $(daemontest_get_chunked_DEPENDENCIES) + @rm -f daemontest_get_chunked$(EXEEXT) + $(LINK) $(daemontest_get_chunked_OBJECTS) $(daemontest_get_chunked_LDADD) $(LIBS) +daemontest_iplimit11$(EXEEXT): $(daemontest_iplimit11_OBJECTS) $(daemontest_iplimit11_DEPENDENCIES) + @rm -f daemontest_iplimit11$(EXEEXT) + $(LINK) $(daemontest_iplimit11_OBJECTS) $(daemontest_iplimit11_LDADD) $(LIBS) +daemontest_large_put$(EXEEXT): $(daemontest_large_put_OBJECTS) $(daemontest_large_put_DEPENDENCIES) + @rm -f daemontest_large_put$(EXEEXT) + $(LINK) $(daemontest_large_put_OBJECTS) $(daemontest_large_put_LDADD) $(LIBS) +daemontest_large_put11$(EXEEXT): $(daemontest_large_put11_OBJECTS) $(daemontest_large_put11_DEPENDENCIES) + @rm -f daemontest_large_put11$(EXEEXT) + $(LINK) $(daemontest_large_put11_OBJECTS) $(daemontest_large_put11_LDADD) $(LIBS) +daemontest_long_header$(EXEEXT): $(daemontest_long_header_OBJECTS) $(daemontest_long_header_DEPENDENCIES) + @rm -f daemontest_long_header$(EXEEXT) + $(LINK) $(daemontest_long_header_OBJECTS) $(daemontest_long_header_LDADD) $(LIBS) +daemontest_long_header11$(EXEEXT): $(daemontest_long_header11_OBJECTS) $(daemontest_long_header11_DEPENDENCIES) + @rm -f daemontest_long_header11$(EXEEXT) + $(LINK) $(daemontest_long_header11_OBJECTS) $(daemontest_long_header11_LDADD) $(LIBS) +daemontest_parse_cookies$(EXEEXT): $(daemontest_parse_cookies_OBJECTS) $(daemontest_parse_cookies_DEPENDENCIES) + @rm -f daemontest_parse_cookies$(EXEEXT) + $(LINK) $(daemontest_parse_cookies_OBJECTS) $(daemontest_parse_cookies_LDADD) $(LIBS) +daemontest_post$(EXEEXT): $(daemontest_post_OBJECTS) $(daemontest_post_DEPENDENCIES) + @rm -f daemontest_post$(EXEEXT) + $(LINK) $(daemontest_post_OBJECTS) $(daemontest_post_LDADD) $(LIBS) +daemontest_post11$(EXEEXT): $(daemontest_post11_OBJECTS) $(daemontest_post11_DEPENDENCIES) + @rm -f daemontest_post11$(EXEEXT) + $(LINK) $(daemontest_post11_OBJECTS) $(daemontest_post11_LDADD) $(LIBS) +daemontest_post_loop$(EXEEXT): $(daemontest_post_loop_OBJECTS) $(daemontest_post_loop_DEPENDENCIES) + @rm -f daemontest_post_loop$(EXEEXT) + $(LINK) $(daemontest_post_loop_OBJECTS) $(daemontest_post_loop_LDADD) $(LIBS) +daemontest_post_loop11$(EXEEXT): $(daemontest_post_loop11_OBJECTS) $(daemontest_post_loop11_DEPENDENCIES) + @rm -f daemontest_post_loop11$(EXEEXT) + $(LINK) $(daemontest_post_loop11_OBJECTS) $(daemontest_post_loop11_LDADD) $(LIBS) +daemontest_postform$(EXEEXT): $(daemontest_postform_OBJECTS) $(daemontest_postform_DEPENDENCIES) + @rm -f daemontest_postform$(EXEEXT) + $(LINK) $(daemontest_postform_OBJECTS) $(daemontest_postform_LDADD) $(LIBS) +daemontest_postform11$(EXEEXT): $(daemontest_postform11_OBJECTS) $(daemontest_postform11_DEPENDENCIES) + @rm -f daemontest_postform11$(EXEEXT) + $(LINK) $(daemontest_postform11_OBJECTS) $(daemontest_postform11_LDADD) $(LIBS) +daemontest_process_arguments$(EXEEXT): $(daemontest_process_arguments_OBJECTS) $(daemontest_process_arguments_DEPENDENCIES) + @rm -f daemontest_process_arguments$(EXEEXT) + $(LINK) $(daemontest_process_arguments_OBJECTS) $(daemontest_process_arguments_LDADD) $(LIBS) +daemontest_process_headers$(EXEEXT): $(daemontest_process_headers_OBJECTS) $(daemontest_process_headers_DEPENDENCIES) + @rm -f daemontest_process_headers$(EXEEXT) + $(LINK) $(daemontest_process_headers_OBJECTS) $(daemontest_process_headers_LDADD) $(LIBS) +daemontest_put$(EXEEXT): $(daemontest_put_OBJECTS) $(daemontest_put_DEPENDENCIES) + @rm -f daemontest_put$(EXEEXT) + $(LINK) $(daemontest_put_OBJECTS) $(daemontest_put_LDADD) $(LIBS) +daemontest_put11$(EXEEXT): $(daemontest_put11_OBJECTS) $(daemontest_put11_DEPENDENCIES) + @rm -f daemontest_put11$(EXEEXT) + $(LINK) $(daemontest_put11_OBJECTS) $(daemontest_put11_LDADD) $(LIBS) +daemontest_put_chunked$(EXEEXT): $(daemontest_put_chunked_OBJECTS) $(daemontest_put_chunked_DEPENDENCIES) + @rm -f daemontest_put_chunked$(EXEEXT) + $(LINK) $(daemontest_put_chunked_OBJECTS) $(daemontest_put_chunked_LDADD) $(LIBS) +daemontest_termination$(EXEEXT): $(daemontest_termination_OBJECTS) $(daemontest_termination_DEPENDENCIES) + @rm -f daemontest_termination$(EXEEXT) + $(LINK) $(daemontest_termination_OBJECTS) $(daemontest_termination_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/curl_version_check.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon_options_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_get.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_get_chunked.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_iplimit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_large_put.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_long_header.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_parse_cookies.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_post.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_post_loop.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_postform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_process_arguments.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_process_headers.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_put.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_put_chunked.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_termination.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + clean-noinstLIBRARIES clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool \ + clean-noinstLIBRARIES clean-noinstPROGRAMS ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/testcurl/curl_version_check.c b/lib/libmicrohttpd/src/testcurl/curl_version_check.c new file mode 100644 index 0000000000..f794aa25eb --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/curl_version_check.c @@ -0,0 +1,156 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file curl_version_check.c + * @brief verify required cURL version is available to run tests + * @author Sagie Amir + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int +parse_version_number (const char **s) +{ + int i = 0; + char num[17]; + + while (i < 16 && ((**s >= '0') & (**s <= '9'))) + { + num[i] = **s; + (*s)++; + i++; + } + + num[i] = '\0'; + + return atoi (num); +} + +const char * +parse_version_string (const char *s, int *major, int *minor, int *micro) +{ + if (!s) + return NULL; + *major = parse_version_number (&s); + if (!s || *s != '.') + return NULL; + s++; + *minor = parse_version_number (&s); + if (*s != '.') + return NULL; + s++; + *micro = parse_version_number (&s); + return s; +} + + +/* + * check local libcurl version matches required version + */ +int +curl_check_version (const char *req_version) +{ + const char *ver; + const char *curl_ver; +#if HTTPS_SUPPORT + const char *ssl_ver; + const char *req_ssl_ver; +#endif + + int loc_major, loc_minor, loc_micro; + int rq_major, rq_minor, rq_micro; + + ver = curl_version (); +#if HAVE_MESSAGES + fprintf (stderr, "curl version: %s\n", ver); +#endif + /* + * this call relies on the cURL string to be of the exact following format : + * 'libcurl/7.16.4 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/0.6.5' OR + * 'libcurl/7.18.2 GnuTLS/2.4.0 zlib/1.2.3.3 libidn/0.6.5' + */ + curl_ver = strchr (ver, '/') + 1; + + /* Parse version numbers */ + parse_version_string (req_version, &rq_major, &rq_minor, &rq_micro); + parse_version_string (curl_ver, &loc_major, &loc_minor, &loc_micro); + + /* Compare version numbers. */ + if ((loc_major > rq_major + || (loc_major == rq_major && loc_minor > rq_minor) + || (loc_major == rq_major && loc_minor == rq_minor + && loc_micro > rq_micro) || (loc_major == rq_major + && loc_minor == rq_minor + && loc_micro == rq_micro)) == 0) + { + fprintf (stderr, + "Error: running curl test depends on local libcurl version > %s\n", + req_version); + return -1; + } + + /* + * enforce required gnutls/openssl version. + * TODO use curl version string to assert use of gnutls + */ +#if HTTPS_SUPPORT + ssl_ver = strchr (curl_ver, ' ') + 1; + + if (strncmp ("GnuTLS", ssl_ver, strlen ("GNUtls")) == 0) + { + ssl_ver = strchr (ssl_ver, '/') + 1; + req_ssl_ver = MHD_REQ_CURL_GNUTLS_VERSION; + } + else if (strncmp ("OpenSSL", ssl_ver, strlen ("OpenSSL")) == 0) + { + ssl_ver = strchr (ssl_ver, '/') + 1; + req_ssl_ver = MHD_REQ_CURL_OPENSSL_VERSION; + } + else + { + fprintf (stderr, "Error: unrecognized curl ssl library\n"); + return -1; + } + + parse_version_string (req_ssl_ver, &rq_major, &rq_minor, &rq_micro); + parse_version_string (ssl_ver, &loc_major, &loc_minor, &loc_micro); + + if ((loc_major > rq_major + || (loc_major == rq_major && loc_minor > rq_minor) + || (loc_major == rq_major && loc_minor == rq_minor + && loc_micro > rq_micro) || (loc_major == rq_major + && loc_minor == rq_minor + && loc_micro == rq_micro)) == 0) + { + fprintf (stderr, + "Error: running curl test depends on local libcurl SSL version > %s\n", + req_ssl_ver); + return -1; + } +#endif + return 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/daemon_options_test.c b/lib/libmicrohttpd/src/testcurl/daemon_options_test.c new file mode 100644 index 0000000000..7a387d9446 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemon_options_test.c @@ -0,0 +1,127 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_get_test.c + * @brief Testcase for libmicrohttpd HTTPS GET operations + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" + +#define MHD_E_MEM "Error: memory error\n" +#define MHD_E_SERVER_INIT "Error: failed to start server\n" + +const int DEBUG_GNUTLS_LOG_LEVEL = 0; +const char *test_file_name = "https_test_file"; +const char test_file_data[] = "Hello World\n"; + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + return 0; +} + +int +test_wrap (char *test_name, int (*test) (void)) +{ + int ret; + + fprintf (stdout, "running test: %s ", test_name); + ret = test (); + if (ret == 0) + { + fprintf (stdout, "[pass]\n"); + } + else + { + fprintf (stdout, "[fail]\n"); + } + return ret; +} + + +/** + * Test daemon initialization with the MHD_OPTION_SOCK_ADDR option + */ +static int +test_ip_addr_option () +{ + struct MHD_Daemon *d; + struct sockaddr_in daemon_ip_addr; +#if HAVE_INET6 + struct sockaddr_in6 daemon_ip_addr6; +#endif + + memset (&daemon_ip_addr, 0, sizeof (struct sockaddr_in)); + daemon_ip_addr.sin_family = AF_INET; + daemon_ip_addr.sin_port = htons (42433); + +#if HAVE_INET6 + memset (&daemon_ip_addr6, 0, sizeof (struct sockaddr_in6)); + daemon_ip_addr6.sin6_family = AF_INET6; + daemon_ip_addr6.sin6_port = htons (42433); +#endif + + inet_pton (AF_INET, "127.0.0.1", &daemon_ip_addr.sin_addr); +#if HAVE_INET6 + inet_pton (AF_INET6, "::ffff:127.0.0.1", &daemon_ip_addr6.sin6_addr); +#endif + + d = MHD_start_daemon (MHD_USE_DEBUG, 42433, + NULL, NULL, &ahc_echo, NULL, MHD_OPTION_SOCK_ADDR, + &daemon_ip_addr, MHD_OPTION_END); + + if (d == 0) + return -1; + + MHD_stop_daemon (d); + +#if HAVE_INET6 + d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_IPv6, 42433, + NULL, NULL, &ahc_echo, NULL, MHD_OPTION_SOCK_ADDR, + &daemon_ip_addr6, MHD_OPTION_END); + + if (d == 0) + return -1; + + MHD_stop_daemon (d); +#endif + + return 0; +} + +/* setup a temporary transfer test file */ +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + errorCount += test_wrap ("ip addr option", &test_ip_addr_option); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_get.c b/lib/libmicrohttpd/src/testcurl/daemontest_get.c new file mode 100644 index 0000000000..43870177f8 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_get.c @@ -0,0 +1,501 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2009 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_get.c + * @brief Testcase for libmicrohttpd GET operations + * TODO: test parsing of query + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/socket.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int ptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&ptr != *unused) + { + *unused = &ptr; + return MHD_YES; + } + *unused = NULL; + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + if (ret == MHD_NO) + abort (); + return ret; +} + + +static int +testInternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system!*/ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 4; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 8; + return 0; +} + +static int +testMultithreadedGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testMultithreadedPoolGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system!*/ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testExternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + +static int +testUnknownPortGet () +{ + struct MHD_Daemon *d; + const union MHD_DaemonInfo *di; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_SOCK_ADDR, &addr, + MHD_OPTION_END); + if (d == NULL) + return 32768; + + di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD); + if (di == NULL) + return 65536; + + if (0 != getsockname(di->listen_fd, &addr, &addr_len)) + return 131072; + + if (addr.sin_family != AF_INET) + return 26214; + + snprintf(buf, sizeof(buf), "http://localhost:%hu/hello_world", + ntohs(addr.sin_port)); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, buf); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 524288; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 1048576; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 2097152; + return 0; +} + + +static int +testStopRace () +{ + struct sockaddr_in sin; + int fd; + struct MHD_Daemon *d; + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 16; + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + { + fprintf(stderr, "socket: %m\n"); + return 256; + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(1081); + sin.sin_addr.s_addr = htonl(0x7f000001); + + if (connect(fd, (struct sockaddr *)(&sin), sizeof(sin)) < 0) + { + fprintf(stderr, "connect: %m\n"); + return 512; + } + + /* printf("Waiting\n"); */ + /* Let the thread get going. */ + usleep(500000); + + /* printf("Stopping daemon\n"); */ + MHD_stop_daemon (d); + + close(fd); + + /* printf("good\n"); */ + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalGet (); + errorCount += testMultithreadedGet (); + errorCount += testMultithreadedPoolGet (); + errorCount += testExternalGet (); + errorCount += testUnknownPortGet (); + errorCount += testStopRace (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_get_chunked.c b/lib/libmicrohttpd/src/testcurl/daemontest_get_chunked.c new file mode 100644 index 0000000000..da11e90c92 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_get_chunked.c @@ -0,0 +1,405 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_get_chunked.c + * @brief Testcase for libmicrohttpd GET operations with chunked content encoding + * TODO: + * - how to test that chunking was actually used? + * - use CURLOPT_HEADERFUNCTION to validate + * footer was sent + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +/** + * MHD content reader callback that returns + * data in chunks. + */ +static int +crc (void *cls, uint64_t pos, char *buf, int max) +{ + struct MHD_Response **responseptr = cls; + + if (pos == 128 * 10) + { + MHD_add_response_header (*responseptr, "Footer", "working"); + return -1; /* end of stream */ + } + if (max < 128) + abort (); /* should not happen in this testcase... */ + memset (buf, 'A' + (pos / 128), 128); + return 128; +} + +/** + * Dummy function that does nothing. + */ +static void +crcf (void *ptr) +{ + free (ptr); +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + static int aptr; + const char *me = cls; + struct MHD_Response *response; + struct MHD_Response **responseptr; + int ret; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + responseptr = malloc (sizeof (struct MHD_Response *)); + response = MHD_create_response_from_callback (-1, + 1024, + &crc, responseptr, &crcf); + *responseptr = response; + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +static int +validate (struct CBC cbc, int ebase) +{ + int i; + char buf[128]; + + if (cbc.pos != 128 * 10) + return ebase; + + for (i = 0; i < 10; i++) + { + memset (buf, 'A' + i, 128); + if (0 != memcmp (buf, &cbc.buf[i * 128], 128)) + { + fprintf (stderr, + "Got `%.*s'\nWant `%.*s'\n", + 128, buf, 128, &cbc.buf[i * 128]); + return ebase * 2; + } + } + return 0; +} + +static int +testInternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return validate (cbc, 4); +} + +static int +testMultithreadedGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return validate (cbc, 64); +} + +static int +testMultithreadedPoolGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return validate (cbc, 64); +} + +static int +testExternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + return validate (cbc, 8192); +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalGet (); + errorCount += testMultithreadedGet (); + errorCount += testMultithreadedPoolGet (); + errorCount += testExternalGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_iplimit.c b/lib/libmicrohttpd/src/testcurl/daemontest_iplimit.c new file mode 100644 index 0000000000..93e6b06c78 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_iplimit.c @@ -0,0 +1,301 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_get.c + * @brief Testcase for libmicrohttpd GET operations + * TODO: test parsing of query + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int ptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&ptr != *unused) + { + *unused = &ptr; + return MHD_YES; + } + *unused = NULL; + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + if (ret == MHD_NO) + abort (); + return ret; +} + +static int +testMultithreadedGet () +{ + struct MHD_Daemon *d; + char buf[2048]; + int k; + + /* Test only valid for HTTP/1.1 (uses persistent connections) */ + if (!oneone) + return 0; + + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2, + MHD_OPTION_END); + if (d == NULL) + return 16; + + for (k = 0; k < 3; ++k) + { + struct CBC cbc[3]; + CURL *cenv[3]; + int i; + + for (i = 0; i < 3; ++i) + { + CURL *c; + CURLcode errornum; + + cenv[i] = c = curl_easy_init (); + cbc[i].buf = buf; + cbc[i].size = 2048; + cbc[i].pos = 0; + + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc[i]); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_FORBID_REUSE, 0L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + errornum = curl_easy_perform (c); + if ( ( (CURLE_OK != errornum) && (i < 2) ) || + ( (CURLE_OK == errornum) && (i == 2) ) ) + { + int j; + + /* First 2 should succeed */ + if (i < 2) + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + + /* Last request should have failed */ + else + fprintf (stderr, + "No error on IP address over limit\n"); + + for (j = 0; j < i; ++j) + curl_easy_cleanup (cenv[j]); + MHD_stop_daemon (d); + return 32; + } + } + + /* Cleanup the environments */ + for (i = 0; i < 3; ++i) + curl_easy_cleanup (cenv[i]); + + sleep(2); + + for (i = 0; i < 2; ++i) + { + if (cbc[i].pos != strlen ("/hello_world")) + { + MHD_stop_daemon (d); + return 64; + } + if (0 != strncmp ("/hello_world", cbc[i].buf, strlen ("/hello_world"))) + { + MHD_stop_daemon (d); + return 128; + } + } + + + } + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithreadedPoolGet () +{ + struct MHD_Daemon *d; + char buf[2048]; + int k; + + /* Test only valid for HTTP/1.1 (uses persistent connections) */ + if (!oneone) + return 0; + + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2, + MHD_OPTION_THREAD_POOL_SIZE, 4, + MHD_OPTION_END); + if (d == NULL) + return 16; + + for (k = 0; k < 3; ++k) + { + struct CBC cbc[3]; + CURL *cenv[3]; + int i; + + for (i = 0; i < 3; ++i) + { + CURL *c; + CURLcode errornum; + + cenv[i] = c = curl_easy_init (); + cbc[i].buf = buf; + cbc[i].size = 2048; + cbc[i].pos = 0; + + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc[i]); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_FORBID_REUSE, 0L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + errornum = curl_easy_perform (c); + if ( ( (CURLE_OK != errornum) && (i < 2) ) || + ( (CURLE_OK == errornum) && (i == 2) ) ) + { + int j; + + /* First 2 should succeed */ + if (i < 2) + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + + /* Last request should have failed */ + else + fprintf (stderr, + "No error on IP address over limit\n"); + + for (j = 0; j < i; ++j) + curl_easy_cleanup (cenv[j]); + MHD_stop_daemon (d); + return 32; + } + } + + /* Cleanup the environments */ + for (i = 0; i < 3; ++i) + curl_easy_cleanup (cenv[i]); + + sleep(2); + + for (i = 0; i < 2; ++i) + { + if (cbc[i].pos != strlen ("/hello_world")) + { + MHD_stop_daemon (d); + return 64; + } + if (0 != strncmp ("/hello_world", cbc[i].buf, strlen ("/hello_world"))) + { + MHD_stop_daemon (d); + return 128; + } + } + + + } + MHD_stop_daemon (d); + return 0; +} + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testMultithreadedGet (); + errorCount += testMultithreadedPoolGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_large_put.c b/lib/libmicrohttpd/src/testcurl/daemontest_large_put.c new file mode 100644 index 0000000000..f046de9f47 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_large_put.c @@ -0,0 +1,469 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_large_put.c + * @brief Testcase for libmicrohttpd PUT operations + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +/** + * Do not make this much larger since we will hit the + * MHD default buffer limit and the test code is not + * written for incremental upload processing... + * (larger values will likely cause MHD to generate + * an internal server error -- which would be avoided + * by writing the putBuffer method in a more general + * fashion). + */ +#define PUT_SIZE (256 * 1024) + +static char *put_buffer; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) +{ + unsigned int *pos = ptr; + unsigned int wrt; + + wrt = size * nmemb; + if (wrt > PUT_SIZE - (*pos)) + wrt = PUT_SIZE - (*pos); + memcpy (stream, &put_buffer[*pos], wrt); + (*pos) += wrt; + return wrt; +} + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + int *done = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp ("PUT", method)) + return MHD_NO; /* unexpected method */ + if ((*done) == 0) + { + if (*upload_data_size != PUT_SIZE) + { +#if 0 + fprintf (stderr, + "Waiting for more data (%u/%u)...\n", + *upload_data_size, PUT_SIZE); +#endif + return MHD_YES; /* not yet ready */ + } + if (0 == memcmp (upload_data, put_buffer, PUT_SIZE)) + { + *upload_data_size = 0; + } + else + { + printf ("Invalid upload data!\n"); + return MHD_NO; + } + *done = 1; + return MHD_YES; + } + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testInternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + char buf[2048]; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1080, + NULL, NULL, &ahc_echo, &done_flag, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024), + MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 4; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 8; + return 0; +} + +static int +testMultithreadedPut () +{ + struct MHD_Daemon *d; + CURL *c; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + char buf[2048]; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, + NULL, NULL, &ahc_echo, &done_flag, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024), + MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + { + fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf); + return 64; + } + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testMultithreadedPoolPut () +{ + struct MHD_Daemon *d; + CURL *c; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + char buf[2048]; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, + NULL, NULL, &ahc_echo, &done_flag, + MHD_OPTION_THREAD_POOL_SIZE, 4, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (1024*1024), + MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + { + fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf); + return 64; + } + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testExternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + unsigned int pos = 0; + int done_flag = 0; + char buf[2048]; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + multi = NULL; + d = MHD_start_daemon (MHD_USE_DEBUG, + 1082, + NULL, NULL, &ahc_echo, &done_flag, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (PUT_SIZE * 4), MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + { + fprintf (stderr, "Got invalid response `%.*s'\n", (int)cbc.pos, cbc.buf); + return 8192; + } + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + put_buffer = malloc (PUT_SIZE); + memset (put_buffer, 1, PUT_SIZE); + errorCount += testInternalPut (); + errorCount += testMultithreadedPut (); + errorCount += testMultithreadedPoolPut (); + errorCount += testExternalPut (); + free (put_buffer); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_long_header.c b/lib/libmicrohttpd/src/testcurl/daemontest_long_header.c new file mode 100644 index 0000000000..98dcc812ac --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_long_header.c @@ -0,0 +1,241 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_long_header.c + * @brief Testcase for libmicrohttpd handling of very long headers + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +/** + * We will set the memory available per connection to + * half of this value, so the actual value does not have + * to be big at all... + */ +#define VERY_LONG (1024*10) + +static int oneone; + +static int +apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + return MHD_YES; +} + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + const char *me = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testLongUrlGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + char *url; + long code; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 1080, + &apc_all, + NULL, + &ahc_echo, + "GET", + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (VERY_LONG / 2), MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + url = malloc (VERY_LONG); + memset (url, 'a', VERY_LONG); + url[VERY_LONG - 1] = '\0'; + memcpy (url, "http://localhost:1080/", strlen ("http://localhost:1080/")); + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK == curl_easy_perform (c)) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + free (url); + return 2; + } + if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + free (url); + return 4; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + free (url); + if (code != MHD_HTTP_REQUEST_URI_TOO_LONG) + return 8; + return 0; +} + + +static int +testLongHeaderGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + char *url; + long code; + struct curl_slist *header = NULL; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 1080, + &apc_all, + NULL, + &ahc_echo, + "GET", + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (VERY_LONG / 2), MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + url = malloc (VERY_LONG); + memset (url, 'a', VERY_LONG); + url[VERY_LONG - 1] = '\0'; + url[VERY_LONG / 2] = ':'; + url[VERY_LONG / 2 + 1] = ' '; + header = curl_slist_append (header, url); + + curl_easy_setopt (c, CURLOPT_HTTPHEADER, header); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK == curl_easy_perform (c)) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + curl_slist_free_all (header); + free (url); + return 32; + } + if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) + { + curl_slist_free_all (header); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + free (url); + return 64; + } + curl_slist_free_all (header); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + free (url); + if (code != MHD_HTTP_REQUEST_ENTITY_TOO_LARGE) + return 128; + return 0; +} + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testLongUrlGet (); + errorCount += testLongHeaderGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_parse_cookies.c b/lib/libmicrohttpd/src/testcurl/daemontest_parse_cookies.c new file mode 100644 index 0000000000..bfa8f86097 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_parse_cookies.c @@ -0,0 +1,249 @@ + +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_parse_cookies.c + * @brief Testcase for HTTP cookie parsing + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int ptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + const char *hdr; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&ptr != *unused) + { + *unused = &ptr; + return MHD_YES; + } + *unused = NULL; + ret = 0; + + hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name1"); + if ((hdr == NULL) || (0 != strcmp (hdr, "var1"))) + abort (); + hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name2"); + if ((hdr == NULL) || (0 != strcmp (hdr, "var2"))) + abort (); + hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name3"); + if ((hdr == NULL) || (0 != strcmp (hdr, ""))) + abort (); + hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name4"); + if ((hdr == NULL) || (0 != strcmp (hdr, "var4 with spaces"))) + abort (); + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + if (ret == MHD_NO) + abort (); + return ret; +} + +static int +testExternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:21080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + /* note that the string below intentionally uses the + various ways cookies can be specified to exercise the + parser! Do not change! */ + curl_easy_setopt (c, CURLOPT_COOKIE, + "name1=var1; name2=var2,name3 ;name4=\"var4 with spaces\";"); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testExternalGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_post.c b/lib/libmicrohttpd/src/testcurl/daemontest_post.c new file mode 100644 index 0000000000..715047fe64 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_post.c @@ -0,0 +1,430 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_post.c + * @brief Testcase for libmicrohttpd POST operations using URL-encoding + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +#define POST_DATA "name=daniel&project=curl" + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +/** + * Note that this post_iterator is not perfect + * in that it fails to support incremental processing. + * (to be fixed in the future) + */ +static int +post_iterator (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *value, uint64_t off, size_t size) +{ + int *eok = cls; + + if ((0 == strcmp (key, "name")) && + (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size))) + (*eok) |= 1; + if ((0 == strcmp (key, "project")) && + (size == strlen ("curl")) && (0 == strncmp (value, "curl", size))) + (*eok) |= 2; + return MHD_YES; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int eok; + struct MHD_Response *response; + struct MHD_PostProcessor *pp; + int ret; + + if (0 != strcmp ("POST", method)) + { + printf ("METHOD: %s\n", method); + return MHD_NO; /* unexpected method */ + } + pp = *unused; + if (pp == NULL) + { + eok = 0; + pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok); + *unused = pp; + } + MHD_post_process (pp, upload_data, *upload_data_size); + if ((eok == 3) && (0 == *upload_data_size)) + { + response = MHD_create_response_from_data (strlen (url), + (void *) url, + MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + MHD_destroy_post_processor (pp); + *unused = NULL; + return ret; + } + *upload_data_size = 0; + return MHD_YES; +} + + +static int +testInternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 4; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 8; + return 0; +} + +static int +testMultithreadedPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testMultithreadedPoolPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testExternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 1082, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPost (); + errorCount += testMultithreadedPost (); + errorCount += testMultithreadedPoolPost (); + errorCount += testExternalPost (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_post_loop.c b/lib/libmicrohttpd/src/testcurl/daemontest_post_loop.c new file mode 100644 index 0000000000..b1e1ab3f14 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_post_loop.c @@ -0,0 +1,452 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_post_loop.c + * @brief Testcase for libmicrohttpd POST operations using URL-encoding + * @author Christian Grothoff (inspired by bug report #1296) + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +#define POST_DATA "<?xml version='1.0' ?>\n<xml>\n<data-id>1</data-id>\n</xml>\n" + +#define LOOPCOUNT 10 + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **mptr) +{ + static int marker; + struct MHD_Response *response; + int ret; + + if (0 != strcmp ("POST", method)) + { + printf ("METHOD: %s\n", method); + return MHD_NO; /* unexpected method */ + } + if ((*mptr != NULL) && (0 == *upload_data_size)) + { + if (*mptr != &marker) + abort (); + response = MHD_create_response_from_data (2, "OK", MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + *mptr = NULL; + return ret; + } + if (strlen (POST_DATA) != *upload_data_size) + return MHD_YES; + *upload_data_size = 0; + *mptr = ▮ + return MHD_YES; +} + + +static int +testInternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + int i; + char url[1024]; + + cbc.buf = buf; + cbc.size = 2048; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 1; + for (i = 0; i < LOOPCOUNT; i++) + { + if (99 == i % 100) + fprintf (stderr, "."); + c = curl_easy_init (); + cbc.pos = 0; + buf[0] = '\0'; + sprintf (url, "http://localhost:1080/hw%d", i); + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + if ((buf[0] != 'O') || (buf[1] != 'K')) + { + MHD_stop_daemon (d); + return 4; + } + } + MHD_stop_daemon (d); + if (LOOPCOUNT >= 99) + fprintf (stderr, "\n"); + return 0; +} + +static int +testMultithreadedPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + int i; + char url[1024]; + + cbc.buf = buf; + cbc.size = 2048; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 16; + for (i = 0; i < LOOPCOUNT; i++) + { + if (99 == i % 100) + fprintf (stderr, "."); + c = curl_easy_init (); + cbc.pos = 0; + buf[0] = '\0'; + sprintf (url, "http://localhost:1081/hw%d", i); + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + if ((buf[0] != 'O') || (buf[1] != 'K')) + { + MHD_stop_daemon (d); + return 64; + } + } + MHD_stop_daemon (d); + if (LOOPCOUNT >= 99) + fprintf (stderr, "\n"); + return 0; +} + +static int +testMultithreadedPoolPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + int i; + char url[1024]; + + cbc.buf = buf; + cbc.size = 2048; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + for (i = 0; i < LOOPCOUNT; i++) + { + if (99 == i % 100) + fprintf (stderr, "."); + c = curl_easy_init (); + cbc.pos = 0; + buf[0] = '\0'; + sprintf (url, "http://localhost:1081/hw%d", i); + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + if ((buf[0] != 'O') || (buf[1] != 'K')) + { + MHD_stop_daemon (d); + return 64; + } + } + MHD_stop_daemon (d); + if (LOOPCOUNT >= 99) + fprintf (stderr, "\n"); + return 0; +} + +static int +testExternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + int i; + unsigned long long timeout; + long ctimeout; + char url[1024]; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 1082, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 256; + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + for (i = 0; i < LOOPCOUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + cbc.pos = 0; + buf[0] = '\0'; + sprintf (url, "http://localhost:1082/hw%d", i); + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + while (CURLM_CALL_MULTI_PERFORM == + curl_multi_perform (multi, &running)); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + if (MHD_NO == MHD_get_timeout (d, &timeout)) + timeout = 100; /* 100ms == INFTY -- CURL bug... */ + if ((CURLM_OK == curl_multi_timeout (multi, &ctimeout)) && + (ctimeout < timeout) && (ctimeout >= 0)) + timeout = ctimeout; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + select (max + 1, &rs, &ws, &es, &tv); + while (CURLM_CALL_MULTI_PERFORM == + curl_multi_perform (multi, &running)); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + if ((buf[0] != 'O') || (buf[1] != 'K')) + { + curl_multi_cleanup (multi); + MHD_stop_daemon (d); + return 8192; + } + } + curl_multi_cleanup (multi); + MHD_stop_daemon (d); + fprintf (stderr, "\n"); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPost (); + errorCount += testMultithreadedPost (); + errorCount += testMultithreadedPoolPost (); + errorCount += testExternalPost (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_postform.c b/lib/libmicrohttpd/src/testcurl/daemontest_postform.c new file mode 100644 index 0000000000..a1e29f6953 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_postform.c @@ -0,0 +1,457 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_post.c + * @brief Testcase for libmicrohttpd POST operations using multipart/postform data + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +/** + * Note that this post_iterator is not perfect + * in that it fails to support incremental processing. + * (to be fixed in the future) + */ +static int +post_iterator (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *value, uint64_t off, size_t size) +{ + int *eok = cls; + +#if 0 + fprintf (stderr, "PI sees %s-%.*s\n", key, size, value); +#endif + if ((0 == strcmp (key, "name")) && + (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size))) + (*eok) |= 1; + if ((0 == strcmp (key, "project")) && + (size == strlen ("curl")) && (0 == strncmp (value, "curl", size))) + (*eok) |= 2; + return MHD_YES; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int eok; + struct MHD_Response *response; + struct MHD_PostProcessor *pp; + int ret; + + if (0 != strcmp ("POST", method)) + { + printf ("METHOD: %s\n", method); + return MHD_NO; /* unexpected method */ + } + pp = *unused; + if (pp == NULL) + { + eok = 0; + pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok); + if (pp == NULL) + abort (); + *unused = pp; + } + MHD_post_process (pp, upload_data, *upload_data_size); + if ((eok == 3) && (0 == *upload_data_size)) + { + response = MHD_create_response_from_data (strlen (url), + (void *) url, + MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + MHD_destroy_post_processor (pp); + *unused = NULL; + return ret; + } + *upload_data_size = 0; + return MHD_YES; +} + +static struct curl_httppost * +make_form () +{ + struct curl_httppost *post = NULL; + struct curl_httppost *last = NULL; + + curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END); + curl_formadd (&post, &last, CURLFORM_COPYNAME, "project", + CURLFORM_COPYCONTENTS, "curl", CURLFORM_END); + return post; +} + + +static int +testInternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + struct curl_httppost *pd; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + pd = make_form (); + curl_easy_setopt (c, CURLOPT_HTTPPOST, pd); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 4; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 8; + return 0; +} + +static int +testMultithreadedPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + struct curl_httppost *pd; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + pd = make_form (); + curl_easy_setopt (c, CURLOPT_HTTPPOST, pd); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testMultithreadedPoolPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + struct curl_httppost *pd; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + pd = make_form (); + curl_easy_setopt (c, CURLOPT_HTTPPOST, pd); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testExternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + struct curl_httppost *pd; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 1082, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + pd = make_form (); + curl_easy_setopt (c, CURLOPT_HTTPPOST, pd); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_formfree (pd); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + curl_formfree (pd); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + curl_formfree (pd); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + curl_formfree (pd); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPost (); + errorCount += testMultithreadedPost (); + errorCount += testMultithreadedPoolPost (); + errorCount += testExternalPost (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_process_arguments.c b/lib/libmicrohttpd/src/testcurl/daemontest_process_arguments.c new file mode 100644 index 0000000000..23fe78e356 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_process_arguments.c @@ -0,0 +1,238 @@ + +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_process_arguments.c + * @brief Testcase for HTTP URI arguments + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int ptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + const char *hdr; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&ptr != *unused) + { + *unused = &ptr; + return MHD_YES; + } + *unused = NULL; + hdr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "k"); + if ((hdr == NULL) || (0 != strcmp (hdr, "v x"))) + abort (); + hdr = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, "hash"); + if ((hdr == NULL) || (0 != strcmp (hdr, "#"))) + abort (); + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + if (ret == MHD_NO) + abort (); + return ret; +} + +static int +testExternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, + "http://localhost:21080/hello_world?k=v+x&hash=%23"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testExternalGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_process_headers.c b/lib/libmicrohttpd/src/testcurl/daemontest_process_headers.c new file mode 100644 index 0000000000..cd4bd68c08 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_process_headers.c @@ -0,0 +1,428 @@ + +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_process_headers.c + * @brief Testcase for HTTP header access + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +kv_cb (void *cls, enum MHD_ValueKind kind, const char *key, const char *value) +{ + if ((0 == strcmp (key, MHD_HTTP_HEADER_HOST)) && + (0 == strcmp (value, "localhost:21080")) && (kind == MHD_HEADER_KIND)) + { + *((int *) cls) = 1; + return MHD_NO; + } + return MHD_YES; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int ptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + const char *hdr; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&ptr != *unused) + { + *unused = &ptr; + return MHD_YES; + } + *unused = NULL; + ret = 0; + MHD_get_connection_values (connection, MHD_HEADER_KIND, &kv_cb, &ret); + if (ret != 1) + abort (); + hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "NotFound"); + if (hdr != NULL) + abort (); + hdr = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT); + if ((hdr == NULL) || (0 != strcmp (hdr, "*/*"))) + abort (); + hdr = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST); + if ((hdr == NULL) || (0 != strcmp (hdr, "localhost:21080"))) + abort (); + MHD_set_connection_value (connection, + MHD_HEADER_KIND, "FakeHeader", "NowPresent"); + hdr = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, "FakeHeader"); + if ((hdr == NULL) || (0 != strcmp (hdr, "NowPresent"))) + abort (); + + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + MHD_add_response_header (response, "MyHeader", "MyValue"); + hdr = MHD_get_response_header (response, "MyHeader"); + if (0 != strcmp ("MyValue", hdr)) + abort (); + MHD_add_response_header (response, "MyHeader", "MyValueToo"); + if (MHD_YES != MHD_del_response_header (response, "MyHeader", "MyValue")) + abort (); + hdr = MHD_get_response_header (response, "MyHeader"); + if (0 != strcmp ("MyValueToo", hdr)) + abort (); + if (1 != MHD_get_response_headers (response, NULL, NULL)) + abort (); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + if (ret == MHD_NO) + abort (); + return ret; +} + + +static int +testInternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:21080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 4; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 8; + return 0; +} + +static int +testMultithreadedGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:21080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testMultithreadedPoolGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 21080, NULL, NULL, &ahc_echo, "GET", + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:21080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + return 0; +} + +static int +testExternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 21080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:21080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalGet (); + errorCount += testMultithreadedGet (); + errorCount += testMultithreadedPoolGet (); + errorCount += testExternalGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_put.c b/lib/libmicrohttpd/src/testcurl/daemontest_put.c new file mode 100644 index 0000000000..76e9632075 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_put.c @@ -0,0 +1,432 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_put.c + * @brief Testcase for libmicrohttpd PUT operations + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) +{ + unsigned int *pos = ptr; + unsigned int wrt; + + wrt = size * nmemb; + if (wrt > 8 - (*pos)) + wrt = 8 - (*pos); + memcpy (stream, &("Hello123"[*pos]), wrt); + (*pos) += wrt; + return wrt; +} + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + int *done = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp ("PUT", method)) + return MHD_NO; /* unexpected method */ + if ((*done) == 0) + { + if (*upload_data_size != 8) + return MHD_YES; /* not yet ready */ + if (0 == memcmp (upload_data, "Hello123", 8)) + { + *upload_data_size = 0; + } + else + { + printf ("Invalid upload data `%8s'!\n", upload_data); + return MHD_NO; + } + *done = 1; + return MHD_YES; + } + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testInternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 4; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 8; + return 0; +} + +static int +testMultithreadedPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 1081, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + + return 0; +} + +static int +testMultithreadedPoolPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 1081, + NULL, NULL, &ahc_echo, &done_flag, + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + + return 0; +} + + +static int +testExternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + unsigned int pos = 0; + int done_flag = 0; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 1082, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPut (); + errorCount += testMultithreadedPut (); + errorCount += testMultithreadedPoolPut (); + errorCount += testExternalPut (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_put_chunked.c b/lib/libmicrohttpd/src/testcurl/daemontest_put_chunked.c new file mode 100644 index 0000000000..3fa1f09250 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_put_chunked.c @@ -0,0 +1,440 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_put_chunked.c + * @brief Testcase for libmicrohttpd PUT operations with chunked encoding + * for the upload data + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) +{ + unsigned int *pos = ptr; + unsigned int wrt; + + wrt = size * nmemb; + if (wrt > 8 - (*pos)) + wrt = 8 - (*pos); + if (wrt > 4) + wrt = 4; /* only send half at first => force multiple chunks! */ + memcpy (stream, &("Hello123"[*pos]), wrt); + (*pos) += wrt; + return wrt; +} + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + int *done = cls; + struct MHD_Response *response; + int ret; + int have; + + if (0 != strcmp ("PUT", method)) + return MHD_NO; /* unexpected method */ + if ((*done) < 8) + { + have = *upload_data_size; + if (have + *done > 8) + { + printf ("Invalid upload data `%8s'!\n", upload_data); + return MHD_NO; + } + if (0 == memcmp (upload_data, &"Hello123"[*done], have)) + { + *done += have; + *upload_data_size = 0; + } + else + { + printf ("Invalid upload data `%8s'!\n", upload_data); + return MHD_NO; + } +#if 0 + fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8); +#endif + return MHD_YES; + } + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testInternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 11080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 1; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + /* + // by not giving the file size, we force chunking! + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + */ + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 4; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 8; + return 0; +} + +static int +testMultithreadedPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 11081, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + /* + // by not giving the file size, we force chunking! + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + */ + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + + return 0; +} + +static int +testMultithreadedPoolPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 11081, + NULL, NULL, &ahc_echo, &done_flag, + MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + /* + // by not giving the file size, we force chunking! + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + */ + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + + return 0; +} + + +static int +testExternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + struct CURLMsg *msg; + time_t start; + struct timeval tv; + unsigned int pos = 0; + int done_flag = 0; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 11082, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 256; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + /* + // by not giving the file size, we force chunking! + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + */ + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + multi = curl_multi_init (); + if (multi == NULL) + { + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 512; + } + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (multi != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + msg = curl_multi_info_read (multi, &running); + if (msg == NULL) + break; + if (msg->msg == CURLMSG_DONE) + { + if (msg->data.result != CURLE_OK) + printf ("%s failed at %s:%d: `%s'\n", + "curl_multi_perform", + __FILE__, + __LINE__, curl_easy_strerror (msg->data.result)); + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + c = NULL; + multi = NULL; + } + } + MHD_run (d); + } + if (multi != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + curl_multi_cleanup (multi); + } + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 8192; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 16384; + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPut (); + errorCount += testMultithreadedPut (); + errorCount += testMultithreadedPoolPut (); + errorCount += testExternalPut (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testcurl/daemontest_termination.c b/lib/libmicrohttpd/src/testcurl/daemontest_termination.c new file mode 100644 index 0000000000..23c5358625 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/daemontest_termination.c @@ -0,0 +1,114 @@ +/* + This file is part of libmicrohttpd + (C) 2009 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_termination.c + * @brief Testcase for libmicrohttpd tolerating client not closing immediately + * @author hollosig + */ +#define PORT 12345 + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <microhttpd.h> +#include <unistd.h> +#include <curl/curl.h> + + +static int +connection_handler (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t * upload_data_size, + void **ptr) +{ + static int i; + + if (*ptr == NULL) + { + *ptr = &i; + return MHD_YES; + } + + if (*upload_data_size != 0) + { + (*upload_data_size) = 0; + return MHD_YES; + } + + struct MHD_Response *response = + MHD_create_response_from_data (strlen ("Response"), "Response", 0, 0); + int ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + + return ret; +} + +static size_t +write_data (void *ptr, size_t size, size_t nmemb, void *stream) +{ + return size * nmemb; +} + +int +main () +{ + struct MHD_Daemon *daemon; + + daemon = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + PORT, + NULL, + NULL, connection_handler, NULL, MHD_OPTION_END); + + if (daemon == NULL) + { + fprintf (stderr, "Daemon cannot be started!"); + exit (1); + } + + CURL *curl = curl_easy_init (); + //curl_easy_setopt(curl, CURLOPT_POST, 1L); + char url[255]; + sprintf (url, "http://localhost:%d", PORT); + curl_easy_setopt (curl, CURLOPT_URL, url); + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_data); + + CURLcode success = curl_easy_perform (curl); + if (success != 0) + { + fprintf (stderr, "CURL Error"); + exit (1); + } + /* CPU used to go crazy here */ + sleep (1); + + curl_easy_cleanup (curl); + MHD_stop_daemon (daemon); + + return 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/Makefile.am b/lib/libmicrohttpd/src/testcurl/https/Makefile.am new file mode 100644 index 0000000000..d707bda06c --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/Makefile.am @@ -0,0 +1,132 @@ +SUBDIRS = . + +if USE_COVERAGE + AM_CFLAGS = --coverage +endif + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https \ + -I$(top_srcdir)/src/daemon/https/tls \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/x509 \ + -I$(top_srcdir)/src/daemon \ + $(LIBCURL_CPPFLAGS) + +check_PROGRAMS = \ + tls_daemon_options_test \ + tls_authentication_test \ + mhds_multi_daemon_test \ + mhds_get_test \ + mhds_session_info_test \ + tls_thread_mode_test \ + tls_multi_thread_mode_test \ + tls_session_time_out_test \ + tls_cipher_change_test \ + tls_alert_test \ + tls_extension_test + +EXTRA_DIST = cert.pem key.pem tls_test_keys.h tls_test_common.h + +# tls_authentication_test currently fails for unknown reasons +TESTS = \ + tls_daemon_options_test \ + mhds_multi_daemon_test \ + mhds_get_test \ + mhds_session_info_test \ + tls_thread_mode_test \ + tls_multi_thread_mode_test \ + tls_session_time_out_test \ + tls_cipher_change_test \ + tls_alert_test \ + tls_extension_test \ + tls_authentication_test + +# cURL dependent tests +tls_extension_test_SOURCES = \ + tls_extension_test.c \ + tls_test_common.c +tls_extension_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_session_time_out_test_SOURCES = \ + tls_session_time_out_test.c \ + tls_test_common.c +tls_session_time_out_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_cipher_change_test_SOURCES = \ + tls_cipher_change_test.c \ + tls_test_common.c +tls_cipher_change_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_alert_test_SOURCES = \ + tls_alert_test.c \ + tls_test_common.c +tls_alert_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_daemon_options_test_SOURCES = \ + tls_daemon_options_test.c \ + tls_test_common.c +tls_daemon_options_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_thread_mode_test_SOURCES = \ + tls_thread_mode_test.c \ + tls_test_common.c +tls_thread_mode_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_multi_thread_mode_test_SOURCES = \ + tls_multi_thread_mode_test.c \ + tls_test_common.c +tls_multi_thread_mode_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_authentication_test_SOURCES = \ + tls_authentication_test.c \ + tls_test_common.c +tls_authentication_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +mhds_session_info_test_SOURCES = \ + mhds_session_info_test.c \ + tls_test_common.c +mhds_session_info_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +mhds_multi_daemon_test_SOURCES = \ + mhds_multi_daemon_test.c \ + tls_test_common.c +mhds_multi_daemon_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +mhds_get_test_SOURCES = \ + mhds_get_test.c \ + tls_test_common.c +mhds_get_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ diff --git a/lib/libmicrohttpd/src/testcurl/https/Makefile.in b/lib/libmicrohttpd/src/testcurl/https/Makefile.in new file mode 100644 index 0000000000..66e9a1cf17 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/Makefile.in @@ -0,0 +1,986 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = tls_daemon_options_test$(EXEEXT) \ + tls_authentication_test$(EXEEXT) \ + mhds_multi_daemon_test$(EXEEXT) mhds_get_test$(EXEEXT) \ + mhds_session_info_test$(EXEEXT) tls_thread_mode_test$(EXEEXT) \ + tls_multi_thread_mode_test$(EXEEXT) \ + tls_session_time_out_test$(EXEEXT) \ + tls_cipher_change_test$(EXEEXT) tls_alert_test$(EXEEXT) \ + tls_extension_test$(EXEEXT) +TESTS = tls_daemon_options_test$(EXEEXT) \ + mhds_multi_daemon_test$(EXEEXT) mhds_get_test$(EXEEXT) \ + mhds_session_info_test$(EXEEXT) tls_thread_mode_test$(EXEEXT) \ + tls_multi_thread_mode_test$(EXEEXT) \ + tls_session_time_out_test$(EXEEXT) \ + tls_cipher_change_test$(EXEEXT) tls_alert_test$(EXEEXT) \ + tls_extension_test$(EXEEXT) tls_authentication_test$(EXEEXT) +subdir = src/testcurl/https +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am_mhds_get_test_OBJECTS = mhds_get_test.$(OBJEXT) \ + tls_test_common.$(OBJEXT) +mhds_get_test_OBJECTS = $(am_mhds_get_test_OBJECTS) +mhds_get_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_mhds_multi_daemon_test_OBJECTS = mhds_multi_daemon_test.$(OBJEXT) \ + tls_test_common.$(OBJEXT) +mhds_multi_daemon_test_OBJECTS = $(am_mhds_multi_daemon_test_OBJECTS) +mhds_multi_daemon_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_mhds_session_info_test_OBJECTS = mhds_session_info_test.$(OBJEXT) \ + tls_test_common.$(OBJEXT) +mhds_session_info_test_OBJECTS = $(am_mhds_session_info_test_OBJECTS) +mhds_session_info_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_alert_test_OBJECTS = tls_alert_test.$(OBJEXT) \ + tls_test_common.$(OBJEXT) +tls_alert_test_OBJECTS = $(am_tls_alert_test_OBJECTS) +tls_alert_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_authentication_test_OBJECTS = \ + tls_authentication_test.$(OBJEXT) tls_test_common.$(OBJEXT) +tls_authentication_test_OBJECTS = \ + $(am_tls_authentication_test_OBJECTS) +tls_authentication_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_cipher_change_test_OBJECTS = tls_cipher_change_test.$(OBJEXT) \ + tls_test_common.$(OBJEXT) +tls_cipher_change_test_OBJECTS = $(am_tls_cipher_change_test_OBJECTS) +tls_cipher_change_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_daemon_options_test_OBJECTS = \ + tls_daemon_options_test.$(OBJEXT) tls_test_common.$(OBJEXT) +tls_daemon_options_test_OBJECTS = \ + $(am_tls_daemon_options_test_OBJECTS) +tls_daemon_options_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_extension_test_OBJECTS = tls_extension_test.$(OBJEXT) \ + tls_test_common.$(OBJEXT) +tls_extension_test_OBJECTS = $(am_tls_extension_test_OBJECTS) +tls_extension_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_multi_thread_mode_test_OBJECTS = \ + tls_multi_thread_mode_test.$(OBJEXT) tls_test_common.$(OBJEXT) +tls_multi_thread_mode_test_OBJECTS = \ + $(am_tls_multi_thread_mode_test_OBJECTS) +tls_multi_thread_mode_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_session_time_out_test_OBJECTS = \ + tls_session_time_out_test.$(OBJEXT) tls_test_common.$(OBJEXT) +tls_session_time_out_test_OBJECTS = \ + $(am_tls_session_time_out_test_OBJECTS) +tls_session_time_out_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_tls_thread_mode_test_OBJECTS = tls_thread_mode_test.$(OBJEXT) \ + tls_test_common.$(OBJEXT) +tls_thread_mode_test_OBJECTS = $(am_tls_thread_mode_test_OBJECTS) +tls_thread_mode_test_DEPENDENCIES = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(mhds_get_test_SOURCES) $(mhds_multi_daemon_test_SOURCES) \ + $(mhds_session_info_test_SOURCES) $(tls_alert_test_SOURCES) \ + $(tls_authentication_test_SOURCES) \ + $(tls_cipher_change_test_SOURCES) \ + $(tls_daemon_options_test_SOURCES) \ + $(tls_extension_test_SOURCES) \ + $(tls_multi_thread_mode_test_SOURCES) \ + $(tls_session_time_out_test_SOURCES) \ + $(tls_thread_mode_test_SOURCES) +DIST_SOURCES = $(mhds_get_test_SOURCES) \ + $(mhds_multi_daemon_test_SOURCES) \ + $(mhds_session_info_test_SOURCES) $(tls_alert_test_SOURCES) \ + $(tls_authentication_test_SOURCES) \ + $(tls_cipher_change_test_SOURCES) \ + $(tls_daemon_options_test_SOURCES) \ + $(tls_extension_test_SOURCES) \ + $(tls_multi_thread_mode_test_SOURCES) \ + $(tls_session_time_out_test_SOURCES) \ + $(tls_thread_mode_test_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + -I$(top_srcdir)/src/daemon/https \ + -I$(top_srcdir)/src/daemon/https/tls \ + -I$(top_srcdir)/src/daemon/https/lgl \ + -I$(top_srcdir)/src/daemon/https/x509 \ + -I$(top_srcdir)/src/daemon \ + $(LIBCURL_CPPFLAGS) + +EXTRA_DIST = cert.pem key.pem tls_test_keys.h tls_test_common.h + +# cURL dependent tests +tls_extension_test_SOURCES = \ + tls_extension_test.c \ + tls_test_common.c + +tls_extension_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_session_time_out_test_SOURCES = \ + tls_session_time_out_test.c \ + tls_test_common.c + +tls_session_time_out_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_cipher_change_test_SOURCES = \ + tls_cipher_change_test.c \ + tls_test_common.c + +tls_cipher_change_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_alert_test_SOURCES = \ + tls_alert_test.c \ + tls_test_common.c + +tls_alert_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_daemon_options_test_SOURCES = \ + tls_daemon_options_test.c \ + tls_test_common.c + +tls_daemon_options_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_thread_mode_test_SOURCES = \ + tls_thread_mode_test.c \ + tls_test_common.c + +tls_thread_mode_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_multi_thread_mode_test_SOURCES = \ + tls_multi_thread_mode_test.c \ + tls_test_common.c + +tls_multi_thread_mode_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +tls_authentication_test_SOURCES = \ + tls_authentication_test.c \ + tls_test_common.c + +tls_authentication_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +mhds_session_info_test_SOURCES = \ + mhds_session_info_test.c \ + tls_test_common.c + +mhds_session_info_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +mhds_multi_daemon_test_SOURCES = \ + mhds_multi_daemon_test.c \ + tls_test_common.c + +mhds_multi_daemon_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +mhds_get_test_SOURCES = \ + mhds_get_test.c \ + tls_test_common.c + +mhds_get_test_LDADD = \ + $(top_builddir)/src/testcurl/libcurl_version_check.a \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/testcurl/https/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/testcurl/https/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +mhds_get_test$(EXEEXT): $(mhds_get_test_OBJECTS) $(mhds_get_test_DEPENDENCIES) + @rm -f mhds_get_test$(EXEEXT) + $(LINK) $(mhds_get_test_OBJECTS) $(mhds_get_test_LDADD) $(LIBS) +mhds_multi_daemon_test$(EXEEXT): $(mhds_multi_daemon_test_OBJECTS) $(mhds_multi_daemon_test_DEPENDENCIES) + @rm -f mhds_multi_daemon_test$(EXEEXT) + $(LINK) $(mhds_multi_daemon_test_OBJECTS) $(mhds_multi_daemon_test_LDADD) $(LIBS) +mhds_session_info_test$(EXEEXT): $(mhds_session_info_test_OBJECTS) $(mhds_session_info_test_DEPENDENCIES) + @rm -f mhds_session_info_test$(EXEEXT) + $(LINK) $(mhds_session_info_test_OBJECTS) $(mhds_session_info_test_LDADD) $(LIBS) +tls_alert_test$(EXEEXT): $(tls_alert_test_OBJECTS) $(tls_alert_test_DEPENDENCIES) + @rm -f tls_alert_test$(EXEEXT) + $(LINK) $(tls_alert_test_OBJECTS) $(tls_alert_test_LDADD) $(LIBS) +tls_authentication_test$(EXEEXT): $(tls_authentication_test_OBJECTS) $(tls_authentication_test_DEPENDENCIES) + @rm -f tls_authentication_test$(EXEEXT) + $(LINK) $(tls_authentication_test_OBJECTS) $(tls_authentication_test_LDADD) $(LIBS) +tls_cipher_change_test$(EXEEXT): $(tls_cipher_change_test_OBJECTS) $(tls_cipher_change_test_DEPENDENCIES) + @rm -f tls_cipher_change_test$(EXEEXT) + $(LINK) $(tls_cipher_change_test_OBJECTS) $(tls_cipher_change_test_LDADD) $(LIBS) +tls_daemon_options_test$(EXEEXT): $(tls_daemon_options_test_OBJECTS) $(tls_daemon_options_test_DEPENDENCIES) + @rm -f tls_daemon_options_test$(EXEEXT) + $(LINK) $(tls_daemon_options_test_OBJECTS) $(tls_daemon_options_test_LDADD) $(LIBS) +tls_extension_test$(EXEEXT): $(tls_extension_test_OBJECTS) $(tls_extension_test_DEPENDENCIES) + @rm -f tls_extension_test$(EXEEXT) + $(LINK) $(tls_extension_test_OBJECTS) $(tls_extension_test_LDADD) $(LIBS) +tls_multi_thread_mode_test$(EXEEXT): $(tls_multi_thread_mode_test_OBJECTS) $(tls_multi_thread_mode_test_DEPENDENCIES) + @rm -f tls_multi_thread_mode_test$(EXEEXT) + $(LINK) $(tls_multi_thread_mode_test_OBJECTS) $(tls_multi_thread_mode_test_LDADD) $(LIBS) +tls_session_time_out_test$(EXEEXT): $(tls_session_time_out_test_OBJECTS) $(tls_session_time_out_test_DEPENDENCIES) + @rm -f tls_session_time_out_test$(EXEEXT) + $(LINK) $(tls_session_time_out_test_OBJECTS) $(tls_session_time_out_test_LDADD) $(LIBS) +tls_thread_mode_test$(EXEEXT): $(tls_thread_mode_test_OBJECTS) $(tls_thread_mode_test_DEPENDENCIES) + @rm -f tls_thread_mode_test$(EXEEXT) + $(LINK) $(tls_thread_mode_test_OBJECTS) $(tls_thread_mode_test_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mhds_get_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mhds_multi_daemon_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mhds_session_info_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_alert_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_authentication_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_cipher_change_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_daemon_options_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_extension_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_multi_thread_mode_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_session_time_out_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_test_common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_thread_mode_test.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/testcurl/https/cert.pem b/lib/libmicrohttpd/src/testcurl/https/cert.pem new file mode 100644 index 0000000000..2c766dff08 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICpjCCAZCgAwIBAgIESEPtjjALBgkqhkiG9w0BAQUwADAeFw0wODA2MDIxMjU0 +MzhaFw0wOTA2MDIxMjU0NDZaMAAwggEfMAsGCSqGSIb3DQEBAQOCAQ4AMIIBCQKC +AQC03TyUvK5HmUAirRp067taIEO4bibh5nqolUoUdo/LeblMQV+qnrv/RNAMTx5X +fNLZ45/kbM9geF8qY0vsPyQvP4jumzK0LOJYuIwmHaUm9vbXnYieILiwCuTgjaud +3VkZDoQ9fteIo+6we9UTpVqZpxpbLulBMh/VsvX0cPJ1VFC7rT59o9hAUlFf9jX/ +GmKdYI79MtgVx0OPBjmmSD6kicBBfmfgkO7bIGwlRtsIyMznxbHu6VuoX/eVxrTv +rmCwgEXLWRZ6ru8MQl5YfqeGXXRVwMeXU961KefbuvmEPccgCxm8FZ1C1cnDHFXh +siSgAzMBjC/b6KVhNQ4KnUdZAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0O +BBYEFJcUvpjvE5fF/yzUshkWDpdYiQh/MAsGCSqGSIb3DQEBBQOCAQEARP7eKSB2 +RNd6XjEjK0SrxtoTnxS3nw9sfcS7/qD1+XHdObtDFqGNSjGYFB3Gpx8fpQhCXdoN +8QUs3/5ZVa5yjZMQewWBgz8kNbnbH40F2y81MHITxxCe1Y+qqHWwVaYLsiOTqj2/ +0S3QjEJ9tvklmg7JX09HC4m5QRYfWBeQLD1u8ZjA1Sf1xJriomFVyRLI2VPO2bNe +JDMXWuP+8kMC7gEvUnJ7A92Y2yrhu3QI3bjPk8uSpHea19Q77tul1UVBJ5g+zpH3 +OsF5p0MyaVf09GTzcLds5nE/osTdXGUyHJapWReVmPm3Zn6gqYlnzD99z+DPIgIV +RhZvQx74NQnS6g== +-----END CERTIFICATE----- diff --git a/lib/libmicrohttpd/src/testcurl/https/key.pem b/lib/libmicrohttpd/src/testcurl/https/key.pem new file mode 100644 index 0000000000..a5848eed9b --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAtN08lLyuR5lAIq0adOu7WiBDuG4m4eZ6qJVKFHaPy3m5TEFf +qp67/0TQDE8eV3zS2eOf5GzPYHhfKmNL7D8kLz+I7psytCziWLiMJh2lJvb2152I +niC4sArk4I2rnd1ZGQ6EPX7XiKPusHvVE6VamacaWy7pQTIf1bL19HDydVRQu60+ +faPYQFJRX/Y1/xpinWCO/TLYFcdDjwY5pkg+pInAQX5n4JDu2yBsJUbbCMjM58Wx +7ulbqF/3lca0765gsIBFy1kWeq7vDEJeWH6nhl10VcDHl1PetSnn27r5hD3HIAsZ +vBWdQtXJwxxV4bIkoAMzAYwv2+ilYTUOCp1HWQIDAQABAoIBAArOQv3R7gmqDspj +lDaTFOz0C4e70QfjGMX0sWnakYnDGn6DU19iv3GnX1S072ejtgc9kcJ4e8VUO79R +EmqpdRR7k8dJr3RTUCyjzf/C+qiCzcmhCFYGN3KRHA6MeEnkvRuBogX4i5EG1k5l +/5t+YBTZBnqXKWlzQLKoUAiMLPg0eRWh+6q7H4N7kdWWBmTpako7TEqpIwuEnPGx +u3EPuTR+LN6lF55WBePbCHccUHUQaXuav18NuDkcJmCiMArK9SKb+h0RqLD6oMI/ +dKD6n8cZXeMBkK+C8U/K0sN2hFHACsu30b9XfdnljgP9v+BP8GhnB0nCB6tNBCPo +32srOwECgYEAxWh3iBT4lWqL6bZavVbnhmvtif4nHv2t2/hOs/CAq8iLAw0oWGZc ++JEZTUDMvFRlulr0kcaWra+4fN3OmJnjeuFXZq52lfMgXBIKBmoSaZpIh2aDY1Rd +RbEse7nQl9hTEPmYspiXLGtnAXW7HuWqVfFFP3ya8rUS3t4d07Hig8ECgYEA6ou6 +OHiBRTbtDqLIv8NghARc/AqwNWgEc9PelCPe5bdCOLBEyFjqKiT2MttnSSUc2Zob +XhYkHC6zN1Mlq30N0e3Q61YK9LxMdU1vsluXxNq2rfK1Scb1oOlOOtlbV3zA3VRF +hV3t1nOA9tFmUrwZi0CUMWJE/zbPAyhwWotKyZkCgYEAh0kFicPdbABdrCglXVae +SnfSjVwYkVuGd5Ze0WADvjYsVkYBHTvhgRNnRJMg+/vWz3Sf4Ps4rgUbqK8Vc20b +AU5G6H6tlCvPRGm0ZxrwTWDHTcuKRVs+pJE8C/qWoklE/AAhjluWVoGwUMbPGuiH +6Gf1bgHF6oj/Sq7rv/VLZ8ECgYBeq7ml05YyLuJutuwa4yzQ/MXfghzv4aVyb0F3 +QCdXR6o2IYgR6jnSewrZKlA9aPqFJrwHNR6sNXlnSmt5Fcf/RWO/qgJQGLUv3+rG +7kuLTNDR05azSdiZc7J89ID3Bkb+z2YkV+6JUiPq/Ei1+nDBEXb/m+/HqALU/nyj +P3gXeQKBgBusb8Rbd+KgxSA0hwY6aoRTPRt8LNvXdsB9vRcKKHUFQvxUWiUSS+L9 +/Qu1sJbrUquKOHqksV5wCnWnAKyJNJlhHuBToqQTgKXjuNmVdYSe631saiI7PHyC +eRJ6DxULPxABytJrYCRrNqmXi5TCiqR2mtfalEMOPxz8rUU8dYyx +-----END RSA PRIVATE KEY----- diff --git a/lib/libmicrohttpd/src/testcurl/https/mhds_get_test.c b/lib/libmicrohttpd/src/testcurl/https/mhds_get_test.c new file mode 100644 index 0000000000..ce0fcbda4e --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/mhds_get_test.c @@ -0,0 +1,136 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_get_test.c + * @brief Testcase for libmicrohttpd HTTPS GET operations + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" + +#include <limits.h> +#include <sys/stat.h> + +#include "gnutls.h" +#include <curl/curl.h> + +#include "tls_test_common.h" + +int curl_check_version (const char *req_version, ...); +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; +extern const char srv_signed_cert_pem[]; +extern const char srv_signed_key_pem[]; + +static int +test_cipher_option (FILE * test_fd, char *cipher_suite, int proto_version) +{ + + int ret; + int ciper[] = { MHD_GNUTLS_CIPHER_3DES_CBC, 0 }; + struct MHD_Daemon *d; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, 42433, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_CIPHER_ALGORITHM, ciper, MHD_OPTION_END); + + if (d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + ret = test_https_transfer (test_fd, cipher_suite, proto_version); + + MHD_stop_daemon (d); + return ret; +} + +/* perform a HTTP GET request via SSL/TLS */ +int +test_secure_get (FILE * test_fd, char *cipher_suite, int proto_version) +{ + int ret; + struct MHD_Daemon *d; + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, 42433, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem, + MHD_OPTION_END); + + if (d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + ret = test_https_transfer (test_fd, cipher_suite, proto_version); + + MHD_stop_daemon (d); + return ret; +} + +int +main (int argc, char *const *argv) +{ + FILE *test_fd; + unsigned int errorCount = 0; + + /* gnutls_global_set_log_level(11); */ + + if (curl_check_version (MHD_REQ_CURL_VERSION, MHD_REQ_CURL_OPENSSL_VERSION)) + { + return -1; + } + + if ((test_fd = setup_test_file ()) == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error: %s\n", strerror (errno)); + fclose (test_fd); + return -1; + } + + errorCount += + test_secure_get (test_fd, "AES256-SHA", CURL_SSLVERSION_TLSv1); + errorCount += + test_secure_get (test_fd, "AES256-SHA", CURL_SSLVERSION_SSLv3); + errorCount += + test_cipher_option (test_fd, "DES-CBC3-SHA", CURL_SSLVERSION_TLSv1); + + print_test_result (errorCount, argv[0]); + + curl_global_cleanup (); + fclose (test_fd); + remove (TEST_FILE_NAME); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/mhds_multi_daemon_test.c b/lib/libmicrohttpd/src/testcurl/https/mhds_multi_daemon_test.c new file mode 100644 index 0000000000..7b9d0fe696 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/mhds_multi_daemon_test.c @@ -0,0 +1,226 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_multi_daemon_test.c + * @brief Testcase for libmicrohttpd multiple HTTPS daemon scenario + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include <curl/curl.h> +#include <limits.h> +#include <sys/stat.h> + +#include "tls_test_common.h" + +extern int curl_check_version (const char *req_version, ...); +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +/* TODO mv to common */ +/** + * perform cURL request for file + * @param test_fd: file to attempt transferring + */ +static int +test_daemon_get (FILE * test_fd, char *cipher_suite, int proto_version, + int port) +{ + CURL *c; + struct CBC cbc; + CURLcode errornum; + char url[255]; + size_t len; + struct stat file_stat; + + stat (TEST_FILE_NAME, &file_stat); + len = file_stat.st_size; + + /* used to memcmp local copy & deamon supplied copy */ + unsigned char *mem_test_file_local; + + mem_test_file_local = malloc (len); + fseek (test_fd, 0, SEEK_SET); + if (fread (mem_test_file_local, sizeof (char), len, test_fd) != len) + { + fprintf (stderr, "Error: failed to read test file. %s\n", + strerror (errno)); + free (mem_test_file_local); + return -1; + } + + if (NULL == (cbc.buf = malloc (sizeof (char) * len))) + { + fprintf (stderr, "Error: failed to read test file. %s\n", + strerror (errno)); + free (mem_test_file_local); + return -1; + } + cbc.size = len; + cbc.pos = 0; + + if (gen_test_file_url (url, port)) + { + free (mem_test_file_local); + free (cbc.buf); + return -1; + } + + c = curl_easy_init (); +#if DEBUG_HTTPS_TEST + curl_easy_setopt (c, CURLOPT_VERBOSE, 1); +#endif + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_FILE, &cbc); + + /* TLS options */ + curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version); + curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); + + /* currently skip any peer authentication */ + curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); + + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + free (mem_test_file_local); + free (cbc.buf); + return errornum; + } + + curl_easy_cleanup (c); + + /* compare received file and local reference */ + if (memcmp (cbc.buf, mem_test_file_local, len) != 0) + { + fprintf (stderr, "Error: local file & received file differ.\n"); + free (mem_test_file_local); + free (cbc.buf); + return -1; + } + + free (mem_test_file_local); + free (cbc.buf); + return 0; +} + +/* + * assert initiating two separate daemons and having one shut down + * doesn't affect the other + */ +int +test_concurent_daemon_pair (FILE * test_fd, char *cipher_suite, + int proto_version) +{ + + int ret; + struct MHD_Daemon *d1; + struct MHD_Daemon *d2; + d1 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + + if (d1 == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + d2 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT + 1, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + + if (d2 == NULL) + { + MHD_stop_daemon (d1); + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + ret = + test_daemon_get (test_fd, cipher_suite, proto_version, DEAMON_TEST_PORT); + ret += + test_daemon_get (test_fd, cipher_suite, proto_version, + DEAMON_TEST_PORT + 1); + + MHD_stop_daemon (d2); + ret += + test_daemon_get (test_fd, cipher_suite, proto_version, DEAMON_TEST_PORT); + MHD_stop_daemon (d1); + return ret; +} + +int +main (int argc, char *const *argv) +{ + FILE *test_fd; + unsigned int errorCount = 0; + + if (curl_check_version (MHD_REQ_CURL_VERSION)) + { + return -1; + } + + if ((test_fd = setup_test_file ()) == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error (code: %u). l:%d f:%s\n", errorCount, __LINE__, + __FUNCTION__); + fclose (test_fd); + return -1; + } + + errorCount += + test_concurent_daemon_pair (test_fd, "AES256-SHA", CURL_SSLVERSION_SSLv3); + + print_test_result (errorCount, "concurent_daemon_pair"); + + curl_global_cleanup (); + fclose (test_fd); + + remove (TEST_FILE_NAME); + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/mhds_session_info_test.c b/lib/libmicrohttpd/src/testcurl/https/mhds_session_info_test.c new file mode 100644 index 0000000000..da0c2cdde1 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/mhds_session_info_test.c @@ -0,0 +1,172 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_session_info_test.c + * @brief Testcase for libmicrohttpd HTTPS connection querying operations + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include <curl/curl.h> + +#include "tls_test_common.h" + +extern int curl_check_version (const char *req_version, ...); +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +struct MHD_Daemon *d; + +/* + * HTTP access handler call back + * used to query negotiated security parameters + */ +static int +query_session_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, + const char *upload_data, const char *version, + size_t *upload_data_size, void **ptr) +{ + struct MHD_Response *response; + int ret; + + /* assert actual connection cipher is the one negotiated */ + if (MHD_get_connection_info + (connection, + MHD_CONNECTION_INFO_CIPHER_ALGO)->cipher_algorithm != + MHD_GNUTLS_CIPHER_AES_256_CBC) + { + fprintf (stderr, "Error: requested cipher mismatch. %s\n", + strerror (errno)); + return -1; + } + + if (MHD_get_connection_info + (connection, + MHD_CONNECTION_INFO_PROTOCOL)->protocol != MHD_GNUTLS_PROTOCOL_SSL3) + { + fprintf (stderr, "Error: requested compression mismatch. %s\n", + strerror (errno)); + return -1; + } + + response = MHD_create_response_from_data (strlen (EMPTY_PAGE), + (void *) EMPTY_PAGE, + MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +/* + * negotiate a secure connection with server & query negotiated security parameters + */ +static int +test_query_session () +{ + CURL *c; + struct CBC cbc; + CURLcode errornum; + char url[256]; + + if (NULL == (cbc.buf = malloc (sizeof (char) * 255))) + return 16; + cbc.size = 255; + cbc.pos = 0; + + gen_test_file_url (url, DEAMON_TEST_PORT); + + /* setup test */ + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT, + NULL, NULL, &query_session_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + + if (d == NULL) + return 2; + + c = curl_easy_init (); +#if DEBUG_HTTPS_TEST + curl_easy_setopt (c, CURLOPT_VERBOSE, 1); +#endif + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_FILE, &cbc); + /* TLS options */ + curl_easy_setopt (c, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); + curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, "AES256-SHA"); + /* currently skip any peer authentication */ + curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); + + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + + MHD_stop_daemon (d); + curl_easy_cleanup (c); + free (cbc.buf); + return -1; + } + + MHD_stop_daemon (d); + curl_easy_cleanup (c); + free (cbc.buf); + return 0; +} + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + if (curl_check_version (MHD_REQ_CURL_VERSION)) + { + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error (code: %u)\n", errorCount); + return -1; + } + + errorCount += test_query_session (); + + print_test_result (errorCount, argv[0]); + + curl_global_cleanup (); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_alert_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_alert_test.c new file mode 100644 index 0000000000..b9d0810088 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_alert_test.c @@ -0,0 +1,187 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_get_test.c + * @brief: daemon TLS alert response test-case + * + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include "gnutls_int.h" +#include "gnutls_datum.h" +#include "gnutls_record.h" + +#include "tls_test_common.h" +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +/* + * assert server closes connection upon receiving a + * close notify alert message. + * + * @param session: an initialized TLS session + */ +static int +test_alert_close_notify (MHD_gtls_session_t session) +{ + int sd, ret; + struct sockaddr_in sa; + + sd = socket (AF_INET, SOCK_STREAM, 0); + if (sd == -1) + { + fprintf (stderr, "Failed to create socket: %s\n", strerror (errno)); + return -1; + } + + memset (&sa, '\0', sizeof (struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = htons (DEAMON_TEST_PORT); + inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr); + + MHD__gnutls_transport_set_ptr (session, (MHD_gnutls_transport_ptr_t) (long) sd); + + ret = connect (sd, &sa, sizeof (struct sockaddr_in)); + + if (ret < 0) + { + fprintf (stderr, "%s\n", MHD_E_FAILED_TO_CONNECT); + return -1; + } + + ret = MHD__gnutls_handshake (session); + if (ret < 0) + { + return -1; + } + + MHD__gnutls_alert_send (session, GNUTLS_AL_FATAL, GNUTLS_A_CLOSE_NOTIFY); + + /* check server responds with a 'close-notify' */ + MHD_gtls_recv_int (session, GNUTLS_ALERT, GNUTLS_HANDSHAKE_FINISHED, 0, 0); + + close (sd); + /* CLOSE_NOTIFY */ + if (session->internals.last_alert != GNUTLS_A_CLOSE_NOTIFY) + { + return -1; + } + + return 0; +} + +/* + * assert server closes connection upon receiving a + * fatal unexpected_message alert. + * + * @param session: an initialized TLS session + */ +static int +test_alert_unexpected_message (MHD_gtls_session_t session) +{ + int sd, ret; + struct sockaddr_in sa; + + sd = socket (AF_INET, SOCK_STREAM, 0); + if (sd == -1) + { + fprintf (stderr, "Failed to create socket: %s\n", strerror (errno)); + return -1; + } + memset (&sa, '\0', sizeof (struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = htons (DEAMON_TEST_PORT); + inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr); + + MHD__gnutls_transport_set_ptr (session, + (MHD_gnutls_transport_ptr_t) ((void *) (long) sd)); + + ret = connect (sd, &sa, sizeof (struct sockaddr_in)); + + if (ret < 0) + { + fprintf (stderr, "%s\n", MHD_E_FAILED_TO_CONNECT); + return -1; + } + + ret = MHD__gnutls_handshake (session); + if (ret < 0) + { + return -1; + } + + MHD__gnutls_alert_send (session, GNUTLS_AL_FATAL, + GNUTLS_A_UNEXPECTED_MESSAGE); + usleep (100); + + /* TODO better RST trigger */ + if (send (sd, "", 1, 0) == 0) + { + return -1; + } + + close (sd); + return 0; +} + +int +main (int argc, char *const *argv) +{ + int errorCount = 0;; + struct MHD_Daemon *d; + MHD_gtls_session_t session; + MHD_gnutls_datum_t key; + MHD_gnutls_datum_t cert; + MHD_gtls_cert_credentials_t xcred; + + MHD__gnutls_global_init (); + MHD_gtls_global_set_log_level (11); + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT, + NULL, NULL, &http_dummy_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + + if (d == NULL) + { + fprintf (stderr, "%s\n", MHD_E_SERVER_INIT); + return -1; + } + + setup_session (&session, &key, &cert, &xcred); + errorCount += test_alert_close_notify (session); + teardown_session (session, &key, &cert, xcred); + + setup_session (&session, &key, &cert, &xcred); + errorCount += test_alert_unexpected_message (session); + teardown_session (session, &key, &cert, xcred); + + print_test_result (errorCount, argv[0]); + + MHD_stop_daemon (d); + MHD__gnutls_global_deinit (); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_authentication_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_authentication_test.c new file mode 100644 index 0000000000..9fe7318d2f --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_authentication_test.c @@ -0,0 +1,237 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file tls_authentication_test.c + * @brief Testcase for libmicrohttpd HTTPS GET operations + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include <curl/curl.h> +#include <limits.h> +#include <sys/stat.h> + +#include "tls_test_common.h" + +extern int curl_check_version (const char *req_version, ...); +extern const char test_file_data[]; + +extern const char ca_key_pem[]; +extern const char ca_cert_pem[]; +extern const char srv_signed_cert_pem[]; +extern const char srv_signed_key_pem[]; + +const char *ca_cert_file_name = "tmp_ca_cert.pem"; + +/* + * test HTTPS transfer + * @param test_fd: file to attempt transfering + */ +static int +test_daemon_get (FILE * test_fd, char *cipher_suite, int proto_version) +{ + CURL *c; + struct CBC cbc; + CURLcode errornum; + char url[255]; + struct stat statb; + + stat (TEST_FILE_NAME, &statb); + + int len = statb.st_size; + + /* used to memcmp local copy & deamon supplied copy */ + unsigned char *mem_test_file_local; + + if (NULL == (mem_test_file_local = malloc (len))) + { + fprintf (stderr, MHD_E_MEM); + return -1; + } + + fseek (test_fd, 0, SEEK_SET); + if (fread (mem_test_file_local, sizeof (char), len, test_fd) != len) + { + fprintf (stderr, "Error: failed to read test file. %s\n", + strerror (errno)); + free (mem_test_file_local); + return -1; + } + + if (NULL == (cbc.buf = malloc (sizeof (char) * len))) + { + fprintf (stderr, MHD_E_MEM); + free (mem_test_file_local); + return -1; + } + cbc.size = len; + cbc.pos = 0; + + /* construct url - this might use doc_path */ + gen_test_file_url (url, DEAMON_TEST_PORT); + + c = curl_easy_init (); +#if DEBUG_HTTPS_TEST + curl_easy_setopt (c, CURLOPT_VERBOSE, 1); +#endif + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 10L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 10L); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_FILE, &cbc); + + /* TLS options */ + curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version); + curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); + + /* perform peer authentication */ + /* TODO merge into send_curl_req */ + curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 1); + curl_easy_setopt (c, CURLOPT_CAINFO, ca_cert_file_name); + curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); + + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + free (mem_test_file_local); + free (cbc.buf); + return errornum; + } + + curl_easy_cleanup (c); + + if (memcmp (cbc.buf, mem_test_file_local, len) != 0) + { + fprintf (stderr, "Error: local file & received file differ.\n"); + free (cbc.buf); + free (mem_test_file_local); + return -1; + } + + free (mem_test_file_local); + free (cbc.buf); + return 0; +} + +/* perform a HTTP GET request via SSL/TLS */ +static int +test_secure_get (FILE * test_fd, char *cipher_suite, int proto_version) +{ + int ret; + struct MHD_Daemon *d; + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem, + MHD_OPTION_END); + + if (d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + ret = test_daemon_get (test_fd, cipher_suite, proto_version); + + MHD_stop_daemon (d); + return ret; +} + +static FILE * +setup_ca_cert () +{ + FILE *cert_fd; + + if (NULL == (cert_fd = fopen (ca_cert_file_name, "wb+"))) + { + fprintf (stderr, "Error: failed to open `%s': %s\n", + ca_cert_file_name, strerror (errno)); + return NULL; + } + if (fwrite (ca_cert_pem, sizeof (char), strlen (ca_cert_pem), cert_fd) + != strlen (ca_cert_pem)) + { + fprintf (stderr, "Error: failed to write `%s. %s'\n", + ca_cert_file_name, strerror (errno)); + fclose (cert_fd); + return NULL; + } + if (fflush (cert_fd)) + { + fprintf (stderr, "Error: failed to flush ca cert file stream. %s\n", + strerror (errno)); + fclose (cert_fd); + return NULL; + } + + return cert_fd; +} + +int +main (int argc, char *const *argv) +{ + FILE *test_fd; + unsigned int errorCount = 0; + + if (curl_check_version (MHD_REQ_CURL_VERSION)) + { + return -1; + } + + if ((test_fd = setup_test_file ()) == NULL || setup_ca_cert () == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error (code: %u)\n", errorCount); + fclose (test_fd); + return -1; + } + + errorCount += + test_secure_get (test_fd, "AES256-SHA", CURL_SSLVERSION_TLSv1); + + print_test_result (errorCount, argv[0]); + + curl_global_cleanup (); + fclose (test_fd); + + remove (TEST_FILE_NAME); + remove (ca_cert_file_name); + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_cipher_change_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_cipher_change_test.c new file mode 100644 index 0000000000..48ba50de91 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_cipher_change_test.c @@ -0,0 +1,154 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_get_test.c + * @brief: daemon TLS cipher change message test-case + * + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include "internal.h" +#include "gnutls_int.h" +#include "gnutls_datum.h" +#include "gnutls_record.h" + +#include "tls_test_common.h" +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +char *http_get_req = "GET / HTTP/1.1\r\n\r\n"; + +/* HTTP access handler call back */ +static int +rehandshake_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, size_t *upload_data_size, + void **ptr) +{ + int ret; + /* server side re-handshake request */ + ret = MHD__gnutls_rehandshake (connection->tls_session); + + if (ret < 0) + { + fprintf (stderr, "Error: %s. f: %s, l: %d\n", + "server failed to send Hello Request", __FUNCTION__, __LINE__); + } + + return 0; +} + +/* + * Cipher change message should only occur while negotiating + * the SSL/TLS handshake. + * Test server disconnects upon receiving an out of context + * message. + * + * @param session: initiallized TLS session + */ +static int +test_out_of_context_cipher_change (MHD_gtls_session_t session) +{ + int sd, ret; + struct sockaddr_in sa; + + sd = socket (AF_INET, SOCK_STREAM, 0); + if (sd == -1) + { + fprintf (stderr, "Failed to create socket: %s\n", strerror (errno)); + return -1; + } + + memset (&sa, '\0', sizeof (struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = htons (DEAMON_TEST_PORT); + inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr); + + MHD__gnutls_transport_set_ptr (session, (MHD_gnutls_transport_ptr_t) (long) sd); + + ret = connect (sd, &sa, sizeof (struct sockaddr_in)); + + if (ret < 0) + { + fprintf (stderr, "%s\n", MHD_E_FAILED_TO_CONNECT); + return -1; + } + + ret = MHD__gnutls_handshake (session); + if (ret < 0) + { + return -1; + } + + /* send an out of context cipher change spec */ + MHD_gtls_send_change_cipher_spec (session, 0); + + + /* assert server has closed connection */ + /* TODO better RST trigger */ + if (send (sd, "", 1, 0) == 0) + { + return -1; + } + + close (sd); + return 0; +} + +int +main (int argc, char *const *argv) +{ + int errorCount = 0;; + struct MHD_Daemon *d; + MHD_gtls_session_t session; + MHD_gnutls_datum_t key; + MHD_gnutls_datum_t cert; + MHD_gtls_cert_credentials_t xcred; + + MHD__gnutls_global_init (); + MHD_gtls_global_set_log_level (11); + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT, + NULL, NULL, &rehandshake_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + + if (d == NULL) + { + fprintf (stderr, "%s\n", MHD_E_SERVER_INIT); + return -1; + } + + setup_session (&session, &key, &cert, &xcred); + errorCount += test_out_of_context_cipher_change (session); + teardown_session (session, &key, &cert, xcred); + + print_test_result (errorCount, argv[0]); + + MHD_stop_daemon (d); + MHD__gnutls_global_deinit (); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_daemon_options_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_daemon_options_test.c new file mode 100644 index 0000000000..d7b29b083f --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_daemon_options_test.c @@ -0,0 +1,182 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file tls_daemon_options_test.c + * @brief Testcase for libmicrohttpd HTTPS GET operations + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include <sys/stat.h> +#include <limits.h> +#include "gnutls.h" + +#include "tls_test_common.h" + +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +int curl_check_version (const char *req_version, ...); + +/** + * test server refuses to negotiate connections with unsupported protocol versions + * + */ +/* TODO rm test_fd */ +static int +test_unmatching_ssl_version (FILE * test_fd, char *cipher_suite, + int curl_req_ssl_version) +{ + struct CBC cbc; + if (NULL == (cbc.buf = malloc (sizeof (char) * 256))) + { + fprintf (stderr, "Error: failed to allocate: %s\n", + strerror (errno)); + return -1; + } + cbc.size = 256; + cbc.pos = 0; + + char url[255]; + if (gen_test_file_url (url, DEAMON_TEST_PORT)) + { + free (cbc.buf); + return -1; + } + + /* assert daemon *rejected* request */ + if (CURLE_OK == + send_curl_req (url, &cbc, cipher_suite, curl_req_ssl_version)) + { + free (cbc.buf); + return -1; + } + + free (cbc.buf); + return 0; +} + +/* setup a temporary transfer test file */ +int +main (int argc, char *const *argv) +{ + FILE *test_fd; + unsigned int errorCount = 0; + unsigned int cpos; + char test_name[64]; + + int daemon_flags = + MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | MHD_USE_DEBUG; + + if (curl_check_version (MHD_REQ_CURL_VERSION)) + { + return -1; + } + + if ((test_fd = setup_test_file ()) == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fclose (test_fd); + remove (TEST_FILE_NAME); + fprintf (stderr, "Error: %s\n", strerror (errno)); + return -1; + } + + int p_ssl3[] = { MHD_GNUTLS_PROTOCOL_SSL3, 0 }; + int p_tls[] = { MHD_GNUTLS_PROTOCOL_TLS1_2, + MHD_GNUTLS_PROTOCOL_TLS1_1, + MHD_GNUTLS_PROTOCOL_TLS1_0, 0 + }; + + struct CipherDef ciphers[] = { + {{MHD_GNUTLS_CIPHER_AES_128_CBC, 0}, "AES128-SHA"}, + {{MHD_GNUTLS_CIPHER_ARCFOUR_128, 0}, "RC4-SHA"}, + {{MHD_GNUTLS_CIPHER_3DES_CBC, 0}, "3DES-SHA"}, + {{MHD_GNUTLS_CIPHER_AES_256_CBC, 0}, "AES256-SHA"}, + {{0, 0}, NULL} + }; + fprintf (stderr, "SHA/TLS tests:\n"); + cpos = 0; + while (ciphers[cpos].curlname != NULL) + { + sprintf (test_name, "%s-TLS", ciphers[cpos].curlname); + errorCount += + test_wrap (test_name, + &test_https_transfer, test_fd, daemon_flags, + ciphers[cpos].curlname, + CURL_SSLVERSION_TLSv1, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_PROTOCOL_VERSION, p_tls, + MHD_OPTION_CIPHER_ALGORITHM, ciphers[cpos].options, + MHD_OPTION_END); + cpos++; + } + fprintf (stderr, "SHA/SSL3 tests:\n"); + cpos = 0; + while (ciphers[cpos].curlname != NULL) + { + sprintf (test_name, "%s-SSL3", ciphers[cpos].curlname); + errorCount += + test_wrap (test_name, + &test_https_transfer, test_fd, daemon_flags, + ciphers[cpos].curlname, + CURL_SSLVERSION_SSLv3, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_PROTOCOL_VERSION, p_ssl3, + MHD_OPTION_CIPHER_ALGORITHM, ciphers[cpos].options, + MHD_OPTION_END); + cpos++; + } +#if 0 + /* manual inspection of the handshake suggests that CURL will + request TLSv1, we send back "SSL3" and CURL takes it *despite* + being configured to speak SSL3-only. Notably, the other way + round (have curl request SSL3, respond with TLSv1 only) + is properly refused by CURL. Either way, this does NOT seem + to be a bug in MHD/gnuTLS but rather in CURL; hence this + test is commented out here... */ + errorCount += + test_wrap ("unmatching version: SSL3 vs. TLS", &test_unmatching_ssl_version, + test_fd, daemon_flags, "AES256-SHA", CURL_SSLVERSION_TLSv1, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_PROTOCOL_VERSION, p_ssl3, MHD_OPTION_END); +#endif + errorCount += + test_wrap ("unmatching version: TLS vs. SSL3", &test_unmatching_ssl_version, + test_fd, daemon_flags, "AES256-SHA", CURL_SSLVERSION_SSLv3, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_PROTOCOL_VERSION, p_tls, MHD_OPTION_END); + curl_global_cleanup (); + fclose (test_fd); + remove (TEST_FILE_NAME); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_extension_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_extension_test.c new file mode 100644 index 0000000000..84ed374f3a --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_extension_test.c @@ -0,0 +1,276 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file tls_extension_test.c + * @brief: test daemon response to TLS client hello requests containing extensions + * + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include "gnutls_int.h" +#include "gnutls_handshake.h" // MHD_gtls_send_handshake +#include "gnutls_num.h" // MHD_gtls_write_x +#include "common.h" // MHD_gtls_version_x + + +#include "tls_test_common.h" +#define MAX_EXT_DATA_LENGTH 256 + +extern int +MHD__gnutls_copy_ciphersuites (MHD_gtls_session_t session, + opaque * ret_data, size_t ret_data_size); + +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +/** + * Test daemon response to TLS client hello requests containing extensions + * + * @param session + * @param exten_t - the type of extension being appended to client hello request + * @param ext_count - the number of consecutive extension replicas inserted into request + * @param ext_length - the length of each appended extension + * @return 0 on successful test completion, -1 otherwise + */ +static int +test_hello_extension (MHD_gtls_session_t session, extensions_t exten_t, + int ext_count, int ext_length) +{ + int i, sd, ret = 0, pos = 0; + int exten_data_len, ciphersuite_len, datalen; + struct sockaddr_in sa; + char url[255]; + opaque *data = NULL; + uint8_t session_id_len = 0; + opaque rnd[TLS_RANDOM_SIZE]; + opaque extdata[MAX_EXT_DATA_LENGTH]; + + /* single, null compression */ + unsigned char comp[] = { 0x01, 0x00 }; + struct CBC cbc; + + sd = -1; + memset (&cbc, 0, sizeof (struct CBC)); + if (NULL == (cbc.buf = malloc (sizeof (char) * 256))) + { + fprintf (stderr, MHD_E_MEM); + ret = -1; + goto cleanup; + } + cbc.size = 256; + + sd = socket (AF_INET, SOCK_STREAM, 0); + if (sd == -1) + { + fprintf(stderr, "Failed to create socket: %s\n", strerror(errno)); + free (cbc.buf); + return -1; + } + memset (&sa, '\0', sizeof (struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = htons (DEAMON_TEST_PORT); + inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr); + + enum MHD_GNUTLS_Protocol hver; + + /* init hash functions */ + session->internals.handshake_mac_handle_md5 = + MHD_gtls_hash_init (MHD_GNUTLS_MAC_MD5); + session->internals.handshake_mac_handle_sha = + MHD_gtls_hash_init (MHD_GNUTLS_MAC_SHA1); + + /* version = 2 , random = [4 for unix time + 28 for random bytes] */ + datalen = 2 /* version */ + TLS_RANDOM_SIZE + (session_id_len + 1); + + data = MHD_gnutls_malloc (datalen); + + hver = MHD_gtls_version_max (session); + data[pos++] = MHD_gtls_version_get_major (hver); + data[pos++] = MHD_gtls_version_get_minor (hver); + + /* Set the version we advertise as maximum (RSA uses it). */ + set_adv_version (session, MHD_gtls_version_get_major (hver), + MHD_gtls_version_get_minor (hver)); + + session->security_parameters.version = hver; + session->security_parameters.timestamp = time (NULL); + + /* generate session client random */ + memset (session->security_parameters.client_random, 0, TLS_RANDOM_SIZE); + MHD_gtls_write_uint32 (time (NULL), rnd); + if (GC_OK != MHD_gc_nonce ((char *) &rnd[4], TLS_RANDOM_SIZE - 4)) abort (); + memcpy (session->security_parameters.client_random, rnd, TLS_RANDOM_SIZE); + memcpy (&data[pos], rnd, TLS_RANDOM_SIZE); + pos += TLS_RANDOM_SIZE; + + /* Copy the Session ID */ + data[pos++] = session_id_len; + + /* + * len = ciphersuite data + 2 bytes ciphersuite length \ + * 1 byte compression length + 1 byte compression data + \ + * 2 bytes extension length, extensions data + */ + ciphersuite_len = MHD__gnutls_copy_ciphersuites (session, extdata, + sizeof (extdata)); + exten_data_len = ext_count * (2 + 2 + ext_length); + datalen += ciphersuite_len + 2 + 2 + exten_data_len; + data = MHD_gtls_realloc_fast (data, datalen); + memcpy (&data[pos], extdata, sizeof (ciphersuite_len)); + pos += ciphersuite_len; + + /* set compression */ + memcpy (&data[pos], comp, sizeof (comp)); + pos += 2; + + /* set extensions length = 2 type bytes + 2 length bytes + extension length */ + MHD_gtls_write_uint16 (exten_data_len, &data[pos]); + pos += 2; + for (i = 0; i < ext_count; ++i) + { + /* write extension type */ + MHD_gtls_write_uint16 (exten_t, &data[pos]); + pos += 2; + MHD_gtls_write_uint16 (ext_length, &data[pos]); + pos += 2; + /* we might want to generate random data here */ + memset (&data[pos], 0, ext_length); + pos += ext_length; + } + + if (connect (sd, &sa, sizeof (struct sockaddr_in)) < 0) + { + fprintf (stderr, "%s\n", MHD_E_FAILED_TO_CONNECT); + ret = -1; + goto cleanup; + } + + MHD__gnutls_transport_set_ptr (session, (MHD_gnutls_transport_ptr_t) (long) sd); + + if (gen_test_file_url (url, DEAMON_TEST_PORT)) + { + ret = -1; + goto cleanup; + } + + /* this should crash the server */ + ret = MHD_gtls_send_handshake (session, data, datalen, + GNUTLS_HANDSHAKE_CLIENT_HELLO); + + /* advance to STATE2 */ + session->internals.handshake_state = STATE2; + ret = MHD__gnutls_handshake (session); + ret = MHD__gnutls_bye (session, GNUTLS_SHUT_WR); + + MHD_gnutls_free (data); + + /* make sure daemon is still functioning */ + if (CURLE_OK != send_curl_req (url, &cbc, "AES128-SHA", + MHD_GNUTLS_PROTOCOL_TLS1_2)) + { + ret = -1; + goto cleanup; + } + +cleanup: + if (sd != -1) + close (sd); + MHD_gnutls_free (cbc.buf); + return ret; +} + +int +main (int argc, char *const *argv) +{ + int i, errorCount = 0; + FILE *test_fd; + struct MHD_Daemon *d; + MHD_gtls_session_t session; + MHD_gnutls_datum_t key; + MHD_gnutls_datum_t cert; + MHD_gtls_cert_credentials_t xcred; + + int ext_arr[] = { GNUTLS_EXTENSION_SERVER_NAME, + -1 + }; + + MHD_gtls_global_set_log_level (11); + + if ((test_fd = setup_test_file ()) == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error: %s\n", strerror (errno)); + return -1; + } + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT, + NULL, NULL, &http_ahc, NULL, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + + if (d == NULL) + { + fprintf (stderr, "%s\n", MHD_E_SERVER_INIT); + return -1; + } + + i = 0; + setup_session (&session, &key, &cert, &xcred); + errorCount += test_hello_extension (session, ext_arr[i], 1, 16); + teardown_session (session, &key, &cert, xcred); +#if 1 + i = 0; + while (ext_arr[i] != -1) + { + setup_session (&session, &key, &cert, &xcred); + errorCount += test_hello_extension (session, ext_arr[i], 1, 16); + teardown_session (session, &key, &cert, xcred); + + setup_session (&session, &key, &cert, &xcred); + errorCount += test_hello_extension (session, ext_arr[i], 3, 8); + teardown_session (session, &key, &cert, xcred); + + /* this test specifically tests the issue raised in CVE-2008-1948 */ + setup_session (&session, &key, &cert, &xcred); + errorCount += test_hello_extension (session, ext_arr[i], 6, 0); + teardown_session (session, &key, &cert, xcred); + i++; + } +#endif + + print_test_result (errorCount, argv[0]); + + MHD_stop_daemon (d); + + curl_global_cleanup (); + fclose (test_fd); + + return errorCount; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_multi_thread_mode_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_multi_thread_mode_test.c new file mode 100644 index 0000000000..602a7175aa --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_multi_thread_mode_test.c @@ -0,0 +1,178 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file tls_thread_mode_test.c + * @brief Testcase for libmicrohttpd HTTPS GET operations + * @author Sagie Amir + * @author Christian Grothoff + * + * TODO: add test for external select! + */ + +#include "platform.h" +#include "microhttpd.h" + +#include <sys/stat.h> +#include <limits.h> +#include "gnutls.h" +#include <curl/curl.h> + +#include "tls_test_common.h" +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +int curl_check_version (const char *req_version, ...); + +/** + * used when spawning multiple threads executing curl server requests + * + */ +static void * +https_transfer_thread_adapter (void *args) +{ + static int nonnull; + struct https_test_data *cargs = args; + int ret; + + /* time spread incomming requests */ + usleep ((useconds_t) 10.0 * ((double) rand ()) / ((double) RAND_MAX)); + ret = test_https_transfer (cargs->test_fd, + cargs->cipher_suite, cargs->proto_version); + if (ret == 0) + return NULL; + return &nonnull; +} + +/** + * Test non-parallel requests. + * + * @return: 0 upon all client requests returning '0', -1 otherwise. + * + * TODO : make client_count a parameter - numver of curl client threads to spawn + */ +static int +test_single_client (FILE * test_fd, char *cipher_suite, + int curl_proto_version) +{ + void *client_thread_ret; + struct https_test_data client_args = + { test_fd, cipher_suite, curl_proto_version }; + + client_thread_ret = https_transfer_thread_adapter (&client_args); + if (client_thread_ret != NULL) + return -1; + return 0; +} + + +/** + * Test parallel request handling. + * + * @return: 0 upon all client requests returning '0', -1 otherwise. + * + * TODO : make client_count a parameter - numver of curl client threads to spawn + */ +static int +test_parallel_clients (FILE * test_fd, char *cipher_suite, + int curl_proto_version) +{ + int i; + int client_count = 3; + void *client_thread_ret; + pthread_t client_arr[client_count]; + struct https_test_data client_args = + { test_fd, cipher_suite, curl_proto_version }; + + for (i = 0; i < client_count; ++i) + { + if (pthread_create (&client_arr[i], NULL, + &https_transfer_thread_adapter, &client_args) != 0) + { + fprintf (stderr, "Error: failed to spawn test client threads.\n"); + + return -1; + } + } + + /* check all client requests fulfilled correctly */ + for (i = 0; i < client_count; ++i) + { + if ((pthread_join (client_arr[i], &client_thread_ret) != 0) || + (client_thread_ret != NULL)) + return -1; + } + + return 0; +} + + +int +main (int argc, char *const *argv) +{ + FILE *test_fd; + unsigned int errorCount = 0; + + /* initialize random seed used by curl clients */ + unsigned int iseed = (unsigned int) time (NULL); + srand (iseed); + + if (curl_check_version (MHD_REQ_CURL_VERSION)) + return -1; + + if ((test_fd = setup_test_file ()) == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error: %s\n", strerror (errno)); + fclose (test_fd); + return -1; + } + + errorCount += + test_wrap ("multi threaded daemon, single client", &test_single_client, + test_fd, + MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION, + "AES256-SHA", CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY, + srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT, + srv_self_signed_cert_pem, MHD_OPTION_END); + + errorCount += + test_wrap ("multi threaded daemon, parallel client", + &test_parallel_clients, test_fd, + MHD_USE_SSL | MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION, + "AES256-SHA", CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY, + srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT, + srv_self_signed_cert_pem, MHD_OPTION_END); + + if (errorCount != 0) + fprintf (stderr, "Failed test: %s.\n", argv[0]); + + curl_global_cleanup (); + fclose (test_fd); + + remove (TEST_FILE_NAME); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_session_time_out_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_session_time_out_test.c new file mode 100644 index 0000000000..7609160d29 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_session_time_out_test.c @@ -0,0 +1,171 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file mhds_get_test.c + * @brief: daemon TLS alert response test-case + * + * @author Sagie Amir + */ + +#include "platform.h" +#include "microhttpd.h" +#include "internal.h" +#include "gnutls_int.h" +#include "gnutls_datum.h" +#include "gnutls_record.h" + +#include "tls_test_common.h" +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +static const int TIME_OUT = 3; + +char *http_get_req = "GET / HTTP/1.1\r\n\r\n"; + +static int +setup_timeout_test (MHD_gtls_session_t * session, + MHD_gnutls_datum_t * key, + MHD_gnutls_datum_t * cert, + MHD_gtls_cert_credentials_t * xcred) +{ + int ret; + + MHD__gnutls_certificate_allocate_credentials (xcred); + + MHD_gtls_set_datum_m (key, srv_key_pem, strlen (srv_key_pem), &malloc); + MHD_gtls_set_datum_m (cert, srv_self_signed_cert_pem, + strlen (srv_self_signed_cert_pem), &malloc); + + MHD__gnutls_certificate_set_x509_key_mem (*xcred, cert, key, + GNUTLS_X509_FMT_PEM); + + MHD__gnutls_init (session, GNUTLS_CLIENT); + ret = MHD__gnutls_priority_set_direct (*session, "NORMAL", NULL); + if (ret < 0) + { + return -1; + } + + MHD__gnutls_credentials_set (*session, MHD_GNUTLS_CRD_CERTIFICATE, xcred); + return 0; +} + +static int +teardown_timeout_test (MHD_gtls_session_t session, + MHD_gnutls_datum_t * key, + MHD_gnutls_datum_t * cert, + MHD_gtls_cert_credentials_t xcred) +{ + + MHD_gtls_free_datum_m (key, free); + MHD_gtls_free_datum_m (cert, free); + + MHD__gnutls_deinit (session); + + MHD__gnutls_certificate_free_credentials (xcred); + return 0; +} + +static int +test_tls_session_time_out (MHD_gtls_session_t session) +{ + int sd, ret; + struct sockaddr_in sa; + + sd = socket (AF_INET, SOCK_STREAM, 0); + if (sd == -1) + { + fprintf (stderr, "Failed to create socket: %s\n", strerror (errno)); + return -1; + } + + memset (&sa, '\0', sizeof (struct sockaddr_in)); + sa.sin_family = AF_INET; + sa.sin_port = htons (DEAMON_TEST_PORT); + inet_pton (AF_INET, "127.0.0.1", &sa.sin_addr); + + MHD__gnutls_transport_set_ptr (session, (MHD_gnutls_transport_ptr_t) (long) sd); + + ret = connect (sd, &sa, sizeof (struct sockaddr_in)); + + if (ret < 0) + { + fprintf (stderr, "Error: %s\n", MHD_E_FAILED_TO_CONNECT); + return -1; + } + + ret = MHD__gnutls_handshake (session); + if (ret < 0) + { + return -1; + } + + sleep (TIME_OUT + 1); + + /* check that server has closed the connection */ + /* TODO better RST trigger */ + if (send (sd, "", 1, 0) == 0) + { + return -1; + } + + close (sd); + return 0; +} + +int +main (int argc, char *const *argv) +{ + int errorCount = 0;; + struct MHD_Daemon *d; + MHD_gtls_session_t session; + MHD_gnutls_datum_t key; + MHD_gnutls_datum_t cert; + MHD_gtls_cert_credentials_t xcred; + + MHD__gnutls_global_init (); + MHD_gtls_global_set_log_level (11); + + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_SSL | + MHD_USE_DEBUG, DEAMON_TEST_PORT, + NULL, NULL, &http_dummy_ahc, NULL, + MHD_OPTION_CONNECTION_TIMEOUT, TIME_OUT, + MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, + MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, + MHD_OPTION_END); + + if (d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + setup_timeout_test (&session, &key, &cert, &xcred); + errorCount += test_tls_session_time_out (session); + teardown_timeout_test (session, &key, &cert, xcred); + + print_test_result (errorCount, argv[0]); + + MHD_stop_daemon (d); + MHD__gnutls_global_deinit (); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_test_common.c b/lib/libmicrohttpd/src/testcurl/https/tls_test_common.c new file mode 100644 index 0000000000..ce79451157 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_test_common.c @@ -0,0 +1,424 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +/** + * @file tls_daemon_options_test.c + * @brief Common tls test functions + * @author Sagie Amir + */ +#include "tls_test_common.h" +#include "tls_test_keys.h" +#include "gnutls.h" +#include "gnutls_datum.h" + +const char test_file_data[] = "Hello World\n"; + +int curl_check_version (const char *req_version, ...); + +void +print_test_result (int test_outcome, char *test_name) +{ +#if 0 + if (test_outcome != 0) + fprintf (stderr, "running test: %s [fail]\n", test_name); + else + fprintf (stdout, "running test: %s [pass]\n", test_name); +#endif +} + +size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +file_reader (void *cls, uint64_t pos, char *buf, int max) +{ + FILE *file = cls; + fseek (file, pos, SEEK_SET); + return fread (buf, 1, max, file); +} + +/** + * HTTP access handler call back + */ +int +http_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, size_t *upload_data_size, void **ptr) +{ + static int aptr; + struct MHD_Response *response; + int ret; + FILE *file; + struct stat buf; + + if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + *ptr = NULL; /* reset when done */ + + file = fopen (url, "rb"); + if (file == NULL) + { + response = MHD_create_response_from_data (strlen (PAGE_NOT_FOUND), + (void *) PAGE_NOT_FOUND, + MHD_NO, MHD_NO); + ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); + MHD_destroy_response (response); + } + else + { + stat (url, &buf); + response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k PAGE_NOT_FOUND size */ + &file_reader, file, + (MHD_ContentReaderFreeCallback) + & fclose); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + } + return ret; +} + +/* HTTP access handler call back */ +int +http_dummy_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, size_t *upload_data_size, + void **ptr) +{ + return 0; +} + +/** + * send a test http request to the daemon + * @param url + * @param cbc - may be null + * @param cipher_suite + * @param proto_version + * @return + */ +/* TODO have test wrap consider a NULL cbc */ +int +send_curl_req (char *url, struct CBC * cbc, char *cipher_suite, + int proto_version) +{ + CURL *c; + CURLcode errornum; + c = curl_easy_init (); +#if DEBUG_HTTPS_TEST + curl_easy_setopt (c, CURLOPT_VERBOSE, CURL_VERBOS_LEVEL); +#endif + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 60L); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 60L); + + if (cbc != NULL) + { + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_FILE, cbc); + } + + /* TLS options */ + curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version); + curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); + + /* currently skip any peer authentication */ + curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); + + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + + /* NOTE: use of CONNECTTIMEOUT without also + setting NOSIGNAL results in really weird + crashes on my system! */ + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + return errornum; + } + curl_easy_cleanup (c); + + return CURLE_OK; +} + +/** + * compile test file url pointing to the current running directory path + * @param url - char buffer into which the url is compiled + * @return + */ +int +gen_test_file_url (char *url, int port) +{ + int ret = 0; + char *doc_path; + size_t doc_path_len; + /* setup test file path, url */ + doc_path_len = PATH_MAX > 4096 ? 4096 : PATH_MAX; + if (NULL == (doc_path = malloc (doc_path_len))) + { + fprintf (stderr, MHD_E_MEM); + return -1; + } + if (getcwd (doc_path, doc_path_len) == NULL) + { + fprintf (stderr, "Error: failed to get working directory. %s\n", + strerror (errno)); + ret = -1; + } + /* construct url - this might use doc_path */ + if (sprintf (url, "%s:%d%s/%s", "https://localhost", port, + doc_path, TEST_FILE_NAME) < 0) + ret = -1; + + free (doc_path); + return ret; +} + +/** + * test HTTPS file transfer + * @param test_fd: file to attempt transferring + */ +int +test_https_transfer (FILE * test_fd, char *cipher_suite, int proto_version) +{ + int len, ret = 0; + struct CBC cbc; + char url[255]; + struct stat statb; + /* used to memcmp local copy & deamon supplied copy */ + unsigned char *mem_test_file_local; + + if (0 != stat (TEST_FILE_NAME, &statb)) + { + fprintf (stderr, "Failed to stat `%s': %s\n", + TEST_FILE_NAME, strerror(errno)); + return -1; + } + len = statb.st_size; + cbc.buf = NULL; + if (NULL == (mem_test_file_local = malloc (len))) + { + fprintf (stderr, MHD_E_MEM); + ret = -1; + goto cleanup; + } + + fseek (test_fd, 0, SEEK_SET); + if (fread (mem_test_file_local, sizeof (char), len, test_fd) != len) + { + fprintf (stderr, "Error: failed to read test file. %s\n", + strerror (errno)); + ret = -1; + goto cleanup; + } + + if (NULL == (cbc.buf = malloc (sizeof (char) * len))) + { + fprintf (stderr, MHD_E_MEM); + ret = -1; + goto cleanup; + } + cbc.size = len; + cbc.pos = 0; + + if (gen_test_file_url (url, DEAMON_TEST_PORT)) + { + ret = -1; + goto cleanup; + } + + if (CURLE_OK != send_curl_req (url, &cbc, cipher_suite, proto_version)) + { + ret = -1; + goto cleanup; + } + + /* compare test file & daemon responce */ + if (memcmp (cbc.buf, mem_test_file_local, len) != 0) + { + fprintf (stderr, "Error: local file & received file differ.\n"); + ret = -1; + } + +cleanup: + free (mem_test_file_local); + if (cbc.buf != NULL) + free (cbc.buf); + return ret; +} + +/** + * setup a mock test file which is requested from the running daemon + * @return open file descriptor to the test file + */ +FILE * +setup_test_file () +{ + FILE *test_fd; + + if (NULL == (test_fd = fopen (TEST_FILE_NAME, "wb+"))) + { + fprintf (stderr, "Error: failed to open `%s': %s\n", + TEST_FILE_NAME, strerror (errno)); + return NULL; + } + if (fwrite (test_file_data, sizeof (char), strlen (test_file_data), test_fd) + != strlen (test_file_data)) + { + fprintf (stderr, "Error: failed to write `%s. %s'\n", + TEST_FILE_NAME, strerror (errno)); + fclose (test_fd); + return NULL; + } + if (fflush (test_fd)) + { + fprintf (stderr, "Error: failed to flush test file stream. %s\n", + strerror (errno)); + fclose (test_fd); + return NULL; + } + return test_fd; +} + +/** + * setup test case + * + * @param d + * @param daemon_flags + * @param arg_list + * @return + */ +int +setup_testcase (struct MHD_Daemon **d, int daemon_flags, va_list arg_list) +{ + *d = MHD_start_daemon_va (daemon_flags, DEAMON_TEST_PORT, + NULL, NULL, &http_ahc, NULL, arg_list); + + if (*d == NULL) + { + fprintf (stderr, MHD_E_SERVER_INIT); + return -1; + } + + return 0; +} + +void +teardown_testcase (struct MHD_Daemon *d) +{ + MHD_stop_daemon (d); +} + +int +setup_session (MHD_gtls_session_t * session, + MHD_gnutls_datum_t * key, + MHD_gnutls_datum_t * cert, MHD_gtls_cert_credentials_t * xcred) +{ + int ret; + const char *err_pos; + + MHD__gnutls_certificate_allocate_credentials (xcred); + + MHD_gtls_set_datum_m (key, srv_key_pem, strlen (srv_key_pem), &malloc); + MHD_gtls_set_datum_m (cert, srv_self_signed_cert_pem, + strlen (srv_self_signed_cert_pem), &malloc); + + MHD__gnutls_certificate_set_x509_key_mem (*xcred, cert, key, + GNUTLS_X509_FMT_PEM); + + MHD__gnutls_init (session, GNUTLS_CLIENT); + ret = MHD__gnutls_priority_set_direct (*session, "NORMAL", &err_pos); + if (ret < 0) + { + return -1; + } + + MHD__gnutls_credentials_set (*session, MHD_GNUTLS_CRD_CERTIFICATE, xcred); + return 0; +} + +int +teardown_session (MHD_gtls_session_t session, + MHD_gnutls_datum_t * key, + MHD_gnutls_datum_t * cert, + MHD_gtls_cert_credentials_t xcred) +{ + + MHD_gtls_free_datum_m (key, free); + MHD_gtls_free_datum_m (cert, free); + + MHD__gnutls_deinit (session); + + MHD__gnutls_certificate_free_credentials (xcred); + return 0; +} + +/* TODO test_wrap: change sig to (setup_func, test, va_list test_arg) */ +int +test_wrap (char *test_name, int + (*test_function) (FILE * test_fd, char *cipher_suite, + int proto_version), FILE * test_fd, + int daemon_flags, char *cipher_suite, int proto_version, ...) +{ + int ret; + va_list arg_list; + struct MHD_Daemon *d; + + va_start (arg_list, proto_version); + if (setup_testcase (&d, daemon_flags, arg_list) != 0) + { + va_end (arg_list); + return -1; + } +#if 0 + fprintf (stdout, "running test: %s ", test_name); +#endif + ret = test_function (test_fd, cipher_suite, proto_version); +#if 0 + if (ret == 0) + { + fprintf (stdout, "[pass]\n"); + } + else + { + fprintf (stdout, "[fail]\n"); + } +#endif + teardown_testcase (d); + va_end (arg_list); + return ret; +} diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_test_common.h b/lib/libmicrohttpd/src/testcurl/https/tls_test_common.h new file mode 100644 index 0000000000..965614d12e --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_test_common.h @@ -0,0 +1,118 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#ifndef TLS_TEST_COMMON_H_ +#define TLS_TEST_COMMON_H_ + +#include "platform.h" +#include "microhttpd.h" +#include <curl/curl.h> +#include <sys/stat.h> +#include <limits.h> +#include "gnutls.h" + +/* this enables verbos CURL version checking */ +#define DEBUG_HTTPS_TEST 0 +#define CURL_VERBOS_LEVEL 0 + +#define DEAMON_TEST_PORT 42433 + +#define TEST_FILE_NAME "https_test_file" + +#define EMPTY_PAGE "<html><head><title>Empty page</title></head><body>Empty page</body></html>" +#define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>" + +#define MHD_E_MEM "Error: memory error\n" +#define MHD_E_SERVER_INIT "Error: failed to start server\n" +#define MHD_E_TEST_FILE_CREAT "Error: failed to setup test file\n" +#define MHD_E_CERT_FILE_CREAT "Error: failed to setup test certificate\n" +#define MHD_E_KEY_FILE_CREAT "Error: failed to setup test certificate\n" +#define MHD_E_FAILED_TO_CONNECT "Error: server connection could not be established\n" + +/* TODO rm if unused */ +struct https_test_data +{ + FILE *test_fd; + char *cipher_suite; + int proto_version; +}; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +struct CipherDef +{ + int options[2]; + char *curlname; +}; + +void print_test_result (int test_outcome, char *test_name); + +size_t copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx); + +int +http_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, size_t *upload_data_size, void **ptr); + +int +http_dummy_ahc (void *cls, struct MHD_Connection *connection, + const char *url, const char *method, const char *upload_data, + const char *version, size_t *upload_data_size, + void **ptr); + +int gen_test_file_url (char *url, int port); + +int +send_curl_req (char *url, struct CBC *cbc, char *cipher_suite, + int proto_version); + +int +test_https_transfer (FILE * test_fd, char *cipher_suite, int proto_version); + +FILE *setup_test_file (); + +int +setup_testcase (struct MHD_Daemon **d, int daemon_flags, va_list arg_list); + +void teardown_testcase (struct MHD_Daemon *d); + +int +setup_session (MHD_gtls_session_t * session, + MHD_gnutls_datum_t * key, + MHD_gnutls_datum_t * cert, + MHD_gtls_cert_credentials_t * xcred); + +int +teardown_session (MHD_gtls_session_t session, + MHD_gnutls_datum_t * key, + MHD_gnutls_datum_t * cert, + MHD_gtls_cert_credentials_t xcred); + +int +test_wrap (char *test_name, int + (*test_function) (FILE * test_fd, char *cipher_suite, + int proto_version), FILE * test_fd, + int daemon_flags, char *cipher_suite, int proto_version, ...); +#endif /* TLS_TEST_COMMON_H_ */ diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_test_keys.h b/lib/libmicrohttpd/src/testcurl/https/tls_test_keys.h new file mode 100644 index 0000000000..8ad8ca35a8 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_test_keys.h @@ -0,0 +1,173 @@ +/* + This file is part of libmicrohttpd + (C) 2006, 2007, 2008 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef MHD_TLS_TEST_KEYS_H +#define MHD_TLS_TEST_KEYS_H + +/* Test Certificates */ + +/* Certificate Authority key */ +const char ca_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEA0EdlP613rjFvEj93tGo9fzBoKWU3CW+AbbfcJ397C89MyZ9J\n" + "rlxyLGfa6qVX7CFVNmzgWWfcl2tHlw/fZmWtf/SFgrlkldvuGyY8H3n2HuMsWz/E\n" + "h7n5VgwBX8NsP4eZNmikepxpr1mYx25K8FjnsKjAR9jGUSV8UfZ7VLIY0x/yqe+3\n" + "32oqc4D/wJbV1AwwvC5Xf9rvHJwcZg57eqbDCL/4GDDk7d9Gark4XK6ZG+FnnxQn\n" + "4a4jIdf4FoPp9s0EieHrHwYzs/uBqmfCSF4wXiaO8bmEwtbAsVbZH74Le7ggUbEe\n" + "o+jan9XK0dE88AIImGzgoBnlic/Rr7J8OWA+iwIDAQABAoIBAEICZqXkUdpsw2F6\n" + "qPMOergNPO3lrKg6ZO8hBs6j2fj3tcPuzljK5sqJDboxNejZ9Zo+rmnXf3Oj5fgL\n" + "6UcYMYEsm4W/QRA3uEJ1fzeQnT7Ty9KNprlHaSzquCLEGlIWJSo3xu0vFlWjJUcL\n" + "fwemfaOhD/OVUeEU6s5FOngwy6pZUsOajs3fNRtwBGuuXjniKZZlpSf2Wqu3xpHZ\n" + "31OF1V0ycUCGPPFtpmUCtnZhS9L8QBTkNtfTIdXv6SfoBRFm0oXb0uL5HGft6yc7\n" + "eYRXIscllQciqG3ymJ/y9o0E3A0YsBVauQyi7OEk+Kg8uoYOBkZCIY69hoN2Znlk\n" + "OY5S5Z0CgYEA3j8pRAJzvc827KcX4vJf05HYD4aCyaI80fNmx1DgXfglTSGLQ361\n" + "6i05YW8WtIvgkma3wF+jJOckBCW/7iq8wAX7Kz75WKGRyyTEb0wSfjx0G8grxX4d\n" + "7sTIAAOnQj5WT6E/bkqxQZAYnVtIPxKtSlwts0H/bjPVYwSFchHK7t8CgYEA7+ks\n" + "C0EMjF8CDeCfvbOUGiiqAvU3G20LEC3WlJM3AU+J9Jzp6AMkgaIA8J5oNdsbFBn4\n" + "N12JPOO+7WRUk6Av8bsh4faE36ThnHohgAL8guRU7jIXvsFyO5yiY7/o/0lES0/V\n" + "6xkh/Epj4MReuCGkiD9ifCVAo+dhHskeE9qbYdUCgYA4yBpa7eV0UUTPIcHQkew5\n" + "ucFh9hPkQDcZzP4tXlR0rbmaAz/5dp4zvmoyopdCeZpezS+VTtn3y7Y/+QUYbILc\n" + "7KpHWkeKhX0iUbp+VQlEh12C25mTU62CG3SdzFEnc5XJsoDqRNsUzSP80B2dP8BW\n" + "h0aFzg7csRGLwtP1WOZoMQKBgQCrgsKd+Q8Dexh421DXyX3jhZalLrEKxlXWZy60\n" + "YNo98aLqYRNHbpe2pR6O5nARsGYXZMlyq0flY9um0sc0Epyz79g1NoufZrxzpUw1\n" + "u+zRlnKxJtaa5KjJvRzKuvPTLYnJXXXM8Na/Cl+E3F3qvQJm9QlvPyKLCmsAGz+J\n" + "agsTUQKBgC0wqqJ6b1tbrAD8AVeeAn/IiP1rxYpc3x2s6ikFO2FMHXHC9wgrRPOc\n" + "mkokV+DrUOv3I/7jG8wQA/FmBUPy562a1bObIKzg6CPXzrN68AmNnOIVU+H8fdxI\n" + "iGyfT8WNpcRmtN11v34qXHwOWGQhpyyk2yNa8VIBSpkShq/EseZ1\n" + "-----END RSA PRIVATE KEY-----\n"; + +/* Certificate Authority cert */ +const char ca_cert_pem[] = "-----BEGIN CERTIFICATE-----\n" + "MIIC6DCCAdKgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n" + "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n" + "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n" + "0EdlP613rjFvEj93tGo9fzBoKWU3CW+AbbfcJ397C89MyZ9JrlxyLGfa6qVX7CFV\n" + "NmzgWWfcl2tHlw/fZmWtf/SFgrlkldvuGyY8H3n2HuMsWz/Eh7n5VgwBX8NsP4eZ\n" + "Nmikepxpr1mYx25K8FjnsKjAR9jGUSV8UfZ7VLIY0x/yqe+332oqc4D/wJbV1Aww\n" + "vC5Xf9rvHJwcZg57eqbDCL/4GDDk7d9Gark4XK6ZG+FnnxQn4a4jIdf4FoPp9s0E\n" + "ieHrHwYzs/uBqmfCSF4wXiaO8bmEwtbAsVbZH74Le7ggUbEeo+jan9XK0dE88AII\n" + "mGzgoBnlic/Rr7J8OWA+iwIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1Ud\n" + "DwEB/wQFAwMHBAAwHQYDVR0OBBYEFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsGCSqG\n" + "SIb3DQEBBQOCAQEAebD5m+vZkVXa8y+QZ5GtsiR9gpH+LKtdWBjk1kmfSgvQI/xA\n" + "aDCV/9BhdNGIBOTYGkln8urWd7g2Mj3TwKEAfNTUFpAsrBAlSSLTGYCSt72S2NsS\n" + "L/qUxmj1W6X95UHXCo49mSZx3LlaY3mz1L87gq/kK0XpzA3g2uF25jt84RvshsXy\n" + "clOc+eRrVETqFZqer96WB7kzFTv+qmROQKmW8X4a2A5r5Jl4vRwOz5/rEeB9Qs0K\n" + "rmK8+5HgvWd80WB8BtfFtZfoY/hHVM8nLD3ELVJrOKiTeIACunQFyT5lV0QkdmSA\n" + "CGInU7jzs8nu+s2avf6j+eVZUbVJ+dFMApTJgg==\n" + "-----END CERTIFICATE-----\n"; + +/* test server CA signed certificates */ +const char srv_signed_cert_pem[] = "-----BEGIN CERTIFICATE-----\n" + "MIIDGzCCAgWgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n" + "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n" + "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n" + "vfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW+K03KwEku55QvnUn\n" + "dwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8ILq4sw32vo0fbMu5BZ\n" + "F49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ020Q5EAAEseD1YtWC\n" + "IpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6QYGGh1QmHRPAy3CB\n" + "II6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6xyoOl204xuekZOaG9\n" + "RUPId74Rtmwfi1TLbBzo2wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM\n" + "MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFOFi4ilKOP1d\n" + "XHlWCMwmVKr7mgy8MB8GA1UdIwQYMBaAFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsG\n" + "CSqGSIb3DQEBBQOCAQEAHVWPxazupbOkG7Did+dY9z2z6RjTzYvurTtEKQgzM2Vz\n" + "GQBA+3pZ3c5mS97fPIs9hZXfnQeelMeZ2XP1a+9vp35bJjZBBhVH+pqxjCgiUflg\n" + "A3Zqy0XwwVCgQLE2HyaU3DLUD/aeIFK5gJaOSdNTXZLv43K8kl4cqDbMeRpVTbkt\n" + "YmG4AyEOYRNKGTqMEJXJoxD5E3rBUNrVI/XyTjYrulxbNPcMWEHKNeeqWpKDYTFo\n" + "Bb01PCthGXiq/4A2RLAFosadzRa8SBpoSjPPfZ0b2w4MJpReHqKbR5+T2t6hzml6\n" + "4ToyOKPDmamiTuN5KzLN3cw7DQlvWMvqSOChPLnA3Q==\n" + "-----END CERTIFICATE-----\n"; + +/* test server key */ +const char srv_signed_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAvfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW\n" + "+K03KwEku55QvnUndwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8IL\n" + "q4sw32vo0fbMu5BZF49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ0\n" + "20Q5EAAEseD1YtWCIpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6\n" + "QYGGh1QmHRPAy3CBII6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6x\n" + "yoOl204xuekZOaG9RUPId74Rtmwfi1TLbBzo2wIDAQABAoIBADu09WSICNq5cMe4\n" + "+NKCLlgAT1NiQpLls1gKRbDhKiHU9j8QWNvWWkJWrCya4QdUfLCfeddCMeiQmv3K\n" + "lJMvDs+5OjJSHFoOsGiuW2Ias7IjnIojaJalfBml6frhJ84G27IXmdz6gzOiTIer\n" + "DjeAgcwBaKH5WwIay2TxIaScl7AwHBauQkrLcyb4hTmZuQh6ArVIN6+pzoVuORXM\n" + "bpeNWl2l/HSN3VtUN6aCAKbN/X3o0GavCCMn5Fa85uJFsab4ss/uP+2PusU71+zP\n" + "sBm6p/2IbGvF5k3VPDA7X5YX61sukRjRBihY8xSnNYx1UcoOsX6AiPnbhifD8+xQ\n" + "Tlf8oJUCgYEA0BTfzqNpr9Wxw5/QXaSdw7S/0eP5a0C/nwURvmfSzuTD4equzbEN\n" + "d+dI/s2JMxrdj/I4uoAfUXRGaabevQIjFzC9uyE3LaOyR2zhuvAzX+vVcs6bSXeU\n" + "pKpCAcN+3Z3evMaX2f+z/nfSUAl2i4J2R+/LQAWJW4KwRky/m+cxpfUCgYEA6bN1\n" + "b73bMgM8wpNt6+fcmS+5n0iZihygQ2U2DEud8nZJL4Nrm1dwTnfZfJBnkGj6+0Q0\n" + "cOwj2KS0/wcEdJBP0jucU4v60VMhp75AQeHqidIde0bTViSRo3HWKXHBIFGYoU3T\n" + "LyPyKndbqsOObnsFXHn56Nwhr2HLf6nw4taGQY8CgYBoSW36FLCNbd6QGvLFXBGt\n" + "2lMhEM8az/K58kJ4WXSwOLtr6MD/WjNT2tkcy0puEJLm6BFCd6A6pLn9jaKou/92\n" + "SfltZjJPb3GUlp9zn5tAAeSSi7YMViBrfuFiHObij5LorefBXISLjuYbMwL03MgH\n" + "Ocl2JtA2ywMp2KFXs8GQWQKBgFyIVv5ogQrbZ0pvj31xr9HjqK6d01VxIi+tOmpB\n" + "4ocnOLEcaxX12BzprW55ytfOCVpF1jHD/imAhb3YrHXu0fwe6DXYXfZV4SSG2vB7\n" + "IB9z14KBN5qLHjNGFpMQXHSMek+b/ftTU0ZnPh9uEM5D3YqRLVd7GcdUhHvG8P8Q\n" + "C9aXAoGBAJtID6h8wOGMP0XYX5YYnhlC7dOLfk8UYrzlp3xhqVkzKthTQTj6wx9R\n" + "GtC4k7U1ki8oJsfcIlBNXd768fqDVWjYju5rzShMpo8OCTS6ipAblKjCxPPVhIpv\n" + "tWPlbSn1qj6wylstJ5/3Z+ZW5H4wIKp5jmLiioDhcP0L/Ex3Zx8O\n" + "-----END RSA PRIVATE KEY-----\n"; + +/* test server self signed certificates */ +const char srv_self_signed_cert_pem[] = "-----BEGIN CERTIFICATE-----\n" + "MIIC+jCCAeSgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n" + "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n" + "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n" + "tDEagv3p9OUhUL55jMucxjNK9N5cuozhcnrwDfBSU6oVrqm5kPqO1I7Cggzw68Y5\n" + "jhTcBi4FXmYOZppm1R3MhSJ5JSi/67Q7X4J5rnJLXYGN27qjMpnoGQ/2xmsNG/is\n" + "i+h/2vbtPU+WP9SEJnTfPLLpZ7KqCAk7FUUzKsuLx3/SOKtdkrWxPKwYTgnDEN6D\n" + "JL7tEzCnG5DFc4mQ7YW9PaRdC3rS1T8PvQ3jB2BUnohM0cFvKRuiU35tU7h7CPbL\n" + "4L66VglXoiwqmgcrwI2U968bD0+wRQ5c5bzNoshJOzN6CTMh1IhbklSh/Z6FA/e8\n" + "hj0yVo2tdllXuJGVs3PIEwIDAQABo1UwUzAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM\n" + "MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFDfU7pAv9LYn\n" + "n7jb4WHl4+Vgi2FnMAsGCSqGSIb3DQEBBQOCAQEAkaembPQMmv6OOjbIod8zTatr\n" + "x5Bwkwp3TOE1NRyy2OytzFIYRUkNrZYlcmrxcbNNycIK41CNVXbriFCF8gcmIq9y\n" + "vaKZn8Gcy+vGggv+1BP9IAPBGKRwSi0wmq9JoGE8hx+qqTpRSdfbM/cps/09hicO\n" + "0EIR7kWEbvnpMBcMKYOtYE9Gce7rdSMWVAsKc174xn8vW6TxCUvmWFv5DPg5HG1v\n" + "y1SUX73qafRo+W6FN4UC/DHfwRhF8RSKEnVbmgDVCs6GHdKBjU2qRgYyj6nWZqK1\n" + "XFUTWgia+Fl3D9vlsXaFcSZKA0Bq1eojl0B0AfeYAxTFwPWXscKvt/bXZfH8bg==\n" + "-----END CERTIFICATE-----\n"; + +/* test server key */ +const char srv_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEAtDEagv3p9OUhUL55jMucxjNK9N5cuozhcnrwDfBSU6oVrqm5\n" + "kPqO1I7Cggzw68Y5jhTcBi4FXmYOZppm1R3MhSJ5JSi/67Q7X4J5rnJLXYGN27qj\n" + "MpnoGQ/2xmsNG/isi+h/2vbtPU+WP9SEJnTfPLLpZ7KqCAk7FUUzKsuLx3/SOKtd\n" + "krWxPKwYTgnDEN6DJL7tEzCnG5DFc4mQ7YW9PaRdC3rS1T8PvQ3jB2BUnohM0cFv\n" + "KRuiU35tU7h7CPbL4L66VglXoiwqmgcrwI2U968bD0+wRQ5c5bzNoshJOzN6CTMh\n" + "1IhbklSh/Z6FA/e8hj0yVo2tdllXuJGVs3PIEwIDAQABAoIBAAEtcg+LFLGtoxjq\n" + "b+tFttBJfbRcfdG6ocYqBGmUXF+MgFs573DHX3sHNOQxlaNHtSgIclF1eYgNZFFt\n" + "VLIoBFTzfEQXoFosPUDoEuqVMeXLttmD7P2jwL780XJLZ4Xj6GY07npq1iGBcEZf\n" + "yCcdoyGkr9jgc5Auyis8DStGg/jfUBC4NBvF0GnuuNPAdYRPKUpKw9EatI+FdMjy\n" + "BuroD90fhdkK8EwMEVb9P17bdIc1MCIZFpUE9YHjVdK/oxCUhQ8KRfdbI4JU5Zh3\n" + "UtO6Jm2wFuP3VmeVpPvE/C2rxI70pyl6HMSiFGNc0rhJYCQ+yhohWj7nZ67H4vLx\n" + "plv5LxkCgYEAz7ewou8oFafDAMNoxaqKudvUg+lxXewdLDKaYBF5ACi9uAPCJ+v7\n" + "M5c/fvPFn/XHzo7xaXbtTAH3Z5xzBs+80OsvL+e1Ut4xR+ELRkybknh/s2wQeABk\n" + "Kb0vA59ukQGj12LV5phZMaVoXe6KJ7hZnN62d3K6m1wGE/k58i4pPLUCgYEA3hN8\n" + "G95zW7g0jVdSr+KUeVmephph9yh8Yb+3I3ojwOIv6d45TopGx8pFZlnBAMZf1ZQx\n" + "DIhzJNnaqZy/4w7RNaOGWnPA/5f+MIoHBiLGEEmfHC3lt087Yp9OuwDUHwpETYdV\n" + "o+KBCvVh60Et3bZUgF/1k/3YXxn8J5dsmJsjNqcCgYBLflyRa1BrRnTGMz9CEDCp\n" + "Si9b3h1Y4Hbd2GppHhCXMTd6yMrpDYhYANGQB3M9Juv+s88j4JhwNoq/uonH4Pqk\n" + "B8Y3qAQr4RuSH0WkwDUOsALhqBX4N1QwI1USAQEDbNAqeP5698X7GD3tXcQSmZrg\n" + "O8WfdjBCRNjkq4EW9xX/vQKBgQDONtmwJ0iHiu2BseyeVo/4fzfKlgUSNQ4K1rOA\n" + "xhIdMeu8Bxa/z7caHsGC4SVPSuYCtbE2Kh6BwapChcPJXCD45fgEViiJLuJiwEj1\n" + "caTpyvNsf1IoffJvCe9ZxtMyX549P8ZOgC3Dt0hN5CBrGLwu2Ox5l+YrqT10pi+5\n" + "JZX1UQKBgQCrcXrdkkDAc/a4+PxNRpJRLcU4fhv8/lr+UWItE8eUe7bd25bTQfQm\n" + "VpNKc/kAJ66PjIED6fy3ADhd2y4naT2a24uAgQ/M494J68qLnGh6K4JU/09uxR2v\n" + "1i2q/4FNLdFFk1XP4iNnTHRLZ+NYr2p5Y9RcvQfTjOauz8Ahav0lyg==\n" + "-----END RSA PRIVATE KEY-----\n"; + +#endif diff --git a/lib/libmicrohttpd/src/testcurl/https/tls_thread_mode_test.c b/lib/libmicrohttpd/src/testcurl/https/tls_thread_mode_test.c new file mode 100644 index 0000000000..cf92a26db8 --- /dev/null +++ b/lib/libmicrohttpd/src/testcurl/https/tls_thread_mode_test.c @@ -0,0 +1,172 @@ +/* + This file is part of libmicrohttpd + (C) 2007 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file tls_thread_mode_test.c + * @brief Testcase for libmicrohttpd HTTPS GET operations + * @author Sagie Amir + * @author Christian Grothoff + * + * TODO: add test for external select! + */ + +#include "platform.h" +#include "microhttpd.h" + +#include <sys/stat.h> +#include <limits.h> +#include "gnutls.h" +#include <curl/curl.h> + +#include "tls_test_common.h" +extern const char srv_key_pem[]; +extern const char srv_self_signed_cert_pem[]; + +int curl_check_version (const char *req_version, ...); + +/** + * used when spawning multiple threads executing curl server requests + * + */ +static void * +https_transfer_thread_adapter (void *args) +{ + static int nonnull; + struct https_test_data *cargs = args; + int ret; + + /* time spread incomming requests */ + usleep ((useconds_t) 10.0 * ((double) rand ()) / ((double) RAND_MAX)); + ret = test_https_transfer (cargs->test_fd, + cargs->cipher_suite, cargs->proto_version); + if (ret == 0) + return NULL; + return &nonnull; +} + +/** + * Test non-parallel requests. + * + * @return: 0 upon all client requests returning '0', -1 otherwise. + * + * TODO : make client_count a parameter - numver of curl client threads to spawn + */ +static int +test_single_client (FILE * test_fd, char *cipher_suite, + int curl_proto_version) +{ + void *client_thread_ret; + struct https_test_data client_args = + { test_fd, cipher_suite, curl_proto_version }; + + client_thread_ret = https_transfer_thread_adapter (&client_args); + if (client_thread_ret != NULL) + return -1; + return 0; +} + +/** + * Test parallel request handling. + * + * @return: 0 upon all client requests returning '0', -1 otherwise. + * + * TODO : make client_count a parameter - numver of curl client threads to spawn + */ +static int +test_parallel_clients (FILE * test_fd, char *cipher_suite, + int curl_proto_version) +{ + int i; + int client_count = 3; + void *client_thread_ret; + pthread_t client_arr[client_count]; + struct https_test_data client_args = + { test_fd, cipher_suite, curl_proto_version }; + + for (i = 0; i < client_count; ++i) + { + if (pthread_create (&client_arr[i], NULL, + &https_transfer_thread_adapter, &client_args) != 0) + { + fprintf (stderr, "Error: failed to spawn test client threads.\n"); + return -1; + } + } + + /* check all client requests fulfilled correctly */ + for (i = 0; i < client_count; ++i) + { + if ((pthread_join (client_arr[i], &client_thread_ret) != 0) || + (client_thread_ret != NULL)) + return -1; + } + + return 0; +} + +int +main (int argc, char *const *argv) +{ + FILE *test_fd; + unsigned int errorCount = 0; + + /* initialize random seed used by curl clients */ + unsigned int iseed = (unsigned int) time (NULL); + srand (iseed); + + if (curl_check_version (MHD_REQ_CURL_VERSION)) + return -1; + + if ((test_fd = setup_test_file ()) == NULL) + { + fprintf (stderr, MHD_E_TEST_FILE_CREAT); + return -1; + } + + if (0 != curl_global_init (CURL_GLOBAL_ALL)) + { + fprintf (stderr, "Error: %s\n", strerror (errno)); + fclose (test_fd); + remove (TEST_FILE_NAME); + return -1; + } + + errorCount += + test_wrap ("single threaded daemon, single client", &test_single_client, + test_fd, + MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG, + "AES256-SHA", CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY, + srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT, + srv_self_signed_cert_pem, MHD_OPTION_END); + + errorCount += + test_wrap ("single threaded daemon, parallel clients", + &test_parallel_clients, test_fd, + MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL | MHD_USE_DEBUG, + "AES256-SHA", CURL_SSLVERSION_TLSv1, MHD_OPTION_HTTPS_MEM_KEY, + srv_key_pem, MHD_OPTION_HTTPS_MEM_CERT, + srv_self_signed_cert_pem, MHD_OPTION_END); + + curl_global_cleanup (); + fclose (test_fd); + remove (TEST_FILE_NAME); + + return errorCount != 0; +} diff --git a/lib/libmicrohttpd/src/testzzuf/Makefile.am b/lib/libmicrohttpd/src/testzzuf/Makefile.am new file mode 100644 index 0000000000..42bc2fdc3d --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/Makefile.am @@ -0,0 +1,105 @@ +SUBDIRS = . + +if USE_COVERAGE + AM_CFLAGS = -fprofile-arcs -ftest-coverage +endif + +INCLUDES = -I$(top_srcdir)/src/include + +EXTRA_DIST = README socat.c + +check_PROGRAMS = \ + daemontest_get \ + daemontest_post \ + daemontest_postform \ + daemontest_put \ + daemontest_large_put \ + daemontest_get11 \ + daemontest_post11 \ + daemontest_postform11 \ + daemontest_put11 \ + daemontest_large_put11 \ + daemontest_long_header \ + daemontest_get_chunked \ + daemontest_put_chunked + +TESTS = $(check_PROGRAMS) + +daemontest_get_SOURCES = \ + daemontest_get.c +daemontest_get_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get_chunked_SOURCES = \ + daemontest_get_chunked.c +daemontest_get_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_SOURCES = \ + daemontest_post.c +daemontest_post_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform_SOURCES = \ + daemontest_postform.c +daemontest_postform_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_SOURCES = \ + daemontest_put.c +daemontest_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_chunked_SOURCES = \ + daemontest_put_chunked.c +daemontest_put_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get11_SOURCES = \ + daemontest_get.c +daemontest_get11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post11_SOURCES = \ + daemontest_post.c +daemontest_post11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform11_SOURCES = \ + daemontest_postform.c +daemontest_postform11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put11_SOURCES = \ + daemontest_put.c +daemontest_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + + +daemontest_large_put_SOURCES = \ + daemontest_large_put.c +daemontest_large_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_large_put11_SOURCES = \ + daemontest_large_put.c +daemontest_large_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_long_header_SOURCES = \ + daemontest_long_header.c +daemontest_long_header_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ diff --git a/lib/libmicrohttpd/src/testzzuf/Makefile.in b/lib/libmicrohttpd/src/testzzuf/Makefile.in new file mode 100644 index 0000000000..e0908968ab --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/Makefile.in @@ -0,0 +1,943 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = daemontest_get$(EXEEXT) daemontest_post$(EXEEXT) \ + daemontest_postform$(EXEEXT) daemontest_put$(EXEEXT) \ + daemontest_large_put$(EXEEXT) daemontest_get11$(EXEEXT) \ + daemontest_post11$(EXEEXT) daemontest_postform11$(EXEEXT) \ + daemontest_put11$(EXEEXT) daemontest_large_put11$(EXEEXT) \ + daemontest_long_header$(EXEEXT) \ + daemontest_get_chunked$(EXEEXT) \ + daemontest_put_chunked$(EXEEXT) +subdir = src/testzzuf +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/MHD_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am_daemontest_get_OBJECTS = daemontest_get.$(OBJEXT) +daemontest_get_OBJECTS = $(am_daemontest_get_OBJECTS) +daemontest_get_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_get11_OBJECTS = daemontest_get.$(OBJEXT) +daemontest_get11_OBJECTS = $(am_daemontest_get11_OBJECTS) +daemontest_get11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_get_chunked_OBJECTS = daemontest_get_chunked.$(OBJEXT) +daemontest_get_chunked_OBJECTS = $(am_daemontest_get_chunked_OBJECTS) +daemontest_get_chunked_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_large_put_OBJECTS = daemontest_large_put.$(OBJEXT) +daemontest_large_put_OBJECTS = $(am_daemontest_large_put_OBJECTS) +daemontest_large_put_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_large_put11_OBJECTS = daemontest_large_put.$(OBJEXT) +daemontest_large_put11_OBJECTS = $(am_daemontest_large_put11_OBJECTS) +daemontest_large_put11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_long_header_OBJECTS = daemontest_long_header.$(OBJEXT) +daemontest_long_header_OBJECTS = $(am_daemontest_long_header_OBJECTS) +daemontest_long_header_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_post_OBJECTS = daemontest_post.$(OBJEXT) +daemontest_post_OBJECTS = $(am_daemontest_post_OBJECTS) +daemontest_post_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_post11_OBJECTS = daemontest_post.$(OBJEXT) +daemontest_post11_OBJECTS = $(am_daemontest_post11_OBJECTS) +daemontest_post11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_postform_OBJECTS = daemontest_postform.$(OBJEXT) +daemontest_postform_OBJECTS = $(am_daemontest_postform_OBJECTS) +daemontest_postform_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_postform11_OBJECTS = daemontest_postform.$(OBJEXT) +daemontest_postform11_OBJECTS = $(am_daemontest_postform11_OBJECTS) +daemontest_postform11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_put_OBJECTS = daemontest_put.$(OBJEXT) +daemontest_put_OBJECTS = $(am_daemontest_put_OBJECTS) +daemontest_put_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_put11_OBJECTS = daemontest_put.$(OBJEXT) +daemontest_put11_OBJECTS = $(am_daemontest_put11_OBJECTS) +daemontest_put11_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +am_daemontest_put_chunked_OBJECTS = daemontest_put_chunked.$(OBJEXT) +daemontest_put_chunked_OBJECTS = $(am_daemontest_put_chunked_OBJECTS) +daemontest_put_chunked_DEPENDENCIES = \ + $(top_builddir)/src/daemon/libmicrohttpd.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(daemontest_get_SOURCES) $(daemontest_get11_SOURCES) \ + $(daemontest_get_chunked_SOURCES) \ + $(daemontest_large_put_SOURCES) \ + $(daemontest_large_put11_SOURCES) \ + $(daemontest_long_header_SOURCES) $(daemontest_post_SOURCES) \ + $(daemontest_post11_SOURCES) $(daemontest_postform_SOURCES) \ + $(daemontest_postform11_SOURCES) $(daemontest_put_SOURCES) \ + $(daemontest_put11_SOURCES) $(daemontest_put_chunked_SOURCES) +DIST_SOURCES = $(daemontest_get_SOURCES) $(daemontest_get11_SOURCES) \ + $(daemontest_get_chunked_SOURCES) \ + $(daemontest_large_put_SOURCES) \ + $(daemontest_large_put11_SOURCES) \ + $(daemontest_long_header_SOURCES) $(daemontest_post_SOURCES) \ + $(daemontest_post11_SOURCES) $(daemontest_postform_SOURCES) \ + $(daemontest_postform11_SOURCES) $(daemontest_put_SOURCES) \ + $(daemontest_put11_SOURCES) $(daemontest_put_chunked_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_SOCAT = @HAVE_SOCAT@ +HAVE_ZZUF = @HAVE_ZZUF@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_VERSION_AGE = @LIB_VERSION_AGE@ +LIB_VERSION_CURRENT = @LIB_VERSION_CURRENT@ +LIB_VERSION_REVISION = @LIB_VERSION_REVISION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MHD_LIBDEPS = @MHD_LIBDEPS@ +MHD_LIB_LDFLAGS = @MHD_LIB_LDFLAGS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CPPFLAGS = @PTHREAD_CPPFLAGS@ +PTHREAD_LDFLAGS = @PTHREAD_LDFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . +@USE_COVERAGE_TRUE@AM_CFLAGS = -fprofile-arcs -ftest-coverage +INCLUDES = -I$(top_srcdir)/src/include +EXTRA_DIST = README socat.c +TESTS = $(check_PROGRAMS) +daemontest_get_SOURCES = \ + daemontest_get.c + +daemontest_get_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get_chunked_SOURCES = \ + daemontest_get_chunked.c + +daemontest_get_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post_SOURCES = \ + daemontest_post.c + +daemontest_post_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform_SOURCES = \ + daemontest_postform.c + +daemontest_postform_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_SOURCES = \ + daemontest_put.c + +daemontest_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put_chunked_SOURCES = \ + daemontest_put_chunked.c + +daemontest_put_chunked_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_get11_SOURCES = \ + daemontest_get.c + +daemontest_get11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_post11_SOURCES = \ + daemontest_post.c + +daemontest_post11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_postform11_SOURCES = \ + daemontest_postform.c + +daemontest_postform11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_put11_SOURCES = \ + daemontest_put.c + +daemontest_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_large_put_SOURCES = \ + daemontest_large_put.c + +daemontest_large_put_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_large_put11_SOURCES = \ + daemontest_large_put.c + +daemontest_large_put11_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +daemontest_long_header_SOURCES = \ + daemontest_long_header.c + +daemontest_long_header_LDADD = \ + $(top_builddir)/src/daemon/libmicrohttpd.la \ + @LIBCURL@ + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/testzzuf/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/testzzuf/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +daemontest_get$(EXEEXT): $(daemontest_get_OBJECTS) $(daemontest_get_DEPENDENCIES) + @rm -f daemontest_get$(EXEEXT) + $(LINK) $(daemontest_get_OBJECTS) $(daemontest_get_LDADD) $(LIBS) +daemontest_get11$(EXEEXT): $(daemontest_get11_OBJECTS) $(daemontest_get11_DEPENDENCIES) + @rm -f daemontest_get11$(EXEEXT) + $(LINK) $(daemontest_get11_OBJECTS) $(daemontest_get11_LDADD) $(LIBS) +daemontest_get_chunked$(EXEEXT): $(daemontest_get_chunked_OBJECTS) $(daemontest_get_chunked_DEPENDENCIES) + @rm -f daemontest_get_chunked$(EXEEXT) + $(LINK) $(daemontest_get_chunked_OBJECTS) $(daemontest_get_chunked_LDADD) $(LIBS) +daemontest_large_put$(EXEEXT): $(daemontest_large_put_OBJECTS) $(daemontest_large_put_DEPENDENCIES) + @rm -f daemontest_large_put$(EXEEXT) + $(LINK) $(daemontest_large_put_OBJECTS) $(daemontest_large_put_LDADD) $(LIBS) +daemontest_large_put11$(EXEEXT): $(daemontest_large_put11_OBJECTS) $(daemontest_large_put11_DEPENDENCIES) + @rm -f daemontest_large_put11$(EXEEXT) + $(LINK) $(daemontest_large_put11_OBJECTS) $(daemontest_large_put11_LDADD) $(LIBS) +daemontest_long_header$(EXEEXT): $(daemontest_long_header_OBJECTS) $(daemontest_long_header_DEPENDENCIES) + @rm -f daemontest_long_header$(EXEEXT) + $(LINK) $(daemontest_long_header_OBJECTS) $(daemontest_long_header_LDADD) $(LIBS) +daemontest_post$(EXEEXT): $(daemontest_post_OBJECTS) $(daemontest_post_DEPENDENCIES) + @rm -f daemontest_post$(EXEEXT) + $(LINK) $(daemontest_post_OBJECTS) $(daemontest_post_LDADD) $(LIBS) +daemontest_post11$(EXEEXT): $(daemontest_post11_OBJECTS) $(daemontest_post11_DEPENDENCIES) + @rm -f daemontest_post11$(EXEEXT) + $(LINK) $(daemontest_post11_OBJECTS) $(daemontest_post11_LDADD) $(LIBS) +daemontest_postform$(EXEEXT): $(daemontest_postform_OBJECTS) $(daemontest_postform_DEPENDENCIES) + @rm -f daemontest_postform$(EXEEXT) + $(LINK) $(daemontest_postform_OBJECTS) $(daemontest_postform_LDADD) $(LIBS) +daemontest_postform11$(EXEEXT): $(daemontest_postform11_OBJECTS) $(daemontest_postform11_DEPENDENCIES) + @rm -f daemontest_postform11$(EXEEXT) + $(LINK) $(daemontest_postform11_OBJECTS) $(daemontest_postform11_LDADD) $(LIBS) +daemontest_put$(EXEEXT): $(daemontest_put_OBJECTS) $(daemontest_put_DEPENDENCIES) + @rm -f daemontest_put$(EXEEXT) + $(LINK) $(daemontest_put_OBJECTS) $(daemontest_put_LDADD) $(LIBS) +daemontest_put11$(EXEEXT): $(daemontest_put11_OBJECTS) $(daemontest_put11_DEPENDENCIES) + @rm -f daemontest_put11$(EXEEXT) + $(LINK) $(daemontest_put11_OBJECTS) $(daemontest_put11_LDADD) $(LIBS) +daemontest_put_chunked$(EXEEXT): $(daemontest_put_chunked_OBJECTS) $(daemontest_put_chunked_DEPENDENCIES) + @rm -f daemontest_put_chunked$(EXEEXT) + $(LINK) $(daemontest_put_chunked_OBJECTS) $(daemontest_put_chunked_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_get.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_get_chunked.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_large_put.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_long_header.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_post.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_postform.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_put.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemontest_put_chunked.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am + + +# 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/lib/libmicrohttpd/src/testzzuf/README b/lib/libmicrohttpd/src/testzzuf/README new file mode 100644 index 0000000000..5ee1569838 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/README @@ -0,0 +1,13 @@ +Testcases in this directory require zzuf and socat. + +zzuf is used to randomly mess with the TCP connection between the CURL +clients and the MHD server. The goal is to expose problems in MHD's +error handling (by introducing random syntax errors). socat is +used to listen on port 11081 and forward the randomzied stream to +port 11080 where MHD is waiting. + +As a result, the testcases in this directory do NOT check that +whatever CURL returns is what was expected -- random modifications to +the TCP stream can have random effects ;-). Testcases "fail" if the +code crashes or hangs indefinitely. + diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_get.c b/lib/libmicrohttpd/src/testzzuf/daemontest_get.c new file mode 100644 index 0000000000..ed0e771926 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_get.c @@ -0,0 +1,313 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_get.c + * @brief Testcase for libmicrohttpd GET operations + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +#include "socat.c" + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int ptr; + const char *me = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&ptr != *unused) + { + *unused = &ptr; + return MHD_YES; + } + *unused = NULL; + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + if (ret == MHD_NO) + abort (); + return ret; +} + + +static int +testInternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithreadedGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 16; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + +static int +testExternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + time_t start; + struct timeval tv; + int i; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 256; + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (c != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + curl_multi_info_read (multi, &running); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + } + fprintf (stderr, "\n"); + curl_multi_cleanup (multi); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalGet (); + errorCount += testMultithreadedGet (); + errorCount += testExternalGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_get_chunked.c b/lib/libmicrohttpd/src/testzzuf/daemontest_get_chunked.c new file mode 100644 index 0000000000..29ee5028c5 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_get_chunked.c @@ -0,0 +1,330 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_get_chunked.c + * @brief Testcase for libmicrohttpd GET operations with chunked content encoding + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +#include "socat.c" + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +/** + * MHD content reader callback that returns + * data in chunks. + */ +static int +crc (void *cls, uint64_t pos, char *buf, int max) +{ + struct MHD_Response **responseptr = cls; + + if (pos == 128 * 10) + { + MHD_add_response_header (*responseptr, "Footer", "working"); + return -1; /* end of stream */ + } + if (max < 128) + abort (); /* should not happen in this testcase... */ + memset (buf, 'A' + (pos / 128), 128); + return 128; +} + +/** + * Dummy function that does nothing. + */ +static void +crcf (void *ptr) +{ + free (ptr); +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + static int aptr; + const char *me = cls; + struct MHD_Response *response; + struct MHD_Response **responseptr; + int ret; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + if (&aptr != *ptr) + { + /* do never respond on first call */ + *ptr = &aptr; + return MHD_YES; + } + responseptr = malloc (sizeof (struct MHD_Response *)); + response = MHD_create_response_from_callback (-1, + 1024, + &crc, responseptr, &crcf); + *responseptr = response; + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + +static int +testInternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithreadedGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 16; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + +static int +testExternalGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + time_t start; + struct timeval tv; + int i; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); + if (d == NULL) + return 256; + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (c != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + curl_multi_info_read (multi, &running); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + } + fprintf (stderr, "\n"); + curl_multi_cleanup (multi); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalGet (); + errorCount += testMultithreadedGet (); + errorCount += testExternalGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_large_put.c b/lib/libmicrohttpd/src/testzzuf/daemontest_large_put.c new file mode 100644 index 0000000000..7bdfde8542 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_large_put.c @@ -0,0 +1,381 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_large_put.c + * @brief Testcase for libmicrohttpd PUT operations + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +#include "socat.c" + +static int oneone; + +/** + * Do not make this much larger since we will hit the + * MHD default buffer limit and the test code is not + * written for incremental upload processing... + */ +#define PUT_SIZE (256 * 1024) + +static char *put_buffer; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) +{ + unsigned int *pos = ptr; + unsigned int wrt; + + wrt = size * nmemb; + if (wrt > PUT_SIZE - (*pos)) + wrt = PUT_SIZE - (*pos); + memcpy (stream, &put_buffer[*pos], wrt); + (*pos) += wrt; + return wrt; +} + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + int *done = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp ("PUT", method)) + return MHD_NO; /* unexpected method */ + if ((*done) == 0) + { + if (*upload_data_size != PUT_SIZE) + { +#if 0 + fprintf (stderr, + "Waiting for more data (%u/%u)...\n", + *upload_data_size, PUT_SIZE); +#endif + return MHD_YES; /* not yet ready */ + } + if (0 == memcmp (upload_data, put_buffer, PUT_SIZE)) + { + *upload_data_size = 0; + } + else + { + return MHD_NO; + } + *done = 1; + return MHD_YES; + } + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testInternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + char buf[2048]; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithreadedPut () +{ + struct MHD_Daemon *d; + CURL *c; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + char buf[2048]; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ , + 11080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 16; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + +static int +testExternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + time_t start; + struct timeval tv; + unsigned int pos = 0; + int done_flag = 0; + char buf[2048]; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + multi = NULL; + d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ , + 11080, + NULL, NULL, &ahc_echo, &done_flag, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + PUT_SIZE * 4, MHD_OPTION_END); + if (d == NULL) + return 256; + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (c != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + curl_multi_info_read (multi, &running); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + curl_multi_cleanup (multi); + MHD_stop_daemon (d); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + put_buffer = malloc (PUT_SIZE); + memset (put_buffer, 1, PUT_SIZE); + errorCount += testInternalPut (); + errorCount += testMultithreadedPut (); + errorCount += testExternalPut (); + free (put_buffer); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_long_header.c b/lib/libmicrohttpd/src/testzzuf/daemontest_long_header.c new file mode 100644 index 0000000000..99b9e5e3c6 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_long_header.c @@ -0,0 +1,231 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_long_header.c + * @brief Testcase for libmicrohttpd handling of very long headers + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +#include "socat.c" + +/** + * We will set the memory available per connection to + * half of this value, so the actual value does not have + * to be big at all... + */ +#define VERY_LONG (1024*10) + +static int oneone; + +static int +apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen) +{ + return MHD_YES; +} + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + const char *me = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp (me, method)) + return MHD_NO; /* unexpected method */ + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testLongUrlGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + char *url; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, + &apc_all, + NULL, + &ahc_echo, + "GET", + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (VERY_LONG / 2), MHD_OPTION_END); + + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + url = malloc (VERY_LONG); + memset (url, 'a', VERY_LONG); + url[VERY_LONG - 1] = '\0'; + memcpy (url, "http://localhost:11081/", + strlen ("http://localhost:11081/")); + curl_easy_setopt (c, CURLOPT_URL, url); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + + MHD_stop_daemon (d); + free (url); + return 0; +} + + +static int +testLongHeaderGet () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + char *url; + struct curl_slist *header = NULL; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, + &apc_all, + NULL, + &ahc_echo, + "GET", + MHD_OPTION_CONNECTION_MEMORY_LIMIT, + (size_t) (VERY_LONG / 2), MHD_OPTION_END); + if (d == NULL) + return 16; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + url = malloc (VERY_LONG); + memset (url, 'a', VERY_LONG); + url[VERY_LONG - 1] = '\0'; + url[VERY_LONG / 2] = ':'; + url[VERY_LONG / 2 + 1] = ' '; + header = curl_slist_append (header, url); + + curl_easy_setopt (c, CURLOPT_HTTPHEADER, header); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_slist_free_all (header); + header = NULL; + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + + MHD_stop_daemon (d); + free (url); + return 0; +} + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testLongUrlGet (); + errorCount += testLongHeaderGet (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_post.c b/lib/libmicrohttpd/src/testzzuf/daemontest_post.c new file mode 100644 index 0000000000..6323a5eb82 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_post.c @@ -0,0 +1,372 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_post.c + * @brief Testcase for libmicrohttpd POST operations using URL-encoding + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + + +#include "socat.c" + +#define POST_DATA "name=daniel&project=curl" + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +/** + * Note that this post_iterator is not perfect + * in that it fails to support incremental processing. + * (to be fixed in the future) + */ +static int +post_iterator (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *value, uint64_t off, size_t size) +{ + int *eok = cls; + + if ((0 == strcmp (key, "name")) && + (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size))) + (*eok) |= 1; + if ((0 == strcmp (key, "project")) && + (size == strlen ("curl")) && (0 == strncmp (value, "curl", size))) + (*eok) |= 2; + return MHD_YES; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int eok; + struct MHD_Response *response; + struct MHD_PostProcessor *pp; + int ret; + + if (0 != strcmp ("POST", method)) + { + return MHD_NO; /* unexpected method */ + } + pp = *unused; + if (pp == NULL) + { + eok = 0; + pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok); + *unused = pp; + } + MHD_post_process (pp, upload_data, *upload_data_size); + if ((eok == 3) && (0 == *upload_data_size)) + { + response = MHD_create_response_from_data (strlen (url), + (void *) url, + MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + MHD_destroy_post_processor (pp); + *unused = NULL; + return ret; + } + *upload_data_size = 0; + return MHD_YES; +} + + +static int +testInternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + + return 0; +} + +static int +testMultithreadedPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 16; + + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + + MHD_stop_daemon (d); + return 0; +} + + +static int +testExternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + time_t start; + struct timeval tv; + int i; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ , + 1082, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 256; + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA); + curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA)); + curl_easy_setopt (c, CURLOPT_POST, 1L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (c != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + curl_multi_info_read (multi, &running); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + + } + fprintf (stderr, "\n"); + curl_multi_cleanup (multi); + zzuf_socat_stop (); + + MHD_stop_daemon (d); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPost (); + errorCount += testMultithreadedPost (); + errorCount += testExternalPost (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_postform.c b/lib/libmicrohttpd/src/testzzuf/daemontest_postform.c new file mode 100644 index 0000000000..817b0bc726 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_postform.c @@ -0,0 +1,387 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_post.c + * @brief Testcase for libmicrohttpd POST operations using multipart/postform data + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + + +#include "socat.c" + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +/** + * Note that this post_iterator is not perfect + * in that it fails to support incremental processing. + * (to be fixed in the future) + */ +static int +post_iterator (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *value, uint64_t off, size_t size) +{ + int *eok = cls; + + if (key == NULL) + return MHD_YES; +#if 0 + fprintf (stderr, "PI sees %s-%.*s\n", key, size, value); +#endif + if ((0 == strcmp (key, "name")) && + (size == strlen ("daniel")) && (0 == strncmp (value, "daniel", size))) + (*eok) |= 1; + if ((0 == strcmp (key, "project")) && + (size == strlen ("curl")) && (0 == strncmp (value, "curl", size))) + (*eok) |= 2; + return MHD_YES; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + static int eok; + struct MHD_Response *response; + struct MHD_PostProcessor *pp; + int ret; + + if (0 != strcmp ("POST", method)) + { + return MHD_NO; /* unexpected method */ + } + pp = *unused; + if (pp == NULL) + { + eok = 0; + pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok); + if (pp == NULL) + return MHD_NO; + *unused = pp; + } + MHD_post_process (pp, upload_data, *upload_data_size); + if ((eok == 3) && (0 == *upload_data_size)) + { + response = MHD_create_response_from_data (strlen (url), + (void *) url, + MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + MHD_destroy_post_processor (pp); + *unused = NULL; + return ret; + } + *upload_data_size = 0; + return MHD_YES; +} + +static struct curl_httppost * +make_form () +{ + struct curl_httppost *post = NULL; + struct curl_httppost *last = NULL; + + curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", + CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END); + curl_formadd (&post, &last, CURLFORM_COPYNAME, "project", + CURLFORM_COPYCONTENTS, "curl", CURLFORM_END); + return post; +} + + +static int +testInternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + struct curl_httppost *pd; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + pd = make_form (); + curl_easy_setopt (c, CURLOPT_HTTPPOST, pd); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + curl_formfree (pd); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithreadedPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + int i; + struct curl_httppost *pd; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ , + 11080, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 16; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + pd = make_form (); + curl_easy_setopt (c, CURLOPT_HTTPPOST, pd); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + curl_formfree (pd); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + +static int +testExternalPost () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + time_t start; + struct timeval tv; + struct curl_httppost *pd; + int i; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ , + 1082, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); + if (d == NULL) + return 256; + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + pd = make_form (); + curl_easy_setopt (c, CURLOPT_HTTPPOST, pd); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_formfree (pd); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (c != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + curl_formfree (pd); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + curl_formfree (pd); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + curl_multi_info_read (multi, &running); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + curl_formfree (pd); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + + MHD_stop_daemon (d); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPost (); + errorCount += testMultithreadedPost (); + errorCount += testExternalPost (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_put.c b/lib/libmicrohttpd/src/testzzuf/daemontest_put.c new file mode 100644 index 0000000000..c759e05559 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_put.c @@ -0,0 +1,360 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_put.c + * @brief Testcase for libmicrohttpd PUT operations + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + + +#include "socat.c" + +static int oneone; + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) +{ + unsigned int *pos = ptr; + unsigned int wrt; + + wrt = size * nmemb; + if (wrt > 8 - (*pos)) + wrt = 8 - (*pos); + memcpy (stream, &("Hello123"[*pos]), wrt); + (*pos) += wrt; + return wrt; +} + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + int *done = cls; + struct MHD_Response *response; + int ret; + + if (0 != strcmp ("PUT", method)) + return MHD_NO; /* unexpected method */ + if ((*done) == 0) + { + if (*upload_data_size != 8) + return MHD_YES; /* not yet ready */ + if (0 == memcmp (upload_data, "Hello123", 8)) + { + *upload_data_size = 0; + } + else + { + printf ("Invalid upload data `%8s'!\n", upload_data); + return MHD_NO; + } + *done = 1; + return MHD_YES; + } + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testInternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , + 11080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithreadedPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */ , + 11080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 16; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + +static int +testExternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + time_t start; + struct timeval tv; + unsigned int pos = 0; + int done_flag = 0; + int i; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG */ , + 11080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 256; + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + if (oneone) + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + else + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (c != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + curl_multi_info_read (multi, &running); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + } + fprintf (stderr, "\n"); + curl_multi_cleanup (multi); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + oneone = NULL != strstr (argv[0], "11"); + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPut (); + errorCount += testMultithreadedPut (); + errorCount += testExternalPut (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/daemontest_put_chunked.c b/lib/libmicrohttpd/src/testzzuf/daemontest_put_chunked.c new file mode 100644 index 0000000000..d49478ee91 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/daemontest_put_chunked.c @@ -0,0 +1,370 @@ +/* + This file is part of libmicrohttpd + (C) 2007, 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file daemontest_put_chunked.c + * @brief Testcase for libmicrohttpd PUT operations with chunked encoding + * for the upload data + * @author Christian Grothoff + */ + +#include "MHD_config.h" +#include "platform.h" +#include <curl/curl.h> +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef WINDOWS +#include <unistd.h> +#endif + +#include "socat.c" + +struct CBC +{ + char *buf; + size_t pos; + size_t size; +}; + +static size_t +putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) +{ + unsigned int *pos = ptr; + unsigned int wrt; + + wrt = size * nmemb; + if (wrt > 8 - (*pos)) + wrt = 8 - (*pos); + if (wrt > 4) + wrt = 4; /* only send half at first => force multiple chunks! */ + memcpy (stream, &("Hello123"[*pos]), wrt); + (*pos) += wrt; + return wrt; +} + +static size_t +copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) +{ + struct CBC *cbc = ctx; + + if (cbc->pos + size * nmemb > cbc->size) + return 0; /* overflow */ + memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); + cbc->pos += size * nmemb; + return size * nmemb; +} + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, + void **unused) +{ + int *done = cls; + struct MHD_Response *response; + int ret; + int have; + + if (0 != strcmp ("PUT", method)) + return MHD_NO; /* unexpected method */ + if ((*done) < 8) + { + have = *upload_data_size; + if (have + *done > 8) + { + return MHD_NO; + } + if (0 == memcmp (upload_data, &"Hello123"[*done], have)) + { + *done += have; + *upload_data_size = 0; + } + else + { + return MHD_NO; + } +#if 0 + fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8); +#endif + return MHD_YES; + } + response = MHD_create_response_from_data (strlen (url), + (void *) url, MHD_NO, MHD_YES); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; +} + + +static int +testInternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + int i; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, + 11080, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 1; + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + /* + // by not giving the file size, we force chunking! + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + */ + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + curl_easy_perform (c); + curl_easy_cleanup (c); + } + fprintf (stderr, "\n"); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + +static int +testMultithreadedPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + unsigned int pos = 0; + int done_flag = 0; + CURLcode errornum; + + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, + 11081, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 16; + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + /* + // by not giving the file size, we force chunking! + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + */ + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + if (CURLE_OK != (errornum = curl_easy_perform (c))) + { + fprintf (stderr, + "curl_easy_perform failed: `%s'\n", + curl_easy_strerror (errornum)); + curl_easy_cleanup (c); + MHD_stop_daemon (d); + return 32; + } + curl_easy_cleanup (c); + MHD_stop_daemon (d); + if (cbc.pos != strlen ("/hello_world")) + return 64; + if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) + return 128; + + return 0; +} + + +static int +testExternalPut () +{ + struct MHD_Daemon *d; + CURL *c; + char buf[2048]; + struct CBC cbc; + CURLM *multi; + CURLMcode mret; + fd_set rs; + fd_set ws; + fd_set es; + int max; + int running; + time_t start; + struct timeval tv; + unsigned int pos = 0; + int done_flag = 0; + int i; + + multi = NULL; + cbc.buf = buf; + cbc.size = 2048; + cbc.pos = 0; + d = MHD_start_daemon (MHD_USE_DEBUG, + 11082, + NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); + if (d == NULL) + return 256; + + multi = curl_multi_init (); + if (multi == NULL) + { + MHD_stop_daemon (d); + return 512; + } + zzuf_socat_start (); + for (i = 0; i < LOOP_COUNT; i++) + { + fprintf (stderr, "."); + c = curl_easy_init (); + curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11082/hello_world"); + curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); + curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); + curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); + curl_easy_setopt (c, CURLOPT_READDATA, &pos); + curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); + /* + // by not giving the file size, we force chunking! + curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); + */ + curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT); + curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT); + // NOTE: use of CONNECTTIMEOUT without also + // setting NOSIGNAL results in really weird + // crashes on my system! + curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); + + + mret = curl_multi_add_handle (multi, c); + if (mret != CURLM_OK) + { + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 1024; + } + start = time (NULL); + while ((time (NULL) - start < 5) && (c != NULL)) + { + max = 0; + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + curl_multi_perform (multi, &running); + mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); + if (mret != CURLM_OK) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 2048; + } + if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) + { + curl_multi_remove_handle (multi, c); + curl_multi_cleanup (multi); + curl_easy_cleanup (c); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 4096; + } + tv.tv_sec = 0; + tv.tv_usec = 1000; + select (max + 1, &rs, &ws, &es, &tv); + curl_multi_perform (multi, &running); + if (running == 0) + { + curl_multi_info_read (multi, &running); + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + c = NULL; + } + MHD_run (d); + } + if (c != NULL) + { + curl_multi_remove_handle (multi, c); + curl_easy_cleanup (c); + } + } + fprintf (stderr, "\n"); + curl_multi_cleanup (multi); + zzuf_socat_stop (); + MHD_stop_daemon (d); + return 0; +} + + + +int +main (int argc, char *const *argv) +{ + unsigned int errorCount = 0; + + if (0 != curl_global_init (CURL_GLOBAL_WIN32)) + return 2; + errorCount += testInternalPut (); + errorCount += testMultithreadedPut (); + errorCount += testExternalPut (); + if (errorCount != 0) + fprintf (stderr, "Error (code: %u)\n", errorCount); + curl_global_cleanup (); + return errorCount != 0; /* 0 == pass */ +} diff --git a/lib/libmicrohttpd/src/testzzuf/socat.c b/lib/libmicrohttpd/src/testzzuf/socat.c new file mode 100644 index 0000000000..e4559a02b4 --- /dev/null +++ b/lib/libmicrohttpd/src/testzzuf/socat.c @@ -0,0 +1,107 @@ +/* + This file is part of libmicrohttpd + (C) 2008 Christian Grothoff + + libmicrohttpd 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, or (at your + option) any later version. + + libmicrohttpd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libmicrohttpd; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file socat.c + * @brief Code to fork-exec zzuf and start the socat process + * @author Christian Grothoff + */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> + + +/** + * A larger loop count will run more random tests -- + * which would be good, except that it may take too + * long for most user's patience. So this small + * value is the default. + */ +#define LOOP_COUNT 10 + +#define CURL_TIMEOUT 50L + +static pid_t zzuf_pid; + +static void +zzuf_socat_start () +{ + int status; + char *const args[] = { + "zzuf", + "--ratio=0.0:0.75", + "-n", + "-A", + "--", + "socat", + "-lf", + "/dev/null", + "TCP4-LISTEN:11081,reuseaddr,fork", + "TCP4:127.0.0.1:11080", + NULL, + }; + zzuf_pid = fork (); + if (zzuf_pid == -1) + { + fprintf (stderr, "fork failed: %s\n", strerror (errno)); + exit (1); + } + if (zzuf_pid != 0) + { + sleep (1); /* allow zzuf and socat to start */ + status = 0; + if (0 < waitpid (zzuf_pid, &status, WNOHANG)) + { + if (WIFEXITED (status)) + fprintf (stderr, + "zzuf died with status code %d!\n", + WEXITSTATUS (status)); + if (WIFSIGNALED (status)) + fprintf (stderr, + "zzuf died from signal %d!\n", WTERMSIG (status)); + exit (1); + } + return; + } + setpgrp (); + execvp ("zzuf", args); + fprintf (stderr, "execution of `zzuf' failed: %s\n", strerror (errno)); + zzuf_pid = 0; /* fork failed */ + exit (1); +} + + +static void +zzuf_socat_stop () +{ + int status; + if (zzuf_pid != 0) + { + if (0 != killpg (zzuf_pid, SIGINT)) + fprintf (stderr, "Failed to killpg: %s\n", strerror (errno)); + kill (zzuf_pid, SIGINT); + waitpid (zzuf_pid, &status, 0); + sleep (1); /* allow socat to also die in peace */ + } +} + +/* end of socat.c */ |