diff options
Diffstat (limited to 'release/src/router/cyassl/src')
-rw-r--r-- | release/src/router/cyassl/src/Makefile.am | 43 | ||||
-rw-r--r-- | release/src/router/cyassl/src/Makefile.in | 730 | ||||
-rw-r--r-- | release/src/router/cyassl/src/cyassl_int.c | 5379 | ||||
-rw-r--r-- | release/src/router/cyassl/src/cyassl_io.c | 190 | ||||
-rw-r--r-- | release/src/router/cyassl/src/keys.c | 751 | ||||
-rw-r--r-- | release/src/router/cyassl/src/sniffer.c | 2187 | ||||
-rw-r--r-- | release/src/router/cyassl/src/ssl.c | 3496 | ||||
-rw-r--r-- | release/src/router/cyassl/src/tls.c | 457 |
8 files changed, 13233 insertions, 0 deletions
diff --git a/release/src/router/cyassl/src/Makefile.am b/release/src/router/cyassl/src/Makefile.am new file mode 100644 index 00000000..5d3181ba --- /dev/null +++ b/release/src/router/cyassl/src/Makefile.am @@ -0,0 +1,43 @@ +INCLUDES = -I../include -I../ctaocrypt/include -I../include/openssl + +lib_LTLIBRARIES = libcyassl.la +libcyassl_la_SOURCES = \ + cyassl_int.c cyassl_io.c keys.c ssl.c tls.c \ + ../ctaocrypt/src/asn.c ../ctaocrypt/src/coding.c ../ctaocrypt/src/des3.c \ + ../ctaocrypt/src/hmac.c ../ctaocrypt/src/md5.c ../ctaocrypt/src/md4.c \ + ../ctaocrypt/src/random.c ../ctaocrypt/src/rsa.c ../ctaocrypt/src/sha.c \ + ../ctaocrypt/src/aes.c ../ctaocrypt/src/sha256.c ../ctaocrypt/src/dh.c \ + ../ctaocrypt/src/dsa.c ../ctaocrypt/src/arc4.c ../ctaocrypt/src/rabbit.c \ + ../ctaocrypt/src/pwdbased.c +libcyassl_la_LDFLAGS = -no-undefined -version-info 0:0:0 +EXTRA_DIST = ../include/*.h ../include/openssl/*.h ../include/*.rc + +if BUILD_AESNI +libcyassl_la_SOURCES += ../ctaocrypt/src/aes_asm.s +endif + +if BUILD_RIPEMD +libcyassl_la_SOURCES += ../ctaocrypt/src/ripemd.c +endif + +if BUILD_SHA512 +libcyassl_la_SOURCES += ../ctaocrypt/src/sha512.c +endif + +if BUILD_SNIFFER +libcyassl_la_SOURCES += sniffer.c +endif + +if BUILD_HC128 +libcyassl_la_SOURCES += ../ctaocrypt/src/hc128.c +endif + +if BUILD_FASTMATH +libcyassl_la_SOURCES += ../ctaocrypt/src/tfm.c +else +libcyassl_la_SOURCES += ../ctaocrypt/src/integer.c +endif + +if BUILD_ECC +libcyassl_la_SOURCES += ../ctaocrypt/src/ecc.c +endif diff --git a/release/src/router/cyassl/src/Makefile.in b/release/src/router/cyassl/src/Makefile.in new file mode 100644 index 00000000..0f61b4e1 --- /dev/null +++ b/release/src/router/cyassl/src/Makefile.in @@ -0,0 +1,730 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 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@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@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@ +target_triplet = @target@ +@BUILD_AESNI_TRUE@am__append_1 = ../ctaocrypt/src/aes_asm.s +@BUILD_RIPEMD_TRUE@am__append_2 = ../ctaocrypt/src/ripemd.c +@BUILD_SHA512_TRUE@am__append_3 = ../ctaocrypt/src/sha512.c +@BUILD_SNIFFER_TRUE@am__append_4 = sniffer.c +@BUILD_HC128_TRUE@am__append_5 = ../ctaocrypt/src/hc128.c +@BUILD_FASTMATH_TRUE@am__append_6 = ../ctaocrypt/src/tfm.c +@BUILD_FASTMATH_FALSE@am__append_7 = ../ctaocrypt/src/integer.c +@BUILD_ECC_TRUE@am__append_8 = ../ctaocrypt/src/ecc.c +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ + $(top_srcdir)/m4/lib_socket_nsl.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)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/ctaocrypt/include/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libcyassl_la_LIBADD = +am__libcyassl_la_SOURCES_DIST = cyassl_int.c cyassl_io.c keys.c ssl.c \ + tls.c ../ctaocrypt/src/asn.c ../ctaocrypt/src/coding.c \ + ../ctaocrypt/src/des3.c ../ctaocrypt/src/hmac.c \ + ../ctaocrypt/src/md5.c ../ctaocrypt/src/md4.c \ + ../ctaocrypt/src/random.c ../ctaocrypt/src/rsa.c \ + ../ctaocrypt/src/sha.c ../ctaocrypt/src/aes.c \ + ../ctaocrypt/src/sha256.c ../ctaocrypt/src/dh.c \ + ../ctaocrypt/src/dsa.c ../ctaocrypt/src/arc4.c \ + ../ctaocrypt/src/rabbit.c ../ctaocrypt/src/pwdbased.c \ + ../ctaocrypt/src/aes_asm.s ../ctaocrypt/src/ripemd.c \ + ../ctaocrypt/src/sha512.c sniffer.c ../ctaocrypt/src/hc128.c \ + ../ctaocrypt/src/tfm.c ../ctaocrypt/src/integer.c \ + ../ctaocrypt/src/ecc.c +@BUILD_AESNI_TRUE@am__objects_1 = aes_asm.lo +@BUILD_RIPEMD_TRUE@am__objects_2 = ripemd.lo +@BUILD_SHA512_TRUE@am__objects_3 = sha512.lo +@BUILD_SNIFFER_TRUE@am__objects_4 = sniffer.lo +@BUILD_HC128_TRUE@am__objects_5 = hc128.lo +@BUILD_FASTMATH_TRUE@am__objects_6 = tfm.lo +@BUILD_FASTMATH_FALSE@am__objects_7 = integer.lo +@BUILD_ECC_TRUE@am__objects_8 = ecc.lo +am_libcyassl_la_OBJECTS = cyassl_int.lo cyassl_io.lo keys.lo ssl.lo \ + tls.lo asn.lo coding.lo des3.lo hmac.lo md5.lo md4.lo \ + random.lo rsa.lo sha.lo aes.lo sha256.lo dh.lo dsa.lo arc4.lo \ + rabbit.lo pwdbased.lo $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + $(am__objects_6) $(am__objects_7) $(am__objects_8) +libcyassl_la_OBJECTS = $(am_libcyassl_la_OBJECTS) +libcyassl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libcyassl_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I. -I$(top_builddir)/ctaocrypt/include@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +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 $@ +CCASCOMPILE = $(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS) +LTCCASCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS) +SOURCES = $(libcyassl_la_SOURCES) +DIST_SOURCES = $(am__libcyassl_la_SOURCES_DIST) +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@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +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@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +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_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +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@ +acx_pthread_config = @acx_pthread_config@ +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 = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I../include -I../ctaocrypt/include -I../include/openssl +lib_LTLIBRARIES = libcyassl.la +libcyassl_la_SOURCES = cyassl_int.c cyassl_io.c keys.c ssl.c tls.c \ + ../ctaocrypt/src/asn.c ../ctaocrypt/src/coding.c \ + ../ctaocrypt/src/des3.c ../ctaocrypt/src/hmac.c \ + ../ctaocrypt/src/md5.c ../ctaocrypt/src/md4.c \ + ../ctaocrypt/src/random.c ../ctaocrypt/src/rsa.c \ + ../ctaocrypt/src/sha.c ../ctaocrypt/src/aes.c \ + ../ctaocrypt/src/sha256.c ../ctaocrypt/src/dh.c \ + ../ctaocrypt/src/dsa.c ../ctaocrypt/src/arc4.c \ + ../ctaocrypt/src/rabbit.c ../ctaocrypt/src/pwdbased.c \ + $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) $(am__append_5) $(am__append_6) \ + $(am__append_7) $(am__append_8) +libcyassl_la_LDFLAGS = -no-undefined -version-info 0:0:0 +EXTRA_DIST = ../include/*.h ../include/openssl/*.h ../include/*.rc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj .s +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + 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 +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + 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 +libcyassl.la: $(libcyassl_la_OBJECTS) $(libcyassl_la_DEPENDENCIES) + $(libcyassl_la_LINK) -rpath $(libdir) $(libcyassl_la_OBJECTS) $(libcyassl_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arc4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asn.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coding.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cyassl_int.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cyassl_io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/des3.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dh.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hc128.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/integer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pwdbased.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rabbit.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripemd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha512.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sniffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tfm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 $@ $< + +asn.lo: ../ctaocrypt/src/asn.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT asn.lo -MD -MP -MF $(DEPDIR)/asn.Tpo -c -o asn.lo `test -f '../ctaocrypt/src/asn.c' || echo '$(srcdir)/'`../ctaocrypt/src/asn.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/asn.Tpo $(DEPDIR)/asn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/asn.c' object='asn.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o asn.lo `test -f '../ctaocrypt/src/asn.c' || echo '$(srcdir)/'`../ctaocrypt/src/asn.c + +coding.lo: ../ctaocrypt/src/coding.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT coding.lo -MD -MP -MF $(DEPDIR)/coding.Tpo -c -o coding.lo `test -f '../ctaocrypt/src/coding.c' || echo '$(srcdir)/'`../ctaocrypt/src/coding.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/coding.Tpo $(DEPDIR)/coding.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/coding.c' object='coding.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o coding.lo `test -f '../ctaocrypt/src/coding.c' || echo '$(srcdir)/'`../ctaocrypt/src/coding.c + +des3.lo: ../ctaocrypt/src/des3.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT des3.lo -MD -MP -MF $(DEPDIR)/des3.Tpo -c -o des3.lo `test -f '../ctaocrypt/src/des3.c' || echo '$(srcdir)/'`../ctaocrypt/src/des3.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/des3.Tpo $(DEPDIR)/des3.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/des3.c' object='des3.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o des3.lo `test -f '../ctaocrypt/src/des3.c' || echo '$(srcdir)/'`../ctaocrypt/src/des3.c + +hmac.lo: ../ctaocrypt/src/hmac.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hmac.lo -MD -MP -MF $(DEPDIR)/hmac.Tpo -c -o hmac.lo `test -f '../ctaocrypt/src/hmac.c' || echo '$(srcdir)/'`../ctaocrypt/src/hmac.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/hmac.Tpo $(DEPDIR)/hmac.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/hmac.c' object='hmac.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hmac.lo `test -f '../ctaocrypt/src/hmac.c' || echo '$(srcdir)/'`../ctaocrypt/src/hmac.c + +md5.lo: ../ctaocrypt/src/md5.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md5.lo -MD -MP -MF $(DEPDIR)/md5.Tpo -c -o md5.lo `test -f '../ctaocrypt/src/md5.c' || echo '$(srcdir)/'`../ctaocrypt/src/md5.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/md5.Tpo $(DEPDIR)/md5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/md5.c' object='md5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md5.lo `test -f '../ctaocrypt/src/md5.c' || echo '$(srcdir)/'`../ctaocrypt/src/md5.c + +md4.lo: ../ctaocrypt/src/md4.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md4.lo -MD -MP -MF $(DEPDIR)/md4.Tpo -c -o md4.lo `test -f '../ctaocrypt/src/md4.c' || echo '$(srcdir)/'`../ctaocrypt/src/md4.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/md4.Tpo $(DEPDIR)/md4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/md4.c' object='md4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md4.lo `test -f '../ctaocrypt/src/md4.c' || echo '$(srcdir)/'`../ctaocrypt/src/md4.c + +random.lo: ../ctaocrypt/src/random.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT random.lo -MD -MP -MF $(DEPDIR)/random.Tpo -c -o random.lo `test -f '../ctaocrypt/src/random.c' || echo '$(srcdir)/'`../ctaocrypt/src/random.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/random.Tpo $(DEPDIR)/random.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/random.c' object='random.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o random.lo `test -f '../ctaocrypt/src/random.c' || echo '$(srcdir)/'`../ctaocrypt/src/random.c + +rsa.lo: ../ctaocrypt/src/rsa.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rsa.lo -MD -MP -MF $(DEPDIR)/rsa.Tpo -c -o rsa.lo `test -f '../ctaocrypt/src/rsa.c' || echo '$(srcdir)/'`../ctaocrypt/src/rsa.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/rsa.Tpo $(DEPDIR)/rsa.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/rsa.c' object='rsa.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rsa.lo `test -f '../ctaocrypt/src/rsa.c' || echo '$(srcdir)/'`../ctaocrypt/src/rsa.c + +sha.lo: ../ctaocrypt/src/sha.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha.lo -MD -MP -MF $(DEPDIR)/sha.Tpo -c -o sha.lo `test -f '../ctaocrypt/src/sha.c' || echo '$(srcdir)/'`../ctaocrypt/src/sha.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/sha.Tpo $(DEPDIR)/sha.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/sha.c' object='sha.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha.lo `test -f '../ctaocrypt/src/sha.c' || echo '$(srcdir)/'`../ctaocrypt/src/sha.c + +aes.lo: ../ctaocrypt/src/aes.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aes.lo -MD -MP -MF $(DEPDIR)/aes.Tpo -c -o aes.lo `test -f '../ctaocrypt/src/aes.c' || echo '$(srcdir)/'`../ctaocrypt/src/aes.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/aes.Tpo $(DEPDIR)/aes.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/aes.c' object='aes.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aes.lo `test -f '../ctaocrypt/src/aes.c' || echo '$(srcdir)/'`../ctaocrypt/src/aes.c + +sha256.lo: ../ctaocrypt/src/sha256.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha256.lo -MD -MP -MF $(DEPDIR)/sha256.Tpo -c -o sha256.lo `test -f '../ctaocrypt/src/sha256.c' || echo '$(srcdir)/'`../ctaocrypt/src/sha256.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/sha256.Tpo $(DEPDIR)/sha256.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/sha256.c' object='sha256.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha256.lo `test -f '../ctaocrypt/src/sha256.c' || echo '$(srcdir)/'`../ctaocrypt/src/sha256.c + +dh.lo: ../ctaocrypt/src/dh.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dh.lo -MD -MP -MF $(DEPDIR)/dh.Tpo -c -o dh.lo `test -f '../ctaocrypt/src/dh.c' || echo '$(srcdir)/'`../ctaocrypt/src/dh.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dh.Tpo $(DEPDIR)/dh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/dh.c' object='dh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dh.lo `test -f '../ctaocrypt/src/dh.c' || echo '$(srcdir)/'`../ctaocrypt/src/dh.c + +dsa.lo: ../ctaocrypt/src/dsa.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dsa.lo -MD -MP -MF $(DEPDIR)/dsa.Tpo -c -o dsa.lo `test -f '../ctaocrypt/src/dsa.c' || echo '$(srcdir)/'`../ctaocrypt/src/dsa.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dsa.Tpo $(DEPDIR)/dsa.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/dsa.c' object='dsa.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dsa.lo `test -f '../ctaocrypt/src/dsa.c' || echo '$(srcdir)/'`../ctaocrypt/src/dsa.c + +arc4.lo: ../ctaocrypt/src/arc4.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT arc4.lo -MD -MP -MF $(DEPDIR)/arc4.Tpo -c -o arc4.lo `test -f '../ctaocrypt/src/arc4.c' || echo '$(srcdir)/'`../ctaocrypt/src/arc4.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/arc4.Tpo $(DEPDIR)/arc4.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/arc4.c' object='arc4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o arc4.lo `test -f '../ctaocrypt/src/arc4.c' || echo '$(srcdir)/'`../ctaocrypt/src/arc4.c + +rabbit.lo: ../ctaocrypt/src/rabbit.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rabbit.lo -MD -MP -MF $(DEPDIR)/rabbit.Tpo -c -o rabbit.lo `test -f '../ctaocrypt/src/rabbit.c' || echo '$(srcdir)/'`../ctaocrypt/src/rabbit.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/rabbit.Tpo $(DEPDIR)/rabbit.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/rabbit.c' object='rabbit.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rabbit.lo `test -f '../ctaocrypt/src/rabbit.c' || echo '$(srcdir)/'`../ctaocrypt/src/rabbit.c + +pwdbased.lo: ../ctaocrypt/src/pwdbased.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pwdbased.lo -MD -MP -MF $(DEPDIR)/pwdbased.Tpo -c -o pwdbased.lo `test -f '../ctaocrypt/src/pwdbased.c' || echo '$(srcdir)/'`../ctaocrypt/src/pwdbased.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/pwdbased.Tpo $(DEPDIR)/pwdbased.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/pwdbased.c' object='pwdbased.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pwdbased.lo `test -f '../ctaocrypt/src/pwdbased.c' || echo '$(srcdir)/'`../ctaocrypt/src/pwdbased.c + +ripemd.lo: ../ctaocrypt/src/ripemd.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ripemd.lo -MD -MP -MF $(DEPDIR)/ripemd.Tpo -c -o ripemd.lo `test -f '../ctaocrypt/src/ripemd.c' || echo '$(srcdir)/'`../ctaocrypt/src/ripemd.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ripemd.Tpo $(DEPDIR)/ripemd.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/ripemd.c' object='ripemd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ripemd.lo `test -f '../ctaocrypt/src/ripemd.c' || echo '$(srcdir)/'`../ctaocrypt/src/ripemd.c + +sha512.lo: ../ctaocrypt/src/sha512.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sha512.lo -MD -MP -MF $(DEPDIR)/sha512.Tpo -c -o sha512.lo `test -f '../ctaocrypt/src/sha512.c' || echo '$(srcdir)/'`../ctaocrypt/src/sha512.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/sha512.Tpo $(DEPDIR)/sha512.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/sha512.c' object='sha512.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sha512.lo `test -f '../ctaocrypt/src/sha512.c' || echo '$(srcdir)/'`../ctaocrypt/src/sha512.c + +hc128.lo: ../ctaocrypt/src/hc128.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hc128.lo -MD -MP -MF $(DEPDIR)/hc128.Tpo -c -o hc128.lo `test -f '../ctaocrypt/src/hc128.c' || echo '$(srcdir)/'`../ctaocrypt/src/hc128.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/hc128.Tpo $(DEPDIR)/hc128.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/hc128.c' object='hc128.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hc128.lo `test -f '../ctaocrypt/src/hc128.c' || echo '$(srcdir)/'`../ctaocrypt/src/hc128.c + +tfm.lo: ../ctaocrypt/src/tfm.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tfm.lo -MD -MP -MF $(DEPDIR)/tfm.Tpo -c -o tfm.lo `test -f '../ctaocrypt/src/tfm.c' || echo '$(srcdir)/'`../ctaocrypt/src/tfm.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/tfm.Tpo $(DEPDIR)/tfm.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/tfm.c' object='tfm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tfm.lo `test -f '../ctaocrypt/src/tfm.c' || echo '$(srcdir)/'`../ctaocrypt/src/tfm.c + +integer.lo: ../ctaocrypt/src/integer.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT integer.lo -MD -MP -MF $(DEPDIR)/integer.Tpo -c -o integer.lo `test -f '../ctaocrypt/src/integer.c' || echo '$(srcdir)/'`../ctaocrypt/src/integer.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/integer.Tpo $(DEPDIR)/integer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/integer.c' object='integer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o integer.lo `test -f '../ctaocrypt/src/integer.c' || echo '$(srcdir)/'`../ctaocrypt/src/integer.c + +ecc.lo: ../ctaocrypt/src/ecc.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ecc.lo -MD -MP -MF $(DEPDIR)/ecc.Tpo -c -o ecc.lo `test -f '../ctaocrypt/src/ecc.c' || echo '$(srcdir)/'`../ctaocrypt/src/ecc.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ecc.Tpo $(DEPDIR)/ecc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../ctaocrypt/src/ecc.c' object='ecc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ecc.lo `test -f '../ctaocrypt/src/ecc.c' || echo '$(srcdir)/'`../ctaocrypt/src/ecc.c + +.s.o: + $(CCASCOMPILE) -c -o $@ $< + +.s.obj: + $(CCASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.s.lo: + $(LTCCASCOMPILE) -c -o $@ $< + +aes_asm.lo: ../ctaocrypt/src/aes_asm.s + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS) -c -o aes_asm.lo `test -f '../ctaocrypt/src/aes_asm.s' || echo '$(srcdir)/'`../ctaocrypt/src/aes_asm.s + +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; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && 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 $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +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) + +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-libLTLIBRARIES clean-libtool \ + 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 + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: 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: uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool 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-libLTLIBRARIES 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 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/release/src/router/cyassl/src/cyassl_int.c b/release/src/router/cyassl/src/cyassl_int.c new file mode 100644 index 00000000..ffdc9ae7 --- /dev/null +++ b/release/src/router/cyassl/src/cyassl_int.c @@ -0,0 +1,5379 @@ +/* cyassl_int.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + + +#include "cyassl_int.h" +#include "cyassl_error.h" +#include "asn.h" + +#ifdef HAVE_LIBZ + #include "zlib.h" +#endif + +#ifdef HAVE_NTRU + #include "crypto_ntru.h" +#endif + +#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS) + #include <stdio.h> +#endif + +#ifdef __sun + #include <sys/filio.h> +#endif + +#define TRUE 1 +#define FALSE 0 + + +#if defined(OPENSSL_EXTRA) && defined(NO_DH) + #error OPENSSL_EXTRA needs DH, please remove NO_DH +#endif + + +int CyaSSL_negotiate(SSL*); + + +#ifndef NO_CYASSL_CLIENT + static int DoHelloVerifyRequest(SSL* ssl, const byte* input, word32*); + static int DoServerHello(SSL* ssl, const byte* input, word32*); + static int DoCertificateRequest(SSL* ssl, const byte* input, word32*); + static int DoServerKeyExchange(SSL* ssl, const byte* input, word32*); +#endif + + +#ifndef NO_CYASSL_SERVER + static int DoClientHello(SSL* ssl, const byte* input, word32*, word32, + word32); + static int DoCertificateVerify(SSL* ssl, byte*, word32*, word32); + static int DoClientKeyExchange(SSL* ssl, byte* input, word32*); +#endif + +typedef enum { + doProcessInit = 0, +#ifndef NO_CYASSL_SERVER + runProcessOldClientHello, +#endif + getRecordLayerHeader, + getData, + runProcessingOneMessage +} processReply; + +static void Hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz, + int content, int verify); + +static void BuildCertHashes(SSL* ssl, Hashes* hashes); + + +void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender); + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +int IsTLS(const SSL* ssl) +{ + if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR) + return 1; + + return 0; +} + + +int IsAtLeastTLSv1_2(const SSL* ssl) +{ + if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR) + return 1; + + return 0; +} + + +#ifdef HAVE_NTRU + +static byte GetEntropy(ENTROPY_CMD cmd, byte* out) +{ + /* TODO: add locking? */ + static RNG rng; + + if (cmd == INIT) { + int ret = InitRng(&rng); + if (ret == 0) + return 1; + else + return 0; + } + + if (out == NULL) + return 0; + + if (cmd == GET_BYTE_OF_ENTROPY) { + RNG_GenerateBlock(&rng, out, 1); + return 1; + } + + if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) { + *out = 1; + return 1; + } + + return 0; +} + +#endif /* HAVE_NTRU */ + +static INLINE void c32to24(word32 in, word24 out) +{ + out[0] = (in >> 16) & 0xff; + out[1] = (in >> 8) & 0xff; + out[2] = in & 0xff; +} + + +static INLINE void c32to48(word32 in, byte out[6]) +{ + out[0] = 0; + out[1] = 0; + out[2] = (in >> 24) & 0xff; + out[3] = (in >> 16) & 0xff; + out[4] = (in >> 8) & 0xff; + out[5] = in & 0xff; +} + + +/* convert 16 bit integer to opaque */ +static void INLINE c16toa(word16 u16, byte* c) +{ + c[0] = (u16 >> 8) & 0xff; + c[1] = u16 & 0xff; +} + + +/* convert 32 bit integer to opaque */ +static INLINE void c32toa(word32 u32, byte* c) +{ + c[0] = (u32 >> 24) & 0xff; + c[1] = (u32 >> 16) & 0xff; + c[2] = (u32 >> 8) & 0xff; + c[3] = u32 & 0xff; +} + + +/* convert a 24 bit integer into a 32 bit one */ +static INLINE void c24to32(const word24 u24, word32* u32) +{ + *u32 = 0; + *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; +} + + +/* convert opaque to 16 bit integer */ +static INLINE void ato16(const byte* c, word16* u16) +{ + *u16 = 0; + *u16 = (c[0] << 8) | (c[1]); +} + + +/* convert opaque to 32 bit integer */ +static INLINE void ato32(const byte* c, word32* u32) +{ + *u32 = 0; + *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; +} + + +#ifdef HAVE_LIBZ + + /* alloc user allocs to work with zlib */ + void* myAlloc(void* opaque, unsigned int item, unsigned int size) + { + return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ); + } + + + void myFree(void* opaque, void* memory) + { + XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ); + } + + + /* init zlib comp/decomp streams, 0 on success */ + static int InitStreams(SSL* ssl) + { + ssl->c_stream.zalloc = (alloc_func)myAlloc; + ssl->c_stream.zfree = (free_func)myFree; + ssl->c_stream.opaque = (voidpf)ssl->heap; + + if (deflateInit(&ssl->c_stream, 8) != Z_OK) return ZLIB_INIT_ERROR; + + ssl->didStreamInit = 1; + + ssl->d_stream.zalloc = (alloc_func)myAlloc; + ssl->d_stream.zfree = (free_func)myFree; + ssl->d_stream.opaque = (voidpf)ssl->heap; + + if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR; + + return 0; + } + + + static void FreeStreams(SSL* ssl) + { + if (ssl->didStreamInit) { + deflateEnd(&ssl->c_stream); + inflateEnd(&ssl->d_stream); + } + } + + + /* compress in to out, return out size or error */ + static int Compress(SSL* ssl, byte* in, int inSz, byte* out, int outSz) + { + int err; + int currTotal = ssl->c_stream.total_out; + + /* put size in front of compression */ + c16toa((word16)inSz, out); + out += 2; + outSz -= 2; + + ssl->c_stream.next_in = in; + ssl->c_stream.avail_in = inSz; + ssl->c_stream.next_out = out; + ssl->c_stream.avail_out = outSz; + + err = deflate(&ssl->c_stream, Z_SYNC_FLUSH); + if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR; + + return ssl->c_stream.total_out - currTotal + sizeof(word16); + } + + + /* decompress in to out, returnn out size or error */ + static int DeCompress(SSL* ssl, byte* in, int inSz, byte* out, int outSz) + { + int err; + int currTotal = ssl->d_stream.total_out; + word16 len; + + /* find size in front of compression */ + ato16(in, &len); + in += 2; + inSz -= 2; + + ssl->d_stream.next_in = in; + ssl->d_stream.avail_in = inSz; + ssl->d_stream.next_out = out; + ssl->d_stream.avail_out = outSz; + + err = inflate(&ssl->d_stream, Z_SYNC_FLUSH); + if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR; + + return ssl->d_stream.total_out - currTotal; + } + +#endif /* HAVE_LIBZ */ + + +void InitSSL_Method(SSL_METHOD* method, ProtocolVersion pv) +{ + method->version = pv; + method->side = CLIENT_END; + method->verifyPeer = 0; + method->verifyNone = 0; + method->failNoCert = 0; + method->downgrade = 0; +} + + +void InitSSL_Ctx(SSL_CTX* ctx, SSL_METHOD* method) +{ + ctx->method = method; + ctx->certificate.buffer = 0; + ctx->privateKey.buffer = 0; + ctx->haveDH = 0; + ctx->haveNTRU = 0; /* start off */ + ctx->haveECDSA = 0; /* start off */ + ctx->heap = ctx; /* defaults to self */ +#ifndef NO_PSK + ctx->havePSK = 0; + ctx->server_hint[0] = 0; + ctx->client_psk_cb = 0; + ctx->server_psk_cb = 0; +#endif /* NO_PSK */ + +#ifdef OPENSSL_EXTRA + ctx->passwd_cb = 0; + ctx->userdata = 0; +#endif /* OPENSSL_EXTRA */ + +#ifndef CYASSL_USER_IO + ctx->CBIORecv = EmbedReceive; + ctx->CBIOSend = EmbedSend; +#else + /* user will set */ + ctx->CBIORecv = NULL; + ctx->CBIOSend = NULL; +#endif + ctx->partialWrite = 0; + ctx->verifyCallback = 0; + + ctx->caList = 0; +#ifdef HAVE_NTRU + if (method->side == CLIENT_END) + ctx->haveNTRU = 1; /* always on cliet side */ + /* server can turn on by loading key */ +#endif +#ifdef HAVE_ECC + if (method->side == CLIENT_END) + ctx->haveECDSA = 1; /* always on cliet side */ + /* server can turn on by loading key */ +#endif + /* remove DH later if server didn't set, add psk later */ + InitSuites(&ctx->suites, method->version, TRUE, FALSE, ctx->haveNTRU, + ctx->haveECDSA, method->side); + ctx->verifyPeer = 0; + ctx->verifyNone = 0; + ctx->failNoCert = 0; + ctx->sessionCacheOff = 0; /* initially on */ + ctx->sessionCacheFlushOff = 0; /* initially on */ + ctx->sendVerify = 0; + ctx->quietShutdown = 0; + +} + + +/* In case contexts are held in array and don't want to free actual ctx */ +void SSL_CtxResourceFree(SSL_CTX* ctx) +{ + XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY); + XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT); + XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); + + FreeSigners(ctx->caList, ctx->heap); +} + + +void FreeSSL_Ctx(SSL_CTX* ctx) +{ + SSL_CtxResourceFree(ctx); + XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX); +} + + + +void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK, + byte haveNTRU, byte haveECDSA, int side) +{ + word32 idx = 0; + int tls = pv.major == 3 && pv.minor >= 1; + int haveRSA = 1; + + (void)tls; /* shut up compiler */ + + if (side == SERVER_END && haveECDSA) + haveRSA = 0; /* can't do RSA with ECDSA cert */ + +#ifdef CYASSL_DTLS + if (pv.major == DTLS_MAJOR && pv.minor == DTLS_MINOR) + tls = 1; +#endif + + suites->setSuites = 0; /* user hasn't set yet */ + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveNTRU && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + if (tls && haveECDSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + if (tls && haveECDSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + if (tls && haveECDSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveECDSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = ECC_BYTE; + suites->suites[idx++] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + if (tls && haveDH && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + if (tls && havePSK) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + if (tls && havePSK) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + if (haveRSA ) { + suites->suites[idx++] = 0; + suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + if (haveRSA ) { + suites->suites[idx++] = 0; + suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5; + } +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + if (haveRSA ) { + suites->suites[idx++] = 0; + suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5 + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_MD5; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_SHA; + } +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA + if (tls && haveRSA) { + suites->suites[idx++] = 0; + suites->suites[idx++] = TLS_RSA_WITH_RABBIT_CBC_SHA; + } +#endif + + suites->suiteSz = idx; +} + + +int InitSSL(SSL* ssl, SSL_CTX* ctx) +{ + int ret; + byte havePSK = 0; + + ssl->ctx = ctx; /* only for passing to calls, options could change */ + ssl->version = ctx->method->version; + ssl->suites = ctx->suites; + +#ifdef HAVE_LIBZ + ssl->didStreamInit = 0; +#endif + + ssl->buffers.certificate.buffer = 0; + ssl->buffers.key.buffer = 0; + ssl->buffers.inputBuffer.length = 0; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; + ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.inputBuffer.dynamicFlag = 0; + ssl->buffers.outputBuffer.length = 0; + ssl->buffers.outputBuffer.idx = 0; + ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; + ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.outputBuffer.dynamicFlag = 0; + ssl->buffers.domainName.buffer = 0; + ssl->buffers.serverDH_P.buffer = 0; + ssl->buffers.serverDH_G.buffer = 0; + ssl->buffers.serverDH_Pub.buffer = 0; + ssl->buffers.serverDH_Priv.buffer = 0; + ssl->buffers.clearOutputBuffer.buffer = 0; + ssl->buffers.clearOutputBuffer.length = 0; + ssl->buffers.prevSent = 0; + ssl->buffers.plainSz = 0; + + if ( (ret = InitRng(&ssl->rng)) ) + return ret; + + InitMd5(&ssl->hashMd5); + InitSha(&ssl->hashSha); +#ifndef NO_SHA256 + InitSha256(&ssl->hashSha256); +#endif + InitRsaKey(&ssl->peerRsaKey, ctx->heap); + + ssl->peerRsaKeyPresent = 0; + ssl->options.side = ctx->method->side; + ssl->options.downgrade = ctx->method->downgrade; + ssl->error = 0; + ssl->options.connReset = 0; + ssl->options.isClosed = 0; + ssl->options.closeNotify = 0; + ssl->options.sentNotify = 0; + ssl->options.usingCompression = 0; + ssl->options.haveDH = ctx->haveDH; + ssl->options.haveNTRU = ctx->haveNTRU; + ssl->options.haveECDSA = ctx->haveECDSA; + ssl->options.havePeerCert = 0; + ssl->options.usingPSK_cipher = 0; + ssl->options.sendAlertState = 0; +#ifndef NO_PSK + havePSK = ctx->havePSK; + ssl->options.havePSK = ctx->havePSK; + ssl->options.client_psk_cb = ctx->client_psk_cb; + ssl->options.server_psk_cb = ctx->server_psk_cb; +#endif /* NO_PSK */ + + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = doProcessInit; + +#ifdef CYASSL_DTLS + ssl->keys.dtls_sequence_number = 0; + ssl->keys.dtls_peer_sequence_number = 0; + ssl->keys.dtls_handshake_number = 0; + ssl->keys.dtls_epoch = 0; + ssl->keys.dtls_peer_epoch = 0; +#endif + ssl->keys.encryptionOn = 0; /* initially off */ + ssl->options.sessionCacheOff = ctx->sessionCacheOff; + ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff; + + ssl->options.verifyPeer = ctx->verifyPeer; + ssl->options.verifyNone = ctx->verifyNone; + ssl->options.failNoCert = ctx->failNoCert; + ssl->options.sendVerify = ctx->sendVerify; + + ssl->options.resuming = 0; + ssl->hmac = Hmac; /* default to SSLv3 */ + ssl->heap = ctx->heap; /* defaults to self */ + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->options.dtls = 0; + ssl->options.partialWrite = ctx->partialWrite; + ssl->options.quietShutdown = ctx->quietShutdown; + + /* SSL_CTX still owns certificate, key, and caList buffers */ + ssl->buffers.certificate = ctx->certificate; + ssl->buffers.key = ctx->privateKey; + ssl->caList = ctx->caList; + +#ifdef OPENSSL_EXTRA + ssl->peerCert.issuer.sz = 0; + ssl->peerCert.subject.sz = 0; +#endif + + /* make sure server has cert and key unless using PSK */ + if (ssl->options.side == SERVER_END && !havePSK) + if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer) + return NO_PRIVATE_KEY; + +#ifndef NO_PSK + ssl->arrays.client_identity[0] = 0; + if (ctx->server_hint[0]) /* set in CTX */ + XSTRNCPY(ssl->arrays.server_hint, ctx->server_hint, MAX_PSK_ID_LEN); + else + ssl->arrays.server_hint[0] = 0; +#endif /* NO_PSK */ + +#ifdef CYASSL_CALLBACKS + ssl->hsInfoOn = 0; + ssl->toInfoOn = 0; +#endif + +#ifdef HAVE_ECC + ssl->peerEccKeyPresent = 0; + ecc_init(&ssl->peerEccKey); + ssl->peerEccDsaKeyPresent = 0; + ecc_init(&ssl->peerEccDsaKey); + ssl->eccDsaKeyPresent = 0; + ecc_init(&ssl->eccDsaKey); + ssl->eccTempKeyPresent = 0; + ecc_init(&ssl->eccTempKey); + + /* make ECDHE for server side */ + if (ssl->options.side == SERVER_END) { + if (ecc_make_key(&ssl->rng, ECDHE_SIZE, &ssl->eccTempKey) != 0) + return ECC_MAKEKEY_ERROR; + ssl->eccTempKeyPresent = 1; + } +#endif + + /* make sure server has DH parms, and add PSK if there, add NTRU too */ + if (!ssl->ctx->suites.setSuites) { /* trust user override */ + if (ssl->options.side == SERVER_END) + InitSuites(&ssl->suites, ssl->version,ssl->options.haveDH, havePSK, + ssl->options.haveNTRU, ssl->options.haveECDSA, + ssl->ctx->method->side); + else + InitSuites(&ssl->suites, ssl->version, TRUE, havePSK, + ssl->options.haveNTRU, ssl->options.haveECDSA, + ssl->ctx->method->side); + } + + ssl->rfd = -1; /* set to invalid descriptor */ + ssl->wfd = -1; + ssl->biord = 0; + ssl->biowr = 0; + + ssl->IOCB_ReadCtx = &ssl->rfd; /* prevent invalid pointer acess if not */ + ssl->IOCB_WriteCtx = &ssl->wfd; /* correctly set */ + +#ifdef SESSION_CERTS + ssl->session.chain.count = 0; +#endif + + ssl->cipher.ssl = ssl; + + return 0; +} + + +int BIO_free(BIO*); /* cyassl_int doesn't have */ + + +/* In case holding SSL object in array and don't want to free actual ssl */ +void SSL_ResourceFree(SSL* ssl) +{ + XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH); + XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH); + XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH); + XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH); + XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); + FreeRsaKey(&ssl->peerRsaKey); + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, FORCED_FREE); + if (ssl->buffers.outputBuffer.dynamicFlag) + ShrinkOutputBuffer(ssl); +#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS) + BIO_free(ssl->biord); + if (ssl->biord != ssl->biowr) /* in case same as write */ + BIO_free(ssl->biowr); +#endif +#ifdef HAVE_LIBZ + FreeStreams(ssl); +#endif +#ifdef HAVE_ECC + ecc_free(&ssl->peerEccKey); + ecc_free(&ssl->peerEccDsaKey); + ecc_free(&ssl->eccTempKey); + ecc_free(&ssl->eccDsaKey); +#endif +} + + +void FreeSSL(SSL* ssl) +{ + SSL_ResourceFree(ssl); + XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL); +} + + +ProtocolVersion MakeSSLv3(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = SSLv3_MINOR; + + return pv; +} + + +#ifdef CYASSL_DTLS + +ProtocolVersion MakeDTLSv1(void) +{ + ProtocolVersion pv; + pv.major = DTLS_MAJOR; + pv.minor = DTLS_MINOR; + + return pv; +} + +#endif /* CYASSL_DTLS */ + + + + +#ifdef USE_WINDOWS_API + + timer_d Timer(void) + { + static int init = 0; + static LARGE_INTEGER freq; + LARGE_INTEGER count; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = 1; + } + + QueryPerformanceCounter(&count); + + return (double)count.QuadPart / freq.QuadPart; + } + + + word32 LowResTimer(void) + { + return (word32)Timer(); + } + + +#elif defined(THREADX) + + #include "rtptime.h" + + word32 LowResTimer(void) + { + return (word32)rtp_get_system_sec(); + } + + +#elif defined(MICRIUM) + + word32 LowResTimer(void) + { + NET_SECURE_OS_TICK clk; + + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + clk = NetSecure_OS_TimeGet(); + #endif + return (word32)clk; + } + +#elif defined(USER_TICKS) + + word32 LowResTimer(void) + { + /* + write your own clock tick function if don't want time(0) + needs second accuracy but doesn't have to correlated to EPOCH + */ + } + +#else /* !USE_WINDOWS_API && !THREADX && !MICRIUM && !USER_TICKS */ + + #include <time.h> + + word32 LowResTimer(void) + { + return time(0); + } + + +#endif /* USE_WINDOWS_API */ + + +/* add output to md5 and sha handshake hashes, exclude record header */ +static void HashOutput(SSL* ssl, const byte* output, int sz, int ivSz) +{ + const byte* buffer = output + RECORD_HEADER_SZ + ivSz; + sz -= RECORD_HEADER_SZ; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + buffer += DTLS_RECORD_EXTRA; + sz -= DTLS_RECORD_EXTRA; + } +#endif + + Md5Update(&ssl->hashMd5, buffer, sz); + ShaUpdate(&ssl->hashSha, buffer, sz); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + Sha256Update(&ssl->hashSha256, buffer, sz); +#endif +} + + +/* add input to md5 and sha handshake hashes, include handshake header */ +static void HashInput(SSL* ssl, const byte* input, int sz) +{ + const byte* buffer = input - HANDSHAKE_HEADER_SZ; + sz += HANDSHAKE_HEADER_SZ; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + buffer -= DTLS_HANDSHAKE_EXTRA; + sz += DTLS_HANDSHAKE_EXTRA; + } +#endif + + Md5Update(&ssl->hashMd5, buffer, sz); + ShaUpdate(&ssl->hashSha, buffer, sz); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + Sha256Update(&ssl->hashSha256, buffer, sz); +#endif +} + + +/* add record layer header for message */ +static void AddRecordHeader(byte* output, word32 length, byte type, SSL* ssl) +{ + RecordLayerHeader* rl; + + /* record layer header */ + rl = (RecordLayerHeader*)output; + rl->type = type; + rl->version = ssl->version; /* type and version same in each */ + + if (!ssl->options.dtls) + c16toa((word16)length, rl->length); + else { +#ifdef CYASSL_DTLS + DtlsRecordLayerHeader* dtls; + + /* dtls record layer header extensions */ + dtls = (DtlsRecordLayerHeader*)output; + c16toa(ssl->keys.dtls_epoch, dtls->epoch); + c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number); + c16toa((word16)length, dtls->length); +#endif + } +} + + +/* add handshake header for message */ +static void AddHandShakeHeader(byte* output, word32 length, byte type, SSL* ssl) +{ + HandShakeHeader* hs; + + /* handshake header */ + hs = (HandShakeHeader*)output; + hs->type = type; + c32to24(length, hs->length); /* type and length same for each */ +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsHandShakeHeader* dtls; + + /* dtls handshake header extensions */ + dtls = (DtlsHandShakeHeader*)output; + c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq); + c32to24(0, dtls->fragment_offset); + c32to24(length, dtls->fragment_length); + } +#endif +} + + +/* add both headers for handshake message */ +static void AddHeaders(byte* output, word32 length, byte type, SSL* ssl) +{ + if (!ssl->options.dtls) { + AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl); + AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl); + } + else { + AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl); + AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl); + } +} + + +static int Receive(SSL* ssl, byte* buf, word32 sz, int flags) +{ + int recvd; + +retry: + recvd = ssl->ctx->CBIORecv((char *)buf, (int)sz, ssl->IOCB_ReadCtx); + if (recvd < 0) + switch (recvd) { + case IO_ERR_GENERAL: /* general/unknown error */ + return -1; + + case IO_ERR_WANT_READ: /* want read, would block */ + return WANT_READ; + + case IO_ERR_CONN_RST: /* connection reset */ + ssl->options.connReset = 1; + return -1; + + case IO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef CYASSL_CALLBACKS + if (ssl->toInfoOn) { + struct itimerval timeout; + getitimer(ITIMER_REAL, &timeout); + if (timeout.it_value.tv_sec == 0 && + timeout.it_value.tv_usec == 0) { + XSTRNCPY(ssl->timeoutInfo.timeoutName, + "recv() timeout", MAX_TIMEOUT_NAME_SZ); + return 0; + } + } + #endif + goto retry; + + case IO_ERR_CONN_CLOSE: /* peer closed connection */ + ssl->options.isClosed = 1; + return -1; + } + + return recvd; +} + + +/* Switch dynamic output buffer back to static, buffer is assumed clear */ +void ShrinkOutputBuffer(SSL* ssl) +{ + CYASSL_MSG("Shrinking output buffer\n"); + XFREE(ssl->buffers.outputBuffer.buffer, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; + ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.outputBuffer.dynamicFlag = 0; +} + + +/* Switch dynamic input buffer back to static, keep any remaining input */ +/* forced free means cleaning up */ +void ShrinkInputBuffer(SSL* ssl, int forcedFree) +{ + int usedLength = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (!forcedFree && usedLength > STATIC_BUFFER_LEN) + return; + + CYASSL_MSG("Shrinking input buffer\n"); + + if (!forcedFree && usedLength) + XMEMCPY(ssl->buffers.inputBuffer.staticBuffer, + ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + usedLength); + + XFREE(ssl->buffers.inputBuffer.buffer, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; + ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; + ssl->buffers.inputBuffer.dynamicFlag = 0; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; +} + + +int SendBuffered(SSL* ssl) +{ + while (ssl->buffers.outputBuffer.length > 0) { + int sent = ssl->ctx->CBIOSend((char*)ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx, + (int)ssl->buffers.outputBuffer.length, + ssl->IOCB_WriteCtx); + if (sent < 0) { + switch (sent) { + + case IO_ERR_WANT_WRITE: /* would block */ + return WANT_WRITE; + + case IO_ERR_CONN_RST: /* connection reset */ + ssl->options.connReset = 1; + break; + + case IO_ERR_ISR: /* interrupt */ + /* see if we got our timeout */ + #ifdef CYASSL_CALLBACKS + if (ssl->toInfoOn) { + struct itimerval timeout; + getitimer(ITIMER_REAL, &timeout); + if (timeout.it_value.tv_sec == 0 && + timeout.it_value.tv_usec == 0) { + XSTRNCPY(ssl->timeoutInfo.timeoutName, + "send() timeout", MAX_TIMEOUT_NAME_SZ); + return WANT_WRITE; + } + } + #endif + continue; + + case IO_ERR_CONN_CLOSE: /* epipe / conn closed, same as reset */ + ssl->options.connReset = 1; + break; + } + + return SOCKET_ERROR_E; + } + + ssl->buffers.outputBuffer.idx += sent; + ssl->buffers.outputBuffer.length -= sent; + } + + ssl->buffers.outputBuffer.idx = 0; + + if (ssl->buffers.outputBuffer.dynamicFlag) + ShrinkOutputBuffer(ssl); + + return 0; +} + + +/* Grow the output buffer, should only be to send cert, should be blank */ +static INLINE int GrowOutputBuffer(SSL* ssl, int size) +{ + byte* tmp = (byte*) XMALLOC(size + ssl->buffers.outputBuffer.length, + ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + CYASSL_MSG("growing output buffer\n"); + + if (!tmp) return -1; + + if (ssl->buffers.outputBuffer.length) + XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer, + ssl->buffers.outputBuffer.length); + + if (ssl->buffers.outputBuffer.dynamicFlag) + XFREE(ssl->buffers.outputBuffer.buffer, ssl->heap, + DYNAMIC_TYPE_OUT_BUFFER); + ssl->buffers.outputBuffer.dynamicFlag = 1; + ssl->buffers.outputBuffer.buffer = tmp; + ssl->buffers.outputBuffer.bufferSize = size + + ssl->buffers.outputBuffer.length; + return 0; +} + + +/* Grow the input buffer, should only be to read cert or big app data */ +static INLINE int GrowInputBuffer(SSL* ssl, int size, int usedLength) +{ + byte* tmp = (byte*) XMALLOC(size + usedLength, ssl->heap, + DYNAMIC_TYPE_IN_BUFFER); + CYASSL_MSG("growing input buffer\n"); + + if (!tmp) return -1; + + if (usedLength) + XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, usedLength); + + if (ssl->buffers.inputBuffer.dynamicFlag) + XFREE(ssl->buffers.inputBuffer.buffer,ssl->heap,DYNAMIC_TYPE_IN_BUFFER); + + ssl->buffers.inputBuffer.dynamicFlag = 1; + ssl->buffers.inputBuffer.buffer = tmp; + ssl->buffers.inputBuffer.bufferSize = size + usedLength; + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; + + return 0; +} + + +/* check avalaible size into outbut buffer */ +static INLINE int CheckAvalaibleSize(SSL *ssl, int size) +{ + if ((word32)size > ssl->buffers.outputBuffer.bufferSize) + if (GrowOutputBuffer(ssl, size) < 0) + return MEMORY_E; + + if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length + < (word32)size) { + if (SendBuffered(ssl) == SOCKET_ERROR_E) + return SOCKET_ERROR_E; + if (ssl->buffers.outputBuffer.bufferSize - + ssl->buffers.outputBuffer.length < (word32)size) + return WANT_WRITE; + } + return 0; +} + +/* do all verify and sanity checks on record header */ +static int GetRecordHeader(SSL* ssl, const byte* input, word32* inOutIdx, + RecordLayerHeader* rh, word16 *size) +{ + if (!ssl->options.dtls) { + XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ); + *inOutIdx += RECORD_HEADER_SZ; + ato16(rh->length, size); + } + else { +#ifdef CYASSL_DTLS + /* type and version in same sport */ + XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ); + *inOutIdx += ENUM_LEN + VERSION_SZ; + *inOutIdx += 4; /* skip epoch and first 2 seq bytes for now */ + ato32(input + *inOutIdx, &ssl->keys.dtls_peer_sequence_number); + *inOutIdx += 4; /* advance past rest of seq */ + ato16(input + *inOutIdx, size); + *inOutIdx += LENGTH_SZ; +#endif + } + + /* catch version mismatch */ + if (rh->version.major != ssl->version.major || + rh->version.minor != ssl->version.minor) { + + if (ssl->options.side == SERVER_END && ssl->options.downgrade == 1 && + ssl->options.acceptState == ACCEPT_BEGIN) + ; /* haven't negotiated yet */ + else + return VERSION_ERROR; /* only use requested version */ + } + + /* record layer length check */ + if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) + return LENGTH_ERROR; + + /* verify record type here as well */ + switch ((enum ContentType)rh->type) { + case handshake: + case change_cipher_spec: + case application_data: + case alert: + break; + default: + return UNKNOWN_RECORD_TYPE; + } + + return 0; +} + + +static int GetHandShakeHeader(SSL* ssl, const byte* input, word32* inOutIdx, + byte *type, word32 *size) +{ + const byte *ptr = input + *inOutIdx; + *inOutIdx += HANDSHAKE_HEADER_SZ; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) + *inOutIdx += DTLS_HANDSHAKE_EXTRA; +#endif + + *type = ptr[0]; + c24to32(&ptr[1], size); + + return 0; +} + + +/* fill with MD5 pad size since biggest required */ +static const byte PAD1[PAD_MD5] = + { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 + }; +static const byte PAD2[PAD_MD5] = + { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c + }; + +/* calculate MD5 hash for finished */ +static void BuildMD5(SSL* ssl, Hashes* hashes, const byte* sender) +{ + byte md5_result[MD5_DIGEST_SIZE]; + + /* make md5 inner */ + Md5Update(&ssl->hashMd5, sender, SIZEOF_SENDER); + Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD1, PAD_MD5); + Md5Final(&ssl->hashMd5, md5_result); + + /* make md5 outer */ + Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD2, PAD_MD5); + Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE); + + Md5Final(&ssl->hashMd5, hashes->md5); +} + + +/* calculate SHA hash for finished */ +static void BuildSHA(SSL* ssl, Hashes* hashes, const byte* sender) +{ + byte sha_result[SHA_DIGEST_SIZE]; + + /* make sha inner */ + ShaUpdate(&ssl->hashSha, sender, SIZEOF_SENDER); + ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA); + ShaFinal(&ssl->hashSha, sha_result); + + /* make sha outer */ + ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA); + ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE); + + ShaFinal(&ssl->hashSha, hashes->sha); +} + + +static void BuildFinished(SSL* ssl, Hashes* hashes, const byte* sender) +{ + /* store current states, building requires get_digest which resets state */ + Md5 md5 = ssl->hashMd5; + Sha sha = ssl->hashSha; +#ifndef NO_SHA256 + Sha256 sha256; + if (IsAtLeastTLSv1_2(ssl)) + sha256 = ssl->hashSha256; +#endif + + if (ssl->options.tls) + BuildTlsFinished(ssl, hashes, sender); + else { + BuildMD5(ssl, hashes, sender); + BuildSHA(ssl, hashes, sender); + } + + /* restore */ + ssl->hashMd5 = md5; + ssl->hashSha = sha; +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + ssl->hashSha256 = sha256; +#endif +} + + +static int DoCertificate(SSL* ssl, byte* input, word32* inOutIdx) +{ + word32 listSz, i = *inOutIdx; + int ret = 0; + int anyError = 0; + int firstTime = 1; /* peer's is at front */ + char domain[ASN_NAME_MAX]; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo); + #endif + c24to32(&input[i], &listSz); + i += CERT_HEADER_SZ; + + while (listSz) { + /* cert size */ + buffer myCert; + word32 certSz; + DecodedCert dCert; + word32 idx = 0; + + c24to32(&input[i], &certSz); + i += CERT_HEADER_SZ; + + myCert.length = certSz; + myCert.buffer = input + i; + i += certSz; + + listSz -= certSz + CERT_HEADER_SZ; + + if (ret != 0 && anyError == 0) + anyError = ret; /* save error from last time */ + +#ifdef SESSION_CERTS + if (ssl->session.chain.count < MAX_CHAIN_DEPTH && + myCert.length < MAX_X509_SIZE) { + ssl->session.chain.certs[ssl->session.chain.count].length = + myCert.length; + XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer, + myCert.buffer, myCert.length); + ssl->session.chain.count++; + } else { + CYASSL_MSG("Couldn't store chain cert for session"); + } +#endif + + InitDecodedCert(&dCert, myCert.buffer, ssl->heap); + ret = ParseCertRelative(&dCert, myCert.length, CERT_TYPE, + !ssl->options.verifyNone, ssl->caList); + + if (!firstTime) { + FreeDecodedCert(&dCert); + continue; + } + + /* get rest of peer info in case user wants to continue */ + if (ret != 0) { + if (!(ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E || + ret == ASN_SIG_CONFIRM_E)) { + FreeDecodedCert(&dCert); + continue; + } + } + + /* first one has peer's key */ + firstTime = 0; + + ssl->options.havePeerCert = 1; + /* set X509 format */ +#ifdef OPENSSL_EXTRA + ssl->peerCert.issuer.sz = (int)XSTRLEN(dCert.issuer) + 1; + XSTRNCPY(ssl->peerCert.issuer.name, dCert.issuer, ASN_NAME_MAX); + ssl->peerCert.subject.sz = (int)XSTRLEN(dCert.subject) + 1; + XSTRNCPY(ssl->peerCert.subject.name, dCert.subject, ASN_NAME_MAX); +#endif + + XMEMCPY(domain, dCert.subjectCN, dCert.subjectCNLen); + domain[dCert.subjectCNLen] = '\0'; + + if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer) + if (XSTRNCMP((char*)ssl->buffers.domainName.buffer, + dCert.subjectCN, + ssl->buffers.domainName.length - 1)) { + ret = DOMAIN_NAME_MISMATCH; /* try to get peer key still */ + } + + /* decode peer key */ + if (dCert.keyOID == RSAk) { + if (RsaPublicKeyDecode(dCert.publicKey, &idx, + &ssl->peerRsaKey, dCert.pubKeySize) != 0) { + ret = PEER_KEY_ERROR; + FreeDecodedCert(&dCert); + continue; + } + ssl->peerRsaKeyPresent = 1; + } +#ifdef HAVE_NTRU + else if (dCert.keyOID == NTRUk) { + if (dCert.pubKeySize > sizeof(ssl->peerNtruKey)) { + ret = PEER_KEY_ERROR; + FreeDecodedCert(&dCert); + continue; + } + XMEMCPY(ssl->peerNtruKey, dCert.publicKey, dCert.pubKeySize); + ssl->peerNtruKeyLen = (word16)dCert.pubKeySize; + ssl->peerNtruKeyPresent = 1; + } +#endif /* HAVE_NTRU */ +#ifdef HAVE_ECC + else if (dCert.keyOID == ECDSAk) { + if (ecc_import_x963(dCert.publicKey, dCert.pubKeySize, + &ssl->peerEccDsaKey) != 0) { + ret = PEER_KEY_ERROR; + FreeDecodedCert(&dCert); + continue; + } + ssl->peerEccDsaKeyPresent = 1; + } +#endif /* HAVE_ECC */ + + FreeDecodedCert(&dCert); + } + + if (anyError != 0) + ret = anyError; + + if (ret == 0 && ssl->options.side == CLIENT_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + + if (ret != 0) { + if (!ssl->options.verifyNone) { + int why = bad_certificate; + if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E) + why = certificate_expired; + if (ssl->ctx->verifyCallback) { + int ok; + X509_STORE_CTX store; + + store.error = ret; + store.error_depth = 1; + store.domain = domain; +#ifdef OPENSSL_EXTRA + store.current_cert = &ssl->peerCert; +#else + store.current_cert = NULL; +#endif + ok = ssl->ctx->verifyCallback(0, &store); + if (ok) + ret = 0; + } + if (ret != 0) { + SendAlert(ssl, alert_fatal, why); /* try to send */ + ssl->options.isClosed = 1; + } + } + ssl->error = ret; + } + + *inOutIdx = i; + return ret; +} + + +int DoFinished(SSL* ssl, const byte* input, word32* inOutIdx, int sniff) +{ + byte verifyMAC[SHA_DIGEST_SIZE]; + int finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ; + int headerSz = HANDSHAKE_HEADER_SZ; + word32 macSz = finishedSz + HANDSHAKE_HEADER_SZ, + idx = *inOutIdx, + padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - finishedSz - + ssl->specs.hash_size; + const byte* mac; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + headerSz += DTLS_HANDSHAKE_EXTRA; + macSz += DTLS_HANDSHAKE_EXTRA; + padSz -= DTLS_HANDSHAKE_EXTRA; + } + #endif + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo); + #endif + if (sniff == NO_SNIFF) { + if (XMEMCMP(input + idx, &ssl->verifyHashes, finishedSz)) + return VERIFY_FINISHED_ERROR; + } + + ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz, + handshake, 1); + idx += finishedSz; + + /* read mac and fill */ + mac = input + idx; + idx += ssl->specs.hash_size; + + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + padSz -= ssl->specs.block_size; + + idx += padSz; + + /* verify mac */ + if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size)) + return VERIFY_MAC_ERROR; + + if (ssl->options.side == CLIENT_END) { + ssl->options.serverState = SERVER_FINISHED_COMPLETE; + if (!ssl->options.resuming) + ssl->options.handShakeState = HANDSHAKE_DONE; + } + else { + ssl->options.clientState = CLIENT_FINISHED_COMPLETE; + if (ssl->options.resuming) + ssl->options.handShakeState = HANDSHAKE_DONE; + } + + *inOutIdx = idx; + return 0; +} + + +static int DoHandShakeMsg(SSL* ssl, byte* input, word32* inOutIdx, + word32 totalSz) +{ + byte type; + word32 size; + int ret = 0; + + CYASSL_ENTER("DoHandShakeMsg()"); + + if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0) + return PARSE_ERROR; + + if (*inOutIdx + size > totalSz) + return INCOMPLETE_DATA; + + HashInput(ssl, input + *inOutIdx, size); +#ifdef CYASSL_CALLBACKS + /* add name later, add on record and handshake header part back on */ + if (ssl->toInfoOn) { + int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add, + size + add, ssl->heap); + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + } +#endif + + switch (type) { + +#ifndef NO_CYASSL_CLIENT + case hello_verify_request: + CYASSL_MSG("processing hello verify request"); + ret = DoHelloVerifyRequest(ssl, input,inOutIdx); + break; + + case server_hello: + CYASSL_MSG("processing server hello"); + ret = DoServerHello(ssl, input, inOutIdx); + break; + + case certificate_request: + CYASSL_MSG("processing certificate request"); + ret = DoCertificateRequest(ssl, input, inOutIdx); + break; + + case server_key_exchange: + CYASSL_MSG("processing server key exchange"); + ret = DoServerKeyExchange(ssl, input, inOutIdx); + break; +#endif + + case certificate: + CYASSL_MSG("processing certificate"); + ret = DoCertificate(ssl, input, inOutIdx); + break; + + case server_hello_done: + CYASSL_MSG("processing server hello done"); + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHelloDone", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ServerHelloDone", &ssl->timeoutInfo); + #endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + break; + + case finished: + CYASSL_MSG("processing finished"); + ret = DoFinished(ssl, input, inOutIdx, NO_SNIFF); + break; + +#ifndef NO_CYASSL_SERVER + case client_hello: + CYASSL_MSG("processing client hello"); + ret = DoClientHello(ssl, input, inOutIdx, totalSz, size); + break; + + case client_key_exchange: + CYASSL_MSG("processing client key exchange"); + ret = DoClientKeyExchange(ssl, input, inOutIdx); + break; + + case certificate_verify: + CYASSL_MSG("processing certificate verify"); + ret = DoCertificateVerify(ssl, input, inOutIdx, totalSz); + break; + +#endif + + default: + ret = UNKNOWN_HANDSHAKE_TYPE; + } + + CYASSL_LEAVE("DoHandShakeMsg()", ret); + return ret; +} + + +static INLINE void Encrypt(SSL* ssl, byte* out, const byte* input, word32 sz) +{ + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case rc4: + Arc4Process(&ssl->encrypt.arc4, out, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case triple_des: + Des3_CbcEncrypt(&ssl->encrypt.des3, out, input, sz); + break; + #endif + + #ifdef BUILD_AES + case aes: +#ifdef CYASSL_AESNI + if ((word)input % 16) { + byte buffer[MAX_RECORD_SIZE + MAX_COMP_EXTRA+MAX_MSG_EXTRA]; + XMEMCPY(buffer, input, sz); + AesCbcEncrypt(&ssl->encrypt.aes, buffer, buffer, sz); + XMEMCPY(out, buffer, sz); + break; + } +#endif + AesCbcEncrypt(&ssl->encrypt.aes, out, input, sz); + break; + #endif + + #ifdef BUILD_HC128 + case hc128: + Hc128_Process(&ssl->encrypt.hc128, out, input, sz); + break; + #endif + + #ifdef BUILD_RABBIT + case rabbit: + RabbitProcess(&ssl->encrypt.rabbit, out, input, sz); + break; + #endif + } +} + + +static INLINE void Decrypt(SSL* ssl, byte* plain, const byte* input, word32 sz) +{ + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case rc4: + Arc4Process(&ssl->decrypt.arc4, plain, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case triple_des: + Des3_CbcDecrypt(&ssl->decrypt.des3, plain, input, sz); + break; + #endif + + #ifdef BUILD_AES + case aes: + AesCbcDecrypt(&ssl->decrypt.aes, plain, input, sz); + break; + #endif + + #ifdef BUILD_HC128 + case hc128: + Hc128_Process(&ssl->decrypt.hc128, plain, input, sz); + break; + #endif + + #ifdef BUILD_RABBIT + case rabbit: + RabbitProcess(&ssl->decrypt.rabbit, plain, input, sz); + break; + #endif + } +} + + +/* decrypt input message in place */ +static int DecryptMessage(SSL* ssl, byte* input, word32 sz, word32* idx) +{ + Decrypt(ssl, input, input, sz); + ssl->keys.encryptSz = sz; + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + *idx += ssl->specs.block_size; /* go past TLSv1.1 IV */ + + return 0; +} + + +static INLINE word32 GetSEQIncrement(SSL* ssl, int verify) +{ + if (verify) + return ssl->keys.peer_sequence_number++; + else + return ssl->keys.sequence_number++; +} + + +int DoApplicationData(SSL* ssl, byte* input, word32* inOutIdx) +{ + word32 msgSz = ssl->keys.encryptSz; + word32 pad = 0, + padByte = 0, + idx = *inOutIdx, + digestSz = ssl->specs.hash_size; + int dataSz; + int ivExtra = 0; + byte* rawData = input + idx; /* keep current for hmac */ +#ifdef HAVE_LIBZ + byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; +#endif + + byte verify[SHA_DIGEST_SIZE]; + const byte* mac; + + if (ssl->specs.cipher_type == block) { + if (ssl->options.tls1_1) + ivExtra = ssl->specs.block_size; + pad = *(input + idx + msgSz - ivExtra - 1); + padByte = 1; + } + + dataSz = msgSz - ivExtra - digestSz - pad - padByte; + if (dataSz < 0) + return BUFFER_ERROR; + + /* read data */ + if (dataSz) { + int rawSz = dataSz; /* keep raw size for hmac */ + + ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1); + +#ifdef HAVE_LIBZ + byte decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; + + if (ssl->options.usingCompression) { + dataSz = DeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp)); + if (dataSz < 0) return dataSz; + } +#endif + + if (ssl->options.usingCompression) + idx += rawSz; + else + idx += dataSz; + + ssl->buffers.clearOutputBuffer.buffer = rawData; + ssl->buffers.clearOutputBuffer.length = dataSz; + } + + /* read mac and fill */ + mac = input + idx; + idx += digestSz; + + idx += pad; + if (padByte) + idx++; + +#ifdef HAVE_LIBZ + if (ssl->options.usingCompression) + XMEMMOVE(rawData, decomp, dataSz); +#endif + + /* verify */ + if (dataSz) { + if (XMEMCMP(mac, verify, digestSz)) + return VERIFY_MAC_ERROR; + } + else + GetSEQIncrement(ssl, 1); /* even though no data, increment verify */ + + *inOutIdx = idx; + return 0; +} + + +/* process alert, return level */ +static int DoAlert(SSL* ssl, byte* input, word32* inOutIdx, int* type) +{ + byte level; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("Alert", &ssl->handShakeInfo); + if (ssl->toInfoOn) + /* add record header back on to info + 2 byte level, data */ + AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx - + RECORD_HEADER_SZ, 2 + RECORD_HEADER_SZ, ssl->heap); + #endif + level = input[(*inOutIdx)++]; + *type = (int)input[(*inOutIdx)++]; + + if (*type == close_notify) + ssl->options.closeNotify = 1; + + if (ssl->keys.encryptionOn) { + int aSz = ALERT_SIZE; + const byte* mac; + byte verify[SHA_DIGEST_SIZE]; + int padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size; + + ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1); + + /* read mac and fill */ + mac = input + *inOutIdx; + *inOutIdx += (ssl->specs.hash_size + padSz); + + /* verify */ + if (XMEMCMP(mac, verify, ssl->specs.hash_size)) + return VERIFY_MAC_ERROR; + } + + return level; +} + +static int GetInputData(SSL *ssl, size_t size) +{ + int in; + int inSz; + int maxLength; + int usedLength; + + + /* check max input length */ + usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx; + maxLength = ssl->buffers.inputBuffer.bufferSize - usedLength; + inSz = (int)(size - usedLength); /* from last partial read */ + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) + inSz = 1500; /* read ahead up to MTU */ +#endif + + if (inSz > maxLength) { + if (GrowInputBuffer(ssl, size, usedLength) < 0) + return MEMORY_E; + } + + if (inSz <= 0) + return BUFFER_ERROR; + + /* Put buffer data at start if not there */ + if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0) + XMEMMOVE(ssl->buffers.inputBuffer.buffer, + ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + usedLength); + + /* remove processed data */ + ssl->buffers.inputBuffer.idx = 0; + ssl->buffers.inputBuffer.length = usedLength; + + /* read data from network */ + do { + in = Receive(ssl, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.length, + inSz, 0); + if (in == -1) + return SOCKET_ERROR_E; + + if (in == WANT_READ) + return WANT_READ; + + ssl->buffers.inputBuffer.length += in; + inSz -= in; + + } while (ssl->buffers.inputBuffer.length < size); + + return 0; +} + +/* process input requests, return 0 is done, 1 is call again to complete, and + negative number is error */ +int ProcessReply(SSL* ssl) +{ + int ret, type, readSz; + word32 startIdx = 0; + byte b0, b1; +#ifdef CYASSL_DTLS + int used; +#endif + + for (;;) { + switch ((processReply)ssl->options.processReply) { + + /* in the CYASSL_SERVER case, get the first byte for detecting + * old client hello */ + case doProcessInit: + + readSz = RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + readSz = DTLS_RECORD_HEADER_SZ; + #endif + + /* get header or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, readSz)) < 0) + return ret; + } else { + #ifdef CYASSL_DTLS + /* read ahead may already have header */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < readSz) + if ((ret = GetInputData(ssl, readSz)) < 0) + return ret; + #endif + } + +#ifndef NO_CYASSL_SERVER + + /* see if sending SSLv2 client hello */ + if ( ssl->options.side == SERVER_END && + ssl->options.clientState == NULL_STATE && + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx] + != handshake) { + ssl->options.processReply = runProcessOldClientHello; + + /* how many bytes need ProcessOldClientHello */ + b0 = + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; + b1 = + ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++]; + ssl->curSize = ((b0 & 0x7f) << 8) | b1; + } + else { + ssl->options.processReply = getRecordLayerHeader; + continue; + } + + /* in the CYASSL_SERVER case, run the old client hello */ + case runProcessOldClientHello: + + /* get sz bytes or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + } else { + #ifdef CYASSL_DTLS + /* read ahead may already have */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < ssl->curSize) + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + #endif /* CYASSL_DTLS */ + } + + ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx, + ssl->curSize); + if (ret < 0) + return ret; + + else if (ssl->buffers.inputBuffer.idx == + ssl->buffers.inputBuffer.length) { + ssl->options.processReply = doProcessInit; + return 0; + } + +#endif /* NO_CYASSL_SERVER */ + + /* get the record layer header */ + case getRecordLayerHeader: + + ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + &ssl->curRL, &ssl->curSize); + if (ret != 0) + return ret; + + ssl->options.processReply = getData; + + /* retrieve record layer data */ + case getData: + + /* get sz bytes or return error */ + if (!ssl->options.dtls) { + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; + } else { +#ifdef CYASSL_DTLS + /* read ahead may already have */ + used = ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx; + if (used < ssl->curSize) + if ((ret = GetInputData(ssl, ssl->curSize)) < 0) + return ret; +#endif + } + + ssl->options.processReply = runProcessingOneMessage; + startIdx = ssl->buffers.inputBuffer.idx; /* in case > 1 msg per */ + + /* the record layer is here */ + case runProcessingOneMessage: + + if (ssl->keys.encryptionOn) + if (DecryptMessage(ssl, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->curSize, + &ssl->buffers.inputBuffer.idx) < 0) + return DECRYPT_ERROR; + + CYASSL_MSG("received record layer msg"); + + switch (ssl->curRL.type) { + case handshake : + /* debugging in DoHandShakeMsg */ + if ((ret = DoHandShakeMsg(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, + ssl->buffers.inputBuffer.length)) + != 0) + return ret; + break; + + case change_cipher_spec: + CYASSL_MSG("got CHANGE CIPHER SPEC"); + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ChangeCipher", &ssl->handShakeInfo); + /* add record header back on info */ + if (ssl->toInfoOn) { + AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, + ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ, + 1 + RECORD_HEADER_SZ, ssl->heap); + AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo); + } + #endif + ssl->buffers.inputBuffer.idx++; + ssl->keys.encryptionOn = 1; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + ssl->keys.dtls_peer_epoch++; + #endif + + #ifdef HAVE_LIBZ + if (ssl->options.usingCompression) + if ( (ret = InitStreams(ssl)) != 0) + return ret; + #endif + if (ssl->options.resuming && ssl->options.side == + CLIENT_END) + BuildFinished(ssl, &ssl->verifyHashes, server); + else if (!ssl->options.resuming && ssl->options.side == + SERVER_END) + BuildFinished(ssl, &ssl->verifyHashes, client); + break; + + case application_data: + CYASSL_MSG("got app DATA"); + if ((ret = DoApplicationData(ssl, + ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx)) + != 0) { + CYASSL_ERROR(ret); + return ret; + } + break; + + case alert: + CYASSL_MSG("got ALERT!"); + if (DoAlert(ssl, ssl->buffers.inputBuffer.buffer, + &ssl->buffers.inputBuffer.idx, &type) == alert_fatal) + return FATAL_ERROR; + + /* catch warnings that are handled as errors */ + if (type == close_notify) + return ssl->error = ZERO_RETURN; + + if (type == decrypt_error) + return FATAL_ERROR; + break; + + default: + CYASSL_ERROR(UNKNOWN_RECORD_TYPE); + return UNKNOWN_RECORD_TYPE; + } + + ssl->options.processReply = doProcessInit; + + /* input exhausted? */ + if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length) + return 0; + /* more messages per record */ + else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) { + #ifdef CYASSL_DTLS + /* read-ahead but dtls doesn't bundle messages per record */ + if (ssl->options.dtls) { + ssl->options.processReply = doProcessInit; + continue; + } + #endif + ssl->options.processReply = runProcessingOneMessage; + continue; + } + /* more records */ + else { + ssl->options.processReply = doProcessInit; + continue; + } + } + } +} + + +int SendChangeCipher(SSL* ssl) +{ + byte *output; + int sendSz = RECORD_HEADER_SZ + ENUM_LEN; + int idx = RECORD_HEADER_SZ; + int ret; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA; + idx += DTLS_RECORD_EXTRA; + } + #endif + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddRecordHeader(output, 1, change_cipher_spec, ssl); + + output[idx] = 1; /* turn it on */ + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + return SendBuffered(ssl); +} + + +static INLINE const byte* GetMacSecret(SSL* ssl, int verify) +{ + if ( (ssl->options.side == CLIENT_END && !verify) || + (ssl->options.side == SERVER_END && verify) ) + return ssl->keys.client_write_MAC_secret; + else + return ssl->keys.server_write_MAC_secret; +} + + +static void Hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz, + int content, int verify) +{ + byte result[SHA_DIGEST_SIZE]; /* max possible sizes */ + word32 digestSz = ssl->specs.hash_size; /* actual sizes */ + word32 padSz = ssl->specs.pad_size; + + Md5 md5; + Sha sha; + + /* data */ + byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 }; + byte conLen[ENUM_LEN + LENGTH_SZ]; /* content & length */ + const byte* macSecret = GetMacSecret(ssl, verify); + + conLen[0] = content; + c16toa((word16)sz, &conLen[ENUM_LEN]); + c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]); + + if (ssl->specs.mac_algorithm == md5_mac) { + InitMd5(&md5); + /* inner */ + Md5Update(&md5, macSecret, digestSz); + Md5Update(&md5, PAD1, padSz); + Md5Update(&md5, seq, SEQ_SZ); + Md5Update(&md5, conLen, sizeof(conLen)); + /* buffer */ + Md5Update(&md5, buffer, sz); + Md5Final(&md5, result); + /* outer */ + Md5Update(&md5, macSecret, digestSz); + Md5Update(&md5, PAD2, padSz); + Md5Update(&md5, result, digestSz); + Md5Final(&md5, digest); + } + else { + InitSha(&sha); + /* inner */ + ShaUpdate(&sha, macSecret, digestSz); + ShaUpdate(&sha, PAD1, padSz); + ShaUpdate(&sha, seq, SEQ_SZ); + ShaUpdate(&sha, conLen, sizeof(conLen)); + /* buffer */ + ShaUpdate(&sha, buffer, sz); + ShaFinal(&sha, result); + /* outer */ + ShaUpdate(&sha, macSecret, digestSz); + ShaUpdate(&sha, PAD2, padSz); + ShaUpdate(&sha, result, digestSz); + ShaFinal(&sha, digest); + } +} + + +static void BuildMD5_CertVerify(SSL* ssl, byte* digest) +{ + byte md5_result[MD5_DIGEST_SIZE]; + + /* make md5 inner */ + Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD1, PAD_MD5); + Md5Final(&ssl->hashMd5, md5_result); + + /* make md5 outer */ + Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN); + Md5Update(&ssl->hashMd5, PAD2, PAD_MD5); + Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE); + + Md5Final(&ssl->hashMd5, digest); +} + + +static void BuildSHA_CertVerify(SSL* ssl, byte* digest) +{ + byte sha_result[SHA_DIGEST_SIZE]; + + /* make sha inner */ + ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA); + ShaFinal(&ssl->hashSha, sha_result); + + /* make sha outer */ + ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN); + ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA); + ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE); + + ShaFinal(&ssl->hashSha, digest); +} + + +static void BuildCertHashes(SSL* ssl, Hashes* hashes) +{ + /* store current states, building requires get_digest which resets state */ + Md5 md5 = ssl->hashMd5; + Sha sha = ssl->hashSha; +#ifndef NO_SHA256 /* for possible future changes */ + Sha256 sha256; + if (IsAtLeastTLSv1_2(ssl)) + sha256 = ssl->hashSha256; +#endif + + if (ssl->options.tls) { + Md5Final(&ssl->hashMd5, hashes->md5); + ShaFinal(&ssl->hashSha, hashes->sha); + } + else { + BuildMD5_CertVerify(ssl, hashes->md5); + BuildSHA_CertVerify(ssl, hashes->sha); + } + + /* restore */ + ssl->hashMd5 = md5; + ssl->hashSha = sha; +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + ssl->hashSha256 = sha256; +#endif +} + + +/* Build SSL Message, encrypted */ +static int BuildMessage(SSL* ssl, byte* output, const byte* input, int inSz, + int type) +{ + word32 digestSz = ssl->specs.hash_size; + word32 sz = RECORD_HEADER_SZ + inSz + digestSz; + word32 pad = 0, i; + word32 idx = RECORD_HEADER_SZ; + word32 ivSz = 0; /* TLSv1.1 IV */ + word32 headerSz = RECORD_HEADER_SZ; + word16 size; + byte iv[AES_BLOCK_SIZE]; /* max size */ + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sz += DTLS_RECORD_EXTRA; + idx += DTLS_RECORD_EXTRA; + headerSz += DTLS_RECORD_EXTRA; + } +#endif + + if (ssl->specs.cipher_type == block) { + word32 blockSz = ssl->specs.block_size; + if (ssl->options.tls1_1) { + ivSz = blockSz; + sz += ivSz; + RNG_GenerateBlock(&ssl->rng, iv, ivSz); + } + sz += 1; /* pad byte */ + pad = (sz - headerSz) % blockSz; + pad = blockSz - pad; + sz += pad; + } + + size = sz - headerSz; /* include mac and digest */ + AddRecordHeader(output, size, type, ssl); + + /* write to output */ + if (ivSz) { + XMEMCPY(output + idx, iv, ivSz); + idx += ivSz; + } + XMEMCPY(output + idx, input, inSz); + idx += inSz; + + if (type == handshake) + HashOutput(ssl, output, headerSz + inSz, ivSz); + ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0); + idx += digestSz; + + if (ssl->specs.cipher_type == block) + for (i = 0; i <= pad; i++) output[idx++] = pad; /* pad byte gets */ + /* pad value too */ + Encrypt(ssl, output + headerSz, output + headerSz, size); + + return sz; +} + + +int SendFinished(SSL* ssl) +{ + int sendSz, + finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : + FINISHED_SZ; + byte input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ]; /* max */ + byte *output; + Hashes* hashes; + int ret; + int headerSz = HANDSHAKE_HEADER_SZ; + + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + headerSz += DTLS_HANDSHAKE_EXTRA; + ssl->keys.dtls_epoch++; + ssl->keys.dtls_sequence_number = 0; /* reset after epoch change */ + } + #endif + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHandShakeHeader(input, finishedSz, finished, ssl); + + /* make finished hashes */ + hashes = (Hashes*)&input[headerSz]; + BuildFinished(ssl, hashes, ssl->options.side == CLIENT_END ? client : + server); + + if ( (sendSz = BuildMessage(ssl, output, input, headerSz + + finishedSz, handshake)) == -1) + return BUILD_MSG_ERROR; + + if (!ssl->options.resuming) { + AddSession(ssl); /* just try */ + if (ssl->options.side == CLIENT_END) + BuildFinished(ssl, &ssl->verifyHashes, server); + else + ssl->options.handShakeState = HANDSHAKE_DONE; + } + else { + if (ssl->options.side == CLIENT_END) + ssl->options.handShakeState = HANDSHAKE_DONE; + else + BuildFinished(ssl, &ssl->verifyHashes, client); + } + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); +} + + +int SendCertificate(SSL* ssl) +{ + int sendSz, length, ret = 0; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + word32 certSz, listSz; + byte* output = 0; + + if (ssl->options.usingPSK_cipher) return 0; /* not needed */ + + if (ssl->options.sendVerify == SEND_BLANK_CERT) { + certSz = 0; + length = CERT_HEADER_SZ; + listSz = 0; + } + else { + certSz = ssl->buffers.certificate.length; + /* list + cert size */ + length = certSz + 2 * CERT_HEADER_SZ; + listSz = certSz + CERT_HEADER_SZ; + } + sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, length, certificate, ssl); + + /* list total */ + c32to24(listSz, output + i); + i += CERT_HEADER_SZ; + + /* member */ + if (certSz) { + c32to24(certSz, output + i); + i += CERT_HEADER_SZ; + XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz); + i += certSz; + } + HashOutput(ssl, output, sendSz, 0); + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + if (ssl->options.side == SERVER_END) + ssl->options.serverState = SERVER_CERT_COMPLETE; + + ssl->buffers.outputBuffer.length += sendSz; + return SendBuffered(ssl); +} + + +int SendCertificateRequest(SSL* ssl) +{ + byte *output; + int ret; + int sendSz; + word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + int typeTotal = 1; /* only rsa for now */ + int reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ; /* add auth later */ + + if (IsAtLeastTLSv1_2(ssl)) + reqSz += LENGTH_SZ + HASH_SIG_SIZE; + + if (ssl->options.usingPSK_cipher) return 0; /* not needed */ + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + i += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, reqSz, certificate_request, ssl); + + /* write to output */ + output[i++] = typeTotal; /* # of types */ + output[i++] = rsa_sign; + + /* supported hash/sig */ + if (IsAtLeastTLSv1_2(ssl)) { + c16toa(HASH_SIG_SIZE, &output[i]); + i += LENGTH_SZ; + + output[i++] = sha_mac; /* hash */ + output[i++] = rsa_sa_algo; /* sig */ + } + + c16toa(0, &output[i]); /* auth's */ + i += REQ_HEADER_SZ; + + HashOutput(ssl, output, sendSz, 0); + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output, + sendSz, ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + return SendBuffered(ssl); +} + + +int SendData(SSL* ssl, const void* buffer, int sz) +{ + int sent = 0, /* plainText size */ + sendSz, + ret; + + if (ssl->error == WANT_WRITE) + ssl->error = 0; + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + int err; + if ( (err = CyaSSL_negotiate(ssl)) != 0) + return err; + } + + /* last time system socket output buffer was full, try again to send */ + if (ssl->buffers.outputBuffer.length > 0) { + if ( (ssl->error = SendBuffered(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + if (ssl->error == SOCKET_ERROR_E && ssl->options.connReset) + return 0; /* peer reset */ + return ssl->error; + } + else { + /* advance sent to previous sent + plain size just sent */ + sent = ssl->buffers.prevSent + ssl->buffers.plainSz; + CYASSL_MSG("sent write buffered data"); + } + } + + for (;;) { + int len = min(sz - sent, OUTPUT_RECORD_SIZE); + byte* out; + byte* sendBuffer = (byte*)buffer + sent; /* may switch on comp */ + int buffSz = len; /* may switch on comp */ +#ifdef HAVE_LIBZ + byte comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA]; +#endif + + if (sent == sz) break; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + len = min(len, MAX_UDP_SIZE); + buffSz = len; + } +#endif + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, len + COMP_EXTRA + + MAX_MSG_EXTRA)) != 0) + return ret; + + /* get ouput buffer */ + out = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + +#ifdef HAVE_LIBZ + if (ssl->options.usingCompression) { + buffSz = Compress(ssl, sendBuffer, buffSz, comp, sizeof(comp)); + if (buffSz < 0) { + return buffSz; + } + sendBuffer = comp; + } +#endif + sendSz = BuildMessage(ssl, out, sendBuffer, buffSz, + application_data); + + ssl->buffers.outputBuffer.length += sendSz; + + if ( (ret = SendBuffered(ssl)) < 0) { + CYASSL_ERROR(ret); + /* store for next call if WANT_WRITE or user embedSend() that + doesn't present like WANT_WRITE */ + ssl->buffers.plainSz = len; + ssl->buffers.prevSent = sent; + if (ret == SOCKET_ERROR_E && ssl->options.connReset) + return 0; /* peer reset */ + return ssl->error = ret; + } + + sent += len; + + /* only one message per attempt */ + if (ssl->options.partialWrite == 1) + break; + } + + return sent; +} + +/* process input data */ +int ReceiveData(SSL* ssl, byte* output, int sz) +{ + int size; + + CYASSL_ENTER("ReceiveData()"); + + if (ssl->error == WANT_READ) + ssl->error = 0; + + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + int err; + if ( (err = CyaSSL_negotiate(ssl)) != 0) + return err; + } + + while (ssl->buffers.clearOutputBuffer.length == 0) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + if (ssl->error == ZERO_RETURN) { + ssl->options.isClosed = 1; + return 0; /* no more data coming */ + } + if (ssl->error == SOCKET_ERROR_E) + if (ssl->options.connReset || ssl->options.isClosed) + return 0; /* peer reset or closed */ + return ssl->error; + } + + if (sz < (int)ssl->buffers.clearOutputBuffer.length) + size = sz; + else + size = ssl->buffers.clearOutputBuffer.length; + + XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size); + ssl->buffers.clearOutputBuffer.length -= size; + ssl->buffers.clearOutputBuffer.buffer += size; + + if (ssl->buffers.clearOutputBuffer.length == 0 && + ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + + CYASSL_LEAVE("ReceiveData()", size); + return size; +} + + +/* send alert message */ +int SendAlert(SSL* ssl, int severity, int type) +{ + byte input[ALERT_SIZE]; + byte *output; + int sendSz; + int ret; + + /* if sendalert is called again for nonbloking */ + if (ssl->options.sendAlertState != 0) { + ret = SendBuffered(ssl); + if (ret == 0) + ssl->options.sendAlertState = 0; + return ret; + } + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, ALERT_SIZE + MAX_MSG_EXTRA)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + input[0] = severity; + input[1] = type; + + if (ssl->keys.encryptionOn) + sendSz = BuildMessage(ssl, output, input, sizeof(input), alert); + else { + RecordLayerHeader *const rl = (RecordLayerHeader*)output; + rl->type = alert; + rl->version = ssl->version; + c16toa(ALERT_SIZE, rl->length); + + XMEMCPY(output + RECORD_HEADER_SZ, input, sizeof(input)); + sendSz = RECORD_HEADER_SZ + sizeof(input); + } + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("Alert", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + ssl->options.sendAlertState = 1; + + return SendBuffered(ssl); +} + + + +void SetErrorString(int error, char* buffer) +{ + const int max = MAX_ERROR_SZ; /* shorthand */ + +#ifdef NO_ERROR_STRINGS + + XSTRNCPY(buffer, "no support for error strings built in", max); + +#else + + /* pass to CTaoCrypt */ + if (error < MAX_CODE_E && error > MIN_CODE_E) { + CTaoCryptErrorString(error, buffer); + return; + } + + switch (error) { + + case UNSUPPORTED_SUITE : + XSTRNCPY(buffer, "unsupported cipher suite", max); + break; + + case PREFIX_ERROR : + XSTRNCPY(buffer, "bad index to key rounds", max); + break; + + case MEMORY_ERROR : + XSTRNCPY(buffer, "out of memory", max); + break; + + case VERIFY_FINISHED_ERROR : + XSTRNCPY(buffer, "verify problem on finished", max); + break; + + case VERIFY_MAC_ERROR : + XSTRNCPY(buffer, "verify mac problem", max); + break; + + case PARSE_ERROR : + XSTRNCPY(buffer, "parse error on header", max); + break; + + case SIDE_ERROR : + XSTRNCPY(buffer, "wrong client/server type", max); + break; + + case NO_PEER_CERT : + XSTRNCPY(buffer, "peer didn't send cert", max); + break; + + case UNKNOWN_HANDSHAKE_TYPE : + XSTRNCPY(buffer, "weird handshake type", max); + break; + + case SOCKET_ERROR_E : + XSTRNCPY(buffer, "error state on socket", max); + break; + + case SOCKET_NODATA : + XSTRNCPY(buffer, "expected data, not there", max); + break; + + case INCOMPLETE_DATA : + XSTRNCPY(buffer, "don't have enough data to complete task", max); + break; + + case UNKNOWN_RECORD_TYPE : + XSTRNCPY(buffer, "unknown type in record hdr", max); + break; + + case DECRYPT_ERROR : + XSTRNCPY(buffer, "error during decryption", max); + break; + + case FATAL_ERROR : + XSTRNCPY(buffer, "revcd alert fatal error", max); + break; + + case ENCRYPT_ERROR : + XSTRNCPY(buffer, "error during encryption", max); + break; + + case FREAD_ERROR : + XSTRNCPY(buffer, "fread problem", max); + break; + + case NO_PEER_KEY : + XSTRNCPY(buffer, "need peer's key", max); + break; + + case NO_PRIVATE_KEY : + XSTRNCPY(buffer, "need the private key", max); + break; + + case RSA_PRIVATE_ERROR : + XSTRNCPY(buffer, "error during rsa priv op", max); + break; + + case MATCH_SUITE_ERROR : + XSTRNCPY(buffer, "can't match cipher suite", max); + break; + + case BUILD_MSG_ERROR : + XSTRNCPY(buffer, "build message failure", max); + break; + + case BAD_HELLO : + XSTRNCPY(buffer, "client hello malformed", max); + break; + + case DOMAIN_NAME_MISMATCH : + XSTRNCPY(buffer, "peer subject name mismatch", max); + break; + + case WANT_READ : + XSTRNCPY(buffer, "non-blocking socket wants data to be read", max); + break; + + case NOT_READY_ERROR : + XSTRNCPY(buffer, "handshake layer not ready yet, complete first", max); + break; + + case PMS_VERSION_ERROR : + XSTRNCPY(buffer, "premaster secret version mismatch error", max); + break; + + case VERSION_ERROR : + XSTRNCPY(buffer, "record layer version error", max); + break; + + case WANT_WRITE : + XSTRNCPY(buffer, "non-blocking socket write buffer full", max); + break; + + case BUFFER_ERROR : + XSTRNCPY(buffer, "malformed buffer input error", max); + break; + + case VERIFY_CERT_ERROR : + XSTRNCPY(buffer, "verify problem on certificate", max); + break; + + case VERIFY_SIGN_ERROR : + XSTRNCPY(buffer, "verify problem based on signature", max); + break; + + case CLIENT_ID_ERROR : + XSTRNCPY(buffer, "psk client identity error", max); + break; + + case SERVER_HINT_ERROR: + XSTRNCPY(buffer, "psk server hint error", max); + break; + + case PSK_KEY_ERROR: + XSTRNCPY(buffer, "psk key callback error", max); + break; + + case NTRU_KEY_ERROR: + XSTRNCPY(buffer, "NTRU key error", max); + break; + + case NTRU_DRBG_ERROR: + XSTRNCPY(buffer, "NTRU drbg error", max); + break; + + case NTRU_ENCRYPT_ERROR: + XSTRNCPY(buffer, "NTRU encrypt error", max); + break; + + case NTRU_DECRYPT_ERROR: + XSTRNCPY(buffer, "NTRU decrypt error", max); + break; + + case ZLIB_INIT_ERROR: + XSTRNCPY(buffer, "zlib init error", max); + break; + + case ZLIB_COMPRESS_ERROR: + XSTRNCPY(buffer, "zlib compress error", max); + break; + + case ZLIB_DECOMPRESS_ERROR: + XSTRNCPY(buffer, "zlib decompress error", max); + break; + + case GETTIME_ERROR: + XSTRNCPY(buffer, "gettimeofday() error", max); + break; + + case GETITIMER_ERROR: + XSTRNCPY(buffer, "getitimer() error", max); + break; + + case SIGACT_ERROR: + XSTRNCPY(buffer, "sigaction() error", max); + break; + + case SETITIMER_ERROR: + XSTRNCPY(buffer, "setitimer() error", max); + break; + + case LENGTH_ERROR: + XSTRNCPY(buffer, "record layer length error", max); + break; + + case PEER_KEY_ERROR: + XSTRNCPY(buffer, "cant decode peer key", max); + break; + + case ZERO_RETURN: + XSTRNCPY(buffer, "peer sent close notify alert", max); + break; + + case ECC_CURVETYPE_ERROR: + XSTRNCPY(buffer, "Bad ECC Curve Type or unsupported", max); + break; + + case ECC_CURVE_ERROR: + XSTRNCPY(buffer, "Bad ECC Curve or unsupported", max); + break; + + case ECC_PEERKEY_ERROR: + XSTRNCPY(buffer, "Bad ECC Peer Key", max); + break; + + case ECC_MAKEKEY_ERROR: + XSTRNCPY(buffer, "ECC Make Key failutre", max); + break; + + case ECC_EXPORT_ERROR: + XSTRNCPY(buffer, "ECC Export Key failutre", max); + break; + + case ECC_SHARED_ERROR: + XSTRNCPY(buffer, "ECC DHE shared failutre", max); + break; + + default : + XSTRNCPY(buffer, "unknown error number", max); + } + +#endif /* NO_ERROR_STRINGS */ +} + + + +/* be sure to add to cipher_name_idx too !!!! */ +const char* const cipher_names[] = +{ +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + "RC4-SHA", +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + "RC4-MD5", +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + "DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + "AES128-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + "AES256-SHA", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + "DHE-RSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + "DHE-RSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + "PSK-AES128-CBC-SHA", +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + "PSK-AES256-CBC-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5 + "HC128-MD5", +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA + "HC128-SHA", +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA + "RABBIT-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + "NTRU-RC4-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + "NTRU-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + "NTRU-AES128-SHA", +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + "NTRU-AES256-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + "ECDHE-RSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + "ECDHE-RSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + "ECDHE-ECDSA-AES128-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + "ECDHE-ECDSA-AES256-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + "ECDHE-RSA-RC4-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + "ECDHE-RSA-DES-CBC3-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + "ECDHE-ECDSA-RC4-SHA", +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + "ECDHE-ECDSA-DES-CBC3-SHA", +#endif + +}; + + + +/* cipher suite number that matches above name table */ +int cipher_name_idx[] = +{ + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + SSL_RSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + SSL_RSA_WITH_RC4_128_MD5, +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + SSL_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + TLS_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + TLS_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + TLS_PSK_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + TLS_PSK_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5 + TLS_RSA_WITH_HC_128_CBC_MD5, +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA + TLS_RSA_WITH_HC_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA + TLS_RSA_WITH_RABBIT_CBC_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + TLS_NTRU_RSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + TLS_NTRU_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + TLS_NTRU_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + TLS_ECDHE_RSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, +#endif + +}; + + +/* return true if set, else false */ +/* only supports full name from cipher_name[] delimited by : */ +int SetCipherList(SSL_CTX* ctx, const char* list) +{ + int ret = 0, i; + char name[MAX_SUITE_NAME]; + + char needle[] = ":"; + char* haystack = (char*)list; + char* prev; + + const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); + int idx = 0; + + if (!list) + return 0; + + if (*list == 0) return 1; /* CyaSSL default */ + + if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1; /* CyaSSL defualt */ + + for(;;) { + size_t len; + prev = haystack; + haystack = XSTRSTR(haystack, needle); + + if (!haystack) /* last cipher */ + len = min(sizeof(name), XSTRLEN(prev)); + else + len = min(sizeof(name), (size_t)(haystack - prev)); + + XSTRNCPY(name, prev, len); + name[(len == sizeof(name)) ? len - 1 : len] = 0; + + for (i = 0; i < suiteSz; i++) + if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) { + if (XSTRSTR(name, "EC")) + ctx->suites.suites[idx++] = ECC_BYTE; /* ECC suite */ + else + ctx->suites.suites[idx++] = 0x00; /* normal */ + ctx->suites.suites[idx++] = cipher_name_idx[i]; + + if (!ret) ret = 1; /* found at least one */ + break; + } + if (!haystack) break; + haystack++; + } + + if (ret) { + ctx->suites.setSuites = 1; + ctx->suites.suiteSz = idx; + } + + return ret; +} + + +#ifdef CYASSL_CALLBACKS + + /* Initialisze HandShakeInfo */ + void InitHandShakeInfo(HandShakeInfo* info) + { + int i; + + info->cipherName[0] = 0; + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) + info->packetNames[i][0] = 0; + info->numberPackets = 0; + info->negotiationError = 0; + } + + /* Set Final HandShakeInfo parameters */ + void FinishHandShakeInfo(HandShakeInfo* info, const SSL* ssl) + { + int i; + int sz = sizeof(cipher_name_idx)/sizeof(int); + + for (i = 0; i < sz; i++) + if (ssl->options.cipherSuite == (byte)cipher_name_idx[i]) { + if (ssl->options.cipherSuite0 == ECC_BYTE) + continue; /* ECC suites at end */ + XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ); + break; + } + + /* error max and min are negative numbers */ + if (ssl->error <= MIN_PARAM_ERR && ssl->error >= MAX_PARAM_ERR) + info->negotiationError = ssl->error; + } + + + /* Add name to info packet names, increase packet name count */ + void AddPacketName(const char* name, HandShakeInfo* info) + { + if (info->numberPackets < MAX_PACKETS_HANDSHAKE) { + XSTRNCPY(info->packetNames[info->numberPackets++], name, + MAX_PACKETNAME_SZ); + } + } + + + /* Initialisze TimeoutInfo */ + void InitTimeoutInfo(TimeoutInfo* info) + { + int i; + + info->timeoutName[0] = 0; + info->flags = 0; + + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) { + info->packets[i].packetName[0] = 0; + info->packets[i].timestamp.tv_sec = 0; + info->packets[i].timestamp.tv_usec = 0; + info->packets[i].bufferValue = 0; + info->packets[i].valueSz = 0; + } + info->numberPackets = 0; + info->timeoutValue.tv_sec = 0; + info->timeoutValue.tv_usec = 0; + } + + + /* Free TimeoutInfo */ + void FreeTimeoutInfo(TimeoutInfo* info, void* heap) + { + int i; + for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) + if (info->packets[i].bufferValue) { + XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO); + info->packets[i].bufferValue = 0; + } + + } + + + /* Add PacketInfo to TimeoutInfo */ + void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data, + int sz, void* heap) + { + if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) { + Timeval currTime; + + /* may add name after */ + if (name) + XSTRNCPY(info->packets[info->numberPackets].packetName, name, + MAX_PACKETNAME_SZ); + + /* add data, put in buffer if bigger than static buffer */ + info->packets[info->numberPackets].valueSz = sz; + if (sz < MAX_VALUE_SZ) + XMEMCPY(info->packets[info->numberPackets].value, data, sz); + else { + info->packets[info->numberPackets].bufferValue = + XMALLOC(sz, heap, DYNAMIC_TYPE_INFO); + if (!info->packets[info->numberPackets].bufferValue) + /* let next alloc catch, just don't fill, not fatal here */ + info->packets[info->numberPackets].valueSz = 0; + else + XMEMCPY(info->packets[info->numberPackets].bufferValue, + data, sz); + } + gettimeofday(&currTime, 0); + info->packets[info->numberPackets].timestamp.tv_sec = + currTime.tv_sec; + info->packets[info->numberPackets].timestamp.tv_usec = + currTime.tv_usec; + info->numberPackets++; + } + } + + + /* Add packet name to previsouly added packet info */ + void AddLateName(const char* name, TimeoutInfo* info) + { + /* make sure we have a valid previous one */ + if (info->numberPackets > 0 && info->numberPackets < + MAX_PACKETS_HANDSHAKE) { + XSTRNCPY(info->packets[info->numberPackets - 1].packetName, name, + MAX_PACKETNAME_SZ); + } + } + + /* Add record header to previsouly added packet info */ + void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info) + { + /* make sure we have a valid previous one */ + if (info->numberPackets > 0 && info->numberPackets < + MAX_PACKETS_HANDSHAKE) { + if (info->packets[info->numberPackets - 1].bufferValue) + XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl, + RECORD_HEADER_SZ); + else + XMEMCPY(info->packets[info->numberPackets - 1].value, rl, + RECORD_HEADER_SZ); + } + } + +#endif /* CYASSL_CALLBACKS */ + + + +/* client only parts */ +#ifndef NO_CYASSL_CLIENT + + int SendClientHello(SSL* ssl) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int idSz = ssl->options.resuming ? ID_LEN : 0; + int ret; + + length = sizeof(ProtocolVersion) + RAN_LEN + + idSz + ENUM_LEN + + ssl->suites.suiteSz + SUITE_LEN + + COMP_LEN + ENUM_LEN; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + length += ENUM_LEN; /* cookie */ + sendSz = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ; + idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + } +#endif + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, length, client_hello, ssl); + + /* client hello, first version */ + XMEMCPY(output + idx, &ssl->version, sizeof(ProtocolVersion)); + idx += sizeof(ProtocolVersion); + ssl->chVersion = ssl->version; /* store in case changed */ + + /* then random */ + if (ssl->options.connectState == CONNECT_BEGIN) { + RNG_GenerateBlock(&ssl->rng, output + idx, RAN_LEN); + + /* store random */ + XMEMCPY(ssl->arrays.clientRandom, output + idx, RAN_LEN); + } else { +#ifdef CYASSL_DTLS + /* send same random on hello again */ + XMEMCPY(output + idx, ssl->arrays.clientRandom, RAN_LEN); +#endif + } + idx += RAN_LEN; + + /* then session id */ + output[idx++] = idSz; + if (idSz) { + XMEMCPY(output + idx, ssl->session.sessionID, ID_LEN); + idx += ID_LEN; + } + + /* then DTLS cookie */ +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + output[idx++] = 0; + } +#endif + /* then cipher suites */ + c16toa(ssl->suites.suiteSz, output + idx); + idx += 2; + XMEMCPY(output + idx, &ssl->suites.suites, ssl->suites.suiteSz); + idx += ssl->suites.suiteSz; + + /* last, compression */ + output[idx++] = COMP_LEN; + if (ssl->options.usingCompression) + output[idx++] = ZLIB_COMPRESSION; + else + output[idx++] = NO_COMPRESSION; + + HashOutput(ssl, output, sendSz, 0); + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz, + ssl->heap); +#endif + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } + + + static int DoHelloVerifyRequest(SSL* ssl, const byte* input, + word32* inOutIdx) + { + ProtocolVersion pv; + byte cookieSz; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest", + &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo); +#endif + XMEMCPY(&pv, input + *inOutIdx, sizeof(pv)); + *inOutIdx += sizeof(pv); + + cookieSz = input[(*inOutIdx)++]; + + if (cookieSz) + *inOutIdx += cookieSz; /* skip for now */ + + ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + return 0; + } + + + static int DoServerHello(SSL* ssl, const byte* input, word32* inOutIdx) + { + byte b; + byte compression; + ProtocolVersion pv; + word32 i = *inOutIdx; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); +#endif + XMEMCPY(&pv, input + i, sizeof(pv)); + i += sizeof(pv); + XMEMCPY(ssl->arrays.serverRandom, input + i, RAN_LEN); + i += RAN_LEN; + b = input[i++]; + if (b) { + XMEMCPY(ssl->arrays.sessionID, input + i, b); + i += b; + } + ssl->options.cipherSuite0 = input[i++]; + ssl->options.cipherSuite = input[i++]; + compression = input[i++]; + + if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression) + ssl->options.usingCompression = 0; /* turn off if server refused */ + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + + *inOutIdx = i; + + if (ssl->options.resuming) { + if (XMEMCMP(ssl->arrays.sessionID, ssl->session.sessionID, ID_LEN) + == 0) { + if (SetCipherSpecs(ssl) == 0) { + int ret; + XMEMCPY(ssl->arrays.masterSecret, ssl->session.masterSecret, + SECRET_LEN); + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + else + ret = DeriveKeys(ssl); + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + return ret; + } + else + return UNSUPPORTED_SUITE; + } + else + ssl->options.resuming = 0; /* server denied resumption try */ + } + + return SetCipherSpecs(ssl); + } + + + /* just read in and ignore for now TODO: */ + static int DoCertificateRequest(SSL* ssl, const byte* input, word32* + inOutIdx) + { + word16 len; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("CertificateRequest", &ssl->timeoutInfo); + #endif + len = input[(*inOutIdx)++]; + + /* types, read in here */ + *inOutIdx += len; + ato16(&input[*inOutIdx], &len); + *inOutIdx += LENGTH_SZ; + + if (IsAtLeastTLSv1_2(ssl)) { + /* hash sig format */ + *inOutIdx += len; + ato16(&input[*inOutIdx], &len); + *inOutIdx += LENGTH_SZ; + } + + /* authorities */ + while (len) { + word16 dnSz; + + ato16(&input[*inOutIdx], &dnSz); + *inOutIdx += (REQUEST_HEADER + dnSz); + len -= dnSz + REQUEST_HEADER; + } + + /* don't send client cert or cert verify if user hasn't provided + cert and private key */ + if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer) + ssl->options.sendVerify = SEND_CERT; + else if (IsAtLeastTLSv1_2(ssl)) + ssl->options.sendVerify = SEND_BLANK_CERT; + + return 0; + } + + + static int DoServerKeyExchange(SSL* ssl, const byte* input, word32* + inOutIdx) + { + word16 sigLen; + word16 verifySz; + word16 length; + byte* signature; + + sigLen = 0; + signature = 0; + + /* keep start idx */ + verifySz = *inOutIdx; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ServerKeyExchange", &ssl->timeoutInfo); + #endif + + #ifndef NO_PSK + if (ssl->specs.kea == psk_kea) { + ato16(&input[*inOutIdx], &length); + *inOutIdx += LENGTH_SZ; + XMEMCPY(ssl->arrays.server_hint, &input[*inOutIdx], + min(length, MAX_PSK_ID_LEN)); + if (length < MAX_PSK_ID_LEN) + ssl->arrays.server_hint[length] = 0; + else + ssl->arrays.server_hint[MAX_PSK_ID_LEN - 1] = 0; + *inOutIdx += length; + + return 0; + } + #endif + #ifdef OPENSSL_EXTRA + if (ssl->specs.kea == diffie_hellman_kea) + { + /* p */ + ato16(&input[*inOutIdx], &length); + *inOutIdx += LENGTH_SZ; + + ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_P.buffer) + ssl->buffers.serverDH_P.length = length; + else + return MEMORY_ERROR; + XMEMCPY(ssl->buffers.serverDH_P.buffer, &input[*inOutIdx], length); + *inOutIdx += length; + + /* g */ + ato16(&input[*inOutIdx], &length); + *inOutIdx += LENGTH_SZ; + + ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_G.buffer) + ssl->buffers.serverDH_G.length = length; + else + return MEMORY_ERROR; + XMEMCPY(ssl->buffers.serverDH_G.buffer, &input[*inOutIdx], length); + *inOutIdx += length; + + /* pub */ + ato16(&input[*inOutIdx], &length); + *inOutIdx += LENGTH_SZ; + + ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_Pub.buffer) + ssl->buffers.serverDH_Pub.length = length; + else + return MEMORY_ERROR; + XMEMCPY(ssl->buffers.serverDH_Pub.buffer, &input[*inOutIdx], length); + *inOutIdx += length; + } /* dh_kea */ + #endif /* OPENSSL_EXTRA */ + + #ifdef HAVE_ECC + if (ssl->specs.kea == ecc_diffie_hellman_kea) + { + byte b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != named_curve) + return ECC_CURVETYPE_ERROR; + + *inOutIdx += 1; /* curve type, eat leading 0 */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b != + secp160r1 && b != secp192r1 && b != secp224r1) + return ECC_CURVE_ERROR; + + length = input[*inOutIdx]; + *inOutIdx += 1; + + if (ecc_import_x963(&input[*inOutIdx], length, &ssl->peerEccKey) != 0) + return ECC_PEERKEY_ERROR; + + *inOutIdx += length; + ssl->peerEccKeyPresent = 1; + } + #endif /* HAVE_ECC */ + + #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC) + { + Md5 md5; + Sha sha; + byte hash[FINISHED_SZ]; + byte messageVerify[MAX_DH_SZ]; + + /* adjust from start idx */ + verifySz = *inOutIdx - verifySz; + + /* save message for hash verify */ + if (verifySz > sizeof(messageVerify)) + return BUFFER_ERROR; + XMEMCPY(messageVerify, &input[*inOutIdx - verifySz], verifySz); + + if (IsAtLeastTLSv1_2(ssl)) { + /* just advance for now TODO: validate hash algo params */ + *inOutIdx += LENGTH_SZ; + } + + /* signature */ + ato16(&input[*inOutIdx], &length); + *inOutIdx += LENGTH_SZ; + + signature = (byte*)&input[*inOutIdx]; + *inOutIdx += length; + sigLen = length; + + /* verify signature */ + + /* md5 */ + InitMd5(&md5); + Md5Update(&md5, ssl->arrays.clientRandom, RAN_LEN); + Md5Update(&md5, ssl->arrays.serverRandom, RAN_LEN); + Md5Update(&md5, messageVerify, verifySz); + Md5Final(&md5, hash); + + /* sha */ + InitSha(&sha); + ShaUpdate(&sha, ssl->arrays.clientRandom, RAN_LEN); + ShaUpdate(&sha, ssl->arrays.serverRandom, RAN_LEN); + ShaUpdate(&sha, messageVerify, verifySz); + ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); + + /* rsa */ + if (ssl->specs.sig_algo == rsa_sa_algo) + { + int ret; + byte* out; + + if (!ssl->peerRsaKeyPresent) + return NO_PEER_KEY; + + ret = RsaSSL_VerifyInline(signature, sigLen,&out, &ssl->peerRsaKey); + + if (IsAtLeastTLSv1_2(ssl)) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 encSigSz; + byte* digest; + int hashType; + int digestSz; + + /* sha1 for now */ + digest = &hash[MD5_DIGEST_SIZE]; + hashType = SHAh; + digestSz = SHA_DIGEST_SIZE; + + encSigSz = EncodeSignature(encodedSig,digest,digestSz,hashType); + + if (encSigSz != ret || XMEMCMP(out, encodedSig, encSigSz) != 0) + return VERIFY_SIGN_ERROR; + } + else { + if (ret != sizeof(hash) || XMEMCMP(out, hash, sizeof(hash))) + return VERIFY_SIGN_ERROR; + } + } +#ifdef HAVE_ECC + /* ecdsa */ + else if (ssl->specs.sig_algo == ecc_dsa_sa_algo) { + int verify = 0, ret; + if (!ssl->peerEccDsaKeyPresent) + return NO_PEER_KEY; + + ret = ecc_verify_hash(signature, sigLen, &hash[MD5_DIGEST_SIZE], + SHA_DIGEST_SIZE, &verify, &ssl->peerEccDsaKey); + if (ret != 0 || verify == 0) + return VERIFY_SIGN_ERROR; + } +#endif /* HAVE_ECC */ + else + return -1; + + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + + return 0; + + } +#endif /* HAVE_OPENSSL or HAVE_ECC */ + return -1; /* not supported by build */ + } + + + int SendClientKeyExchange(SSL* ssl) + { + byte encSecret[MAX_NTRU_ENCRYPT_SZ]; + word32 encSz = 0; + word32 idx = 0; + int ret = 0; + + if (ssl->specs.kea == rsa_kea) { + RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret, + SECRET_LEN); + ssl->arrays.preMasterSecret[0] = ssl->chVersion.major; + ssl->arrays.preMasterSecret[1] = ssl->chVersion.minor; + ssl->arrays.preMasterSz = SECRET_LEN; + + if (ssl->peerRsaKeyPresent == 0) + return NO_PEER_KEY; + + ret = RsaPublicEncrypt(ssl->arrays.preMasterSecret, SECRET_LEN, + encSecret, sizeof(encSecret), &ssl->peerRsaKey, + &ssl->rng); + if (ret > 0) { + encSz = ret; + ret = 0; /* set success to 0 */ + } + #ifdef OPENSSL_EXTRA + } else if (ssl->specs.kea == diffie_hellman_kea) { + buffer serverP = ssl->buffers.serverDH_P; + buffer serverG = ssl->buffers.serverDH_G; + buffer serverPub = ssl->buffers.serverDH_Pub; + byte priv[ENCRYPT_LEN]; + word32 privSz; + DhKey key; + + if (serverP.buffer == 0 || serverG.buffer == 0 || + serverPub.buffer == 0) + return NO_PEER_KEY; + + InitDhKey(&key); + ret = DhSetKey(&key, serverP.buffer, serverP.length, + serverG.buffer, serverG.length); + if (ret == 0) + /* for DH, encSecret is Yc, agree is pre-master */ + ret = DhGenerateKeyPair(&key, &ssl->rng, priv, &privSz, + encSecret, &encSz); + if (ret == 0) + ret = DhAgree(&key, ssl->arrays.preMasterSecret, + &ssl->arrays.preMasterSz, priv, privSz, + serverPub.buffer, serverPub.length); + FreeDhKey(&key); + #endif /* OPENSSL_EXTRA */ + #ifndef NO_PSK + } else if (ssl->specs.kea == psk_kea) { + byte* pms = ssl->arrays.preMasterSecret; + + ssl->arrays.psk_keySz = ssl->options.client_psk_cb(ssl, + ssl->arrays.server_hint, ssl->arrays.client_identity, + MAX_PSK_ID_LEN, ssl->arrays.psk_key, MAX_PSK_KEY_LEN); + if (ssl->arrays.psk_keySz == 0 || + ssl->arrays.psk_keySz > MAX_PSK_KEY_LEN) + return PSK_KEY_ERROR; + encSz = (word32)XSTRLEN(ssl->arrays.client_identity); + if (encSz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR; + XMEMCPY(encSecret, ssl->arrays.client_identity, encSz); + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16)ssl->arrays.psk_keySz, pms); + pms += 2; + XMEMSET(pms, 0, ssl->arrays.psk_keySz); + pms += ssl->arrays.psk_keySz; + c16toa((word16)ssl->arrays.psk_keySz, pms); + pms += 2; + XMEMCPY(pms, ssl->arrays.psk_key, ssl->arrays.psk_keySz); + ssl->arrays.preMasterSz = ssl->arrays.psk_keySz * 2 + 4; + #endif /* NO_PSK */ + #ifdef HAVE_NTRU + } else if (ssl->specs.kea == ntru_kea) { + word32 rc; + word16 cipherLen = sizeof(encSecret); + DRBG_HANDLE drbg; + static uint8_t const cyasslStr[] = { + 'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U' + }; + + RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret, + SECRET_LEN); + ssl->arrays.preMasterSz = SECRET_LEN; + + if (ssl->peerNtruKeyPresent == 0) + return NO_PEER_KEY; + + rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr, + sizeof(cyasslStr), GetEntropy, &drbg); + if (rc != DRBG_OK) + return NTRU_DRBG_ERROR; + + rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen,ssl->peerNtruKey, + ssl->arrays.preMasterSz, + ssl->arrays.preMasterSecret, + &cipherLen, encSecret); + crypto_drbg_uninstantiate(drbg); + if (rc != NTRU_OK) + return NTRU_ENCRYPT_ERROR; + + encSz = cipherLen; + ret = 0; + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + } else if (ssl->specs.kea == ecc_diffie_hellman_kea) { + ecc_key myKey; + word32 size = sizeof(encSecret); + + if (!ssl->peerEccKeyPresent || !ssl->peerEccKey.dp) + return NO_PEER_KEY; + + ecc_init(&myKey); + ret = ecc_make_key(&ssl->rng, ssl->peerEccKey.dp->size, &myKey); + if (ret != 0) + return ECC_MAKEKEY_ERROR; + + /* precede export with 1 byte length */ + ret = ecc_export_x963(&myKey, encSecret + 1, &size); + encSecret[0] = size; + encSz = size + 1; + + if (ret != 0) + ret = ECC_EXPORT_ERROR; + else { + size = sizeof(ssl->arrays.preMasterSecret); + ret = ecc_shared_secret(&myKey, &ssl->peerEccKey, + ssl->arrays.preMasterSecret, &size); + if (ret != 0) + ret = ECC_SHARED_ERROR; + } + + ssl->arrays.preMasterSz = size; + ecc_free(&myKey); + #endif /* HAVE_ECC */ + } else + return -1; /* unsupported kea */ + + if (ret == 0) { + byte *output; + int sendSz; + word32 tlsSz = 0; + + if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea) + tlsSz = 2; + + if (ssl->specs.kea == ecc_diffie_hellman_kea) /* always off */ + tlsSz = 0; + + sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + idx = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + idx += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA; + } + #endif + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl); + + if (tlsSz) { + c16toa((word16)encSz, &output[idx]); + idx += 2; + } + XMEMCPY(output + idx, encSecret, encSz); + idx += encSz; + + HashOutput(ssl, output, sendSz, 0); + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + + ret = SendBuffered(ssl); + } + + if (ret == 0 || ret == WANT_WRITE) { + int tmpRet = MakeMasterSecret(ssl); + if (tmpRet != 0) + ret = tmpRet; /* save WANT_WRITE unless more serious */ + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + } + + return ret; + } + + int SendCertificateVerify(SSL* ssl) + { + byte *output; + int sendSz = 0, length, ret; + word32 idx = 0; + RsaKey key; + + if (ssl->options.sendVerify == SEND_BLANK_CERT) + return 0; /* sent blank cert, can't verify */ + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, MAX_CERT_VERIFY_SZ)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + BuildCertHashes(ssl, &ssl->certHashes); + + /* TODO: when add DSS support check here */ + InitRsaKey(&key, ssl->heap); + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key, + ssl->buffers.key.length); + if (ret == 0) { + byte* verify = (byte*)&output[RECORD_HEADER_SZ + + HANDSHAKE_HEADER_SZ]; + byte* signBuffer = ssl->certHashes.md5; + word32 signSz = sizeof(Hashes); + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 extraSz = 0; /* tls 1.2 hash/sig */ + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + length = RsaEncryptSize(&key); + if (IsAtLeastTLSv1_2(ssl)) { + verify[0] = sha_mac; + verify[1] = rsa_sa_algo; + extraSz = HASH_SIG_SIZE; + } + c16toa((word16)length, verify + extraSz); /* prepend verify header*/ + + if (IsAtLeastTLSv1_2(ssl)) { + byte* digest; + int hashType; + int digestSz; + + /* sha1 for now */ + digest = ssl->certHashes.sha; + hashType = SHAh; + digestSz = SHA_DIGEST_SIZE; + + signSz = EncodeSignature(encodedSig, digest, digestSz,hashType); + signBuffer = encodedSig; + } + + ret = RsaSSL_Sign(signBuffer, signSz, verify + extraSz + + VERIFY_HEADER, ENCRYPT_LEN, &key, &ssl->rng); + + if (ret > 0) { + ret = 0; /* reset */ + + AddHeaders(output, length + extraSz + VERIFY_HEADER, + certificate_verify, ssl); + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + + extraSz + VERIFY_HEADER; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + HashOutput(ssl, output, sendSz, 0); + } + } + + FreeRsaKey(&key); + + if (ret == 0) { + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateVerify", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("CertificateVerify", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + ssl->buffers.outputBuffer.length += sendSz; + return SendBuffered(ssl); + } + else + return ret; + } + + + +#endif /* NO_CYASSL_CLIENT */ + + +#ifndef NO_CYASSL_SERVER + + int SendServerHello(SSL* ssl) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + int ret; + + length = sizeof(ProtocolVersion) + RAN_LEN + + ID_LEN + ENUM_LEN + + SUITE_LEN + + ENUM_LEN; + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, MAX_HELLO_SZ)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + AddHeaders(output, length, server_hello, ssl); + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* now write to output */ + /* first version */ + XMEMCPY(output + idx, &ssl->version, sizeof(ProtocolVersion)); + idx += sizeof(ProtocolVersion); + + /* then random */ + if (!ssl->options.resuming) + RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN); + XMEMCPY(output + idx, ssl->arrays.serverRandom, RAN_LEN); + idx += RAN_LEN; + +#ifdef SHOW_SECRETS + { + int j; + printf("server random: "); + for (j = 0; j < RAN_LEN; j++) + printf("%02x", ssl->arrays.serverRandom[j]); + printf("\n"); + } +#endif + /* then session id */ + output[idx++] = ID_LEN; + if (!ssl->options.resuming) + RNG_GenerateBlock(&ssl->rng, ssl->arrays.sessionID, ID_LEN); + XMEMCPY(output + idx, ssl->arrays.sessionID, ID_LEN); + idx += ID_LEN; + + /* then cipher suite */ + output[idx++] = ssl->options.cipherSuite0; + output[idx++] = ssl->options.cipherSuite; + + /* last, compression */ + if (ssl->options.usingCompression) + output[idx++] = ZLIB_COMPRESSION; + else + output[idx++] = NO_COMPRESSION; + + ssl->buffers.outputBuffer.length += sendSz; + HashOutput(ssl, output, sendSz, 0); + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz, + ssl->heap); + #endif + + ssl->options.serverState = SERVER_HELLO_COMPLETE; + + return SendBuffered(ssl); + } + + +#ifdef HAVE_ECC + + byte SetCurveId(int size) + { + switch(size) { + case 20: + return secp160r1; + break; + case 24: + return secp192r1; + break; + case 28: + return secp224r1; + break; + case 32: + return secp256r1; + break; + case 48: + return secp384r1; + break; + case 66: + return secp521r1; + break; + default: + return 0; + } + } + +#endif /* HAVE_ECC */ + + + int SendServerKeyExchange(SSL* ssl) + { + int ret = 0; + + #ifndef NO_PSK + if (ssl->specs.kea == psk_kea) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + if (ssl->arrays.server_hint[0] == 0) return 0; /* don't send */ + + /* include size part */ + length = (word32)XSTRLEN(ssl->arrays.server_hint); + if (length > MAX_PSK_ID_LEN) return SERVER_HINT_ERROR; + length += HINT_LEN_SZ; + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* key data */ + c16toa((word16)(length - HINT_LEN_SZ), output + idx); + idx += HINT_LEN_SZ; + XMEMCPY(output + idx, ssl->arrays.server_hint, length -HINT_LEN_SZ); + + HashOutput(ssl, output, sendSz, 0); + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + ret = SendBuffered(ssl); + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + } + #endif /*NO_PSK */ + + #ifdef HAVE_ECC + if (ssl->specs.kea == ecc_diffie_hellman_kea) + { + byte *output; + word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int sendSz; + byte export[MAX_EXPORT_ECC_SZ]; + word32 expSz = sizeof(export); + word32 sigSz; + word32 preSigSz, preSigIdx; + RsaKey rsaKey; + ecc_key dsaKey; + + /* curve type, named curve, length(1) */ + length = ENUM_LEN + CURVE_LEN + ENUM_LEN; + /* pub key size */ + if (ecc_export_x963(&ssl->eccTempKey, export, &expSz) != 0) + return ECC_EXPORT_ERROR; + length += expSz; + + preSigSz = length; + preSigIdx = idx; + + InitRsaKey(&rsaKey, ssl->heap); + ecc_init(&dsaKey); + + /* sig length */ + length += LENGTH_SZ; + + if (!ssl->buffers.key.buffer) { + FreeRsaKey(&rsaKey); + ecc_free(&dsaKey); + return NO_PRIVATE_KEY; + } + + if (ssl->specs.sig_algo == rsa_sa_algo) { + /* rsa sig size */ + word32 i = 0; + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i, + &rsaKey, ssl->buffers.key.length); + if (ret != 0) return ret; + sigSz = RsaEncryptSize(&rsaKey); + } + else if (ssl->specs.sig_algo == ecc_dsa_sa_algo) { + /* ecdsa sig size */ + word32 i = 0; + ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i, + &dsaKey, ssl->buffers.key.length); + if (ret != 0) return ret; + sigSz = ecc_sig_size(&dsaKey); + } + else { + FreeRsaKey(&rsaKey); + ecc_free(&dsaKey); + return -1; /* unsupported type */ + } + length += sigSz; + + if (IsAtLeastTLSv1_2(ssl)) + length += HASH_SIG_SIZE; + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) { + FreeRsaKey(&rsaKey); + ecc_free(&dsaKey); + return ret; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* key exchange data */ + output[idx++] = named_curve; + output[idx++] = 0x00; /* leading zero */ + output[idx++] = SetCurveId(ecc_size(&ssl->eccTempKey)); + output[idx++] = expSz; + XMEMCPY(output + idx, export, expSz); + idx += expSz; + if (IsAtLeastTLSv1_2(ssl)) { + output[idx++] = sha_mac; + output[idx++] = ssl->specs.sig_algo; + } + c16toa(sigSz, output + idx); + idx += LENGTH_SZ; + + /* do signature */ + { + Md5 md5; + Sha sha; + byte hash[FINISHED_SZ]; + byte* signBuffer = hash; + word32 signSz = sizeof(hash); + + /* md5 */ + InitMd5(&md5); + Md5Update(&md5, ssl->arrays.clientRandom, RAN_LEN); + Md5Update(&md5, ssl->arrays.serverRandom, RAN_LEN); + Md5Update(&md5, output + preSigIdx, preSigSz); + Md5Final(&md5, hash); + + /* sha */ + InitSha(&sha); + ShaUpdate(&sha, ssl->arrays.clientRandom, RAN_LEN); + ShaUpdate(&sha, ssl->arrays.serverRandom, RAN_LEN); + ShaUpdate(&sha, output + preSigIdx, preSigSz); + ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]); + + if (ssl->specs.sig_algo == rsa_sa_algo) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + if (IsAtLeastTLSv1_2(ssl)) { + byte* digest; + int hashType; + int digestSz; + + /* sha1 for now */ + digest = &hash[MD5_DIGEST_SIZE]; + hashType = SHAh; + digestSz = SHA_DIGEST_SIZE; + + signSz = EncodeSignature(encodedSig, digest, digestSz, + hashType); + signBuffer = encodedSig; + } + ret = RsaSSL_Sign(signBuffer, signSz, output + idx, sigSz, + &rsaKey, &ssl->rng); + FreeRsaKey(&rsaKey); + if (ret > 0) + ret = 0; /* reset on success */ + else + return ret; + } + else if (ssl->specs.sig_algo == ecc_dsa_sa_algo) { + word32 sz = sigSz; + + FreeRsaKey(&rsaKey); + ret = ecc_sign_hash(&hash[MD5_DIGEST_SIZE], SHA_DIGEST_SIZE, + output + idx, &sz, &ssl->rng, &dsaKey); + } + } + + HashOutput(ssl, output, sendSz, 0); + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, + output, sendSz, ssl->heap); + #endif + + ssl->buffers.outputBuffer.length += sendSz; + ret = SendBuffered(ssl); + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + } + #endif /* HAVE_ECC */ + + return ret; + } + + + static int MatchSuite(SSL* ssl, Suites* peerSuites) + { + word16 i, j; + + /* & 0x1 equivalent % 2 */ + if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1) + return MATCH_SUITE_ERROR; + + /* start with best, if a match we are good */ + for (i = 0; i < ssl->suites.suiteSz; i += 2) + for (j = 0; j < peerSuites->suiteSz; j += 2) + if (ssl->suites.suites[i] == peerSuites->suites[j] && + ssl->suites.suites[i+1] == peerSuites->suites[j+1] ) { + + ssl->options.cipherSuite0 = ssl->suites.suites[i]; + ssl->options.cipherSuite = ssl->suites.suites[i+1]; + return SetCipherSpecs(ssl); + } + + return MATCH_SUITE_ERROR; + } + + + /* process alert, return level */ + int ProcessOldClientHello(SSL* ssl, const byte* input, word32* inOutIdx, + word32 inSz, word16 sz) + { + word32 idx = *inOutIdx; + word16 sessionSz; + word16 randomSz; + word16 i, j; + ProtocolVersion pv; + Suites clSuites; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + + /* manually hash input since different format */ + Md5Update(&ssl->hashMd5, input + idx, sz); + ShaUpdate(&ssl->hashSha, input + idx, sz); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + Sha256Update(&ssl->hashSha256, input + idx, sz); +#endif + + /* does this value mean client_hello? */ + idx++; + + /* version */ + pv.major = input[idx++]; + pv.minor = input[idx++]; + ssl->chVersion = pv; /* store */ + + if (ssl->version.minor > 0 && pv.minor == 0) { + if (!ssl->options.downgrade) + return VERSION_ERROR; + /* turn off tls */ + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = 0; + InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, FALSE, + ssl->options.haveNTRU, ssl->options.haveECDSA, + ssl->ctx->method->side); + } + + /* suite size */ + ato16(&input[idx], &clSuites.suiteSz); + idx += 2; + + if (clSuites.suiteSz > MAX_SUITE_SZ) + return BUFFER_ERROR; + + /* session size */ + ato16(&input[idx], &sessionSz); + idx += 2; + + if (sessionSz > ID_LEN) + return BUFFER_ERROR; + + /* random size */ + ato16(&input[idx], &randomSz); + idx += 2; + + if (randomSz > RAN_LEN) + return BUFFER_ERROR; + + /* suites */ + for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) { + byte first = input[idx++]; + if (!first) { /* implicit: skip sslv2 type */ + XMEMCPY(&clSuites.suites[j], &input[idx], 2); + j += 2; + } + idx += 2; + } + clSuites.suiteSz = j; + + /* session id */ + if (sessionSz) { + XMEMCPY(ssl->arrays.sessionID, input + idx, sessionSz); + idx += sessionSz; + ssl->options.resuming = 1; + } + + /* random */ + if (randomSz < RAN_LEN) + XMEMSET(ssl->arrays.clientRandom, 0, RAN_LEN - randomSz); + XMEMCPY(&ssl->arrays.clientRandom[RAN_LEN - randomSz], input + idx, + randomSz); + idx += randomSz; + + if (ssl->options.usingCompression) + ssl->options.usingCompression = 0; /* turn off */ + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + *inOutIdx = idx; + + /* DoClientHello uses same resume code */ + while (ssl->options.resuming) { /* let's try */ + int ret; + SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret); + if (!session) { + ssl->options.resuming = 0; + break; /* session lookup failed */ + } + if (MatchSuite(ssl, &clSuites) < 0) + return UNSUPPORTED_SUITE; + + RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN); + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + else + ret = DeriveKeys(ssl); + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + + return ret; + } + + return MatchSuite(ssl, &clSuites); + } + + + static int DoClientHello(SSL* ssl, const byte* input, word32* inOutIdx, + word32 totalSz, word32 helloSz) + { + byte b; + ProtocolVersion pv; + Suites clSuites; + word32 i = *inOutIdx; + word32 begin = i; + +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); +#endif + /* make sure can read up to session */ + if (i + sizeof(pv) + RAN_LEN + ENUM_LEN > totalSz) + return INCOMPLETE_DATA; + + XMEMCPY(&pv, input + i, sizeof(pv)); + ssl->chVersion = pv; /* store */ + i += sizeof(pv); + if (ssl->version.minor > 0 && pv.minor == 0) { + if (!ssl->options.downgrade) + return VERSION_ERROR; + /* turn off tls */ + ssl->options.tls = 0; + ssl->options.tls1_1 = 0; + ssl->version.minor = 0; + InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, FALSE, + ssl->options.haveNTRU, ssl->options.haveECDSA, + ssl->ctx->method->side); + } + /* random */ + XMEMCPY(ssl->arrays.clientRandom, input + i, RAN_LEN); + i += RAN_LEN; + +#ifdef SHOW_SECRETS + { + int j; + printf("client random: "); + for (j = 0; j < RAN_LEN; j++) + printf("%02x", ssl->arrays.clientRandom[j]); + printf("\n"); + } +#endif + /* session id */ + b = input[i++]; + if (b) { + if (i + ID_LEN > totalSz) + return INCOMPLETE_DATA; + XMEMCPY(ssl->arrays.sessionID, input + i, ID_LEN); + i += b; + ssl->options.resuming= 1; /* client wants to resume */ + } + + #ifdef CYASSL_DTLS + /* cookie */ + if (ssl->options.dtls) { + b = input[i++]; + if (b) { + if (b > MAX_COOKIE_LEN) + return BUFFER_ERROR; + if (i + b > totalSz) + return INCOMPLETE_DATA; + XMEMCPY(ssl->arrays.cookie, input + i, b); + i += b; + } + } + #endif + + if (i + LENGTH_SZ > totalSz) + return INCOMPLETE_DATA; + /* suites */ + ato16(&input[i], &clSuites.suiteSz); + i += 2; + + /* suites and comp len */ + if (i + clSuites.suiteSz + ENUM_LEN > totalSz) + return INCOMPLETE_DATA; + if (clSuites.suiteSz > MAX_SUITE_SZ) + return BUFFER_ERROR; + XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz); + i += clSuites.suiteSz; + + b = input[i++]; /* comp len */ + if (i + b > totalSz) + return INCOMPLETE_DATA; + + if (ssl->options.usingCompression) { + int match = 0; + while (b--) { + byte comp = input[i++]; + if (comp == ZLIB_COMPRESSION) + match = 1; + } + if (!match) + ssl->options.usingCompression = 0; /* turn off */ + } + else + i += b; /* ignore, since we're not on */ + + ssl->options.clientState = CLIENT_HELLO_COMPLETE; + + *inOutIdx = i; + if ( (i - begin) < helloSz) + *inOutIdx = begin + helloSz; /* skip extensions */ + + /* ProcessOld uses same resume code */ + while (ssl->options.resuming) { /* let's try */ + int ret; + SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret); + if (!session) { + ssl->options.resuming = 0; + break; /* session lookup failed */ + } + if (MatchSuite(ssl, &clSuites) < 0) + return UNSUPPORTED_SUITE; + + RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN); + if (ssl->options.tls) + ret = DeriveTlsKeys(ssl); + else + ret = DeriveKeys(ssl); + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + + return ret; + } + return MatchSuite(ssl, &clSuites); + } + + + static int DoCertificateVerify(SSL* ssl, byte* input, word32* inOutsz, + word32 totalSz) + { + word16 sz = 0; + word32 i = *inOutsz; + int ret = VERIFY_CERT_ERROR; /* start in error state */ + byte* sig; + byte* out; + int outLen; + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("CertificateVerify", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("CertificateVerify", &ssl->timeoutInfo); + #endif + if ( (i + VERIFY_HEADER) > totalSz) + return INCOMPLETE_DATA; + + if (IsAtLeastTLSv1_2(ssl)) + i += HASH_SIG_SIZE; + ato16(&input[i], &sz); + i += VERIFY_HEADER; + + if ( (i + sz) > totalSz) + return INCOMPLETE_DATA; + + if (sz > ENCRYPT_LEN) + return BUFFER_ERROR; + + sig = &input[i]; + *inOutsz = i + sz; + /* TODO: when add DSS support check here */ + if (ssl->peerRsaKeyPresent != 0) { + outLen = RsaSSL_VerifyInline(sig, sz, &out, &ssl->peerRsaKey); + + if (IsAtLeastTLSv1_2(ssl)) { + byte encodedSig[MAX_ENCODED_SIG_SZ]; + word32 sigSz; + byte* digest; + int hashType; + int digestSz; + + /* sha1 for now */ + digest = ssl->certHashes.sha; + hashType = SHAh; + digestSz = SHA_DIGEST_SIZE; + + sigSz = EncodeSignature(encodedSig, digest, digestSz, hashType); + + if (outLen == sigSz && XMEMCMP(out, encodedSig, sigSz) == 0) + ret = 0; + } + else { + if (outLen == sizeof(ssl->certHashes) && XMEMCMP(out, + ssl->certHashes.md5, sizeof(ssl->certHashes)) == 0) + ret = 0; + } + } + return ret; + } + + + int SendServerHelloDone(SSL* ssl) + { + byte *output; + int sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + int ret; + + #ifdef CYASSL_DTLS + if (ssl->options.dtls) + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + #endif + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, 0, server_hello_done, ssl); + + HashOutput(ssl, output, sendSz, 0); +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ServerHelloDone", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz, + ssl->heap); +#endif + ssl->options.serverState = SERVER_HELLODONE_COMPLETE; + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } + + + int SendHelloVerifyRequest(SSL* ssl) + { + byte* output; + int length = VERSION_SZ + ENUM_LEN; + int idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ; + int sendSz = length + idx; + int ret; + + /* check for avalaible size */ + if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.idx; + + AddHeaders(output, length, hello_verify_request, ssl); + + XMEMCPY(output + idx, &ssl->chVersion, VERSION_SZ); + idx += VERSION_SZ; + output[idx++] = 0; /* no cookie for now */ + + HashOutput(ssl, output, sendSz, 0); +#ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output, + sendSz, ssl->heap); +#endif + ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } + + + static int DoClientKeyExchange(SSL* ssl, byte* input, + word32* inOutIdx) + { + int ret = 0; + word32 length = 0; + byte* out; + + if (ssl->options.verifyPeer && ssl->options.failNoCert) + if (!ssl->options.havePeerCert) { + CYASSL_MSG("client didn't present peer cert"); + return NO_PEER_CERT; + } + + #ifdef CYASSL_CALLBACKS + if (ssl->hsInfoOn) + AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); + if (ssl->toInfoOn) + AddLateName("ClientKeyExchange", &ssl->timeoutInfo); + #endif + if (ssl->specs.kea == rsa_kea) { + word32 idx = 0; + RsaKey key; + byte* tmp = 0; + + InitRsaKey(&key, ssl->heap); + + if (ssl->buffers.key.buffer) + ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key, + ssl->buffers.key.length); + else + return NO_PRIVATE_KEY; + + if (ret == 0) { + length = RsaEncryptSize(&key); + ssl->arrays.preMasterSz = SECRET_LEN; + + if (ssl->options.tls) + (*inOutIdx) += 2; + tmp = input + *inOutIdx; + *inOutIdx += length; + + if (RsaPrivateDecryptInline(tmp, length, &out, &key) == + SECRET_LEN) { + XMEMCPY(ssl->arrays.preMasterSecret, out, SECRET_LEN); + if (ssl->arrays.preMasterSecret[0] != ssl->chVersion.major + || + ssl->arrays.preMasterSecret[1] != ssl->chVersion.minor) + + ret = PMS_VERSION_ERROR; + else + ret = MakeMasterSecret(ssl); + } + else + ret = RSA_PRIVATE_ERROR; + } + + FreeRsaKey(&key); +#ifndef NO_PSK + } else if (ssl->specs.kea == psk_kea) { + byte* pms = ssl->arrays.preMasterSecret; + word16 ci_sz; + + ato16(&input[*inOutIdx], &ci_sz); + *inOutIdx += LENGTH_SZ; + if (ci_sz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR; + + XMEMCPY(ssl->arrays.client_identity, &input[*inOutIdx], ci_sz); + *inOutIdx += ci_sz; + ssl->arrays.client_identity[ci_sz] = 0; + + ssl->arrays.psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays.client_identity, ssl->arrays.psk_key, + MAX_PSK_KEY_LEN); + if (ssl->arrays.psk_keySz == 0 || + ssl->arrays.psk_keySz > MAX_PSK_KEY_LEN) return PSK_KEY_ERROR; + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16)ssl->arrays.psk_keySz, pms); + pms += 2; + XMEMSET(pms, 0, ssl->arrays.psk_keySz); + pms += ssl->arrays.psk_keySz; + c16toa((word16)ssl->arrays.psk_keySz, pms); + pms += 2; + XMEMCPY(pms, ssl->arrays.psk_key, ssl->arrays.psk_keySz); + ssl->arrays.preMasterSz = ssl->arrays.psk_keySz * 2 + 4; + + ret = MakeMasterSecret(ssl); +#endif /* NO_PSK */ +#ifdef HAVE_NTRU + } else if (ssl->specs.kea == ntru_kea) { + word32 rc; + word16 cipherLen; + word16 plainLen = sizeof(ssl->arrays.preMasterSecret); + byte* tmp; + + if (!ssl->buffers.key.buffer) + return NO_PRIVATE_KEY; + + ato16(&input[*inOutIdx], &cipherLen); + *inOutIdx += LENGTH_SZ; + if (cipherLen > MAX_NTRU_ENCRYPT_SZ) + return NTRU_KEY_ERROR; + + tmp = input + *inOutIdx; + rc = crypto_ntru_decrypt((word16)ssl->buffers.key.length, + ssl->buffers.key.buffer, cipherLen, tmp, &plainLen, + ssl->arrays.preMasterSecret); + + if (rc != NTRU_OK || plainLen != SECRET_LEN) + return NTRU_DECRYPT_ERROR; + *inOutIdx += cipherLen; + + ssl->arrays.preMasterSz = plainLen; + ret = MakeMasterSecret(ssl); +#endif /* HAVE_NTRU */ +#ifdef HAVE_ECC + } else if (ssl->specs.kea == ecc_diffie_hellman_kea) { + word32 size; + word32 length = input[*inOutIdx]; /* one byte length */ + *inOutIdx += 1; + + ret = ecc_import_x963(&input[*inOutIdx], length, &ssl->peerEccKey); + if (ret != 0) + return ECC_PEERKEY_ERROR; + *inOutIdx += length; + ssl->peerEccKeyPresent = 1; + + size = sizeof(ssl->arrays.preMasterSecret); + ret = ecc_shared_secret(&ssl->eccTempKey, &ssl->peerEccKey, + ssl->arrays.preMasterSecret, &size); + if (ret != 0) + return ECC_SHARED_ERROR; + ssl->arrays.preMasterSz = size; + ret = MakeMasterSecret(ssl); +#endif /* HAVE_ECC */ + } + + if (ret == 0) { + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + if (ssl->options.verifyPeer) + BuildCertHashes(ssl, &ssl->certHashes); + } + + return ret; + } + +#endif /* NO_CYASSL_SERVER */ + + +#ifdef SINGLE_THREADED + +int InitMutex(CyaSSL_Mutex* m) +{ + return 0; +} + + +int FreeMutex(CyaSSL_Mutex* m) +{ + return 0; +} + + +int LockMutex(CyaSSL_Mutex* m) +{ + return 0; +} + + +int UnLockMutex(CyaSSL_Mutex* m) +{ + return 0; +} + +#else /* MULTI_THREAD */ + + #ifdef USE_WINDOWS_API + + int InitMutex(CyaSSL_Mutex* m) + { + InitializeCriticalSection(m); + return 0; + } + + + int FreeMutex(CyaSSL_Mutex* m) + { + DeleteCriticalSection(m); + return 0; + } + + + int LockMutex(CyaSSL_Mutex* m) + { + EnterCriticalSection(m); + return 0; + } + + + int UnLockMutex(CyaSSL_Mutex* m) + { + LeaveCriticalSection(m); + return 0; + } + + #elif defined(CYASSL_PTHREADS) + + int InitMutex(CyaSSL_Mutex* m) + { + if (pthread_mutex_init(m, 0) == 0) + return 0; + else + return -1; + } + + + int FreeMutex(CyaSSL_Mutex* m) + { + if (pthread_mutex_destroy(m) == 0) + return 0; + else + return -1; + } + + + int LockMutex(CyaSSL_Mutex* m) + { + if (pthread_mutex_lock(m) == 0) + return 0; + else + return -1; + } + + + int UnLockMutex(CyaSSL_Mutex* m) + { + if (pthread_mutex_unlock(m) == 0) + return 0; + else + return -1; + } + + #elif defined(THREADX) + + int InitMutex(CyaSSL_Mutex* m) + { + if (tx_mutex_create(m, "CyaSSL Mutex", TX_NO_INHERIT) == 0) + return 0; + else + return -1; + } + + + int FreeMutex(CyaSSL_Mutex* m) + { + if (tx_mutex_delete(m) == 0) + return 0; + else + return -1; + } + + + int LockMutex(CyaSSL_Mutex* m) + { + if (tx_mutex_get(m, TX_WAIT_FOREVER) == 0) + return 0; + else + return -1; + } + + + int UnLockMutex(CyaSSL_Mutex* m) + { + if (tx_mutex_put(m) == 0) + return 0; + else + return -1; + } + + #elif defined(MICRIUM) + + int InitMutex(CyaSSL_Mutex* m) + { + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + if (NetSecure_OS_MutexCreate(m) == 0) + return 0; + else + return -1; + #else + return 0; + #endif + } + + + int FreeMutex(CyaSSL_Mutex* m) + { + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + if (NetSecure_OS_FreeMutex(m) == 0) + return 0; + else + return -1; + #else + return 0; + #endif + } + + + int LockMutex(CyaSSL_Mutex* m) + { + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + if (NetSecure_OS_LockMutex(m) == 0) + return 0; + else + return -1; + #else + return 0; + #endif + } + + + int UnLockMutex(CyaSSL_Mutex* m) + { + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + if (NetSecure_OS_UnLockMutex(m) == 0) + return 0; + else + return -1; + #else + return 0; + #endif + + } + + #endif /* USE_WINDOWS_API */ +#endif /* SINGLE_THREADED */ + + +#ifdef DEBUG_CYASSL + + static int logging = 0; + + + int CyaSSL_Debugging_ON(void) + { + logging = 1; + return 0; + } + + + void CyaSSL_Debugging_OFF(void) + { + logging = 0; + } + + +#ifdef THREADX + int dc_log_printf(char*, ...); +#endif + + void CYASSL_MSG(const char* msg) + { + if (logging) { +#ifdef THREADX + dc_log_printf("%s\n", msg); +#elif defined(MICRIUM) + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + NetSecure_TraceOut((CPU_CHAR *)msg); + #endif +#else + fprintf(stderr, "%s\n", msg); +#endif + } + } + + + void CYASSL_ENTER(const char* msg) + { + if (logging) { + char buffer[80]; + sprintf(buffer, "CyaSSL Entering %s", msg); + CYASSL_MSG(buffer); + } + } + + + void CYASSL_LEAVE(const char* msg, int ret) + { + if (logging) { + char buffer[80]; + sprintf(buffer, "CyaSSL Leaving %s, return %d", msg, ret); + CYASSL_MSG(buffer); + } + } + + + void CYASSL_ERROR(int error) + { + if (logging) { + char buffer[80]; + sprintf(buffer, "CyaSSL error occured, error = %d", error); + CYASSL_MSG(buffer); + } + } + + +#else /* DEBUG_CYASSL */ + + int CyaSSL_Debugging_ON(void) + { + return -1; /* not compiled in */ + } + + + void CyaSSL_Debugging_OFF(void) + { + /* already off */ + } + +#endif /* DEBUG_CYASSL */ diff --git a/release/src/router/cyassl/src/cyassl_io.c b/release/src/router/cyassl/src/cyassl_io.c new file mode 100644 index 00000000..a5f5283f --- /dev/null +++ b/release/src/router/cyassl/src/cyassl_io.c @@ -0,0 +1,190 @@ +/* cyassl_io.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifdef _WIN32_WCE + /* On WinCE winsock2.h must be included before windows.h for socket stuff */ + #include <winsock2.h> +#endif + +#include "cyassl_int.h" + +/* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove + automatic setting of default I/O functions EmbedSend() and EmbedReceive() + but they'll still nedd SetCallback xxx() at end of file +*/ +#ifndef CYASSL_USER_IO + +#ifdef HAVE_LIBZ + #include "zlib.h" +#endif + +#ifndef USE_WINDOWS_API + #include <sys/types.h> + #include <errno.h> + #include <unistd.h> + #include <fcntl.h> + #if !(defined(DEVKITPRO) || defined(THREADX)) + #include <sys/socket.h> + #include <arpa/inet.h> + #include <netinet/in.h> + #include <netdb.h> + #include <sys/ioctl.h> + #endif + #ifdef THREADX + #include <socket.h> + #endif +#endif /* USE_WINDOWS_API */ + +#ifdef __sun + #include <sys/filio.h> +#endif + +#ifdef USE_WINDOWS_API + /* no epipe yet */ + #ifndef WSAEPIPE + #define WSAEPIPE -12345 + #endif + #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK + #define SOCKET_EAGAIN WSAEWOULDBLOCK + #define SOCKET_ECONNRESET WSAECONNRESET + #define SOCKET_EINTR WSAEINTR + #define SOCKET_EPIPE WSAEPIPE +#else + #define SOCKET_EWOULDBLOCK EWOULDBLOCK + #define SOCKET_EAGAIN EAGAIN + #define SOCKET_ECONNRESET ECONNRESET + #define SOCKET_EINTR EINTR + #define SOCKET_EPIPE EPIPE +#endif /* USE_WINDOWS_API */ + + +#ifdef DEVKITPRO + /* from network.h */ + int net_send(int, const void*, int, unsigned int); + int net_recv(int, void*, int, unsigned int); + #define SEND_FUNCTION net_send + #define RECV_FUNCTION net_recv +#else + #define SEND_FUNCTION send + #define RECV_FUNCTION recv +#endif + + +static INLINE int LastError(void) +{ +#ifdef USE_WINDOWS_API + return WSAGetLastError(); +#else + return errno; +#endif +} + +/* The receive embedded callback + * return : nb bytes read, or error + */ +int EmbedReceive(char *buf, int sz, void *ctx) +{ + int recvd; + int err; + int socket = *(int*)ctx; + + recvd = RECV_FUNCTION(socket, (char *)buf, sz, 0); + + if (recvd == -1) { + err = LastError(); + if (err == SOCKET_EWOULDBLOCK || + err == SOCKET_EAGAIN) + return IO_ERR_WANT_READ; + + else if (err == SOCKET_ECONNRESET) + return IO_ERR_CONN_RST; + + else if (err == SOCKET_EINTR) + return IO_ERR_ISR; + + else + return IO_ERR_GENERAL; + } + else if (recvd == 0) + return IO_ERR_CONN_CLOSE; + + return recvd; +} + +/* The send embedded callback + * return : nb bytes sent, or error + */ +int EmbedSend(char *buf, int sz, void *ctx) +{ + int socket = *(int*)ctx; + int sent; + int len = sz; + + sent = SEND_FUNCTION(socket, &buf[sz - len], len, 0); + + if (sent == -1) { + if (LastError() == SOCKET_EWOULDBLOCK || + LastError() == SOCKET_EAGAIN) + return IO_ERR_WANT_WRITE; + + else if (LastError() == SOCKET_ECONNRESET) + return IO_ERR_CONN_RST; + + else if (LastError() == SOCKET_EINTR) + return IO_ERR_ISR; + + else if (LastError() == SOCKET_EPIPE) + return IO_ERR_CONN_CLOSE; + + else + return IO_ERR_GENERAL; + } + + return sent; +} + + +#endif /* CYASSL_USER_IO */ + +void CyaSSL_SetIORecv(SSL_CTX *ctx, CallbackIORecv CBIORecv) +{ + ctx->CBIORecv = CBIORecv; +} + + +void CyaSSL_SetIOSend(SSL_CTX *ctx, CallbackIOSend CBIOSend) +{ + ctx->CBIOSend = CBIOSend; +} + + +void CyaSSL_SetIOReadCtx(SSL* ssl, void *rctx) +{ + ssl->IOCB_ReadCtx = rctx; +} + + +void CyaSSL_SetIOWriteCtx(SSL* ssl, void *wctx) +{ + ssl->IOCB_WriteCtx = wctx; +} + diff --git a/release/src/router/cyassl/src/keys.c b/release/src/router/cyassl/src/keys.c new file mode 100644 index 00000000..3a51f7fb --- /dev/null +++ b/release/src/router/cyassl/src/keys.c @@ -0,0 +1,751 @@ +/* keys.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + + +#include "cyassl_int.h" +#include "cyassl_error.h" +#ifdef SHOW_SECRETS + #include <stdio.h> +#endif + + +#ifndef NO_TLS + int MakeTlsMasterSecret(SSL*); + void TLS_hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz, + int content, int verify); +#endif + + + +int SetCipherSpecs(SSL* ssl) +{ + /* ECC extensions */ + if (ssl->options.cipherSuite0 == ECC_BYTE) { + + switch (ssl->options.cipherSuite) { + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA + case TLS_ECDHE_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ecc_diffie_hellman_kea; + ssl->specs.sig_algo = ecc_dsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + + default: + return UNSUPPORTED_SUITE; + } + } else { /* Normal suites */ + switch (ssl->options.cipherSuite) { + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA + case SSL_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA + case TLS_NTRU_RSA_WITH_RC4_128_SHA : + ssl->specs.bulk_cipher_algorithm = rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5 + case SSL_RSA_WITH_RC4_128_MD5 : + ssl->specs.bulk_cipher_algorithm = rc4; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = md5_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = MD5_DIGEST_SIZE; + ssl->specs.pad_size = PAD_MD5; + ssl->specs.key_size = RC4_KEY_SIZE; + ssl->specs.iv_size = 0; + ssl->specs.block_size = 0; + + break; +#endif + +#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA + case SSL_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA + case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = triple_des; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = DES3_KEY_SIZE; + ssl->specs.block_size = DES_BLOCK_SIZE; + ssl->specs.iv_size = DES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA + case TLS_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA + case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA + case TLS_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA + case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = ntru_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA + case TLS_PSK_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA + case TLS_PSK_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = psk_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + ssl->options.usingPSK_cipher = 1; + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_128_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = aes; + ssl->specs.cipher_type = block; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = diffie_hellman_kea; + ssl->specs.sig_algo = rsa_sa_algo; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = AES_256_KEY_SIZE; + ssl->specs.block_size = AES_BLOCK_SIZE; + ssl->specs.iv_size = AES_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5 + case TLS_RSA_WITH_HC_128_CBC_MD5 : + ssl->specs.bulk_cipher_algorithm = hc128; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = md5_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = MD5_DIGEST_SIZE; + ssl->specs.pad_size = PAD_MD5; + ssl->specs.key_size = HC_128_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HC_128_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA + case TLS_RSA_WITH_HC_128_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = hc128; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = HC_128_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = HC_128_IV_SIZE; + + break; +#endif + +#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA + case TLS_RSA_WITH_RABBIT_CBC_SHA : + ssl->specs.bulk_cipher_algorithm = rabbit; + ssl->specs.cipher_type = stream; + ssl->specs.mac_algorithm = sha_mac; + ssl->specs.kea = rsa_kea; + ssl->specs.hash_size = SHA_DIGEST_SIZE; + ssl->specs.pad_size = PAD_SHA; + ssl->specs.key_size = RABBIT_KEY_SIZE; + ssl->specs.block_size = 0; + ssl->specs.iv_size = RABBIT_IV_SIZE; + + break; +#endif + + default: + return UNSUPPORTED_SUITE; + } + } /* ECC / Normal suites else */ + + /* set TLS if it hasn't been turned off */ + if (ssl->version.major == 3 && ssl->version.minor >= 1) { +#ifndef NO_TLS + ssl->options.tls = 1; + ssl->hmac = TLS_hmac; + if (ssl->version.minor >= 2) + ssl->options.tls1_1 = 1; +#endif + } + +#ifdef CYASSL_DTLS + if (ssl->options.dtls) + ssl->hmac = TLS_hmac; +#endif + + return 0; +} + + +enum KeyStuff { + MASTER_ROUNDS = 3, + PREFIX = 3, /* up to three letters for master prefix */ + KEY_PREFIX = 7 /* up to 7 prefix letters for key rounds */ + + +}; + + +/* true or false, zero for error */ +static int SetPrefix(byte* sha_input, int index) +{ + switch (index) { + case 0: + XMEMCPY(sha_input, "A", 1); + break; + case 1: + XMEMCPY(sha_input, "BB", 2); + break; + case 2: + XMEMCPY(sha_input, "CCC", 3); + break; + case 3: + XMEMCPY(sha_input, "DDDD", 4); + break; + case 4: + XMEMCPY(sha_input, "EEEEE", 5); + break; + case 5: + XMEMCPY(sha_input, "FFFFFF", 6); + break; + case 6: + XMEMCPY(sha_input, "GGGGGGG", 7); + break; + default: + return 0; + } + return 1; +} + + +static int SetKeys(Ciphers* encrypt, Ciphers* decrypt, Keys* keys, + CipherSpecs* specs, byte side) +{ +#ifdef BUILD_ARC4 + word32 sz = specs->key_size; + if (specs->bulk_cipher_algorithm == rc4) { + if (side == CLIENT_END) { + Arc4SetKey(&encrypt->arc4, keys->client_write_key, sz); + Arc4SetKey(&decrypt->arc4, keys->server_write_key, sz); + } + else { + Arc4SetKey(&encrypt->arc4, keys->server_write_key, sz); + Arc4SetKey(&decrypt->arc4, keys->client_write_key, sz); + } + } +#endif + +#ifdef BUILD_HC128 + if (specs->bulk_cipher_algorithm == hc128) { + if (side == CLIENT_END) { + Hc128_SetKey(&encrypt->hc128, keys->client_write_key, + keys->client_write_IV); + Hc128_SetKey(&decrypt->hc128, keys->server_write_key, + keys->server_write_IV); + } + else { + Hc128_SetKey(&encrypt->hc128, keys->server_write_key, + keys->server_write_IV); + Hc128_SetKey(&decrypt->hc128, keys->client_write_key, + keys->client_write_IV); + } + } +#endif + +#ifdef BUILD_RABBIT + if (specs->bulk_cipher_algorithm == rabbit) { + if (side == CLIENT_END) { + RabbitSetKey(&encrypt->rabbit, keys->client_write_key, + keys->client_write_IV); + RabbitSetKey(&decrypt->rabbit, keys->server_write_key, + keys->server_write_IV); + } + else { + RabbitSetKey(&encrypt->rabbit, keys->server_write_key, + keys->server_write_IV); + RabbitSetKey(&decrypt->rabbit, keys->client_write_key, + keys->client_write_IV); + } + } +#endif + +#ifdef BUILD_DES3 + if (specs->bulk_cipher_algorithm == triple_des) { + if (side == CLIENT_END) { + Des3_SetKey(&encrypt->des3, keys->client_write_key, + keys->client_write_IV, DES_ENCRYPTION); + Des3_SetKey(&decrypt->des3, keys->server_write_key, + keys->server_write_IV, DES_DECRYPTION); + } + else { + Des3_SetKey(&encrypt->des3, keys->server_write_key, + keys->server_write_IV, DES_ENCRYPTION); + Des3_SetKey(&decrypt->des3, keys->client_write_key, + keys->client_write_IV, DES_DECRYPTION); + } + } +#endif + +#ifdef BUILD_AES + if (specs->bulk_cipher_algorithm == aes) { + if (side == CLIENT_END) { + AesSetKey(&encrypt->aes, keys->client_write_key, + specs->key_size, keys->client_write_IV, + AES_ENCRYPTION); + AesSetKey(&decrypt->aes, keys->server_write_key, + specs->key_size, keys->server_write_IV, + AES_DECRYPTION); + } + else { + AesSetKey(&encrypt->aes, keys->server_write_key, + specs->key_size, keys->server_write_IV, + AES_ENCRYPTION); + AesSetKey(&decrypt->aes, keys->client_write_key, + specs->key_size, keys->client_write_IV, + AES_DECRYPTION); + } + } +#endif + + keys->sequence_number = 0; + keys->peer_sequence_number = 0; + keys->encryptionOn = 0; + + return 0; +} + + +/* TLS can call too */ +int StoreKeys(SSL* ssl, const byte* keyData) +{ + int sz = ssl->specs.hash_size, i; + + XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz); + i = sz; + XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz); + i += sz; + + sz = ssl->specs.key_size; + XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz); + i += sz; + XMEMCPY(ssl->keys.server_write_key, &keyData[i], sz); + i += sz; + + sz = ssl->specs.iv_size; + XMEMCPY(ssl->keys.client_write_IV, &keyData[i], sz); + i += sz; + XMEMCPY(ssl->keys.server_write_IV, &keyData[i], sz); + + return SetKeys(&ssl->encrypt, &ssl->decrypt, &ssl->keys, &ssl->specs, + ssl->options.side); +} + + +int DeriveKeys(SSL* ssl) +{ + int length = 2 * ssl->specs.hash_size + + 2 * ssl->specs.key_size + + 2 * ssl->specs.iv_size; + int rounds = (length + MD5_DIGEST_SIZE - 1 ) / MD5_DIGEST_SIZE, i; + + byte shaOutput[SHA_DIGEST_SIZE]; + byte md5Input[SECRET_LEN + SHA_DIGEST_SIZE]; + byte shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN]; + + Md5 md5; + Sha sha; + + byte keyData[KEY_PREFIX * MD5_DIGEST_SIZE]; /* max size */ + + InitMd5(&md5); + InitSha(&sha); + + XMEMCPY(md5Input, ssl->arrays.masterSecret, SECRET_LEN); + + for (i = 0; i < rounds; ++i) { + int j = i + 1; + int idx = j; + + if (!SetPrefix(shaInput, i)) { + return PREFIX_ERROR; + } + + XMEMCPY(shaInput + idx, ssl->arrays.masterSecret, SECRET_LEN); + idx += SECRET_LEN; + XMEMCPY(shaInput + idx, ssl->arrays.serverRandom, RAN_LEN); + idx += RAN_LEN; + XMEMCPY(shaInput + idx, ssl->arrays.clientRandom, RAN_LEN); + idx += RAN_LEN; + + ShaUpdate(&sha, shaInput, sizeof(shaInput) - KEY_PREFIX + j); + ShaFinal(&sha, shaOutput); + + XMEMCPY(&md5Input[SECRET_LEN], shaOutput, SHA_DIGEST_SIZE); + Md5Update(&md5, md5Input, sizeof(md5Input)); + Md5Final(&md5, keyData + i * MD5_DIGEST_SIZE); + } + + return StoreKeys(ssl, keyData); +} + + +void CleanPreMaster(SSL* ssl) +{ + int i, sz = ssl->arrays.preMasterSz; + + for (i = 0; i < sz; i++) + ssl->arrays.preMasterSecret[i] = 0; + + RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret, sz); + + for (i = 0; i < sz; i++) + ssl->arrays.preMasterSecret[i] = 0; + +} + + +/* Create and store the master secret see page 32, 6.1 */ +int MakeMasterSecret(SSL* ssl) +{ + byte shaOutput[SHA_DIGEST_SIZE]; + byte md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE]; + byte shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN]; + int i, ret; + word32 idx; + word32 pmsSz = ssl->arrays.preMasterSz; + + Md5 md5; + Sha sha; + +#ifdef SHOW_SECRETS + { + int j; + printf("pre master secret: "); + for (j = 0; j < pmsSz; j++) + printf("%02x", ssl->arrays.preMasterSecret[j]); + printf("\n"); + } +#endif + +#ifndef NO_TLS + if (ssl->options.tls) return MakeTlsMasterSecret(ssl); +#endif + + InitMd5(&md5); + InitSha(&sha); + + XMEMCPY(md5Input, ssl->arrays.preMasterSecret, pmsSz); + + for (i = 0; i < MASTER_ROUNDS; ++i) { + byte prefix[PREFIX]; + if (!SetPrefix(prefix, i)) { + return PREFIX_ERROR; + } + + idx = 0; + XMEMCPY(shaInput, prefix, i + 1); + idx += i + 1; + + XMEMCPY(shaInput + idx, ssl->arrays.preMasterSecret, pmsSz); + idx += pmsSz; + XMEMCPY(shaInput + idx, ssl->arrays.clientRandom, RAN_LEN); + idx += RAN_LEN; + XMEMCPY(shaInput + idx, ssl->arrays.serverRandom, RAN_LEN); + idx += RAN_LEN; + ShaUpdate(&sha, shaInput, idx); + ShaFinal(&sha, shaOutput); + + idx = pmsSz; /* preSz */ + XMEMCPY(md5Input + idx, shaOutput, SHA_DIGEST_SIZE); + idx += SHA_DIGEST_SIZE; + Md5Update(&md5, md5Input, idx); + Md5Final(&md5, &ssl->arrays.masterSecret[i * MD5_DIGEST_SIZE]); + } + +#ifdef SHOW_SECRETS + { + int i; + printf("master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", ssl->arrays.masterSecret[i]); + printf("\n"); + } +#endif + + ret = DeriveKeys(ssl); + CleanPreMaster(ssl); + + return ret; +} + + + + diff --git a/release/src/router/cyassl/src/sniffer.c b/release/src/router/cyassl/src/sniffer.c new file mode 100644 index 00000000..40891dfc --- /dev/null +++ b/release/src/router/cyassl/src/sniffer.c @@ -0,0 +1,2187 @@ +/* sniffer.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifdef CYASSL_SNIFFER + +#include "ssl.h" +#include "cyassl_int.h" +#include "cyassl_error.h" +#include "sniffer.h" +#include "sniffer_error.h" +#include <time.h> + +#ifndef _WIN32 + #include <arpa/inet.h> +#endif + +#include <assert.h> + + +#ifdef _WIN32 + #define SNPRINTF _snprintf +#else + #define SNPRINTF snprintf +#endif + + +/* Misc constants */ +enum { + MAX_SERVER_ADDRESS = 128, /* maximum server address length */ + MAX_ERROR_LEN = 80, /* maximum error length */ + ETHER_IF_ADDR_LEN = 6, /* ethernet interface address length */ + LOCAL_IF_ADDR_LEN = 4, /* localhost interface address length, !windows */ + TCP_PROTO = 6, /* TCP_PROTOCOL */ + IP_HDR_SZ = 20, /* IP header legnth, min */ + TCP_HDR_SZ = 20, /* TCP header legnth, min */ + IPV4 = 4, /* IP version 4 */ + TCP_PROTOCOL = 6, /* TCP Protocol id */ + TRACE_MSG_SZ = 80, /* Trace Message buffer size */ + HASH_SIZE = 499, /* Session Hash Table Rows */ + PSEUDO_HDR_SZ = 12, /* TCP Pseudo Header size in bytes */ + FATAL_ERROR_STATE = 1, /* SnifferSession fatal error state */ + SNIFFER_TIMEOUT = 900, /* Cache unclosed Sessions for 15 minutes */ +}; + + +#ifdef _WIN32 + +static HMODULE dllModule; /* for error string resources */ + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + static int didInit = 0; + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + if (didInit == 0) { + dllModule = hModule; + ssl_InitSniffer(); + didInit = 1; + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + if (didInit) { + ssl_FreeSniffer(); + didInit = 0; + } + break; + } + return TRUE; +} + +#endif /* _WIN32 */ + + +static int TraceOn = 0; /* Trace is off by default */ +static FILE* TraceFile = 0; + + +/* windows uses .rc talbe for this */ +#ifndef _WIN32 + +static const char* const msgTable[] = +{ + /* 1 */ + "Out of Memory", + "New SSL Sniffer Server Registered", + "Checking IP Header", + "SSL Sniffer Server Not Registered", + "Checking TCP Header", + + /* 6 */ + "SSL Sniffer Server Port Not Registered", + "RSA Private Decrypt Error", + "RSA Private Decode Error", + "Set Cipher Spec Error", + "Server Hello Input Malformed", + + /* 11 */ + "Couldn't Resume Session Error", + "Server Did Resumption", + "Client Hello Input Malformed", + "Client Trying to Resume", + "Handshake Input Malformed", + + /* 16 */ + "Got Hello Verify msg", + "Got Server Hello msg", + "Got Cert Request msg", + "Got Server Key Exchange msg", + "Got Cert msg", + + /* 21 */ + "Got Server Hello Done msg", + "Got Finished msg", + "Got Client Hello msg", + "Got Client Key Exchange msg", + "Got Cert Verify msg", + + /* 26 */ + "Got Unknown Handshake msg", + "New SSL Sniffer Session created", + "Couldn't create new SSL", + "Got a Packet to decode", + "No data present", + + /* 31 */ + "Session Not Found", + "Got an Old Client Hello msg", + "Old Client Hello Input Malformed", + "Old Client Hello OK", + "Bad Old Client Hello", + + /* 36 */ + "Bad Record Header", + "Record Header Input Malformed", + "Got a HandShake msg", + "Bad HandShake msg", + "Got a Change Cipher Spec msg", + + /* 41 */ + "Got Application Data msg", + "Bad Application Data", + "Got an Alert msg", + "Another msg to Process", + "Removing Session From Table", + + /* 46 */ + "Bad Key File", + "Wrong IP Version", + "Wrong Protocol type", + "Packet Short for header processing", + "Got Unknown Record Type", + + /* 51 */ + "Can't Open Trace File", + "Session in Fatal Error State", + "Partial SSL record received", + "Buffer Error, malformed input", + "Added to Partial Input", + + /* 56 */ + "Received a Duplicate Packet", + "Received an Out of Order Packet", + "Received an Overlap Duplicate Packet", + "Received an Overlap Reassembly Begin Duplicate Packet", + "Received an Overlap Reassembly End Duplicate Packet", + + /* 61 */ + "Missed the Client Hello Entirely", +}; + + +/* *nix version uses table above */ +static void GetError(int idx, char* buffer) +{ + XSTRNCPY(buffer, msgTable[idx - 1], MAX_ERROR_LEN); +} + + +#else /* _WIN32 */ + + +/* Windows version uses .rc table */ +static void GetError(int idx, char* buffer) +{ + if (!LoadStringA(dllModule, idx, buffer, MAX_ERROR_LEN)) + buffer[0] = 0; +} + + +#endif /* _WIN32 */ + + +/* Packet Buffer for reassembly list and ready list */ +typedef struct PacketBuffer { + word32 begin; /* relative sequence begin */ + word32 end; /* relative sequence end */ + byte* data; /* actual data */ + struct PacketBuffer* next; /* next on reassembly list or ready list */ +} PacketBuffer; + + +/* Sniffer Server holds info for each server/port monitored */ +typedef struct SnifferServer { + SSL_CTX* ctx; /* SSL context */ + char address[MAX_SERVER_ADDRESS]; /* passed in server address */ + word32 server; /* netowrk order address */ + int port; /* server port */ + struct SnifferServer* next; /* for list */ +} SnifferServer; + + +/* Session Flags */ +typedef struct Flags { + byte side; /* which end is current packet headed */ + byte serverCipherOn; /* indicates whether cipher is active */ + byte clientCipherOn; /* indicates whether cipher is active */ + byte resuming; /* did this session come from resumption */ + byte cached; /* have we cached this session yet */ + byte clientHello; /* processed client hello yet, for SSLv2 */ + byte finCount; /* get both FINs before removing */ + byte fatalError; /* fatal error state */ +} Flags; + + +/* Out of Order FIN caputre */ +typedef struct FinCaputre { + word32 cliFinSeq; /* client relative sequence FIN 0 is no */ + word32 srvFinSeq; /* server relative sequence FIN, 0 is no */ + byte cliCounted; /* did we count yet, detects duplicates */ + byte srvCounted; /* did we count yet, detects duplicates */ +} FinCaputre; + + +/* Sniffer Session holds info for each client/server SSL/TLS session */ +typedef struct SnifferSession { + SnifferServer* context; /* server context */ + SSL* sslServer; /* SSL server side decode */ + SSL* sslClient; /* SSL client side decode */ + word32 server; /* server address in network byte order */ + word32 client; /* client address in network byte order */ + word16 srvPort; /* server port */ + word16 cliPort; /* client port */ + word32 cliSeqStart; /* client start sequence */ + word32 srvSeqStart; /* server start sequence */ + word32 cliExpected; /* client expected sequence (relative) */ + word32 srvExpected; /* server expected sequence (relative) */ + FinCaputre finCaputre; /* retain out of order FIN s */ + Flags flags; /* session flags */ + time_t bornOn; /* born on ticks */ + PacketBuffer* cliReassemblyList; /* client out of order packets */ + PacketBuffer* srvReassemblyList; /* server out of order packets */ + struct SnifferSession* next; /* for hash table list */ +} SnifferSession; + + +/* Sniffer Server List and mutex */ +static SnifferServer* ServerList = 0; +static CyaSSL_Mutex ServerListMutex; + + +/* Session Hash Table, mutex, and count */ +static SnifferSession* SessionTable[HASH_SIZE]; +static CyaSSL_Mutex SessionMutex; +static int SessionCount = 0; + + +/* Initialize overall Sniffer */ +void ssl_InitSniffer(void) +{ + InitCyaSSL(); + InitMutex(&ServerListMutex); + InitMutex(&SessionMutex); +} + + +/* Free Sniffer Server's resources/self */ +static void FreeSnifferServer(SnifferServer* server) +{ + if (server) + SSL_CTX_free(server->ctx); + free(server); +} + + +/* free PacketBuffer's resources/self */ +static void FreePacketBuffer(PacketBuffer* remove) +{ + if (remove) { + free(remove->data); + free(remove); + } +} + + +/* remove PacketBuffer List */ +static void FreePacketList(PacketBuffer* buffer) +{ + if (buffer) { + PacketBuffer* remove; + PacketBuffer* packet = buffer; + + while (packet) { + remove = packet; + packet = packet->next; + FreePacketBuffer(remove); + } + } +} + + +/* Free Sniffer Session's resources/self */ +static void FreeSnifferSession(SnifferSession* session) +{ + if (session) { + SSL_free(session->sslClient); + SSL_free(session->sslServer); + + FreePacketList(session->cliReassemblyList); + FreePacketList(session->srvReassemblyList); + } + free(session); +} + + +/* Free overall Sniffer */ +void ssl_FreeSniffer(void) +{ + SnifferServer* server; + SnifferServer* removeServer; + SnifferSession* session; + SnifferSession* removeSession; + int i; + + LockMutex(&ServerListMutex); + LockMutex(&SessionMutex); + + server = ServerList; + while (server) { + removeServer = server; + server = server->next; + FreeSnifferServer(removeServer); + } + + for (i = 0; i < HASH_SIZE; i++) { + session = SessionTable[i]; + while (session) { + removeSession = session; + session = session->next; + FreeSnifferSession(removeSession); + } + } + + UnLockMutex(&SessionMutex); + UnLockMutex(&ServerListMutex); + + FreeMutex(&SessionMutex); + FreeMutex(&ServerListMutex); + FreeCyaSSL(); +} + + +/* Initialize a SnifferServer */ +static void InitSnifferServer(SnifferServer* sniffer) +{ + sniffer->ctx = 0; + XMEMSET(sniffer->address, 0, MAX_SERVER_ADDRESS); + sniffer->server = 0; + sniffer->port = 0; + sniffer->next = 0; +} + + +/* Initialize session flags */ +static void InitFlags(Flags* flags) +{ + flags->side = 0; + flags->serverCipherOn = 0; + flags->clientCipherOn = 0; + flags->resuming = 0; + flags->cached = 0; + flags->clientHello = 0; + flags->finCount = 0; + flags->fatalError = 0; +} + + +/* Initialize FIN Capture */ +static void InitFinCapture(FinCaputre* cap) +{ + cap->cliFinSeq = 0; + cap->srvFinSeq = 0; + cap->cliCounted = 0; + cap->srvCounted = 0; +} + + +/* Initialize a Sniffer Session */ +static void InitSession(SnifferSession* session) +{ + session->context = 0; + session->sslServer = 0; + session->sslClient = 0; + session->server = 0; + session->client = 0; + session->srvPort = 0; + session->cliPort = 0; + session->cliSeqStart = 0; + session->srvSeqStart = 0; + session->cliExpected = 0; + session->srvExpected = 0; + session->bornOn = 0; + session->cliReassemblyList = 0; + session->srvReassemblyList = 0; + session->next = 0; + + InitFlags(&session->flags); + InitFinCapture(&session->finCaputre); +} + + +/* IP Info from IP Header */ +typedef struct IpInfo { + int length; /* length of this header */ + int total; /* total length of fragment */ + word32 src; /* network order source address */ + word32 dst; /* network order destination address */ +} IpInfo; + + +/* TCP Info from TCP Header */ +typedef struct TcpInfo { + int srcPort; /* source port */ + int dstPort; /* source port */ + int length; /* length of this header */ + word32 sequence; /* sequence number */ + byte fin; /* FIN set */ + byte rst; /* RST set */ + byte syn; /* SYN set */ + byte ack; /* ACK set */ +} TcpInfo; + + +/* Tcp Pseudo Header for Checksum calculation */ +typedef struct TcpPseudoHdr { + word32 src; /* source address */ + word32 dst; /* destination address */ + byte rsv; /* reserved, always 0 */ + byte protocol; /* IP protocol */ + word16 legnth; /* tcp header length + data length (doesn't include */ + /* pseudo header length) network order */ +} TcpPseudoHdr; + + +/* Password Setting Callback */ +static int SetPassword(char* passwd, int sz, int rw, void* userdata) +{ + XSTRNCPY(passwd, userdata, sz); + return XSTRLEN(userdata); +} + + +/* Ethernet Header */ +typedef struct EthernetHdr { + byte dst[ETHER_IF_ADDR_LEN]; /* destination host address */ + byte src[ETHER_IF_ADDR_LEN]; /* source host address */ + word16 type; /* IP, ARP, etc */ +} EthernetHdr; + + +/* IP Header */ +typedef struct IpHdr { + byte ver_hl; /* version/header length */ + byte tos; /* type of service */ + word16 length; /* total length */ + word16 id; /* identification */ + word16 offset; /* fragment offset field */ + byte ttl; /* time to live */ + byte protocol; /* protocol */ + word16 sum; /* checksum */ + word32 src; /* source address */ + word32 dst; /* destination address */ +} IpHdr; + + +#define IP_HL(ip) ( (((ip)->ver_hl) & 0x0f) * 4) +#define IP_V(ip) ( ((ip)->ver_hl) >> 4) + +/* TCP Header */ +typedef struct TcpHdr { + word16 srcPort; /* source port */ + word16 dstPort; /* destination port */ + word32 sequence; /* sequence number */ + word32 ack; /* acknoledgment number */ + byte offset; /* data offset, reserved */ + byte flags; /* option flags */ + word16 window; /* window */ + word16 sum; /* checksum */ + word16 urgent; /* urgent pointer */ +} TcpHdr; + +#define TCP_LEN(tcp) ( (((tcp)->offset & 0xf0) >> 4) * 4) +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_ACK 0x10 + + + + + +/* Use platform specific GetError to write to tracfile if tracing */ +static void Trace(int idx) +{ + if (TraceOn) { + char buffer[MAX_ERROR_LEN]; + GetError(idx, buffer); + fprintf(TraceFile, "\t%s\n", buffer); +#ifdef DEBUG_SNIFFER + fprintf(stderr, "\t%s\n", buffer); +#endif + } +} + + +/* Show TimeStamp for beginning of packet Trace */ +static void TraceHeader(void) +{ + if (TraceOn) { + time_t ticks = time(NULL); + fprintf(TraceFile, "\n%s", ctime(&ticks)); + } +} + + +/* Show Set Server info for Trace */ +static void TraceSetServer(const char* server, int port, const char* keyFile) +{ + if (TraceOn) { + fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n"); + fprintf(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", server, + port, keyFile); + } +} + + +/* Trace got packet number */ +static void TracePacket(void) +{ + if (TraceOn) { + static word32 packetNumber = 0; + fprintf(TraceFile, "\tGot a Packet to decode, packet %u\n", + ++packetNumber); + } +} + + +/* Convert network byte order address into human readable */ +static char* IpToS(word32 addr, char* str) +{ + byte* p = (byte*)&addr; + + SNPRINTF(str, TRACE_MSG_SZ, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + + return str; +} + + +/* Show destination and source address from Ip Hdr for packet Trace */ +static void TraceIP(IpHdr* iphdr) +{ + if (TraceOn) { + char src[TRACE_MSG_SZ]; + char dst[TRACE_MSG_SZ]; + fprintf(TraceFile, "\tdst:%s src:%s\n", IpToS(iphdr->dst, dst), + IpToS(iphdr->src, src)); + } +} + + +/* Show destination and source port from Tcp Hdr for packet Trace */ +static void TraceTcp(TcpHdr* tcphdr) +{ + if (TraceOn) { + fprintf(TraceFile, "\tdstPort:%u srcPort:%u\n", ntohs(tcphdr->dstPort), + ntohs(tcphdr->srcPort)); + } +} + + +/* Show sequence and payload length for Trace */ +static void TraceSequence(word32 seq, int len) +{ + if (TraceOn) { + fprintf(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len); + } +} + + +/* Show relative expected and relative received sequences */ +static void TraceRelativeSequence(word32 expected, word32 got) +{ + if (TraceOn) { + fprintf(TraceFile, "\tExpected sequence:%u, received sequence:%u\n", + expected, got); + } +} + + +/* Show server sequence startup from SYN */ +static void TraceServerSyn(word32 seq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq); + } +} + + +/* Show client sequence startup from SYN */ +static void TraceClientSyn(word32 seq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq); + } +} + + +/* Show client FIN capture */ +static void TraceClientFin(word32 finSeq, word32 relSeq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n", + finSeq, relSeq); + } +} + + +/* Show server FIN capture */ +static void TraceServerFin(word32 finSeq, word32 relSeq) +{ + if (TraceOn) { + fprintf(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n", + finSeq, relSeq); + } +} + + +/* Show number of SSL data bytes decoded, could be 0 (ok) */ +static void TraceGotData(int bytes) +{ + if (TraceOn) { + fprintf(TraceFile, "\t%d bytes of SSL App data processed\n", bytes); + } +} + + +/* Show bytes added to old SSL App data */ +static void TraceAddedData(int newBytes, int existingBytes) +{ + if (TraceOn) { + fprintf(TraceFile, + "\t%d bytes added to %d exisiting bytes in User Buffer\n", + newBytes, existingBytes); + } +} + + +/* Show Stale Session */ +static void TraceStaleSession(SnifferSession* session) +{ + if (TraceOn) { + fprintf(TraceFile, "\tFound a stale session\n"); + } +} + + +/* Show Finding Stale Sessions */ +static void TraceFindingStale() +{ + if (TraceOn) { + fprintf(TraceFile, "\tTrying to find Stale Sessions\n"); + } +} + + +/* Show Removed Session */ +static void TraceRemovedSession() +{ + if (TraceOn) { + fprintf(TraceFile, "\tRemoved it\n"); + } +} + + +/* Set user error string */ +static void SetError(int idx, char* error, SnifferSession* session, int fatal) +{ + GetError(idx, error); + Trace(idx); + if (session && fatal == FATAL_ERROR_STATE) + session->flags.fatalError = 1; +} + + +/* See if this IPV4 network order address has been registered */ +/* return 1 is true, 0 is false */ +static int IsServerRegistered(word32 addr) +{ + int ret = 0; /* false */ + SnifferServer* sniffer; + + LockMutex(&ServerListMutex); + + sniffer = ServerList; + while (sniffer) { + if (sniffer->server == addr) { + ret = 1; + break; + } + sniffer = sniffer->next; + } + + UnLockMutex(&ServerListMutex); + + return ret; +} + + +/* See if this port has been registered to watch */ +/* return 1 is true, 0 is false */ +static int IsPortRegistered(word32 port) +{ + int ret = 0; /* false */ + SnifferServer* sniffer; + + LockMutex(&ServerListMutex); + + sniffer = ServerList; + while (sniffer) { + if (sniffer->port == port) { + ret = 1; + break; + } + sniffer = sniffer->next; + } + + UnLockMutex(&ServerListMutex); + + return ret; +} + + +/* Get SnifferServer from IP and Port */ +static SnifferServer* GetSnifferServer(IpInfo* ipInfo, TcpInfo* tcpInfo) +{ + SnifferServer* sniffer; + + LockMutex(&ServerListMutex); + + sniffer = ServerList; + while (sniffer) { + if (sniffer->port == tcpInfo->srcPort && sniffer->server == ipInfo->src) + break; + if (sniffer->port == tcpInfo->dstPort && sniffer->server == ipInfo->dst) + break; + sniffer = sniffer->next; + } + + UnLockMutex(&ServerListMutex); + + return sniffer; +} + + +/* Hash the Session Info, return hash row */ +static word32 SessionHash(IpInfo* ipInfo, TcpInfo* tcpInfo) +{ + word32 hash = ipInfo->src * ipInfo->dst; + hash *= tcpInfo->srcPort * tcpInfo->dstPort; + + return hash % HASH_SIZE; +} + + +/* Get Exisiting SnifferSession from IP and Port */ +static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo) +{ + SnifferSession* session; + + word32 row = SessionHash(ipInfo, tcpInfo); + assert(row >= 0 && row <= HASH_SIZE); + + LockMutex(&SessionMutex); + + session = SessionTable[row]; + while (session) { + if (session->server == ipInfo->src && session->client == ipInfo->dst && + session->srvPort == tcpInfo->srcPort && + session->cliPort == tcpInfo->dstPort) + break; + if (session->client == ipInfo->src && session->server == ipInfo->dst && + session->cliPort == tcpInfo->srcPort && + session->srvPort == tcpInfo->dstPort) + break; + + session = session->next; + } + + UnLockMutex(&SessionMutex); + + /* determine side */ + if (session) { + if (ipInfo->dst == session->context->server && + tcpInfo->dstPort == session->context->port) + session->flags.side = SERVER_END; + else + session->flags.side = CLIENT_END; + } + + return session; +} + + +/* Sets the private key for a specific server and port */ +/* returns 0 on success, -1 on error */ +int ssl_SetPrivateKey(const char* serverAddress, int port, const char* keyFile, + int keyType, const char* password, char* error) +{ + int ret; + int type = (keyType == FILETYPE_PEM) ? SSL_FILETYPE_PEM : + SSL_FILETYPE_ASN1; + SnifferServer* sniffer; + + TraceHeader(); + TraceSetServer(serverAddress, port, keyFile); + + sniffer = (SnifferServer*)malloc(sizeof(SnifferServer)); + if (sniffer == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + return -1; + } + InitSnifferServer(sniffer); + + XSTRNCPY(sniffer->address, serverAddress, MAX_SERVER_ADDRESS); + sniffer->server = inet_addr(sniffer->address); + sniffer->port = port; + + /* start in client mode since SSL_new needs a cert for server */ + sniffer->ctx = SSL_CTX_new(SSLv3_client_method()); + if (!sniffer->ctx) { + SetError(MEMORY_STR, error, NULL, 0); + FreeSnifferServer(sniffer); + return -1; + } + + if (password){ + SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword); + SSL_CTX_set_default_passwd_cb_userdata(sniffer->ctx, (void*)password); + } + ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type); + if (ret != SSL_SUCCESS) { + SetError(KEY_FILE_STR, error, NULL, 0); + FreeSnifferServer(sniffer); + return -1; + } + Trace(NEW_SERVER_STR); + + LockMutex(&ServerListMutex); + + sniffer->next = ServerList; + ServerList = sniffer; + + UnLockMutex(&ServerListMutex); + + return 0; +} + + +/* Check IP Header for IPV4, TCP, and a registered server address */ +/* returns 0 on success, -1 on error */ +static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, char* error) +{ + int version = IP_V(iphdr); + + TraceIP(iphdr); + Trace(IP_CHECK_STR); + if (version != IPV4) { + SetError(BAD_IPVER_STR, error, NULL, 0); + return -1; + } + + if (iphdr->protocol != TCP_PROTOCOL) { + SetError(BAD_PROTO_STR, error, NULL, 0); + return -1; + } + + if (!IsServerRegistered(iphdr->src) && !IsServerRegistered(iphdr->dst)) { + SetError(SERVER_NOT_REG_STR, error, NULL, 0); + return -1; + } + + info->length = IP_HL(iphdr); + info->total = ntohs(iphdr->length); + info->src = iphdr->src; + info->dst = iphdr->dst; + + return 0; +} + + +/* Check TCP Header for a registered port */ +/* returns 0 on success, -1 on error */ +static int CheckTcpHdr(TcpHdr* tcphdr, TcpInfo* info, char* error) +{ + TraceTcp(tcphdr); + Trace(TCP_CHECK_STR); + info->srcPort = ntohs(tcphdr->srcPort); + info->dstPort = ntohs(tcphdr->dstPort); + info->length = TCP_LEN(tcphdr); + info->sequence = ntohl(tcphdr->sequence); + info->fin = tcphdr->flags & TCP_FIN; + info->rst = tcphdr->flags & TCP_RST; + info->syn = tcphdr->flags & TCP_SYN; + info->ack = tcphdr->flags & TCP_ACK; + + if (!IsPortRegistered(info->srcPort) && !IsPortRegistered(info->dstPort)) { + SetError(SERVER_PORT_NOT_REG_STR, error, NULL, 0); + return -1; + } + + return 0; +} + + +/* Decode Record Layer Header */ +static int GetRecordHeader(const byte* input, RecordLayerHeader* rh, int* size) +{ + XMEMCPY(rh, input, RECORD_HEADER_SZ); + *size = (rh->length[0] << 8) | rh->length[1]; + + if (*size > (RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) + return LENGTH_ERROR; + + return 0; +} + + +/* Process Client Key Exchange, RSA only */ +static int ProcessClientKeyExchange(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + word32 idx = 0; + RsaKey key; + int ret; + + InitRsaKey(&key, 0); + + ret = RsaPrivateKeyDecode(session->context->ctx->privateKey.buffer, + &idx, &key, session->context->ctx->privateKey.length); + if (ret == 0) { + int length = RsaEncryptSize(&key); + + if (IsTLS(session->sslServer)) + input += 2; /* tls pre length */ + + ret = RsaPrivateDecrypt(input, length, + session->sslServer->arrays.preMasterSecret, SECRET_LEN, &key); + + if (ret != SECRET_LEN) { + SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE); + FreeRsaKey(&key); + return -1; + } + ret = 0; /* not in error state */ + session->sslServer->arrays.preMasterSz = SECRET_LEN; + + /* store for client side as well */ + XMEMCPY(session->sslClient->arrays.preMasterSecret, + session->sslServer->arrays.preMasterSecret, SECRET_LEN); + session->sslClient->arrays.preMasterSz = SECRET_LEN; + + #ifdef SHOW_SECRETS + { + int i; + printf("pre master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", session->sslServer->arrays.preMasterSecret[i]); + printf("\n"); + } + #endif + } + else { + SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE); + FreeRsaKey(&key); + return -1; + } + + if (SetCipherSpecs(session->sslServer) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + FreeRsaKey(&key); + return -1; + } + + if (SetCipherSpecs(session->sslClient) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + FreeRsaKey(&key); + return -1; + } + + MakeMasterSecret(session->sslServer); + MakeMasterSecret(session->sslClient); +#ifdef SHOW_SECRETS + { + int i; + printf("server master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", session->sslServer->arrays.masterSecret[i]); + printf("\n"); + + printf("client master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", session->sslClient->arrays.masterSecret[i]); + printf("\n"); + + printf("server suite = %d\n", session->sslServer->options.cipherSuite); + printf("client suite = %d\n", session->sslClient->options.cipherSuite); + } +#endif + + FreeRsaKey(&key); + return ret; +} + + +/* Process Server Hello */ +static int ProcessServerHello(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + ProtocolVersion pv; + byte b; + int toRead = sizeof(ProtocolVersion) + RAN_LEN + ENUM_LEN; + + /* make sure we didn't miss ClientHello */ + if (session->flags.clientHello == 0) { + SetError(MISSED_CLIENT_HELLO_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + /* make sure can read through session len */ + if (toRead > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + XMEMCPY(&pv, input, sizeof(ProtocolVersion)); + input += sizeof(ProtocolVersion); + *sslBytes -= sizeof(ProtocolVersion); + + session->sslServer->version = pv; + session->sslClient->version = pv; + + XMEMCPY(session->sslServer->arrays.serverRandom, input, RAN_LEN); + XMEMCPY(session->sslClient->arrays.serverRandom, input, RAN_LEN); + input += RAN_LEN; + *sslBytes -= RAN_LEN; + + b = *input++; + *sslBytes -= 1; + + /* make sure can read through compression */ + if ( (b + SUITE_LEN + ENUM_LEN) > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + XMEMCPY(session->sslServer->arrays.sessionID, input, ID_LEN); + input += b; + *sslBytes -= b; + + (void)*input++; /* eat first byte, always 0 */ + b = *input++; + session->sslServer->options.cipherSuite = b; + session->sslClient->options.cipherSuite = b; + *sslBytes -= SUITE_LEN; + + if (XMEMCMP(session->sslServer->arrays.sessionID, + session->sslClient->arrays.sessionID, ID_LEN) == 0) { + /* resuming */ + SSL_SESSION* resume = GetSession(session->sslServer, + session->sslServer->arrays.masterSecret); + if (resume == NULL) { + SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + /* make sure client has master secret too */ + XMEMCPY(session->sslClient->arrays.masterSecret, + session->sslServer->arrays.masterSecret, SECRET_LEN); + session->flags.resuming = 1; + + Trace(SERVER_DID_RESUMPTION_STR); + if (SetCipherSpecs(session->sslServer) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (SetCipherSpecs(session->sslClient) != 0) { + SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (session->sslServer->options.tls) { + DeriveTlsKeys(session->sslServer); + DeriveTlsKeys(session->sslClient); + } + else { + DeriveKeys(session->sslServer); + DeriveKeys(session->sslClient); + } + } +#ifdef SHOW_SECRETS + { + int i; + printf("cipher suite = 0x%02x\n", + session->sslServer->options.cipherSuite); + printf("server random: "); + for (i = 0; i < RAN_LEN; i++) + printf("%02x", session->sslServer->arrays.serverRandom[i]); + printf("\n"); + } +#endif + return 0; +} + + +/* Process normal Client Hello */ +static int ProcessClientHello(const byte* input, int* sslBytes, + SnifferSession* session, char* error) +{ + byte sessionLen; + int toRead = sizeof(ProtocolVersion) + RAN_LEN + ENUM_LEN; + + session->flags.clientHello = 1; /* don't process again */ + + /* make sure can read up to session len */ + if (toRead > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + /* skip, get negotiated one from server hello */ + input += sizeof(ProtocolVersion); + *sslBytes -= sizeof(ProtocolVersion); + + XMEMCPY(session->sslServer->arrays.clientRandom, input, RAN_LEN); + XMEMCPY(session->sslClient->arrays.clientRandom, input, RAN_LEN); + + input += RAN_LEN; + *sslBytes -= RAN_LEN; + + /* store session in case trying to resume */ + sessionLen = *input++; + if (sessionLen) { + if (ID_LEN > *sslBytes) { + SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + Trace(CLIENT_RESUME_TRY_STR); + XMEMCPY(session->sslClient->arrays.sessionID, input, ID_LEN); + } +#ifdef SHOW_SECRETS + { + int i; + printf("client random: "); + for (i = 0; i < RAN_LEN; i++) + printf("%02x", session->sslServer->arrays.clientRandom[i]); + printf("\n"); + } +#endif + + return 0; +} + + +/* Process HandShake input */ +static int DoHandShake(const byte* input, int* sslBytes, IpInfo* ipInfo, + TcpInfo* tcpInfo, SnifferSession* session, char* error) +{ + byte type; + int size; + int ret = 0; + + if (*sslBytes < HANDSHAKE_HEADER_SZ) { + SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + type = input[0]; + size = (input[1] << 16) | (input[2] << 8) | input[3]; + + input += HANDSHAKE_HEADER_SZ; + *sslBytes -= HANDSHAKE_HEADER_SZ; + + if (*sslBytes < size) { + SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + switch (type) { + case hello_verify_request: + Trace(GOT_HELLO_VERIFY_STR); + break; + case server_hello: + Trace(GOT_SERVER_HELLO_STR); + ret = ProcessServerHello(input, sslBytes, session, error); + break; + case certificate_request: + Trace(GOT_CERT_REQ_STR); + break; + case server_key_exchange: + Trace(GOT_SERVER_KEY_EX_STR); + break; + case certificate: + Trace(GOT_CERT_STR); + break; + case server_hello_done: + Trace(GOT_SERVER_HELLO_DONE_STR); + break; + case finished: + Trace(GOT_FINISHED_STR); + { + SSL* ssl; + word32 inOutIdx = 0; + + if (session->flags.side == SERVER_END) + ssl = session->sslServer; + else + ssl = session->sslClient; + ret = DoFinished(ssl, input, &inOutIdx, SNIFF); + + if (ret == 0 && session->flags.cached == 0) { + AddSession(session->sslServer); + session->flags.cached = 1; + } + } + break; + case client_hello: + Trace(GOT_CLIENT_HELLO_STR); + ret = ProcessClientHello(input, sslBytes, session, error); + break; + case client_key_exchange: + Trace(GOT_CLIENT_KEY_EX_STR); + ret = ProcessClientKeyExchange(input, sslBytes, session, error); + break; + case certificate_verify: + Trace(GOT_CERT_VER_STR); + break; + default: + SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0); + return -1; + } + + return ret; +} + + +/* Decrypt input into plain output */ +static void Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz) +{ + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_ARC4 + case rc4: + Arc4Process(&ssl->decrypt.arc4, output, input, sz); + break; + #endif + + #ifdef BUILD_DES3 + case triple_des: + Des3_CbcDecrypt(&ssl->decrypt.des3, output, input, sz); + break; + #endif + + #ifdef BUILD_AES + case aes: + AesCbcDecrypt(&ssl->decrypt.aes, output, input, sz); + break; + #endif + + #ifdef BUILD_HC128 + case hc128: + Hc128_Process(&ssl->decrypt.hc128, output, input, sz); + break; + #endif + + #ifdef BUILD_RABBIT + case rabbit: + RabbitProcess(&ssl->decrypt.rabbit, output, input, sz); + break; + #endif + } +} + + +/* Decrypt input message into output, adjust output steam if needed */ +static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz, + byte* output) +{ + Decrypt(ssl, output, input, sz); + ssl->keys.encryptSz = sz; + if (ssl->options.tls1_1 && ssl->specs.cipher_type == block) + return output + ssl->specs.block_size; /* go past TLSv1.1 IV */ + + return output; +} + + +/* remove session from table, use rowHint if no info (means we have a lock) */ +static void RemoveSession(SnifferSession* session, IpInfo* ipInfo, + TcpInfo* tcpInfo, word32 rowHint) +{ + SnifferSession* previous = 0; + SnifferSession* current; + word32 row = rowHint; + int haveLock = 0; + + if (ipInfo && tcpInfo) + row = SessionHash(ipInfo, tcpInfo); + else + haveLock = 1; + + assert(row >= 0 && row <= HASH_SIZE); + Trace(REMOVE_SESSION_STR); + + if (!haveLock) + LockMutex(&SessionMutex); + + current = SessionTable[row]; + + while (current) { + if (current == session) { + if (previous) + previous->next = current->next; + else + SessionTable[row] = current->next; + FreeSnifferSession(session); + TraceRemovedSession(); + break; + } + previous = current; + current = current->next; + } + + if (!haveLock) + UnLockMutex(&SessionMutex); +} + + +/* Remove stale sessions from the Session Table, have a lock */ +static void RemoveStaleSessions() +{ + word32 i; + SnifferSession* session; + + for (i = 0; i < HASH_SIZE; i++) { + session = SessionTable[i]; + while (session) { + SnifferSession* next = session->next; + if (time(NULL) >= session->bornOn + SNIFFER_TIMEOUT) { + TraceStaleSession(session); + RemoveSession(session, NULL, NULL, i); + } + session = next; + } + } +} + + +/* Create a new Sniffer Session */ +static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo, + char* error) +{ + SnifferSession* session = 0; + int row; + + Trace(NEW_SESSION_STR); + /* create a new one */ + session = (SnifferSession*)malloc(sizeof(SnifferSession)); + if (session == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + return 0; + } + InitSession(session); + session->server = ipInfo->dst; + session->client = ipInfo->src; + session->srvPort = tcpInfo->dstPort; + session->cliPort = tcpInfo->srcPort; + session->cliSeqStart = tcpInfo->sequence; + session->cliExpected = 1; /* relative */ + session->bornOn = time(NULL); + + session->context = GetSnifferServer(ipInfo, tcpInfo); + if (session->context == NULL) { + SetError(SERVER_NOT_REG_STR, error, NULL, 0); + free(session); + return 0; + } + + session->sslServer = SSL_new(session->context->ctx); + session->sslClient = SSL_new(session->context->ctx); + if (session->sslClient == NULL) { + if (session->sslServer) { + SSL_free(session->sslClient); + session->sslClient = 0; + } + SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE); + free(session); + return 0; + } + /* put server back into server mode */ + session->sslServer->options.side = SERVER_END; + + row = SessionHash(ipInfo, tcpInfo); + + /* add it to the session table */ + LockMutex(&SessionMutex); + + session->next = SessionTable[row]; + SessionTable[row] = session; + + SessionCount++; + + if ( (SessionCount % HASH_SIZE) == 0) { + TraceFindingStale(); + RemoveStaleSessions(); + } + + UnLockMutex(&SessionMutex); + + /* determine headed side */ + if (ipInfo->dst == session->context->server && + tcpInfo->dstPort == session->context->port) + session->flags.side = SERVER_END; + else + session->flags.side = CLIENT_END; + + return session; +} + + +/* Process Old Client Hello Input */ +static int DoOldHello(SnifferSession* session, const byte* sslFrame, + int* rhSize, int* sslBytes, char* error) +{ + const byte* input = sslFrame; + byte b0, b1; + word32 idx = 0; + int ret; + + Trace(GOT_OLD_CLIENT_HELLO_STR); + session->flags.clientHello = 1; /* don't process again */ + b0 = *input++; + b1 = *input++; + *sslBytes -= 2; + *rhSize = ((b0 & 0x7f) << 8) | b1; + + if (*rhSize > *sslBytes) { + SetError(OLD_CLIENT_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + ret = ProcessOldClientHello(session->sslServer, input, &idx, *sslBytes, + *rhSize); + if (ret < 0) { + SetError(BAD_OLD_CLIENT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + Trace(OLD_CLIENT_OK_STR); + XMEMCPY(session->sslClient->arrays.clientRandom, + session->sslServer->arrays.clientRandom, RAN_LEN); + + *sslBytes -= *rhSize; + return 0; +} + + +/* Calculate the TCP checksum, see RFC 1071 */ +/* return 0 for success, -1 on error */ +/* can be called from decode() with + TcpChecksum(&ipInfo, &tcpInfo, sslBytes, packet + ipInfo.length); + could also add a 64bit version if type available and using this +*/ +int TcpChecksum(IpInfo* ipInfo, TcpInfo* tcpInfo, int dataLen, + const byte* packet) +{ + TcpPseudoHdr pseudo; + int count = PSEUDO_HDR_SZ; + const word16* data = (word16*)&pseudo; + word32 sum = 0; + word16 checksum; + + pseudo.src = ipInfo->src; + pseudo.dst = ipInfo->dst; + pseudo.rsv = 0; + pseudo.protocol = TCP_PROTO; + pseudo.legnth = htons(tcpInfo->length + dataLen); + + /* pseudo header sum */ + while (count >= 2) { + sum += *data++; + count -= 2; + } + + count = tcpInfo->length + dataLen; + data = (word16*)packet; + + /* main sum */ + while (count > 1) { + sum += *data++; + count -=2; + } + + /* get left-over, if any */ + packet = (byte*)data; + if (count > 0) { + sum += *packet; + } + + /* fold 32bit sum into 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + checksum = (word16)~sum; + /* checksum should now equal 0, since included already calcd checksum */ + /* field, but tcp checksum offloading could negate calculation */ + if (checksum == 0) + return 0; + return -1; +} + + +/* Check IP and TCP headers, set payload */ +/* returns 0 on success, -1 on error */ +int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet, + int length, const byte** sslFrame, int* sslBytes, char* error) +{ + TraceHeader(); + TracePacket(); + if (length < IP_HDR_SZ) { + SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); + return -1; + } + if (CheckIpHdr((IpHdr*)packet, ipInfo, error) != 0) + return -1; + + if (length < (ipInfo->length + TCP_HDR_SZ)) { + SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); + return -1; + } + if (CheckTcpHdr((TcpHdr*)(packet + ipInfo->length), tcpInfo, error) != 0) + return -1; + + *sslFrame = packet + ipInfo->length + tcpInfo->length; + if (*sslFrame > packet + length) { + SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); + return -1; + } + *sslBytes = packet + length - *sslFrame; + + return 0; +} + + +/* Create or Find existing session */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int CheckSession(IpInfo* ipInfo, TcpInfo* tcpInfo, int sslBytes, + SnifferSession** session, char* error) +{ + /* create a new SnifferSession on client SYN */ + if (tcpInfo->syn && !tcpInfo->ack) { + TraceClientSyn(tcpInfo->sequence); + *session = CreateSession(ipInfo, tcpInfo, error); + if (*session == NULL) { + *session = GetSnifferSession(ipInfo, tcpInfo); + /* already had exisiting, so OK */ + if (*session) + return 1; + + SetError(MEMORY_STR, error, NULL, 0); + return -1; + } + return 1; + } + /* get existing sniffer session */ + else { + *session = GetSnifferSession(ipInfo, tcpInfo); + if (*session == NULL) { + /* don't worry about extraneous RST or duplicate FINs */ + if (tcpInfo->fin || tcpInfo->rst) + return 1; + /* don't worry about duplicate ACKs either */ + if (sslBytes == 0 && tcpInfo->ack) + return 1; + + SetError(BAD_SESSION_STR, error, NULL, 0); + return -1; + } + } + return 0; +} + + +#ifndef min + +static INLINE word32 min(word32 a, word32 b) +{ + return a > b ? b : a; +} + +#endif + + +/* Create a Packet Buffer from *begin - end, adjust new *begin and bytesLeft */ +static PacketBuffer* CreateBuffer(word32* begin, word32 end, const byte* data, + int* bytesLeft) +{ + PacketBuffer* pb; + + int added = end - *begin + 1; + assert(*begin <= end); + + pb = (PacketBuffer*)malloc(sizeof(PacketBuffer)); + if (pb == NULL) return NULL; + + pb->next = 0; + pb->begin = *begin; + pb->end = end; + pb->data = (byte*)malloc(added); + + if (pb->data == NULL) { + free(pb); + return NULL; + } + XMEMCPY(pb->data, data, added); + + *bytesLeft -= added; + *begin = pb->end + 1; + + return pb; +} + + +/* Add sslFrame to Reassembly List */ +/* returns 1 (end) on success, -1, on error */ +static int AddToReassembly(byte from, word32 seq, const byte* sslFrame, + int sslBytes, SnifferSession* session, char* error) +{ + PacketBuffer* add; + PacketBuffer** front = (from == SERVER_END) ? &session->cliReassemblyList: + &session->srvReassemblyList; + PacketBuffer* curr = *front; + PacketBuffer* prev = curr; + + word32 startSeq = seq; + word32 added; + int bytesLeft = sslBytes; /* could be overlapping fragment */ + + /* if list is empty add full frame to front */ + if (!curr) { + add = CreateBuffer(&seq, seq + sslBytes - 1, sslFrame, &bytesLeft); + if (add == NULL) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + *front = add; + return 1; + } + + /* add to front if before current front, up to next->begin */ + if (seq < curr->begin) { + word32 end = seq + sslBytes - 1; + + if (end >= curr->begin) + end = curr->begin - 1; + + add = CreateBuffer(&seq, end, sslFrame, &bytesLeft); + if (add == NULL) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + add->next = curr; + *front = add; + } + + /* while we have bytes left, try to find a gap to fill */ + while (bytesLeft > 0) { + /* get previous packet in list */ + while (curr && (seq >= curr->begin)) { + prev = curr; + curr = curr->next; + } + + /* don't add duplicate data */ + if (prev->end >= seq) { + if ( (seq + bytesLeft - 1) <= prev->end) + return 1; + seq = prev->end + 1; + bytesLeft = startSeq + sslBytes - seq; + } + + if (!curr) + /* we're at the end */ + added = bytesLeft; + else + /* we're in between two frames */ + added = min((word32)bytesLeft, curr->begin - seq); + + /* data already there */ + if (added == 0) + continue; + + add = CreateBuffer(&seq, seq + added - 1, &sslFrame[seq - startSeq], + &bytesLeft); + if (add == NULL) { + SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + add->next = prev->next; + prev->next = add; + } + return 1; +} + + +/* Add out of order FIN capture */ +/* returns 1 for success (end) */ +static int AddFinCapture(SnifferSession* session, word32 sequence) +{ + if (session->flags.side == SERVER_END) { + if (session->finCaputre.cliCounted == 0) + session->finCaputre.cliFinSeq = sequence; + } + else { + if (session->finCaputre.srvCounted == 0) + session->finCaputre.srvFinSeq = sequence; + } + return 1; +} + + +/* Adjust incoming sequence based on side */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session, + int* sslBytes, const byte** sslFrame, char* error) +{ + word32 seqStart = (session->flags.side == SERVER_END) ? + session->cliSeqStart :session->srvSeqStart; + word32 real = tcpInfo->sequence - seqStart; + word32* expected = (session->flags.side == SERVER_END) ? + &session->cliExpected : &session->srvExpected; + PacketBuffer* reassemblyList = (session->flags.side == SERVER_END) ? + session->cliReassemblyList : session->srvReassemblyList; + + /* handle rollover of sequence */ + if (tcpInfo->sequence < seqStart) + real = 0xffffffffU - seqStart + tcpInfo->sequence; + + TraceRelativeSequence(*expected, real); + + if (real < *expected) { + Trace(DUPLICATE_STR); + if (real + *sslBytes > *expected) { + int overlap = *expected - real; + Trace(OVERLAP_DUPLICATE_STR); + + /* adjust to expected, remove duplicate */ + *sslFrame += overlap; + *sslBytes -= overlap; + + if (reassemblyList) { + word32 newEnd = *expected + *sslBytes; + + if (newEnd > reassemblyList->begin) { + Trace(OVERLAP_REASSEMBLY_BEGIN_STR); + + /* remove bytes already on reassembly list */ + *sslBytes -= newEnd - reassemblyList->begin; + } + if (newEnd > reassemblyList->end) { + Trace(OVERLAP_REASSEMBLY_END_STR); + + /* may be past reassembly list end (could have more on list) + so try to add what's past the front->end */ + AddToReassembly(session->flags.side, reassemblyList->end +1, + *sslFrame + reassemblyList->end - *expected + 1, + newEnd - reassemblyList->end, session, error); + } + } + } + else + return 1; + } + else if (real > *expected) { + Trace(OUT_OF_ORDER_STR); + if (*sslBytes > 0) + return AddToReassembly(session->flags.side, real, *sslFrame, + *sslBytes, session, error); + else if (tcpInfo->fin) + return AddFinCapture(session, real); + } + /* got expected sequence */ + *expected += *sslBytes; + if (tcpInfo->fin) + *expected += 1; + + return 0; +} + + +/* Check TCP Sequence status */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo, + SnifferSession* session, int* sslBytes, + const byte** sslFrame, char* error) +{ + int actualLen; + + /* init SEQ from server to client */ + if (tcpInfo->syn && tcpInfo->ack) { + session->srvSeqStart = tcpInfo->sequence; + session->srvExpected = 1; + TraceServerSyn(tcpInfo->sequence); + return 1; + } + + /* adjust potential ethernet trailer */ + actualLen = ipInfo->total - ipInfo->length - tcpInfo->length; + if (*sslBytes > actualLen) { + *sslBytes = actualLen; + } + + TraceSequence(tcpInfo->sequence, *sslBytes); + + return AdjustSequence(tcpInfo, session, sslBytes, sslFrame, error); +} + + +/* Check Status before record processing */ +/* returns 0 on success (continue), -1 on error, 1 on success (end) */ +static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo, + const byte** sslFrame, SnifferSession* session, + int* sslBytes, const byte** end, char* error) +{ + word32 length; + SSL* ssl = (session->flags.side == SERVER_END) ? session->sslServer : + session->sslClient; + /* remove SnifferSession on 2nd FIN or RST */ + if (tcpInfo->fin || tcpInfo->rst) { + /* flag FIN and RST */ + if (tcpInfo->fin) + session->flags.finCount += 1; + else if (tcpInfo->rst) + session->flags.finCount += 2; + + if (session->flags.finCount >= 2) { + RemoveSession(session, ipInfo, tcpInfo, 0); + return 1; + } + } + + if (session->flags.fatalError == FATAL_ERROR_STATE) { + SetError(FATAL_ERROR_STR, error, NULL, 0); + return -1; + } + + if (*sslBytes == 0) { + Trace(NO_DATA_STR); + return 1; + } + + /* if current partial data, add to end of partial */ + if ( (length = ssl->buffers.inputBuffer.length) ) { + Trace(PARTIAL_ADD_STR); + + if ( (*sslBytes + length) > ssl->buffers.inputBuffer.bufferSize) { + SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + XMEMCPY(&ssl->buffers.inputBuffer.buffer[length], *sslFrame, *sslBytes); + *sslBytes += length; + ssl->buffers.inputBuffer.length = *sslBytes; + *sslFrame = ssl->buffers.inputBuffer.buffer; + *end = *sslFrame + *sslBytes; + } + + if (session->flags.clientHello == 0 && **sslFrame != handshake) { + int rhSize; + int ret = DoOldHello(session, *sslFrame, &rhSize, sslBytes, error); + if (ret < 0) + return -1; /* error already set */ + if (*sslBytes <= 0) + return 1; + } + + return 0; +} + + +/* See if input on the reassembly list is ready for consuming */ +/* returns 1 for TRUE, 0 for FALSE */ +static int HaveMoreInput(SnifferSession* session, const byte** sslFrame, + int* sslBytes, const byte** end) +{ + /* sequence and reassembly based on from, not to */ + int moreInput = 0; + PacketBuffer** front = (session->flags.side == SERVER_END) ? + &session->cliReassemblyList : &session->srvReassemblyList; + word32* expected = (session->flags.side == SERVER_END) ? + &session->cliExpected : &session->srvExpected; + /* buffer is on receiving end */ + word32* length = (session->flags.side == SERVER_END) ? + &session->sslServer->buffers.inputBuffer.length : + &session->sslClient->buffers.inputBuffer.length; + byte* buffer = (session->flags.side == SERVER_END) ? + session->sslServer->buffers.inputBuffer.buffer : + session->sslClient->buffers.inputBuffer.buffer; + + while (*front && ((*front)->begin == *expected) ) { + word32 room = STATIC_BUFFER_LEN - *length; + word32 packetLen = (*front)->end - (*front)->begin + 1; + + if (packetLen <= room) { + PacketBuffer* remove = *front; + + XMEMCPY(&buffer[*length], (*front)->data, packetLen); + *length += packetLen; + *expected += packetLen; + + /* remove used packet */ + *front = (*front)->next; + FreePacketBuffer(remove); + + moreInput = 1; + } + else + break; + } + if (moreInput) { + *sslFrame = buffer; + *sslBytes = *length; + *end = buffer + *length; + } + return moreInput; +} + + + +/* Process Message(s) from sslFrame */ +/* return Number of bytes on success, 0 for no data yet, and -1 on error */ +static int ProcessMessage(IpInfo* ipInfo, TcpInfo* tcpInfo,const byte* sslFrame, + SnifferSession* session, int sslBytes, byte* data, + const byte* end, char* error) +{ + const byte* sslBegin = sslFrame; + const byte* tmp; + RecordLayerHeader rh; + int rhSize; + int ret; + int decoded = 0; /* bytes stored for user in data */ + int notEnough; /* notEnough bytes yet flag */ + SSL* ssl = (session->flags.side == SERVER_END) ? + session->sslServer : session->sslClient; +doMessage: + notEnough = 0; + if (sslBytes >= RECORD_HEADER_SZ) { + if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) { + SetError(BAD_RECORD_HDR_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + } + else + notEnough = 1; + + if (notEnough || rhSize > (sslBytes - RECORD_HEADER_SZ)) { + /* don't have enough input yet to process full SSL record */ + Trace(PARTIAL_INPUT_STR); + + /* store partial if not there already or we advanced */ + if (ssl->buffers.inputBuffer.length == 0 || sslBegin != sslFrame) { + if (sslBytes > ssl->buffers.inputBuffer.bufferSize) { + SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + XMEMCPY(ssl->buffers.inputBuffer.buffer, sslFrame, sslBytes); + ssl->buffers.inputBuffer.length = sslBytes; + } + if (HaveMoreInput(session, &sslFrame, &sslBytes, &end)) + goto doMessage; + return decoded; + } + sslFrame += RECORD_HEADER_SZ; + sslBytes -= RECORD_HEADER_SZ; + tmp = sslFrame + rhSize; /* may have more than one record to process */ + + /* decrypt if needed */ + if (session->flags.side == SERVER_END && session->flags.serverCipherOn) + sslFrame = DecryptMessage(ssl, sslFrame, rhSize, + ssl->buffers.outputBuffer.buffer); + else if (session->flags.side == CLIENT_END && session->flags.clientCipherOn) + sslFrame = DecryptMessage(ssl, sslFrame, rhSize, + ssl->buffers.outputBuffer.buffer); + + switch ((enum ContentType)rh.type) { + case handshake: + Trace(GOT_HANDSHAKE_STR); + ret = DoHandShake(sslFrame, &sslBytes, ipInfo, tcpInfo, session, + error); + if (ret != 0) { + if (session->flags.fatalError == 0) + SetError(BAD_HANDSHAKE_STR,error,session,FATAL_ERROR_STATE); + return -1; + } + break; + case change_cipher_spec: + if (session->flags.side == SERVER_END) + session->flags.serverCipherOn = 1; + else + session->flags.clientCipherOn = 1; + Trace(GOT_CHANGE_CIPHER_STR); + break; + case application_data: + Trace(GOT_APP_DATA_STR); + { + word32 inOutIdx = 0; + + ret = DoApplicationData(ssl, (byte*)sslFrame, &inOutIdx); + if (ret == 0) { + ret = ssl->buffers.clearOutputBuffer.length; + TraceGotData(ret); + if (ret) { /* may be blank message */ + XMEMCPY(&data[decoded], + ssl->buffers.clearOutputBuffer.buffer, ret); + TraceAddedData(ret, decoded); + decoded += ret; + ssl->buffers.clearOutputBuffer.length = 0; + } + } + else { + SetError(BAD_APP_DATA_STR, error,session,FATAL_ERROR_STATE); + return -1; + } + } + break; + case alert: + Trace(GOT_ALERT_STR); + break; + default: + SetError(GOT_UNKNOWN_RECORD_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + if (tmp < end) { + Trace(ANOTHER_MSG_STR); + sslFrame = tmp; + sslBytes = end - tmp; + goto doMessage; + } + + /* clear used input */ + ssl->buffers.inputBuffer.length = 0; + + /* could have more input ready now */ + if (HaveMoreInput(session, &sslFrame, &sslBytes, &end)) + goto doMessage; + + return decoded; +} + + +/* See if we need to process any pending FIN captures */ +static void CheckFinCapture(IpInfo* ipInfo, TcpInfo* tcpInfo, + SnifferSession* session) +{ + if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <= + session->cliExpected) { + if (session->finCaputre.cliCounted == 0) { + session->flags.finCount += 1; + session->finCaputre.cliCounted = 1; + TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected); + } + } + + if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <= + session->srvExpected) { + if (session->finCaputre.srvCounted == 0) { + session->flags.finCount += 1; + session->finCaputre.srvCounted = 1; + TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected); + } + } + + if (session->flags.finCount >= 2) + RemoveSession(session, ipInfo, tcpInfo, 0); +} + + +/* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */ +/* returns Number of bytes on success, 0 for no data yet, and -1 on error */ +int ssl_DecodePacket(const byte* packet, int length, byte* data, char* error) +{ + TcpInfo tcpInfo; + IpInfo ipInfo; + const byte* sslFrame; + const byte* end = packet + length; + int sslBytes; /* ssl bytes unconsumed */ + int ret; + SnifferSession* session = 0; + + if (CheckHeaders(&ipInfo, &tcpInfo, packet, length, &sslFrame, &sslBytes, + error) != 0) + return -1; + + ret = CheckSession(&ipInfo, &tcpInfo, sslBytes, &session, error); + if (ret == -1) return -1; + else if (ret == 1) return 0; /* done for now */ + + ret = CheckSequence(&ipInfo, &tcpInfo, session, &sslBytes, &sslFrame,error); + if (ret == -1) return -1; + else if (ret == 1) return 0; /* done for now */ + + ret = CheckPreRecord(&ipInfo, &tcpInfo, &sslFrame, session, &sslBytes, + &end, error); + if (ret == -1) return -1; + else if (ret == 1) return 0; /* done for now */ + + ret = ProcessMessage(&ipInfo, &tcpInfo, sslFrame, session, sslBytes, data, + end, error); + CheckFinCapture(&ipInfo, &tcpInfo, session); + return ret; +} + + +/* Enables (if traceFile)/ Disables debug tracing */ +/* returns 0 on success, -1 on error */ +int ssl_Trace(const char* traceFile, char* error) +{ + if (traceFile) { + TraceFile = fopen(traceFile, "a"); + if (!TraceFile) { + SetError(BAD_TRACE_FILE_STR, error, NULL, 0); + return -1; + } + TraceOn = 1; + } + else + TraceOn = 0; + + return 0; +} + + + + +#endif /* CYASSL_SNIFFER */ diff --git a/release/src/router/cyassl/src/ssl.c b/release/src/router/cyassl/src/ssl.c new file mode 100644 index 00000000..68be3614 --- /dev/null +++ b/release/src/router/cyassl/src/ssl.c @@ -0,0 +1,3496 @@ +/* ssl.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "ssl.h" +#include "cyassl_int.h" +#include "cyassl_error.h" +#include "coding.h" + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + #include "evp.h" +#endif + +#ifdef OPENSSL_EXTRA + /* openssl headers begin */ + #include "hmac.h" + #include "crypto.h" + #include "des.h" + /* openssl headers end, cyassl internal headers next */ + #include "ctc_hmac.h" + #include "random.h" + #include "des3.h" + #include "ctc_md4.h" + #include "coding.h" +#endif + +#ifdef HAVE_ERRNO_H + #include <errno.h> +#endif + +#define TRUE 1 +#define FALSE 0 + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + + +SSL_CTX* SSL_CTX_new(SSL_METHOD* method) +{ + SSL_CTX* ctx = (SSL_CTX*) XMALLOC(sizeof(SSL_CTX), 0, DYNAMIC_TYPE_CTX); + if (ctx) + InitSSL_Ctx(ctx, method); + + return ctx; +} + + +void SSL_CTX_free(SSL_CTX* ctx) +{ + if (ctx) + FreeSSL_Ctx(ctx); +} + + +SSL* SSL_new(SSL_CTX* ctx) +{ + + SSL* ssl = (SSL*) XMALLOC(sizeof(SSL), ctx->heap, DYNAMIC_TYPE_SSL); + if (ssl) + if (InitSSL(ssl, ctx) < 0) { + FreeSSL(ssl); + ssl = 0; + } + + return ssl; +} + + +void SSL_free(SSL* ssl) +{ + CYASSL_ENTER("SSL_free"); + if (ssl) + FreeSSL(ssl); + CYASSL_LEAVE("SSL_free", 0); +} + + +int SSL_set_fd(SSL* ssl, int fd) +{ + ssl->rfd = fd; /* not used directly to allow IO callbacks */ + ssl->wfd = fd; + + ssl->IOCB_ReadCtx = &ssl->rfd; + ssl->IOCB_WriteCtx = &ssl->wfd; + + return SSL_SUCCESS; +} + + +int SSL_get_fd(const SSL* ssl) +{ + return ssl->rfd; +} + + +int CyaSSL_negotiate(SSL* ssl) +{ + int err = -1; + +#ifndef NO_CYASSL_SERVER + if (ssl->options.side == SERVER_END) + err = SSL_accept(ssl); +#endif + +#ifndef NO_CYASSL_CLIENT + if (ssl->options.side == CLIENT_END) + err = SSL_connect(ssl); +#endif + + if (err == SSL_SUCCESS) + return 0; + else + return err; +} + + +int SSL_write(SSL* ssl, const void* buffer, int sz) +{ + int ret; + + CYASSL_ENTER("SSL_write()"); + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + + ret = SendData(ssl, buffer, sz); + + CYASSL_LEAVE("SSL_write()", ret); + + if (ret < 0) + return SSL_FATAL_ERROR; + else + return ret; +} + + +int SSL_read(SSL* ssl, void* buffer, int sz) +{ + int ret; + + CYASSL_ENTER("SSL_read()"); + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + + ret = ReceiveData(ssl, (byte*)buffer, min(sz, OUTPUT_RECORD_SIZE)); + + CYASSL_LEAVE("SSL_read()", ret); + + if (ret < 0) + return SSL_FATAL_ERROR; + else + return ret; +} + + +int SSL_shutdown(SSL* ssl) +{ + CYASSL_ENTER("SSL_shutdown()"); + + if (ssl->options.quietShutdown) { + CYASSL_MSG("quiet shutdown, no close notify sent"); + return 0; + } + + /* try to send close notify, not an error if can't */ + if (!ssl->options.isClosed && !ssl->options.connReset && + !ssl->options.sentNotify) { + ssl->error = SendAlert(ssl, alert_warning, close_notify); + if (ssl->error < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.sentNotify = 1; /* don't send close_notify twice */ + } + + CYASSL_LEAVE("SSL_shutdown()", ssl->error); + + ssl->error = SSL_ERROR_SYSCALL; /* simulate OpenSSL behavior */ + + return 0; +} + + +int SSL_get_error(SSL* ssl, int dummy) +{ + if (ssl->error == WANT_READ) + return SSL_ERROR_WANT_READ; /* convert to OpenSSL type */ + else if (ssl->error == WANT_WRITE) + return SSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ + else if (ssl->error == ZERO_RETURN) + return SSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ + return ssl->error; +} + + +int SSL_want_read(SSL* ssl) +{ + if (ssl->error == WANT_READ) + return 1; + + return 0; +} + + +int SSL_want_write(SSL* ssl) +{ + if (ssl->error == WANT_WRITE) + return 1; + + return 0; +} + + +char* ERR_error_string(unsigned long errNumber, char* buffer) +{ + static char* msg = "Please supply a buffer for error string"; + + if (buffer) { + SetErrorString(errNumber, buffer); + return buffer; + } + + return msg; +} + + +void ERR_error_string_n(unsigned long e, char* buf, size_t len) +{ + if (len) ERR_error_string(e, buf); +} + + +#ifndef NO_FILESYSTEM + +void ERR_print_errors_fp(FILE* fp, int err) +{ + char buffer[MAX_ERROR_SZ + 1]; + + SetErrorString(err, buffer); + fprintf(fp, "%s", buffer); +} + +#endif + + +int SSL_pending(SSL* ssl) +{ + return ssl->buffers.clearOutputBuffer.length; +} + + +/* owns der */ +static int AddCA(SSL_CTX* ctx, buffer der) +{ + word32 ret; + DecodedCert cert; + Signer* signer = 0; + + InitDecodedCert(&cert, der.buffer, ctx->heap); + ret = ParseCert(&cert, der.length, CA_TYPE, ctx->verifyPeer, 0); + + if (ret == 0) { + /* take over signer parts */ + signer = MakeSigner(ctx->heap); + if (!signer) + ret = MEMORY_ERROR; + else { + signer->keyOID = cert.keyOID; + signer->publicKey = cert.publicKey; + signer->pubKeySize = cert.pubKeySize; + signer->name = cert.subjectCN; + XMEMCPY(signer->hash, cert.subjectHash, SHA_DIGEST_SIZE); + + cert.publicKey = 0; /* don't free here */ + cert.subjectCN = 0; + + signer->next = ctx->caList; + ctx->caList = signer; /* takes ownership */ + } + } + + FreeDecodedCert(&cert); + XFREE(der.buffer, ctx->heap, DYNAMIC_TYPE_CA); + + if (ret == 0) return SSL_SUCCESS; + return ret; +} + + +#ifndef NO_SESSION_CACHE + + /* basic config gives a cache with 33 sessions, adequate for clients and + embedded servers + + BIG_SESSION_CACHE allows 1055 sessions, adequate for servers that aren't + under heavy load, basically allows 200 new sessions per minute + + HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load, + allows over 13,000 new sessions per minute or over 200 new sessions per + second + */ + #ifdef HUGE_SESSION_CACHE + #define SESSIONS_PER_ROW 11 + #define SESSION_ROWS 5981 + #elif defined(BIG_SESSION_CACHE) + #define SESSIONS_PER_ROW 5 + #define SESSION_ROWS 211 + #else + #define SESSIONS_PER_ROW 3 + #define SESSION_ROWS 11 + #endif + + typedef struct SessionRow { + int nextIdx; /* where to place next one */ + int totalCount; /* sessions ever on this row */ + SSL_SESSION Sessions[SESSIONS_PER_ROW]; + } SessionRow; + + static SessionRow SessionCache[SESSION_ROWS]; + + static CyaSSL_Mutex mutex; /* SessionCache mutex */ + +#endif /* NO_SESSION_CACHE */ + + + static int PemToDer(const unsigned char* buff, long sz, int type, + buffer* der, void* heap, EncryptedInfo* info, int* eccKey) + { + char header[PEM_LINE_LEN]; + char footer[PEM_LINE_LEN]; + char* headerEnd; + char* footerEnd; + long neededSz; + int pkcs8 = 0; + int dynamicType; + + if (type == CERT_TYPE || type == CA_TYPE) { + XSTRNCPY(header, "-----BEGIN CERTIFICATE-----", sizeof(header)); + XSTRNCPY(footer, "-----END CERTIFICATE-----", sizeof(footer)); + dynamicType = (type == CA_TYPE) ? DYNAMIC_TYPE_CA : + DYNAMIC_TYPE_CERT; + } else { + XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----", sizeof(header)); + XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----", sizeof(footer)); + dynamicType = DYNAMIC_TYPE_KEY; + } + + /* find header */ + headerEnd = XSTRSTR((char*)buff, header); + if (!headerEnd && type == PRIVATEKEY_TYPE) { /* may be pkcs8 */ + XSTRNCPY(header, "-----BEGIN PRIVATE KEY-----", sizeof(header)); + XSTRNCPY(footer, "-----END PRIVATE KEY-----", sizeof(footer)); + + headerEnd = XSTRSTR((char*)buff, header); + if (headerEnd) + pkcs8 = 1; + /* + else + maybe encrypted "-----BEGIN ENCRYPTED PRIVATE KEY-----" + */ + } + if (!headerEnd && type == PRIVATEKEY_TYPE) { /* may be ecc */ + XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----", sizeof(header)); + XSTRNCPY(footer, "-----END EC PRIVATE KEY-----", sizeof(footer)); + + headerEnd = XSTRSTR((char*)buff, header); + if (headerEnd) + *eccKey = 1; + } + if (!headerEnd) + return SSL_BAD_FILE; + headerEnd += XSTRLEN(header); + + /* get next line */ + if (headerEnd[0] == '\n') + headerEnd++; + else if (headerEnd[1] == '\n') + headerEnd += 2; + else + return SSL_BAD_FILE; + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + { + /* remove encrypted header if there */ + char encHeader[] = "Proc-Type"; + char* line = XSTRSTR((char*)buff, encHeader); + if (line) { + char* newline; + char* finish; + char* start = XSTRSTR(line, "DES"); + + if (!start) + start = XSTRSTR(line, "AES"); + + if (!start) return SSL_BAD_FILE; + if (!info) return SSL_BAD_FILE; + + finish = XSTRSTR(start, ","); + + if (start && finish && (start < finish)) { + newline = XSTRSTR(finish, "\r"); + + XMEMCPY(info->name, start, finish - start); + info->name[finish - start] = 0; + XMEMCPY(info->iv, finish + 1, sizeof(info->iv)); + + if (!newline) newline = XSTRSTR(finish, "\n"); + if (newline && (newline > finish)) { + info->ivSz = (word32)(newline - (finish + 1)); + info->set = 1; + } + else + return SSL_BAD_FILE; + } + else + return SSL_BAD_FILE; + + /* eat blank line */ + while (*newline == '\r' || *newline == '\n') + newline++; + headerEnd = newline; + } + } +#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ + + /* find footer */ + footerEnd = XSTRSTR((char*)buff, footer); + if (!footerEnd) return SSL_BAD_FILE; + + /* set up der buffer */ + neededSz = (long)(footerEnd - headerEnd); + if (neededSz > sz || neededSz < 0) return SSL_BAD_FILE; + der->buffer = (byte*) XMALLOC(neededSz, heap, dynamicType); + if (!der->buffer) return MEMORY_ERROR; + der->length = neededSz; + + if (Base64Decode((byte*)headerEnd, neededSz, der->buffer, + &der->length) < 0) + return SSL_BAD_FILE; + + if (pkcs8) + return ToTraditional(der->buffer, der->length); + + /* not full support yet + if (pkcs8Enc) + return ToTraditionalEnc(der->buffer, der->length); + */ + + return 0; + } + + + static int ProcessBuffer(SSL_CTX* ctx, const unsigned char* buff, + long sz, int format, int type) + { + EncryptedInfo info; + buffer der; /* holds DER or RAW (for NTRU) */ + int dynamicType; + int eccKey = 0; + + info.set = 0; + der.buffer = 0; + + if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM + && format != SSL_FILETYPE_RAW) + return SSL_BAD_FILETYPE; + + if (type == CA_TYPE) + dynamicType = DYNAMIC_TYPE_CA; + else if (type == CERT_TYPE) + dynamicType = DYNAMIC_TYPE_CERT; + else + dynamicType = DYNAMIC_TYPE_KEY; + + if (format == SSL_FILETYPE_PEM) { + if (PemToDer(buff, sz, type, &der, ctx->heap, &info, &eccKey) < 0) { + XFREE(der.buffer, ctx->heap, dynamicType); + return SSL_BAD_FILE; + } + } + else { /* ASN1 (DER) or RAW (NTRU) */ + der.buffer = (byte*) XMALLOC(sz, ctx->heap, dynamicType); + if (!der.buffer) return MEMORY_ERROR; + XMEMCPY(der.buffer, buff, sz); + der.length = sz; + } + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + if (info.set) { + /* decrypt */ + char password[80]; + int passwordSz; + + byte key[AES_256_KEY_SIZE]; + byte iv[AES_IV_SIZE]; + + if (!ctx->passwd_cb) return -1; + + /* use file's salt for key derivation, hex decode first */ + if (Base16Decode(info.iv, info.ivSz, info.iv, &info.ivSz) != 0) + return -1; + + passwordSz = ctx->passwd_cb(password, sizeof(password), 0, + ctx->userdata); + if (EVP_BytesToKey(info.name, "MD5", info.iv, (byte*)password, + passwordSz, 1, key, iv) <= 0) + return -1; + + if (XSTRNCMP(info.name, "DES-CBC", 7) == 0) { + Des des; + Des_SetKey(&des, key, info.iv, DES_DECRYPTION); + Des_CbcDecrypt(&des, der.buffer, der.buffer, der.length); + } + else if (XSTRNCMP(info.name, "DES-EDE3-CBC", 13) == 0) { + Des3 des; + Des3_SetKey(&des, key, info.iv, DES_DECRYPTION); + Des3_CbcDecrypt(&des, der.buffer, der.buffer, der.length); + } + else if (XSTRNCMP(info.name, "AES-128-CBC", 13) == 0) { + Aes aes; + AesSetKey(&aes, key, AES_128_KEY_SIZE, info.iv, AES_DECRYPTION); + AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length); + } + else if (XSTRNCMP(info.name, "AES-192-CBC", 13) == 0) { + Aes aes; + AesSetKey(&aes, key, AES_192_KEY_SIZE, info.iv, AES_DECRYPTION); + AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length); + } + else if (XSTRNCMP(info.name, "AES-256-CBC", 13) == 0) { + Aes aes; + AesSetKey(&aes, key, AES_256_KEY_SIZE, info.iv, AES_DECRYPTION); + AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length); + } + else + return SSL_BAD_FILE; + } +#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ + + if (type == CA_TYPE) + return AddCA(ctx, der); /* takes der over */ + else if (type == CERT_TYPE) { + if (ctx->certificate.buffer) + XFREE(ctx->certificate.buffer, ctx->heap, dynamicType); + ctx->certificate = der; /* takes der over */ + } + else if (type == PRIVATEKEY_TYPE) { + if (ctx->privateKey.buffer) + XFREE(ctx->privateKey.buffer, ctx->heap, dynamicType); + ctx->privateKey = der; /* takes der over */ + } + else { + XFREE(der.buffer, ctx->heap, dynamicType); + return SSL_BAD_CERTTYPE; + } + + if (type == PRIVATEKEY_TYPE && format != SSL_FILETYPE_RAW) { + if (!eccKey) { + /* make sure RSA key can be used */ + RsaKey key; + word32 idx = 0; + + InitRsaKey(&key, 0); + if (RsaPrivateKeyDecode(der.buffer,&idx,&key,der.length) != 0) { +#ifdef HAVE_ECC + /* could have DER ECC, no easy way to tell */ + if (format == SSL_FILETYPE_ASN1) + eccKey = 1; /* try it out */ +#endif + if (!eccKey) { + FreeRsaKey(&key); + return SSL_BAD_FILE; + } + } + FreeRsaKey(&key); + } +#ifdef HAVE_ECC + if (eccKey ) { + /* make sure ECC key can be used */ + word32 idx = 0; + ecc_key key; + + ecc_init(&key); + if (EccPrivateKeyDecode(der.buffer,&idx,&key,der.length) != 0) { + ecc_free(&key); + return SSL_BAD_FILE; + } + ecc_free(&key); + ctx->haveECDSA = 1; + } +#endif /* HAVE_ECC */ + } + + return SSL_SUCCESS; + } + + +#ifndef NO_FILESYSTEM + +#ifndef MICRIUM + #define XFILE FILE + #define XFOPEN fopen + #define XFSEEK fseek + #define XFTELL ftell + #define XREWIND rewind + #define XFREAD fread + #define XFCLOSE fclose + #define XSEEK_END SEEK_END +#else + #include <fs.h> + #define XFILE FS_FILE + #define XFOPEN fs_fopen + #define XFSEEK fs_fseek + #define XFTELL fs_ftell + #define XREWIND fs_rewind + #define XFREAD fs_fread + #define XFCLOSE fs_fclose + #define XSEEK_END FS_SEEK_END +#endif + +static int ProcessFile(SSL_CTX* ctx, const char* fname, int format, int type) +{ + byte staticBuffer[FILE_BUFFER_SIZE]; + byte* buffer = staticBuffer; + int dynamic = 0; + int ret; + long sz = 0; + XFILE* file = XFOPEN(fname, "rb"); + + if (!file) return SSL_BAD_FILE; + XFSEEK(file, 0, XSEEK_END); + sz = XFTELL(file); + XREWIND(file); + + if (sz > sizeof(staticBuffer)) { + buffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE); + if (buffer == NULL) { + XFCLOSE(file); + return SSL_BAD_FILE; + } + dynamic = 1; + } + + if ( (ret = XFREAD(buffer, sz, 1, file)) < 0) + ret = SSL_BAD_FILE; + else + ret = ProcessBuffer(ctx, buffer, sz, format, type); + + XFCLOSE(file); + if (dynamic) XFREE(buffer, ctx->heap, DYNAMIC_TYPE_FILE); + + return ret; +} + + +/* just one for now TODO: add dir support from path */ +int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, + const char* path) +{ + if (ProcessFile(ctx, file, SSL_FILETYPE_PEM, CA_TYPE) == SSL_SUCCESS) + return SSL_SUCCESS; + + return SSL_FAILURE; +} + + +#ifdef CYASSL_DER_LOAD + +/* Add format parameter to allow DER load of CA files */ +int CyaSSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, int format) +{ + if (ProcessFile(ctx, file, format, CA_TYPE) == SSL_SUCCESS) + return SSL_SUCCESS; + + return SSL_FAILURE; +} + +#endif /* CYASSL_DER_LOAD */ + + +#ifdef CYASSL_CERT_GEN + +/* load pem cert from file into der buffer, return der size or error */ +int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz) +{ + byte staticBuffer[FILE_BUFFER_SIZE]; + byte* fileBuf = staticBuffer; + int dynamic = 0; + int ret; + int ecc = 0; + long sz = 0; + XFILE* file = XFOPEN(fileName, "rb"); + EncryptedInfo info; + buffer converted; + + converted.buffer = 0; + + if (!file) return SSL_BAD_FILE; + XFSEEK(file, 0, XSEEK_END); + sz = XFTELL(file); + XREWIND(file); + + if (sz > sizeof(staticBuffer)) { + fileBuf = (byte*) XMALLOC(sz, 0, DYNAMIC_TYPE_FILE); + if (fileBuf == NULL) { + XFCLOSE(file); + return SSL_BAD_FILE; + } + dynamic = 1; + } + + if ( (ret = XFREAD(fileBuf, sz, 1, file)) < 0) + ret = SSL_BAD_FILE; + else + ret = PemToDer(fileBuf, sz, CA_TYPE, &converted, 0, &info, &ecc); + + if (ret == 0) { + if (converted.length < derSz) { + memcpy(derBuf, converted.buffer, converted.length); + ret = converted.length; + } + else + ret = BUFFER_E; + } + + XFREE(converted.buffer, 0, DYNAMIC_TYPE_CA); + if (dynamic) + XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE); + XFCLOSE(file); + + return ret; +} + +#endif /* CYASSL_CERT_GEN */ + + +int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int format) +{ + if (ProcessFile(ctx, file, format, CERT_TYPE) == SSL_SUCCESS) + return SSL_SUCCESS; + + return SSL_FAILURE; +} + + +int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int format) +{ + if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE) == SSL_SUCCESS) + return SSL_SUCCESS; + + return SSL_FAILURE; +} + + +int SSL_CTX_use_certificate_chain_file(SSL_CTX* ctx, const char* file) +{ + /* add first to ctx, all tested implementations support this */ + if (ProcessFile(ctx, file, SSL_FILETYPE_PEM, CERT_TYPE) == SSL_SUCCESS) + return SSL_SUCCESS; + + return SSL_FAILURE; +} + + +#ifdef HAVE_NTRU + +int CyaSSL_CTX_use_NTRUPrivateKey_file(SSL_CTX* ctx, const char* file) +{ + if (ProcessFile(ctx, file, SSL_FILETYPE_RAW, PRIVATEKEY_TYPE) + == SSL_SUCCESS) { + ctx->haveNTRU = 1; + return SSL_SUCCESS; + } + + return SSL_FAILURE; +} + +#endif /* HAVE_NTRU */ + + + +#ifdef OPENSSL_EXTRA + + int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX* ctx,const char* file,int format) + { + if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE) == SSL_SUCCESS) + return SSL_SUCCESS; + + return SSL_FAILURE; + } + +#endif /* OPENSSL_EXTRA */ + +#endif /* NO_FILESYSTEM */ + + +void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, VerifyCallback vc) +{ + if (mode & SSL_VERIFY_PEER) { + ctx->verifyPeer = 1; + ctx->verifyNone = 0; /* in case perviously set */ + } + + if (mode == SSL_VERIFY_NONE) { + ctx->verifyNone = 1; + ctx->verifyPeer = 0; /* in case previously set */ + } + + if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + ctx->failNoCert = 1; + + ctx->verifyCallback = vc; +} + + +#ifndef NO_SESSION_CACHE + +SSL_SESSION* SSL_get_session(SSL* ssl) +{ + return GetSession(ssl, 0); +} + + +int SSL_set_session(SSL* ssl, SSL_SESSION* session) +{ + if (session) + return SetSession(ssl, session); + + return SSL_FAILURE; +} + +#endif /* NO_SESSION_CACHE */ + + +void SSL_load_error_strings(void) /* compatibility only */ +{} + + +int SSL_library_init(void) +{ + if (InitCyaSSL() == 0) + return SSL_SUCCESS; + else + return -1; +} + + +#ifndef NO_SESSION_CACHE + +/* on by default if built in but allow user to turn off */ +long SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long mode) +{ + if (mode == SSL_SESS_CACHE_OFF) + ctx->sessionCacheOff = 1; + + if (mode == SSL_SESS_CACHE_NO_AUTO_CLEAR) + ctx->sessionCacheFlushOff = 1; + + return SSL_SUCCESS; +} + +#endif /* NO_SESSION_CACHE */ + + +int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list) +{ + if (SetCipherList(ctx, list)) + return SSL_SUCCESS; + else + return SSL_FAILURE; +} + + +/* client only parts */ +#ifndef NO_CYASSL_CLIENT + + SSL_METHOD* SSLv3_client_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) + InitSSL_Method(method, MakeSSLv3()); + return method; + } + + #ifdef CYASSL_DTLS + SSL_METHOD* DTLSv1_client_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) + InitSSL_Method(method, MakeDTLSv1()); + return method; + } + #endif + + + /* please see note at top of README if you get an error from connect */ + int SSL_connect(SSL* ssl) + { + int neededState; + + CYASSL_ENTER("SSL_connect()"); + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + if (ssl->options.side != CLIENT_END) { + CYASSL_ERROR(ssl->error = SIDE_ERROR); + return SSL_FATAL_ERROR; + } + + #ifdef CYASSL_DTLS + if (ssl->version.major == DTLS_MAJOR && + ssl->version.minor == DTLS_MINOR) { + ssl->options.dtls = 1; + ssl->options.tls = 1; + ssl->options.tls1_1 = 1; + } + #endif + + if (ssl->buffers.outputBuffer.length > 0) { + if ( (ssl->error = SendBuffered(ssl)) == 0) { + ssl->options.connectState++; + CYASSL_MSG("connect state: Advanced from buffered send"); + } + else { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + + switch (ssl->options.connectState) { + + case CONNECT_BEGIN : + /* always send client hello first */ + if ( (ssl->error = SendClientHello(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.connectState = CLIENT_HELLO_SENT; + CYASSL_MSG("connect state: CLIENT_HELLO_SENT"); + + case CLIENT_HELLO_SENT : + neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : + SERVER_HELLODONE_COMPLETE; + #ifdef CYASSL_DTLS + if (ssl->options.dtls && !ssl->options.resuming) + neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + #endif + /* get response */ + while (ssl->options.serverState < neededState) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + /* if resumption failed, reset needed state */ + else if (neededState == SERVER_FINISHED_COMPLETE) + if (!ssl->options.resuming) { + if (!ssl->options.dtls) + neededState = SERVER_HELLODONE_COMPLETE; + else + neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE; + } + } + + ssl->options.connectState = HELLO_AGAIN; + CYASSL_MSG("connect state: HELLO_AGAIN"); + + case HELLO_AGAIN : + #ifdef CYASSL_DTLS + if (ssl->options.dtls && !ssl->options.resuming) { + /* re-init hashes, exclude first hello and verify request */ + InitMd5(&ssl->hashMd5); + InitSha(&ssl->hashSha); + #ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + InitSha256(&ssl->hashSha256); + #endif + if ( (ssl->error = SendClientHello(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + #endif + + ssl->options.connectState = HELLO_AGAIN_REPLY; + CYASSL_MSG("connect state: HELLO_AGAIN_REPLY"); + + case HELLO_AGAIN_REPLY : + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + neededState = ssl->options.resuming ? + SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE; + + /* get response */ + while (ssl->options.serverState < neededState) { + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + /* if resumption failed, reset needed state */ + else if (neededState == SERVER_FINISHED_COMPLETE) + if (!ssl->options.resuming) + neededState = SERVER_HELLODONE_COMPLETE; + } + } + #endif + + ssl->options.connectState = FIRST_REPLY_DONE; + CYASSL_MSG("connect state: FIRST_REPLY_DONE"); + + case FIRST_REPLY_DONE : + if (ssl->options.sendVerify) + if ( (ssl->error = SendCertificate(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.connectState = FIRST_REPLY_FIRST; + CYASSL_MSG("connect state: FIRST_REPLY_FIRST"); + + case FIRST_REPLY_FIRST : + if (!ssl->options.resuming) + if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.connectState = FIRST_REPLY_SECOND; + CYASSL_MSG("connect state: FIRST_REPLY_SECOND"); + + case FIRST_REPLY_SECOND : + if (ssl->options.sendVerify) + if ( (ssl->error = SendCertificateVerify(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.connectState = FIRST_REPLY_THIRD; + CYASSL_MSG("connect state: FIRST_REPLY_THIRD"); + + case FIRST_REPLY_THIRD : + if ( (ssl->error = SendChangeCipher(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.connectState = FIRST_REPLY_FOURTH; + CYASSL_MSG("connect state: FIRST_REPLY_FOURTH"); + + case FIRST_REPLY_FOURTH : + if ( (ssl->error = SendFinished(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.connectState = FINISHED_DONE; + CYASSL_MSG("connect state: FINISHED_DONE"); + + case FINISHED_DONE : + /* get response */ + while (ssl->options.serverState < SERVER_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.connectState = SECOND_REPLY_DONE; + CYASSL_MSG("connect state: SECOND_REPLY_DONE"); + + case SECOND_REPLY_DONE: + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + CYASSL_LEAVE("SSL_connect()", SSL_SUCCESS); + return SSL_SUCCESS; + + default: + CYASSL_MSG("Unknown connect state ERROR"); + return SSL_FATAL_ERROR; /* unknown connect state */ + } + } + +#endif /* NO_CYASSL_CLIENT */ + + +/* server only parts */ +#ifndef NO_CYASSL_SERVER + + SSL_METHOD* SSLv3_server_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) { + InitSSL_Method(method, MakeSSLv3()); + method->side = SERVER_END; + } + return method; + } + + + #ifdef CYASSL_DTLS + SSL_METHOD* DTLSv1_server_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) { + InitSSL_Method(method, MakeDTLSv1()); + method->side = SERVER_END; + } + return method; + } + #endif + + + int SSL_accept(SSL* ssl) + { + CYASSL_ENTER("SSL_accept()"); + + #ifdef HAVE_ERRNO_H + errno = 0; + #endif + + if (ssl->options.side != SERVER_END) { + CYASSL_ERROR(ssl->error = SIDE_ERROR); + return SSL_FATAL_ERROR; + } + + #ifdef CYASSL_DTLS + if (ssl->version.major == DTLS_MAJOR && + ssl->version.minor == DTLS_MINOR) { + ssl->options.dtls = 1; + ssl->options.tls = 1; + ssl->options.tls1_1 = 1; + } + #endif + + if (ssl->buffers.outputBuffer.length > 0) { + if ( (ssl->error = SendBuffered(ssl)) == 0) { + ssl->options.acceptState++; + CYASSL_MSG("accept state: Advanced from buffered send"); + } + else { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + + switch (ssl->options.acceptState) { + + case ACCEPT_BEGIN : + /* get response */ + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE; + CYASSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE"); + + case ACCEPT_CLIENT_HELLO_DONE : + #ifdef CYASSL_DTLS + if (ssl->options.dtls && !ssl->options.resuming) + if ( (ssl->error = SendHelloVerifyRequest(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + #endif + ssl->options.acceptState = HELLO_VERIFY_SENT; + CYASSL_MSG("accept state HELLO_VERIFY_SENT"); + + case HELLO_VERIFY_SENT: + #ifdef CYASSL_DTLS + if (ssl->options.dtls && !ssl->options.resuming) { + ssl->options.clientState = NULL_STATE; /* get again */ + /* re-init hashes, exclude first hello and verify request */ + InitMd5(&ssl->hashMd5); + InitSha(&ssl->hashSha); + #ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) + InitSha256(&ssl->hashSha256); + #endif + + while (ssl->options.clientState < CLIENT_HELLO_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + #endif + ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE; + CYASSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE"); + + case ACCEPT_FIRST_REPLY_DONE : + if ( (ssl->error = SendServerHello(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_HELLO_SENT; + CYASSL_MSG("accept state SERVER_HELLO_SENT"); + + case SERVER_HELLO_SENT : + if (!ssl->options.resuming) + if ( (ssl->error = SendCertificate(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = CERT_SENT; + CYASSL_MSG("accept state CERT_SENT"); + + case CERT_SENT : + if (!ssl->options.resuming) + if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = KEY_EXCHANGE_SENT; + CYASSL_MSG("accept state KEY_EXCHANGE_SENT"); + + case KEY_EXCHANGE_SENT : + if (!ssl->options.resuming) + if (ssl->options.verifyPeer) + if ( (ssl->error = SendCertificateRequest(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = CERT_REQ_SENT; + CYASSL_MSG("accept state CERT_REQ_SENT"); + + case CERT_REQ_SENT : + if (!ssl->options.resuming) + if ( (ssl->error = SendServerHelloDone(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = SERVER_HELLO_DONE; + CYASSL_MSG("accept state SERVER_HELLO_DONE"); + + case SERVER_HELLO_DONE : + if (!ssl->options.resuming) { + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } + ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE; + CYASSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); + + case ACCEPT_SECOND_REPLY_DONE : + if ( (ssl->error = SendChangeCipher(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + ssl->options.acceptState = CHANGE_CIPHER_SENT; + CYASSL_MSG("accept state CHANGE_CIPHER_SENT"); + + case CHANGE_CIPHER_SENT : + if ( (ssl->error = SendFinished(ssl)) != 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_FINISHED_DONE; + CYASSL_MSG("accept state ACCEPT_FINISHED_DONE"); + + case ACCEPT_FINISHED_DONE : + if (ssl->options.resuming) + while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE) + if ( (ssl->error = ProcessReply(ssl)) < 0) { + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + + ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE; + CYASSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE"); + + case ACCEPT_THIRD_REPLY_DONE : + if (ssl->buffers.inputBuffer.dynamicFlag) + ShrinkInputBuffer(ssl, NO_FORCED_FREE); + CYASSL_LEAVE("SSL_accept()", SSL_SUCCESS); + return SSL_SUCCESS; + + default : + CYASSL_MSG("Unknown accept state ERROR"); + return SSL_FATAL_ERROR; + } + } + +#endif /* NO_CYASSL_SERVER */ + + +int InitCyaSSL(void) +{ +#ifndef NO_SESSION_CACHE + if (InitMutex(&mutex) == 0) + return 0; + else + return -1; +#else + return 0; +#endif +} + + +int FreeCyaSSL(void) +{ +#ifndef NO_SESSION_CACHE + if (FreeMutex(&mutex) == 0) + return 0; + else + return -1; +#else + return 0; +#endif +} + + +#ifndef NO_SESSION_CACHE + + +static INLINE word32 HashSession(const byte* sessionID) +{ + /* id is random, just make 32 bit number from first 4 bytes for now */ + return (sessionID[0] << 24) | (sessionID[1] << 16) | (sessionID[2] << 8) | + sessionID[3]; +} + + +void SSL_flush_sessions(SSL_CTX* ctx, long tm) +{ + /* static table now, no flusing needed */ +} + + +SSL_SESSION* GetSession(SSL* ssl, byte* masterSecret) +{ + SSL_SESSION* ret = 0; + const byte* id = ssl->arrays.sessionID; + word32 row; + int idx; + + if (ssl->options.sessionCacheOff) + return 0; + + row = HashSession(id) % SESSION_ROWS; + + if (LockMutex(&mutex) != 0) + return 0; + + if (SessionCache[row].totalCount >= SESSIONS_PER_ROW) + idx = SESSIONS_PER_ROW - 1; + else + idx = SessionCache[row].nextIdx - 1; + + for (; idx >= 0; idx--) { + SSL_SESSION* current; + + if (idx >= SESSIONS_PER_ROW) /* server could have restarted, idx */ + break; /* would be word32(-1) and seg fault */ + + current = &SessionCache[row].Sessions[idx]; + if (XMEMCMP(current->sessionID, id, ID_LEN) == 0) { + if (LowResTimer() < (current->bornOn + current->timeout)) { + ret = current; + if (masterSecret) + XMEMCPY(masterSecret, current->masterSecret, SECRET_LEN); + } + break; + } + } + + UnLockMutex(&mutex); + + return ret; +} + + +int SetSession(SSL* ssl, SSL_SESSION* session) +{ + if (ssl->options.sessionCacheOff) + return SSL_FAILURE; + + if (LowResTimer() < (session->bornOn + session->timeout)) { + ssl->session = *session; + ssl->options.resuming = 1; + +#ifdef SESSION_CERTS + ssl->version = session->version; + ssl->options.cipherSuite0 = session->cipherSuite0; + ssl->options.cipherSuite = session->cipherSuite; +#endif + + return SSL_SUCCESS; + } + return SSL_FAILURE; /* session timed out */ +} + + +int AddSession(SSL* ssl) +{ + word32 row, idx; + + if (ssl->options.sessionCacheOff) + return 0; + + row = HashSession(ssl->arrays.sessionID) % SESSION_ROWS; + + if (LockMutex(&mutex) != 0) + return -1; + + idx = SessionCache[row].nextIdx++; + + XMEMCPY(SessionCache[row].Sessions[idx].masterSecret, + ssl->arrays.masterSecret, SECRET_LEN); + XMEMCPY(SessionCache[row].Sessions[idx].sessionID, ssl->arrays.sessionID, + ID_LEN); + + SessionCache[row].Sessions[idx].timeout = DEFAULT_TIMEOUT; + SessionCache[row].Sessions[idx].bornOn = LowResTimer(); + +#ifdef SESSION_CERTS + SessionCache[row].Sessions[idx].chain.count = ssl->session.chain.count; + XMEMCPY(SessionCache[row].Sessions[idx].chain.certs, + ssl->session.chain.certs, sizeof(x509_buffer) * MAX_CHAIN_DEPTH); + + SessionCache[row].Sessions[idx].version = ssl->version; + SessionCache[row].Sessions[idx].cipherSuite0 = ssl->options.cipherSuite0; + SessionCache[row].Sessions[idx].cipherSuite = ssl->options.cipherSuite; +#endif + + SessionCache[row].totalCount++; + if (SessionCache[row].nextIdx == SESSIONS_PER_ROW) + SessionCache[row].nextIdx = 0; + + if (UnLockMutex(&mutex) != 0) + return -1; + + return 0; +} + + + #ifdef SESSION_STATS + + void PrintSessionStats(void) + { + word32 totalSessionsSeen = 0; + word32 totalSessionsNow = 0; + word32 rowNow; + int i; + double E; /* expected freq */ + double chiSquare = 0; + + for (i = 0; i < SESSION_ROWS; i++) { + totalSessionsSeen += SessionCache[i].totalCount; + + if (SessionCache[i].totalCount >= SESSIONS_PER_ROW) + rowNow = SESSIONS_PER_ROW; + else if (SessionCache[i].nextIdx == 0) + rowNow = 0; + else + rowNow = SessionCache[i].nextIdx; + + totalSessionsNow += rowNow; + } + + printf("Total Sessions Seen = %d\n", totalSessionsSeen); + printf("Total Sessions Now = %d\n", totalSessionsNow); + + E = (double)totalSessionsSeen / SESSION_ROWS; + + for (i = 0; i < SESSION_ROWS; i++) { + double diff = SessionCache[i].totalCount - E; + diff *= diff; /* sqaure */ + diff /= E; /* normalize */ + + chiSquare += diff; + } + printf(" chi-square = %5.1f, d.f. = %d\n", chiSquare, + SESSION_ROWS - 1); + if (SESSION_ROWS == 11) + printf(" .05 p value = 18.3, chi-square should be less\n"); + else if (SESSION_ROWS == 211) + printf(".05 p value = 244.8, chi-square should be less\n"); + else if (SESSION_ROWS == 5981) + printf(".05 p value = 6161.0, chi-square should be less\n"); + printf("\n"); + } + + #endif /* SESSION_STATS */ + +#endif /* NO_SESSION_CACHE */ + + +/* call before SSL_connect, if verifying will add name check to + date check and signature check */ +int CyaSSL_check_domain_name(SSL* ssl, const char* dn) +{ + if (ssl->buffers.domainName.buffer) + XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN); + + ssl->buffers.domainName.length = (word32)XSTRLEN(dn) + 1; + ssl->buffers.domainName.buffer = (byte*) XMALLOC( + ssl->buffers.domainName.length, ssl->heap, DYNAMIC_TYPE_DOMAIN); + + if (ssl->buffers.domainName.buffer) { + XSTRNCPY((char*)ssl->buffers.domainName.buffer, dn, + ssl->buffers.domainName.length); + return SSL_SUCCESS; + } + else { + ssl->error = MEMORY_ERROR; + return SSL_FAILURE; + } +} + + +/* turn on CyaSSL zlib compression + returns 0 for success, else error (not built in) +*/ +int CyaSSL_set_compression(SSL* ssl) +{ +#ifdef HAVE_LIBZ + ssl->options.usingCompression = 1; + return 0; +#else + return -1; +#endif +} + + +#ifndef USE_WINDOWS_API + #ifndef NO_WRITEV + + /* simulate writev semantics, doesn't actually do block at a time though + because of SSL_write behavior and because front adds may be small */ + int CyaSSL_writev(SSL* ssl, const struct iovec* iov, int iovcnt) + { + byte tmp[OUTPUT_RECORD_SIZE]; + byte* buffer = tmp; + int send = 0; + int newBuffer = 0; + int idx = 0; + int i; + int ret; + + for (i = 0; i < iovcnt; i++) + send += iov[i].iov_len; + + if (send > sizeof(tmp)) { + byte* tmp2 = (byte*) XMALLOC(send, ssl->heap, + DYNAMIC_TYPE_WRITEV); + if (!tmp2) + return MEMORY_ERROR; + buffer = tmp2; + newBuffer = 1; + } + + for (i = 0; i < iovcnt; i++) { + XMEMCPY(&buffer[idx], iov[i].iov_base, iov[i].iov_len); + idx += iov[i].iov_len; + } + + ret = SSL_write(ssl, buffer, send); + + if (newBuffer) XFREE(buffer, ssl->heap, DYNAMIC_TYPE_WRITEV); + + return ret; + } + #endif +#endif + + +#ifdef CYASSL_CALLBACKS + + typedef struct itimerval Itimerval; + + /* don't keep calling simple functions while setting up timer and singals + if no inlining these are the next best */ + + #define AddTimes(a, b, c) \ + do { \ + c.tv_sec = a.tv_sec + b.tv_sec; \ + c.tv_usec = a.tv_usec + b.tv_usec; \ + if (c.tv_sec >= 1000000) { \ + c.tv_sec++; \ + c.tv_usec -= 1000000; \ + } \ + } while (0) + + + #define SubtractTimes(a, b, c) \ + do { \ + c.tv_sec = a.tv_sec - b.tv_sec; \ + c.tv_usec = a.tv_usec - b.tv_usec; \ + if (c.tv_sec < 0) { \ + c.tv_sec--; \ + c.tv_usec += 1000000; \ + } \ + } while (0) + + #define CmpTimes(a, b, cmp) \ + ((a.tv_sec == b.tv_sec) ? \ + (a.tv_usec cmp b.tv_usec) : \ + (a.tv_sec cmp b.tv_sec)) \ + + + /* do nothing handler */ + static void myHandler(int signo) + { + return; + } + + + static int CyaSSL_ex_wrapper(SSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, Timeval timeout) + { + int ret = -1; + int oldTimerOn = 0; /* was timer already on */ + Timeval startTime; + Timeval endTime; + Timeval totalTime; + Itimerval myTimeout; + Itimerval oldTimeout; /* if old timer adjust from total time to reset */ + struct sigaction act, oact; + + #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; } + + if (hsCb) { + ssl->hsInfoOn = 1; + InitHandShakeInfo(&ssl->handShakeInfo); + } + if (toCb) { + ssl->toInfoOn = 1; + InitTimeoutInfo(&ssl->timeoutInfo); + + if (gettimeofday(&startTime, 0) < 0) + ERR_OUT(GETTIME_ERROR); + + /* use setitimer to simulate getitimer, init 0 myTimeout */ + myTimeout.it_interval.tv_sec = 0; + myTimeout.it_interval.tv_usec = 0; + myTimeout.it_value.tv_sec = 0; + myTimeout.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0) + ERR_OUT(SETITIMER_ERROR); + + if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) { + oldTimerOn = 1; + + /* is old timer going to expire before ours */ + if (CmpTimes(oldTimeout.it_value, timeout, <)) { + timeout.tv_sec = oldTimeout.it_value.tv_sec; + timeout.tv_usec = oldTimeout.it_value.tv_usec; + } + } + myTimeout.it_value.tv_sec = timeout.tv_sec; + myTimeout.it_value.tv_usec = timeout.tv_usec; + + /* set up signal handler, don't restart socket send/recv */ + act.sa_handler = myHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_INTERRUPT + act.sa_flags |= SA_INTERRUPT; +#endif + if (sigaction(SIGALRM, &act, &oact) < 0) + ERR_OUT(SIGACT_ERROR); + + if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0) + ERR_OUT(SETITIMER_ERROR); + } + + /* do main work */ +#ifndef NO_CYASSL_CLIENT + if (ssl->options.side == CLIENT_END) + ret = SSL_connect(ssl); +#endif +#ifndef NO_CYASSL_SERVER + if (ssl->options.side == SERVER_END) + ret = SSL_accept(ssl); +#endif + + /* do callbacks */ + if (toCb) { + if (oldTimerOn) { + gettimeofday(&endTime, 0); + SubtractTimes(endTime, startTime, totalTime); + /* adjust old timer for elapsed time */ + if (CmpTimes(totalTime, oldTimeout.it_value, <)) + SubtractTimes(oldTimeout.it_value, totalTime, + oldTimeout.it_value); + else { + /* reset value to interval, may be off */ + oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec; + oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec; + } + /* keep iter the same whether there or not */ + } + /* restore old handler */ + if (sigaction(SIGALRM, &oact, 0) < 0) + ret = SIGACT_ERROR; /* more pressing error, stomp */ + else + /* use old settings which may turn off (expired or not there) */ + if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0) + ret = SETITIMER_ERROR; + + /* if we had a timeout call callback */ + if (ssl->timeoutInfo.timeoutName[0]) { + ssl->timeoutInfo.timeoutValue.tv_sec = timeout.tv_sec; + ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec; + (toCb)(&ssl->timeoutInfo); + } + /* clean up */ + FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap); + ssl->toInfoOn = 0; + } + if (hsCb) { + FinishHandShakeInfo(&ssl->handShakeInfo, ssl); + (hsCb)(&ssl->handShakeInfo); + ssl->hsInfoOn = 0; + } + return ret; + } + + +#ifndef NO_CYASSL_CLIENT + + int CyaSSL_connect_ex(SSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb, Timeval timeout) + { + return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout); + } + +#endif + + +#ifndef NO_CYASSL_SERVER + + int CyaSSL_accept_ex(SSL* ssl, HandShakeCallBack hsCb, + TimeoutCallBack toCb,Timeval timeout) + { + return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout); + } + +#endif + +#endif /* CYASSL_CALLBACKS */ + + +#ifndef NO_PSK + + void SSL_CTX_set_psk_client_callback(SSL_CTX* ctx, psk_client_callback cb) + { + ctx->havePSK = 1; + ctx->client_psk_cb = cb; + } + + + void SSL_set_psk_client_callback(SSL* ssl, psk_client_callback cb) + { + ssl->options.havePSK = 1; + ssl->options.client_psk_cb = cb; + + InitSuites(&ssl->suites, ssl->version,TRUE,TRUE, ssl->options.haveNTRU, + ssl->options.haveECDSA, ssl->ctx->method->side); + } + + + void SSL_CTX_set_psk_server_callback(SSL_CTX* ctx, psk_server_callback cb) + { + ctx->havePSK = 1; + ctx->server_psk_cb = cb; + } + + + void SSL_set_psk_server_callback(SSL* ssl, psk_server_callback cb) + { + ssl->options.havePSK = 1; + ssl->options.server_psk_cb = cb; + + InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, TRUE, + ssl->options.haveNTRU, ssl->options.haveECDSA, + ssl->ctx->method->side); + } + + + const char* SSL_get_psk_identity_hint(const SSL* ssl) + { + return ssl->arrays.server_hint; + } + + + const char* SSL_get_psk_identity(const SSL* ssl) + { + return ssl->arrays.client_identity; + } + + + int SSL_CTX_use_psk_identity_hint(SSL_CTX* ctx, const char* hint) + { + if (hint == 0) + ctx->server_hint[0] = 0; + else + XSTRNCPY(ctx->server_hint, hint, MAX_PSK_ID_LEN); + return SSL_SUCCESS; + } + + + int SSL_use_psk_identity_hint(SSL* ssl, const char* hint) + { + if (hint == 0) + ssl->arrays.server_hint[0] = 0; + else + XSTRNCPY(ssl->arrays.server_hint, hint, MAX_PSK_ID_LEN); + return SSL_SUCCESS; + } + +#endif /* NO_PSK */ + + +#if defined(NO_FILESYSTEM) || defined(MICRIUM) + + /* CyaSSL extension allows DER files to be loaded from buffers as well */ + int CyaSSL_CTX_load_verify_buffer(SSL_CTX* ctx, const unsigned char* buffer, + long sz, int format) + { + return ProcessBuffer(ctx, buffer, sz, format, CA_TYPE); + } + + + int CyaSSL_CTX_use_certificate_buffer(SSL_CTX* ctx, + const unsigned char* buffer,long sz,int format) + { + return ProcessBuffer(ctx, buffer, sz, format, CERT_TYPE); + } + + + int CyaSSL_CTX_use_PrivateKey_buffer(SSL_CTX* ctx, + const unsigned char* buffer,long sz,int format) + { + return ProcessBuffer(ctx, buffer, sz, format, PRIVATEKEY_TYPE); + } + + + int CyaSSL_CTX_use_certificate_chain_buffer(SSL_CTX* ctx, + const unsigned char* buffer, long sz) + { + /* add first to ctx, all tested implementations support this */ + return ProcessBuffer(ctx, buffer, sz, SSL_FILETYPE_PEM, CA_TYPE); + } + +#endif /* NO_FILESYSTEM || MICRIUM */ + + +#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS) + + + int SSLeay_add_ssl_algorithms(void) + { + OpenSSL_add_all_algorithms(); + return SSL_SUCCESS; + } + + + long SSL_CTX_sess_set_cache_size(SSL_CTX* ctx, long sz) + { + /* cache size fixed at compile time in CyaSSL */ + return 0; + } + + + void SSL_CTX_set_quiet_shutdown(SSL_CTX* ctx, int mode) + { + if (mode) + ctx->quietShutdown = 1; + } + + + int SSL_CTX_check_private_key(SSL_CTX* ctx) + { + /* TODO: check private against public for RSA match */ + return SSL_SUCCESS; + } + + + void SSL_set_bio(SSL* ssl, BIO* rd, BIO* wr) + { + SSL_set_rfd(ssl, rd->fd); + SSL_set_wfd(ssl, wr->fd); + + ssl->biord = rd; + ssl->biowr = wr; + } + + + void SSL_CTX_set_client_CA_list(SSL_CTX* ctx, STACK_OF(X509_NAME)* names) + { + + } + + + STACK_OF(X509_NAME)* SSL_load_client_CA_file(const char* fname) + { + return 0; + } + + + int SSL_CTX_set_default_verify_paths(SSL_CTX* ctx) + { + /* TODO:, not needed in goahead */ + return SSL_NOT_IMPLEMENTED; + } + + + void SSL_set_accept_state(SSL* ssl) + { + byte havePSK = 0; + + ssl->options.side = SERVER_END; + /* reset suites in case user switched */ +#ifndef NO_PSK + havePSK = ssl->options.havePSK; +#endif + InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, havePSK, + ssl->options.haveNTRU, ssl->options.haveECDSA, + ssl->ctx->method->side); + } + + + void OpenSSL_add_all_algorithms(void) + { + InitCyaSSL(); + } + + + int SSLeay_add_all_algorithms(void) + { + OpenSSL_add_all_algorithms(); + return SSL_SUCCESS; + } + + + void SSL_CTX_set_tmp_rsa_callback(SSL_CTX* ctx, RSA*(*f)(SSL*, int, int)) + { + /* CyaSSL verifies all these internally */ + } + + + void SSL_set_shutdown(SSL* ssl, int opt) + { + + } + + + long SSL_CTX_set_options(SSL_CTX* ctx, long opt) + { + /* goahead calls with 0, do nothing */ + return opt; + } + + + int SSL_set_rfd(SSL* ssl, int rfd) + { + ssl->rfd = rfd; /* not used directly to allow IO callbacks */ + + ssl->IOCB_ReadCtx = &ssl->rfd; + + return SSL_SUCCESS; + } + + + int SSL_set_wfd(SSL* ssl, int wfd) + { + ssl->wfd = wfd; /* not used directly to allow IO callbacks */ + + ssl->IOCB_WriteCtx = &ssl->wfd; + + return SSL_SUCCESS; + } + + + RSA* RSA_generate_key(int len, unsigned long bits, void(*f)(int, + int, void*), void* data) + { + /* no tmp key needed, actual generation not supported */ + return 0; + } + + + X509_NAME* X509_get_issuer_name(X509* cert) + { + return &cert->issuer; + } + + + X509_NAME* X509_get_subject_name(X509* cert) + { + return &cert->subject; + } + + + /* copy name into buffer, at most sz bytes, if buffer is null will + malloc buffer, call responsible for freeing */ + char* X509_NAME_oneline(X509_NAME* name, char* buffer, int sz) + { + int copySz = min(sz, name->sz); + if (!name->sz) return buffer; + + if (!buffer) { + buffer = (char*)XMALLOC(name->sz, 0, DYNAMIC_TYPE_OPENSSL); + if (!buffer) return buffer; + copySz = name->sz; + } + + if (copySz == 0) + return buffer; + + XMEMCPY(buffer, name->name, copySz - 1); + buffer[copySz - 1] = 0; + + return buffer; + } + + + X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX* ctx) + { + return 0; + } + + + int X509_STORE_CTX_get_error(X509_STORE_CTX* ctx) + { + return 0; + } + + + int X509_STORE_CTX_get_error_depth(X509_STORE_CTX* ctx) + { + return 0; + } + + + BIO_METHOD* BIO_f_buffer(void) + { + static BIO_METHOD meth; + meth.type = BIO_BUFFER; + + return &meth; + } + + + long BIO_set_write_buffer_size(BIO* bio, long size) + { + /* CyaSSL has internal buffer, compatibility only */ + return size; + } + + + BIO_METHOD* BIO_f_ssl(void) + { + static BIO_METHOD meth; + meth.type = BIO_SSL; + + return &meth; + } + + + BIO* BIO_new_socket(int sfd, int close) + { + BIO* bio = (BIO*) XMALLOC(sizeof(BIO), 0, DYNAMIC_TYPE_OPENSSL); + if (bio) { + bio->type = BIO_SOCKET; + bio->close = close; + bio->eof = 0; + bio->ssl = 0; + bio->fd = sfd; + bio->prev = 0; + bio->next = 0; + } + return bio; + } + + + int BIO_eof(BIO* b) + { + if (b->eof) + return 1; + + return 0; + } + + + long BIO_set_ssl(BIO* b, SSL* ssl, int close) + { + b->ssl = ssl; + b->close = close; + /* add to ssl for bio free if SSL_free called before/instead of free_all? */ + + return 0; + } + + + BIO* BIO_new(BIO_METHOD* method) + { + BIO* bio = (BIO*) XMALLOC(sizeof(BIO), 0, DYNAMIC_TYPE_OPENSSL); + if (bio) { + bio->type = method->type; + bio->close = 0; + bio->eof = 0; + bio->ssl = 0; + bio->fd = 0; + bio->prev = 0; + bio->next = 0; + } + return bio; + } + + +#ifdef USE_WINDOWS_API + #define CloseSocket(s) closesocket(s) +#else + #define CloseSocket(s) close(s) +#endif + + int BIO_free(BIO* bio) + { + /* unchain?, doesn't matter in goahead since from free all */ + if (bio) { + if (bio->close) { + if (bio->ssl) + SSL_free(bio->ssl); + if (bio->fd) + CloseSocket(bio->fd); + } + XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL); + } + return 0; + } + + + int BIO_free_all(BIO* bio) + { + BIO* next = bio; + + while ( (bio = next) ) { + next = bio->next; + BIO_free(bio); + } + return 0; + } + + + int BIO_read(BIO* bio, void* buf, int len) + { + int ret; + SSL* ssl = 0; + BIO* front = bio; + + /* already got eof, again is error */ + if (front->eof) + return -1; + + while(bio && ((ssl = bio->ssl) == 0) ) + bio = bio->next; + + if (ssl == 0) return -1; + + ret = SSL_read(ssl, buf, len); + if (ret == 0) + front->eof = 1; + else if (ret < 0) { + int err = SSL_get_error(ssl, 0); + if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) ) + front->eof = 1; + } + return ret; + } + + + int BIO_write(BIO* bio, const void* data, int len) + { + int ret; + SSL* ssl = 0; + BIO* front = bio; + + /* already got eof, again is error */ + if (front->eof) + return -1; + + while(bio && ((ssl = bio->ssl) == 0) ) + bio = bio->next; + + if (ssl == 0) return -1; + + ret = SSL_write(ssl, data, len); + if (ret == 0) + front->eof = 1; + else if (ret < 0) { + int err = SSL_get_error(ssl, 0); + if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) ) + front->eof = 1; + } + + return ret; + } + + + BIO* BIO_push(BIO* top, BIO* append) + { + top->next = append; + append->prev = top; + + return top; + } + + + int BIO_flush(BIO* bio) + { + /* for CyaSSL no flushing needed */ + return 1; + } + + +#endif /* OPENSSL_EXTRA || GOAHEAD_WS */ + + +#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) + + void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX* ctx, void* userdata) + { + ctx->userdata = userdata; + } + + + void SSL_CTX_set_default_passwd_cb(SSL_CTX* ctx, pem_password_cb cb) + { + ctx->passwd_cb = cb; + } + + int CRYPTO_num_locks(void) + { + return 0; + } + + void CRYPTO_set_locking_callback(void (*f)(int, int, const char*, int)) + { + + } + + void CRYPTO_set_id_callback(unsigned long (*f)(void)) + { + + } + + unsigned long ERR_get_error(void) + { + /* TODO: */ + return 0; + } + + int EVP_BytesToKey(const EVP_CIPHER* type, const EVP_MD* md, + const byte* salt, const byte* data, int sz, int count, + byte* key, byte* iv) + { + int keyLen = 0; + int ivLen = 0; + + Md5 myMD; + byte digest[MD5_DIGEST_SIZE]; + + int j; + int keyLeft; + int ivLeft; + int keyOutput = 0; + + InitMd5(&myMD); + + /* only support MD5 for now */ + if (XSTRNCMP(md, "MD5", 3)) return 0; + + /* only support CBC DES and AES for now */ + if (XSTRNCMP(type, "DES-CBC", 7) == 0) { + keyLen = DES_KEY_SIZE; + ivLen = DES_IV_SIZE; + } + else if (XSTRNCMP(type, "DES-EDE3-CBC", 12) == 0) { + keyLen = DES3_KEY_SIZE; + ivLen = DES_IV_SIZE; + } + else if (XSTRNCMP(type, "AES-128-CBC", 11) == 0) { + keyLen = AES_128_KEY_SIZE; + ivLen = AES_IV_SIZE; + } + else if (XSTRNCMP(type, "AES-192-CBC", 11) == 0) { + keyLen = AES_192_KEY_SIZE; + ivLen = AES_IV_SIZE; + } + else if (XSTRNCMP(type, "AES-256-CBC", 11) == 0) { + keyLen = AES_256_KEY_SIZE; + ivLen = AES_IV_SIZE; + } + else + return 0; + + keyLeft = keyLen; + ivLeft = ivLen; + + while (keyOutput < (keyLen + ivLen)) { + int digestLeft = MD5_DIGEST_SIZE; + /* D_(i - 1) */ + if (keyOutput) /* first time D_0 is empty */ + Md5Update(&myMD, digest, MD5_DIGEST_SIZE); + /* data */ + Md5Update(&myMD, data, sz); + /* salt */ + if (salt) + Md5Update(&myMD, salt, EVP_SALT_SIZE); + Md5Final(&myMD, digest); + /* count */ + for (j = 1; j < count; j++) { + Md5Update(&myMD, digest, MD5_DIGEST_SIZE); + Md5Final(&myMD, digest); + } + + if (keyLeft) { + int store = min(keyLeft, MD5_DIGEST_SIZE); + XMEMCPY(&key[keyLen - keyLeft], digest, store); + + keyOutput += store; + keyLeft -= store; + digestLeft -= store; + } + + if (ivLeft && digestLeft) { + int store = min(ivLeft, digestLeft); + XMEMCPY(&iv[ivLen - ivLeft], &digest[MD5_DIGEST_SIZE - + digestLeft], store); + keyOutput += store; + ivLeft -= store; + } + } + if (keyOutput != (keyLen + ivLen)) + return 0; + return keyOutput; + } + +#endif /* OPENSSL_EXTRA || HAVE_WEBSERVER */ + + +#ifdef OPENSSL_EXTRA + + unsigned long SSLeay(void) + { + return SSLEAY_VERSION_NUMBER; + } + + + const char* SSLeay_version(int type) + { + static const char* version = "SSLeay CyaSSL compatibility"; + return version; + } + + + void MD5_Init(MD5_CTX* md5) + { + typedef char md5_test[sizeof(MD5_CTX) >= sizeof(Md5) ? 1 : -1]; + (void)sizeof(md5_test); + + InitMd5((Md5*)md5); + } + + + void MD5_Update(MD5_CTX* md5, const void* input, unsigned long sz) + { + Md5Update((Md5*)md5, (const byte*)input, sz); + } + + + void MD5_Final(byte* input, MD5_CTX* md5) + { + Md5Final((Md5*)md5, input); + } + + + void SHA_Init(SHA_CTX* sha) + { + typedef char sha_test[sizeof(SHA_CTX) >= sizeof(Sha) ? 1 : -1]; + (void)sizeof(sha_test); + + InitSha((Sha*)sha); + } + + + void SHA_Update(SHA_CTX* sha, const void* input, unsigned long sz) + { + ShaUpdate((Sha*)sha, (const byte*)input, sz); + } + + + void SHA_Final(byte* input, SHA_CTX* sha) + { + ShaFinal((Sha*)sha, input); + } + + + const EVP_MD* EVP_md5(void) + { + static const char* type = "MD5"; + return type; + } + + + const EVP_MD* EVP_sha1(void) + { + static const char* type = "SHA"; + return type; + } + + + void EVP_MD_CTX_init(EVP_MD_CTX* ctx) + { + /* do nothing */ + } + + + int EVP_MD_CTX_cleanup(EVP_MD_CTX* ctx) + { + return 0; + } + + + int EVP_DigestInit(EVP_MD_CTX* ctx, const EVP_MD* type) + { + if (XSTRNCMP(type, "MD5", 3) == 0) { + ctx->macType = MD5; + MD5_Init((MD5_CTX*)&ctx->hash); + } + else if (XSTRNCMP(type, "SHA", 3) == 0) { + ctx->macType = SHA; + SHA_Init((SHA_CTX*)&ctx->hash); + } + else + return -1; + + return 0; + } + + + int EVP_DigestUpdate(EVP_MD_CTX* ctx, const void* data, size_t sz) + { + if (ctx->macType == MD5) + MD5_Update((MD5_CTX*)&ctx->hash, data, (unsigned long)sz); + else if (ctx->macType == SHA) + SHA_Update((SHA_CTX*)&ctx->hash, data, (unsigned long)sz); + else + return -1; + + return 0; + } + + + int EVP_DigestFinal(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s) + { + if (ctx->macType == MD5) { + MD5_Final(md, (MD5_CTX*)&ctx->hash); + if (s) *s = MD5_DIGEST_SIZE; + } + else if (ctx->macType == SHA) { + SHA_Final(md, (SHA_CTX*)&ctx->hash); + if (s) *s = SHA_DIGEST_SIZE; + } + else + return -1; + + return 0; + } + + + int EVP_DigestFinal_ex(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s) + { + return EVP_DigestFinal(ctx, md, s); + } + + + unsigned char* HMAC(const EVP_MD* evp_md, const void* key, int key_len, + const unsigned char* d, int n, unsigned char* md, unsigned int* md_len) + { + Hmac hmac; + + if (!md) return 0; /* no static buffer support */ + + if (XSTRNCMP(evp_md, "MD5", 3) == 0) { + HmacSetKey(&hmac, MD5, key, key_len); + if (md_len) *md_len = MD5_DIGEST_SIZE; + } + else if (XSTRNCMP(evp_md, "SHA", 3) == 0) { + HmacSetKey(&hmac, SHA, key, key_len); + if (md_len) *md_len = SHA_DIGEST_SIZE; + } + else + return 0; + + HmacUpdate(&hmac, d, n); + HmacFinal(&hmac, md); + + return md; + } + + void ERR_clear_error(void) + { + /* TODO: */ + } + + + int RAND_status(void) + { + return 1; /* CTaoCrypt provides enough seed internally */ + } + + + int RAND_bytes(unsigned char* buf, int num) + { + RNG rng; + + if (InitRng(&rng)) + return 0; + + RNG_GenerateBlock(&rng, buf, num); + + return 1; + } + + + int DES_key_sched(const_DES_cblock* key, DES_key_schedule* schedule) + { + XMEMCPY(schedule, key, sizeof(const_DES_cblock)); + return 0; + } + + + void DES_cbc_encrypt(const unsigned char* input, unsigned char* output, + long length, DES_key_schedule* schedule, DES_cblock* ivec, + int enc) + { + Des des; + Des_SetKey(&des, (const byte*)schedule, (const byte*)ivec, !enc); + + if (enc) + Des_CbcEncrypt(&des, output, input, length); + else + Des_CbcDecrypt(&des, output, input, length); + } + + + /* correctly sets ivec for next call */ + void DES_ncbc_encrypt(const unsigned char* input, unsigned char* output, + long length, DES_key_schedule* schedule, DES_cblock* ivec, + int enc) + { + Des des; + Des_SetKey(&des, (const byte*)schedule, (const byte*)ivec, !enc); + + if (enc) + Des_CbcEncrypt(&des, output, input, length); + else + Des_CbcDecrypt(&des, output, input, length); + + XMEMCPY(ivec, output + length - sizeof(DES_cblock), sizeof(DES_cblock)); + } + + + void ERR_free_strings(void) + { + /* handled internally */ + } + + + void ERR_remove_state(unsigned long state) + { + /* TODO: GetErrors().Remove(); */ + } + + + void EVP_cleanup(void) + { + /* nothing to do here */ + } + + + void CRYPTO_cleanup_all_ex_data(void) + { + /* nothing to do here */ + } + + + long SSL_CTX_set_mode(SSL_CTX* ctx, long mode) + { + /* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is CyaSSL default mode */ + + if (mode == SSL_MODE_ENABLE_PARTIAL_WRITE) + ctx->partialWrite = 1; + + return mode; + } + + + long SSL_CTX_get_mode(SSL_CTX* ctx) + { + /* TODO: */ + return 0; + } + + + void SSL_CTX_set_default_read_ahead(SSL_CTX* ctx, int m) + { + /* TODO: maybe? */ + } + + + int SSL_CTX_set_session_id_context(SSL_CTX* ctx, + const unsigned char* sid_ctx, + unsigned int sid_ctx_len) + { + /* No application specific context needed for cyaSSL */ + return SSL_SUCCESS; + } + + + long SSL_CTX_sess_get_cache_size(SSL_CTX* ctx) + { + /* TODO: maybe? */ + return (~0); + } + + unsigned long ERR_get_error_line_data(const char** file, int* line, + const char** data, int *flags) + { + /* Not implemented */ + return 0; + } + + + X509* SSL_get_peer_certificate(SSL* ssl) + { + if (ssl->peerCert.issuer.sz) + return &ssl->peerCert; + else + return 0; + } + + + + int SSL_set_ex_data(SSL* ssl, int idx, void* data) + { + return 0; + } + + + int SSL_get_shutdown(const SSL* ssl) + { + return 0; + } + + + int SSL_set_session_id_context(SSL* ssl, const unsigned char* id, + unsigned int len) + { + return 0; + } + + + void SSL_set_connect_state(SSL* ssl) + { + /* client by default */ + } + + + int SSL_session_reused(SSL* ssl) + { + return ssl->options.resuming; + } + + + void SSL_SESSION_free(SSL_SESSION* session) + { + + } + + + const char* SSL_get_version(SSL* ssl) + { + if (ssl->version.major == 3) { + switch (ssl->version.minor) { + case 0 : + return "SSLv3"; + case 1 : + return "TLSv1"; + case 2 : + return "TLSv1.1"; + case 3 : + return "TLSv1.2"; + } + } + return "unknown"; + } + + + SSL_CIPHER* SSL_get_current_cipher(SSL* ssl) + { + return &ssl->cipher; + } + + + const char* SSL_CIPHER_get_name(const SSL_CIPHER* cipher) + { + if (cipher) { + if (cipher->ssl->options.cipherSuite0 == ECC_BYTE) { + /* ECC suites */ + switch (cipher->ssl->options.cipherSuite) { + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA : + return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA : + return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA : + return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA : + return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; + case TLS_ECDHE_RSA_WITH_RC4_128_SHA : + return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"; + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA : + return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA : + return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA : + return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; + } + } else { + /* normal suites */ + switch (cipher->ssl->options.cipherSuite) { + case SSL_RSA_WITH_RC4_128_SHA : + return "SSL_RSA_WITH_RC4_128_SHA"; + case SSL_RSA_WITH_RC4_128_MD5 : + return "SSL_RSA_WITH_RC4_128_MD5"; + case SSL_RSA_WITH_3DES_EDE_CBC_SHA : + return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; + case TLS_RSA_WITH_AES_128_CBC_SHA : + return "TLS_RSA_WITH_AES_128_CBC_SHA"; + case TLS_RSA_WITH_AES_256_CBC_SHA : + return "TLS_RSA_WITH_AES_256_CBC_SHA"; + case TLS_PSK_WITH_AES_128_CBC_SHA : + return "TLS_PSK_WITH_AES_128_CBC_SHA"; + case TLS_PSK_WITH_AES_256_CBC_SHA : + return "TLS_PSK_WITH_AES_256_CBC_SHA"; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : + return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : + return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; + case TLS_RSA_WITH_HC_128_CBC_MD5 : + return "TLS_RSA_WITH_HC_128_CBC_MD5"; + case TLS_RSA_WITH_HC_128_CBC_SHA : + return "TLS_RSA_WITH_HC_128_CBC_SHA"; + case TLS_RSA_WITH_RABBIT_CBC_SHA : + return "TLS_RSA_WITH_RABBIT_CBC_SHA"; + case TLS_NTRU_RSA_WITH_RC4_128_SHA : + return "TLS_NTRU_RSA_WITH_RC4_128_SHA"; + case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA : + return "TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA"; + case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA : + return "TLS_NTRU_RSA_WITH_AES_128_CBC_SHA"; + case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA : + return "TLS_NTRU_RSA_WITH_AES_256_CBC_SHA"; + } + } /* normal / ECC */ + } + + return "NONE"; + } + + + char* SSL_CIPHER_description(SSL_CIPHER* cipher, char* buffer, int len) + { + return 0; + } + + + SSL_SESSION* SSL_get1_session(SSL* ssl) /* what's ref count */ + { + return 0; + } + + + void X509_free(X509* buf) + { + + } + + + void OPENSSL_free(void* buf) + { + + } + + + int OCSP_parse_url(char* url, char** host, char** port, char** path, + int* ssl) + { + return 0; + } + + + SSL_METHOD* SSLv2_client_method(void) + { + return 0; + } + + + SSL_METHOD* SSLv2_server_method(void) + { + return 0; + } + + +#ifndef NO_MD4 + + void MD4_Init(MD4_CTX* md4) + { + /* make sure we have a big enough buffer */ + typedef char ok[sizeof(md4->buffer) >= sizeof(Md4) ? 1 : -1]; + (void) sizeof(ok); + + InitMd4((Md4*)md4); + } + + + void MD4_Update(MD4_CTX* md4, const void* data, size_t len) + { + Md4Update((Md4*)md4, (const byte*)data, (word32)len); + } + + + void MD4_Final(unsigned char* digest, MD4_CTX* md4) + { + Md4Final((Md4*)md4, digest); + } + +#endif /* NO_MD4 */ + + + BIO* BIO_pop(BIO* top) + { + return 0; + } + + + int BIO_pending(BIO* bio) + { + return 0; + } + + + + BIO_METHOD* BIO_s_mem(void) + { + return 0; + } + + + BIO_METHOD* BIO_f_base64(void) + { + return 0; + } + + + void BIO_set_flags(BIO* bio, int flags) + { + + } + + + + void RAND_screen(void) + { + + } + + + const char* RAND_file_name(char* fname, size_t len) + { + return 0; + } + + + int RAND_write_file(const char* fname) + { + return 0; + } + + + int RAND_load_file(const char* fname, long len) + { + /* CTaoCrypt provides enough entropy internally or will report error */ + if (len == -1) + return 1024; + else + return (int)len; + } + + + int RAND_egd(const char* path) + { + return 0; + } + + + + COMP_METHOD* COMP_zlib(void) + { + return 0; + } + + + COMP_METHOD* COMP_rle(void) + { + return 0; + } + + + int SSL_COMP_add_compression_method(int method, void* data) + { + return 0; + } + + + + int SSL_get_ex_new_index(long idx, void* data, void* cb1, void* cb2, + void* cb3) + { + return 0; + } + + + void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock_value* (*f)( + const char*, int)) + { + + } + + + void CRYPTO_set_dynlock_lock_callback(void (*f)(int, CRYPTO_dynlock_value*, + const char*, int)) + { + + } + + + void CRYPTO_set_dynlock_destroy_callback(void (*f)(CRYPTO_dynlock_value*, + const char*, int)) + { + + } + + + + const char* X509_verify_cert_error_string(long err) + { + return 0; + } + + + + int X509_LOOKUP_add_dir(X509_LOOKUP* lookup, const char* dir, long len) + { + return 0; + } + + + int X509_LOOKUP_load_file(X509_LOOKUP* lookup, const char* file, long len) + { + return 0; + } + + + X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void) + { + return 0; + } + + + X509_LOOKUP_METHOD* X509_LOOKUP_file(void) + { + return 0; + } + + + + X509_LOOKUP* X509_STORE_add_lookup(X509_STORE* store, X509_LOOKUP_METHOD* m) + { + return 0; + } + + + X509_STORE* X509_STORE_new(void) + { + return 0; + } + + + int X509_STORE_get_by_subject(X509_STORE_CTX* ctx, int idx, X509_NAME* name, + X509_OBJECT* obj) + { + return 0; + } + + + int X509_STORE_CTX_init(X509_STORE_CTX* ctx, X509_STORE* store, X509* x509, + STACK_OF(X509)* sk) + { + return 0; + } + + + void X509_STORE_CTX_cleanup(X509_STORE_CTX* ctx) + { + + } + + + + ASN1_TIME* X509_CRL_get_lastUpdate(X509_CRL* crl) + { + return 0; + } + + + ASN1_TIME* X509_CRL_get_nextUpdate(X509_CRL* crl) + { + return 0; + } + + + + EVP_PKEY* X509_get_pubkey(X509* x509) + { + return 0; + } + + + int X509_CRL_verify(X509_CRL* crl, EVP_PKEY* key) + { + return 0; + } + + + void X509_STORE_CTX_set_error(X509_STORE_CTX* ctx, int err) + { + + } + + + void X509_OBJECT_free_contents(X509_OBJECT* obj) + { + + } + + + void EVP_PKEY_free(EVP_PKEY* key) + { + + } + + + int X509_cmp_current_time(const ASN1_TIME* time) + { + return 0; + } + + + int sk_X509_REVOKED_num(X509_REVOKED* revoked) + { + return 0; + } + + + + X509_REVOKED* X509_CRL_get_REVOKED(X509_CRL* crl) + { + return 0; + } + + + X509_REVOKED* sk_X509_REVOKED_value(X509_REVOKED* revoked, int value) + { + return 0; + } + + + + ASN1_INTEGER* X509_get_serialNumber(X509* x509) + { + return 0; + } + + + + int ASN1_TIME_print(BIO* bio, const ASN1_TIME* time) + { + return 0; + } + + + + int ASN1_INTEGER_cmp(const ASN1_INTEGER* a, const ASN1_INTEGER* b) + { + return 0; + } + + + long ASN1_INTEGER_get(const ASN1_INTEGER* i) + { + return 0; + } + + + + void* X509_STORE_CTX_get_ex_data(X509_STORE_CTX* ctx, int idx) + { + return 0; + } + + + int SSL_get_ex_data_X509_STORE_CTX_idx(void) + { + return 0; + } + + + void* SSL_get_ex_data(const SSL* ssl, int idx) + { + return 0; + } + + + long SSL_CTX_set_timeout(SSL_CTX* ctx, long to) + { + return 0; + } + + + void SSL_CTX_set_info_callback(SSL_CTX* ctx, void (*f)()) + { + + } + + + unsigned long ERR_peek_error(void) + { + return 0; + } + + + int ERR_GET_REASON(int err) + { + return 0; + } + + + char* SSL_alert_type_string_long(int alert) + { + return 0; + } + + + char* SSL_alert_desc_string_long(int alert) + { + return 0; + } + + + char* SSL_state_string_long(SSL* ssl) + { + return 0; + } + + + + void RSA_free(RSA* rsa) + { + + } + + + int PEM_def_callback(char* name, int num, int w, void* key) + { + return 0; + } + + + long SSL_CTX_sess_accept(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_connect(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_accept_good(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_connect_good(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_accept_renegotiate(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_connect_renegotiate(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_hits(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_cb_hits(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_cache_full(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_misses(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_timeouts(SSL_CTX* ctx) + { + return 0; + } + + + long SSL_CTX_sess_number(SSL_CTX* ctx) + { + return 0; + } + + + void DES_set_key_unchecked(const_DES_cblock* des, DES_key_schedule* key) + { + } + + + void DES_set_odd_parity(DES_cblock* des) + { + } + + + void DES_ecb_encrypt(DES_cblock* desa, DES_cblock* desb, + DES_key_schedule* key, int len) + { + } + + int BIO_printf(BIO* bio, const char* format, ...) + { + return 0; + } + + + int ASN1_UTCTIME_print(BIO* bio, const ASN1_UTCTIME* a) + { + return 0; + } + + + int sk_num(X509_REVOKED* rev) + { + return 0; + } + + + void* sk_value(X509_REVOKED* rev, int i) + { + return 0; + } + + + /* stunnel 4.28 needs */ + void* SSL_CTX_get_ex_data(const SSL_CTX* ctx, int d) + { + return 0; + } + + + int SSL_CTX_set_ex_data(SSL_CTX* ctx, int d, void* p) + { + return SSL_SUCCESS; + } + + + void SSL_CTX_sess_set_get_cb(SSL_CTX* ctx, SSL_SESSION*(*f)(SSL*, + unsigned char*, int, int*)) + { + + } + + + void SSL_CTX_sess_set_new_cb(SSL_CTX* ctx, int (*f)(SSL*, SSL_SESSION*)) + { + + } + + + void SSL_CTX_sess_set_remove_cb(SSL_CTX* ctx, void (*f)(SSL_CTX*, + SSL_SESSION*)) + { + + } + + + int i2d_SSL_SESSION(SSL_SESSION* sess, unsigned char** p) + { + return sizeof(SSL_SESSION); + } + + + SSL_SESSION* d2i_SSL_SESSION(SSL_SESSION** sess, const unsigned char** p, + long i) + { + return *sess; + } + + + long SSL_SESSION_get_timeout(const SSL_SESSION* sess) + { + return sess->timeout; + } + + + long SSL_SESSION_get_time(const SSL_SESSION* sess) + { + return sess->bornOn; + } + + + int SSL_CTX_get_ex_new_index(long idx, void* arg, void* a, void* b, void* c) + { + return 0; + } + + +#endif /* OPENSSL_EXTRA */ + + +#ifdef SESSION_CERTS + + +/* Get peer's certificate chain */ +X509_CHAIN* CyaSSL_get_peer_chain(SSL* ssl) +{ + if (ssl) + return &ssl->session.chain; + + return 0; +} + + +/* Get peer's certificate chain total count */ +int CyaSSL_get_chain_count(X509_CHAIN* chain) +{ + if (chain) + return chain->count; + + return 0; +} + + +/* Get peer's ASN.1 DER ceritifcate at index (idx) length in bytes */ +int CyaSSL_get_chain_length(X509_CHAIN* chain, int idx) +{ + if (chain) + return chain->certs[idx].length; + + return 0; +} + + +/* Get peer's ASN.1 DER ceritifcate at index (idx) */ +byte* CyaSSL_get_chain_cert(X509_CHAIN* chain, int idx) +{ + if (chain) + return chain->certs[idx].buffer; + + return 0; +} + + +/* Get peer's PEM ceritifcate at index (idx), output to buffer if inLen big + enough else return error (-1), output length is in *outLen */ +int CyaSSL_get_chain_cert_pem(X509_CHAIN* chain, int idx, + unsigned char* buffer, int inLen, int* outLen) +{ + const char header[] = "-----BEGIN CERTIFICATE-----\n"; + const char footer[] = "-----END CERTIFICATE-----\n"; + + int headerLen = sizeof(header) - 1; + int footerLen = sizeof(footer) - 1; + int i; + + if (!chain || !outLen || !buffer) + return -1; + + /* don't even try if inLen too short */ + if (inLen < headerLen + footerLen + chain->certs[idx].length) + return -1; + + /* header */ + XMEMCPY(buffer, header, headerLen); + i = headerLen; + + /* body */ + *outLen = inLen; /* input to Base64Encode */ + if (Base64Encode(chain->certs[idx].buffer, chain->certs[idx].length, + buffer + i, (word32*)outLen) < 0) + return -1; + i += *outLen; + + /* footer */ + if ( (i + footerLen) > inLen) + return -1; + XMEMCPY(buffer + i, footer, footerLen); + *outLen += headerLen + footerLen; + + return 0; +} + + +/* get session ID */ +const byte* CyaSSL_get_sessionID(const SSL_SESSION* session) +{ + return session->sessionID; +} + + +#endif /* SESSION_CERTS */ + diff --git a/release/src/router/cyassl/src/tls.c b/release/src/router/cyassl/src/tls.c new file mode 100644 index 00000000..d6dd003e --- /dev/null +++ b/release/src/router/cyassl/src/tls.c @@ -0,0 +1,457 @@ +/* tls.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "ssl.h" +#include "cyassl_int.h" +#include "cyassl_error.h" +#include "ctc_hmac.h" + + + +#ifndef NO_TLS + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +/* calculate XOR for TLSv1 PRF */ +static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha) +{ + word32 i; + + for (i = 0; i < digLen; i++) + digest[i] = md5[i] ^ sha[i]; +} + + + +/* compute p_hash for MD5, SHA-1, or SHA-256 for TLSv1 PRF */ +void p_hash(byte* result, word32 resLen, const byte* secret, word32 secLen, + const byte* seed, word32 seedLen, int hash) +{ + word32 len = hash == md5_mac ? MD5_DIGEST_SIZE : hash == sha_mac ? + SHA_DIGEST_SIZE : SHA256_DIGEST_SIZE; + word32 times = resLen / len; + word32 lastLen = resLen % len; + word32 lastTime; + word32 i; + word32 idx = 0; + byte previous[SHA256_DIGEST_SIZE]; /* max size */ + byte current[SHA256_DIGEST_SIZE]; /* max size */ + + Hmac hmac; + + if (lastLen) times += 1; + lastTime = times - 1; + + HmacSetKey(&hmac, hash == md5_mac ? MD5 : hash == sha_mac ? SHA : SHA256, + secret, secLen); + HmacUpdate(&hmac, seed, seedLen); /* A0 = seed */ + HmacFinal(&hmac, previous); /* A1 */ + + for (i = 0; i < times; i++) { + HmacUpdate(&hmac, previous, len); + HmacUpdate(&hmac, seed, seedLen); + HmacFinal(&hmac, current); + + if ( (i == lastTime) && lastLen) + XMEMCPY(&result[idx], current, lastLen); + else { + XMEMCPY(&result[idx], current, len); + idx += len; + HmacUpdate(&hmac, previous, len); + HmacFinal(&hmac, previous); + } + } +} + + + +/* compute TLSv1 PRF (pseudo random function using HMAC) */ +static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, + const byte* label, word32 labLen, const byte* seed, word32 seedLen, + int useSha256) +{ + word32 half = (secLen + 1) / 2; + + byte md5_half[MAX_PRF_HALF]; /* half is real size */ + byte sha_half[MAX_PRF_HALF]; /* half is real size */ + byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */ + byte md5_result[MAX_PRF_DIG]; /* digLen is real size */ + byte sha_result[MAX_PRF_DIG]; /* digLen is real size */ + + if (half > MAX_PRF_HALF) + return; + if (labLen + seedLen > MAX_PRF_LABSEED) + return; + if (digLen > MAX_PRF_DIG) + return; + + XMEMCPY(md5_half, secret, half); + XMEMCPY(sha_half, secret + half - secLen % 2, half); + + XMEMCPY(labelSeed, label, labLen); + XMEMCPY(labelSeed + labLen, seed, seedLen); + + if (useSha256) { + p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen, + sha256_mac); + return; + } + + p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen, + md5_mac); + p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen, + sha_mac); + get_xor(digest, digLen, md5_result, sha_result); +} + + +void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender) +{ + const byte* side; + byte handshake_hash[FINISHED_SZ]; + word32 hashSz = FINISHED_SZ; + + Md5Final(&ssl->hashMd5, handshake_hash); + ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]); +#ifndef NO_SHA256 + if (IsAtLeastTLSv1_2(ssl)) { + Sha256Final(&ssl->hashSha256, handshake_hash); + hashSz = SHA256_DIGEST_SIZE; + } +#endif + + if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0) + side = tls_client; + else + side = tls_server; + + PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays.masterSecret, SECRET_LEN, + side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl)); +} + + +ProtocolVersion MakeTLSv1(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_MINOR; + + return pv; +} + + +ProtocolVersion MakeTLSv1_1(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_1_MINOR; + + return pv; +} + + +ProtocolVersion MakeTLSv1_2(void) +{ + ProtocolVersion pv; + pv.major = SSLv3_MAJOR; + pv.minor = TLSv1_2_MINOR; + + return pv; +} + + +static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret"; +static const byte key_label [KEY_LABEL_SZ + 1] = "key expansion"; + + +int DeriveTlsKeys(SSL* ssl) +{ + int length = 2 * ssl->specs.hash_size + + 2 * ssl->specs.key_size + + 2 * ssl->specs.iv_size; + byte seed[SEED_LEN]; + byte key_data[MAX_PRF_DIG]; + + XMEMCPY(seed, ssl->arrays.serverRandom, RAN_LEN); + XMEMCPY(&seed[RAN_LEN], ssl->arrays.clientRandom, RAN_LEN); + + PRF(key_data, length, ssl->arrays.masterSecret, SECRET_LEN, key_label, + KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl)); + + return StoreKeys(ssl, key_data); +} + + +int MakeTlsMasterSecret(SSL* ssl) +{ + byte seed[SEED_LEN]; + + XMEMCPY(seed, ssl->arrays.clientRandom, RAN_LEN); + XMEMCPY(&seed[RAN_LEN], ssl->arrays.serverRandom, RAN_LEN); + + PRF(ssl->arrays.masterSecret, SECRET_LEN, + ssl->arrays.preMasterSecret, ssl->arrays.preMasterSz, + master_label, MASTER_LABEL_SZ, + seed, SEED_LEN, IsAtLeastTLSv1_2(ssl)); + +#ifdef SHOW_SECRETS + { + int i; + printf("master secret: "); + for (i = 0; i < SECRET_LEN; i++) + printf("%02x", ssl->arrays.masterSecret[i]); + printf("\n"); + } +#endif + + return DeriveTlsKeys(ssl); +} + + +/*** next for static INLINE s copied from cyassl_int.c ***/ + +/* convert 16 bit integer to opaque */ +static void INLINE c16toa(word16 u16, byte* c) +{ + c[0] = (u16 >> 8) & 0xff; + c[1] = u16 & 0xff; +} + + +/* convert 32 bit integer to opaque */ +static INLINE void c32toa(word32 u32, byte* c) +{ + c[0] = (u32 >> 24) & 0xff; + c[1] = (u32 >> 16) & 0xff; + c[2] = (u32 >> 8) & 0xff; + c[3] = u32 & 0xff; +} + + +static INLINE word32 GetSEQIncrement(SSL* ssl, int verify) +{ +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + if (verify) + return ssl->keys.dtls_peer_sequence_number; /* explicit from peer */ + else + return ssl->keys.dtls_sequence_number - 1; /* already incremented */ + } +#endif + if (verify) + return ssl->keys.peer_sequence_number++; + else + return ssl->keys.sequence_number++; +} + + +#ifdef CYASSL_DTLS + +static INLINE word32 GetEpoch(SSL* ssl, int verify) +{ + if (verify) + return ssl->keys.dtls_peer_epoch; + else + return ssl->keys.dtls_epoch; +} + +#endif /* CYASSL_DTLS */ + + +static INLINE const byte* GetMacSecret(SSL* ssl, int verify) +{ + if ( (ssl->options.side == CLIENT_END && !verify) || + (ssl->options.side == SERVER_END && verify) ) + return ssl->keys.client_write_MAC_secret; + else + return ssl->keys.server_write_MAC_secret; +} + +/*** end copy ***/ + + +/* TLS type HAMC */ +void TLS_hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz, + int content, int verify) +{ + Hmac hmac; + byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 }; + byte length[LENGTH_SZ]; + byte inner[ENUM_LEN + VERSION_SZ + LENGTH_SZ]; /* type + version +len */ + int type; + + c16toa((word16)sz, length); +#ifdef CYASSL_DTLS + if (ssl->options.dtls) + c16toa(GetEpoch(ssl, verify), seq); +#endif + c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]); + + if (ssl->specs.mac_algorithm == md5_mac) + type = MD5; + else + type = SHA; + HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size); + + HmacUpdate(&hmac, seq, SEQ_SZ); /* seq_num */ + inner[0] = content; /* type */ + inner[ENUM_LEN] = ssl->version.major; + inner[ENUM_LEN + ENUM_LEN] = ssl->version.minor; /* version */ + XMEMCPY(&inner[ENUM_LEN + VERSION_SZ], length, LENGTH_SZ); /* length */ + HmacUpdate(&hmac, inner, sizeof(inner)); + HmacUpdate(&hmac, buffer, sz); /* content */ + HmacFinal(&hmac, digest); +} + + +#ifndef NO_CYASSL_CLIENT + + SSL_METHOD* TLSv1_client_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) + InitSSL_Method(method, MakeTLSv1()); + return method; + } + + + SSL_METHOD* TLSv1_1_client_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) + InitSSL_Method(method, MakeTLSv1_1()); + return method; + } + + + SSL_METHOD* TLSv1_2_client_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) + InitSSL_Method(method, MakeTLSv1_2()); + return method; + } + + + /* TODO: add downgrade */ + SSL_METHOD* SSLv23_client_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) + InitSSL_Method(method, MakeTLSv1()); + return method; + } + + +#endif /* NO_CYASSL_CLIENT */ + + + +#ifndef NO_CYASSL_SERVER + + SSL_METHOD* TLSv1_server_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) { + InitSSL_Method(method, MakeTLSv1()); + method->side = SERVER_END; + } + return method; + } + + + SSL_METHOD* TLSv1_1_server_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) { + InitSSL_Method(method, MakeTLSv1_1()); + method->side = SERVER_END; + } + return method; + } + + + SSL_METHOD* TLSv1_2_server_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) { + InitSSL_Method(method, MakeTLSv1_2()); + method->side = SERVER_END; + } + return method; + } + + + SSL_METHOD *SSLv23_server_method(void) + { + SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, + DYNAMIC_TYPE_METHOD); + if (method) { + InitSSL_Method(method, MakeTLSv1()); + method->side = SERVER_END; + method->downgrade = 1; + } + return method; + } + + + +#endif /* NO_CYASSL_SERVER */ + +#else /* NO_TLS */ + +/* catch CyaSSL programming errors */ +void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender) +{ + +} + + +int DeriveTlsKeys(SSL* ssl) +{ + return -1; +} + + +int MakeTlsMasterSecret(SSL* ssl) +{ + return -1; +} + +#endif /* NO_TLS */ + |