diff options
245 files changed, 32173 insertions, 2061 deletions
diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am index 9f3c55c20d5..d60672e05f8 100644 --- a/BUILD/Makefile.am +++ b/BUILD/Makefile.am @@ -29,6 +29,7 @@ EXTRA_DIST = FINISH.sh \ compile-pentium-debug-max \ compile-pentium-debug-no-bdb \ compile-pentium-debug-openssl \ + compile-pentium-debug-yassl \ compile-pentium-gcov \ compile-pentium-gprof \ compile-pentium-max \ diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index f84dfd4b22d..a507d30e518 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -53,11 +53,14 @@ max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --wit max_no_es_configs="$max_leave_isam_configs --without-isam" max_configs="$max_no_es_configs --with-embedded-server" -alpha_cflags="-mcpu=ev6 -Wa,-mev6" # Not used yet -amd64_cflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES" -pentium_cflags="-mcpu=pentiumpro" -pentium64_cflags="-mcpu=nocona -m64" -ppc_cflags="-mpowerpc -mcpu=powerpc" +path=`dirname $0` +. "$path/check-cpu" + +alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag" +amd64_cflags="$check_cpu_cflags" +pentium_cflags="$check_cpu_cflags" +pentium64_cflags="$check_cpu_cflags -m64" +ppc_cflags="$check_cpu_cflags" sparc_cflags="" # be as fast as we can be without losing our ability to backtrace diff --git a/BUILD/check-cpu b/BUILD/check-cpu new file mode 100755 index 00000000000..553df39191f --- /dev/null +++ b/BUILD/check-cpu @@ -0,0 +1,81 @@ +#!/bin/sh +# +# Check cpu of current machine and find the +# best compiler optimization flags for gcc +# +# + +if test -r /proc/cpuinfo ; then + cpuinfo="cat /proc/cpuinfo" + cpu_family=`$cpuinfo | grep 'family' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + if test -z "$cpu_family" ; then + cpu_family=`$cpuinfo | grep 'cpu' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + fi + cpu_vendor=`$cpuinfo | grep 'vendor_id' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + model_name=`$cpuinfo | grep 'model name' | cut -d ':' -f 2 | head -1` + if test -z "$model_name" ; then + model_name=`$cpuinfo | grep 'cpu model' | cut -d ':' -f 2 | head -1` + fi + if test -z "$model_name" ; then + model_name=`uname -m` + fi +fi + +case "$cpu_family--$model_name" in + Alpha*EV6*) + cpu_flag="ev6"; + ;; + *Xeon*) + cpu_flag="nocona"; + ;; + *Pentium*4*CPU*) + cpu_flag="pentium4"; + ;; + *Athlon*64*) + cpu_flag="athlon64"; + ;; + *Athlon*) + cpu_flag="athlon"; + ;; + *Itanium*) + # Don't need to set any flags for itanium(at the moment) + cpu_flag=""; + ;; + *ppc) + cpu_flag="powerpc"; + ;; + *) + cpu_flag=""; + ;; +esac + +if test -z "$cpu_flag"; then + echo "BUILD/check-cpu: Oops, could not findout what kind of cpu this machine is using." + check_cpu_flags="" + return +fi + +echo "cpu_flag: $cpu_flag" + +if test -z "$CC" ; then + cc="gcc"; +else + cc=$CC + +fi + +cc_ver=`$cc --version | sed 1q` +cc_verno=`echo $cc_ver | sed -e 's/[^0-9. ]//g; s/^ *//g; s/ .*//g'` + +case "$cc_ver--$cc_verno" in + *GCC*--3.4*|*GCC*--3.5*|*GCC*--4.*) + check_cpu_cflags="-mtune=$cpu_flag -march=$cpu_flag" + ;; + *GCC*) + check_cpu_cflags="-mcpu=$cpu_flag -march=$cpu_flag" + ;; + *) + check_cpu_cflags="" + ;; +esac +echo $check_cpu_cflags diff --git a/BUILD/compile-pentium-debug-yassl b/BUILD/compile-pentium-debug-yassl new file mode 100755 index 00000000000..666e73d0267 --- /dev/null +++ b/BUILD/compile-pentium-debug-yassl @@ -0,0 +1,13 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $debug_cflags" +c_warnings="$c_warnings $debug_extra_warnings" +cxx_warnings="$cxx_warnings $debug_extra_warnings" +extra_configs="$pentium_configs $debug_configs" + +extra_configs="$extra_configs --with-debug=full --with-yassl" + +. "$path/FINISH.sh" diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index e706a3358d5..346dcae3cfd 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -50,6 +50,8 @@ dlenev@build.mysql.com dlenev@jabberwock.localdomain dlenev@mysql.com ejonore@mc03.ndb.mysql.com +evgen@moonbone.(none) +evgen@moonbone.local gbichot@production.mysql.com gbichot@quadita2.mysql.com gbichot@quadxeon.mysql.com diff --git a/Makefile.am b/Makefile.am index 78efd47b762..eec27484710 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ AUTOMAKE_OPTIONS = foreign # These are built from source in the Docs directory EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT -SUBDIRS = . include @docs_dirs@ @zlib_dir@ \ +SUBDIRS = . include @docs_dirs@ @zlib_dir@ @yassl_dir@ \ @readline_topdir@ sql-common \ @thread_dirs@ pstack \ @sql_union_dirs@ scripts man tests \ @@ -102,5 +102,10 @@ tags: test: cd mysql-test; ./mysql-test-run && ./mysql-test-run --ps-protocol +test-force: + cd mysql-test; \ + mysql-test-run --force ;\ + mysql-test-run --ps-protocol --force + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/client/Makefile.am b/client/Makefile.am index 58dcebfd852..791da2760a5 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -30,10 +30,10 @@ noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \ mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc mysqladmin_SOURCES = mysqladmin.cc mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS) -mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS) mysqltest_SOURCES= mysqltest.c $(top_srcdir)/mysys/my_getsystime.c mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) -mysqlbinlog_SOURCES = mysqlbinlog.cc $(top_srcdir)/mysys/mf_tempdir.c +mysqlbinlog_SOURCES = mysqlbinlog.cc $(top_srcdir)/mysys/mf_tempdir.c $(top_srcdir)/mysys/my_new.cc +mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS) mysqltestmanagerc_SOURCES = mysqlmanagerc.c mysqltestmanager_pwgen_SOURCES = mysqlmanager-pwgen.c sql_src=log_event.h mysql_priv.h log_event.cc my_decimal.h my_decimal.cc diff --git a/client/mysql.cc b/client/mysql.cc index 4eed4349b45..5282f74453d 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -703,8 +703,16 @@ static void usage(int version) #ifdef __NETWARE__ #define printf consoleprintf #endif - printf("%s Ver %s Distrib %s, for %s (%s)\n", - my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + +#if defined(USE_LIBEDIT_INTERFACE) + const char* readline= ""; +#else + const char* readline= "readline"; +#endif + + printf("%s Ver %s Distrib %s, for %s (%s) using %s %s\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE, + readline, rl_library_version); if (version) return; printf("\ @@ -1323,7 +1331,7 @@ static void initialize_readline (char *name) setlocale(LC_ALL,""); /* so as libedit use isprint */ #endif rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; - rl_completion_entry_function= (CPFunction*)&no_completion; + rl_completion_entry_function= (Function*)&no_completion; #else rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; rl_completion_entry_function= (Function*)&no_completion; diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 24fe14b6675..32e0dfdb837 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -727,7 +727,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) void (*func) (MYSQL_RES*, MYSQL_ROW, uint); new_line = 1; - if (mysql_query(mysql, "show status") || + if (mysql_query(mysql, "show /*!50002 GLOBAL */ status") || !(res = mysql_store_result(mysql))) { my_printf_error(0, "unable to show status; error: '%s'", MYF(ME_BELL), @@ -1346,6 +1346,3 @@ static my_bool wait_pidfile(char *pidfile, time_t last_modified, } DBUG_RETURN(error); } -#ifdef __GNUC__ -FIX_GCC_LINKING_PROBLEM -#endif diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 59c90f59e8e..1a628bd08c7 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1458,4 +1458,3 @@ int main(int argc, char** argv) #include "log_event.cc" #endif -FIX_GCC_LINKING_PROBLEM diff --git a/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c index 62a407e66a8..21fc8bc2c1d 100644 --- a/cmd-line-utils/libedit/chared.c +++ b/cmd-line-utils/libedit/chared.c @@ -1,4 +1,4 @@ -/* $NetBSD: chared.c,v 1.18 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: chared.c,v 1.22 2004/08/13 12:10:38 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: chared.c,v 1.18 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * chared.c: Character editor utilities @@ -62,13 +51,13 @@ cv_undo(EditLine *el) { c_undo_t *vu = &el->el_chared.c_undo; c_redo_t *r = &el->el_chared.c_redo; - int size; + uint size; /* Save entire line for undo */ size = el->el_line.lastchar - el->el_line.buffer; vu->len = size; vu->cursor = el->el_line.cursor - el->el_line.buffer; - memcpy(vu->buf, el->el_line.buffer, (size_t)size); + memcpy(vu->buf, el->el_line.buffer, size); /* save command info for redo */ r->count = el->el_state.doingarg ? el->el_state.argument : 0; @@ -139,6 +128,21 @@ c_delafter(EditLine *el, int num) } +/* c_delafter1(): + * Delete the character after the cursor, do not yank + */ +protected void +c_delafter1(EditLine *el) +{ + char *cp; + + for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) + *cp = cp[1]; + + el->el_line.lastchar--; +} + + /* c_delbefore(): * Delete num characters before the cursor */ @@ -167,6 +171,21 @@ c_delbefore(EditLine *el, int num) } +/* c_delbefore1(): + * Delete the character before the cursor, do not yank + */ +protected void +c_delbefore1(EditLine *el) +{ + char *cp; + + for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++) + *cp = cp[1]; + + el->el_line.lastchar--; +} + + /* ce__isword(): * Return if p is part of a word according to emacs */ @@ -460,8 +479,8 @@ ch_init(EditLine *el) el->el_state.argument = 1; el->el_state.lastcmd = ED_UNASSIGNED; - el->el_chared.c_macro.nline = NULL; el->el_chared.c_macro.level = -1; + el->el_chared.c_macro.offset = 0; el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO * sizeof(char *)); if (el->el_chared.c_macro.macro == NULL) @@ -582,7 +601,7 @@ ch_enlargebufs(el, addlen) return 0; /* Safe to set enlarged buffer size */ - el->el_line.limit = &newbuffer[newsz - EL_LEAVE]; + el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE]; return 1; } diff --git a/cmd-line-utils/libedit/chared.h b/cmd-line-utils/libedit/chared.h index d2e6f742413..2dd0a5795c7 100644 --- a/cmd-line-utils/libedit/chared.h +++ b/cmd-line-utils/libedit/chared.h @@ -1,4 +1,4 @@ -/* $NetBSD: chared.h,v 1.11 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: chared.h,v 1.14 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -66,8 +62,8 @@ typedef struct c_macro_t { int level; + int offset; char **macro; - char *nline; } c_macro_t; /* @@ -158,7 +154,9 @@ protected char *c__next_word(char *, char *, int, int (*)(int)); protected char *c__prev_word(char *, char *, int, int (*)(int)); protected void c_insert(EditLine *, int); protected void c_delbefore(EditLine *, int); +protected void c_delbefore1(EditLine *); protected void c_delafter(EditLine *, int); +protected void c_delafter1(EditLine *); protected int c_gets(EditLine *, char *, const char *); protected int c_hpos(EditLine *); diff --git a/cmd-line-utils/libedit/common.c b/cmd-line-utils/libedit/common.c index f290057568a..81bf9bf29ff 100644 --- a/cmd-line-utils/libedit/common.c +++ b/cmd-line-utils/libedit/common.c @@ -1,4 +1,4 @@ -/* $NetBSD: common.c,v 1.14 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: common.c,v 1.16 2003/08/07 16:44:30 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: common.c,v 1.14 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * common.c: Common Editor functions @@ -56,7 +45,7 @@ __RCSID("$NetBSD: common.c,v 1.14 2002/11/20 16:50:08 christos Exp $"); */ protected el_action_t /*ARGSUSED*/ -ed_end_of_file(EditLine *el, int c __attribute__((unused))) +ed_end_of_file(EditLine *el, int c __attribute__((__unused__))) { re_goto_bottom(el); @@ -113,7 +102,7 @@ ed_insert(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_word(EditLine *el, int c __attribute__((unused))) +ed_delete_prev_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *p, *kp; @@ -141,7 +130,7 @@ ed_delete_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_delete_next_char(EditLine *el, int c __attribute__((unused))) +ed_delete_next_char(EditLine *el, int c __attribute__((__unused__))) { #ifdef notdef /* XXX */ #define EL el->el_line @@ -192,7 +181,7 @@ ed_delete_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_kill_line(EditLine *el, int c __attribute__((unused))) +ed_kill_line(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -213,7 +202,7 @@ ed_kill_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_end(EditLine *el, int c __attribute__((unused))) +ed_move_to_end(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.lastchar; @@ -236,7 +225,7 @@ ed_move_to_end(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_beg(EditLine *el, int c __attribute__((unused))) +ed_move_to_beg(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; @@ -285,7 +274,7 @@ ed_transpose_chars(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_next_char(EditLine *el, int c __attribute__((unused))) +ed_next_char(EditLine *el, int c __attribute__((__unused__))) { char *lim = el->el_line.lastchar; @@ -314,7 +303,7 @@ ed_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_word(EditLine *el, int c __attribute__((unused))) +ed_prev_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) @@ -340,7 +329,7 @@ ed_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_char(EditLine *el, int c __attribute__((unused))) +ed_prev_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor > el->el_line.buffer) { @@ -437,8 +426,7 @@ ed_argument_digit(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_unassigned(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_unassigned(EditLine *el, int c __attribute__((__unused__))) { return (CC_ERROR); @@ -455,8 +443,8 @@ ed_unassigned(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigint(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_sigint(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -469,8 +457,8 @@ ed_tty_sigint(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_dsusp(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_dsusp(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -483,8 +471,8 @@ ed_tty_dsusp(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_flush_output(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_flush_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -497,8 +485,8 @@ ed_tty_flush_output(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigquit(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_sigquit(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -511,8 +499,8 @@ ed_tty_sigquit(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigtstp(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -525,8 +513,8 @@ ed_tty_sigtstp(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_stop_output(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_stop_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -539,8 +527,8 @@ ed_tty_stop_output(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_start_output(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_start_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -553,7 +541,7 @@ ed_tty_start_output(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_newline(EditLine *el, int c __attribute__((unused))) +ed_newline(EditLine *el, int c __attribute__((__unused__))) { re_goto_bottom(el); @@ -569,7 +557,7 @@ ed_newline(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_char(EditLine *el, int c __attribute__((unused))) +ed_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor <= el->el_line.buffer) @@ -589,7 +577,7 @@ ed_delete_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_clear_screen(EditLine *el, int c __attribute__((unused))) +ed_clear_screen(EditLine *el, int c __attribute__((__unused__))) { term_clear_screen(el); /* clear the whole real screen */ @@ -604,8 +592,8 @@ ed_clear_screen(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_redisplay(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_redisplay(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_REDISPLAY); @@ -618,7 +606,7 @@ ed_redisplay(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_start_over(EditLine *el, int c __attribute__((unused))) +ed_start_over(EditLine *el, int c __attribute__((__unused__))) { ch_reset(el); @@ -632,8 +620,8 @@ ed_start_over(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_sequence_lead_in(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -646,7 +634,7 @@ ed_sequence_lead_in(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_prev_history(EditLine *el, int c __attribute__((unused))) +ed_prev_history(EditLine *el, int c __attribute__((__unused__))) { char beep = 0; int sv_event = el->el_history.eventno; @@ -684,7 +672,7 @@ ed_prev_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_next_history(EditLine *el, int c __attribute__((unused))) +ed_next_history(EditLine *el, int c __attribute__((__unused__))) { el_action_t beep = CC_REFRESH, rval; @@ -711,7 +699,7 @@ ed_next_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_search_prev_history(EditLine *el, int c __attribute__((unused))) +ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) { const char *hp; int h; @@ -779,7 +767,7 @@ ed_search_prev_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_search_next_history(EditLine *el, int c __attribute__((unused))) +ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) { const char *hp; int h; @@ -833,7 +821,7 @@ ed_search_next_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_line(EditLine *el, int c __attribute__((unused))) +ed_prev_line(EditLine *el, int c __attribute__((__unused__))) { char *ptr; int nchars = c_hpos(el); @@ -876,7 +864,7 @@ ed_prev_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_next_line(EditLine *el, int c __attribute__((unused))) +ed_next_line(EditLine *el, int c __attribute__((__unused__))) { char *ptr; int nchars = c_hpos(el); @@ -910,7 +898,7 @@ ed_next_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_command(EditLine *el, int c __attribute__((unused))) +ed_command(EditLine *el, int c __attribute__((__unused__))) { char tmpbuf[EL_BUFSIZ]; int tmplen; diff --git a/cmd-line-utils/libedit/el.c b/cmd-line-utils/libedit/el.c index 1b445d40f1c..c32a01b2151 100644 --- a/cmd-line-utils/libedit/el.c +++ b/cmd-line-utils/libedit/el.c @@ -1,4 +1,4 @@ -/* $NetBSD: el.c,v 1.30 2002/11/12 00:00:23 thorpej Exp $ */ +/* $NetBSD: el.c,v 1.39 2004/07/08 00:51:36 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; -#else -__RCSID("$NetBSD: el.c,v 1.30 2002/11/12 00:00:23 thorpej Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * el.c: EditLine interface functions @@ -72,7 +61,10 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) el->el_infd = fileno(fin); el->el_outfile = fout; el->el_errfile = ferr; - el->el_prog = strdup(prog); + if ((el->el_prog = el_strdup(prog)) == NULL) { + el_free(el); + return NULL; + } /* * Initialize all the modules. Order is important!!! @@ -80,11 +72,11 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) el->el_flags = 0; if (term_init(el) == -1) { - free(el->el_prog); + el_free(el->el_prog); el_free(el); return NULL; } - (void) el_key_init(el); + (void) key_init(el); (void) map_init(el); if (tty_init(el) == -1) el->el_flags |= NO_TTY; @@ -112,7 +104,7 @@ el_end(EditLine *el) el_reset(el); term_end(el); - el_key_end(el); + key_end(el); map_end(el); tty_end(el); ch_end(el); @@ -257,6 +249,27 @@ el_set(EditLine *el, int op, ...) el->el_data = va_arg(va, void *); break; + case EL_UNBUFFERED: + rv = va_arg(va, int); + if (rv && !(el->el_flags & UNBUFFERED)) { + el->el_flags |= UNBUFFERED; + read_prepare(el); + } else if (!rv && (el->el_flags & UNBUFFERED)) { + el->el_flags &= ~UNBUFFERED; + read_finish(el); + } + rv = 0; + break; + + case EL_PREP_TERM: + rv = va_arg(va, int); + if (rv) + (void) tty_rawmode(el); + else + (void) tty_cookedmode(el); + rv = 0; + break; + default: rv = -1; break; @@ -297,21 +310,22 @@ el_get(EditLine *el, int op, void *ret) rv = 0; break; -#if 0 /* XXX */ case EL_TERMINAL: - rv = term_get(el, (const char *) &ret); + term_get(el, (const char **)ret); + rv = 0; break; +#if 0 /* XXX */ case EL_BIND: case EL_TELLTC: case EL_SETTC: case EL_ECHOTC: case EL_SETTY: { - char *argv[20]; + const char *argv[20]; int i; - for (i = 1; i < 20; i++) + for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++) if ((argv[i] = va_arg(va, char *)) == NULL) break; @@ -378,6 +392,11 @@ el_get(EditLine *el, int op, void *ret) rv = 0; break; + case EL_UNBUFFERED: + *((int *) ret) = (!(el->el_flags & UNBUFFERED)); + rv = 0; + break; + default: rv = -1; } @@ -409,12 +428,17 @@ el_source(EditLine *el, const char *fname) fp = NULL; if (fname == NULL) { -#ifdef HAVE_ISSETUGID static const char elpath[] = "/.editrc"; +#ifdef MAXPATHLEN char path[MAXPATHLEN]; +#else + char path[4096]; +#endif +#ifdef HAVE_ISSETUGID if (issetugid()) return (-1); +#endif if ((ptr = getenv("HOME")) == NULL) return (-1); if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path)) @@ -422,14 +446,6 @@ el_source(EditLine *el, const char *fname) if (strlcat(path, elpath, sizeof(path)) >= sizeof(path)) return (-1); fname = path; -#else - /* - * If issetugid() is missing, always return an error, in order - * to keep from inadvertently opening up the user to a security - * hole. - */ - return (-1); -#endif } if (fp == NULL) fp = fopen(fname, "r"); @@ -496,10 +512,13 @@ el_editmode(EditLine *el, int argc, const char **argv) return (-1); how = argv[1]; - if (strcmp(how, "on") == 0) + if (strcmp(how, "on") == 0) { el->el_flags &= ~EDIT_DISABLED; - else if (strcmp(how, "off") == 0) + tty_rawmode(el); + } else if (strcmp(how, "off") == 0) { + tty_cookedmode(el); el->el_flags |= EDIT_DISABLED; + } else { (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how); return (-1); diff --git a/cmd-line-utils/libedit/el.h b/cmd-line-utils/libedit/el.h index 49bd462ad3b..c4b6cff2186 100644 --- a/cmd-line-utils/libedit/el.h +++ b/cmd-line-utils/libedit/el.h @@ -1,4 +1,4 @@ -/* $NetBSD: el.h,v 1.13 2002/11/15 14:32:33 christos Exp $ */ +/* $NetBSD: el.h,v 1.16 2003/10/18 23:48:42 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -55,9 +51,10 @@ #define EL_BUFSIZ 1024 /* Maximum line size */ -#define HANDLE_SIGNALS 1<<0 -#define NO_TTY 1<<1 -#define EDIT_DISABLED 1<<2 +#define HANDLE_SIGNALS 0x01 +#define NO_TTY 0x02 +#define EDIT_DISABLED 0x04 +#define UNBUFFERED 0x08 typedef int bool_t; /* True or not */ @@ -91,6 +88,7 @@ typedef struct el_state_t { /* * Until we come up with something better... */ +#define el_strdup(a) strdup(a) #define el_malloc(a) malloc(a) #define el_realloc(a,b) realloc(a, b) #define el_free(a) free(a) @@ -98,7 +96,7 @@ typedef struct el_state_t { #include "tty.h" #include "prompt.h" #include "key.h" -#include "libedit_term.h" +#include "el_term.h" #include "refresh.h" #include "chared.h" #include "common.h" diff --git a/cmd-line-utils/libedit/el_term.h b/cmd-line-utils/libedit/el_term.h new file mode 100644 index 00000000000..9e5588ee96f --- /dev/null +++ b/cmd-line-utils/libedit/el_term.h @@ -0,0 +1,131 @@ +/* $NetBSD: term.h,v 1.15 2003/09/14 21:48:55 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)term.h 8.1 (Berkeley) 6/4/93 + */ + +/* + * el.term.h: Termcap header + */ +#ifndef _h_el_term +#define _h_el_term + +#include "histedit.h" + +typedef struct { /* Symbolic function key bindings */ + const char *name; /* name of the key */ + int key; /* Index in termcap table */ + key_value_t fun; /* Function bound to it */ + int type; /* Type of function */ +} fkey_t; + +typedef struct { + const char *t_name; /* the terminal name */ + coord_t t_size; /* # lines and cols */ + int t_flags; +#define TERM_CAN_INSERT 0x001 /* Has insert cap */ +#define TERM_CAN_DELETE 0x002 /* Has delete cap */ +#define TERM_CAN_CEOL 0x004 /* Has CEOL cap */ +#define TERM_CAN_TAB 0x008 /* Can use tabs */ +#define TERM_CAN_ME 0x010 /* Can turn all attrs. */ +#define TERM_CAN_UP 0x020 /* Can move up */ +#define TERM_HAS_META 0x040 /* Has a meta key */ +#define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */ +#define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */ + char *t_buf; /* Termcap buffer */ + int t_loc; /* location used */ + char **t_str; /* termcap strings */ + int *t_val; /* termcap values */ + char *t_cap; /* Termcap buffer */ + fkey_t *t_fkey; /* Array of keys */ +} el_term_t; + +/* + * fKey indexes + */ +#define A_K_DN 0 +#define A_K_UP 1 +#define A_K_LT 2 +#define A_K_RT 3 +#define A_K_HO 4 +#define A_K_EN 5 +#define A_K_NKEYS 6 + +#ifdef _SUNOS +extern int tgetent(char *, const char *); +extern int tgetflag(char *); +extern int tgetnum(char *); +extern int tputs(const char *, int, int (*)(int)); +extern char* tgoto(const char*, int, int); +extern char* tgetstr(char*, char**); +#endif + +protected void term_move_to_line(EditLine *, int); +protected void term_move_to_char(EditLine *, int); +protected void term_clear_EOL(EditLine *, int); +protected void term_overwrite(EditLine *, const char *, int); +protected void term_insertwrite(EditLine *, char *, int); +protected void term_deletechars(EditLine *, int); +protected void term_clear_screen(EditLine *); +protected void term_beep(EditLine *); +protected int term_change_size(EditLine *, int, int); +protected int term_get_size(EditLine *, int *, int *); +protected int term_init(EditLine *); +protected void term_bind_arrow(EditLine *); +protected void term_print_arrow(EditLine *, const char *); +protected int term_clear_arrow(EditLine *, const char *); +protected int term_set_arrow(EditLine *, const char *, key_value_t *, int); +protected void term_end(EditLine *); +protected void term_get(EditLine *, const char **); +protected int term_set(EditLine *, const char *); +protected int term_settc(EditLine *, int, const char **); +protected int term_telltc(EditLine *, int, const char **); +protected int term_echotc(EditLine *, int, const char **); +protected int term__putc(int); +protected void term__flush(void); + +/* + * Easy access macros + */ +#define EL_FLAGS (el)->el_term.t_flags + +#define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT) +#define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE) +#define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL) +#define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB) +#define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME) +#define EL_HAS_META (EL_FLAGS & TERM_HAS_META) +#define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS) +#define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS) + +#endif /* _h_el_term */ diff --git a/cmd-line-utils/libedit/emacs.c b/cmd-line-utils/libedit/emacs.c index d58d1620693..79f2bf0c818 100644 --- a/cmd-line-utils/libedit/emacs.c +++ b/cmd-line-utils/libedit/emacs.c @@ -1,4 +1,4 @@ -/* $NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 christos Exp $ */ +/* $NetBSD: emacs.c,v 1.19 2004/10/28 21:14:52 dsl Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * emacs.c: Emacs functions @@ -56,7 +45,7 @@ __RCSID("$NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 christos Exp $"); */ protected el_action_t /*ARGSUSED*/ -em_delete_or_list(EditLine *el, int c __attribute__((unused))) +em_delete_or_list(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) { @@ -75,7 +64,10 @@ em_delete_or_list(EditLine *el, int c __attribute__((unused))) return (CC_ERROR); } } else { - c_delafter(el, el->el_state.argument); /* delete after dot */ + if (el->el_state.doingarg) + c_delafter(el, el->el_state.argument); + else + c_delafter1(el); if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; /* bounds check */ @@ -90,7 +82,7 @@ em_delete_or_list(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_delete_next_word(EditLine *el, int c __attribute__((unused))) +em_delete_next_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *p, *kp; @@ -119,14 +111,12 @@ em_delete_next_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_yank(EditLine *el, int c __attribute__((unused))) +em_yank(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; - if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) { - if (!ch_enlargebufs(el, 1)) - return (CC_ERROR); - } + if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) + return (CC_NORM); if (el->el_line.lastchar + (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >= @@ -156,7 +146,7 @@ em_yank(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_kill_line(EditLine *el, int c __attribute__((unused))) +em_kill_line(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -178,7 +168,7 @@ em_kill_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_kill_region(EditLine *el, int c __attribute__((unused))) +em_kill_region(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -211,7 +201,7 @@ em_kill_region(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_copy_region(EditLine *el, int c __attribute__((unused))) +em_copy_region(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -235,12 +225,12 @@ em_copy_region(EditLine *el, int c __attribute__((unused))) } -/* em_gosmacs_traspose(): +/* em_gosmacs_transpose(): * Exchange the two characters before the cursor * Gosling emacs transpose chars [^T] */ protected el_action_t -em_gosmacs_traspose(EditLine *el, int c) +em_gosmacs_transpose(EditLine *el, int c) { if (el->el_line.cursor > &el->el_line.buffer[1]) { @@ -260,7 +250,7 @@ em_gosmacs_traspose(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_next_word(EditLine *el, int c __attribute__((unused))) +em_next_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) return (CC_ERROR); @@ -285,7 +275,7 @@ em_next_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_upper_case(EditLine *el, int c __attribute__((unused))) +em_upper_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -293,8 +283,8 @@ em_upper_case(EditLine *el, int c __attribute__((unused))) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (islower((unsigned char) *cp)) - *cp = toupper(*cp); + if (islower((unsigned char)*cp)) + *cp = toupper((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -309,7 +299,7 @@ em_upper_case(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_capitol_case(EditLine *el, int c __attribute__((unused))) +em_capitol_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -317,16 +307,16 @@ em_capitol_case(EditLine *el, int c __attribute__((unused))) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) { - if (isalpha((unsigned char) *cp)) { - if (islower((unsigned char) *cp)) - *cp = toupper(*cp); + if (isalpha((unsigned char)*cp)) { + if (islower((unsigned char)*cp)) + *cp = toupper((unsigned char)*cp); cp++; break; } } for (; cp < ep; cp++) - if (isupper((unsigned char) *cp)) - *cp = tolower(*cp); + if (isupper((unsigned char)*cp)) + *cp = tolower((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -341,7 +331,7 @@ em_capitol_case(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_lower_case(EditLine *el, int c __attribute__((unused))) +em_lower_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -349,8 +339,8 @@ em_lower_case(EditLine *el, int c __attribute__((unused))) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (isupper((unsigned char) *cp)) - *cp = tolower(*cp); + if (isupper((unsigned char)*cp)) + *cp = tolower((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -365,7 +355,7 @@ em_lower_case(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_set_mark(EditLine *el, int c __attribute__((unused))) +em_set_mark(EditLine *el, int c __attribute__((__unused__))) { el->el_chared.c_kill.mark = el->el_line.cursor; @@ -379,7 +369,7 @@ em_set_mark(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_exchange_mark(EditLine *el, int c __attribute__((unused))) +em_exchange_mark(EditLine *el, int c __attribute__((__unused__))) { char *cp; @@ -396,7 +386,7 @@ em_exchange_mark(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_universal_argument(EditLine *el, int c __attribute__((unused))) +em_universal_argument(EditLine *el, int c __attribute__((__unused__))) { /* multiply current argument by 4 */ if (el->el_state.argument > 1000000) @@ -413,7 +403,7 @@ em_universal_argument(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_meta_next(EditLine *el, int c __attribute__((unused))) +em_meta_next(EditLine *el, int c __attribute__((__unused__))) { el->el_state.metanext = 1; @@ -426,7 +416,7 @@ em_meta_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_toggle_overwrite(EditLine *el, int c __attribute__((unused))) +em_toggle_overwrite(EditLine *el, int c __attribute__((__unused__))) { el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ? @@ -440,7 +430,7 @@ em_toggle_overwrite(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_copy_prev_word(EditLine *el, int c __attribute__((unused))) +em_copy_prev_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *oldc, *dp; @@ -467,7 +457,7 @@ em_copy_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_next(EditLine *el, int c __attribute__((unused))) +em_inc_search_next(EditLine *el, int c __attribute__((__unused__))) { el->el_search.patlen = 0; @@ -480,9 +470,32 @@ em_inc_search_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_prev(EditLine *el, int c __attribute__((unused))) +em_inc_search_prev(EditLine *el, int c __attribute__((__unused__))) { el->el_search.patlen = 0; return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); } + + +/* em_delete_prev_char(): + * Delete the character to the left of the cursor + * [^?] + */ +protected el_action_t +/*ARGSUSED*/ +em_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) +{ + + if (el->el_line.cursor <= el->el_line.buffer) + return (CC_ERROR); + + if (el->el_state.doingarg) + c_delbefore(el, el->el_state.argument); + else + c_delbefore1(el); + el->el_line.cursor -= el->el_state.argument; + if (el->el_line.cursor < el->el_line.buffer) + el->el_line.cursor = el->el_line.buffer; + return (CC_REFRESH); +} diff --git a/cmd-line-utils/libedit/fgetln.c b/cmd-line-utils/libedit/fgetln.c index 4f7416a4c8d..5b95b2f6584 100644 --- a/cmd-line-utils/libedit/fgetln.c +++ b/cmd-line-utils/libedit/fgetln.c @@ -1,109 +1,88 @@ +/* $NetBSD: fgetln.c,v 1.2 2003/12/10 01:30:27 lukem Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <config.h> #include <stdio.h> -#include "compat.h" +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> -#ifndef HAVE_FGETLN -#ifdef HAVE_GETLINE - -extern int getline (char **lineptr, size_t *n, FILE *stream); - -#else - -/* The interface here is that of GNU libc's getline */ -static int -getline (char **lineptr, size_t *n, FILE *stream) +char * +fgetln(FILE *fp, size_t *len) { -#define EXPAND_CHUNK 16 - - int n_read = 0; - char *line = *lineptr; - - if (lineptr == NULL) return -1; - if (n == NULL) return -1; - if (stream == NULL) return -1; - if (*lineptr == NULL || *n == 0) return -1; - -#ifdef HAVE_FLOCKFILE - flockfile (stream); -#endif - - while (1) - { - int c; - -#ifdef HAVE_FLOCKFILE - c = getc_unlocked (stream); -#else - c = getc (stream); -#endif - - if (c == EOF) - { - if (n_read > 0) - line[n_read] = '\0'; - break; - } - - if (n_read + 2 >= *n) - { - size_t new_size; - - if (*n == 0) - new_size = 16; - else - new_size = *n * 2; - - if (*n >= new_size) /* Overflowed size_t */ - line = NULL; - else - line = (char *) (*lineptr ? (char*) realloc(*lineptr, new_size) : - (char*) malloc(new_size)); - - if (line) - { - *lineptr = line; - *n = new_size; - } - else - { - if (*n > 0) - { - (*lineptr)[*n - 1] = '\0'; - n_read = *n - 2; - } - break; - } - } - - line[n_read] = c; - n_read++; - - if (c == '\n') - { - line[n_read] = '\0'; - break; - } - } - -#ifdef HAVE_FLOCKFILE - funlockfile (stream); -#endif - - return n_read - 1; + static char *buf = NULL; + static size_t bufsiz = 0; + char *ptr; + + + if (buf == NULL) { + bufsiz = BUFSIZ; + if ((buf = malloc(bufsiz)) == NULL) + return NULL; + } + + if (fgets(buf, bufsiz, fp) == NULL) + return NULL; + *len = 0; + + while ((ptr = strchr(&buf[*len], '\n')) == NULL) { + size_t nbufsiz = bufsiz + BUFSIZ; + char *nbuf = realloc(buf, nbufsiz); + + if (nbuf == NULL) { + int oerrno = errno; + free(buf); + errno = oerrno; + buf = NULL; + return NULL; + } else + buf = nbuf; + + *len = bufsiz; + if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) + return buf; + + bufsiz = nbufsiz; + } + + *len = (ptr - buf) + 1; + return buf; } -#endif /* ! HAVE_GETLINE */ -char *fgetln(FILE *stream, size_t *len) -{ - char *ptr = NULL; - int sz; - size_t length= 0; - - sz = getline(&ptr, &length, stream); - if(len) { - *len = sz; - } - - return sz >= 0 ? ptr : NULL; -} -#endif diff --git a/cmd-line-utils/libedit/hist.c b/cmd-line-utils/libedit/hist.c index 59c2f39dd34..e8f5c0f39ba 100644 --- a/cmd-line-utils/libedit/hist.c +++ b/cmd-line-utils/libedit/hist.c @@ -1,4 +1,4 @@ -/* $NetBSD: hist.c,v 1.12 2003/01/21 18:40:23 christos Exp $ */ +/* $NetBSD: hist.c,v 1.15 2003/11/01 23:36:39 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: hist.c,v 1.12 2003/01/21 18:40:23 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * hist.c: History access functions @@ -157,7 +146,6 @@ hist_get(EditLine *el) * process a history command */ protected int -/*ARGSUSED*/ hist_command(EditLine *el, int argc, const char **argv) { const char *str; @@ -167,7 +155,7 @@ hist_command(EditLine *el, int argc, const char **argv) if (el->el_history.ref == NULL) return (-1); - if (argc == 0 || strcmp(argv[0], "list") == 1) { + if (argc == 1 || strcmp(argv[1], "list") == 0) { /* List history entries */ for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el)) @@ -176,15 +164,15 @@ hist_command(EditLine *el, int argc, const char **argv) return (0); } - if (argc != 2) + if (argc != 3) return (-1); - num = (int)strtol(argv[1], NULL, 0); + num = (int)strtol(argv[2], NULL, 0); - if (strcmp(argv[0], "size") == 0) + if (strcmp(argv[1], "size") == 0) return history(el->el_history.ref, &ev, H_SETSIZE, num); - if (strcmp(argv[0], "unique") == 0) + if (strcmp(argv[1], "unique") == 0) return history(el->el_history.ref, &ev, H_SETUNIQUE, num); return -1; diff --git a/cmd-line-utils/libedit/hist.h b/cmd-line-utils/libedit/hist.h index b713281b382..46e14634adf 100644 --- a/cmd-line-utils/libedit/hist.h +++ b/cmd-line-utils/libedit/hist.h @@ -1,4 +1,4 @@ -/* $NetBSD: hist.h,v 1.9 2003/01/21 18:40:23 christos Exp $ */ +/* $NetBSD: hist.h,v 1.10 2003/08/07 16:44:31 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/histedit.h b/cmd-line-utils/libedit/histedit.h index 3137bd680a7..c58eb62dcfa 100644 --- a/cmd-line-utils/libedit/histedit.h +++ b/cmd-line-utils/libedit/histedit.h @@ -1,4 +1,4 @@ -/* $NetBSD: histedit.h,v 1.21 2003/01/21 18:40:24 christos Exp $ */ +/* $NetBSD: histedit.h,v 1.25 2003/12/05 13:37:48 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -45,7 +41,7 @@ #define _HISTEDIT_H_ #define LIBEDIT_MAJOR 2 -#define LIBEDIT_MINOR 6 +#define LIBEDIT_MINOR 9 #include <sys/types.h> #include <stdio.h> @@ -53,6 +49,7 @@ /* * ==== Editing ==== */ + typedef struct editline EditLine; /* @@ -64,7 +61,6 @@ typedef struct lineinfo { const char *lastchar; } LineInfo; - /* * EditLine editor function return codes. * For user-defined function interface @@ -84,9 +80,8 @@ typedef struct lineinfo { * Initialization, cleanup, and resetting */ EditLine *el_init(const char *, FILE *, FILE *, FILE *); -void el_reset(EditLine *); void el_end(EditLine *); - +void el_reset(EditLine *); /* * Get a line, a character or push a string back in the input queue @@ -131,6 +126,8 @@ int el_get(EditLine *, int, void *); #define EL_RPROMPT 12 /* , el_pfunc_t); */ #define EL_GETCFN 13 /* , el_rfunc_t); */ #define EL_CLIENTDATA 14 /* , void *); */ +#define EL_UNBUFFERED 15 /* , int); */ +#define EL_PREP_TERM 16 /* , int); */ #define EL_BUILTIN_GETCFN (NULL) @@ -146,7 +143,6 @@ int el_source(EditLine *, const char *); */ void el_resize(EditLine *); - /* * User-defined function interface. */ @@ -154,6 +150,7 @@ const LineInfo *el_line(EditLine *); int el_insertstr(EditLine *, const char *); void el_deletestr(EditLine *, int); + /* * ==== History ==== */ @@ -196,4 +193,22 @@ int history(History *, HistEvent *, int, ...); #define H_SETUNIQUE 20 /* , int); */ #define H_GETUNIQUE 21 /* , void); */ + +/* + * ==== Tokenization ==== + */ + +typedef struct tokenizer Tokenizer; + +/* + * String tokenization functions, using simplified sh(1) quoting rules + */ +Tokenizer *tok_init(const char *); +void tok_end(Tokenizer *); +void tok_reset(Tokenizer *); +int tok_line(Tokenizer *, const LineInfo *, + int *, const char ***, int *, int *); +int tok_str(Tokenizer *, const char *, + int *, const char ***); + #endif /* _HISTEDIT_H_ */ diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c index 53648203bf0..1da6a864181 100644 --- a/cmd-line-utils/libedit/history.c +++ b/cmd-line-utils/libedit/history.c @@ -1,4 +1,4 @@ -/* $NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $ */ +/* $NetBSD: history.c,v 1.28 2004/11/27 18:31:45 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * hist.c: History access functions @@ -51,11 +40,7 @@ __RCSID("$NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $"); #include <string.h> #include <stdlib.h> #include <stdarg.h> -#ifdef HAVE_VIS_H #include <vis.h> -#else -#include "np/vis.h" -#endif #include <sys/stat.h> static const char hist_cookie[] = "_HiStOrY_V2_\n"; @@ -91,6 +76,7 @@ struct history { #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) +#define h_strdup(a) strdup(a) #define h_malloc(a) malloc(a) #define h_realloc(a, b) realloc((a), (b)) #define h_free(a) free(a) @@ -249,20 +235,19 @@ history_def_next(ptr_t p, HistEvent *ev) { history_t *h = (history_t *) p; - if (h->cursor != &h->list) - h->cursor = h->cursor->next; - else { + if (h->cursor == &h->list) { he_seterrev(ev, _HE_EMPTY_LIST); return (-1); } - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { + if (h->cursor->next == &h->list) { he_seterrev(ev, _HE_END_REACHED); return (-1); } + h->cursor = h->cursor->next; + *ev = h->cursor->ev; + return (0); } @@ -275,21 +260,20 @@ history_def_prev(ptr_t p, HistEvent *ev) { history_t *h = (history_t *) p; - if (h->cursor != &h->list) - h->cursor = h->cursor->prev; - else { + if (h->cursor == &h->list) { he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); return (-1); } - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { + if (h->cursor->prev == &h->list) { he_seterrev(ev, _HE_START_REACHED); return (-1); } + h->cursor = h->cursor->prev; + *ev = h->cursor->ev; + return (0); } @@ -374,7 +358,8 @@ history_def_add(ptr_t p, HistEvent *ev, const char *str) */ /* ARGSUSED */ private void -history_def_delete(history_t *h, HistEvent *ev __attribute__((unused)), hentry_t *hp) +history_def_delete(history_t *h, + HistEvent *ev __attribute__((__unused__)), hentry_t *hp) { HistEventPrivate *evp = (void *)&hp->ev; if (hp == &h->list) @@ -397,7 +382,7 @@ history_def_insert(history_t *h, HistEvent *ev, const char *str) h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); if (h->cursor == NULL) goto oomem; - if ((h->cursor->ev.str = strdup(str)) == NULL) { + if ((h->cursor->ev.str = h_strdup(str)) == NULL) { h_free((ptr_t)h->cursor); goto oomem; } @@ -447,7 +432,7 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str) */ /* ARGSUSED */ private int -history_def_init(ptr_t *p, HistEvent *ev __attribute__((unused)), int n) +history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n) { history_t *h = (history_t *) h_malloc(sizeof(history_t)); if (h == NULL) @@ -661,6 +646,12 @@ history_load(History *h, const char *fname) if ((fp = fopen(fname, "r")) == NULL) return (i); + if ((line = fgetln(fp, &sz)) == NULL) + goto done; + + if (strncmp(line, hist_cookie, sz) != 0) + goto done; + ptr = h_malloc(max_size = 1024); if (ptr == NULL) goto done; @@ -674,7 +665,7 @@ history_load(History *h, const char *fname) if (max_size < sz) { char *nptr; - max_size = (sz + 1023) & ~1023; + max_size = (sz + 1024) & ~1023; nptr = h_realloc(ptr, max_size); if (nptr == NULL) { i = -1; @@ -714,16 +705,18 @@ history_save(History *h, const char *fname) if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) goto done; + if (fputs(hist_cookie, fp) == EOF) + goto done; ptr = h_malloc(max_size = 1024); if (ptr == NULL) goto done; for (i = 0, retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++) { - len = strlen(ev.str) * 4 + 1; + len = strlen(ev.str) * 4; if (len >= max_size) { char *nptr; - max_size = (len + 1023) & ~1023; + max_size = (len + 1024) & ~1023; nptr = h_realloc(ptr, max_size); if (nptr == NULL) { i = -1; @@ -732,7 +725,7 @@ history_save(History *h, const char *fname) ptr = nptr; } (void) strvis(ptr, ev.str, VIS_WHITE); - (void) fprintf(fp, "%s\n", ev.str); + (void) fprintf(fp, "%s\n", ptr); } oomem: h_free((ptr_t)ptr); diff --git a/cmd-line-utils/libedit/key.c b/cmd-line-utils/libedit/key.c index e75db00ce1b..090a2684e92 100644 --- a/cmd-line-utils/libedit/key.c +++ b/cmd-line-utils/libedit/key.c @@ -1,4 +1,4 @@ -/* $NetBSD: key.c,v 1.13 2002/03/18 16:00:55 christos Exp $ */ +/* $NetBSD: key.c,v 1.15 2003/10/18 23:48:42 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: key.c,v 1.13 2002/03/18 16:00:55 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * key.c: This module contains the procedures for maintaining @@ -103,14 +92,14 @@ private int key__decode_char(char *, int, int); * Initialize the key maps */ protected int -el_key_init(EditLine *el) +key_init(EditLine *el) { el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ); if (el->el_key.buf == NULL) return (-1); el->el_key.map = NULL; - el_key_reset(el); + key_reset(el); return (0); } @@ -119,7 +108,7 @@ el_key_init(EditLine *el) * Free the key maps */ protected void -el_key_end(EditLine *el) +key_end(EditLine *el) { el_free((ptr_t) el->el_key.buf); @@ -133,7 +122,7 @@ el_key_end(EditLine *el) * Associate cmd with a key value */ protected key_value_t * -el_key_map_cmd(EditLine *el, int cmd) +key_map_cmd(EditLine *el, int cmd) { el->el_key.val.cmd = (el_action_t) cmd; @@ -145,7 +134,7 @@ el_key_map_cmd(EditLine *el, int cmd) * Associate str with a key value */ protected key_value_t * -el_key_map_str(EditLine *el, char *str) +key_map_str(EditLine *el, char *str) { el->el_key.val.str = str; @@ -159,7 +148,7 @@ el_key_map_str(EditLine *el, char *str) * [Always bind the ansi arrow keys?] */ protected void -el_key_reset(EditLine *el) +key_reset(EditLine *el) { node__put(el, el->el_key.map); @@ -177,7 +166,7 @@ el_key_reset(EditLine *el) * The last character read is returned in *ch. */ protected int -el_key_get(EditLine *el, char *ch, key_value_t *val) +key_get(EditLine *el, char *ch, key_value_t *val) { return (node_trav(el, el->el_key.map, ch, val)); @@ -191,7 +180,7 @@ el_key_get(EditLine *el, char *ch, key_value_t *val) * out str or a unix command. */ protected void -el_key_add(EditLine *el, const char *key, key_value_t *val, int ntype) +key_add(EditLine *el, const char *key, key_value_t *val, int ntype) { if (key[0] == '\0') { @@ -219,7 +208,7 @@ el_key_add(EditLine *el, const char *key, key_value_t *val, int ntype) * */ protected void -el_key_clear(EditLine *el, el_action_t *map, const char *in) +key_clear(EditLine *el, el_action_t *map, const char *in) { if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && @@ -227,7 +216,7 @@ el_key_clear(EditLine *el, el_action_t *map, const char *in) el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) || (map == el->el_map.alt && el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN))) - (void) el_key_delete(el, in); + (void) key_delete(el, in); } @@ -236,7 +225,7 @@ el_key_clear(EditLine *el, el_action_t *map, const char *in) * they exists. */ protected int -el_key_delete(EditLine *el, const char *key) +key_delete(EditLine *el, const char *key) { if (key[0] == '\0') { @@ -257,7 +246,7 @@ el_key_delete(EditLine *el, const char *key) * Print entire el->el_key.map if null */ protected void -el_key_print(EditLine *el, const char *key) +key_print(EditLine *el, const char *key) { /* do nothing if el->el_key.map is empty and null key specified */ @@ -356,7 +345,8 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int break; case XK_STR: case XK_EXE: - ptr->val.str = strdup(val->str); + if ((ptr->val.str = el_strdup(val->str)) == NULL) + return -1; break; default: EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); @@ -504,7 +494,7 @@ node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt) if (str[1] == 0) { el->el_key.buf[ncnt + 1] = '"'; el->el_key.buf[ncnt + 2] = '\0'; - el_key_kprint(el, el->el_key.buf, + key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); return (0); } else @@ -552,7 +542,7 @@ node_enum(EditLine *el, key_node_t *ptr, int cnt) /* print this key and function */ el->el_key.buf[ncnt + 1] = '"'; el->el_key.buf[ncnt + 2] = '\0'; - el_key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); + key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); } else (void) node_enum(el, ptr->next, ncnt + 1); @@ -568,7 +558,7 @@ node_enum(EditLine *el, key_node_t *ptr, int cnt) * function specified by val */ protected void -el_key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) +key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) { el_bindings_t *fp; char unparsbuf[EL_BUFSIZ]; @@ -579,7 +569,7 @@ el_key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) case XK_STR: case XK_EXE: (void) fprintf(el->el_outfile, fmt, key, - el_key__decode_str(val->str, unparsbuf, + key__decode_str(val->str, unparsbuf, ntype == XK_STR ? "\"\"" : "[]")); break; case XK_CMD: @@ -644,7 +634,7 @@ key__decode_char(char *buf, int cnt, int ch) * Make a printable version of the ey */ protected char * -el_key__decode_str(const char *str, char *buf, const char *sep) +key__decode_str(const char *str, char *buf, const char *sep) { char *b; const char *p; diff --git a/cmd-line-utils/libedit/key.h b/cmd-line-utils/libedit/key.h index 9d83d7c2521..39a075c504e 100644 --- a/cmd-line-utils/libedit/key.h +++ b/cmd-line-utils/libedit/key.h @@ -1,4 +1,4 @@ -/* $NetBSD: key.h,v 1.6 2002/03/18 16:00:55 christos Exp $ */ +/* $NetBSD: key.h,v 1.8 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -62,19 +58,22 @@ typedef struct el_key_t { #define XK_NOD 2 #define XK_EXE 3 -protected int el_key_init(EditLine *); -protected void el_key_end(EditLine *); -protected key_value_t *el_key_map_cmd(EditLine *, int); -protected key_value_t *el_key_map_str(EditLine *, char *); -protected void el_key_reset(EditLine *); -protected int el_key_get(EditLine *, char *, key_value_t *); -protected void el_key_add(EditLine *, - const char *, key_value_t *, int); -protected void el_key_clear(EditLine *, el_action_t *, const char *); -protected int el_key_delete(EditLine *, const char *); -protected void el_key_print(EditLine *, const char *); -protected void el_key_kprint(EditLine *, const char *, key_value_t *, +#undef key_end +#undef key_clear +#undef key_print + +protected int key_init(EditLine *); +protected void key_end(EditLine *); +protected key_value_t *key_map_cmd(EditLine *, int); +protected key_value_t *key_map_str(EditLine *, char *); +protected void key_reset(EditLine *); +protected int key_get(EditLine *, char *, key_value_t *); +protected void key_add(EditLine *, const char *, key_value_t *, int); +protected void key_clear(EditLine *, el_action_t *, const char *); +protected int key_delete(EditLine *, const char *); +protected void key_print(EditLine *, const char *); +protected void key_kprint(EditLine *, const char *, key_value_t *, int); -protected char *el_key__decode_str(const char *, char *, const char *); +protected char *key__decode_str(const char *, char *, const char *); #endif /* _h_el_key */ diff --git a/cmd-line-utils/libedit/makelist.sh b/cmd-line-utils/libedit/makelist.sh index b2502d16ed1..502604791f5 100644 --- a/cmd-line-utils/libedit/makelist.sh +++ b/cmd-line-utils/libedit/makelist.sh @@ -68,7 +68,7 @@ case $FLAG in /\(\):/ { pr = substr($2, 1, 2); if (pr == "vi" || pr == "em" || pr == "ed") { - name = substr($2, 1, length($2) - 3); + name = substr($2, 1, index($2,"(") - 1); # # XXX: need a space between name and prototype so that -fc and -fh # parsing is much easier @@ -97,7 +97,7 @@ case $FLAG in /\(\):/ { pr = substr($2, 1, 2); if (pr == "vi" || pr == "em" || pr == "ed") { - name = substr($2, 1, length($2) - 3); + name = substr($2, 1, index($2,"(") - 1); uname = ""; fname = ""; for (i = 1; i <= length(name); i++) { @@ -117,6 +117,7 @@ case $FLAG in printf(" \""); for (i = 2; i < NF; i++) printf("%s ", $i); + sub("\r", "", $i); printf("%s\" },\n", $i); ok = 0; } @@ -219,7 +220,7 @@ case $FLAG in /\(\):/ { pr = substr($2, 1, 2); if (pr == "vi" || pr == "em" || pr == "ed") { - name = substr($2, 1, length($2) - 3); + name = substr($2, 1, index($2, "(") - 1); fname = ""; for (i = 1; i <= length(name); i++) { s = substr(name, i, 1); diff --git a/cmd-line-utils/libedit/map.c b/cmd-line-utils/libedit/map.c index a16625311ae..d99c36ff665 100644 --- a/cmd-line-utils/libedit/map.c +++ b/cmd-line-utils/libedit/map.c @@ -1,4 +1,4 @@ -/* $NetBSD: map.c,v 1.18 2002/11/15 14:32:33 christos Exp $ */ +/* $NetBSD: map.c,v 1.20 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: map.c,v 1.18 2002/11/15 14:32:33 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * map.c: Editor function definitions @@ -71,7 +60,7 @@ private const el_action_t el_map_emacs[] = { /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_NEXT_CHAR, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */ + /* 8 */ EM_DELETE_PREV_CHAR, /* ^H */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ @@ -190,7 +179,7 @@ private const el_action_t el_map_emacs[] = { /* 124 */ ED_INSERT, /* | */ /* 125 */ ED_INSERT, /* } */ /* 126 */ ED_INSERT, /* ~ */ - /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */ + /* 127 */ EM_DELETE_PREV_CHAR, /* ^? */ /* 128 */ ED_UNASSIGNED, /* M-^@ */ /* 129 */ ED_UNASSIGNED, /* M-^A */ /* 130 */ ED_UNASSIGNED, /* M-^B */ @@ -1011,8 +1000,7 @@ map_init_meta(EditLine *el) break; default: buf[1] = i & 0177; - el_key_add(el, buf, - el_key_map_cmd(el, (int) map[i]), XK_CMD); + key_add(el, buf, key_map_cmd(el, (int) map[i]), XK_CMD); break; } map[(int) buf[0]] = ED_SEQUENCE_LEAD_IN; @@ -1034,7 +1022,7 @@ map_init_vi(EditLine *el) el->el_map.type = MAP_VI; el->el_map.current = el->el_map.key; - el_key_reset(el); + key_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = vii[i]; @@ -1063,7 +1051,7 @@ map_init_emacs(EditLine *el) el->el_map.type = MAP_EMACS; el->el_map.current = el->el_map.key; - el_key_reset(el); + key_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = emacs[i]; @@ -1076,7 +1064,7 @@ map_init_emacs(EditLine *el) buf[0] = CONTROL('X'); buf[1] = CONTROL('X'); buf[2] = 0; - el_key_add(el, buf, el_key_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); + key_add(el, buf, key_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); tty_bind_char(el, 1); term_bind_arrow(el); @@ -1133,7 +1121,7 @@ map_print_key(EditLine *el, el_action_t *map, const char *in) el_bindings_t *bp; if (in[0] == '\0' || in[1] == '\0') { - (void) el_key__decode_str(in, outbuf, ""); + (void) key__decode_str(in, outbuf, ""); for (bp = el->el_map.help; bp->name != NULL; bp++) if (bp->func == map[(unsigned char) *in]) { (void) fprintf(el->el_outfile, @@ -1141,7 +1129,7 @@ map_print_key(EditLine *el, el_action_t *map, const char *in) return; } } else - el_key_print(el, in); + key_print(el, in); } @@ -1163,20 +1151,20 @@ map_print_some_keys(EditLine *el, el_action_t *map, int first, int last) if (first == last) (void) fprintf(el->el_outfile, "%-15s-> is undefined\n", - el_key__decode_str(firstbuf, unparsbuf, STRQQ)); + key__decode_str(firstbuf, unparsbuf, STRQQ)); return; } for (bp = el->el_map.help; bp->name != NULL; bp++) { if (bp->func == map[first]) { if (first == last) { (void) fprintf(el->el_outfile, "%-15s-> %s\n", - el_key__decode_str(firstbuf, unparsbuf, STRQQ), + key__decode_str(firstbuf, unparsbuf, STRQQ), bp->name); } else { (void) fprintf(el->el_outfile, "%-4s to %-7s-> %s\n", - el_key__decode_str(firstbuf, unparsbuf, STRQQ), - el_key__decode_str(lastbuf, extrabuf, STRQQ), + key__decode_str(firstbuf, unparsbuf, STRQQ), + key__decode_str(lastbuf, extrabuf, STRQQ), bp->name); } return; @@ -1230,7 +1218,7 @@ map_print_all_keys(EditLine *el) map_print_some_keys(el, el->el_map.alt, prev, i - 1); (void) fprintf(el->el_outfile, "Multi-character bindings\n"); - el_key_print(el, ""); + key_print(el, ""); (void) fprintf(el->el_outfile, "Arrow key bindings\n"); term_print_arrow(el, ""); } @@ -1323,9 +1311,9 @@ map_bind(EditLine *el, int argc, const char **argv) return (-1); } if (in[1]) - (void) el_key_delete(el, in); + (void) key_delete(el, in); else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) - (void) el_key_delete(el, in); + (void) key_delete(el, in); else map[(unsigned char) *in] = ED_UNASSIGNED; return (0); @@ -1353,9 +1341,9 @@ map_bind(EditLine *el, int argc, const char **argv) return (-1); } if (key) - term_set_arrow(el, in, el_key_map_str(el, out), ntype); + term_set_arrow(el, in, key_map_str(el, out), ntype); else - el_key_add(el, in, el_key_map_str(el, out), ntype); + key_add(el, in, key_map_str(el, out), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; break; @@ -1366,13 +1354,13 @@ map_bind(EditLine *el, int argc, const char **argv) return (-1); } if (key) - term_set_arrow(el, in, el_key_map_str(el, out), ntype); + term_set_arrow(el, in, key_map_str(el, out), ntype); else { if (in[1]) { - el_key_add(el, in, el_key_map_cmd(el, cmd), ntype); + key_add(el, in, key_map_cmd(el, cmd), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; } else { - el_key_clear(el, map, in); + key_clear(el, map, in); map[(unsigned char) *in] = cmd; } } diff --git a/cmd-line-utils/libedit/map.h b/cmd-line-utils/libedit/map.h index 3c9948ccf88..3b08f48be7a 100644 --- a/cmd-line-utils/libedit/map.h +++ b/cmd-line-utils/libedit/map.h @@ -1,4 +1,4 @@ -/* $NetBSD: map.h,v 1.7 2002/03/18 16:00:56 christos Exp $ */ +/* $NetBSD: map.h,v 1.8 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/parse.c b/cmd-line-utils/libedit/parse.c index d09b890c1ab..993cf5b752d 100644 --- a/cmd-line-utils/libedit/parse.c +++ b/cmd-line-utils/libedit/parse.c @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.16 2003/01/21 18:40:24 christos Exp $ */ +/* $NetBSD: parse.c,v 1.20 2003/12/05 13:37:48 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: parse.c,v 1.16 2003/01/21 18:40:24 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * parse.c: parse an editline extended command @@ -59,7 +48,6 @@ __RCSID("$NetBSD: parse.c,v 1.16 2003/01/21 18:40:24 christos Exp $"); * setty */ #include "el.h" -#include "tokenizer.h" #include <stdlib.h> private const struct { @@ -87,9 +75,8 @@ parse_line(EditLine *el, const char *line) int argc; Tokenizer *tok; - if (!(tok = tok_init(NULL))) - return -1; - tok_line(tok, line, &argc, &argv); + tok = tok_init(NULL); + tok_str(tok, line, &argc, &argv); argc = el_parse(el, argc, argv); tok_end(tok); return (argc); @@ -207,7 +194,7 @@ parse__escape(const char **const ptr) c = *p; break; } - } else if (*p == '^' && isalpha((unsigned char) p[1])) { + } else if (*p == '^') { p++; c = (*p == '?') ? '\177' : (*p & 0237); } else @@ -215,6 +202,7 @@ parse__escape(const char **const ptr) *ptr = ++p; return (c); } + /* parse__string(): * Parse the escapes from in and put the raw string out */ @@ -237,6 +225,14 @@ parse__string(char *out, const char *in) *out++ = n; break; + case 'M': + if (in[1] == '-' && in[2] != '\0') { + *out++ = '\033'; + in += 2; + break; + } + /*FALLTHROUGH*/ + default: *out++ = *in++; break; diff --git a/cmd-line-utils/libedit/parse.h b/cmd-line-utils/libedit/parse.h index 4aaef2f834a..4b796666b8e 100644 --- a/cmd-line-utils/libedit/parse.h +++ b/cmd-line-utils/libedit/parse.h @@ -1,4 +1,4 @@ -/* $NetBSD: parse.h,v 1.4 2000/09/04 22:06:31 lukem Exp $ */ +/* $NetBSD: parse.h,v 1.5 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/prompt.c b/cmd-line-utils/libedit/prompt.c index 03d8309a991..455dd60331b 100644 --- a/cmd-line-utils/libedit/prompt.c +++ b/cmd-line-utils/libedit/prompt.c @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.c,v 1.9 2002/03/18 16:00:56 christos Exp $ */ +/* $NetBSD: prompt.c,v 1.11 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: prompt.c,v 1.9 2002/03/18 16:00:56 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * prompt.c: Prompt printing functions @@ -59,7 +48,7 @@ private char *prompt_default_r(EditLine *); */ private char * /*ARGSUSED*/ -prompt_default(EditLine *el __attribute__((unused))) +prompt_default(EditLine *el __attribute__((__unused__))) { static char a[3] = {'?', ' ', '\0'}; @@ -72,7 +61,7 @@ prompt_default(EditLine *el __attribute__((unused))) */ private char * /*ARGSUSED*/ -prompt_default_r(EditLine *el __attribute__((unused))) +prompt_default_r(EditLine *el __attribute__((__unused__))) { static char a[1] = {'\0'}; @@ -127,7 +116,7 @@ prompt_init(EditLine *el) */ protected void /*ARGSUSED*/ -prompt_end(EditLine *el __attribute__((unused))) +prompt_end(EditLine *el __attribute__((__unused__))) { } diff --git a/cmd-line-utils/libedit/prompt.h b/cmd-line-utils/libedit/prompt.h index 08810e22a0c..d18110861f8 100644 --- a/cmd-line-utils/libedit/prompt.h +++ b/cmd-line-utils/libedit/prompt.h @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.h,v 1.5 2000/09/04 22:06:31 lukem Exp $ */ +/* $NetBSD: prompt.h,v 1.6 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/read.c b/cmd-line-utils/libedit/read.c index 5eaa83bf482..40093d6647f 100644 --- a/cmd-line-utils/libedit/read.c +++ b/cmd-line-utils/libedit/read.c @@ -1,4 +1,4 @@ -/* $NetBSD: read.c,v 1.24 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: read.c,v 1.35 2005/03/09 23:55:02 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,20 +32,14 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: read.c,v 1.24 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * read.c: Clean this junk up! This is horrible code. * Terminal read functions */ #include <errno.h> +#include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include "el.h" @@ -97,6 +87,10 @@ el_read_getfn(EditLine *el) } +#ifndef MIN +#define MIN(A,B) ((A) < (B) ? (A) : (B)) +#endif + #ifdef DEBUG_EDIT private void read_debug(EditLine *el) @@ -121,11 +115,7 @@ read_debug(EditLine *el) */ /* ARGSUSED */ private int -read__fixio(int fd -#if !(defined(TRY_AGAIN) && (defined(FIONBIO) || (defined(F_SETFL) && defined(O_NDELAY)))) - __attribute__((unused)) -#endif /* !(defined(TRY_AGAIN) && (defined(FIONBIO) || (defined(F_SETFL) && defined(O_NDELAY)))) */ -, int e) +read__fixio(int fd __attribute__((__unused__)), int e) { switch (e) { @@ -190,18 +180,10 @@ read_preread(EditLine *el) { int chrs = 0; - if (el->el_chared.c_macro.nline) { - el_free((ptr_t) el->el_chared.c_macro.nline); - el->el_chared.c_macro.nline = NULL; - } if (el->el_tty.t_mode == ED_IO) return (0); #ifdef FIONREAD - -#ifndef MIN // definition of MIN is lacking on hpux.. -#define MIN(x,y) (((x)<(y))?(x):(y)) -#endif (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs); if (chrs > 0) { char buf[EL_BUFSIZ]; @@ -210,8 +192,7 @@ read_preread(EditLine *el) (size_t) MIN(chrs, EL_BUFSIZ - 1)); if (chrs > 0) { buf[chrs] = '\0'; - el->el_chared.c_macro.nline = strdup(buf); - el_push(el, el->el_chared.c_macro.nline); + el_push(el, buf); } } #endif /* FIONREAD */ @@ -230,11 +211,12 @@ el_push(EditLine *el, char *str) if (str != NULL && ma->level + 1 < EL_MAXMACRO) { ma->level++; - ma->macro[ma->level] = str; - } else { - term_beep(el); - term__flush(); + if ((ma->macro[ma->level] = el_strdup(str)) != NULL) + return; + ma->level--; } + term_beep(el); + term__flush(); } @@ -266,7 +248,7 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) cmd = el->el_map.current[(unsigned char) *ch]; if (cmd == ED_SEQUENCE_LEAD_IN) { key_value_t val; - switch (el_key_get(el, ch, &val)) { + switch (key_get(el, ch, &val)) { case XK_CMD: cmd = val.cmd; break; @@ -331,14 +313,16 @@ el_getc(EditLine *el, char *cp) if (ma->level < 0) break; - if (*ma->macro[ma->level] == 0) { - ma->level--; + if (ma->macro[ma->level][ma->offset] == '\0') { + el_free(ma->macro[ma->level--]); + ma->offset = 0; continue; } - *cp = *ma->macro[ma->level]++ & 0377; - if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode - * On */ - ma->level--; + *cp = ma->macro[ma->level][ma->offset++] & 0377; + if (ma->macro[ma->level][ma->offset] == '\0') { + /* Needed for QuoteMode On */ + el_free(ma->macro[ma->level--]); + ma->offset = 0; } return (1); } @@ -359,6 +343,35 @@ el_getc(EditLine *el, char *cp) return (num_read); } +protected void +read_prepare(EditLine *el) +{ + if (el->el_flags & HANDLE_SIGNALS) + sig_set(el); + if (el->el_flags & NO_TTY) + return; + if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED) + tty_rawmode(el); + + /* This is relatively cheap, and things go terribly wrong if + we have the wrong size. */ + el_resize(el); + re_clear_display(el); /* reset the display stuff */ + ch_reset(el); + re_refresh(el); /* print the prompt */ + + if (el->el_flags & UNBUFFERED) + term__flush(); +} + +protected void +read_finish(EditLine *el) +{ + if ((el->el_flags & UNBUFFERED) == 0) + (void) tty_cookedmode(el); + if (el->el_flags & HANDLE_SIGNALS) + sig_clr(el); +} public const char * el_gets(EditLine *el, int *nread) @@ -367,13 +380,11 @@ el_gets(EditLine *el, int *nread) el_action_t cmdnum = 0; int num; /* how many chars we have read at NL */ char ch; + int crlf = 0; #ifdef FIONREAD c_macro_t *ma = &el->el_chared.c_macro; #endif /* FIONREAD */ - if (el->el_flags & HANDLE_SIGNALS) - sig_set(el); - if (el->el_flags & NO_TTY) { char *cp = el->el_line.buffer; size_t idx; @@ -387,6 +398,8 @@ el_gets(EditLine *el, int *nread) cp = &el->el_line.buffer[idx]; } cp++; + if (el->el_flags & UNBUFFERED) + break; if (cp[-1] == '\r' || cp[-1] == '\n') break; } @@ -398,12 +411,6 @@ el_gets(EditLine *el, int *nread) return (el->el_line.buffer); } - /* This is relatively cheap, and things go terribly wrong if - we have the wrong size. */ - el_resize(el); - - re_clear_display(el); /* reset the display stuff */ - ch_reset(el); #ifdef FIONREAD if (el->el_tty.t_mode == EX_IO && ma->level < 0) { @@ -420,11 +427,16 @@ el_gets(EditLine *el, int *nread) } #endif /* FIONREAD */ - re_refresh(el); /* print the prompt */ + if ((el->el_flags & UNBUFFERED) == 0) + read_prepare(el); if (el->el_flags & EDIT_DISABLED) { - char *cp = el->el_line.buffer; + char *cp; size_t idx; + if ((el->el_flags & UNBUFFERED) == 0) + cp = el->el_line.buffer; + else + cp = el->el_line.lastchar; term__flush(); @@ -439,7 +451,10 @@ el_gets(EditLine *el, int *nread) if (*cp == 4) /* ought to be stty eof */ break; cp++; - if (cp[-1] == '\r' || cp[-1] == '\n') + crlf = cp[-1] == '\r' || cp[-1] == '\n'; + if (el->el_flags & UNBUFFERED) + break; + if (crlf) break; } @@ -463,8 +478,7 @@ el_gets(EditLine *el, int *nread) #endif /* DEBUG_READ */ break; } - if ((unsigned int)cmdnum >= (unsigned int)(el->el_map.nfunc)) - { /* BUG CHECK command */ + if ((uint)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, "ERROR: illegal command from key 0%o\r\n", ch); @@ -494,7 +508,7 @@ el_gets(EditLine *el, int *nread) el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { if (cmdnum == VI_DELETE_PREV_CHAR && el->el_chared.c_redo.pos != el->el_chared.c_redo.buf - && isprint(el->el_chared.c_redo.pos[-1])) + && isprint((unsigned char)el->el_chared.c_redo.pos[-1])) el->el_chared.c_redo.pos--; else *el->el_chared.c_redo.pos++ = ch; @@ -536,7 +550,13 @@ el_gets(EditLine *el, int *nread) continue; /* keep going... */ case CC_EOF: /* end of file typed */ - num = 0; + if ((el->el_flags & UNBUFFERED) == 0) + num = 0; + else if (num == -1) { + *el->el_line.lastchar++ = CONTROL('d'); + el->el_line.cursor = el->el_line.lastchar; + num = 1; + } break; case CC_NEWLINE: /* normal end of line */ @@ -567,14 +587,19 @@ el_gets(EditLine *el, int *nread) el->el_state.argument = 1; el->el_state.doingarg = 0; el->el_chared.c_vcmd.action = NOP; + if (el->el_flags & UNBUFFERED) + break; } term__flush(); /* flush any buffered output */ /* make sure the tty is set up correctly */ - (void) tty_cookedmode(el); - if (el->el_flags & HANDLE_SIGNALS) - sig_clr(el); - if (nread) - *nread = num; + if ((el->el_flags & UNBUFFERED) == 0) { + read_finish(el); + if (nread) + *nread = num; + } else { + if (nread) + *nread = el->el_line.lastchar - el->el_line.buffer; + } return (num ? el->el_line.buffer : NULL); } diff --git a/cmd-line-utils/libedit/read.h b/cmd-line-utils/libedit/read.h index b01e77db239..1982f47253b 100644 --- a/cmd-line-utils/libedit/read.h +++ b/cmd-line-utils/libedit/read.h @@ -1,4 +1,4 @@ -/* $NetBSD: read.h,v 1.1 2001/09/27 19:29:50 christos Exp $ */ +/* $NetBSD: read.h,v 1.4 2004/02/27 14:52:18 christos Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -49,6 +49,8 @@ typedef struct el_read_t { } el_read_t; protected int read_init(EditLine *); +protected void read_prepare(EditLine *); +protected void read_finish(EditLine *); protected int el_read_setfn(EditLine *, el_rfunc_t); protected el_rfunc_t el_read_getfn(EditLine *); diff --git a/cmd-line-utils/libedit/readline.c b/cmd-line-utils/libedit/readline.c index 5b40ade582c..3a38e8a99ab 100644 --- a/cmd-line-utils/libedit/readline.c +++ b/cmd-line-utils/libedit/readline.c @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $ */ +/* $NetBSD: readline.c,v 1.49 2005/03/10 19:34:46 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -36,10 +36,25 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $"); -#endif /* not lint && not SCCSID */ +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#include <config.h> + +#ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +#else +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifndef _AIX +extern char *alloca (); +# endif +# endif +#endif #include <sys/types.h> #include <sys/stat.h> @@ -51,19 +66,20 @@ __RCSID("$NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $"); #include <stdlib.h> #include <unistd.h> #include <limits.h> -#ifdef HAVE_ALLOCA_H -#include <alloca.h> -#endif -#include "histedit.h" -#include "readline/readline.h" +#include <errno.h> +#include <fcntl.h> +#include <vis.h> + #include "el.h" #include "fcns.h" /* for EL_NUM_FCNS */ +#include "histedit.h" +#include "readline/readline.h" /* for rl_complete() */ -#define TAB '\r' +#define TAB '\r' /* see comment at the #ifdef for sense of this */ -#define GDB_411_HACK +/* #define GDB_411_HACK */ /* readline compatibility stuff - look at readline sources/documentation */ /* to see what these variables mean */ @@ -78,6 +94,9 @@ FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; +VFunction *rl_linefunc = NULL; +int rl_done = 0; +VFunction *rl_event_hook = NULL; int history_base = 1; /* probably never subject to change */ int history_length = 0; @@ -86,16 +105,34 @@ char history_expansion_char = '!'; char history_subst_char = '^'; char *history_no_expand_chars = expand_chars; Function *history_inhibit_expansion_function = NULL; +char *history_arg_extract(int start, int end, const char *str); int rl_inhibit_completion = 0; int rl_attempted_completion_over = 0; char *rl_basic_word_break_characters = break_chars; char *rl_completer_word_break_characters = NULL; char *rl_completer_quote_characters = NULL; -CPFunction *rl_completion_entry_function = NULL; +Function *rl_completion_entry_function = NULL; CPPFunction *rl_attempted_completion_function = NULL; +Function *rl_pre_input_hook = NULL; +Function *rl_startup1_hook = NULL; +Function *rl_getc_function = NULL; +char *rl_terminal_name = NULL; +int rl_already_prompted = 0; +int rl_filename_completion_desired = 0; +int rl_ignore_completion_duplicates = 0; +int rl_catch_signals = 1; +VFunction *rl_redisplay_function = NULL; +Function *rl_startup_hook = NULL; +VFunction *rl_completion_display_matches_hook = NULL; +VFunction *rl_prep_term_function = NULL; +VFunction *rl_deprep_term_function = NULL; /* + * The current prompt string. + */ +char *rl_prompt = NULL; +/* * This is set to character indicating type of completion being done by * rl_complete_internal(); this is available for application completion * functions. @@ -128,30 +165,30 @@ static int _rl_complete_show_all = 0; static History *h = NULL; static EditLine *e = NULL; +static Function *map[256]; static int el_rl_complete_cmdnum = 0; /* internal functions */ static unsigned char _el_rl_complete(EditLine *, int); +static unsigned char _el_rl_tstp(EditLine *, int); static char *_get_prompt(EditLine *); static HIST_ENTRY *_move_history(int); -static int _history_search_gen(const char *, int, int); -static int _history_expand_command(const char *, size_t, char **); +static int _history_expand_command(const char *, size_t, size_t, + char **); static char *_rl_compat_sub(const char *, const char *, - const char *, int); -static int rl_complete_internal(int); + const char *, int); +static int _rl_complete_internal(int); static int _rl_qsort_string_compare(const void *, const void *); - -/* - * needed for prompt switching in readline() - */ -static char *el_rl_prompt = NULL; +static int _rl_event_read_char(EditLine *, char *); +static void _rl_update_pos(void); /* ARGSUSED */ static char * -_get_prompt(EditLine *el __attribute__((unused))) +_get_prompt(EditLine *el __attribute__((__unused__))) { - return (el_rl_prompt); + rl_already_prompted = 1; + return (rl_prompt); } @@ -168,7 +205,7 @@ _move_history(int op) return (HIST_ENTRY *) NULL; rl_he.line = ev.str; - rl_he.data = ""; + rl_he.data = (histdata_t) &(ev.num); return (&rl_he); } @@ -221,29 +258,41 @@ rl_initialize(void) el_set(e, EL_HIST, history, h); /* for proper prompt printing in readline() */ - el_rl_prompt = strdup(""); - if (el_rl_prompt == NULL) { + rl_prompt = strdup(""); + if (rl_prompt == NULL) { history_end(h); el_end(e); return -1; } el_set(e, EL_PROMPT, _get_prompt); - el_set(e, EL_SIGNAL, 1); + el_set(e, EL_SIGNAL, rl_catch_signals); /* set default mode to "emacs"-style and read setting afterwards */ /* so this can be overriden */ el_set(e, EL_EDITOR, "emacs"); + if (rl_terminal_name != NULL) + el_set(e, EL_TERMINAL, rl_terminal_name); + else + el_get(e, EL_TERMINAL, &rl_terminal_name); /* - * Word completition - this has to go AFTER rebinding keys + * Word completion - this has to go AFTER rebinding keys * to emacs-style. */ el_set(e, EL_ADDFN, "rl_complete", - "ReadLine compatible completition function", + "ReadLine compatible completion function", _el_rl_complete); el_set(e, EL_BIND, "^I", "rl_complete", NULL); /* + * Send TSTP when ^Z is pressed. + */ + el_set(e, EL_ADDFN, "rl_tstp", + "ReadLine compatible suspend function", + _el_rl_tstp); + el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); + + /* * Find out where the rl_complete function was added; this is * used later to detect that lastcmd was also rl_complete. */ @@ -264,7 +313,10 @@ rl_initialize(void) li = el_line(e); /* a cheesy way to get rid of const cast. */ rl_line_buffer = memchr(li->buffer, *li->buffer, 1); - rl_point = rl_end = 0; + _rl_update_pos(); + + if (rl_startup_hook) + (*rl_startup_hook)(NULL, 0); return (0); } @@ -281,19 +333,38 @@ readline(const char *prompt) int count; const char *ret; char *buf; + static int used_event_hook; if (e == NULL || h == NULL) rl_initialize(); + rl_done = 0; + /* update prompt accordingly to what has been passed */ if (!prompt) prompt = ""; - if (strcmp(el_rl_prompt, prompt) != 0) { - free(el_rl_prompt); - el_rl_prompt = strdup(prompt); - if (el_rl_prompt == NULL) + if (strcmp(rl_prompt, prompt) != 0) { + free(rl_prompt); + rl_prompt = strdup(prompt); + if (rl_prompt == NULL) return NULL; } + + if (rl_pre_input_hook) + (*rl_pre_input_hook)(NULL, 0); + + if (rl_event_hook && !(e->el_flags&NO_TTY)) { + el_set(e, EL_GETCFN, _rl_event_read_char); + used_event_hook = 1; + } + + if (!rl_event_hook && used_event_hook) { + el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); + used_event_hook = 0; + } + + rl_already_prompted = 0; + /* get one line from input stream */ ret = el_gets(e, &count); @@ -333,73 +404,178 @@ using_history(void) /* * substitute ``what'' with ``with'', returning resulting string; if - * globally == 1, substitutes all occurences of what, otherwise only the + * globally == 1, substitutes all occurrences of what, otherwise only the * first one */ static char * _rl_compat_sub(const char *str, const char *what, const char *with, int globally) { - char *result; - const char *temp, *new; - unsigned int len, with_len, what_len, add; - size_t size, i; + const char *s; + char *r, *result; + size_t len, with_len, what_len; - result = malloc((size = 16)); - if (result == NULL) - return NULL; - temp = str; + len = strlen(str); with_len = strlen(with); what_len = strlen(what); - len = 0; - do { - new = strstr(temp, what); - if (new) { - i = new - temp; - add = i + with_len; - if (i + add + 1 >= size) { - char *nresult; - size += add + 1; - nresult = realloc(result, size); - if (nresult == NULL) { - free(result); - return NULL; - } - result = nresult; - } - (void) strncpy(&result[len], temp, i); - len += i; - (void) strcpy(&result[len], with); /* safe */ - len += with_len; - temp = new + what_len; - } else { - add = strlen(temp); - if (len + add + 1 >= size) { - char *nresult; - size += add + 1; - nresult = realloc(result, size); - if (nresult == NULL) { - free(result); - return NULL; - } - result = nresult; + + /* calculate length we need for result */ + s = str; + while (*s) { + if (*s == *what && !strncmp(s, what, what_len)) { + len += with_len - what_len; + if (!globally) + break; + s += what_len; + } else + s++; + } + r = result = malloc(len + 1); + if (result == NULL) + return NULL; + s = str; + while (*s) { + if (*s == *what && !strncmp(s, what, what_len)) { + (void)strncpy(r, with, with_len); + r += with_len; + s += what_len; + if (!globally) { + (void)strcpy(r, s); + return(result); } - (void) strcpy(&result[len], temp); /* safe */ - len += add; - temp = NULL; + } else + *r++ = *s++; + } + *r = 0; + return(result); +} + +static char *last_search_pat; /* last !?pat[?] search pattern */ +static char *last_search_match; /* last !?pat[?] that matched */ + +const char * +get_history_event(const char *cmd, int *cindex, int qchar) +{ + int idx, sign, sub, num, begin, ret; + size_t len; + char *pat; + const char *rptr; + HistEvent ev; + + idx = *cindex; + if (cmd[idx++] != history_expansion_char) + return(NULL); + + /* find out which event to take */ + if (cmd[idx] == history_expansion_char || cmd[idx] == 0) { + if (history(h, &ev, H_FIRST) != 0) + return(NULL); + *cindex = cmd[idx]? (idx + 1):idx; + return(ev.str); + } + sign = 0; + if (cmd[idx] == '-') { + sign = 1; + idx++; + } + + if ('0' <= cmd[idx] && cmd[idx] <= '9') { + HIST_ENTRY *rl_he; + + num = 0; + while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { + num = num * 10 + cmd[idx] - '0'; + idx++; } - } while (temp && globally); - result[len] = '\0'; + if (sign) + num = history_length - num + 1; - return (result); -} + if (!(rl_he = history_get(num))) + return(NULL); + + *cindex = idx; + return(rl_he->line); + } + sub = 0; + if (cmd[idx] == '?') { + sub = 1; + idx++; + } + begin = idx; + while (cmd[idx]) { + if (cmd[idx] == '\n') + break; + if (sub && cmd[idx] == '?') + break; + if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' + || cmd[idx] == '\t' || cmd[idx] == qchar)) + break; + idx++; + } + len = idx - begin; + if (sub && cmd[idx] == '?') + idx++; + if (sub && len == 0 && last_search_pat && *last_search_pat) + pat = last_search_pat; + else if (len == 0) + return(NULL); + else { + if ((pat = malloc(len + 1)) == NULL) + return NULL; + (void)strncpy(pat, cmd + begin, len); + pat[len] = '\0'; + } + if (history(h, &ev, H_CURR) != 0) { + if (pat != last_search_pat) + free(pat); + return (NULL); + } + num = ev.num; + + if (sub) { + if (pat != last_search_pat) { + if (last_search_pat) + free(last_search_pat); + last_search_pat = pat; + } + ret = history_search(pat, -1); + } else + ret = history_search_prefix(pat, -1); + + if (ret == -1) { + /* restore to end of list on failed search */ + history(h, &ev, H_FIRST); + (void)fprintf(rl_outstream, "%s: Event not found\n", pat); + if (pat != last_search_pat) + free(pat); + return(NULL); + } + + if (sub && len) { + if (last_search_match && last_search_match != pat) + free(last_search_match); + last_search_match = pat; + } + + if (pat != last_search_pat) + free(pat); + + if (history(h, &ev, H_CURR) != 0) + return(NULL); + *cindex = idx; + rptr = ev.str; + + /* roll back to original position */ + (void)history(h, &ev, H_SET, num); + + return rptr; +} /* * the real function doing history expansion - takes as argument command * to do and data upon which the command should be executed * does expansion the way I've understood readline documentation - * word designator ``%'' isn't supported (yet ?) * * returns 0 if data was not modified, 1 if it was and 2 if the string * should be only printed and not executed; in case of error, @@ -407,144 +583,145 @@ _rl_compat_sub(const char *str, const char *what, const char *with, * it's callers responsibility to free() string returned in *result */ static int -_history_expand_command(const char *command, size_t cmdlen, char **result) +_history_expand_command(const char *command, size_t offs, size_t cmdlen, + char **result) { - char **arr, *tempcmd, *line, *search = NULL, *cmd; - const char *event_data = NULL; + char *tmp, *search = NULL, *aptr; + const char *ptr, *cmd; static char *from = NULL, *to = NULL; - int start = -1, end = -1, max, i, idx; - int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0; - int event_num = 0, retval; - size_t cmdsize; + int start, end, idx, has_mods = 0; + int p_on = 0, g_on = 0; *result = NULL; + aptr = NULL; + ptr = NULL; - cmd = alloca(cmdlen + 1); - (void) strncpy(cmd, command, cmdlen); - cmd[cmdlen] = 0; + /* First get event specifier */ + idx = 0; - idx = 1; - /* find out which event to take */ - if (cmd[idx] == history_expansion_char) { - event_num = history_length; - idx++; + if (strchr(":^*$", command[offs + 1])) { + char str[4]; + /* + * "!:" is shorthand for "!!:". + * "!^", "!*" and "!$" are shorthand for + * "!!:^", "!!:*" and "!!:$" respectively. + */ + str[0] = str[1] = '!'; + str[2] = '0'; + ptr = get_history_event(str, &idx, 0); + idx = (command[offs + 1] == ':')? 1:0; + has_mods = 1; } else { - int off, num; - size_t len; - off = idx; - while (cmd[off] && !strchr(":^$*-%", cmd[off])) - off++; - num = atoi(&cmd[idx]); - if (num != 0) { - event_num = num; - if (num < 0) - event_num += history_length + 1; + if (command[offs + 1] == '#') { + /* use command so far */ + if ((aptr = malloc(offs + 1)) == NULL) + return -1; + (void)strncpy(aptr, command, offs); + aptr[offs] = '\0'; + idx = 1; } else { - int prefix = 1, curr_num; - HistEvent ev; - - len = off - idx; - if (cmd[idx] == '?') { - idx++, len--; - if (cmd[off - 1] == '?') - len--; - else if (cmd[off] != '\n' && cmd[off] != '\0') - return (-1); - prefix = 0; - } - search = alloca(len + 1); - (void) strncpy(search, &cmd[idx], len); - search[len] = '\0'; - - if (history(h, &ev, H_CURR) != 0) - return (-1); - curr_num = ev.num; + int qchar; - if (prefix) - retval = history_search_prefix(search, -1); - else - retval = history_search(search, -1); + qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; + ptr = get_history_event(command + offs, &idx, qchar); + } + has_mods = command[offs + idx] == ':'; + } - if (retval == -1) { - fprintf(rl_outstream, "%s: Event not found\n", - search); - return (-1); - } - if (history(h, &ev, H_CURR) != 0) - return (-1); - event_data = ev.str; + if (ptr == NULL && aptr == NULL) + return(-1); - /* roll back to original position */ - history(h, &ev, H_NEXT_EVENT, curr_num); - } - idx = off; + if (!has_mods) { + *result = strdup(aptr? aptr : ptr); + if (aptr) + free(aptr); + return(1); } - if (!event_data && event_num >= 0) { - HIST_ENTRY *rl_he; - rl_he = history_get(event_num); - if (!rl_he) - return (0); - event_data = rl_he->line; + cmd = command + offs + idx + 1; + + /* Now parse any word designators */ + + if (*cmd == '%') /* last word matched by ?pat? */ + tmp = strdup(last_search_match? last_search_match:""); + else if (strchr("^*$-0123456789", *cmd)) { + start = end = -1; + if (*cmd == '^') + start = end = 1, cmd++; + else if (*cmd == '$') + start = -1, cmd++; + else if (*cmd == '*') + start = 1, cmd++; + else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { + start = 0; + while (*cmd && '0' <= *cmd && *cmd <= '9') + start = start * 10 + *cmd++ - '0'; + + if (*cmd == '-') { + if (isdigit((unsigned char) cmd[1])) { + cmd++; + end = 0; + while (*cmd && '0' <= *cmd && *cmd <= '9') + end = end * 10 + *cmd++ - '0'; + } else if (cmd[1] == '$') { + cmd += 2; + end = -1; + } else { + cmd++; + end = -2; + } + } else if (*cmd == '*') + end = -1, cmd++; + else + end = start; + } + tmp = history_arg_extract(start, end, aptr? aptr:ptr); + if (tmp == NULL) { + (void)fprintf(rl_outstream, "%s: Bad word specifier", + command + offs + idx); + if (aptr) + free(aptr); + return(-1); + } } else - return (-1); + tmp = strdup(aptr? aptr:ptr); - if (cmd[idx] != ':') - return (-1); - cmd += idx + 1; - - /* recognize cmd */ - if (*cmd == '^') - start = end = 1, cmd++; - else if (*cmd == '$') - start = end = -1, cmd++; - else if (*cmd == '*') - start = 1, end = -1, cmd++; - else if (isdigit((unsigned char) *cmd)) { - const char *temp; - int shifted = 0; - - start = atoi(cmd); - temp = cmd; - for (; isdigit((unsigned char) *cmd); cmd++); - if (temp != cmd) - shifted = 1; - if (shifted && *cmd == '-') { - if (!isdigit((unsigned char) *(cmd + 1))) - end = -2; - else { - end = atoi(cmd + 1); - for (; isdigit((unsigned char) *cmd); cmd++); - } - } else if (shifted && *cmd == '*') - end = -1, cmd++; - else if (shifted) - end = start; + if (aptr) + free(aptr); + + if (*cmd == 0 || (cmd - (command + offs) >= cmdlen)) { + *result = tmp; + return(1); } - if (*cmd == ':') - cmd++; - line = strdup(event_data); - if (line == NULL) - return 0; for (; *cmd; cmd++) { if (*cmd == ':') continue; - else if (*cmd == 'h') - h_on = 1 | g_on, g_on = 0; - else if (*cmd == 't') - t_on = 1 | g_on, g_on = 0; - else if (*cmd == 'r') - r_on = 1 | g_on, g_on = 0; - else if (*cmd == 'e') - e_on = 1 | g_on, g_on = 0; - else if (*cmd == 'p') - p_on = 1 | g_on, g_on = 0; + else if (*cmd == 'h') { /* remove trailing path */ + if ((aptr = strrchr(tmp, '/')) != NULL) + *aptr = 0; + } else if (*cmd == 't') { /* remove leading path */ + if ((aptr = strrchr(tmp, '/')) != NULL) { + aptr = strdup(aptr + 1); + free(tmp); + tmp = aptr; + } + } else if (*cmd == 'r') { /* remove trailing suffix */ + if ((aptr = strrchr(tmp, '.')) != NULL) + *aptr = 0; + } else if (*cmd == 'e') { /* remove all but suffix */ + if ((aptr = strrchr(tmp, '.')) != NULL) { + aptr = strdup(aptr); + free(tmp); + tmp = aptr; + } + } else if (*cmd == 'p') /* print only */ + p_on = 1; else if (*cmd == 'g') g_on = 2; else if (*cmd == 's' || *cmd == '&') { char *what, *with, delim; - unsigned int len, from_len; + size_t len, from_len; size_t size; if (*cmd == '&' && (from == NULL || to == NULL)) @@ -559,13 +736,12 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) } len = 0; for (; *cmd && *cmd != delim; cmd++) { - if (*cmd == '\\' - && *(cmd + 1) == delim) + if (*cmd == '\\' && cmd[1] == delim) cmd++; if (len >= size) { char *nwhat; nwhat = realloc(what, - (size <<= 1)); + (size <<= 1)); if (nwhat == NULL) { free(what); return 0; @@ -612,7 +788,7 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) } if (*cmd == '&') { /* safe */ - (void) strcpy(&with[len], from); + (void)strcpy(&with[len], from); len += from_len; continue; } @@ -624,88 +800,18 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) } with[len] = '\0'; to = with; - - tempcmd = _rl_compat_sub(line, from, to, - (g_on) ? 1 : 0); - if (tempcmd) { - free(line); - line = tempcmd; - } - g_on = 0; } - } - } - - arr = history_tokenize(line); - free(line); /* no more needed */ - if (arr && *arr == NULL) - free(arr), arr = NULL; - if (!arr) - return (-1); - - /* find out max valid idx to array of array */ - max = 0; - for (i = 0; arr[i]; i++) - max++; - max--; - - /* set boundaries to something relevant */ - if (start < 0) - start = 1; - if (end < 0) - end = max - ((end < -1) ? 1 : 0); - - /* check boundaries ... */ - if (start > max || end > max || start > end) - return (-1); - for (i = 0; i <= max; i++) { - char *temp; - if (h_on && (i == 1 || h_on > 1) && - (temp = strrchr(arr[i], '/'))) - *(temp + 1) = '\0'; - if (t_on && (i == 1 || t_on > 1) && - (temp = strrchr(arr[i], '/'))) - (void) strcpy(arr[i], temp + 1); - if (r_on && (i == 1 || r_on > 1) && - (temp = strrchr(arr[i], '.'))) - *temp = '\0'; - if (e_on && (i == 1 || e_on > 1) && - (temp = strrchr(arr[i], '.'))) - (void) strcpy(arr[i], temp); - } - - cmdsize = 1, cmdlen = 0; - if ((tempcmd = malloc(cmdsize)) == NULL) - return 0; - for (i = start; start <= i && i <= end; i++) { - int arr_len; - - arr_len = strlen(arr[i]); - if (cmdlen + arr_len + 1 >= cmdsize) { - char *ntempcmd; - cmdsize += arr_len + 1; - ntempcmd = realloc(tempcmd, cmdsize); - if (ntempcmd == NULL) { - free(tempcmd); - return 0; + aptr = _rl_compat_sub(tmp, from, to, g_on); + if (aptr) { + free(tmp); + tmp = aptr; } - tempcmd = ntempcmd; + g_on = 0; } - (void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ - cmdlen += arr_len; - tempcmd[cmdlen++] = ' '; /* add a space */ } - while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1])) - cmdlen--; - tempcmd[cmdlen] = '\0'; - - *result = tempcmd; - - for (i = 0; i <= max; i++) - free(arr[i]); - free(arr), arr = (char **) NULL; - return (p_on) ? 2 : 1; + *result = tmp; + return (p_on? 2:1); } @@ -715,27 +821,36 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) int history_expand(char *str, char **output) { - int i, retval = 0, idx; - size_t size; - char *temp, *result; + int ret = 0; + size_t idx, i, size; + char *tmp, *result; if (h == NULL || e == NULL) rl_initialize(); - *output = strdup(str); /* do it early */ - if (*output == NULL) - return 0; + if (history_expansion_char == 0) { + *output = strdup(str); + return(0); + } + *output = NULL; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ - temp = alloca(4 + strlen(str) + 1); - temp[0] = temp[1] = history_expansion_char; - temp[2] = ':'; - temp[3] = 's'; - (void) strcpy(temp + 4, str); - str = temp; + *output = malloc(strlen(str) + 4 + 1); + if (*output == NULL) + return 0; + (*output)[0] = (*output)[1] = history_expansion_char; + (*output)[2] = ':'; + (*output)[3] = 's'; + (void)strcpy((*output) + 4, str); + str = *output; + } else { + *output = strdup(str); + if (*output == NULL) + return 0; } -#define ADD_STRING(what, len) \ + +#define ADD_STRING(what, len) \ { \ if (idx + len + 1 > size) { \ char *nresult = realloc(result, (size += len + 1));\ @@ -753,35 +868,35 @@ history_expand(char *str, char **output) result = NULL; size = idx = 0; for (i = 0; str[i];) { - int start, j, loop_again; - size_t len; + int qchar, loop_again; + size_t len, start, j; + qchar = 0; loop_again = 1; start = j = i; loop: for (; str[j]; j++) { if (str[j] == '\\' && str[j + 1] == history_expansion_char) { - (void) strcpy(&str[j], &str[j + 1]); + (void)strcpy(&str[j], &str[j + 1]); continue; } if (!loop_again) { - if (str[j] == '?') { - while (str[j] && str[++j] != '?'); - if (str[j] == '?') - j++; - } else if (isspace((unsigned char) str[j])) + if (isspace((unsigned char) str[j]) + || str[j] == qchar) break; } if (str[j] == history_expansion_char && !strchr(history_no_expand_chars, str[j + 1]) && (!history_inhibit_expansion_function || - (*history_inhibit_expansion_function)(str, j) == 0)) + (*history_inhibit_expansion_function)(str, + (int)j) == 0)) break; } - if (str[j] && str[j + 1] != '#' && loop_again) { + if (str[j] && loop_again) { i = j; + qchar = (j > 0 && str[j - 1] == '"' )? '"':0; j++; if (str[j] == history_expansion_char) j++; @@ -789,61 +904,116 @@ loop: goto loop; } len = i - start; - temp = &str[start]; - ADD_STRING(temp, len); + tmp = &str[start]; + ADD_STRING(tmp, len); - if (str[i] == '\0' || str[i] != history_expansion_char - || str[i + 1] == '#') { + if (str[i] == '\0' || str[i] != history_expansion_char) { len = j - i; - temp = &str[i]; - ADD_STRING(temp, len); + tmp = &str[i]; + ADD_STRING(tmp, len); if (start == 0) - retval = 0; + ret = 0; else - retval = 1; + ret = 1; break; } - retval = _history_expand_command(&str[i], (size_t) (j - i), - &temp); - if (retval != -1) { - len = strlen(temp); - ADD_STRING(temp, len); + ret = _history_expand_command (str, i, (j - i), &tmp); + if (ret > 0 && tmp) { + len = strlen(tmp); + ADD_STRING(tmp, len); + free(tmp); } i = j; - } /* for(i ...) */ + } - if (retval == 2) { - add_history(temp); + /* ret is 2 for "print only" option */ + if (ret == 2) { + add_history(result); #ifdef GDB_411_HACK /* gdb 4.11 has been shipped with readline, where */ /* history_expand() returned -1 when the line */ /* should not be executed; in readline 2.1+ */ /* it should return 2 in such a case */ - retval = -1; + ret = -1; #endif } free(*output); *output = result; - return (retval); + return (ret); } +/* +* Return a string consisting of arguments of "str" from "start" to "end". +*/ +char * +history_arg_extract(int start, int end, const char *str) +{ + size_t i, len, max; + char **arr, *result; + + arr = history_tokenize(str); + if (!arr) + return(NULL); + if (arr && *arr == NULL) { + free(arr); + return(NULL); + } + + for (max = 0; arr[max]; max++) + continue; + max--; + + if (start == '$') + start = max; + if (end == '$') + end = max; + if (end < 0) + end = max + end + 1; + if (start < 0) + start = end; + + if (start < 0 || end < 0 || start > max || end > max || start > end) + return(NULL); + + for (i = start, len = 0; i <= end; i++) + len += strlen(arr[i]) + 1; + len++; + result = malloc(len); + if (result == NULL) + return NULL; + + for (i = start, len = 0; i <= end; i++) { + (void)strcpy(result + len, arr[i]); + len += strlen(arr[i]); + if (i < end) + result[len++] = ' '; + } + result[len] = 0; + + for (i = 0; arr[i]; i++) + free(arr[i]); + free(arr); + + return(result); +} /* - * Parse the string into individual tokens, similarily to how shell would do it. + * Parse the string into individual tokens, + * similar to how shell would do it. */ char ** history_tokenize(const char *str) { - int size = 1, result_idx = 0, i, start; + int size = 1, idx = 0, i, start; size_t len; char **result = NULL, *temp, delim = '\0'; - for (i = 0; str[i]; i++) { + for (i = 0; str[i];) { while (isspace((unsigned char) str[i])) i++; start = i; - for (; str[i]; i++) { + for (; str[i];) { if (str[i] == '\\') { if (str[i+1] != '\0') i++; @@ -855,9 +1025,11 @@ history_tokenize(const char *str) break; else if (!delim && strchr("'`\"", str[i])) delim = str[i]; + if (str[i]) + i++; } - if (result_idx + 2 >= size) { + if (idx + 2 >= size) { char **nresult; size <<= 1; nresult = realloc(result, size * sizeof(char *)); @@ -870,15 +1042,18 @@ history_tokenize(const char *str) len = i - start; temp = malloc(len + 1); if (temp == NULL) { + for (i = 0; i < idx; i++) + free(result[i]); free(result); return NULL; } - (void) strncpy(temp, &str[start], len); + (void)strncpy(temp, &str[start], len); temp[len] = '\0'; - result[result_idx++] = temp; - result[result_idx] = NULL; + result[idx++] = temp; + result[idx] = NULL; + if (str[i]) + i++; } - return (result); } @@ -962,28 +1137,29 @@ history_get(int num) { static HIST_ENTRY she; HistEvent ev; - int i = 1, curr_num; + int curr_num; if (h == NULL || e == NULL) rl_initialize(); - /* rewind to beginning */ + /* save current position */ if (history(h, &ev, H_CURR) != 0) return (NULL); curr_num = ev.num; - if (history(h, &ev, H_LAST) != 0) + + /* start from most recent */ + if (history(h, &ev, H_FIRST) != 0) return (NULL); /* error */ - while (i < num && history(h, &ev, H_PREV) == 0) - i++; - if (i != num) - return (NULL); /* not so many entries */ + + /* look backwards for event matching specified offset */ + if (history(h, &ev, H_NEXT_EVENT, num)) + return (NULL); she.line = ev.str; she.data = NULL; - /* rewind history to the same event it was before */ - (void) history(h, &ev, H_FIRST); - (void) history(h, &ev, H_NEXT_EVENT, curr_num); + /* restore pointer to where it was */ + (void)history(h, &ev, H_SET, curr_num); return (&she); } @@ -1000,11 +1176,11 @@ add_history(const char *line) if (h == NULL || e == NULL) rl_initialize(); - (void) history(h, &ev, H_ENTER, line); + (void)history(h, &ev, H_ENTER, line); if (history(h, &ev, H_GETSIZE) == 0) history_length = ev.num; - return (!(history_length > 0)); /* return 0 if all is okay */ + return (!(history_length > 0)); /* return 0 if all is okay */ } @@ -1086,22 +1262,17 @@ int history_set_pos(int pos) { HistEvent ev; - int off, curr_num; + int curr_num; if (pos > history_length || pos < 0) return (-1); history(h, &ev, H_CURR); curr_num = ev.num; - history(h, &ev, H_FIRST); - off = 0; - while (off < pos && history(h, &ev, H_NEXT) == 0) - off++; - if (off != pos) { /* do a rollback in case of error */ - history(h, &ev, H_FIRST); - history(h, &ev, H_NEXT_EVENT, curr_num); - return (-1); + if (history(h, &ev, H_SET, pos)) { + history(h, &ev, H_SET, curr_num); + return(-1); } return (0); } @@ -1130,10 +1301,10 @@ next_history(void) /* - * generic history search function + * searches for first history event containing the str */ -static int -_history_search_gen(const char *str, int direction, int pos) +int +history_search(const char *str, int direction) { HistEvent ev; const char *strp; @@ -1144,38 +1315,25 @@ _history_search_gen(const char *str, int direction, int pos) curr_num = ev.num; for (;;) { - strp = strstr(ev.str, str); - if (strp && (pos < 0 || &ev.str[pos] == strp)) + if ((strp = strstr(ev.str, str)) != NULL) return (int) (strp - ev.str); - if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) + if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) break; } - - history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); - + history(h, &ev, H_SET, curr_num); return (-1); } /* - * searches for first history event containing the str - */ -int -history_search(const char *str, int direction) -{ - - return (_history_search_gen(str, direction, -1)); -} - - -/* * searches for first history event beginning with str */ int history_search_prefix(const char *str, int direction) { + HistEvent ev; - return (_history_search_gen(str, direction, 0)); + return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str)); } @@ -1185,8 +1343,8 @@ history_search_prefix(const char *str, int direction) */ /* ARGSUSED */ int -history_search_pos(const char *str, - int direction __attribute__((unused)), int pos) +history_search_pos(const char *str, + int direction __attribute__((__unused__)), int pos) { HistEvent ev; int curr_num, off; @@ -1217,7 +1375,7 @@ history_search_pos(const char *str, /********************************/ -/* completition functions */ +/* completion functions */ /* * does tilde expansion of strings of type ``~user/foo'' @@ -1246,7 +1404,7 @@ tilde_expand(char *txt) temp = malloc(len); if (temp == NULL) return NULL; - (void) strncpy(temp, txt + 1, len - 2); + (void)strncpy(temp, txt + 1, len - 2); temp[len - 2] = '\0'; } pass = getpwnam(temp); @@ -1261,7 +1419,7 @@ tilde_expand(char *txt) temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); if (temp == NULL) return NULL; - (void) sprintf(temp, "%s/%s", pass->pw_dir, txt); + (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); return (temp); } @@ -1295,7 +1453,7 @@ filename_completion_function(const char *text, int state) return NULL; } filename = nptr; - (void) strcpy(filename, temp); + (void)strcpy(filename, temp); len = temp - text; /* including last slash */ nptr = realloc(dirname, len + 1); if (nptr == NULL) { @@ -1303,12 +1461,16 @@ filename_completion_function(const char *text, int state) return NULL; } dirname = nptr; - (void) strncpy(dirname, text, len); + (void)strncpy(dirname, text, len); dirname[len] = '\0'; } else { - filename = strdup(text); - if (filename == NULL) - return NULL; + if (*text == 0) + filename = NULL; + else { + filename = strdup(text); + if (filename == NULL) + return NULL; + } dirname = NULL; } @@ -1324,13 +1486,11 @@ filename_completion_function(const char *text, int state) return NULL; } dirname = nptr; - (void) strcpy(dirname, temp); /* safe */ + (void)strcpy(dirname, temp); /* safe */ free(temp); /* no longer needed */ } /* will be used in cycle */ - filename_len = strlen(filename); - if (filename_len == 0) - return (NULL); /* no expansion possible */ + filename_len = filename ? strlen(filename) : 0; if (dir != NULL) { (void)closedir(dir); @@ -1342,14 +1502,17 @@ filename_completion_function(const char *text, int state) } /* find the match */ while ((entry = readdir(dir)) != NULL) { + /* skip . and .. */ + if (entry->d_name[0] == '.' && (!entry->d_name[1] + || (entry->d_name[1] == '.' && !entry->d_name[2]))) + continue; + if (filename_len == 0) + break; /* otherwise, get first entry where first */ /* filename_len characters are equal */ if (entry->d_name[0] == filename[0] -#ifndef STRUCT_DIRENT_HAS_D_NAMLEN + /* Some dirents have d_namlen, but it is not portable. */ && strlen(entry->d_name) >= filename_len -#else - && entry->d_namlen >= filename_len -#endif && strncmp(entry->d_name, filename, filename_len) == 0) break; @@ -1358,16 +1521,13 @@ filename_completion_function(const char *text, int state) if (entry) { /* match found */ struct stat stbuf; -#ifndef STRUCT_DIRENT_HAS_D_NAMLEN + /* Some dirents have d_namlen, but it is not portable. */ len = strlen(entry->d_name) + -#else - len = entry->d_namlen + -#endif ((dirname) ? strlen(dirname) : 0) + 1 + 1; temp = malloc(len); if (temp == NULL) return NULL; - (void) sprintf(temp, "%s%s", + (void)sprintf(temp, "%s%s", dirname ? dirname : "", entry->d_name); /* safe */ /* test, if it's directory */ @@ -1420,32 +1580,43 @@ username_completion_function(const char *text, int state) */ /* ARGSUSED */ static unsigned char -_el_rl_complete(EditLine *el __attribute__((unused)), int ch) +_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) { return (unsigned char) rl_complete(0, ch); } +/* + * el-compatible wrapper to send TSTP on ^Z + */ +/* ARGSUSED */ +static unsigned char +_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) +{ + (void)kill(0, SIGTSTP); + return CC_NORM; +} /* - * returns list of completitions for text given + * returns list of completions for text given */ char ** completion_matches(const char *text, CPFunction *genfunc) { char **match_list = NULL, *retstr, *prevstr; size_t match_list_len, max_equal, which, i; - unsigned int matches; + size_t matches; if (h == NULL || e == NULL) rl_initialize(); matches = 0; match_list_len = 1; - while ((retstr = (*genfunc) (text, matches)) != NULL) { + while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { /* allow for list terminator here */ - if (matches + 2 >= match_list_len) { + if (matches + 3 >= match_list_len) { char **nmatch_list; - match_list_len <<= 1; + while (matches + 3 >= match_list_len) + match_list_len <<= 1; nmatch_list = realloc(match_list, match_list_len * sizeof(char *)); if (nmatch_list == NULL) { @@ -1477,7 +1648,7 @@ completion_matches(const char *text, CPFunction *genfunc) free(match_list); return NULL; } - (void) strncpy(retstr, match_list[1], max_equal); + (void)strncpy(retstr, match_list[1], max_equal); retstr[max_equal] = '\0'; match_list[0] = retstr; @@ -1532,9 +1703,10 @@ rl_display_match_list (matches, len, max) idx = 1; for(; count > 0; count--) { - for(i=0; i < limit && matches[idx]; i++, idx++) - fprintf(e->el_outfile, "%-*s ", max, matches[idx]); - fprintf(e->el_outfile, "\n"); + for(i = 0; i < limit && matches[idx]; i++, idx++) + (void)fprintf(e->el_outfile, "%-*s ", max, + matches[idx]); + (void)fprintf(e->el_outfile, "\n"); } } @@ -1550,9 +1722,9 @@ rl_display_match_list (matches, len, max) * Note: '*' support is not implemented */ static int -rl_complete_internal(int what_to_do) +_rl_complete_internal(int what_to_do) { - CPFunction *complet_func; + Function *complet_func; const LineInfo *li; char *temp, **matches; const char *ctemp; @@ -1565,7 +1737,7 @@ rl_complete_internal(int what_to_do) complet_func = rl_completion_entry_function; if (!complet_func) - complet_func = filename_completion_function; + complet_func = (Function *)(void *)filename_completion_function; /* We now look backwards for the start of a filename/variable word */ li = el_line(e); @@ -1573,26 +1745,26 @@ rl_complete_internal(int what_to_do) while (ctemp > li->buffer && !strchr(rl_basic_word_break_characters, ctemp[-1]) && (!rl_special_prefixes - || !strchr(rl_special_prefixes, ctemp[-1]) ) ) + || !strchr(rl_special_prefixes, ctemp[-1]) ) ) ctemp--; len = li->cursor - ctemp; temp = alloca(len + 1); - (void) strncpy(temp, ctemp, len); + (void)strncpy(temp, ctemp, len); temp[len] = '\0'; /* these can be used by function called in completion_matches() */ /* or (*rl_attempted_completion_function)() */ - rl_point = li->cursor - li->buffer; - rl_end = li->lastchar - li->buffer; + _rl_update_pos(); - if (!rl_attempted_completion_function) - matches = completion_matches(temp, complet_func); - else { + if (rl_attempted_completion_function) { int end = li->cursor - li->buffer; matches = (*rl_attempted_completion_function) (temp, (int) (end - len), end); - } + } else + matches = 0; + if (!rl_attempted_completion_function || !matches) + matches = completion_matches(temp, (CPFunction *)complet_func); if (matches) { int i, retval = CC_REFRESH; @@ -1613,11 +1785,12 @@ rl_complete_internal(int what_to_do) if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { /* * We found exact match. Add a space after - * it, unless we do filename completition and the + * it, unless we do filename completion and the * object is a directory. */ size_t alen = strlen(matches[0]); - if ((complet_func != filename_completion_function + if ((complet_func != + (Function *)filename_completion_function || (alen > 0 && (matches[0])[alen - 1] != '/')) && rl_completion_append_character) { char buf[2]; @@ -1640,20 +1813,20 @@ rl_complete_internal(int what_to_do) matches_num = i - 1; /* newline to get on next line from command line */ - fprintf(e->el_outfile, "\n"); + (void)fprintf(e->el_outfile, "\n"); /* * If there are too many items, ask user for display * confirmation. */ if (matches_num > rl_completion_query_items) { - fprintf(e->el_outfile, - "Display all %d possibilities? (y or n) ", - matches_num); - fflush(e->el_outfile); + (void)fprintf(e->el_outfile, + "Display all %d possibilities? (y or n) ", + matches_num); + (void)fflush(e->el_outfile); if (getc(stdin) != 'y') match_display = 0; - fprintf(e->el_outfile, "\n"); + (void)fprintf(e->el_outfile, "\n"); } if (match_display) @@ -1689,20 +1862,24 @@ rl_complete_internal(int what_to_do) * complete word at current point */ int +/*ARGSUSED*/ rl_complete(int ignore, int invoking_key) { if (h == NULL || e == NULL) rl_initialize(); if (rl_inhibit_completion) { - rl_insert(ignore, invoking_key); + char arr[2]; + arr[0] = (char)invoking_key; + arr[1] = '\0'; + el_insertstr(e, arr); return (CC_REFRESH); } else if (e->el_state.lastcmd == el_rl_complete_cmdnum) - return rl_complete_internal('?'); + return _rl_complete_internal('?'); else if (_rl_complete_show_all) - return rl_complete_internal('!'); + return _rl_complete_internal('!'); else - return (rl_complete_internal(TAB)); + return _rl_complete_internal(TAB); } @@ -1751,7 +1928,7 @@ rl_read_key(void) */ /* ARGSUSED */ void -rl_reset_terminal(const char *p __attribute__((unused))) +rl_reset_terminal(const char *p __attribute__((__unused__))) { if (h == NULL || e == NULL) @@ -1780,3 +1957,211 @@ rl_insert(int count, int c) return (0); } + +/*ARGSUSED*/ +int +rl_newline(int count, int c) +{ + /* + * Readline-4.0 appears to ignore the args. + */ + return rl_insert(1, '\n'); +} + +/*ARGSUSED*/ +static unsigned char +rl_bind_wrapper(EditLine *el, unsigned char c) +{ + if (map[c] == NULL) + return CC_ERROR; + + _rl_update_pos(); + + (*map[c])(NULL, c); + + /* If rl_done was set by the above call, deal with it here */ + if (rl_done) + return CC_EOF; + + return CC_NORM; +} + +int +rl_add_defun(const char *name, Function *fun, int c) +{ + char dest[8]; + if (c >= sizeof(map) / sizeof(map[0]) || c < 0) + return -1; + map[(unsigned char)c] = fun; + el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); + vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); + el_set(e, EL_BIND, dest, name); + return 0; +} + +void +rl_callback_read_char() +{ + int count = 0, done = 0; + const char *buf = el_gets(e, &count); + char *wbuf; + + if (buf == NULL || count-- <= 0) + return; +#ifdef CTRL2 /* _AIX */ + if (count == 0 && buf[0] == CTRL2('d')) +#else + if (count == 0 && buf[0] == CTRL('d')) +#endif + done = 1; + if (buf[count] == '\n' || buf[count] == '\r') + done = 2; + + if (done && rl_linefunc != NULL) { + el_set(e, EL_UNBUFFERED, 0); + if (done == 2) { + if ((wbuf = strdup(buf)) != NULL) + wbuf[count] = '\0'; + } else + wbuf = NULL; + (*(void (*)(const char *))rl_linefunc)(wbuf); + el_set(e, EL_UNBUFFERED, 1); + } +} + +void +rl_callback_handler_install (const char *prompt, VFunction *linefunc) +{ + if (e == NULL) { + rl_initialize(); + } + if (rl_prompt) + free(rl_prompt); + rl_prompt = prompt ? strdup(strchr(prompt, *prompt)) : NULL; + rl_linefunc = linefunc; + el_set(e, EL_UNBUFFERED, 1); +} + +void +rl_callback_handler_remove(void) +{ + el_set(e, EL_UNBUFFERED, 0); +} + +void +rl_redisplay(void) +{ + char a[2]; +#ifdef CTRL2 /* _AIX */ + a[0] = CTRL2('r'); +#else + a[0] = CTRL('r'); +#endif + a[1] = '\0'; + el_push(e, a); +} + +int +rl_get_previous_history(int count, int key) +{ + char a[2]; + a[0] = key; + a[1] = '\0'; + while (count--) + el_push(e, a); + return 0; +} + +void +/*ARGSUSED*/ +rl_prep_terminal(int meta_flag) +{ + el_set(e, EL_PREP_TERM, 1); +} + +void +rl_deprep_terminal() +{ + el_set(e, EL_PREP_TERM, 0); +} + +int +rl_read_init_file(const char *s) +{ + return(el_source(e, s)); +} + +int +rl_parse_and_bind(const char *line) +{ + const char **argv; + int argc; + Tokenizer *tok; + + tok = tok_init(NULL); + tok_str(tok, line, &argc, &argv); + argc = el_parse(e, argc, argv); + tok_end(tok); + return (argc ? 1 : 0); +} + +void +rl_stuff_char(int c) +{ + char buf[2]; + + buf[0] = c; + buf[1] = '\0'; + el_insertstr(e, buf); +} + +static int +_rl_event_read_char(EditLine *el, char *cp) +{ + int n, num_read = 0; + + *cp = 0; + while (rl_event_hook) { + + (*rl_event_hook)(); + +#if defined(FIONREAD) + if (ioctl(el->el_infd, FIONREAD, &n) < 0) + return(-1); + if (n) + num_read = read(el->el_infd, cp, 1); + else + num_read = 0; +#elif defined(F_SETFL) && defined(O_NDELAY) + if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) + return(-1); + if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) + return(-1); + num_read = read(el->el_infd, cp, 1); + if (fcntl(el->el_infd, F_SETFL, n)) + return(-1); +#else + /* not non-blocking, but what you gonna do? */ + num_read = read(el->el_infd, cp, 1); + return(-1); +#endif + + if (num_read < 0 && errno == EAGAIN) + continue; + if (num_read == 0) + continue; + break; + } + if (!rl_event_hook) + el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); + return(num_read); +} + +static void +_rl_update_pos(void) +{ + const LineInfo *li = el_line(e); + + rl_point = li->cursor - li->buffer; + rl_end = li->lastchar - li->buffer; +} diff --git a/cmd-line-utils/libedit/readline/readline.h b/cmd-line-utils/libedit/readline/readline.h index 7485dde4052..902179c208a 100644 --- a/cmd-line-utils/libedit/readline/readline.h +++ b/cmd-line-utils/libedit/readline/readline.h @@ -1,4 +1,4 @@ -/* $NetBSD: readline.h,v 1.1 2001/01/05 21:15:50 jdolecek Exp $ */ +/* $NetBSD: readline.h,v 1.12 2004/09/08 18:15:37 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _READLINE_H_ -#define _READLINE_H_ +#define _READLINE_H_ #include <sys/types.h> @@ -48,11 +48,45 @@ typedef void VFunction(void); typedef char *CPFunction(const char *, int); typedef char **CPPFunction(const char *, int, int); +typedef void *histdata_t; + typedef struct _hist_entry { const char *line; - const char *data; + histdata_t *data; } HIST_ENTRY; +typedef struct _keymap_entry { + char type; +#define ISFUNC 0 +#define ISKMAP 1 +#define ISMACR 2 + Function *function; +} KEYMAP_ENTRY; + +#define KEYMAP_SIZE 256 + +typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; +typedef KEYMAP_ENTRY *Keymap; + +#define control_character_threshold 0x20 +#define control_character_bit 0x40 + +#ifndef CTRL +#include <sys/ioctl.h> +#ifdef __GLIBC__ +#include <sys/ttydefaults.h> +#endif +#ifndef CTRL +#define CTRL(c) ((c) & 037) +#endif +#endif +#ifndef UNCTRL +#define UNCTRL(c) (((c) - 'a' + 'A')|control_character_bit) +#endif + +#define RUBOUT 0x7f +#define ABORT_CHAR CTRL('G') + /* global variables used by readline enabled applications */ #ifdef __cplusplus extern "C" { @@ -68,12 +102,31 @@ extern int max_input_history; extern char *rl_basic_word_break_characters; extern char *rl_completer_word_break_characters; extern char *rl_completer_quote_characters; -extern CPFunction *rl_completion_entry_function; +extern Function *rl_completion_entry_function; extern CPPFunction *rl_attempted_completion_function; extern int rl_completion_type; extern int rl_completion_query_items; extern char *rl_special_prefixes; extern int rl_completion_append_character; +extern int rl_inhibit_completion; +extern Function *rl_pre_input_hook; +extern Function *rl_startup_hook; +extern char *rl_terminal_name; +extern int rl_already_prompted; +extern char *rl_prompt; +/* + * The following is not implemented + */ +extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, + emacs_meta_keymap, + emacs_ctlx_keymap; +extern int rl_filename_completion_desired; +extern int rl_ignore_completion_duplicates; +extern Function *rl_getc_function; +extern VFunction *rl_redisplay_function; +extern VFunction *rl_completion_display_matches_hook; +extern VFunction *rl_prep_term_function; +extern VFunction *rl_deprep_term_function; /* supported functions */ char *readline(const char *); @@ -99,6 +152,8 @@ int read_history(const char *); int write_history(const char *); int history_expand(char *, char **); char **history_tokenize(const char *); +const char *get_history_event(const char *, int *, int); +char *history_arg_extract(int, int, const char *); char *tilde_expand(char *); char *filename_completion_function(const char *, int); @@ -111,6 +166,26 @@ void rl_display_match_list(char **, int, int); int rl_insert(int, int); void rl_reset_terminal(const char *); int rl_bind_key(int, int (*)(int, int)); +int rl_newline(int, int); +void rl_callback_read_char(void); +void rl_callback_handler_install(const char *, VFunction *); +void rl_callback_handler_remove(void); +void rl_redisplay(void); +int rl_get_previous_history(int, int); +void rl_prep_terminal(int); +void rl_deprep_terminal(void); +int rl_read_init_file(const char *); +int rl_parse_and_bind(const char *); +void rl_stuff_char(int); +int rl_add_defun(const char *, Function *, int); + +/* + * The following are not implemented + */ +Keymap rl_get_keymap(void); +Keymap rl_make_bare_keymap(void); +int rl_generic_bind(int, const char *, const char *, Keymap); +int rl_bind_key_in_map(int, Function *, Keymap); #ifdef __cplusplus } #endif diff --git a/cmd-line-utils/libedit/refresh.c b/cmd-line-utils/libedit/refresh.c index e71bdba2b61..b2833d215c5 100644 --- a/cmd-line-utils/libedit/refresh.c +++ b/cmd-line-utils/libedit/refresh.c @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.c,v 1.24 2003/03/10 21:18:49 christos Exp $ */ +/* $NetBSD: refresh.c,v 1.26 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: refresh.c,v 1.24 2003/03/10 21:18:49 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * refresh.c: Lower level screen refreshing functions @@ -57,8 +46,8 @@ __RCSID("$NetBSD: refresh.c,v 1.24 2003/03/10 21:18:49 christos Exp $"); private void re_addc(EditLine *, int); private void re_update_line(EditLine *, char *, char *, int); -private void re_insert (EditLine *el, char *, int, int, char *, int); -private void re_delete(EditLine *el, char *, int, int, int); +private void re_insert (EditLine *, char *, int, int, char *, int); +private void re_delete(EditLine *, char *, int, int, int); private void re_fastputc(EditLine *, int); private void re__strncopy(char *, char *, size_t); private void re__copy_and_pad(char *, const char *, size_t); @@ -338,8 +327,8 @@ re_goto_bottom(EditLine *el) */ private void /*ARGSUSED*/ -re_insert(EditLine *el __attribute__((unused)), - char *d, int dat, int dlen, char *s, int num) +re_insert(EditLine *el __attribute__((__unused__)), + char *d, int dat, int dlen, char *s, int num) { char *a, *b; @@ -382,8 +371,8 @@ re_insert(EditLine *el __attribute__((unused)), */ private void /*ARGSUSED*/ -re_delete(EditLine *el __attribute__((unused)), - char *d, int dat, int dlen, int num) +re_delete(EditLine *el __attribute__((__unused__)), + char *d, int dat, int dlen, int num) { char *a, *b; diff --git a/cmd-line-utils/libedit/refresh.h b/cmd-line-utils/libedit/refresh.h index 33c0887c1b3..dd2bd02094b 100644 --- a/cmd-line-utils/libedit/refresh.h +++ b/cmd-line-utils/libedit/refresh.h @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.h,v 1.4 2001/01/10 07:45:42 jdolecek Exp $ */ +/* $NetBSD: refresh.h,v 1.5 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/search.c b/cmd-line-utils/libedit/search.c index 0957529485c..848429e091b 100644 --- a/cmd-line-utils/libedit/search.c +++ b/cmd-line-utils/libedit/search.c @@ -1,4 +1,4 @@ -/* $NetBSD: search.c,v 1.14 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: search.c,v 1.20 2004/11/04 01:16:03 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,21 +32,13 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: search.c,v 1.14 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * search.c: History and character search functions */ #include <stdlib.h> #if defined(REGEX) -#include <sys/types.h> #include <regex.h> #elif defined(REGEXP) #include <regexp.h> @@ -227,8 +215,11 @@ ce_inc_search(EditLine *el, int dir) if (el->el_search.patlen == 0) { /* first round */ pchar = ':'; #ifdef ANCHOR +#define LEN 2 el->el_search.patbuf[el->el_search.patlen++] = '.'; el->el_search.patbuf[el->el_search.patlen++] = '*'; +#else +#define LEN 0 #endif } done = redo = 0; @@ -237,7 +228,7 @@ ce_inc_search(EditLine *el, int dir) *cp; *el->el_line.lastchar++ = *cp++) continue; *el->el_line.lastchar++ = pchar; - for (cp = &el->el_search.patbuf[1]; + for (cp = &el->el_search.patbuf[LEN]; cp < &el->el_search.patbuf[el->el_search.patlen]; *el->el_line.lastchar++ = *cp++) continue; @@ -250,7 +241,7 @@ ce_inc_search(EditLine *el, int dir) switch (el->el_map.current[(unsigned char) ch]) { case ED_INSERT: case ED_DIGIT: - if (el->el_search.patlen > EL_BUFSIZ - 3) + if (el->el_search.patlen >= EL_BUFSIZ - LEN) term_beep(el); else { el->el_search.patbuf[el->el_search.patlen++] = @@ -271,8 +262,9 @@ ce_inc_search(EditLine *el, int dir) redo++; break; + case EM_DELETE_PREV_CHAR: case ED_DELETE_PREV_CHAR: - if (el->el_search.patlen > 1) + if (el->el_search.patlen > LEN) done++; else term_beep(el); @@ -287,17 +279,18 @@ ce_inc_search(EditLine *el, int dir) case 0027: /* ^W: Append word */ /* No can do if globbing characters in pattern */ - for (cp = &el->el_search.patbuf[1];; cp++) - if (cp >= &el->el_search.patbuf[el->el_search.patlen]) { + for (cp = &el->el_search.patbuf[LEN];; cp++) + if (cp >= &el->el_search.patbuf[ + el->el_search.patlen]) { el->el_line.cursor += - el->el_search.patlen - 1; + el->el_search.patlen - LEN - 1; cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, 1, ce__isword); while (el->el_line.cursor < cp && *el->el_line.cursor != '\n') { - if (el->el_search.patlen > - EL_BUFSIZ - 3) { + if (el->el_search.patlen >= + EL_BUFSIZ - LEN) { term_beep(el); break; } @@ -339,13 +332,13 @@ ce_inc_search(EditLine *el, int dir) /* Can't search if unmatched '[' */ for (cp = &el->el_search.patbuf[el->el_search.patlen-1], ch = ']'; - cp > el->el_search.patbuf; + cp >= &el->el_search.patbuf[LEN]; cp--) if (*cp == '[' || *cp == ']') { ch = *cp; break; } - if (el->el_search.patlen > 1 && ch != '[') { + if (el->el_search.patlen > LEN && ch != '[') { if (redo && newdir == dir) { if (pchar == '?') { /* wrap around */ el->el_history.eventno = @@ -375,9 +368,8 @@ ce_inc_search(EditLine *el, int dir) '\0'; if (el->el_line.cursor < el->el_line.buffer || el->el_line.cursor > el->el_line.lastchar || - (ret = ce_search_line(el, - &el->el_search.patbuf[1], - newdir)) == CC_ERROR) { + (ret = ce_search_line(el, newdir)) + == CC_ERROR) { /* avoid c_setpat */ el->el_state.lastcmd = (el_action_t) newdir; @@ -390,11 +382,11 @@ ce_inc_search(EditLine *el, int dir) el->el_line.lastchar : el->el_line.buffer; (void) ce_search_line(el, - &el->el_search.patbuf[1], newdir); } } - el->el_search.patbuf[--el->el_search.patlen] = + el->el_search.patlen -= LEN; + el->el_search.patbuf[el->el_search.patlen] = '\0'; if (ret == CC_ERROR) { term_beep(el); @@ -453,9 +445,6 @@ cv_search(EditLine *el, int dir) #ifdef ANCHOR tmpbuf[0] = '.'; tmpbuf[1] = '*'; -#define LEN 2 -#else -#define LEN 0 #endif tmplen = LEN; @@ -521,24 +510,39 @@ cv_search(EditLine *el, int dir) * Look for a pattern inside a line */ protected el_action_t -ce_search_line(EditLine *el, char *pattern, int dir) +ce_search_line(EditLine *el, int dir) { - char *cp; + char *cp = el->el_line.cursor; + char *pattern = el->el_search.patbuf; + char oc, *ocp; +#ifdef ANCHOR + ocp = &pattern[1]; + oc = *ocp; + *ocp = '^'; +#else + ocp = pattern; + oc = *ocp; +#endif if (dir == ED_SEARCH_PREV_HISTORY) { - for (cp = el->el_line.cursor; cp >= el->el_line.buffer; cp--) - if (el_match(cp, pattern)) { + for (; cp >= el->el_line.buffer; cp--) { + if (el_match(cp, ocp)) { + *ocp = oc; el->el_line.cursor = cp; return (CC_NORM); } + } + *ocp = oc; return (CC_ERROR); } else { - for (cp = el->el_line.cursor; *cp != '\0' && - cp < el->el_line.limit; cp++) - if (el_match(cp, pattern)) { + for (; *cp != '\0' && cp < el->el_line.limit; cp++) { + if (el_match(cp, ocp)) { + *ocp = oc; el->el_line.cursor = cp; return (CC_NORM); } + } + *ocp = oc; return (CC_ERROR); } } diff --git a/cmd-line-utils/libedit/search.h b/cmd-line-utils/libedit/search.h index a7363072a4c..2aa8f985013 100644 --- a/cmd-line-utils/libedit/search.h +++ b/cmd-line-utils/libedit/search.h @@ -1,4 +1,4 @@ -/* $NetBSD: search.h,v 1.6 2002/11/15 14:32:34 christos Exp $ */ +/* $NetBSD: search.h,v 1.8 2003/10/18 23:27:36 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -63,7 +59,7 @@ protected int c_hmatch(EditLine *, const char *); protected void c_setpat(EditLine *); protected el_action_t ce_inc_search(EditLine *, int); protected el_action_t cv_search(EditLine *, int); -protected el_action_t ce_search_line(EditLine *, char *, int); +protected el_action_t ce_search_line(EditLine *, int); protected el_action_t cv_repeat_srch(EditLine *, int); protected el_action_t cv_csearch(EditLine *, int, int, int, int); diff --git a/cmd-line-utils/libedit/sig.c b/cmd-line-utils/libedit/sig.c index 3730067ed5f..8e70933d606 100644 --- a/cmd-line-utils/libedit/sig.c +++ b/cmd-line-utils/libedit/sig.c @@ -1,4 +1,4 @@ -/* $NetBSD: sig.c,v 1.10 2003/03/10 00:58:05 christos Exp $ */ +/* $NetBSD: sig.c,v 1.11 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: sig.c,v 1.10 2003/03/10 00:58:05 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * sig.c: Signal handling stuff. diff --git a/cmd-line-utils/libedit/sig.h b/cmd-line-utils/libedit/sig.h index 8effea8e121..0bf1fc37e39 100644 --- a/cmd-line-utils/libedit/sig.h +++ b/cmd-line-utils/libedit/sig.h @@ -1,4 +1,4 @@ -/* $NetBSD: sig.h,v 1.4 2003/03/10 00:58:05 christos Exp $ */ +/* $NetBSD: sig.h,v 1.5 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/strlcpy.c b/cmd-line-utils/libedit/strlcpy.c index 74317d99cd2..e38d6cf1c4b 100644 --- a/cmd-line-utils/libedit/strlcpy.c +++ b/cmd-line-utils/libedit/strlcpy.c @@ -1,28 +1,73 @@ +/* $NetBSD: strlcpy.c,v 1.14 2003/10/27 00:12:42 lukem Exp $ */ +/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <config.h> + +#include <sys/types.h> +#include <assert.h> #include <string.h> -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t size) +#ifdef _LIBC +# ifdef __weak_alias +__weak_alias(strlcpy, _strlcpy) +# endif +#endif + +#if !HAVE_STRLCPY +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +#ifdef _LIBC +_strlcpy(dst, src, siz) +#else +strlcpy(dst, src, siz) +#endif + char *dst; + const char *src; + size_t siz; { - if(size) { - strncpy(dst, src, size-1); - dst[size-1] = '\0'; - } else { - dst[0] = '\0'; + char *d = dst; + const char *s = src; + size_t n = siz; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); } - return strlen(src); -} -size_t strlcat(char *dst, const char *src, size_t size) -{ - int dl = strlen(dst); - int sz = size-dl-1; - - if(sz >= 0) { - strncat(dst, src, sz); - dst[sz] = '\0'; + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; } - return dl+strlen(src); + return(s - src - 1); /* count does not include NUL */ } - #endif diff --git a/cmd-line-utils/libedit/sys.h b/cmd-line-utils/libedit/sys.h index a7477d2c5ba..c8a29dbfb05 100644 --- a/cmd-line-utils/libedit/sys.h +++ b/cmd-line-utils/libedit/sys.h @@ -1,4 +1,4 @@ -/* $NetBSD: sys.h,v 1.6 2003/03/10 00:57:38 christos Exp $ */ +/* $NetBSD: sys.h,v 1.9 2004/01/17 17:57:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -48,6 +44,28 @@ #include <sys/cdefs.h> #endif +#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8) +# define __attribute__(A) +#endif + +#ifndef __P +# define __P(x) x +#endif + +#ifndef _DIAGASSERT +# define _DIAGASSERT(x) +#endif + +#ifndef __BEGIN_DECLS +# ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + #ifndef public # define public /* Externally visible functions/variables */ #endif @@ -61,6 +79,10 @@ /* When we want to hide everything */ #endif +#ifndef HAVE_U_INT32_T +typedef unsigned int u_int32_t; +#endif + #ifndef _PTR_T # define _PTR_T typedef void *ptr_t; diff --git a/cmd-line-utils/libedit/term.c b/cmd-line-utils/libedit/term.c index c4ee0d30aab..b516d6753c3 100644 --- a/cmd-line-utils/libedit/term.c +++ b/cmd-line-utils/libedit/term.c @@ -1,4 +1,4 @@ -/* $NetBSD: term.c,v 1.35 2002/03/18 16:00:59 christos Exp $ */ +/* $NetBSD: term.c,v 1.40 2004/05/22 23:21:28 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; -#else -__RCSID("$NetBSD: term.c,v 1.35 2002/03/18 16:00:59 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * term.c: Editor/termcap-curses interface @@ -55,24 +44,23 @@ __RCSID("$NetBSD: term.c,v 1.35 2002/03/18 16:00:59 christos Exp $"); #include <string.h> #include <stdlib.h> #include <unistd.h> -#ifdef HAVE_TERMCAP_H -#include <termcap.h> -#endif + #ifdef HAVE_CURSES_H -#include <curses.h> -#endif -#ifdef HAVE_NCURSES_H -#include <ncurses.h> +# include <curses.h> +#elif HAVE_NCURSES_H +# include <ncurses.h> #endif -#include "el.h" - -#if !defined(HAVE_TERMCAP_H) && defined(HAVE_TERM_H) -#include <term.h> +/* Solaris's term.h does horrid things. */ +#if (defined(HAVE_TERM_H) && !defined(_SUNOS)) +# include <term.h> #endif + #include <sys/types.h> #include <sys/ioctl.h> +#include "el.h" + /* * IMPORTANT NOTE: these routines are allowed to look at the current screen * and the current possition assuming that it is correct. If this is not @@ -356,6 +344,7 @@ term_init(EditLine *el) term_init_arrow(el); return (0); } + /* term_end(): * Clean up the terminal stuff */ @@ -372,6 +361,8 @@ term_end(EditLine *el) el->el_term.t_str = NULL; el_free((ptr_t) el->el_term.t_val); el->el_term.t_val = NULL; + el_free((ptr_t) el->el_term.t_fkey); + el->el_term.t_fkey = NULL; term_free_display(el); } @@ -648,7 +639,8 @@ mc_again: * from col 0 */ if (EL_CAN_TAB ? - (((unsigned int)-del) > (((unsigned int) where >> 3) + + ((unsigned int)-del > + (((unsigned int) where >> 3) + (where & 07))) : (-del > where)) { term__putc('\r'); /* do a CR */ @@ -876,6 +868,12 @@ term_clear_to_bottom(EditLine *el) } #endif +protected void +term_get(EditLine *el, const char **term) +{ + *term = el->el_term.t_name; +} + /* term_set(): * Read in the terminal capabilities from the requested terminal @@ -937,8 +935,11 @@ term_set(EditLine *el, const char *term) /* Get the size */ Val(T_co) = tgetnum("co"); Val(T_li) = tgetnum("li"); - for (t = tstr; t->name != NULL; t++) - term_alloc(el, t, tgetstr(t->name, &area)); + for (t = tstr; t->name != NULL; t++) { + /* XXX: some systems tgetstr needs non const */ + term_alloc(el, t, tgetstr(strchr(t->name, *t->name), + &area)); + } } if (Val(T_co) < 2) @@ -957,6 +958,7 @@ term_set(EditLine *el, const char *term) return (-1); (void) sigprocmask(SIG_SETMASK, &oset, NULL); term_bind_arrow(el); + el->el_term.t_name = term; return (i <= 0 ? -1 : 0); } @@ -1078,32 +1080,32 @@ term_reset_arrow(EditLine *el) static const char stOH[] = {033, 'O', 'H', '\0'}; static const char stOF[] = {033, 'O', 'F', '\0'}; - el_key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); - el_key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); if (el->el_map.type == MAP_VI) { - el_key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); - el_key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); } } @@ -1157,7 +1159,7 @@ term_print_arrow(EditLine *el, const char *name) for (i = 0; i < A_K_NKEYS; i++) if (*name == '\0' || strcmp(name, arrow[i].name) == 0) if (arrow[i].type != XK_NOD) - el_key_kprint(el, arrow[i].name, &arrow[i].fun, + key_kprint(el, arrow[i].name, &arrow[i].fun, arrow[i].type); } @@ -1198,20 +1200,20 @@ term_bind_arrow(EditLine *el) * unassigned key. */ if (arrow[i].type == XK_NOD) - el_key_clear(el, map, p); + key_clear(el, map, p); else { if (p[1] && (dmap[j] == map[j] || map[j] == ED_SEQUENCE_LEAD_IN)) { - el_key_add(el, p, &arrow[i].fun, + key_add(el, p, &arrow[i].fun, arrow[i].type); map[j] = ED_SEQUENCE_LEAD_IN; } else if (map[j] == ED_UNASSIGNED) { - el_key_clear(el, map, p); + key_clear(el, map, p); if (arrow[i].type == XK_CMD) map[j] = arrow[i].fun.cmd; else - el_key_add(el, p, &arrow[i].fun, - arrow[i].type); + key_add(el, p, &arrow[i].fun, + arrow[i].type); } } } @@ -1244,12 +1246,10 @@ term__flush(void) /* term_telltc(): * Print the current termcap characteristics */ -char *el_key__decode_str(const char *, char *, const char *); - protected int /*ARGSUSED*/ -term_telltc(EditLine *el, int argc __attribute__((unused)), - const char **argv __attribute__((unused))) +term_telltc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv __attribute__((__unused__))) { const struct termcapstr *t; char **ts; @@ -1273,7 +1273,7 @@ term_telltc(EditLine *el, int argc __attribute__((unused)), (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", t->long_name, t->name, *ts && **ts ? - el_key__decode_str(*ts, upbuf, "") : "(empty)"); + key__decode_str(*ts, upbuf, "") : "(empty)"); (void) fputc('\n', el->el_outfile); return (0); } @@ -1284,8 +1284,8 @@ term_telltc(EditLine *el, int argc __attribute__((unused)), */ protected int /*ARGSUSED*/ -term_settc(EditLine *el, int argc __attribute__((unused)), - const char **argv __attribute__((unused))) +term_settc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv) { const struct termcapstr *ts; const struct termcapval *tv; @@ -1361,9 +1361,8 @@ term_settc(EditLine *el, int argc __attribute__((unused)), */ protected int /*ARGSUSED*/ -term_echotc(EditLine *el __attribute__((unused)), - int argc __attribute__((unused)), - const char **argv __attribute__((unused))) +term_echotc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv) { char *cap, *scap, *ep; int arg_need, arg_cols, arg_rows; @@ -1422,7 +1421,7 @@ term_echotc(EditLine *el __attribute__((unused)), } (void) fprintf(el->el_outfile, fmtd, 0); #else - (void) fprintf(el->el_outfile, fmtd, el->el_tty.t_speed); + (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed); #endif return (0); } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { @@ -1441,8 +1440,10 @@ term_echotc(EditLine *el __attribute__((unused)), scap = el->el_term.t_str[t - tstr]; break; } - if (t->name == NULL) - scap = tgetstr(*argv, &area); + if (t->name == NULL) { + /* XXX: some systems tgetstr needs non const */ + scap = tgetstr(strchr(*argv, **argv), &area); + } if (!scap || scap[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, diff --git a/cmd-line-utils/libedit/tokenizer.c b/cmd-line-utils/libedit/tokenizer.c index f6892d9954c..561b41740f8 100644 --- a/cmd-line-utils/libedit/tokenizer.c +++ b/cmd-line-utils/libedit/tokenizer.c @@ -1,4 +1,4 @@ -/* $NetBSD: tokenizer.c,v 1.11 2002/10/27 20:24:29 christos Exp $ */ +/* $NetBSD: tokenizer.c,v 1.14 2003/12/05 13:37:48 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,21 +32,14 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: tokenizer.c,v 1.11 2002/10/27 20:24:29 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * tokenize.c: Bourne shell like tokenizer */ #include <string.h> #include <stdlib.h> -#include "tokenizer.h" +#include "histedit.h" typedef enum { Q_none, Q_single, Q_double, Q_one, Q_doubleone @@ -64,6 +53,7 @@ typedef enum { #define WINCR 20 #define AINCR 10 +#define tok_strdup(a) strdup(a) #define tok_malloc(a) malloc(a) #define tok_free(a) free(a) #define tok_realloc(a, b) realloc(a, b) @@ -111,7 +101,7 @@ tok_init(const char *ifs) if (tok == NULL) return NULL; - tok->ifs = strdup(ifs ? ifs : IFS); + tok->ifs = tok_strdup(ifs ? ifs : IFS); if (tok->ifs == NULL) { tok_free((ptr_t)tok); return NULL; @@ -173,21 +163,39 @@ tok_end(Tokenizer *tok) /* tok_line(): - * Bourne shell like tokenizing - * Return: - * -1: Internal error - * 3: Quoted return - * 2: Unmatched double quote - * 1: Unmatched single quote - * 0: Ok + * Bourne shell (sh(1)) like tokenizing + * Arguments: + * tok current tokenizer state (setup with tok_init()) + * line line to parse + * Returns: + * -1 Internal error + * 3 Quoted return + * 2 Unmatched double quote + * 1 Unmatched single quote + * 0 Ok + * Modifies (if return value is 0): + * argc number of arguments + * argv argument array + * cursorc if !NULL, argv element containing cursor + * cursorv if !NULL, offset in argv[cursorc] of cursor */ public int -tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) +tok_line(Tokenizer *tok, const LineInfo *line, + int *argc, const char ***argv, int *cursorc, int *cursoro) { const char *ptr; - - for (;;) { - switch (*(ptr = line++)) { + int cc, co; + + cc = co = -1; + ptr = line->buffer; + for (ptr = line->buffer; ;ptr++) { + if (ptr >= line->lastchar) + ptr = ""; + if (ptr == line->cursor) { + cc = tok->argc; + co = tok->wptr - tok->wstart; + } + switch (*ptr) { case '\'': tok->flags |= TOK_KEEP; tok->flags &= ~TOK_EAT; @@ -286,10 +294,7 @@ tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) tok->flags &= ~TOK_EAT; switch (tok->quote) { case Q_none: - tok_finish(tok); - *argv = (const char **)tok->argv; - *argc = tok->argc; - return (0); + goto tok_line_outok; case Q_single: case Q_double: @@ -319,10 +324,7 @@ tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) tok->flags &= ~TOK_EAT; return (3); } - tok_finish(tok); - *argv = (const char **)tok->argv; - *argc = tok->argc; - return (0); + goto tok_line_outok; case Q_single: return (1); @@ -407,4 +409,32 @@ tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) tok->argv = p; } } + tok_line_outok: + if (cc == -1 && co == -1) { + cc = tok->argc; + co = tok->wptr - tok->wstart; + } + if (cursorc != NULL) + *cursorc = cc; + if (cursoro != NULL) + *cursoro = co; + tok_finish(tok); + *argv = (const char **)tok->argv; + *argc = tok->argc; + return (0); +} + +/* tok_str(): + * Simpler version of tok_line, taking a NUL terminated line + * and splitting into words, ignoring cursor state. + */ +public int +tok_str(Tokenizer *tok, const char *line, int *argc, const char ***argv) +{ + LineInfo li; + + memset(&li, 0, sizeof(li)); + li.buffer = line; + li.cursor = li.lastchar = strchr(line, '\0'); + return (tok_line(tok, &li, argc, argv, NULL, NULL)); } diff --git a/cmd-line-utils/libedit/tty.c b/cmd-line-utils/libedit/tty.c index fe81762fb82..6f73fb4f9e7 100644 --- a/cmd-line-utils/libedit/tty.c +++ b/cmd-line-utils/libedit/tty.c @@ -1,4 +1,4 @@ -/* $NetBSD: tty.c,v 1.16 2002/03/18 16:01:01 christos Exp $ */ +/* $NetBSD: tty.c,v 1.21 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,18 +32,12 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: tty.c,v 1.16 2002/03/18 16:01:01 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include <config.h> /* * tty.c: tty interface stuff */ +#include <assert.h> #include "tty.h" #include "el.h" @@ -124,11 +114,11 @@ private const ttychar_t ttychar = { private const ttymap_t tty_map[] = { #ifdef VERASE {C_ERASE, VERASE, - {ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, + {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE */ #ifdef VERASE2 {C_ERASE2, VERASE2, - {ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, + {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE2 */ #ifdef VKILL {C_KILL, VKILL, @@ -455,6 +445,7 @@ private const ttymodes_t ttymodes[] = { #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) #define tty__cooked_mode(td) ((td)->c_lflag & ICANON) +private int tty__getcharindex(int); private void tty__getchar(struct termios *, unsigned char *); private void tty__setchar(struct termios *, unsigned char *); private speed_t tty__getspeed(struct termios *); @@ -568,7 +559,7 @@ tty_init(EditLine *el) */ protected void /*ARGSUSED*/ -tty_end(EditLine *el __attribute__((unused))) +tty_end(EditLine *el __attribute__((__unused__))) { /* XXX: Maybe reset to an initial state? */ @@ -588,6 +579,113 @@ tty__getspeed(struct termios *td) return (spd); } +/* tty__getspeed(): + * Return the index of the asked char in the c_cc array + */ +private int +tty__getcharindex(int i) +{ + switch (i) { +#ifdef VINTR + case C_INTR: + return VINTR; +#endif /* VINTR */ +#ifdef VQUIT + case C_QUIT: + return VQUIT; +#endif /* VQUIT */ +#ifdef VERASE + case C_ERASE: + return VERASE; +#endif /* VERASE */ +#ifdef VKILL + case C_KILL: + return VKILL; +#endif /* VKILL */ +#ifdef VEOF + case C_EOF: + return VEOF; +#endif /* VEOF */ +#ifdef VEOL + case C_EOL: + return VEOL; +#endif /* VEOL */ +#ifdef VEOL2 + case C_EOL2: + return VEOL2; +#endif /* VEOL2 */ +#ifdef VSWTCH + case C_SWTCH: + return VSWTCH; +#endif /* VSWTCH */ +#ifdef VDSWTCH + case C_DSWTCH: + return VDSWTCH; +#endif /* VDSWTCH */ +#ifdef VERASE2 + case C_ERASE2: + return VERASE2; +#endif /* VERASE2 */ +#ifdef VSTART + case C_START: + return VSTART; +#endif /* VSTART */ +#ifdef VSTOP + case C_STOP: + return VSTOP; +#endif /* VSTOP */ +#ifdef VWERASE + case C_WERASE: + return VWERASE; +#endif /* VWERASE */ +#ifdef VSUSP + case C_SUSP: + return VSUSP; +#endif /* VSUSP */ +#ifdef VDSUSP + case C_DSUSP: + return VDSUSP; +#endif /* VDSUSP */ +#ifdef VREPRINT + case C_REPRINT: + return VREPRINT; +#endif /* VREPRINT */ +#ifdef VDISCARD + case C_DISCARD: + return VDISCARD; +#endif /* VDISCARD */ +#ifdef VLNEXT + case C_LNEXT: + return VLNEXT; +#endif /* VLNEXT */ +#ifdef VSTATUS + case C_STATUS: + return VSTATUS; +#endif /* VSTATUS */ +#ifdef VPAGE + case C_PAGE: + return VPAGE; +#endif /* VPAGE */ +#ifdef VPGOFF + case C_PGOFF: + return VPGOFF; +#endif /* VPGOFF */ +#ifdef VKILL2 + case C_KILL2: + return VKILL2; +#endif /* KILL2 */ +#ifdef VMIN + case C_MIN: + return VMIN; +#endif /* VMIN */ +#ifdef VTIME + case C_TIME: + return VTIME; +#endif /* VTIME */ + default: + return -1; + } +} /* tty__getchar(): * Get the tty characters @@ -784,15 +882,15 @@ tty_bind_char(EditLine *el, int force) if (new[0] == old[0] && !force) continue; /* Put the old default binding back, and set the new binding */ - el_key_clear(el, map, (char *)old); + key_clear(el, map, (char *)old); map[old[0]] = dmap[old[0]]; - el_key_clear(el, map, (char *)new); + key_clear(el, map, (char *)new); /* MAP_VI == 1, MAP_EMACS == 0... */ map[new[0]] = tp->bind[el->el_map.type]; if (dalt) { - el_key_clear(el, alt, (char *)old); + key_clear(el, alt, (char *)old); alt[old[0]] = dalt[old[0]]; - el_key_clear(el, alt, (char *)new); + key_clear(el, alt, (char *)new); alt[new[0]] = tp->bind[el->el_map.type + 1]; } } @@ -1041,13 +1139,14 @@ tty_noquotemode(EditLine *el) */ protected int /*ARGSUSED*/ -tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) +tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) { const ttymodes_t *m; char x; int aflag = 0; const char *s, *d; const char *name; + struct termios *tios = &el->el_tty.t_ex; int z = EX_IO; if (argv == NULL) @@ -1062,14 +1161,17 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) break; case 'd': argv++; + tios = &el->el_tty.t_ed; z = ED_IO; break; case 'x': argv++; + tios = &el->el_tty.t_ex; z = EX_IO; break; case 'q': argv++; + tios = &el->el_tty.t_ts; z = QU_IO; break; default: @@ -1119,6 +1221,7 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) return (0); } while (argv && (s = *argv++)) { + char *p; switch (*s) { case '+': case '-': @@ -1129,8 +1232,11 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) break; } d = s; + if ((p = strchr(s, '=')) != NULL) + *p++ = '\0'; for (m = ttymodes; m->m_name; m++) - if (strcmp(m->m_name, d) == 0) + if (strcmp(m->m_name, d) == 0 && + (p == NULL || m->m_type == MD_CHAR)) break; if (!m->m_name) { @@ -1138,6 +1244,16 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) "%s: Invalid argument `%s'.\n", name, d); return (-1); } + if (p) { + int c = ffs((int)m->m_value); + int v = *p ? parse__escape((const char **const) &p) : + el->el_tty.t_vdisable; + assert(c-- != 0); + c = tty__getcharindex(c); + assert(c != -1); + tios->c_cc[c] = v; + continue; + } switch (x) { case '+': el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; diff --git a/cmd-line-utils/libedit/tty.h b/cmd-line-utils/libedit/tty.h index e9597fceb2b..cc7c4ad8c66 100644 --- a/cmd-line-utils/libedit/tty.h +++ b/cmd-line-utils/libedit/tty.h @@ -1,4 +1,4 @@ -/* $NetBSD: tty.h,v 1.9 2002/03/18 16:01:01 christos Exp $ */ +/* $NetBSD: tty.h,v 1.10 2003/08/07 16:44:34 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/unvis.c b/cmd-line-utils/libedit/unvis.c new file mode 100644 index 00000000000..ffa8ac4251c --- /dev/null +++ b/cmd-line-utils/libedit/unvis.c @@ -0,0 +1,311 @@ +/* $NetBSD: unvis.c,v 1.24 2003/08/07 16:42:59 agc Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> + +#define __LIBC12_SOURCE__ + +#include <sys/types.h> + +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <vis.h> + +#ifdef __weak_alias +__weak_alias(strunvis,_strunvis) +__weak_alias(unvis,_unvis) +#endif + +#ifdef __warn_references +__warn_references(unvis, + "warning: reference to compatibility unvis(); include <vis.h> for correct reference") +#endif + +#if !HAVE_VIS +/* + * decode driven by state machine + */ +#define S_GROUND 0 /* haven't seen escape char */ +#define S_START 1 /* start decoding special sequence */ +#define S_META 2 /* metachar started (M) */ +#define S_META1 3 /* metachar more, regular char (-) */ +#define S_CTRL 4 /* control char started (^) */ +#define S_OCTAL2 5 /* octal digit 2 */ +#define S_OCTAL3 6 /* octal digit 3 */ +#define S_HEX1 7 /* hex digit */ +#define S_HEX2 8 /* hex digit 2 */ + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10)) + +int +unvis(cp, c, astate, flag) + char *cp; + int c; + int *astate, flag; +{ + return __unvis13(cp, (int)c, astate, flag); +} + +/* + * unvis - decode characters previously encoded by vis + */ +int +__unvis13(cp, c, astate, flag) + char *cp; + int c; + int *astate, flag; +{ + + _DIAGASSERT(cp != NULL); + _DIAGASSERT(astate != NULL); + + if (flag & UNVIS_END) { + if (*astate == S_OCTAL2 || *astate == S_OCTAL3 + || *astate == S_HEX2) { + *astate = S_GROUND; + return (UNVIS_VALID); + } + return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD); + } + + switch (*astate) { + + case S_GROUND: + *cp = 0; + if (c == '\\') { + *astate = S_START; + return (0); + } + if ((flag & VIS_HTTPSTYLE) && c == '%') { + *astate = S_HEX1; + return (0); + } + *cp = c; + return (UNVIS_VALID); + + case S_START: + switch(c) { + case '\\': + *cp = c; + *astate = S_GROUND; + return (UNVIS_VALID); + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + *cp = (c - '0'); + *astate = S_OCTAL2; + return (0); + case 'M': + *cp = (char)0200; + *astate = S_META; + return (0); + case '^': + *astate = S_CTRL; + return (0); + case 'n': + *cp = '\n'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'r': + *cp = '\r'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'b': + *cp = '\b'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'a': + *cp = '\007'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'v': + *cp = '\v'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 't': + *cp = '\t'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'f': + *cp = '\f'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 's': + *cp = ' '; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'E': + *cp = '\033'; + *astate = S_GROUND; + return (UNVIS_VALID); + case '\n': + /* + * hidden newline + */ + *astate = S_GROUND; + return (UNVIS_NOCHAR); + case '$': + /* + * hidden marker + */ + *astate = S_GROUND; + return (UNVIS_NOCHAR); + } + *astate = S_GROUND; + return (UNVIS_SYNBAD); + + case S_META: + if (c == '-') + *astate = S_META1; + else if (c == '^') + *astate = S_CTRL; + else { + *astate = S_GROUND; + return (UNVIS_SYNBAD); + } + return (0); + + case S_META1: + *astate = S_GROUND; + *cp |= c; + return (UNVIS_VALID); + + case S_CTRL: + if (c == '?') + *cp |= 0177; + else + *cp |= c & 037; + *astate = S_GROUND; + return (UNVIS_VALID); + + case S_OCTAL2: /* second possible octal digit */ + if (isoctal(c)) { + /* + * yes - and maybe a third + */ + *cp = (*cp << 3) + (c - '0'); + *astate = S_OCTAL3; + return (0); + } + /* + * no - done with current sequence, push back passed char + */ + *astate = S_GROUND; + return (UNVIS_VALIDPUSH); + + case S_OCTAL3: /* third possible octal digit */ + *astate = S_GROUND; + if (isoctal(c)) { + *cp = (*cp << 3) + (c - '0'); + return (UNVIS_VALID); + } + /* + * we were done, push back passed char + */ + return (UNVIS_VALIDPUSH); + case S_HEX1: + if (isxdigit(c)) { + *cp = xtod(c); + *astate = S_HEX2; + return (0); + } + /* + * no - done with current sequence, push back passed char + */ + *astate = S_GROUND; + return (UNVIS_VALIDPUSH); + case S_HEX2: + *astate = S_GROUND; + if (isxdigit(c)) { + *cp = xtod(c) | (*cp << 4); + return (UNVIS_VALID); + } + return (UNVIS_VALIDPUSH); + default: + /* + * decoder in unknown state - (probably uninitialized) + */ + *astate = S_GROUND; + return (UNVIS_SYNBAD); + } +} + +/* + * strunvis - decode src into dst + * + * Number of chars decoded into dst is returned, -1 on error. + * Dst is null terminated. + */ + +int +strunvisx(dst, src, flag) + char *dst; + const char *src; + int flag; +{ + char c; + char *start = dst; + int state = 0; + + _DIAGASSERT(src != NULL); + _DIAGASSERT(dst != NULL); + + while ((c = *src++) != '\0') { + again: + switch (__unvis13(dst, c, &state, flag)) { + case UNVIS_VALID: + dst++; + break; + case UNVIS_VALIDPUSH: + dst++; + goto again; + case 0: + case UNVIS_NOCHAR: + break; + default: + return (-1); + } + } + if (__unvis13(dst, c, &state, UNVIS_END) == UNVIS_VALID) + dst++; + *dst = '\0'; + return (dst - start); +} + +int +strunvis(dst, src) + char *dst; + const char *src; +{ + return strunvisx(dst, src, 0); +} +#endif diff --git a/cmd-line-utils/libedit/vi.c b/cmd-line-utils/libedit/vi.c index 5380872cf65..4a0352859dd 100644 --- a/cmd-line-utils/libedit/vi.c +++ b/cmd-line-utils/libedit/vi.c @@ -1,4 +1,4 @@ -/* $NetBSD: vi.c,v 1.16 2003/03/10 11:09:25 dsl Exp $ */ +/* $NetBSD: vi.c,v 1.20 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,18 +32,11 @@ * SUCH DAMAGE. */ -#include "config.h" +#include <config.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: vi.c,v 1.16 2003/03/10 11:09:25 dsl Exp $"); -#endif -#endif /* not lint && not SCCSID */ /* * vi.c: Vi mode commands. @@ -123,7 +112,7 @@ cv_paste(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_paste_next(EditLine *el, int c __attribute__((unused))) +vi_paste_next(EditLine *el, int c __attribute__((__unused__))) { return (cv_paste(el, 0)); @@ -136,7 +125,7 @@ vi_paste_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_paste_prev(EditLine *el, int c __attribute__((unused))) +vi_paste_prev(EditLine *el, int c __attribute__((__unused__))) { return (cv_paste(el, 1)); @@ -149,7 +138,7 @@ vi_paste_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_big_word(EditLine *el, int c __attribute__((unused))) +vi_prev_big_word(EditLine *el, int c) { if (el->el_line.cursor == el->el_line.buffer) @@ -174,7 +163,7 @@ vi_prev_big_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_word(EditLine *el, int c __attribute__((unused))) +vi_prev_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) @@ -199,7 +188,7 @@ vi_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_next_big_word(EditLine *el, int c __attribute__((unused))) +vi_next_big_word(EditLine *el, int c) { if (el->el_line.cursor >= el->el_line.lastchar - 1) @@ -223,7 +212,7 @@ vi_next_big_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_next_word(EditLine *el, int c __attribute__((unused))) +vi_next_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor >= el->el_line.lastchar - 1) @@ -278,7 +267,7 @@ vi_change_case(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_change_meta(EditLine *el, int c __attribute__((unused))) +vi_change_meta(EditLine *el, int c __attribute__((__unused__))) { /* @@ -295,7 +284,7 @@ vi_change_meta(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_insert_at_bol(EditLine *el, int c __attribute__((unused))) +vi_insert_at_bol(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; @@ -311,7 +300,7 @@ vi_insert_at_bol(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_replace_char(EditLine *el, int c __attribute__((unused))) +vi_replace_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor >= el->el_line.lastchar) @@ -330,7 +319,7 @@ vi_replace_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_replace_mode(EditLine *el, int c __attribute__((unused))) +vi_replace_mode(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; @@ -346,7 +335,7 @@ vi_replace_mode(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_substitute_char(EditLine *el, int c __attribute__((unused))) +vi_substitute_char(EditLine *el, int c __attribute__((__unused__))) { c_delafter(el, el->el_state.argument); @@ -361,7 +350,7 @@ vi_substitute_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_substitute_line(EditLine *el, int c __attribute__((unused))) +vi_substitute_line(EditLine *el, int c __attribute__((__unused__))) { cv_undo(el); @@ -379,7 +368,7 @@ vi_substitute_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_change_to_eol(EditLine *el, int c __attribute__((unused))) +vi_change_to_eol(EditLine *el, int c __attribute__((__unused__))) { cv_undo(el); @@ -397,7 +386,7 @@ vi_change_to_eol(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_insert(EditLine *el, int c __attribute__((unused))) +vi_insert(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; @@ -412,7 +401,7 @@ vi_insert(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_add(EditLine *el, int c __attribute__((unused))) +vi_add(EditLine *el, int c __attribute__((__unused__))) { int ret; @@ -437,7 +426,7 @@ vi_add(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_add_at_eol(EditLine *el, int c __attribute__((unused))) +vi_add_at_eol(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; @@ -453,7 +442,7 @@ vi_add_at_eol(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_delete_meta(EditLine *el, int c __attribute__((unused))) +vi_delete_meta(EditLine *el, int c __attribute__((__unused__))) { return (cv_action(el, DELETE)); @@ -466,7 +455,7 @@ vi_delete_meta(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_end_big_word(EditLine *el, int c __attribute__((unused))) +vi_end_big_word(EditLine *el, int c) { if (el->el_line.cursor == el->el_line.lastchar) @@ -490,7 +479,7 @@ vi_end_big_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_end_word(EditLine *el, int c __attribute__((unused))) +vi_end_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) @@ -514,7 +503,7 @@ vi_end_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_undo(EditLine *el, int c __attribute__((unused))) +vi_undo(EditLine *el, int c __attribute__((__unused__))) { c_undo_t un = el->el_chared.c_undo; @@ -540,7 +529,7 @@ vi_undo(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_command_mode(EditLine *el, int c __attribute__((unused))) +vi_command_mode(EditLine *el, int c __attribute__((__unused__))) { /* [Esc] cancels pending action */ @@ -585,20 +574,14 @@ vi_zero(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_delete_prev_char(EditLine *el, int c __attribute__((unused))) +vi_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) { - char *cp; - cp = el->el_line.cursor; - if (cp <= el->el_line.buffer) + if (el->el_line.cursor <= el->el_line.buffer) return (CC_ERROR); - /* do the delete here so we dont mess up the undo and paste buffers */ - el->el_line.cursor = --cp; - for (; cp < el->el_line.lastchar; cp++) - cp[0] = cp[1]; - el->el_line.lastchar = cp - 1; - + c_delbefore1(el); + el->el_line.cursor--; return (CC_REFRESH); } @@ -609,23 +592,35 @@ vi_delete_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_list_or_eof(EditLine *el, int c __attribute__((unused))) +vi_list_or_eof(EditLine *el, int c __attribute__((__unused__))) { -#ifdef notyet - if (el->el_line.cursor == el->el_line.lastchar && - el->el_line.cursor == el->el_line.buffer) { -#endif - term_overwrite(el, STReof, 4); /* then do a EOF */ - term__flush(); - return (CC_EOF); -#ifdef notyet + if (el->el_line.cursor == el->el_line.lastchar) { + if (el->el_line.cursor == el->el_line.buffer) { + term_overwrite(el, STReof, 4); /* then do a EOF */ + term__flush(); + return (CC_EOF); + } else { + /* + * Here we could list completions, but it is an + * error right now + */ + term_beep(el); + return (CC_ERROR); + } } else { +#ifdef notyet re_goto_bottom(el); *el->el_line.lastchar = '\0'; /* just in case */ return (CC_LIST_CHOICES); - } +#else + /* + * Just complain for now. + */ + term_beep(el); + return (CC_ERROR); #endif + } } @@ -635,7 +630,7 @@ vi_list_or_eof(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_kill_line_prev(EditLine *el, int c __attribute__((unused))) +vi_kill_line_prev(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -656,7 +651,7 @@ vi_kill_line_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_search_prev(EditLine *el, int c __attribute__((unused))) +vi_search_prev(EditLine *el, int c __attribute__((__unused__))) { return (cv_search(el, ED_SEARCH_PREV_HISTORY)); @@ -669,7 +664,7 @@ vi_search_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_search_next(EditLine *el, int c __attribute__((unused))) +vi_search_next(EditLine *el, int c __attribute__((__unused__))) { return (cv_search(el, ED_SEARCH_NEXT_HISTORY)); @@ -682,7 +677,7 @@ vi_search_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_search_next(EditLine *el, int c __attribute__((unused))) +vi_repeat_search_next(EditLine *el, int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) @@ -698,7 +693,7 @@ vi_repeat_search_next(EditLine *el, int c __attribute__((unused))) */ /*ARGSUSED*/ protected el_action_t -vi_repeat_search_prev(EditLine *el, int c __attribute__((unused))) +vi_repeat_search_prev(EditLine *el, int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) @@ -716,7 +711,7 @@ vi_repeat_search_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_next_char(EditLine *el, int c __attribute__((unused))) +vi_next_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); } @@ -728,7 +723,7 @@ vi_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_char(EditLine *el, int c __attribute__((unused))) +vi_prev_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); } @@ -740,7 +735,7 @@ vi_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_next_char(EditLine *el, int c __attribute__((unused))) +vi_to_next_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); } @@ -752,7 +747,7 @@ vi_to_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_prev_char(EditLine *el, int c __attribute__((unused))) +vi_to_prev_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); } @@ -764,7 +759,7 @@ vi_to_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_next_char(EditLine *el, int c __attribute__((unused))) +vi_repeat_next_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, @@ -778,7 +773,7 @@ vi_repeat_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_prev_char(EditLine *el, int c __attribute__((unused))) +vi_repeat_prev_char(EditLine *el, int c __attribute__((__unused__))) { el_action_t r; int dir = el->el_search.chadir; @@ -796,7 +791,7 @@ vi_repeat_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_match(EditLine *el, int c __attribute__((unused))) +vi_match(EditLine *el, int c) { const char match_chars[] = "()[]{}"; char *cp; @@ -843,7 +838,7 @@ vi_match(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_undo_line(EditLine *el, int c __attribute__((unused))) +vi_undo_line(EditLine *el, int c) { cv_undo(el); @@ -857,7 +852,7 @@ vi_undo_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_column(EditLine *el, int c __attribute__((unused))) +vi_to_column(EditLine *el, int c) { el->el_line.cursor = el->el_line.buffer; @@ -871,7 +866,7 @@ vi_to_column(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_yank_end(EditLine *el, int c __attribute__((unused))) +vi_yank_end(EditLine *el, int c) { cv_yank(el, el->el_line.cursor, @@ -885,7 +880,7 @@ vi_yank_end(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_yank(EditLine *el, int c __attribute__((unused))) +vi_yank(EditLine *el, int c) { return cv_action(el, YANK); @@ -897,7 +892,7 @@ vi_yank(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_comment_out(EditLine *el, int c __attribute__((unused))) +vi_comment_out(EditLine *el, int c) { el->el_line.cursor = el->el_line.buffer; @@ -915,7 +910,7 @@ vi_comment_out(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_alias(EditLine *el __attribute__((unused)), int c __attribute__((unused))) +vi_alias(EditLine *el, int c) { #ifdef __weak_extern char alias_name[3]; @@ -947,7 +942,7 @@ vi_alias(EditLine *el __attribute__((unused)), int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_history_line(EditLine *el, int c __attribute__((unused))) +vi_to_history_line(EditLine *el, int c) { int sv_event_no = el->el_history.eventno; el_action_t rval; @@ -992,7 +987,7 @@ vi_to_history_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_histedit(EditLine *el, int c __attribute__((unused))) +vi_histedit(EditLine *el, int c) { int fd; pid_t pid; @@ -1048,7 +1043,7 @@ vi_histedit(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_history_word(EditLine *el, int c __attribute__((unused))) +vi_history_word(EditLine *el, int c) { const char *wp = HIST_FIRST(el); const char *wep, *wsp; @@ -1097,7 +1092,7 @@ vi_history_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_redo(EditLine *el, int c __attribute__((unused))) +vi_redo(EditLine *el, int c) { c_redo_t *r = &el->el_chared.c_redo; diff --git a/cmd-line-utils/libedit/vis.c b/cmd-line-utils/libedit/vis.c new file mode 100644 index 00000000000..127d28733a8 --- /dev/null +++ b/cmd-line-utils/libedit/vis.c @@ -0,0 +1,392 @@ +/* $NetBSD: vis.c,v 1.27 2004/02/26 23:01:15 enami Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#include <config.h> + +#ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +#else +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifndef _AIX +extern char *alloca (); +# endif +# endif +#endif + +#include <sys/types.h> + +#include <assert.h> +#include <vis.h> +#include <stdlib.h> + +#ifdef __weak_alias +__weak_alias(strsvis,_strsvis) +__weak_alias(strsvisx,_strsvisx) +__weak_alias(strvis,_strvis) +__weak_alias(strvisx,_strvisx) +__weak_alias(svis,_svis) +__weak_alias(vis,_vis) +#endif + +#if !HAVE_VIS || !HAVE_SVIS +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> + +#undef BELL +#define BELL '\a' + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') +#define issafe(c) (c == '\b' || c == BELL || c == '\r') +#define xtoa(c) "0123456789abcdef"[c] + +#define MAXEXTRAS 5 + + +#define MAKEEXTRALIST(flag, extra, orig) \ +do { \ + const char *o = orig; \ + char *e; \ + while (*o++) \ + continue; \ + extra = alloca((size_t)((o - orig) + MAXEXTRAS)); \ + for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ + continue; \ + e--; \ + if (flag & VIS_SP) *e++ = ' '; \ + if (flag & VIS_TAB) *e++ = '\t'; \ + if (flag & VIS_NL) *e++ = '\n'; \ + if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ + *e = '\0'; \ +} while (/*CONSTCOND*/0) + + +/* + * This is HVIS, the macro of vis used to HTTP style (RFC 1808) + */ +#define HVIS(dst, c, flag, nextc, extra) \ +do \ + if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \ + *dst++ = '%'; \ + *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); \ + *dst++ = xtoa((unsigned int)c & 0xf); \ + } else { \ + SVIS(dst, c, flag, nextc, extra); \ + } \ +while (/*CONSTCOND*/0) + +/* + * This is SVIS, the central macro of vis. + * dst: Pointer to the destination buffer + * c: Character to encode + * flag: Flag word + * nextc: The character following 'c' + * extra: Pointer to the list of extra characters to be + * backslash-protected. + */ +#define SVIS(dst, c, flag, nextc, extra) \ +do { \ + int isextra; \ + isextra = strchr(extra, c) != NULL; \ + if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || \ + ((flag & VIS_SAFE) && issafe(c)))) { \ + *dst++ = c; \ + break; \ + } \ + if (flag & VIS_CSTYLE) { \ + switch (c) { \ + case '\n': \ + *dst++ = '\\'; *dst++ = 'n'; \ + continue; \ + case '\r': \ + *dst++ = '\\'; *dst++ = 'r'; \ + continue; \ + case '\b': \ + *dst++ = '\\'; *dst++ = 'b'; \ + continue; \ + case BELL: \ + *dst++ = '\\'; *dst++ = 'a'; \ + continue; \ + case '\v': \ + *dst++ = '\\'; *dst++ = 'v'; \ + continue; \ + case '\t': \ + *dst++ = '\\'; *dst++ = 't'; \ + continue; \ + case '\f': \ + *dst++ = '\\'; *dst++ = 'f'; \ + continue; \ + case ' ': \ + *dst++ = '\\'; *dst++ = 's'; \ + continue; \ + case '\0': \ + *dst++ = '\\'; *dst++ = '0'; \ + if (isoctal(nextc)) { \ + *dst++ = '0'; \ + *dst++ = '0'; \ + } \ + continue; \ + default: \ + if (isgraph(c)) { \ + *dst++ = '\\'; *dst++ = c; \ + continue; \ + } \ + } \ + } \ + if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { \ + *dst++ = '\\'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; \ + *dst++ = (c & 07) + '0'; \ + } else { \ + if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; \ + if (c & 0200) { \ + c &= 0177; *dst++ = 'M'; \ + } \ + if (iscntrl(c)) { \ + *dst++ = '^'; \ + if (c == 0177) \ + *dst++ = '?'; \ + else \ + *dst++ = c + '@'; \ + } else { \ + *dst++ = '-'; *dst++ = c; \ + } \ + } \ +} while (/*CONSTCOND*/0) + + +/* + * svis - visually encode characters, also encoding the characters + * pointed to by `extra' + */ +char * +svis(dst, c, flag, nextc, extra) + char *dst; + int c, flag, nextc; + const char *extra; +{ + char *nextra; + _DIAGASSERT(dst != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (flag & VIS_HTTPSTYLE) + HVIS(dst, c, flag, nextc, nextra); + else + SVIS(dst, c, flag, nextc, nextra); + *dst = '\0'; + return(dst); +} + + +/* + * strsvis, strsvisx - visually encode characters from src into dst + * + * Extra is a pointer to a \0-terminated list of characters to + * be encoded, too. These functions are useful e. g. to + * encode strings in such a way so that they are not interpreted + * by a shell. + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strsvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strsvis(dst, csrc, flag, extra) + char *dst; + const char *csrc; + int flag; + const char *extra; +{ + int c; + char *start; + char *nextra; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (flag & VIS_HTTPSTYLE) { + for (start = dst; (c = *src++) != '\0'; /* empty */) + HVIS(dst, c, flag, *src, nextra); + } else { + for (start = dst; (c = *src++) != '\0'; /* empty */) + SVIS(dst, c, flag, *src, nextra); + } + *dst = '\0'; + return (dst - start); +} + + +int +strsvisx(dst, csrc, len, flag, extra) + char *dst; + const char *csrc; + size_t len; + int flag; + const char *extra; +{ + int c; + char *start; + char *nextra; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + + if (flag & VIS_HTTPSTYLE) { + for (start = dst; len > 0; len--) { + c = *src++; + HVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } else { + for (start = dst; len > 0; len--) { + c = *src++; + SVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } + *dst = '\0'; + return (dst - start); +} +#endif + +#if !HAVE_VIS +/* + * vis - visually encode characters + */ +char * +vis(dst, c, flag, nextc) + char *dst; + int c, flag, nextc; + +{ + char *extra; + + _DIAGASSERT(dst != NULL); + + MAKEEXTRALIST(flag, extra, ""); + if (flag & VIS_HTTPSTYLE) + HVIS(dst, c, flag, nextc, extra); + else + SVIS(dst, c, flag, nextc, extra); + *dst = '\0'; + return (dst); +} + + +/* + * strvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(dst, src, flag) + char *dst; + const char *src; + int flag; +{ + char *extra; + + MAKEEXTRALIST(flag, extra, ""); + return (strsvis(dst, src, flag, extra)); +} + + +int +strvisx(dst, src, len, flag) + char *dst; + const char *src; + size_t len; + int flag; +{ + char *extra; + + MAKEEXTRALIST(flag, extra, ""); + return (strsvisx(dst, src, len, flag, extra)); +} +#endif diff --git a/cmd-line-utils/libedit/vis.h b/cmd-line-utils/libedit/vis.h new file mode 100644 index 00000000000..44f6fc7d785 --- /dev/null +++ b/cmd-line-utils/libedit/vis.h @@ -0,0 +1,92 @@ +/* $NetBSD: vis.h,v 1.15 2005/02/03 04:39:32 perry Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vis.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include <config.h> + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropiate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ +#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +__BEGIN_DECLS +char *vis(char *, int, int, int); +char *svis(char *, int, int, int, const char *); +int strvis(char *, const char *, int); +int strsvis(char *, const char *, int, const char *); +int strvisx(char *, const char *, size_t, int); +int strsvisx(char *, const char *, size_t, int, const char *); +int strunvis(char *, const char *); +int strunvisx(char *, const char *, int); +#ifdef __LIBC12_SOURCE__ +int unvis(char *, int, int *, int); +int __unvis13(char *, int, int *, int); +#else +int unvis(char *, int, int *, int); +#endif +__END_DECLS + +#endif /* !_VIS_H_ */ diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4 index 201702e5379..d75dedafa2a 100644 --- a/config/ac-macros/misc.m4 +++ b/config/ac-macros/misc.m4 @@ -646,8 +646,8 @@ m4_define([_AC_PROG_CXX_EXIT_DECLARATION], 'void exit (int);' \ '#include <stdlib.h>' do - _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include <stdlib.h> -$ac_declaration], + _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration +@%:@include <stdlib.h>], [exit (42);])], [], [continue]) diff --git a/config/ac-macros/yassl.m4 b/config/ac-macros/yassl.m4 new file mode 100644 index 00000000000..ada1a2c0bd1 --- /dev/null +++ b/config/ac-macros/yassl.m4 @@ -0,0 +1,33 @@ +AC_CONFIG_FILES(extra/yassl/Makefile dnl +extra/yassl/taocrypt/Makefile dnl +extra/yassl/taocrypt/src/Makefile dnl +extra/yassl/src/Makefile) + +AC_DEFUN([MYSQL_CHECK_YASSL], [ + AC_MSG_CHECKING(for yaSSL) + AC_ARG_WITH([yassl], + [ --with-yassl Include the yaSSL support], + [yassl=yes], + [yassl=no]) + + if test "$yassl" = "yes" + then + if test "$openssl" != "no" + then + AC_MSG_ERROR([Cannot configure MySQL to use yaSSL and OpenSSL simultaneously.]) + fi + AC_MSG_RESULT([using bundled yaSSL]) + yassl_dir="extra/yassl" + openssl_libs="\ + \$(top_builddir)/extra/yassl/src/libyassl.a\ + \$(top_builddir)/extra/yassl/taocrypt/src/libtaocrypt.a" + openssl_includes="-I\$(top_srcdir)/extra/yassl/include" + AC_DEFINE([HAVE_OPENSSL], [1], [Defined by configure. Using yaSSL for OpenSSL emulation.]) + else + yassl_dir="" + AC_MSG_RESULT(no) + fi + AC_SUBST(openssl_libs) + AC_SUBST(openssl_includes) + AC_SUBST(yassl_dir) +]) diff --git a/configure.in b/configure.in index d71446aa91a..8b0a0ddeb56 100644 --- a/configure.in +++ b/configure.in @@ -47,6 +47,7 @@ sinclude(config/ac-macros/large_file.m4) sinclude(config/ac-macros/misc.m4) sinclude(config/ac-macros/openssl.m4) sinclude(config/ac-macros/readline.m4) +sinclude(config/ac-macros/yassl.m4) sinclude(config/ac-macros/zlib.m4) # Remember to add a directory sql/share/LANGUAGE @@ -116,7 +117,6 @@ AC_SUBST(SAVE_LDFLAGS) AC_SUBST(SAVE_CXXLDFLAGS) AC_SUBST(CXXLDFLAGS) - #AC_ARG_PROGRAM # Automaticly invoked by AM_INIT_AUTOMAKE AM_SANITY_CHECK @@ -294,7 +294,7 @@ case "$target_os" in AC_SYS_COMPILER_FLAG(-belf,sco_belf_option,CFLAGS,[],[ case "$LDFLAGS" in *-belf*) ;; - *) echo "Adding -belf option to ldflags." + *) AC_MSG_WARN([Adding -belf option to ldflags.]) LDFLAGS="$LDFLAGS -belf" ;; esac @@ -305,7 +305,7 @@ case "$target_os" in case "$LDFLAGS" in *-belf*) ;; *) - echo "Adding -belf option to ldflags." + AC_MSG_WARN([Adding -belf option to ldflags.]) LDFLAGS="$LDFLAGS -belf" ;; esac @@ -336,7 +336,6 @@ AC_SUBST(LD) AC_SUBST(INSTALL_SCRIPT) export CC CXX CFLAGS LD LDFLAGS AR - if test "$GXX" = "yes" then # mysqld requires -fno-implicit-templates. @@ -344,42 +343,29 @@ then # mysqld doesn't use run-time-type-checking, so we disable it. CXXFLAGS="$CXXFLAGS -fno-implicit-templates -fno-exceptions -fno-rtti" - # If you are using 'gcc' 3.0 (not g++) to compile C++ programs on Linux, - # we will gets some problems when linking static programs. - # The following code is used to fix this problem. - - if echo $CXX | grep gcc > /dev/null 2>&1 - then - GCC_VERSION=`gcc -v 2>&1 | grep version | sed -e 's/[[^0-9. ]]//g; s/^ *//g; s/ .*//g'` - case $SYSTEM_TYPE in - *freebsd*) - # The libsupc++ library on freebsd with gcc 3.4.2 is dependent on - # libstdc++, disable it since other solution works fine - GCC_VERSION="NOSUPCPP_$GCC_VERSION" - ;; - *) - ;; - esac - echo "Using gcc version '$GCC_VERSION'" - case "$GCC_VERSION" in - 3.4.*|3.5.*) - # Statically link the language support function's found in libsupc++.a - LIBS="$LIBS -lsupc++" - echo "Using -libsupc++ for static linking with gcc" - ;; - *) - # Using -lsupc++ doesn't work in gcc 3.3 on SuSE 9.2 - # (causes link failures when linking things staticly) - CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL" - echo "Using MYSYS_NEW for static linking with gcc" - ;; - esac - fi + CXX_VERNO=`echo $CXX_VERSION | sed -e 's/[[^0-9. ]]//g; s/^ *//g; s/ .*//g'` + case "$CXX_VERNO" in + 3.*) + USE_MYSYS_NEW="-DUSE_MYSYS_NEW" # yassl needs it + if echo $CXX | grep gcc > /dev/null 2>&1 + then + # If you are using 'gcc' 3.0 (not g++) to compile C++ programs on Linux, + # we will gets some problems when linking static programs. + # The following code is used to fix this problem. + CXXFLAGS="$CXXFLAGS $USE_MYSYS_NEW" + AC_MSG_WARN([Using MYSYS_NEW for static linking with gcc]) + fi + ;; + *) + USE_MYSYS_NEW="" + ;; + esac + AC_SUBST(USE_MYSYS_NEW) fi # Avoid bug in fcntl on some versions of linux AC_MSG_CHECKING("if we should use 'skip-locking' as default for $target_os") -# Any wariation of Linux +# Any variation of Linux if expr "$target_os" : "[[Ll]]inux.*" > /dev/null then MYSQLD_DEFAULT_SWITCHES="--skip-locking" @@ -957,7 +943,7 @@ case $SYSTEM_TYPE in *solaris2.7*) # Solaris 2.7 has a broken /usr/include/widec.h # Make a fixed copy in ./include - echo "Fixing broken include files for $SYSTEM_TYPE" + AC_MSG_WARN([Fixing broken include files for $SYSTEM_TYPE]) echo " - Creating local copy of widec.h" if test ! -d include then @@ -971,7 +957,7 @@ case $SYSTEM_TYPE in *solaris2.8*) # Solaris 2.8 has a broken /usr/include/widec.h # Make a fixed copy in ./include - echo "Fixing broken include files for $SYSTEM_TYPE" + AC_MSG_WARN([Fixing broken include files for $SYSTEM_TYPE]) echo " - Creating local copy of widec.h" if test ! -d include then @@ -983,7 +969,7 @@ case $SYSTEM_TYPE in CXXFLAGS="$CXXFLAGS -DHAVE_CURSES_H -I$builddir/include -DHAVE_RWLOCK_T" ;; *solaris2.5.1*) - echo "Enabling getpass() workaround for Solaris 2.5.1" + AC_MSG_WARN([Enabling getpass() workaround for Solaris 2.5.1]) CFLAGS="$CFLAGS -DHAVE_BROKEN_GETPASS -DSOLARIS -DHAVE_RWLOCK_T"; CXXFLAGS="$CXXFLAGS -DHAVE_RWLOCK_T -DSOLARIS" ;; @@ -992,26 +978,26 @@ case $SYSTEM_TYPE in CXXFLAGS="$CXXFLAGS -DHAVE_RWLOCK_T" ;; *SunOS*) - echo "Enabling getpass() workaround for SunOS" + AC_MSG_WARN([Enabling getpass() workaround for SunOS]) CFLAGS="$CFLAGS -DHAVE_BROKEN_GETPASS -DSOLARIS"; ;; *hpux10.20*) - echo "Enabling workarounds for hpux 10.20" + AC_MSG_WARN([Enabling workarounds for hpux 10.20]) CFLAGS="$CFLAGS -DHAVE_BROKEN_SNPRINTF -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX10 -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT -DHAVE_POSIX1003_4a_MUTEX" CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_SNPRINTF -D_INCLUDE_LONGLONG -DSIGNALS_DONT_BREAK_READ -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHPUX10 -DSIGNAL_WITH_VIO_CLOSE -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT -DHAVE_POSIX1003_4a_MUTEX" if test "$with_named_thread" = "no" then - echo "Using --with-named-thread=-lpthread" + AC_MSG_WARN([Using --with-named-thread=-lpthread]) with_named_thread="-lcma" fi ;; *hpux11.*) - echo "Enabling workarounds for hpux 11" + AC_MSG_WARN([Enabling workarounds for hpux 11]) CFLAGS="$CFLAGS -DHPUX11 -DSNPRINTF_RETURN_TRUNC -DHAVE_BROKEN_PREAD -DDONT_USE_FINITE -DHAVE_BROKEN_GETPASS -DNO_FCNTL_NONBLOCK -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT" CXXFLAGS="$CXXFLAGS -DHPUX11 -DSNPRINTF_RETURN_TRUNC -DHAVE_BROKEN_PREAD -DDONT_USE_FINITE -D_INCLUDE_LONGLONG -DNO_FCNTL_NONBLOCK -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT" if test "$with_named_thread" = "no" then - echo "Using --with-named-thread=-lpthread" + AC_MSG_WARN([Using --with-named-thread=-lpthread]) with_named_thread="-lpthread" fi # Fixes for HPUX 11.0 compiler @@ -1067,7 +1053,7 @@ case $SYSTEM_TYPE in fi ;; *freebsd*) - echo "Adding fix for interrupted reads" + AC_MSG_WARN([Adding fix for interrupted reads]) OSVERSION=`sysctl -a | grep osreldate | awk '{ print $2 }'` if test "$OSVERSION" -gt "480100" && \ test "$OSVERSION" -lt "500000" || \ @@ -1080,13 +1066,13 @@ case $SYSTEM_TYPE in fi ;; *netbsd*) - echo "Adding flag -Dunix" + AC_MSG_WARN([Adding flag -Dunix]) CFLAGS="$CFLAGS -Dunix" CXXFLAGS="$CXXFLAGS -Dunix" OVERRIDE_MT_LD_ADD="\$(top_srcdir)/mit-pthreads/obj/libpthread.a" ;; *bsdi*) - echo "Adding fix for BSDI" + AC_MSG_WARN([Adding fix for BSDI]) CFLAGS="$CFLAGS -D__BSD__ -DHAVE_BROKEN_REALPATH" AC_DEFINE_UNQUOTED([SOCKOPT_OPTLEN_TYPE], [size_t], [Last argument to get/setsockopt]) @@ -1094,13 +1080,13 @@ case $SYSTEM_TYPE in *sgi-irix6*) if test "$with_named_thread" = "no" then - echo "Using --with-named-thread=-lpthread" + AC_MSG_WARN([Using --with-named-thread=-lpthread]) with_named_thread="-lpthread" fi CXXFLAGS="$CXXFLAGS -D_BOOL" ;; *aix4.3*) - echo "Adding defines for AIX" + AC_MSG_WARN([Adding defines for AIX]) CFLAGS="$CFLAGS -Wa,-many -DUNDEF_HAVE_INITGROUPS -DSIGNALS_DONT_BREAK_READ" CXXFLAGS="$CXXFLAGS -Wa,-many -DUNDEF_HAVE_INITGROUPS -DSIGNALS_DONT_BREAK_READ" ;; @@ -1108,11 +1094,11 @@ dnl Is this the right match for DEC OSF on alpha? *dec-osf*) if test "$ac_cv_prog_gcc" = "yes" && test "$host_cpu" = "alpha" then - echo "Adding defines for DEC OSF on alpha" + AC_MSG_WARN([Adding defines for DEC OSF on alpha]) CFLAGS="$CFLAGS -mieee" CXXFLAGS="$CXXFLAGS -mieee" fi - echo "Adding defines for OSF1" + AC_MSG_WARN([Adding defines for OSF1]) # gethostbyname_r is deprecated and doesn't work ok on OSF1 CFLAGS="$CFLAGS -DUNDEF_HAVE_GETHOSTBYNAME_R -DSNPRINTF_RETURN_TRUNC" CXXFLAGS="$CXXFLAGS -DUNDEF_HAVE_GETHOSTBYNAME_R -DSNPRINTF_RETURN_TRUNC" @@ -1399,7 +1385,7 @@ then CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; fi else - { echo "configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; + { AC_MSG_ERROR([configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual.]) }; fi else AC_MSG_RESULT("no") @@ -1445,7 +1431,7 @@ then fi AC_MSG_RESULT("yes") else - { echo "configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; + { AC_MSG_ERROR([configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual.]) }; fi else AC_MSG_RESULT("no") @@ -1488,7 +1474,7 @@ then fi AC_MSG_RESULT("yes") else - { echo "configure: error: Can't find thread libs on Caldera OpenUNIX 8. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; + { AC_MSG_ERROR([configure: error: Can't find thread libs on Caldera OpenUNIX 8. See the Installation chapter in the Reference Manual.]) }; fi else AC_MSG_RESULT("no") @@ -1819,6 +1805,9 @@ If you are using gcc 2.8.# you should upgrade to egcs 1.0.3 or newer and try again]); fi fi +AC_CHECK_TYPES([sigset_t, off_t], [], [], [#include <sys/types.h>]) +AC_CHECK_TYPES([size_t], [], [], [#include <stdio.h>]) + MYSQL_PTHREAD_YIELD ###################################################################### @@ -2259,7 +2248,7 @@ if test "$with_tools" = "yes" then if test "$THREAD_SAFE_CLIENT" = "no" then - echo "Warning: extra-tools disabled because --enable-thread-safe-client wasn't used" + AC_MSG_WARN([extra-tools disabled because --enable-thread-safe-client wasn't used]) else tools_dirs="tools" fi @@ -2280,6 +2269,7 @@ AC_SUBST(tools_dirs) #MYSQL_CHECK_CPU MYSQL_CHECK_VIO MYSQL_CHECK_OPENSSL +MYSQL_CHECK_YASSL libmysqld_dirs= if test "$with_embedded_server" = "yes" @@ -2406,17 +2396,24 @@ then compile_readline=yes AC_DEFINE_UNQUOTED(USE_NEW_READLINE_INTERFACE, 1) else + # Use system readline library AC_LANG_SAVE AC_LANG_CPLUSPLUS MYSQL_CHECK_LIBEDIT_INTERFACE MYSQL_CHECK_NEW_RL_INTERFACE MYSQL_CHECK_READLINE_DECLARES_HIST_ENTRY AC_LANG_RESTORE - if [test "$mysql_cv_new_rl_interface" = "yes"] || [test "$mysql_cv_libedit_interface" = "no"] + if [test "$mysql_cv_new_rl_interface" = "yes"] then + # Use the new readline interface readline_link="-lreadline" - else + elif [test "$mysql_cv_libedit_interface" = "yes"]; then + # Use libedit readline_link="-ledit" + else + AC_MSG_ERROR([Could not find system readline or libedit libraries + Use --with-readline or --with-libedit to use the bundled + versions of libedit or readline]) fi fi fi diff --git a/extra/Makefile.am b/extra/Makefile.am index dac6bf0fc0b..3aa4c531709 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -24,6 +24,7 @@ BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \ $(top_builddir)/include/mysqld_ername.h pkginclude_HEADERS= $(BUILT_SOURCES) CLEANFILES = $(BUILT_SOURCES) +DIST_SUBDIRS= yassl # This will build mysqld_error.h and sql_state.h $(top_builddir)/include/mysqld_error.h: comp_err diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c index d5836cb0dc8..946ac219e1a 100644 --- a/extra/my_print_defaults.c +++ b/extra/my_print_defaults.c @@ -27,12 +27,20 @@ const char *config_file="my"; /* Default config file */ uint verbose= 0, opt_defaults_file_used= 0; +const char *default_dbug_option="d:t:o,/tmp/my_print_defaults.trace"; static struct my_option my_long_options[] = { {"config-file", 'c', "The config file to be used.", (gptr*) &config_file, (gptr*) &config_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef DBUG_OFF + {"debug", '#', "This is a non-debug version. Catch this and exit", + 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#else + {"debug", '#', "Output debug log", (gptr*) &default_dbug_option, + (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"defaults-file", 'c', "Synonym for --config-file.", (gptr*) &config_file, (gptr*) &config_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -68,6 +76,7 @@ static void usage(my_bool version) puts("Prints all arguments that is give to some program using the default files"); printf("Usage: %s [OPTIONS] groups\n", my_progname); my_print_help(my_long_options); + my_print_default_files(config_file); my_print_variables(my_long_options); printf("\nExample usage:\n%s --config-file=my client mysql\n", my_progname); } @@ -95,6 +104,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': usage(1); exit(0); + case '#': + DBUG_PUSH(argument ? argument : default_dbug_option); + break; } return 0; } @@ -118,7 +130,7 @@ static int get_options(int *argc,char ***argv) int main(int argc, char **argv) { int count, error; - char **load_default_groups, *tmp_arguments[2], + char **load_default_groups, *tmp_arguments[3], **argument, **arguments; char *defaults, *extra_defaults; MY_INIT(argv[0]); diff --git a/extra/yassl/AUTHORS b/extra/yassl/AUTHORS new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/extra/yassl/AUTHORS diff --git a/extra/yassl/ChangeLog b/extra/yassl/ChangeLog new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/extra/yassl/ChangeLog diff --git a/extra/yassl/INSTALL b/extra/yassl/INSTALL new file mode 100644 index 00000000000..54caf7c190f --- /dev/null +++ b/extra/yassl/INSTALL @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/extra/yassl/Makefile.am b/extra/yassl/Makefile.am new file mode 100644 index 00000000000..7c1f2ea5acb --- /dev/null +++ b/extra/yassl/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = taocrypt src +EXTRA_DIST = yassl.dsp yassl.dsw mySTL/*.hpp diff --git a/extra/yassl/NEWS b/extra/yassl/NEWS new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/extra/yassl/NEWS diff --git a/extra/yassl/README b/extra/yassl/README new file mode 100644 index 00000000000..198a1031cb7 --- /dev/null +++ b/extra/yassl/README @@ -0,0 +1,263 @@ +yaSSL Release notes, version 0.9.6 + +This release of yaSSL contains minor bug fixes, removal of STL support, and +removal of exceptions and rtti so that the library can be linked without the +std c++ library. + +--To build on Linux, Solaris, FreeBSD, Mac OS X, or Cygwin + +./configure +make + +run testsuite from yaSSL-Home/testsuite to test the build + + +--To build on Win32 + +Choose (Re)Build All from the project workspace + +run Debug\testsuite.exe from yaSSL-Home\testsuite to test the build + + + +******************yaSSL Release notes, version 0.9.2 + +This release of yaSSL contains minor bug fixes, expanded certificate +verification and chaining, and improved documentation. + +Please see build instructions in release notes 0.3.0. + + + +******************yaSSL Release notes, version 0.9.0 + +This release of yaSSL contains minor bug fixes, client verification handling, +hex and base64 encoing/decoding, and an improved test suite. + +Please see build instructions in release notes 0.3.0. + + +******************yaSSL Release notes, version 0.8.0 + +This release of yaSSL contains minor bug fixes, and initial porting effort to +64bit, BigEndian, and more UNIX systems. + +Please see build instructions in release notes 0.3.0. + + +******************yaSSL Release notes, version 0.6.0 + +This release of yaSSL contains minor bug fixes, source cleanup, and binary beta +(1) of the yaSSL libraries. + +Please see build instructions in release notes 0.3.0. + + + +******************yaSSL Release notes, version 0.5.0 + +This release of yaSSL contains minor bug fixes, full session resumption +support, and initial testing suite support. + + + +Please see build instructions in release notes 0.3.0. + + + +******************yaSSL Release notes, version 0.4.0 + +This release of yaSSL contains minor bug fixes, an optional memory tracker, +an echo client and server with input/output redirection for load testing, +and initial session caching support. + + +Please see build instructions in release notes 0.3.0. + + +******************yaSSL Release notes, version 0.3.5 + +This release of yaSSL contains minor bug fixes and extensions to the crypto +library including a full test suite. + + +*******************yaSSL Release notes, version 0.3.0 + +This release of yaSSL contains minor bug fixes and extensions to the crypto +library including AES and an improved random number generator. GNU autoconf +and automake are now used to simplify the build process on Linux. + +*** Linux Build process + +./configure +make + +*** Windows Build process + +open the yassl workspace and build the project + + +*******************yaSSL Release notes, version 0.2.9 + +This release of yaSSL contains minor bug fixes and extensions to the crypto +library. + +See the notes at the bottom of this page for build instructions. + + +*******************yaSSL Release notes, version 0.2.5 + +This release of yaSSL contains minor bug fixes and a beta binary of the yaSSL +libraries for win32 and linux. + +See the notes at the bottom of this page for build instructions. + + + +*******************yaSSL Release notes, version 0.2.0 + +This release of yaSSL contains minor bug fixes and initial alternate crypto +functionality. + +*** Complete Build *** + +See the notes in Readme.txt for build instructions. + +*** Update Build *** + +If you have already done a complete build of yaSSL as described in the release +0.0.1 - 0.1.0 notes and downloaded the update to 0.2.0, place the update file +yassl-update-0.2.0.tar.gz in the yaSSL home directory and issue the command: + +gzip -cd yassl-update-0.2.0.tar.gz | tar xvf - + +to update the previous release. + +Then issue the make command on linux or rebuild the yaSSL project on Windows. + +*******************yaSSL Release notes, version 0.1.0 + +This release of yaSSL contains minor bug fixes, full client and server TLSv1 +support including full ephemeral Diffie-Hellman support, SSL type RSA and DSS +signing and verification, and initial stunnel 4.05 build support. + + + +*********************yaSSL Release notes, version 0.0.3 + +The third release of yaSSL contains minor bug fixes, client certificate +enhancements, and initial ephemeral Diffie-Hellman integration: + + + +********************* + +yaSSL Release notes, version 0.0.2 + +The second release of yaSSL contains minor bug fixes, client certificate +enhancements, session resumption, and improved TLS support including: + +- HMAC for MD5 and SHA-1 +- PRF (pseudo random function) +- Master Secret and Key derivation routines +- Record Authentication codes +- Finish verify data check + +Once ephemeral RSA and DH are added yaSSL will be fully complaint with TLS. + + + +********************** + +yassl Release notes, version 0.0.1 + +The first release of yassl supports normal RSA mode SSLv3 connections with +support for SHA-1 and MD5 digests. Ciphers include DES, 3DES, and RC4. + +yassl uses the CryptoPP library for cryptography, the source is available at +www.cryptopp.com . + +yassl uses CML (the Certificate Management Library) for x509 support. More +features will be in future versions. The CML source is available for download +from www.digitalnet.com/knowledge/cml_home.htm . + +The next release of yassl will support the 3 lesser-used SSL connection modes; +HandShake resumption, Ephemeral RSA (or DH), and Client Authentication as well +as full support for TLS. Backwards support for SSLv2 is not planned at this +time. + + +********************** + +Building yassl on linux: + +use the ./buildall script to build everything. + +buildall will configure and build CML, CryptoPP, and yassl. Testing was +preformed with gcc version 3.3.2 on kernel 2.4.22. + + +********************** + +Building yassl on Windows: + +Testing was preformed on Windows 2000 with Visual C++ 6 sp5. + +1) decompress esnacc_r16.tgz in place, see buildall for syntax if unsure + +2) decompress smp_r23.tgz in place + +3) unzip cryptopp51/crypto51.zip in place + +4) Build SNACC (part of CML) using snacc_builds.dsw in the SNACC directory + +5) Build SMP (part of CMP) using smp.dsw in the smp directory + +6) Build yassl using yassl.dsw + + +********************** + +examples, server and client: + +Please see the server and client examples in both versions to see how to link +to yassl and the support libraries. On linux do 'make server' and 'make +client' to build them. On Windows you will find the example projects in the +main workspace, yassl.dsw. + +The example server and client are compatible with openssl. + + +********************** + +Building yassl into mysql on linux: + +Testing was done using mysql version 4.0.17. + +alter openssl_libs in the configure file, line 21056. Change '-lssl -lcrypto' +to '-lyassl -lcryptopp -lcmapi -lcmlasn -lctil -lc++asn1'. + +see build/config_command for the configure command used to configure mysql +please change /home/touska/ to the relevant directory of course. + +add yassl/lib to the LD_LIBRARY_PATH because libmysql/conf_to_src does not +use the ssl lib directory though it does use the ssl libraries. + +make + +make install + + +********************* + +License: yassl is currently under the GPL, please see license information +in the source and include files. + + +********************* + +Contact: please send comments or questions to Todd A Ouska at todd@yassl.com +and/or Larry Stefonic at larry@yassl.com or 425-741-6858. + + + diff --git a/extra/yassl/include/buffer.hpp b/extra/yassl/include/buffer.hpp new file mode 100644 index 00000000000..126bdbc19b7 --- /dev/null +++ b/extra/yassl/include/buffer.hpp @@ -0,0 +1,207 @@ +/* buffer.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* yaSSL buffer header defines input and output buffers to simulate streaming + * with SSL types and sockets + */ + +#ifndef yaSSL_BUFFER_HPP +#define yaSSL_BUFFER_HPP + +#include <cassert> // assert +#include "yassl_error.hpp" // Error +#include "memory.hpp" // mySTL::auto_ptr +#include "algorithm.hpp" // mySTL::swap + + +#ifdef _MSC_VER + // disable truncated debug symbols + #pragma warning(disable:4786) +#endif + + +namespace yaSSL { + +typedef unsigned char byte; +typedef unsigned int uint; +const uint AUTO = 0xFEEDBEEF; + + +// Checking Policy should implement a check function that tests whether the +// index is within the size limit of the array +struct Check { + void check(uint i, uint limit); +}; + + +struct NoCheck { + void check(uint, uint); +}; + +/* input_buffer operates like a smart c style array with a checking option, + * meant to be read from through [] with AUTO index or read(). + * Should only write to at/near construction with assign() or raw (e.g., recv) + * followed by add_size with the number of elements added by raw write. + * + * Not using vector because need checked []access, offset, and the ability to + * write to the buffer bulk wise and have the correct size + */ + +class input_buffer : public Check { + uint size_; // number of elements in buffer + uint current_; // current offset position in buffer + byte* buffer_; // storage for buffer + byte* end_; // end of storage marker +public: + input_buffer(); + + explicit input_buffer(uint s); + + // with assign + input_buffer(uint s, const byte* t, uint len); + + ~input_buffer(); + + // users can pass defualt zero length buffer and then allocate + void allocate(uint s); + + // for passing to raw writing functions at beginning, then use add_size + byte* get_buffer() const; + + // after a raw write user can set new size + // if you know the size before the write use assign() + void add_size(uint i); + + uint get_capacity() const; + + uint get_current() const; + + uint get_size() const; + + uint get_remaining() const; + + void set_current(uint i); + + // read only access through [], advance current + // user passes in AUTO index for ease of use + const byte& operator[](uint i); + + // end of input test + bool eof(); + + // peek ahead + byte peek() const; + + // write function, should use at/near construction + void assign(const byte* t, uint s); + + // use read to query input, adjusts current + void read(byte* dst, uint length); + +private: + input_buffer(const input_buffer&); // hide copy + input_buffer& operator=(const input_buffer&); // and assign +}; + + +/* output_buffer operates like a smart c style array with a checking option. + * Meant to be written to through [] with AUTO index or write(). + * Size (current) counter increases when written to. Can be constructed with + * zero length buffer but be sure to allocate before first use. + * Don't use add write for a couple bytes, use [] instead, way less overhead. + * + * Not using vector because need checked []access and the ability to + * write to the buffer bulk wise and retain correct size + */ +class output_buffer : public Check { + uint current_; // current offset and elements in buffer + byte* buffer_; // storage for buffer + byte* end_; // end of storage marker +public: + // default + output_buffer(); + + // with allocate + explicit output_buffer(uint s); + + // with assign + output_buffer(uint s, const byte* t, uint len); + + ~output_buffer(); + + uint get_size() const; + + uint get_capacity() const; + + void set_current(uint c); + + // users can pass defualt zero length buffer and then allocate + void allocate(uint s); + + // for passing to reading functions when finished + const byte* get_buffer() const; + + // allow write access through [], update current + // user passes in AUTO as index for ease of use + byte& operator[](uint i); + + // end of output test + bool eof(); + + void write(const byte* t, uint s); + +private: + output_buffer(const output_buffer&); // hide copy + output_buffer& operator=(const output_buffer&); // and assign +}; + + + + +// turn delete an incomplete type into comipler error instead of warning +template <typename T> +inline void checked_delete(T* p) +{ + typedef char complete_type[sizeof(T) ? 1 : -1]; + (void)sizeof(complete_type); + delete p; +} + + +// checked delete functor increases effeciency, no indirection on function call +// sets pointer to zero so safe for std conatiners +struct del_ptr_zero +{ + template <typename T> + void operator()(T*& p) const + { + T* tmp = 0; + mySTL::swap(tmp, p); + checked_delete(tmp); + } +}; + + + +} // naemspace + +#endif // yaSSL_BUUFER_HPP diff --git a/extra/yassl/include/cert_wrapper.hpp b/extra/yassl/include/cert_wrapper.hpp new file mode 100644 index 00000000000..2381347c27e --- /dev/null +++ b/extra/yassl/include/cert_wrapper.hpp @@ -0,0 +1,124 @@ +/* cert_wrapper.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* The certificate wrapper header defines certificate management functions + * + */ + + +#ifndef yaSSL_CERT_WRAPPER_HPP +#define yaSSL_CERT_WRAPPER_HPP + +#ifdef _MSC_VER + // disable truncated debug symbols + #pragma warning(disable:4786) +#endif + + +#include "yassl_types.hpp" // SignatureAlgorithm +#include "buffer.hpp" // input_buffer +#include "asn.hpp" // SignerList +#include "list.hpp" // mySTL::list +#include "algorithm.hpp" // mySTL::for_each + +namespace yaSSL { + +typedef unsigned char opaque; +class X509; // forward openSSL type + +using TaoCrypt::SignerList; + +// an x509 version 3 certificate +class x509 { + uint length_; + opaque* buffer_; +public: + explicit x509(uint sz); + ~x509(); + + uint get_length() const; + const opaque* get_buffer() const; + opaque* use_buffer(); + + x509(const x509&); + x509& operator=(const x509&); +private: + void Swap(x509&); +}; + + +// Certificate Manager keeps a list of the cert chain and public key +class CertManager { + typedef mySTL::list<x509*> CertList; + + CertList list_; // self + input_buffer privateKey_; + + CertList peerList_; // peer + input_buffer peerPublicKey_; + X509* peerX509_; // peer's openSSL X509 + + SignatureAlgorithm keyType_; // self key type + SignatureAlgorithm peerKeyType_; // peer's key type + + SignerList signers_; // decoded CA keys and names + // plus verified chained certs + bool verifyPeer_; + bool failNoCert_; + bool sendVerify_; +public: + CertManager(); + ~CertManager(); + + void AddPeerCert(x509* x); // take ownership + void CopySelfCert(const x509* x); + int CopyCaCert(const x509* x); + int Validate(); + + int SetPrivateKey(const x509&); + + const x509* get_cert() const; + const opaque* get_peerKey() const; + const opaque* get_privateKey() const; + X509* get_peerX509() const; + SignatureAlgorithm get_keyType() const; + SignatureAlgorithm get_peerKeyType() const; + + uint get_peerKeyLength() const; + uint get_privateKeyLength() const; + + bool verifyPeer() const; + bool failNoCert() const; + bool sendVerify() const; + + void setVerifyPeer(); + void setFailNoCert(); + void setSendVerify(); +private: + CertManager(const CertManager&); // hide copy + CertManager& operator=(const CertManager&); // and assign +}; + + +} // naemspace + +#endif // yaSSL_CERT_WRAPPER_HPP diff --git a/extra/yassl/include/crypto_wrapper.hpp b/extra/yassl/include/crypto_wrapper.hpp new file mode 100644 index 00000000000..fa60c774cd9 --- /dev/null +++ b/extra/yassl/include/crypto_wrapper.hpp @@ -0,0 +1,418 @@ +/* crypto_wrapper.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* The crypto wrapper header is used to define policies for the cipher + * components used by SSL. There are 3 policies to consider: + * + * 1) MAC, the Message Authentication Code used for each Message + * 2) Bulk Cipher, the Cipher used to encrypt/decrypt each Message + * 3) Atuhentication, the Digitial Signing/Verifiaction scheme used + * + * This header doesn't rely on a specific crypto libraries internals, + * only the implementation should. + */ + + +#ifndef yaSSL_CRYPTO_WRAPPER_HPP +#define yaSSL_CRYPTO_WRAPPER_HPP + +#include "yassl_types.hpp" + + +namespace yaSSL { + + +// Digest policy should implement a get_digest, update, and get sizes for pad and +// digest +struct Digest { + virtual void get_digest(byte*) = 0; + virtual void get_digest(byte*, const byte*, unsigned int) = 0; + virtual void update(const byte*, unsigned int) = 0; + virtual uint get_digestSize() const = 0; + virtual uint get_padSize() const = 0; + virtual ~Digest() {} +}; + + +// For use with NULL Digests +struct NO_MAC : public Digest { + void get_digest(byte*); + void get_digest(byte*, const byte*, unsigned int); + void update(const byte*, unsigned int); + uint get_digestSize() const; + uint get_padSize() const; +}; + + +// MD5 Digest +class MD5 : public Digest { +public: + void get_digest(byte*); + void get_digest(byte*, const byte*, unsigned int); + void update(const byte*, unsigned int); + uint get_digestSize() const; + uint get_padSize() const; + MD5(); + ~MD5(); + MD5(const MD5&); + MD5& operator=(const MD5&); +private: + struct MD5Impl; + MD5Impl* pimpl_; +}; + + +// SHA-1 Digest +class SHA : public Digest { +public: + void get_digest(byte*); + void get_digest(byte*, const byte*, unsigned int); + void update(const byte*, unsigned int); + uint get_digestSize() const; + uint get_padSize() const; + SHA(); + ~SHA(); + SHA(const SHA&); + SHA& operator=(const SHA&); +private: + struct SHAImpl; + SHAImpl* pimpl_; + +}; + + +// RIPEMD-160 Digest +class RMD : public Digest { +public: + void get_digest(byte*); + void get_digest(byte*, const byte*, unsigned int); + void update(const byte*, unsigned int); + uint get_digestSize() const; + uint get_padSize() const; + RMD(); + ~RMD(); + RMD(const RMD&); + RMD& operator=(const RMD&); +private: + struct RMDImpl; + RMDImpl* pimpl_; + +}; + + +// HMAC_MD5 +class HMAC_MD5 : public Digest { +public: + void get_digest(byte*); + void get_digest(byte*, const byte*, unsigned int); + void update(const byte*, unsigned int); + uint get_digestSize() const; + uint get_padSize() const; + HMAC_MD5(const byte*, unsigned int); + ~HMAC_MD5(); +private: + struct HMAC_MD5Impl; + HMAC_MD5Impl* pimpl_; + + HMAC_MD5(const HMAC_MD5&); + HMAC_MD5& operator=(const HMAC_MD5&); +}; + + +// HMAC_SHA-1 +class HMAC_SHA : public Digest { +public: + void get_digest(byte*); + void get_digest(byte*, const byte*, unsigned int); + void update(const byte*, unsigned int); + uint get_digestSize() const; + uint get_padSize() const; + HMAC_SHA(const byte*, unsigned int); + ~HMAC_SHA(); +private: + struct HMAC_SHAImpl; + HMAC_SHAImpl* pimpl_; + + HMAC_SHA(const HMAC_SHA&); + HMAC_SHA& operator=(const HMAC_SHA&); +}; + + +// HMAC_RMD +class HMAC_RMD : public Digest { +public: + void get_digest(byte*); + void get_digest(byte*, const byte*, unsigned int); + void update(const byte*, unsigned int); + uint get_digestSize() const; + uint get_padSize() const; + HMAC_RMD(const byte*, unsigned int); + ~HMAC_RMD(); +private: + struct HMAC_RMDImpl; + HMAC_RMDImpl* pimpl_; + + HMAC_RMD(const HMAC_RMD&); + HMAC_RMD& operator=(const HMAC_RMD&); +}; + + +// BulkCipher policy should implement encrypt, decrypt, get block size, +// and set keys for encrypt and decrypt +struct BulkCipher { + virtual void encrypt(byte*, const byte*, unsigned int) = 0; + virtual void decrypt(byte*, const byte*, unsigned int) = 0; + virtual void set_encryptKey(const byte*, const byte* = 0) = 0; + virtual void set_decryptKey(const byte*, const byte* = 0) = 0; + virtual uint get_blockSize() const = 0; + virtual int get_keySize() const = 0; + virtual int get_ivSize() const = 0; + virtual ~BulkCipher() {} +}; + + +// For use with NULL Ciphers +struct NO_Cipher : public BulkCipher { + void encrypt(byte*, const byte*, unsigned int) {} + void decrypt(byte*, const byte*, unsigned int) {} + void set_encryptKey(const byte*, const byte*) {} + void set_decryptKey(const byte*, const byte*) {} + uint get_blockSize() const { return 0; } + int get_keySize() const { return 0; } + int get_ivSize() const { return 0; } +}; + + +// SSLv3 and TLSv1 always use DES in CBC mode so IV is required +class DES : public BulkCipher { +public: + void encrypt(byte*, const byte*, unsigned int); + void decrypt(byte*, const byte*, unsigned int); + void set_encryptKey(const byte*, const byte*); + void set_decryptKey(const byte*, const byte*); + uint get_blockSize() const { return DES_BLOCK; } + int get_keySize() const { return DES_KEY_SZ; } + int get_ivSize() const { return DES_IV_SZ; } + DES(); + ~DES(); +private: + struct DESImpl; + DESImpl* pimpl_; + + DES(const DES&); // hide copy + DES& operator=(const DES&); // & assign +}; + + +// 3DES Encrypt-Decrypt-Encrypt in CBC mode +class DES_EDE : public BulkCipher { +public: + void encrypt(byte*, const byte*, unsigned int); + void decrypt(byte*, const byte*, unsigned int); + void set_encryptKey(const byte*, const byte*); + void set_decryptKey(const byte*, const byte*); + uint get_blockSize() const { return DES_BLOCK; } + int get_keySize() const { return DES_EDE_KEY_SZ; } + int get_ivSize() const { return DES_IV_SZ; } + DES_EDE(); + ~DES_EDE(); +private: + struct DES_EDEImpl; + DES_EDEImpl* pimpl_; + + DES_EDE(const DES_EDE&); // hide copy + DES_EDE& operator=(const DES_EDE&); // & assign +}; + + +// Alledged RC4 +class RC4 : public BulkCipher { +public: + void encrypt(byte*, const byte*, unsigned int); + void decrypt(byte*, const byte*, unsigned int); + void set_encryptKey(const byte*, const byte*); + void set_decryptKey(const byte*, const byte*); + uint get_blockSize() const { return 0; } + int get_keySize() const { return RC4_KEY_SZ; } + int get_ivSize() const { return 0; } + RC4(); + ~RC4(); +private: + struct RC4Impl; + RC4Impl* pimpl_; + + RC4(const RC4&); // hide copy + RC4& operator=(const RC4&); // & assign +}; + + +// AES +class AES : public BulkCipher { +public: + void encrypt(byte*, const byte*, unsigned int); + void decrypt(byte*, const byte*, unsigned int); + void set_encryptKey(const byte*, const byte*); + void set_decryptKey(const byte*, const byte*); + uint get_blockSize() const { return AES_BLOCK_SZ; } + int get_keySize() const; + int get_ivSize() const { return AES_IV_SZ; } + explicit AES(unsigned int = AES_128_KEY_SZ); + ~AES(); +private: + struct AESImpl; + AESImpl* pimpl_; + + AES(const AES&); // hide copy + AES& operator=(const AES&); // & assign +}; + + +// Random number generator +class RandomPool { +public: + void Fill(opaque* dst, uint sz) const; + RandomPool(); + ~RandomPool(); + + int GetError() const; + + friend class RSA; + friend class DSS; + friend class DiffieHellman; +private: + struct RandomImpl; + RandomImpl* pimpl_; + + RandomPool(const RandomPool&); // hide copy + RandomPool& operator=(const RandomPool&); // & assign +}; + + +// Authentication policy should implement sign, and verify +struct Auth { + virtual void sign(byte*, const byte*, unsigned int, const RandomPool&) = 0; + virtual bool verify(const byte*, unsigned int, const byte*, + unsigned int) = 0; + virtual uint get_signatureLength() const = 0; + virtual ~Auth() {} +}; + + +// For use with NULL Authentication schemes +struct NO_Auth : public Auth { + void sign(byte*, const byte*, unsigned int, const RandomPool&) {} + bool verify(const byte*, unsigned int, const byte*, unsigned int) + { return true; } +}; + + +// Digitial Signature Standard scheme +class DSS : public Auth { +public: + void sign(byte*, const byte*, unsigned int, const RandomPool&); + bool verify(const byte*, unsigned int, const byte*, unsigned int); + uint get_signatureLength() const; + DSS(const byte*, unsigned int, bool publicKey = true); + ~DSS(); +private: + struct DSSImpl; + DSSImpl* pimpl_; + + DSS(const DSS&); + DSS& operator=(const DSS&); +}; + + +// RSA Authentication and exchange +class RSA : public Auth { +public: + void sign(byte*, const byte*, unsigned int, const RandomPool&); + bool verify(const byte*, unsigned int, const byte*, unsigned int); + void encrypt(byte*, const byte*, unsigned int, const RandomPool&); + void decrypt(byte*, const byte*, unsigned int, const RandomPool&); + uint get_signatureLength() const; + uint get_cipherLength() const; + RSA(const byte*, unsigned int, bool publicKey = true); + ~RSA(); +private: + struct RSAImpl; + RSAImpl* pimpl_; + + RSA(const RSA&); // hide copy + RSA& operator=(const RSA&); // & assing +}; + + +class Integer; + +// Diffie-Hellman agreement +// hide for now TODO: figure out a way to give access to C clients p and g args +class DiffieHellman { +public: + DiffieHellman(const byte*, unsigned int, const byte*, unsigned int, + const byte*, unsigned int, const RandomPool& random); + //DiffieHellman(const char*, const RandomPool&); + DiffieHellman(const Integer&, const Integer&, const RandomPool&); + ~DiffieHellman(); + + DiffieHellman(const DiffieHellman&); + DiffieHellman& operator=(const DiffieHellman&); + + uint get_agreedKeyLength() const; + const byte* get_agreedKey() const; + const byte* get_publicKey() const; + void makeAgreement(const byte*); + + void set_sizes(int&, int&, int&) const; + void get_parms(byte*, byte*, byte*) const; +private: + struct DHImpl; + DHImpl* pimpl_; +}; + + +// Lagrge Integer +class Integer { +public: + Integer(); + ~Integer(); + + Integer(const Integer&); + Integer& operator=(const Integer&); + + void assign(const byte*, unsigned int); + + friend class DiffieHellman; +private: + struct IntegerImpl; + IntegerImpl* pimpl_; +}; + + +class x509; + +x509* PemToDer(const char*, CertType); + + +} // naemspace + +#endif // yaSSL_CRYPTO_WRAPPER_HPP diff --git a/extra/yassl/include/factory.hpp b/extra/yassl/include/factory.hpp new file mode 100644 index 00000000000..96798466352 --- /dev/null +++ b/extra/yassl/include/factory.hpp @@ -0,0 +1,106 @@ +/* factory.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* The factory header defines an Object Factory, used by SSL message and + * handshake types. + * + * See Desgin Pattern in GoF and Alexandrescu's chapter in Modern C++ Design, + * page 208 + */ + + + +#ifndef yaSSL_FACTORY_HPP +#define yaSSL_FACTORY_HPP + +#include "vector.hpp" +#include "pair.hpp" +#include "yassl_error.hpp" + + + +// VC60 workaround: it doesn't allow typename in some places +#if defined(_MSC_VER) && (_MSC_VER < 1300) + #define CPP_TYPENAME +#else + #define CPP_TYPENAME typename +#endif + + +namespace yaSSL { + + +// Factory uses its callback map to create objects by id, +// returning an abstract base pointer +template<class AbstractProduct, + typename IdentifierType = int, + typename ProductCreator = AbstractProduct* (*)() + > +class Factory { + typedef mySTL::pair<IdentifierType, ProductCreator> CallBack; + typedef mySTL::vector<CallBack> CallBackVector; + + CallBackVector callbacks_; +public: + // pass function pointer to register all callbacks upon creation + explicit Factory(void (*init)(Factory<AbstractProduct, IdentifierType, + ProductCreator>&)) + { + init(*this); + } + + // reservce place in vector before registering, used by init funcion + void Reserve(size_t sz) + { + callbacks_.reserve(sz); + } + + // register callback + void Register(const IdentifierType& id, ProductCreator pc) + { + callbacks_.push_back(mySTL::make_pair(id, pc)); + } + + // THE Creator, returns a new object of the proper type or 0 + AbstractProduct* CreateObject(const IdentifierType& id) const + { + const CallBack* first = callbacks_.begin(); + const CallBack* last = callbacks_.end(); + + while (first != last) { + if (first->first == id) + break; + ++first; + } + + if (first == callbacks_.end()) + return 0; + return (first->second)(); + } +private: + Factory(const Factory&); // hide copy + Factory& operator=(const Factory&); // and assign +}; + + +} // naemspace + +#endif // yaSSL_FACTORY_HPP diff --git a/extra/yassl/include/handshake.hpp b/extra/yassl/include/handshake.hpp new file mode 100644 index 00000000000..6261359cd58 --- /dev/null +++ b/extra/yassl/include/handshake.hpp @@ -0,0 +1,72 @@ +/* handshake.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* The handshake header declares function prototypes for creating and reading + * the various handshake messages. + */ + + + +#ifndef yaSSL_HANDSHAKE_HPP +#define yaSSL_HANDSHAKE_HPP + +#include "yassl_types.hpp" + + +namespace yaSSL { + +// forward decls +class SSL; +class Finished; +class Data; +class Alert; +struct Hashes; + +enum BufferOutput { buffered, unbuffered }; + +void sendClientHello(SSL&); +void sendServerHello(SSL&, BufferOutput = buffered); +void sendServerHelloDone(SSL&, BufferOutput = buffered); +void sendClientKeyExchange(SSL&, BufferOutput = buffered); +void sendServerKeyExchange(SSL&, BufferOutput = buffered); +void sendChangeCipher(SSL&, BufferOutput = buffered); +void sendFinished(SSL&, ConnectionEnd, BufferOutput = buffered); +void sendCertificate(SSL&, BufferOutput = buffered); +void sendCertificateRequest(SSL&, BufferOutput = buffered); +void sendCertificateVerify(SSL&, BufferOutput = buffered); +int sendData(SSL&, const void*, int); +int sendAlert(SSL& ssl, const Alert& alert); + +int receiveData(SSL&, Data&); +void processReply(SSL&); + +void buildFinished(SSL&, Finished&, const opaque*); +void build_certHashes(SSL&, Hashes&); + +void hmac(SSL&, byte*, const byte*, uint, ContentType, bool verify = false); +void TLS_hmac(SSL&, byte*, const byte*, uint, ContentType, + bool verify = false); +void PRF(byte* digest, uint digLen, const byte* secret, uint secLen, + const byte* label, uint labLen, const byte* seed, uint seedLen); + +} // naemspace + +#endif // yaSSL_HANDSHAKE_HPP diff --git a/extra/yassl/include/lock.hpp b/extra/yassl/include/lock.hpp new file mode 100644 index 00000000000..11a623879d4 --- /dev/null +++ b/extra/yassl/include/lock.hpp @@ -0,0 +1,90 @@ +/* lock.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* lock.hpp provides an os specific Lock, locks mutex on entry and unlocks + * automatically upon exit, no-ops provided for Single Threaded +*/ + +#ifndef yaSSL_LOCK_HPP +#define yaSSL_LOCK_HPP + + +namespace yaSSL { + + +#ifdef MULTI_THREADED + #ifdef WIN32 + #include <windows.h> + + class Mutex { + CRITICAL_SECTION cs_; + public: + Mutex(); + ~Mutex(); + + class Lock; + friend class Lock; + + class Lock { + Mutex& mutex_; + public: + explicit Lock(Mutex& lm); + ~Lock(); + }; + }; + #else // WIN32 + #include <pthread.h> + + class Mutex { + pthread_mutex_t mutex_; + public: + + Mutex(); + ~Mutex(); + + class Lock; + friend class Lock; + + class Lock { + Mutex& mutex_; + public: + explicit Lock(Mutex& lm); + ~Lock(); + }; + }; + + #endif // WIN32 +#else // MULTI_THREADED (WE'RE SINGLE) + + class Mutex { + public: + class Lock { + public: + explicit Lock(Mutex&) {} + }; + }; + +#endif // MULTI_THREADED + + + +} // namespace +#endif // yaSSL_LOCK_HPP diff --git a/extra/yassl/include/log.hpp b/extra/yassl/include/log.hpp new file mode 100644 index 00000000000..5753bb4502d --- /dev/null +++ b/extra/yassl/include/log.hpp @@ -0,0 +1,58 @@ +/* log.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* yaSSL log interface + * + */ + +#ifndef yaSSL_LOG_HPP +#define yaSSL_LOG_HPP + +#include "socket_wrapper.hpp" + +#ifdef YASSL_LOG +#include <cstdio> +#endif + +namespace yaSSL { + +typedef unsigned int uint; + + +// Debug logger +class Log { +#ifdef YASSL_LOG + FILE* log_; +#endif +public: + explicit Log(const char* str = "yaSSL.log"); + ~Log(); + + void Trace(const char*); + void ShowTCP(socket_t, bool ended = false); + void ShowData(uint, bool sent = false); +}; + + +} // naemspace + +#endif // yaSSL_LOG_HPP diff --git a/extra/yassl/include/openssl/crypto.h b/extra/yassl/include/openssl/crypto.h new file mode 100644 index 00000000000..4a0c1db0df1 --- /dev/null +++ b/extra/yassl/include/openssl/crypto.h @@ -0,0 +1,13 @@ +/* crypto.h for openSSL */ + +#ifndef ysSSL_crypto_h__ +#define yaSSL_crypto_h__ + +const char* SSLeay_version(int type); + +#define SSLEAY_VERSION 0x0900L +#define SSLEAY_VERSION_NUMBER SSLEAY_VERSION + + +#endif /* yaSSL_crypto_h__ */ + diff --git a/extra/yassl/include/openssl/des.h b/extra/yassl/include/openssl/des.h new file mode 100644 index 00000000000..67be7eecfb9 --- /dev/null +++ b/extra/yassl/include/openssl/des.h @@ -0,0 +1 @@ +/* des.h for openssl */ diff --git a/extra/yassl/include/openssl/err.h b/extra/yassl/include/openssl/err.h new file mode 100644 index 00000000000..054d0940509 --- /dev/null +++ b/extra/yassl/include/openssl/err.h @@ -0,0 +1,8 @@ +/* err.h for openssl */ + +#ifndef ysSSL_err_h__ +#define yaSSL_err_h__ + + + +#endif /* yaSSL_err_h__ */ diff --git a/extra/yassl/include/openssl/lhash.h b/extra/yassl/include/openssl/lhash.h new file mode 100644 index 00000000000..01f8535f869 --- /dev/null +++ b/extra/yassl/include/openssl/lhash.h @@ -0,0 +1,2 @@ +/* lhash.h for openSSL */ + diff --git a/extra/yassl/include/openssl/md5.h b/extra/yassl/include/openssl/md5.h new file mode 100644 index 00000000000..a1025b92782 --- /dev/null +++ b/extra/yassl/include/openssl/md5.h @@ -0,0 +1 @@ +/* md5.h for openssl */ diff --git a/extra/yassl/include/openssl/opensslv.h b/extra/yassl/include/openssl/opensslv.h new file mode 100644 index 00000000000..d932130684f --- /dev/null +++ b/extra/yassl/include/openssl/opensslv.h @@ -0,0 +1,12 @@ +/* opensslv.h compatibility */ + +#ifndef yaSSL_opensslv_h__ +#define yaSSL_opensslv_h__ + + +/* api version compatibility */ +#define OPENSSL_VERSION_NUMBER 0x0090700f + + +#endif /* yaSSLopensslv_h__ */ + diff --git a/extra/yassl/include/openssl/rand.h b/extra/yassl/include/openssl/rand.h new file mode 100644 index 00000000000..df9c9020346 --- /dev/null +++ b/extra/yassl/include/openssl/rand.h @@ -0,0 +1,2 @@ +/* rand.h for openSSL */ + diff --git a/extra/yassl/include/openssl/rsa.h b/extra/yassl/include/openssl/rsa.h new file mode 100644 index 00000000000..1ab9d13b89f --- /dev/null +++ b/extra/yassl/include/openssl/rsa.h @@ -0,0 +1,10 @@ +/* rsa.h for openSSL */ + + +#ifndef ysSSL_rsa_h__ +#define yaSSL_rsa_h__ + +enum { RSA_F4 = 1 }; + + +#endif /* yaSSL_rsa_h__ */ diff --git a/extra/yassl/include/openssl/ssl.h b/extra/yassl/include/openssl/ssl.h new file mode 100644 index 00000000000..361918846fc --- /dev/null +++ b/extra/yassl/include/openssl/ssl.h @@ -0,0 +1,400 @@ +/* ssl.h + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* ssl.h defines openssl compatibility layer + * + */ + +#ifndef ysSSL_openssl_h__ +#define yaSSL_openssl_h__ + +#include <stdio.h> /* ERR_print fp */ +#include "rsa.h" + +#if defined(__cplusplus) && !defined(YASSL_MYSQL_COMPATIBLE) +namespace yaSSL { +extern "C" { +#endif + + +#if defined(__cplusplus) && !defined(YASSL_MYSQL_COMPATIBLE) + class SSL; + class SSL_SESSION; + class SSL_METHOD; + class SSL_CTX; + class SSL_CIPHER; + + class RSA; + + class X509; + class X509_NAME; +#else + typedef struct SSL SSL; + typedef struct SSL_SESION SSL_SESSION; + typedef struct SSL_METHOD SSL_METHOD; + typedef struct SSL_CTX SSL_CTX; + typedef struct SSL_CIPHER SSL_CIPHER; + + typedef struct RSA RSA; + + typedef struct X509 X509; + typedef struct X509_NAME X509_NAME; +#endif + + +/* Big Number stuff, different file? */ +typedef struct BIGNUM BIGNUM; + +BIGNUM *BN_bin2bn(const unsigned char*, int, BIGNUM*); + + +/* Diffie-Hellman stuff, different file? */ +/* mySQL deferences to set group parameters */ +typedef struct DH { + BIGNUM* p; + BIGNUM* g; +} DH; + +DH* DH_new(void); +void DH_free(DH*); + +/* RSA stuff */ + +void RSA_free(RSA*); +RSA* RSA_generate_key(int, unsigned long, void(*)(int, int, void*), void*); + + +/* X509 stuff, different file? */ + +typedef struct X509_STORE X509_STORE; +typedef struct X509_LOOKUP X509_LOOKUP; +typedef struct X509_OBJECT { char c; } X509_OBJECT; +typedef struct X509_CRL X509_CRL; +typedef struct X509_REVOKED X509_REVOKED; +typedef struct X509_LOOKUP_METHOD X509_LOOKUP_METHOD; + + +void X509_free(X509*); + + +/* bio stuff */ +typedef struct BIO BIO; + +/* ASN stuff */ +typedef struct ASN1_TIME ASN1_TIME; + + + +/* because mySQL dereferences to use error and current_cert, even after calling + * get functions for local references */ +typedef struct X509_STORE_CTX { + int error; + int error_depth; + X509* current_cert; +} X509_STORE_CTX; + + + +X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX*); +int X509_STORE_CTX_get_error(X509_STORE_CTX*); +int X509_STORE_CTX_get_error_depth(X509_STORE_CTX*); + +char* X509_NAME_oneline(X509_NAME*, char*, int); +X509_NAME* X509_get_issuer_name(X509*); +X509_NAME* X509_get_subject_name(X509*); +const char* X509_verify_cert_error_string(long); + +int X509_LOOKUP_add_dir(X509_LOOKUP*, const char*, long); +int X509_LOOKUP_load_file(X509_LOOKUP*, const char*, long); +X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void); +X509_LOOKUP_METHOD* X509_LOOKUP_file(void); + +X509_LOOKUP* X509_STORE_add_lookup(X509_STORE*, X509_LOOKUP_METHOD*); +X509_STORE* X509_STORE_new(void); +int X509_STORE_get_by_subject(X509_STORE_CTX*, int, X509_NAME*, + X509_OBJECT*); + + + + +enum { /* X509 Constants */ + X509_V_OK = 0, + X509_V_ERR_CERT_CHAIN_TOO_LONG = 1, + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2, + X509_V_ERR_CERT_NOT_YET_VALID = 3, + X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 4, + X509_V_ERR_CERT_HAS_EXPIRED = 5, + X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 6, + X509_FILETYPE_PEM = 7, + X509_LU_X509 = 8, + X509_LU_CRL = 9, + X509_V_ERR_CRL_SIGNATURE_FAILURE = 10, + X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 11, + X509_V_ERR_CRL_HAS_EXPIRED = 12, + X509_V_ERR_CERT_REVOKED = 13, + +}; + + +/* Error stuff, could move to yassl_error */ +unsigned long ERR_get_error_line_data(const char**, int*, const char**, int *); +void ERR_print_errors_fp(FILE*); +char* ERR_error_string(unsigned long,char*); +void ERR_remove_state(unsigned long); +unsigned long ERR_get_error(void); +unsigned long ERR_peek_error(void); +int ERR_GET_REASON(int); + + +enum { /* ERR Constants */ + ERR_TXT_STRING = 1, + EVP_R_BAD_DECRYPT = 2, +}; + + + +SSL_CTX* SSL_CTX_new(SSL_METHOD*); +SSL* SSL_new(SSL_CTX*); +int SSL_set_fd (SSL*, int); +int SSL_connect(SSL*); +int SSL_write(SSL*, const void*, int); +int SSL_read(SSL*, void*, int); +int SSL_accept(SSL*); +void SSL_CTX_free(SSL_CTX*); +void SSL_free(SSL*); +int SSL_clear(SSL*); +int SSL_shutdown(SSL*); + +void SSL_set_connect_state(SSL*); +void SSL_set_accept_state(SSL*); +int SSL_do_handshake(SSL*); + +const char* SSL_get_cipher(SSL*); +const char* SSL_get_cipher_name(SSL*); /* uses SSL_get_cipher */ +char* SSL_get_shared_ciphers(SSL*, char*, int); +const char* SSL_get_cipher_list(SSL*, int); +const char* SSL_get_version(SSL*); +const char* SSLeay_version(int); + +int SSL_get_error(SSL*, int); +void SSL_load_error_strings(void); + +int SSL_set_session(SSL *ssl, SSL_SESSION *session); +SSL_SESSION* SSL_get_session(SSL* ssl); +long SSL_SESSION_set_timeout(SSL_SESSION*, long); +X509* SSL_get_peer_certificate(SSL*); +long SSL_get_verify_result(SSL*); + + +typedef int (*VerifyCallback)(int, X509_STORE_CTX*); +typedef int (*pem_password_cb)(char*, int, int, void*); + +void SSL_CTX_set_verify(SSL_CTX*, int, VerifyCallback verify_callback); +int SSL_CTX_load_verify_locations(SSL_CTX*, const char*, const char*); +int SSL_CTX_set_default_verify_paths(SSL_CTX*); +int SSL_CTX_check_private_key(SSL_CTX*); +int SSL_CTX_set_session_id_context(SSL_CTX*, const unsigned char*, + unsigned int); + +void SSL_CTX_set_tmp_rsa_callback(SSL_CTX*, RSA*(*)(SSL*, int, int)); +long SSL_CTX_set_options(SSL_CTX*, long); +long SSL_CTX_set_session_cache_mode(SSL_CTX*, long); +long SSL_CTX_set_timeout(SSL_CTX*, long); +int SSL_CTX_use_certificate_chain_file(SSL_CTX*, const char*); +void SSL_CTX_set_default_passwd_cb(SSL_CTX*, pem_password_cb); +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX*, const char*, int); +void SSL_CTX_set_info_callback(SSL_CTX*, void (*)()); + +long SSL_CTX_sess_accept(SSL_CTX*); +long SSL_CTX_sess_connect(SSL_CTX*); +long SSL_CTX_sess_accept_good(SSL_CTX*); +long SSL_CTX_sess_connect_good(SSL_CTX*); +long SSL_CTX_sess_accept_renegotiate(SSL_CTX*); +long SSL_CTX_sess_connect_renegotiate(SSL_CTX*); +long SSL_CTX_sess_hits(SSL_CTX*); +long SSL_CTX_sess_cb_hits(SSL_CTX*); +long SSL_CTX_sess_cache_full(SSL_CTX*); +long SSL_CTX_sess_misses(SSL_CTX*); +long SSL_CTX_sess_timeouts(SSL_CTX*); +long SSL_CTX_sess_number(SSL_CTX*); +long SSL_CTX_sess_get_cache_size(SSL_CTX*); + +int SSL_CTX_get_verify_mode(SSL_CTX*); +int SSL_get_verify_mode(SSL*); +int SSL_CTX_get_verify_depth(SSL_CTX*); +int SSL_get_verify_depth(SSL*); + +long SSL_get_default_timeout(SSL*); +long SSL_CTX_get_session_cache_mode(SSL_CTX*); +int SSL_session_reused(SSL*); + +int SSL_set_rfd(SSL*, int); +int SSL_set_wfd(SSL*, int); +void SSL_set_shutdown(SSL*, int); + +int SSL_want_read(SSL*); +int SSL_want_write(SSL*); + +int SSL_pending(SSL*); + + +enum { /* ssl Constants */ + SSL_BAD_FILETYPE = -5, + SSL_BAD_FILE = -4, + SSL_NOT_IMPLEMENTED = -3, + SSL_UNKNOWN = -2, + SSL_FATAL_ERROR = -1, + SSL_NORMAL_SHUTDOWN = 0, + SSL_ERROR_NONE = 0, // for most functions + SSL_FAILURE = 0, // for some functions + SSL_SUCCESS = 1, + + SSL_FILETYPE_ASN1 = 10, + SSL_FILETYPE_PEM = 11, + SSL_FILETYPE_DEFAULT = 10, /* ASN1 */ + + SSL_VERIFY_NONE = 0, + SSL_VERIFY_PEER = 1, + SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2, + SSL_VERIFY_CLIENT_ONCE = 4, + + SSL_SESS_CACHE_OFF = 30, + SSL_SESS_CACHE_CLIENT = 31, + SSL_SESS_CACHE_SERVER = 32, + SSL_SESS_CACHE_BOTH = 33, + SSL_SESS_CACHE_NO_AUTO_CLEAR = 34, + SSL_SESS_CACHE_NO_INTERNAL_LOOKUP = 35, + + SSL_OP_MICROSOFT_SESS_ID_BUG = 50, + SSL_OP_NETSCAPE_CHALLENGE_BUG = 51, + SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 52, + SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = 53, + SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 54, + SSL_OP_MSIE_SSLV2_RSA_PADDING = 55, + SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 56, + SSL_OP_TLS_D5_BUG = 57, + SSL_OP_TLS_BLOCK_PADDING_BUG = 58, + SSL_OP_TLS_ROLLBACK_BUG = 59, + SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 60, + SSL_OP_ALL = 61, + SSL_OP_SINGLE_DH_USE = 62, + SSL_OP_EPHEMERAL_RSA = 63, + SSL_OP_NO_SSLv2 = 64, + SSL_OP_NO_SSLv3 = 65, + SSL_OP_NO_TLSv1 = 66, + SSL_OP_PKCS1_CHECK_1 = 67, + SSL_OP_PKCS1_CHECK_2 = 68, + SSL_OP_NETSCAPE_CA_DN_BUG = 69, + SSL_OP_NON_EXPORT_FIRST = 70, + SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 71, + + SSL_ERROR_WANT_READ = 80, + SSL_ERROR_WANT_WRITE = 81, + SSL_ERROR_SYSCALL = 82, + SSL_ERROR_WANT_X509_LOOKUP = 83, + SSL_ERROR_ZERO_RETURN = 84, + SSL_ERROR_SSL = 85, + + SSL_SENT_SHUTDOWN = 90, + SSL_RECEIVED_SHUTDOWN = 91, + SSL_CB_LOOP = 92, + SSL_ST_CONNECT = 93, + SSL_ST_ACCEPT = 94, + SSL_CB_ALERT = 95, + SSL_CB_READ = 96, + SSL_CB_HANDSHAKE_DONE = 97, + +}; + + +SSL_METHOD *SSLv3_method(void); +SSL_METHOD *SSLv3_server_method(void); +SSL_METHOD *SSLv3_client_method(void); +SSL_METHOD *TLSv1_server_method(void); +SSL_METHOD *TLSv1_client_method(void); +SSL_METHOD *SSLv23_server_method(void); + +int SSL_CTX_use_certificate_file(SSL_CTX*, const char*, int); +int SSL_CTX_use_PrivateKey_file(SSL_CTX*, const char*, int); +int SSL_CTX_set_cipher_list(SSL_CTX*, const char*); + +long SSL_CTX_sess_set_cache_size(SSL_CTX*, long); +long SSL_CTX_set_tmp_dh(SSL_CTX*, DH*); + +void OpenSSL_add_all_algorithms(void); +void SSLeay_add_ssl_algorithms(void); + + +SSL_CIPHER* SSL_get_current_cipher(SSL*); +char* SSL_CIPHER_description(SSL_CIPHER*, char*, int); + + +char* SSL_alert_type_string_long(int); +char* SSL_alert_desc_string_long(int); +char* SSL_state_string_long(SSL*); + + +/* EVP stuff, des and md5, different file? */ +typedef struct Digest Digest; +typedef Digest EVP_MD; + +typedef struct BulkCipher BulkCipher; +typedef BulkCipher EVP_CIPHER; + +typedef struct EVP_PKEY EVP_PKEY; + +typedef unsigned char DES_cblock[8]; +typedef const DES_cblock const_DES_cblock; +typedef DES_cblock DES_key_schedule; + + +const EVP_MD* EVP_md5(void); +const EVP_CIPHER* EVP_des_ede3_cbc(void); + +typedef unsigned char opaque; + +int EVP_BytesToKey(const EVP_CIPHER*, const EVP_MD*, const opaque*, + const opaque*, int, int, opaque*, opaque*); + +void DES_set_key_unchecked(const_DES_cblock*, DES_key_schedule*); +void DES_ede3_cbc_encrypt(const opaque*, opaque*, long, DES_key_schedule*, + DES_key_schedule*, DES_key_schedule*, DES_cblock*, int); + + +/* RAND stuff */ +void RAND_screen(void); +const char* RAND_file_name(char*, size_t); +int RAND_write_file(const char*); +int RAND_load_file(const char*, long); + + +#define SSL_DEFAULT_CIPHER_LIST "" /* default all */ + + + + +#if defined(__cplusplus) && !defined(YASSL_MYSQL_COMPATIBLE) +} /* namespace */ +} /* extern "C" */ +#endif + + +#endif /* yaSSL_openssl_h__ */ diff --git a/extra/yassl/include/socket_wrapper.hpp b/extra/yassl/include/socket_wrapper.hpp new file mode 100644 index 00000000000..dddbd65e220 --- /dev/null +++ b/extra/yassl/include/socket_wrapper.hpp @@ -0,0 +1,95 @@ +/* socket_wrapper.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* The socket wrapper header defines a Socket class that hides the differences + * between Berkely style sockets and Windows sockets, allowing transparent TCP + * access. + */ + + +#ifndef yaSSL_SOCKET_WRAPPER_HPP +#define yaSSL_SOCKET_WRAPPER_HPP + +#include <cassert> + +#ifdef WIN32 + #include <winsock2.h> +#else + #include <sys/time.h> + #include <sys/types.h> + #include <sys/socket.h> + #include <unistd.h> + #include <netinet/in.h> + #include <arpa/inet.h> +#endif + + +namespace yaSSL { + +typedef unsigned int uint; + +#ifdef WIN32 + typedef SOCKET socket_t; +#else + typedef int socket_t; + const socket_t INVALID_SOCKET = -1; + const int SD_RECEIVE = 0; + const int SD_SEND = 1; + const int SD_BOTH = 2; + const int SOCKET_ERROR = -1; +#endif + + + +typedef unsigned char byte; + + +// Wraps Windows Sockets and BSD Sockets +class Socket { + socket_t socket_; // underlying socket descriptor +public: + explicit Socket(socket_t s = INVALID_SOCKET); + virtual ~Socket(); + + void set_fd(socket_t s); + uint get_ready() const; + socket_t get_fd() const; + + uint send(const byte* buf, unsigned int len, int flags = 0) const; + uint receive(byte* buf, unsigned int len, int flags = 0) const; + + void wait() const; + + void closeSocket(); + void shutDown(int how = SD_SEND); + + static int get_lastError(); + static void set_lastError(int error); +private: + Socket(const Socket&); // hide copy + Socket& operator= (const Socket&); // and assign +}; + + +} // naemspace + +#endif // yaSSL_SOCKET_WRAPPER_HPP diff --git a/extra/yassl/include/timer.hpp b/extra/yassl/include/timer.hpp new file mode 100644 index 00000000000..3025b7a0bd9 --- /dev/null +++ b/extra/yassl/include/timer.hpp @@ -0,0 +1,43 @@ +/* timer.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* timer.hpp provides a high res and low res timers + * +*/ + + +#ifndef yaSSL_TIMER_HPP +#define yaSSL_TIMER_HPP + +namespace yaSSL { + +typedef double timer_d; +typedef unsigned int uint; + + + +timer_d timer(); +uint lowResTimer(); + + + +} // namespace +#endif // yaSSL_TIMER_HPP diff --git a/extra/yassl/include/yassl_error.hpp b/extra/yassl/include/yassl_error.hpp new file mode 100644 index 00000000000..4165eb24b66 --- /dev/null +++ b/extra/yassl/include/yassl_error.hpp @@ -0,0 +1,78 @@ +/* yassl_error.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* yaSSL error header defines error codes and an exception class + */ + +#ifndef yaSSL_ERROR_HPP +#define yaSSL_ERROR_HPP + +#include "stdexcept.hpp" + + +namespace yaSSL { + + +enum YasslError { + no_error = 0, + + // 10 - 47 from AlertDescription, 0 also close_notify + + range_error = 101, + realloc_error = 102, + factory_error = 103, + unknown_cipher = 104, + prefix_error = 105, + record_layer = 106, + handshake_layer = 107, + out_of_order = 108, + bad_input = 109, + match_error = 110, + no_key_file = 111, + verify_error = 112, + send_error = 113, + receive_error = 114, + certificate_error = 115, + + // 1000+ from TaoCrypt error.hpp + +}; + + +enum Library { yaSSL_Lib = 0, CryptoLib, SocketLib }; + +// Base class for all yaSSL exceptions +class Error : public mySTL::runtime_error { + YasslError error_; + Library lib_; +public: + explicit Error(const char* s = "", YasslError e = no_error, + Library l = yaSSL_Lib); + + YasslError get_number() const; + Library get_lib() const; +}; + + +} // naemspace + +#endif // yaSSL_ERROR_HPP diff --git a/extra/yassl/include/yassl_imp.hpp b/extra/yassl/include/yassl_imp.hpp new file mode 100644 index 00000000000..52108b6aa1c --- /dev/null +++ b/extra/yassl/include/yassl_imp.hpp @@ -0,0 +1,742 @@ +/* yassl_imp.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* yaSSL implementation header defines all strucutres from the SSL.v3 + * specification "draft-freier-ssl-version3-02.txt" + * all page citations refer to this document unless otherwise noted. + */ + + +#ifndef yaSSL_IMP_HPP +#define yaSSL_IMP_HPP + +#ifdef _MSC_VER + // disable truncated debug symbols + #pragma warning(disable:4786) +#endif + +#include "yassl_types.hpp" +#include "factory.hpp" +#include "list.hpp" // mySTL::list + + +namespace yaSSL { + + +class SSL; // forward decls +class input_buffer; +class output_buffer; + + +struct ProtocolVersion { + uint8 major_; + uint8 minor_; // major and minor SSL/TLS version numbers + + ProtocolVersion(uint8 maj = 3, uint8 min = 0); +}; + + +// Record Layer Header for PlainText, Compressed, and CipherText +struct RecordLayerHeader { + ContentType type_; + ProtocolVersion version_; + uint16 length_; // should not exceed 2^14 +}; + + +// base for all messages +struct Message { + virtual input_buffer& set(input_buffer&) =0; + virtual output_buffer& get(output_buffer&) const =0; + + virtual void Process(input_buffer&, SSL&) =0; + virtual ContentType get_type() const =0; + virtual uint16 get_length() const =0; + + virtual ~Message() {} +}; + + +class ChangeCipherSpec : public Message { + CipherChoice type_; +public: + ChangeCipherSpec(); + + friend input_buffer& operator>>(input_buffer&, ChangeCipherSpec&); + friend output_buffer& operator<<(output_buffer&, const ChangeCipherSpec&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + ContentType get_type() const; + uint16 get_length() const; + void Process(input_buffer&, SSL&); +private: + ChangeCipherSpec(const ChangeCipherSpec&); // hide copy + ChangeCipherSpec& operator=(const ChangeCipherSpec&); // and assign +}; + + + +class Alert : public Message { + AlertLevel level_; + AlertDescription description_; +public: + Alert() {} + Alert(AlertLevel al, AlertDescription ad); + + ContentType get_type() const; + uint16 get_length() const; + void Process(input_buffer&, SSL&); + + friend input_buffer& operator>>(input_buffer&, Alert&); + friend output_buffer& operator<<(output_buffer&, const Alert&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; +private: + Alert(const Alert&); // hide copy + Alert& operator=(const Alert&); // and assign +}; + + +class Data : public Message { + uint16 length_; + opaque* buffer_; // read buffer used by fillData input + const opaque* write_buffer_; // write buffer used by output operator +public: + Data(); + Data(uint16 len, opaque* b); + Data(uint16 len, const opaque* w); + + friend output_buffer& operator<<(output_buffer&, const Data&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + ContentType get_type() const; + uint16 get_length() const; + const opaque* get_buffer() const; + void set_length(uint16 l); + opaque* set_buffer(); + void Process(input_buffer&, SSL&); +private: + Data(const Data&); // hide copy + Data& operator=(const Data&); // and assign +}; + + +uint32 c24to32(const uint24); // forward form internal header +void c32to24(uint32, uint24&); + + +// HandShake header, same for each message type from page 20/21 +class HandShakeHeader : public Message { + HandShakeType type_; + uint24 length_; // length of message +public: + HandShakeHeader() {} + + ContentType get_type() const; + uint16 get_length() const; + HandShakeType get_handshakeType() const; + void Process(input_buffer&, SSL&); + + void set_type(HandShakeType hst); + void set_length(uint32 u32); + + friend input_buffer& operator>>(input_buffer&, HandShakeHeader&); + friend output_buffer& operator<<(output_buffer&, const HandShakeHeader&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; +private: + HandShakeHeader(const HandShakeHeader&); // hide copy + HandShakeHeader& operator=(const HandShakeHeader&); // and assign +}; + + +// Base Class for all handshake messages +class HandShakeBase { + int length_; +public: + int get_length() const; + void set_length(int); + + // for building buffer's type field + virtual HandShakeType get_type() const =0; + + // handles dispactch of proper >> + virtual input_buffer& set(input_buffer& in) =0; + virtual output_buffer& get(output_buffer& out) const =0; + + virtual void Process(input_buffer&, SSL&) =0; + + virtual ~HandShakeBase() {} +}; + + +struct HelloRequest : public HandShakeBase { + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + void Process(input_buffer&, SSL&); + + HandShakeType get_type() const; +}; + + +// The Client's Hello Message from page 23 +class ClientHello : public HandShakeBase { + ProtocolVersion client_version_; + Random random_; + uint8 id_len_; // session id length + opaque session_id_[ID_LEN]; + uint16 suite_len_; // cipher suite length + opaque cipher_suites_[MAX_SUITE_SZ]; + uint8 comp_len_; // compression length + CompressionMethod compression_methods_; +public: + friend input_buffer& operator>>(input_buffer&, ClientHello&); + friend output_buffer& operator<<(output_buffer&, const ClientHello&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + HandShakeType get_type() const; + void Process(input_buffer&, SSL&); + + const opaque* get_random() const; + friend void buildClientHello(SSL&, ClientHello&, CompressionMethod); + friend void ProcessOldClientHello(input_buffer& input, SSL& ssl); + + ClientHello(); + explicit ClientHello(ProtocolVersion pv); +private: + ClientHello(const ClientHello&); // hide copy + ClientHello& operator=(const ClientHello&); // and assign +}; + + + +// The Server's Hello Message from page 24 +class ServerHello : public HandShakeBase { + ProtocolVersion server_version_; + Random random_; + uint8 id_len_; // session id length + opaque session_id_[ID_LEN]; + opaque cipher_suite_[SUITE_LEN]; + CompressionMethod compression_method_; +public: + explicit ServerHello(ProtocolVersion pv); + ServerHello(); + + friend input_buffer& operator>>(input_buffer&, ServerHello&); + friend output_buffer& operator<<(output_buffer&, const ServerHello&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + HandShakeType get_type() const; + void Process(input_buffer&, SSL&); + + const opaque* get_random() const; + friend void buildServerHello(SSL&, ServerHello&); +private: + ServerHello(const ServerHello&); // hide copy + ServerHello& operator=(const ServerHello&); // and assign +}; + + +class x509; + +// Certificate could be a chain +class Certificate : public HandShakeBase { + const x509* cert_; +public: + Certificate(); + explicit Certificate(const x509* cert); + friend output_buffer& operator<<(output_buffer&, const Certificate&); + + const opaque* get_buffer() const; + + // Process handles input, needs SSL + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + HandShakeType get_type() const; + void Process(input_buffer&, SSL&); +private: + Certificate(const Certificate&); // hide copy + Certificate& operator=(const Certificate&); // and assign +}; + + + +// RSA Public Key +struct ServerRSAParams { + opaque* rsa_modulus_; + opaque* rsa_exponent_; +}; + + +// Ephemeral Diffie-Hellman Parameters +class ServerDHParams { + int pSz_; + int gSz_; + int pubSz_; + opaque* p_; + opaque* g_; + opaque* Ys_; +public: + ServerDHParams(); + ~ServerDHParams(); + + int get_pSize() const; + int get_gSize() const; + int get_pubSize() const; + + const opaque* get_p() const; + const opaque* get_g() const; + const opaque* get_pub() const; + + opaque* alloc_p(int sz); + opaque* alloc_g(int sz); + opaque* alloc_pub(int sz); +private: + ServerDHParams(const ServerDHParams&); // hide copy + ServerDHParams& operator=(const ServerDHParams&); // and assign +}; + + +struct ServerKeyBase { + virtual ~ServerKeyBase() {} + virtual void build(SSL&) {} + virtual void read(SSL&, input_buffer&) {} + virtual int get_length() const; + virtual opaque* get_serverKey() const; +}; + + +// Server random number for FORTEZZA KEA +struct Fortezza_Server : public ServerKeyBase { + opaque r_s_[FORTEZZA_MAX]; +}; + + +struct SignatureBase { + virtual ~SignatureBase() {} +}; + +struct anonymous_sa : public SignatureBase {}; + + +struct Hashes { + uint8 md5_[MD5_LEN]; + uint8 sha_[SHA_LEN]; +}; + + +struct rsa_sa : public SignatureBase { + Hashes hashes_; +}; + + +struct dsa_sa : public SignatureBase { + uint8 sha_[SHA_LEN]; +}; + + +// Server's Diffie-Hellman exchange +class DH_Server : public ServerKeyBase { + ServerDHParams parms_; + opaque* signature_; + + int length_; // total length of message + opaque* keyMessage_; // total exchange message +public: + DH_Server(); + ~DH_Server(); + + void build(SSL&); + void read(SSL&, input_buffer&); + int get_length() const; + opaque* get_serverKey() const; +private: + DH_Server(const DH_Server&); // hide copy + DH_Server& operator=(const DH_Server&); // and assign +}; + + +// Server's RSA exchange +struct RSA_Server : public ServerKeyBase { + ServerRSAParams params_; + opaque* signature_; // signed rsa_sa hashes +}; + + +class ServerKeyExchange : public HandShakeBase { + ServerKeyBase* server_key_; +public: + explicit ServerKeyExchange(SSL&); + ServerKeyExchange(); + ~ServerKeyExchange(); + + void createKey(SSL&); + void build(SSL& ssl); + + const opaque* getKey() const; + int getKeyLength() const; + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + friend output_buffer& operator<<(output_buffer&, const ServerKeyExchange&); + + void Process(input_buffer&, SSL&); + HandShakeType get_type() const; +private: + ServerKeyExchange(const ServerKeyExchange&); // hide copy + ServerKeyExchange& operator=(const ServerKeyExchange&); // and assign +}; + + + +class CertificateRequest : public HandShakeBase { + ClientCertificateType certificate_types_[CERT_TYPES]; + int typeTotal_; + mySTL::list<DistinguishedName> certificate_authorities_; +public: + CertificateRequest(); + ~CertificateRequest(); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + friend input_buffer& operator>>(input_buffer&, CertificateRequest&); + friend output_buffer& operator<<(output_buffer&, + const CertificateRequest&); + + void Process(input_buffer&, SSL&); + HandShakeType get_type() const; + + void Build(); +private: + CertificateRequest(const CertificateRequest&); // hide copy + CertificateRequest& operator=(const CertificateRequest&); // and assign +}; + + +struct ServerHelloDone : public HandShakeBase { + ServerHelloDone(); + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + void Process(input_buffer& input, SSL& ssl); + + HandShakeType get_type() const; +}; + + +struct PreMasterSecret { + opaque random_[SECRET_LEN]; // first two bytes Protocol Version +}; + + +struct ClientKeyBase { + virtual ~ClientKeyBase() {} + virtual void build(SSL&) {} + virtual void read(SSL&, input_buffer&) {} + virtual int get_length() const; + virtual opaque* get_clientKey() const; +}; + + +class EncryptedPreMasterSecret : public ClientKeyBase { + opaque* secret_; + int length_; +public: + EncryptedPreMasterSecret(); + ~EncryptedPreMasterSecret(); + + void build(SSL&); + void read(SSL&, input_buffer&); + int get_length() const; + opaque* get_clientKey() const; + void alloc(int sz); +private: + // hide copy and assign + EncryptedPreMasterSecret(const EncryptedPreMasterSecret&); + EncryptedPreMasterSecret& operator=(const EncryptedPreMasterSecret&); +}; + + +// Fortezza Key Parameters from page 29 +// hard code lengths cause only used here +struct FortezzaKeys : public ClientKeyBase { + opaque y_c_ [128]; // client's Yc, public value + opaque r_c_ [128]; // client's Rc + opaque y_signature_ [40]; // DSS signed public key + opaque wrapped_client_write_key_ [12]; // wrapped by the TEK + opaque wrapped_server_write_key_ [12]; // wrapped by the TEK + opaque client_write_iv_ [24]; + opaque server_write_iv_ [24]; + opaque master_secret_iv_ [24]; // IV used to encrypt preMaster + opaque encrypted_preMasterSecret_[48]; // random & crypted by the TEK +}; + + + +// Diffie-Hellman public key from page 40/41 +class ClientDiffieHellmanPublic : public ClientKeyBase { + PublicValueEncoding public_value_encoding_; + int length_; // includes two byte length for message + opaque* Yc_; // length + Yc_ + // dh_Yc only if explicit, otherwise sent in certificate + enum { KEY_OFFSET = 2 }; +public: + ClientDiffieHellmanPublic(); + ~ClientDiffieHellmanPublic(); + + void build(SSL&); + void read(SSL&, input_buffer&); + int get_length() const; + opaque* get_clientKey() const; + void alloc(int sz, bool offset = false); +private: + // hide copy and assign + ClientDiffieHellmanPublic(const ClientDiffieHellmanPublic&); + ClientDiffieHellmanPublic& operator=(const ClientDiffieHellmanPublic&); +}; + + +class ClientKeyExchange : public HandShakeBase { + ClientKeyBase* client_key_; +public: + explicit ClientKeyExchange(SSL& ssl); + ClientKeyExchange(); + ~ClientKeyExchange(); + + void createKey(SSL&); + void build(SSL& ssl); + + const opaque* getKey() const; + int getKeyLength() const; + + friend output_buffer& operator<<(output_buffer&, const ClientKeyExchange&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + HandShakeType get_type() const; + void Process(input_buffer&, SSL&); +private: + ClientKeyExchange(const ClientKeyExchange&); // hide copy + ClientKeyExchange& operator=(const ClientKeyExchange&); // and assign +}; + + +class CertificateVerify : public HandShakeBase { + Hashes hashes_; + byte* signature_; // owns +public: + CertificateVerify(); + ~CertificateVerify(); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + friend input_buffer& operator>>(input_buffer&, CertificateVerify&); + friend output_buffer& operator<<(output_buffer&, const CertificateVerify&); + + void Process(input_buffer&, SSL&); + HandShakeType get_type() const; + + void Build(SSL&); +private: + CertificateVerify(const CertificateVerify&); // hide copy + CertificateVerify& operator=(const CertificateVerify&); // and assign +}; + + +class Finished : public HandShakeBase { + Hashes hashes_; +public: + Finished(); + + uint8* set_md5(); + uint8* set_sha(); + + friend input_buffer& operator>>(input_buffer&, Finished&); + friend output_buffer& operator<<(output_buffer&, const Finished&); + + input_buffer& set(input_buffer& in); + output_buffer& get(output_buffer& out) const; + + void Process(input_buffer&, SSL&); + + HandShakeType get_type() const; +private: + Finished(const Finished&); // hide copy + Finished& operator=(const Finished&); // and assign +}; + + +class RandomPool; // forward for connection + + +// SSL Connection defined on page 11 +struct Connection { + opaque *pre_master_secret_; + opaque master_secret_[SECRET_LEN]; + opaque client_random_[RAN_LEN]; + opaque server_random_[RAN_LEN]; + opaque sessionID_[ID_LEN]; + opaque client_write_MAC_secret_[SHA_LEN]; // sha is max size + opaque server_write_MAC_secret_[SHA_LEN]; + opaque client_write_key_[AES_256_KEY_SZ]; // aes 256bit is max sz + opaque server_write_key_[AES_256_KEY_SZ]; + opaque client_write_IV_[AES_IV_SZ]; // aes is max size + opaque server_write_IV_[AES_IV_SZ]; + uint32 sequence_number_; + uint32 peer_sequence_number_; + uint32 pre_secret_len_; // pre master length + bool send_server_key_; // server key exchange? + bool master_clean_; // master secret clean? + bool TLS_; // TLSv1 or greater + ProtocolVersion version_; + RandomPool& random_; + + Connection(ProtocolVersion v, RandomPool& ran); + ~Connection(); + + void AllocPreSecret(uint sz); + void CleanPreMaster(); + void CleanMaster(); + void TurnOffTLS(); +private: + Connection(const Connection&); // hide copy + Connection& operator=(const Connection&); // and assign +}; + + +struct Ciphers; // forward + + +// TLSv1 Security Spec, defined on page 56 of RFC 2246 +struct Parameters { + ConnectionEnd entity_; + BulkCipherAlgorithm bulk_cipher_algorithm_; + CipherType cipher_type_; + uint8 key_size_; + uint8 iv_size_; + IsExportable is_exportable_; + MACAlgorithm mac_algorithm_; + uint8 hash_size_; + CompressionMethod compression_algorithm_; + KeyExchangeAlgorithm kea_; // yassl additions + SignatureAlgorithm sig_algo_; // signature auth type + SignatureAlgorithm verify_algo_; // cert verify auth type + bool pending_; + bool resumable_; // new conns by session + uint16 encrypt_size_; // current msg encrypt sz + Cipher suite_[SUITE_LEN]; // choosen suite + uint8 suites_size_; + Cipher suites_[MAX_SUITE_SZ]; + char cipher_name_[MAX_SUITE_NAME]; + char cipher_list_[MAX_CIPHER_LIST]; + + Parameters(ConnectionEnd, const Ciphers&, ProtocolVersion); + + void SetSuites(ProtocolVersion pv); + void SetCipherNames(); +private: + Parameters(const Parameters&); // hide copy + Parameters& operator=(const Parameters&); // and assing +}; + + +input_buffer& operator>>(input_buffer&, RecordLayerHeader&); +output_buffer& operator<<(output_buffer&, const RecordLayerHeader&); + +input_buffer& operator>>(input_buffer&, Message&); +output_buffer& operator<<(output_buffer&, const Message&); + +input_buffer& operator>>(input_buffer&, HandShakeBase&); +output_buffer& operator<<(output_buffer&, const HandShakeBase&); + + +// Message Factory definition +// uses the ContentType enumeration for unique id +typedef Factory<Message> MessageFactory; +void InitMessageFactory(MessageFactory&); // registers derived classes + +// HandShake Factory definition +// uses the HandShakeType enumeration for unique id +typedef Factory<HandShakeBase> HandShakeFactory; +void InitHandShakeFactory(HandShakeFactory&); // registers derived classes + +// ServerKey Factory definition +// uses KeyExchangeAlgorithm enumeration for unique id +typedef Factory<ServerKeyBase> ServerKeyFactory; +void InitServerKeyFactory(ServerKeyFactory&); + +// ClientKey Factory definition +// uses KeyExchangeAlgorithm enumeration for unique id +typedef Factory<ClientKeyBase> ClientKeyFactory; +void InitClientKeyFactory(ClientKeyFactory&); + + +// Message Creators +Message* CreateHandShake(); +Message* CreateCipherSpec(); +Message* CreateAlert(); +Message* CreateData(); + + +// HandShake Creators +HandShakeBase* CreateCertificate(); +HandShakeBase* CreateHelloRequest(); +HandShakeBase* CreateClientHello(); +HandShakeBase* CreateServerHello(); +HandShakeBase* CreateServerKeyExchange(); +HandShakeBase* CreateCertificateRequest(); +HandShakeBase* CreateServerHelloDone(); +HandShakeBase* CreateClientKeyExchange(); +HandShakeBase* CreateCertificateVerify(); +HandShakeBase* CreateFinished(); + + +// ServerKey Exchange Creators +ServerKeyBase* CreateRSAServerKEA(); +ServerKeyBase* CreateDHServerKEA(); +ServerKeyBase* CreateFortezzaServerKEA(); + +// ClientKey Exchange Creators +ClientKeyBase* CreateRSAClient(); +ClientKeyBase* CreateDHClient(); +ClientKeyBase* CreateFortezzaClient(); + + + +} // naemspace + +#endif // yaSSL_IMP_HPP diff --git a/extra/yassl/include/yassl_int.hpp b/extra/yassl/include/yassl_int.hpp new file mode 100644 index 00000000000..fa13baf1ac2 --- /dev/null +++ b/extra/yassl/include/yassl_int.hpp @@ -0,0 +1,538 @@ +/* yassl_int.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* yaSSL internal header defines SSL supporting types not specified in the + * draft along with type conversion functions and openssl compatibility + */ + + +#ifndef yaSSL_INT_HPP +#define yaSSL_INT_HPP + +#include "yassl_imp.hpp" +#include "crypto_wrapper.hpp" +#include "cert_wrapper.hpp" +#include "lock.hpp" +#include "log.hpp" + + +namespace yaSSL { + + +// State Machine for Record Layer Protocol +enum RecordLayerState { + recordNotReady = 0, // fatal error, no more processing + recordReady +}; + + +// State Machine for HandShake Protocol +enum HandShakeState { + handShakeNotReady = 0, // fatal error, no more processing + preHandshake, // initial state + inHandshake, // handshake started + handShakeReady // handshake done +}; + + +// client input HandShake state, use if HandShakeState == inHandShake +enum ClientState { + serverNull = 0, + serverHelloComplete, + serverCertComplete, + serverKeyExchangeComplete, + serverHelloDoneComplete, + serverFinishedComplete +}; + + +// server input HandShake state, use if HandShakeState == inHandShake +enum ServerState { + clientNull = 0, + clientHelloComplete, + clientKeyExchangeComplete, + clientFinishedComplete +}; + + +// combines all states +class States { + enum {MAX_ERROR_SZ = 80 }; + + RecordLayerState recordLayer_; + HandShakeState handshakeLayer_; + ClientState clientState_; + ServerState serverState_; + char errorString_[MAX_ERROR_SZ]; + YasslError what_; +public: + States(); + + const RecordLayerState& getRecord() const; + const HandShakeState& getHandShake() const; + const ClientState& getClient() const; + const ServerState& getServer() const; + const char* getString() const; + YasslError What() const; + + RecordLayerState& useRecord(); + HandShakeState& useHandShake(); + ClientState& useClient(); + ServerState& useServer(); + char* useString(); + void SetError(YasslError); +private: + States(const States&); // hide copy + States& operator=(const States&); // and assign +}; + + +// holds all factories +class sslFactory { + MessageFactory messageFactory_; // creates new messages by type + HandShakeFactory handShakeFactory_; // creates new handshake types + ServerKeyFactory serverKeyFactory_; // creates new server key types + ClientKeyFactory clientKeyFactory_; // creates new client key types + + sslFactory(); // only GetSSL_Factory creates +public: + const MessageFactory& getMessage() const; + const HandShakeFactory& getHandShake() const; + const ServerKeyFactory& getServerKey() const; + const ClientKeyFactory& getClientKey() const; + + friend sslFactory& GetSSL_Factory(); // singleton creator +private: + sslFactory(const sslFactory&); // hide copy + sslFactory& operator=(const sslFactory&); // and assign +}; + + +// openSSL X509 names +class X509_NAME { + char* name_; +public: + X509_NAME(const char*, size_t sz); + ~X509_NAME(); + + char* GetName(); +private: + X509_NAME(const X509_NAME&); // hide copy + X509_NAME& operator=(const X509_NAME&); // and assign +}; + + +// openSSL X509 +class X509 { + X509_NAME issuer_; + X509_NAME subject_; +public: + X509(const char* i, size_t, const char* s, size_t); + ~X509() {} + + X509_NAME* GetIssuer(); + X509_NAME* GetSubject(); +private: + X509(const X509&); // hide copy + X509& operator=(const X509&); // and assign +}; + + +// openSSL bignum +struct BIGNUM { + Integer int_; + void assign(const byte* b, uint s) { int_.assign(b,s); } +}; + + +// openSSL session +class SSL_SESSION { + opaque sessionID_[ID_LEN]; + opaque master_secret_[SECRET_LEN]; + Cipher suite_[SUITE_LEN]; + uint bornOn_; // create time in seconds + uint timeout_; // timeout in seconds + RandomPool& random_; // will clean master secret +public: + explicit SSL_SESSION(RandomPool&); + SSL_SESSION(const SSL&, RandomPool&); + ~SSL_SESSION(); + + const opaque* GetID() const; + const opaque* GetSecret() const; + const Cipher* GetSuite() const; + uint GetBornOn() const; + uint GetTimeOut() const; + void SetTimeOut(uint); + + SSL_SESSION& operator=(const SSL_SESSION&); // allow assign for resumption +private: + SSL_SESSION(const SSL_SESSION&); // hide copy +}; + + +// holds all sessions +class Sessions { + mySTL::list<SSL_SESSION*> list_; + RandomPool random_; // for session cleaning + Mutex mutex_; // no-op for single threaded + + Sessions() {} // only GetSessions can create +public: + SSL_SESSION* lookup(const opaque*, SSL_SESSION* copy = 0); + void add(const SSL&); + void remove(const opaque*); + + ~Sessions(); + + friend Sessions& GetSessions(); // singleton creator +private: + Sessions(const Sessions&); // hide copy + Sessions& operator=(const Sessions&); // and assign +}; + + +Sessions& GetSessions(); // forward singletons +sslFactory& GetSSL_Factory(); + + +// openSSL method and context types +class SSL_METHOD { + ProtocolVersion version_; + ConnectionEnd side_; + bool verifyPeer_; + bool failNoCert_; +public: + explicit SSL_METHOD(ConnectionEnd ce, ProtocolVersion pv); + + ProtocolVersion getVersion() const; + ConnectionEnd getSide() const; + + void setVerifyPeer(); + void setFailNoCert(); + + bool verifyPeer() const; + bool failNoCert() const; +private: + SSL_METHOD(const SSL_METHOD&); // hide copy + SSL_METHOD& operator=(const SSL_METHOD&); // and assign +}; + + +struct Ciphers { + bool setSuites_; // user set suites from default + byte suites_[MAX_SUITE_SZ]; // new suites + int suiteSz_; // suite length in bytes + + Ciphers() : setSuites_(false), suiteSz_(0) {} +}; + + +struct DH; // forward + + +// save for SSL construction +struct DH_Parms { + Integer p_; + Integer g_; + bool set_; // if set by user + + DH_Parms() : set_(false) {} +}; + + +enum StatsField { + Accept, Connect, AcceptGood, ConnectGood, AcceptRenegotiate, + ConnectRenegotiate, Hits, CbHits, CacheFull, Misses, Timeouts, Number, + GetCacheSize, VerifyMode, VerifyDepth +}; + + +// SSL stats +struct Stats { + long accept_; + long connect_; + long acceptGood_; + long connectGood_; + long acceptRenegotiate_; + long connectRenegotiate_; + + long hits_; + long cbHits_; + long cacheFull_; + long misses_; + long timeouts_; + long number_; + long getCacheSize_; + + int verifyMode_; + int verifyDepth_; +public: + Stats() : accept_(0), connect_(0), acceptGood_(0), connectGood_(0), + acceptRenegotiate_(0), connectRenegotiate_(0), hits_(0), cbHits_(0), + cacheFull_(0), misses_(0), timeouts_(0), number_(0), getCacheSize_(0), + verifyMode_(0), verifyDepth_(0) + {} +private: + Stats(const Stats&); // hide copy + Stats& operator=(const Stats&); // and assign +}; + + +// the SSL context +class SSL_CTX { +public: + typedef mySTL::list<x509*> CertList; +private: + SSL_METHOD* method_; + x509* certificate_; + x509* privateKey_; + CertList caList_; + Ciphers ciphers_; + DH_Parms dhParms_; + Stats stats_; + Mutex mutex_; // for Stats +public: + explicit SSL_CTX(SSL_METHOD* meth); + ~SSL_CTX(); + + const x509* getCert() const; + const x509* getKey() const; + const SSL_METHOD* getMethod() const; + const Ciphers& GetCiphers() const; + const DH_Parms& GetDH_Parms() const; + const Stats& GetStats() const; + + void setVerifyPeer(); + void setFailNoCert(); + bool SetCipherList(const char*); + bool SetDH(const DH&); + + void IncrementStats(StatsField); + void AddCA(x509* ca); + const CertList& GetCA_List() const; + + friend int read_file(SSL_CTX*, const char*, int, CertType); +private: + SSL_CTX(const SSL_CTX&); // hide copy + SSL_CTX& operator=(const SSL_CTX&); // and assign +}; + + +// holds all cryptographic types +class Crypto { + Digest* digest_; // agreed upon digest + BulkCipher* cipher_; // agreed upon cipher + DiffieHellman* dh_; // dh parms + RandomPool random_; // random number generator + CertManager cert_; // manages certificates +public: + explicit Crypto(); + ~Crypto(); + + const Digest& get_digest() const; + const BulkCipher& get_cipher() const; + const DiffieHellman& get_dh() const; + const RandomPool& get_random() const; + const CertManager& get_certManager() const; + + Digest& use_digest(); + BulkCipher& use_cipher(); + DiffieHellman& use_dh(); + RandomPool& use_random(); + CertManager& use_certManager(); + + void SetDH(DiffieHellman*); + void SetDH(const DH_Parms&); + void setDigest(Digest*); + void setCipher(BulkCipher*); + + bool DhSet(); +private: + Crypto(const Crypto&); // hide copy + Crypto& operator=(const Crypto&); // and assign +}; + + +// holds all handshake and verify hashes +class sslHashes { + MD5 md5HandShake_; // md5 handshake hash + SHA shaHandShake_; // sha handshake hash + Finished verify_; // peer's verify hash + Hashes certVerify_; // peer's cert verify hash +public: + sslHashes() {} + + const MD5& get_MD5() const; + const SHA& get_SHA() const; + const Finished& get_verify() const; + const Hashes& get_certVerify() const; + + MD5& use_MD5(); + SHA& use_SHA(); + Finished& use_verify(); + Hashes& use_certVerify(); +private: + sslHashes(const sslHashes&); // hide copy + sslHashes& operator=(const sslHashes&); // and assign +}; + + +// holds input and output buffers +class Buffers { + typedef mySTL::list<input_buffer*> inputList; + typedef mySTL::list<output_buffer*> outputList; + + inputList dataList_; // list of users app data / handshake + outputList handShakeList_; // buffered handshake msgs +public: + Buffers() {} + ~Buffers(); + + const inputList& getData() const; + const outputList& getHandShake() const; + + inputList& useData(); + outputList& useHandShake(); +private: + Buffers(const Buffers&); // hide copy + Buffers& operator=(const Buffers&); // and assign +}; + + +// wraps security parameters +class Security { + Connection conn_; // connection information + Parameters parms_; // may be pending + SSL_SESSION resumeSession_; // if resuming + SSL_CTX* ctx_; // context used to init + bool resuming_; // trying to resume +public: + Security(ProtocolVersion, RandomPool&, ConnectionEnd, const Ciphers&, + SSL_CTX*); + + const SSL_CTX* GetContext() const; + const Connection& get_connection() const; + const Parameters& get_parms() const; + const SSL_SESSION& get_resume() const; + bool get_resuming() const; + + Connection& use_connection(); + Parameters& use_parms(); + SSL_SESSION& use_resume(); + + void set_resuming(bool b); +private: + Security(const Security&); // hide copy + Security& operator=(const Security&); // and assign +}; + + +// THE SSL type +class SSL { + Crypto crypto_; // agreed crypto agents + Security secure_; // Connection and Session parms + States states_; // Record and HandShake states + sslHashes hashes_; // handshake, finished hashes + Socket socket_; // socket wrapper + Buffers buffers_; // buffered handshakes and data + Log log_; // logger +public: + SSL(SSL_CTX* ctx); + + // gets and uses + const Crypto& getCrypto() const; + const Security& getSecurity() const; + const States& getStates() const; + const sslHashes& getHashes() const; + const sslFactory& getFactory() const; + const Socket& getSocket() const; + YasslError GetError() const; + + Crypto& useCrypto(); + Security& useSecurity(); + States& useStates(); + sslHashes& useHashes(); + Socket& useSocket(); + Log& useLog(); + + // sets + void set_pending(Cipher suite); + void set_random(const opaque*, ConnectionEnd); + void set_sessionID(const opaque*); + void set_session(SSL_SESSION*); + void set_preMaster(const opaque*, uint); + void set_masterSecret(const opaque*); + void SetError(YasslError); + + // helpers + bool isTLS() const; + void order_error(); + void makeMasterSecret(); + void makeTLSMasterSecret(); + void addData(input_buffer* data); + void fillData(Data&); + void addBuffer(output_buffer* b); + void flushBuffer(); + void verifyState(const RecordLayerHeader&); + void verifyState(const HandShakeHeader&); + void verifyState(ClientState); + void verifyState(ServerState); + void verfiyHandShakeComplete(); + void matchSuite(const opaque*, uint length); + void deriveKeys(); + void deriveTLSKeys(); + void Send(const byte*, uint); + + uint bufferedData(); + uint get_SEQIncrement(bool); + + const byte* get_macSecret(bool); +private: + void storeKeys(const opaque*); + void setKeys(); + void verifyClientState(HandShakeType); + void verifyServerState(HandShakeType); + + SSL(const SSL&); // hide copy + const SSL& operator=(const SSL&); // and assign +}; + + + +// conversion functions +void c32to24(uint32, uint24&); +void c24to32(const uint24, uint32&); + +uint32 c24to32(const uint24); + +void ato16(const opaque*, uint16&); +void ato24(const opaque*, uint24&); + +void c16toa(uint16, opaque*); +void c24toa(const uint24, opaque*); +void c32toa(uint32 u32, opaque*); + + +} // naemspace + +#endif // yaSSL_INT_HPP diff --git a/extra/yassl/include/yassl_types.hpp b/extra/yassl/include/yassl_types.hpp new file mode 100644 index 00000000000..70888f35c81 --- /dev/null +++ b/extra/yassl/include/yassl_types.hpp @@ -0,0 +1,415 @@ +/* yassl_types.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* yaSSL types header defines all constants, enums, and typedefs + * from the SSL.v3 specification "draft-freier-ssl-version3-02.txt" + */ + + +#ifndef yaSSL_TYPES_HPP +#define yaSSL_TYPES_HPP + +#include<cstddef> + +namespace yaSSL { + +// library allocation +struct new_t {}; // yaSSL New type +extern new_t ys; // pass in parameter + +} // namespace yaSSL + +void* operator new (size_t, yaSSL::new_t); +void* operator new[](size_t, yaSSL::new_t); + +namespace yaSSL { + + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef uint8 uint24[3]; +typedef uint32 uint64[2]; + +typedef uint8 opaque; +typedef opaque byte; + +typedef unsigned int uint; + + +// all length constants in bytes +const int ID_LEN = 32; // session id length +const int SUITE_LEN = 2; // cipher suite length +const int SECRET_LEN = 48; // pre RSA and all master secret length +const int MASTER_ROUNDS = 3; // master secret derivation rounds +const int RAN_LEN = 32; // client and server random length +const int MAC_BLOCK_SZ = 64; // MAC block size, & padding +const int MD5_LEN = 16; // MD5 digest length +const int SHA_LEN = 20; // SHA digest length +const int RMD_LEN = 20; // RIPEMD-160 digest length +const int PREFIX = 3; // up to 3 prefix letters for secret rounds +const int KEY_PREFIX = 7; // up to 7 prefix letters for key rounds +const int FORTEZZA_MAX = 128; // Maximum Fortezza Key length +const int MAX_SUITE_SZ = 64; // 32 max suites * sizeof(suite) +const int MAX_SUITE_NAME = 48; // max length of suite name +const int MAX_CIPHER_LIST = 512; // max length of cipher list names +const int SIZEOF_ENUM = 1; // SSL considers an enum 1 byte, not 4 +const int SIZEOF_SENDER = 4; // Sender constant, for finished generation +const int PAD_MD5 = 48; // pad length 1 and 2 for md5 finished +const int PAD_SHA = 40; // should be 44, specd wrong by netscape +const int PAD_RMD = 44; // pad length for RIPEMD-160, some use 40?? +const int CERT_HEADER = 3; // always use 3 bytes for certificate +const int CERT_TYPES = 7; // certificate request types +const int REQUEST_HEADER = 2; // request uses 2 bytes +const int VERIFY_HEADER = 2; // verify length field +const int MIN_CERT_TYPES = 1; // minimum certificate request types +const int MIN_DIS_NAMES = 3; // minimum distinguished names +const int MIN_DIS_SIZE = 1; // minimum distinguished name size +const int RECORD_HEADER = 5; // type + version + length(2) +const int HANDSHAKE_HEADER = 4; // type + length(3) +const int FINISHED_SZ = MD5_LEN + SHA_LEN; // sizeof finished data +const int TLS_FINISHED_SZ = 12; // TLS verify data size +const int SEQ_SZ = 8; // 64 bit sequence number +const int LENGTH_SZ = 2; // length field for HMAC, data only +const int VERSION_SZ = SIZEOF_ENUM * 2; // SSL/TLS length of version +const int DES_KEY_SZ = 8; // DES Key length +const int DES_EDE_KEY_SZ = 24; // DES EDE Key length +const int DES_BLOCK = 8; // DES is always fixed block size 8 +const int DES_IV_SZ = DES_BLOCK; // Init Vector length for DES +const int RC4_KEY_SZ = 16; // RC4 Key length +const int AES_128_KEY_SZ = 16; // AES 128bit Key length +const int AES_256_KEY_SZ = 32; // AES 256bit Key length +const int AES_BLOCK_SZ = 16; // AES 128bit block size, rfc 3268 +const int AES_IV_SZ = AES_BLOCK_SZ; // AES Init Vector length +const int DSS_SIG_SZ = 40; // two 20 byte high byte first Integers +const int DSS_ENCODED_EXTRA = 6; // seqID + len(1) + (intID + len(1)) * 2 +const int EVP_SALT_SZ = 8; +const int MASTER_LABEL_SZ = 13; // TLS master secret label size +const int KEY_LABEL_SZ = 13; // TLS key block expansion size +const int FINISHED_LABEL_SZ = 15; // TLS finished lable length +const int SEED_LEN = RAN_LEN * 2; // TLS seed, client + server random +const int DEFAULT_TIMEOUT = 500; // Default Session timeout in seconds +const int MAX_RECORD_SIZE = 16384; // 2^14, max size by standard + + +typedef uint8 Cipher; // first byte is always 0x00 for SSLv3 & TLS + +typedef opaque Random[RAN_LEN]; + +typedef opaque* DistinguishedName; + +typedef bool IsExportable; + + +enum CompressionMethod { no_compression = 0 }; + +enum CipherType { stream, block }; + +enum CipherChoice { change_cipher_spec_choice = 1 }; + +enum PublicValueEncoding { implicit_encoding, explicit_encoding }; + +enum ConnectionEnd { server_end, client_end }; + +enum AlertLevel { warning = 1, fatal = 2, }; + + + +// Record Layer Header identifier from page 12 +enum ContentType { + no_type = 0, + change_cipher_spec = 20, + alert = 21, + handshake = 22, + application_data = 23 +}; + + +// HandShake Layer Header identifier from page 20 +enum HandShakeType { + no_shake = -1, + hello_request = 0, + client_hello = 1, + server_hello = 2, + certificate = 11, + server_key_exchange = 12, + certificate_request = 13, + server_hello_done = 14, + certificate_verify = 15, + client_key_exchange = 16, + finished = 20 +}; + + +// Valid Alert types from page 16/17 +enum AlertDescription { + close_notify = 0, + unexpected_message = 10, + bad_record_mac = 20, + decompression_failure = 30, + handshake_failure = 40, + no_certificate = 41, + bad_certificate = 42, + unsupported_certificate = 43, + certificate_revoked = 44, + certificate_expired = 45, + certificate_unknown = 46, + illegal_parameter = 47 +}; + + +// Supported Key Exchange Protocols +enum KeyExchangeAlgorithm { + no_kea = 0, + rsa_kea, + diffie_hellman_kea, + fortezza_kea +}; + + +// Supported Authentication Schemes +enum SignatureAlgorithm { + anonymous_sa_algo = 0, + rsa_sa_algo, + dsa_sa_algo +}; + + +// Valid client certificate request types from page 27 +enum ClientCertificateType { + rsa_sign = 1, + dss_sign = 2, + rsa_fixed_dh = 3, + dss_fixed_dh = 4, + rsa_ephemeral_dh = 5, + dss_ephemeral_dh = 6, + fortezza_kea_cert = 20 +}; + + +// Supported Ciphers from page 43 +enum BulkCipherAlgorithm { + cipher_null, + rc4, + rc2, + des, + triple_des, // leading 3 (3des) not valid identifier + des40, + idea, + aes +}; + + +// Supported Message Authentication Codes from page 43 +enum MACAlgorithm { + no_mac, + md5, + sha, + rmd +}; + + +// Certificate file Type +enum CertType { Cert = 0, PrivateKey, CA }; + + +// all Cipher Suites from pages 41/42 +const Cipher SSL_NULL_WITH_NULL_NULL = 0; // { 0x00, 0x00 } +const Cipher SSL_RSA_WITH_NULL_MD5 = 1; // { 0x00, 0x01 } +const Cipher SSL_RSA_WITH_NULL_SHA = 2; // { 0x00, 0x02 } +const Cipher SSL_RSA_EXPORT_WITH_RC4_40_MD5 = 3; // { 0x00, 0x03 } +const Cipher SSL_RSA_WITH_RC4_128_MD5 = 4; // { 0x00, 0x04 } +const Cipher SSL_RSA_WITH_RC4_128_SHA = 5; // { 0x00, 0x05 } +const Cipher SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 6; // { 0x00, 0x06 } +const Cipher SSL_RSA_WITH_IDEA_CBC_SHA = 7; // { 0x00, 0x07 } +const Cipher SSL_RSA_EXPORT_WITH_DES40_CBC_SHA = 8; // { 0x00, 0x08 } +const Cipher SSL_RSA_WITH_DES_CBC_SHA = 9; // { 0x00, 0x09 } +const Cipher SSL_RSA_WITH_3DES_EDE_CBC_SHA = 10; // { 0x00, 0x0A } +const Cipher SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 11; // { 0x00, 0x0B } +const Cipher SSL_DH_DSS_WITH_DES_CBC_SHA = 12; // { 0x00, 0x0C } +const Cipher SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA = 13; // { 0x00, 0x0D } +const Cipher SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 14; // { 0x00, 0x0E } +const Cipher SSL_DH_RSA_WITH_DES_CBC_SHA = 15; // { 0x00, 0x0F } +const Cipher SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA = 16; // { 0x00, 0x10 } +const Cipher SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 17; // { 0x00, 0x11 } +const Cipher SSL_DHE_DSS_WITH_DES_CBC_SHA = 18; // { 0x00, 0x12 } +const Cipher SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 19; // { 0x00, 0x13 } +const Cipher SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 20; // { 0x00, 0x14 } +const Cipher SSL_DHE_RSA_WITH_DES_CBC_SHA = 21; // { 0x00, 0x15 } +const Cipher SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 22; // { 0x00, 0x16 } +const Cipher SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = 23; // { 0x00, 0x17 } +const Cipher SSL_DH_anon_WITH_RC4_128_MD5 = 24; // { 0x00, 0x18 } +const Cipher SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 25; // { 0x00, 0x19 } +const Cipher SSL_DH_anon_WITH_DES_CBC_SHA = 26; // { 0x00, 0x1A } +const Cipher SSL_DH_anon_WITH_3DES_EDE_CBC_SHA = 27; // { 0x00, 0x1B } +const Cipher SSL_FORTEZZA_KEA_WITH_NULL_SHA = 28; // { 0x00, 0x1C } +const Cipher SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA = 29; // { 0x00, 0x1D } +const Cipher SSL_FORTEZZA_KEA_WITH_RC4_128_SHA = 30; // { 0x00, 0x1E } + +// .. to 0x2B uses Kerberos Authentication + + +// TLS AES extensions +const Cipher TLS_RSA_WITH_AES_128_CBC_SHA = 47; // { 0x00, 0x2F } +const Cipher TLS_DH_DSS_WITH_AES_128_CBC_SHA = 48; // { 0x00, 0x30 } +const Cipher TLS_DH_RSA_WITH_AES_128_CBC_SHA = 49; // { 0x00, 0x31 } +const Cipher TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 50; // { 0x00, 0x32 } +const Cipher TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 51; // { 0x00, 0x33 } +const Cipher TLS_DH_anon_WITH_AES_128_CBC_SHA = 52; // { 0x00, 0x34 } + +const Cipher TLS_RSA_WITH_AES_256_CBC_SHA = 53; // { 0x00, 0x35 } +const Cipher TLS_DH_DSS_WITH_AES_256_CBC_SHA = 54; // { 0x00, 0x36 } +const Cipher TLS_DH_RSA_WITH_AES_256_CBC_SHA = 55; // { 0x00, 0x37 } +const Cipher TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 56; // { 0x00, 0x38 } +const Cipher TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 57; // { 0x00, 0x39 } +const Cipher TLS_DH_anon_WITH_AES_256_CBC_SHA = 58; // { 0x00, 0x3A } + + +// OpenPGP extensions + +const Cipher TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160 = 114; // { 0x00, 0x72 }; +const Cipher TLS_DHE_DSS_WITH_AES_128_CBC_RMD160 = 115; // { 0x00, 0x73 }; +const Cipher TLS_DHE_DSS_WITH_AES_256_CBC_RMD160 = 116; // { 0x00, 0x74 }; +const Cipher TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160 = 119; // { 0x00, 0x77 }; +const Cipher TLS_DHE_RSA_WITH_AES_128_CBC_RMD160 = 120; // { 0x00, 0x78 }; +const Cipher TLS_DHE_RSA_WITH_AES_256_CBC_RMD160 = 121; // { 0x00, 0x79 }; +const Cipher TLS_RSA_WITH_3DES_EDE_CBC_RMD160 = 124; // { 0x00, 0x7C }; +const Cipher TLS_RSA_WITH_AES_128_CBC_RMD160 = 125; // { 0x00, 0x7D }; +const Cipher TLS_RSA_WITH_AES_256_CBC_RMD160 = 126; // { 0x00, 0x7E }; + + +const char* const null_str = ""; + +const char* const cipher_names[128] = +{ + null_str, // SSL_NULL_WITH_NULL_NULL = 0 + null_str, // SSL_RSA_WITH_NULL_MD5 = 1 + null_str, // SSL_RSA_WITH_NULL_SHA = 2 + null_str, // SSL_RSA_EXPORT_WITH_RC4_40_MD5 = 3 + "RC4-MD5", // SSL_RSA_WITH_RC4_128_MD5 = 4 + "RC4-SHA", // SSL_RSA_WITH_RC4_128_SHA = 5 + null_str, // SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 6 + null_str, // SSL_RSA_WITH_IDEA_CBC_SHA = 7 + null_str, // SSL_RSA_EXPORT_WITH_DES40_CBC_SHA = 8 + "DES-CBC-SHA", // SSL_RSA_WITH_DES_CBC_SHA = 9 + "DES-CBC3-SHA", // SSL_RSA_WITH_3DES_EDE_CBC_SHA = 10 + + null_str, // SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 11 + null_str, // SSL_DH_DSS_WITH_DES_CBC_SHA = 12 + null_str, // SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA = 13 + null_str, // SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 14 + null_str, // SSL_DH_RSA_WITH_DES_CBC_SHA = 15 + null_str, // SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA = 16 + null_str, // SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 17 + "EDH-DSS-DES-CBC-SHA", // SSL_DHE_DSS_WITH_DES_CBC_SHA = 18 + "EDH-DSS-DES-CBC3-SHA", // SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 19 + null_str, // SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 20 + + "EDH-RSA-DES-CBC-SHA", // SSL_DHE_RSA_WITH_DES_CBC_SHA = 21 + "EDH-RSA-DES-CBC3-SHA", // SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 22 + null_str, // SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = 23 + null_str, // SSL_DH_anon_WITH_RC4_128_MD5 = 24 + null_str, // SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 25 + null_str, // SSL_DH_anon_WITH_DES_CBC_SHA = 26 + null_str, // SSL_DH_anon_WITH_3DES_EDE_CBC_SHA = 27 + null_str, // SSL_FORTEZZA_KEA_WITH_NULL_SHA = 28 + null_str, // SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA = 29 + null_str, // SSL_FORTEZZA_KEA_WITH_RC4_128_SHA = 30 + + null_str, null_str, null_str, null_str, null_str, // 31 - 35 + null_str, null_str, null_str, null_str, null_str, // 36 - 40 + null_str, null_str, null_str, null_str, null_str, // 41 - 45 + null_str, // 46 + + // TLS AES extensions + "AES128-SHA", // TLS_RSA_WITH_AES_128_CBC_SHA = 47 + null_str, // TLS_DH_DSS_WITH_AES_128_CBC_SHA = 48 + null_str, // TLS_DH_RSA_WITH_AES_128_CBC_SHA = 49 + "DHE-DSS-AES128-SHA", // TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 50 + "DHE-RSA-AES128-SHA", // TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 51 + null_str, // TLS_DH_anon_WITH_AES_128_CBC_SHA = 52 + + "AES256-SHA", // TLS_RSA_WITH_AES_256_CBC_SHA = 53 + null_str, // TLS_DH_DSS_WITH_AES_256_CBC_SHA = 54 + null_str, // TLS_DH_RSA_WITH_AES_256_CBC_SHA = 55 + "DHE-DSS-AES256-SHA", // TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 56 + "DHE-RSA-AES256-SHA", // TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 57 + null_str, // TLS_DH_anon_WITH_AES_256_CBC_SHA = 58 + + null_str, // 59 + null_str, // 60 + null_str, null_str, null_str, null_str, null_str, // 61 - 65 + null_str, null_str, null_str, null_str, null_str, // 66 - 70 + null_str, null_str, null_str, null_str, null_str, // 71 - 75 + null_str, null_str, null_str, null_str, null_str, // 76 - 80 + null_str, null_str, null_str, null_str, null_str, // 81 - 85 + null_str, null_str, null_str, null_str, null_str, // 86 - 90 + null_str, null_str, null_str, null_str, null_str, // 91 - 95 + null_str, null_str, null_str, null_str, null_str, // 96 - 100 + null_str, null_str, null_str, null_str, null_str, // 101 - 105 + null_str, null_str, null_str, null_str, null_str, // 106 - 110 + null_str, null_str, null_str, // 111 - 113 + + "DHE-DSS-DES-CBC3-RMD", // TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160 = 114 + "DHE-DSS-AES128-RMD", // TLS_DHE_DSS_WITH_AES_128_CBC_RMD160 = 115 + "DHE-DSS-AES256-RMD", // TLS_DHE_DSS_WITH_AES_256_CBC_RMD160 = 116 + null_str, // 117 + null_str, // 118 + "DHE-RSA-DES-CBC3-RMD", // TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160 = 119 + "DHE-RSA-AES128-RMD", // TLS_DHE_RSA_WITH_AES_128_CBC_RMD160 = 120 + "DHE-RSA-AES256-RMD", // TLS_DHE_RSA_WITH_AES_256_CBC_RMD160 = 121 + null_str, // 122 + null_str, // 123 + "DES-CBC3-RMD", // TLS_RSA_WITH_3DES_EDE_CBC_RMD160 = 124 + "AES128-RMD", // TLS_RSA_WITH_AES_128_CBC_RMD160 = 125 + "AES256-RMD", // TLS_RSA_WITH_AES_256_CBC_RMD160 = 126 + null_str, // 127 +}; + +// fill with MD5 pad size since biggest required +const opaque 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 + }; +const opaque 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 + }; + +const opaque client[SIZEOF_SENDER] = { 0x43, 0x4C, 0x4E, 0x54 }; +const opaque server[SIZEOF_SENDER] = { 0x53, 0x52, 0x56, 0x52 }; + +const opaque tls_client[FINISHED_LABEL_SZ + 1] = "client finished"; +const opaque tls_server[FINISHED_LABEL_SZ + 1] = "server finished"; + +const opaque master_label[MASTER_LABEL_SZ + 1] = "master secret"; +const opaque key_label [KEY_LABEL_SZ + 1] = "key expansion"; + + +} // naemspace + +#endif // yaSSL_TYPES_HPP diff --git a/extra/yassl/mySTL/algorithm.hpp b/extra/yassl/mySTL/algorithm.hpp new file mode 100644 index 00000000000..3ceb0ca5fdc --- /dev/null +++ b/extra/yassl/mySTL/algorithm.hpp @@ -0,0 +1,111 @@ +/* mySTL algorithm.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* mySTL algorithm implements max, min, for_each, swap, find_if, copy, + * copy_backward, fill + */ + +#ifndef mySTL_ALGORITHM_HPP +#define mySTL_ALGORITHM_HPP + + +namespace mySTL { + + +template<typename T> +inline const T& max(const T& a, const T&b) +{ + return a < b ? b : a; +} + + +template<typename T> +inline const T& min(const T& a, const T&b) +{ + return b < a ? b : a; +} + + +template<typename InIter, typename Func> +Func for_each(InIter first, InIter last, Func op) +{ + while (first != last) { + op(*first); + ++first; + } + return op; +} + + +template<typename T> +inline void swap(T& a, T& b) +{ + T tmp = a; + a = b; + b = tmp; +} + + +template<typename InIter, typename Pred> +InIter find_if(InIter first, InIter last, Pred pred) +{ + while (first != last && !pred(*first)) + ++first; + return first; +} + + +template<typename InputIter, typename OutputIter> +inline OutputIter copy(InputIter first, InputIter last, OutputIter place) +{ + while (first != last) { + *place = *first; + ++first; + ++place; + } + return place; +} + + +template<typename InputIter, typename OutputIter> +inline OutputIter +copy_backward(InputIter first, InputIter last, OutputIter place) +{ + while (first != last) + *--place = *--last; + return place; +} + + +template<typename InputIter, typename T> +void fill(InputIter first, InputIter last, const T& v) +{ + while (first != last) { + *first = v; + ++first; + } +} + + +} // namespace mySTL + +#endif // mySTL_ALGORITHM_HPP diff --git a/extra/yassl/mySTL/helpers.hpp b/extra/yassl/mySTL/helpers.hpp new file mode 100644 index 00000000000..1b62d60cd2e --- /dev/null +++ b/extra/yassl/mySTL/helpers.hpp @@ -0,0 +1,94 @@ +/* mySTL helpers.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* mySTL helpers implements misc constructs for vector and list + * + */ + +#ifndef mySTL_HELPERS_HPP +#define mySTL_HELPERS_HPP + +#include <cstdlib> + + +namespace mySTL { + + +template <typename T, typename T2> +inline void construct(T* p, const T2& value) +{ + new (static_cast<void*>(p)) T(value); +} + + +template <typename T> +inline void construct(T* p) +{ + new (static_cast<void*>(p)) T(); +} + + +template <typename T> +inline void destroy(T* p) +{ + p->~T(); +} + + +template <typename Iter> +void destroy(Iter first, Iter last) +{ + while (first != last) { + destroy(&*first); + ++first; + } +} + + +template <typename Iter, typename PlaceIter> +PlaceIter uninit_copy(Iter first, Iter last, PlaceIter place) +{ + while (first != last) { + construct(&*place, *first); + ++first; + ++place; + } + return place; +} + + +template <typename PlaceIter, typename Size, typename T> +PlaceIter uninit_fill_n(PlaceIter place, Size n, const T& value) +{ + while (n) { + construct(&*place, value); + --n; + ++place; + } + return place; +} + + + +} // namespace mySTL + +#endif // mySTL_HELPERS_HPP diff --git a/extra/yassl/mySTL/list.hpp b/extra/yassl/mySTL/list.hpp new file mode 100644 index 00000000000..5bbec6ab7c6 --- /dev/null +++ b/extra/yassl/mySTL/list.hpp @@ -0,0 +1,374 @@ +/* mySTL list.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* mySTL list implements a simple list + * + */ + +#ifndef mySTL_LIST_HPP +#define mySTL_LIST_HPP + + +#include "helpers.hpp" +#include <new> // ::operator new and delete, placement too + + +namespace mySTL { + + + +template<typename T> +class list { + struct node { + node(T t) : prev_(0), next_(0), value_(t) {} + + node* prev_; + node* next_; + T value_; + }; +public: + list() : head_(0), tail_(0), sz_(0) {} + ~list(); + + void push_front(T); + void pop_front(); + T front() const; + void push_back(T); + void pop_back(); + T back() const; + bool remove(T); + size_t size() const { return sz_; } + bool empty() const { return sz_ == 0; } + + class iterator { + node* current_; + public: + iterator() : current_(0) {} + explicit iterator(node* p) : current_(p) {} + + T& operator*() const + { + return current_->value_; + } + + T* operator->() const + { + return &(operator*()); + } + + iterator& operator++() + { + current_ = current_->next_; + return *this; + } + + iterator& operator--() + { + current_ = current_->prev_; + return *this; + } + + iterator& operator++(int) + { + iterator tmp = *this; + current_ = current_->next_; + return *this; + } + + iterator& operator--(int) + { + iterator tmp = *this; + current_ = current_->prev_; + return *this; + } + + bool operator==(const iterator& other) const + { + return current_ == other.current_; + } + + bool operator!=(const iterator& other) const + { + return current_ != other.current_; + } + + friend class list<T>; + }; + + bool erase(iterator); + + iterator begin() const { return iterator(head_); } + iterator rbegin() const { return iterator(tail_); } + iterator end() const { return iterator(); } + + typedef iterator const_iterator; // for now + + class underflow {}; + class overflow {}; +private: + node* head_; + node* tail_; + size_t sz_; + + node* look_up(T); + + list(const list&); // hide copy + list& operator=(const list&); // and assign +}; + + +template<typename T> +list<T>::~list() +{ + node* start = head_; + node* next_; + + for (; start; start = next_) { + next_ = start->next_; + destroy(start); + ::operator delete(start); + } +} + + +template<typename T> +void list<T>::push_front(T t) +{ + void* mem = ::operator new(sizeof(node)); + if (!mem) abort(); + node* add = new (mem) node(t); + + if (head_) { + add->next_ = head_; + head_->prev_ = add; + } + else + tail_ = add; + + head_ = add; + ++sz_; +} + + +template<typename T> +void list<T>::pop_front() +{ + node* front = head_; + + if (head_ == 0) + return; + else if (head_ == tail_) + head_ = tail_ = 0; + else { + head_ = head_->next_; + head_->prev_ = 0; + } + destroy(front); + ::operator delete(front); + --sz_; +} + + +template<typename T> +T list<T>::front() const +{ + if (head_ == 0) return 0; + return head_->value_; +} + + +template<typename T> +void list<T>::push_back(T t) +{ + void* mem = ::operator new(sizeof(node)); + if (!mem) abort(); + node* add = new (mem) node(t); + + if (tail_) { + tail_->next_ = add; + add->prev_ = tail_; + } + else + head_ = add; + + tail_ = add; + ++sz_; +} + + +template<typename T> +void list<T>::pop_back() +{ + node* rear = tail_; + + if (tail_ == 0) + return; + else if (tail_ == head_) + tail_ = head_ = 0; + else { + tail_ = tail_->prev_; + tail_->next_ = 0; + } + destroy(rear); + ::operator delete(rear); + --sz_; +} + + +template<typename T> +T list<T>::back() const +{ + if (tail_ == 0) return 0; + return tail_->value_; +} + + +template<typename T> +typename list<T>::node* list<T>::look_up(T t) +{ + node* list = head_; + + if (list == 0) return 0; + + for (; list; list = list->next_) + if (list->value_ == t) + return list; + + return 0; +} + + +template<typename T> +bool list<T>::remove(T t) +{ + node* del = look_up(t); + + if (del == 0) + return false; + else if (del == head_) + pop_front(); + else if (del == tail_) + pop_back(); + else { + del->prev_->next_ = del->next_; + del->next_->prev_ = del->prev_; + + destroy(del); + ::operator delete(del); + --sz_; + } + return true; +} + + +template<typename T> +bool list<T>::erase(iterator iter) +{ + node* del = iter.current_; + + if (del == 0) + return false; + else if (del == head_) + pop_front(); + else if (del == tail_) + pop_back(); + else { + del->prev_->next_ = del->next_; + del->next_->prev_ = del->prev_; + + destroy(del); + ::operator delete(del); + --sz_; + } + return true; +} + + +/* MSVC can't handle ?? + +template<typename T> +T& list<T>::iterator::operator*() const +{ + return current_->value_; +} + + +template<typename T> +T* list<T>::iterator::operator->() const +{ + return &(operator*()); +} + + +template<typename T> +typename list<T>::iterator& list<T>::iterator::operator++() +{ + current_ = current_->next_; + return *this; +} + + +template<typename T> +typename list<T>::iterator& list<T>::iterator::operator--() +{ + current_ = current_->prev_; + return *this; +} + + +template<typename T> +typename list<T>::iterator& list<T>::iterator::operator++(int) +{ + iterator tmp = *this; + current_ = current_->next_; + return tmp; +} + + +template<typename T> +typename list<T>::iterator& list<T>::iterator::operator--(int) +{ + iterator tmp = *this; + current_ = current_->prev_; + return tmp; +} + + +template<typename T> +bool list<T>::iterator::operator==(const iterator& other) const +{ + return current_ == other.current_; +} + + +template<typename T> +bool list<T>::iterator::operator!=(const iterator& other) const +{ + return current_ != other.current_; +} +*/ // end MSVC 6 can't handle + + + +} // namespace mySTL + +#endif // mySTL_LIST_HPP diff --git a/extra/yassl/mySTL/memory.hpp b/extra/yassl/mySTL/memory.hpp new file mode 100644 index 00000000000..4049ed80813 --- /dev/null +++ b/extra/yassl/mySTL/memory.hpp @@ -0,0 +1,127 @@ +/* mySTL memory.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* mySTL memory implements auto_ptr + * + */ + +#ifndef mySTL_MEMORY_HPP +#define mySTL_MEMORY_HPP + + +#ifdef _MSC_VER + // disable operator-> warning for builtins + #pragma warning(disable:4284) +#endif + + +namespace mySTL { + + +template<typename T> +struct auto_ptr_ref { + T* ptr_; + explicit auto_ptr_ref(T* p) : ptr_(p) {} +}; + + +template<typename T> +class auto_ptr { + T* ptr_; +public: + explicit auto_ptr(T* p = 0) : ptr_(p) {} + ~auto_ptr() + { + delete ptr_; + } + + + auto_ptr(auto_ptr& other) : ptr_(other.release()) {} + auto_ptr& operator=(auto_ptr& that) + { + if (this != &that) { + delete ptr_; + ptr_ = that.release(); + } + return *this; + } + + + T* operator->() const + { + return ptr_; + } + + T& operator*() const + { + return *ptr_; + } + + T* get() const + { + return ptr_; + } + + T* release() + { + T* tmp = ptr_; + ptr_ = 0; + return tmp; + } + + void reset(T* p = 0) + { + if (ptr_ != p) { + delete ptr_; + ptr_ = p; + } + } + + // auto_ptr_ref conversions + auto_ptr(auto_ptr_ref<T> ref) : ptr_(ref.ptr_) {} + + auto_ptr& operator=(auto_ptr_ref<T> ref) + { + if (this->ptr_ != ref.ptr_) { + delete ptr_; + ptr_ = ref.ptr_; + } + return *this; + } + + template<typename T2> + operator auto_ptr<T2>() + { + return auto_ptr<T2>(this->release()); + } + + template<typename T2> + operator auto_ptr_ref<T2>() + { + return auto_ptr_ref<T2>(this->release()); + } +}; + + +} // namespace mySTL + +#endif // mySTL_MEMORY_HPP diff --git a/extra/yassl/mySTL/pair.hpp b/extra/yassl/mySTL/pair.hpp new file mode 100644 index 00000000000..c9bb03b5953 --- /dev/null +++ b/extra/yassl/mySTL/pair.hpp @@ -0,0 +1,61 @@ +/* mySTL pair.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* mySTL pair implements pair + * + */ + +#ifndef mySTL_PAIR_HPP +#define mySTL_PAIR_HPP + + + +namespace mySTL { + + +template<typename T1, typename T2> +struct pair { + typedef T1 first_type; + typedef T2 second_type; + + first_type first; + second_type second; + + pair() {} + pair(const T1& t1, const T2& t2) : first(t1), second(t2) {} + + template<typename U1, typename U2> + pair(const pair<U1, U2>& p) : first(p.first), second(p.second) {} +}; + + +template<typename T1, typename T2> +inline pair<T1, T2> make_pair(const T1& a, const T2& b) +{ + return pair<T1, T2>(a, b); +} + + + +} // namespace mySTL + +#endif // mySTL_PAIR_HPP diff --git a/extra/yassl/mySTL/stdexcept.hpp b/extra/yassl/mySTL/stdexcept.hpp new file mode 100644 index 00000000000..817861438a5 --- /dev/null +++ b/extra/yassl/mySTL/stdexcept.hpp @@ -0,0 +1,72 @@ +/* mySTL stdexcept.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* mySTL memory implements exception, runtime_error + * + */ + +#ifndef mySTL_STDEXCEPT_HPP +#define mySTL_STDEXCEPT_HPP + + +#include <cstring> // strncpy + + +namespace mySTL { + + +class exception { +public: + exception() {} + virtual ~exception() {} + + virtual const char* what() const { return ""; } +}; + + +class named_exception : public exception { +public: + enum { NAME_SIZE = 80 }; + + explicit named_exception(const char* str) + { + strncpy(name_, str, NAME_SIZE); + name_[NAME_SIZE - 1] = 0; + } + + virtual const char* what() const { return name_; } +private: + char name_[NAME_SIZE]; +}; + + +class runtime_error : public named_exception { +public: + explicit runtime_error(const char* str) : named_exception(str) {} +}; + + + + +} // namespace mySTL + +#endif // mySTL_STDEXCEPT_HPP diff --git a/extra/yassl/mySTL/vector.hpp b/extra/yassl/mySTL/vector.hpp new file mode 100644 index 00000000000..7f1f99295e4 --- /dev/null +++ b/extra/yassl/mySTL/vector.hpp @@ -0,0 +1,154 @@ +/* mySTL vector.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* mySTL vector implements simple vector, w/ swap + * + */ + +#ifndef mySTL_VECTOR_HPP +#define mySTL_VECTOR_HPP + + +#include "helpers.hpp" // construct, destory, fill, etc. +#include "algorithm.hpp" // swap +#include <new> // ::operator new and delete, placement too +#include <cassert> // assert + + +namespace mySTL { + + +template <typename T> +struct vector_base { + T* start_; + T* finish_; + T* end_of_storage_; + + vector_base() : start_(0), finish_(0), end_of_storage_(0) {} + vector_base(size_t n) + { + start_ = static_cast<T*>(::operator new(n * sizeof(T))); + if (!start_) abort(); + finish_ = start_; + end_of_storage_ = start_ + n; + } + + ~vector_base() { ::operator delete(start_); } + + void Swap(vector_base& that) + { + swap(start_, that.start_); + swap(finish_, that.finish_); + swap(end_of_storage_, that.end_of_storage_); + } +}; + + + +template <typename T> +class vector { +public: + vector() {} + explicit vector(size_t n) : vec_(n) + { + vec_.finish_ = uninit_fill_n(vec_.start_, n, T()); + } + + ~vector() { destroy(vec_.start_, vec_.finish_); } + + vector(const vector& other) : vec_(other.size()) + { + vec_.finish_ = uninit_copy(other.vec_.start_, other.vec_.finish_, + vec_.start_); + } + + size_t capacity() const { return vec_.end_of_storage_ - vec_.start_; } + + size_t size() const { return vec_.finish_ - vec_.start_; } + + T& operator[](size_t idx) { return *(vec_.start_ + idx); } + const T& operator[](size_t idx) const { return *(vec_.start_ + idx); } + + const T* begin() const { return vec_.start_; } + const T* end() const { return vec_.finish_; } + + void push_back(const T& v) + { + if (vec_.finish_ != vec_.end_of_storage_) { + construct(vec_.finish_, v); + ++vec_.finish_; + } + else { + vector tmp(size() * 2 + 1, *this); + construct(tmp.vec_.finish_, v); + ++tmp.vec_.finish_; + Swap(tmp); + } + } + + void resize(size_t n, const T& v) + { + if (n == size()) return; + + if (n < size()) { + T* first = vec_.start_ + n; + destroy(first, vec_.finish_); + vec_.finish_ -= vec_.finish_ - first; + } + else { + vector tmp(n, *this); + tmp.vec_.finish_ = uninit_fill_n(tmp.vec_.finish_, n - size(), v); + Swap(tmp); + } + } + + void reserve(size_t n) + { + if (capacity() < n) { + vector tmp(n, *this); + Swap(tmp); + } + } + + void Swap(vector& that) + { + vec_.Swap(that.vec_); + } +private: + vector_base<T> vec_; + + vector& operator=(const vector&); // hide assign + + // for growing, n must be bigger than other size + vector(size_t n, const vector& other) : vec_(n) + { + assert(n > other.size()); + vec_.finish_ = uninit_copy(other.vec_.start_, other.vec_.finish_, + vec_.start_); + } +}; + + + +} // namespace mySTL + +#endif // mySTL_VECTOR_HPP diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am new file mode 100644 index 00000000000..9dd8a09b00b --- /dev/null +++ b/extra/yassl/src/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I../include -I../taocrypt/include -I../mySTL + +noinst_LIBRARIES = libyassl.a +libyassl_a_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \ + handshake.cpp lock.cpp log.cpp socket_wrapper.cpp ssl.cpp \ + timer.cpp yassl_imp.cpp yassl_error.cpp yassl_int.cpp +EXTRA_DIST = ../include/*.hpp ../include/openssl/*.h +AM_CXXFLAGS=@USE_MYSYS_NEW@ diff --git a/extra/yassl/src/buffer.cpp b/extra/yassl/src/buffer.cpp new file mode 100644 index 00000000000..c97103c6f6d --- /dev/null +++ b/extra/yassl/src/buffer.cpp @@ -0,0 +1,280 @@ +/* buffer.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* yaSSL buffer header implements input/output buffers to simulate streaming + * with SSL types and sockets + */ + +#include "runtime.hpp" +#include "buffer.hpp" +#include "yassl_types.hpp" + +namespace yaSSL { + + + +// Checking Policy should implement a check function that tests whether the +// index is within the size limit of the array + +void Check::check(uint i, uint limit) +{ + assert(i < limit); +} + + +void NoCheck::check(uint, uint) +{ +} + + +/* input_buffer operates like a smart c style array with a checking option, + * meant to be read from through [] with AUTO index or read(). + * Should only write to at/near construction with assign() or raw (e.g., recv) + * followed by add_size with the number of elements added by raw write. + * + * Not using vector because need checked []access, offset, and the ability to + * write to the buffer bulk wise and have the correct size + */ + + +input_buffer::input_buffer() + : size_(0), current_(0), buffer_(0), end_(0) +{} + + +input_buffer::input_buffer(uint s) + : size_(0), current_(0), buffer_(new (ys) byte[s]), end_(buffer_ + s) +{} + + +// with assign +input_buffer::input_buffer(uint s, const byte* t, uint len) + : size_(0), current_(0), buffer_(new (ys) byte[s]), end_(buffer_ + s) +{ + assign(t, len); +} + + +input_buffer::~input_buffer() +{ + delete [] buffer_; +} + + +// users can pass defualt zero length buffer and then allocate +void input_buffer::allocate(uint s) +{ + assert(!buffer_); // find realloc error + buffer_ = new (ys) byte[s]; + end_ = buffer_ + s; +} + + +// for passing to raw writing functions at beginning, then use add_size +byte* input_buffer::get_buffer() const +{ + return buffer_; +} + + +// after a raw write user can set new size +// if you know the size before the write use assign() +void input_buffer::add_size(uint i) +{ + check(size_ + i-1, get_capacity()); + size_ += i; +} + + +uint input_buffer::get_capacity() const +{ + return end_ - buffer_; +} + + +uint input_buffer::get_current() const +{ + return current_; +} + + +uint input_buffer::get_size() const +{ + return size_; +} + + +uint input_buffer::get_remaining() const +{ + return size_ - current_; +} + + +void input_buffer::set_current(uint i) +{ + if (i) + check(i - 1, size_); + current_ = i; +} + + +// read only access through [], advance current +// user passes in AUTO index for ease of use +const byte& input_buffer::operator[](uint i) +{ + assert (i == AUTO); + check(current_, size_); + return buffer_[current_++]; +} + + +// end of input test +bool input_buffer::eof() +{ + return current_ >= size_; +} + + +// peek ahead +byte input_buffer::peek() const +{ + return buffer_[current_]; +} + + +// write function, should use at/near construction +void input_buffer::assign(const byte* t, uint s) +{ + check(current_, get_capacity()); + add_size(s); + memcpy(&buffer_[current_], t, s); +} + + +// use read to query input, adjusts current +void input_buffer::read(byte* dst, uint length) +{ + check(current_ + length - 1, size_); + memcpy(dst, &buffer_[current_], length); + current_ += length; +} + + + +/* output_buffer operates like a smart c style array with a checking option. + * Meant to be written to through [] with AUTO index or write(). + * Size (current) counter increases when written to. Can be constructed with + * zero length buffer but be sure to allocate before first use. + * Don't use add write for a couple bytes, use [] instead, way less overhead. + * + * Not using vector because need checked []access and the ability to + * write to the buffer bulk wise and retain correct size + */ + + +output_buffer::output_buffer() + : current_(0), buffer_(0), end_(0) +{} + + +// with allocate +output_buffer::output_buffer(uint s) + : current_(0), buffer_(new (ys) byte[s]), end_(buffer_ + s) +{} + + +// with assign +output_buffer::output_buffer(uint s, const byte* t, uint len) + : current_(0), buffer_(new (ys) byte[s]), end_(buffer_+ s) +{ + write(t, len); +} + + +output_buffer::~output_buffer() +{ + delete [] buffer_; +} + + +uint output_buffer::get_size() const +{ + return current_; +} + + +uint output_buffer::get_capacity() const +{ + return end_ - buffer_; +} + + +void output_buffer::set_current(uint c) +{ + check(c, get_capacity()); + current_ = c; +} + + +// users can pass defualt zero length buffer and then allocate +void output_buffer::allocate(uint s) +{ + assert(!buffer_); // find realloc error + buffer_ = new (ys) byte[s]; end_ = buffer_ + s; +} + + +// for passing to reading functions when finished +const byte* output_buffer::get_buffer() const +{ + return buffer_; +} + + +// allow write access through [], update current +// user passes in AUTO as index for ease of use +byte& output_buffer::operator[](uint i) +{ + assert(i == AUTO); + check(current_, get_capacity()); + return buffer_[current_++]; +} + + +// end of output test +bool output_buffer::eof() +{ + return current_ >= get_capacity(); +} + + +void output_buffer::write(const byte* t, uint s) +{ + check(current_ + s - 1, get_capacity()); + memcpy(&buffer_[current_], t, s); + current_ += s; +} + + + +} // naemspace + diff --git a/extra/yassl/src/cert_wrapper.cpp b/extra/yassl/src/cert_wrapper.cpp new file mode 100644 index 00000000000..ab3cb471990 --- /dev/null +++ b/extra/yassl/src/cert_wrapper.cpp @@ -0,0 +1,318 @@ +/* cert_wrapper.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* The certificate wrapper source implements certificate management functions + * + */ + +#include "runtime.hpp" +#include "cert_wrapper.hpp" +#include "yassl_int.hpp" + +#if defined(USE_CML_LIB) + #include "cmapi_cpp.h" +#else + #include "asn.hpp" + #include "file.hpp" +#endif // USE_CML_LIB + + +namespace yaSSL { + + +x509::x509(uint sz) : length_(sz), buffer_(new (ys) opaque[sz]) +{ +} + + +x509::~x509() +{ + delete [] buffer_; +} + + +x509::x509(const x509& that) : length_(that.length_), + buffer_(new (ys) opaque[length_]) +{ + memcpy(buffer_, that.buffer_, length_); +} + + +void x509::Swap(x509& that) +{ + mySTL::swap(length_, that.length_); + mySTL::swap(buffer_, that.buffer_); +} + + +x509& x509::operator=(const x509& that) +{ + x509 temp(that); + Swap(temp); + return *this; +} + + +uint x509::get_length() const +{ + return length_; +} + + +const opaque* x509::get_buffer() const +{ + return buffer_; +} + + +opaque* x509::use_buffer() +{ + return buffer_; +} + + +//CertManager +CertManager::CertManager() + : peerX509_(0), verifyPeer_(false), failNoCert_(false), sendVerify_(false) +{} + + +CertManager::~CertManager() +{ + delete peerX509_; + + mySTL::for_each(signers_.begin(), signers_.end(), del_ptr_zero()) ; + + mySTL::for_each(peerList_.begin(), peerList_.end(), del_ptr_zero()) ; + + mySTL::for_each(list_.begin(), list_.end(), del_ptr_zero()) ; +} + + +bool CertManager::verifyPeer() const +{ + return verifyPeer_; +} + + +bool CertManager::failNoCert() const +{ + return failNoCert_; +} + + +bool CertManager::sendVerify() const +{ + return sendVerify_; +} + + +void CertManager::setVerifyPeer() +{ + verifyPeer_ = true; +} + + +void CertManager::setFailNoCert() +{ + failNoCert_ = true; +} + + +void CertManager::setSendVerify() +{ + sendVerify_ = true; +} + + +void CertManager::AddPeerCert(x509* x) +{ + peerList_.push_back(x); // take ownership +} + + +void CertManager::CopySelfCert(const x509* x) +{ + if (x) + list_.push_back(new (ys) x509(*x)); +} + + +// add to signers +int CertManager::CopyCaCert(const x509* x) +{ + TaoCrypt::Source source(x->get_buffer(), x->get_length()); + TaoCrypt::CertDecoder cert(source, true, &signers_); + + if (!cert.GetError().What()) { + const TaoCrypt::PublicKey& key = cert.GetPublicKey(); + signers_.push_back(new (ys) TaoCrypt::Signer(key.GetKey(), key.size(), + cert.GetCommonName(), cert.GetHash())); + } + return cert.GetError().What(); +} + + +const x509* CertManager::get_cert() const +{ + return list_.front(); +} + + +const opaque* CertManager::get_peerKey() const +{ + return peerPublicKey_.get_buffer(); +} + + +X509* CertManager::get_peerX509() const +{ + return peerX509_; +} + + +SignatureAlgorithm CertManager::get_peerKeyType() const +{ + return peerKeyType_; +} + + +SignatureAlgorithm CertManager::get_keyType() const +{ + return keyType_; +} + + +uint CertManager::get_peerKeyLength() const +{ + return peerPublicKey_.get_size(); +} + + +const opaque* CertManager::get_privateKey() const +{ + return privateKey_.get_buffer(); +} + + +uint CertManager::get_privateKeyLength() const +{ + return privateKey_.get_size(); +} + + +// Validate the peer's certificate list, from root to peer (last to first) +int CertManager::Validate() +{ + CertList::iterator last = peerList_.rbegin(); // fix this + int count = peerList_.size(); + + while ( count > 1 ) { + TaoCrypt::Source source((*last)->get_buffer(), (*last)->get_length()); + TaoCrypt::CertDecoder cert(source, true, &signers_); + + if (int err = cert.GetError().What()) + return err; + + const TaoCrypt::PublicKey& key = cert.GetPublicKey(); + signers_.push_back(new (ys) TaoCrypt::Signer(key.GetKey(), key.size(), + cert.GetCommonName(), cert.GetHash())); + --last; + --count; + } + + if (count) { + // peer's is at the front + TaoCrypt::Source source((*last)->get_buffer(), (*last)->get_length()); + TaoCrypt::CertDecoder cert(source, true, &signers_); + + if (int err = cert.GetError().What()) + return err; + + uint sz = cert.GetPublicKey().size(); + peerPublicKey_.allocate(sz); + peerPublicKey_.assign(cert.GetPublicKey().GetKey(), sz); + + if (cert.GetKeyType() == TaoCrypt::RSAk) + peerKeyType_ = rsa_sa_algo; + else + peerKeyType_ = dsa_sa_algo; + + int iSz = cert.GetIssuer() ? strlen(cert.GetIssuer()) + 1 : 0; + int sSz = cert.GetCommonName() ? strlen(cert.GetCommonName()) + 1 : 0; + peerX509_ = new (ys) X509(cert.GetIssuer(), iSz, cert.GetCommonName(), + sSz); + } + return 0; +} + + +// Set the private key +int CertManager::SetPrivateKey(const x509& key) +{ + privateKey_.allocate(key.get_length()); + privateKey_.assign(key.get_buffer(), key.get_length()); + + // set key type + if (x509* cert = list_.front()) { + TaoCrypt::Source source(cert->get_buffer(), cert->get_length()); + TaoCrypt::CertDecoder cert(source, false); + cert.DecodeToKey(); + if (int err = cert.GetError().What()) + return err; + if (cert.GetKeyType() == TaoCrypt::RSAk) + keyType_ = rsa_sa_algo; + else + keyType_ = dsa_sa_algo; + } + return 0; +} + + +#if defined(USE_CML_LIB) + +// Get the peer's certificate, extract and save public key +void CertManager::SetPeerKey() +{ + // first cert is the peer's + x509* main = peerList_.front(); + + Bytes_struct cert; + cert.num = main->get_length(); + cert.data = main->set_buffer(); + + CML::Certificate cm(cert); + const CML::ASN::Cert& raw = cm.base(); + CTIL::CSM_Buffer key = raw.pubKeyInfo.key; + + uint sz; + opaque* key_buffer = reinterpret_cast<opaque*>(key.Get(sz)); + peerPublicKey_.allocate(sz); + peerPublicKey_.assign(key_buffer, sz); +} + + +#endif // USE_CML_LIB + + + +} // namespace diff --git a/extra/yassl/src/crypto_wrapper.cpp b/extra/yassl/src/crypto_wrapper.cpp new file mode 100644 index 00000000000..c083c56f313 --- /dev/null +++ b/extra/yassl/src/crypto_wrapper.cpp @@ -0,0 +1,978 @@ +/* crypto_wrapper.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* The crypto wrapper source implements the policies for the cipher + * components used by SSL. + * + * The implementation relies on a specfic library, taoCrypt. + */ + +#if !defined(USE_CRYPTOPP_LIB) + +#include "runtime.hpp" +#include "crypto_wrapper.hpp" +#include "cert_wrapper.hpp" + +#include "md5.hpp" +#include "sha.hpp" +#include "ripemd.hpp" +#include "hmac.hpp" +#include "modes.hpp" +#include "des.hpp" +#include "arc4.hpp" +#include "aes.hpp" +#include "rsa.hpp" +#include "dsa.hpp" +#include "dh.hpp" +#include "random.hpp" +#include "file.hpp" +#include "coding.hpp" + + +namespace yaSSL { + + +// MD5 Implementation +struct MD5::MD5Impl { + TaoCrypt::MD5 md5_; + MD5Impl() {} + explicit MD5Impl(const TaoCrypt::MD5& md5) : md5_(md5) {} +}; + + +MD5::MD5() : pimpl_(new (ys) MD5Impl) {} + + +MD5::~MD5() { delete pimpl_; } + + +MD5::MD5(const MD5& that) : Digest(), pimpl_(new (ys) + MD5Impl(that.pimpl_->md5_)) {} + + +MD5& MD5::operator=(const MD5& that) +{ + pimpl_->md5_ = that.pimpl_->md5_; + return *this; +} + + +uint MD5::get_digestSize() const +{ + return MD5_LEN; +} + + +uint MD5::get_padSize() const +{ + return PAD_MD5; +} + + +// Fill out with MD5 digest from in that is sz bytes, out must be >= digest sz +void MD5::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->md5_.Update(in, sz); + pimpl_->md5_.Final(out); +} + +// Fill out with MD5 digest from previous updates +void MD5::get_digest(byte* out) +{ + pimpl_->md5_.Final(out); +} + + +// Update the current digest +void MD5::update(const byte* in, unsigned int sz) +{ + pimpl_->md5_.Update(in, sz); +} + + +// SHA Implementation +struct SHA::SHAImpl { + TaoCrypt::SHA sha_; + SHAImpl() {} + explicit SHAImpl(const TaoCrypt::SHA& sha) : sha_(sha) {} +}; + + +SHA::SHA() : pimpl_(new (ys) SHAImpl) {} + + +SHA::~SHA() { delete pimpl_; } + + +SHA::SHA(const SHA& that) : Digest(), pimpl_(new (ys) + SHAImpl(that.pimpl_->sha_)) {} + +SHA& SHA::operator=(const SHA& that) +{ + pimpl_->sha_ = that.pimpl_->sha_; + return *this; +} + + +uint SHA::get_digestSize() const +{ + return SHA_LEN; +} + + +uint SHA::get_padSize() const +{ + return PAD_SHA; +} + + +// Fill out with SHA digest from in that is sz bytes, out must be >= digest sz +void SHA::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->sha_.Update(in, sz); + pimpl_->sha_.Final(out); +} + + +// Fill out with SHA digest from previous updates +void SHA::get_digest(byte* out) +{ + pimpl_->sha_.Final(out); +} + + +// Update the current digest +void SHA::update(const byte* in, unsigned int sz) +{ + pimpl_->sha_.Update(in, sz); +} + + +// RMD-160 Implementation +struct RMD::RMDImpl { + TaoCrypt::RIPEMD160 rmd_; + RMDImpl() {} + explicit RMDImpl(const TaoCrypt::RIPEMD160& rmd) : rmd_(rmd) {} +}; + + +RMD::RMD() : pimpl_(new (ys) RMDImpl) {} + + +RMD::~RMD() { delete pimpl_; } + + +RMD::RMD(const RMD& that) : Digest(), pimpl_(new (ys) + RMDImpl(that.pimpl_->rmd_)) {} + +RMD& RMD::operator=(const RMD& that) +{ + pimpl_->rmd_ = that.pimpl_->rmd_; + return *this; +} + + +uint RMD::get_digestSize() const +{ + return RMD_LEN; +} + + +uint RMD::get_padSize() const +{ + return PAD_RMD; +} + + +// Fill out with RMD digest from in that is sz bytes, out must be >= digest sz +void RMD::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->rmd_.Update(in, sz); + pimpl_->rmd_.Final(out); +} + + +// Fill out with RMD digest from previous updates +void RMD::get_digest(byte* out) +{ + pimpl_->rmd_.Final(out); +} + + +// Update the current digest +void RMD::update(const byte* in, unsigned int sz) +{ + pimpl_->rmd_.Update(in, sz); +} + + +// HMAC_MD5 Implementation +struct HMAC_MD5::HMAC_MD5Impl { + TaoCrypt::HMAC<TaoCrypt::MD5> mac_; + HMAC_MD5Impl() {} +}; + + +HMAC_MD5::HMAC_MD5(const byte* secret, unsigned int len) + : pimpl_(new (ys) HMAC_MD5Impl) +{ + pimpl_->mac_.SetKey(secret, len); +} + + +HMAC_MD5::~HMAC_MD5() { delete pimpl_; } + + +uint HMAC_MD5::get_digestSize() const +{ + return MD5_LEN; +} + + +uint HMAC_MD5::get_padSize() const +{ + return PAD_MD5; +} + + +// Fill out with MD5 digest from in that is sz bytes, out must be >= digest sz +void HMAC_MD5::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); + pimpl_->mac_.Final(out); +} + +// Fill out with MD5 digest from previous updates +void HMAC_MD5::get_digest(byte* out) +{ + pimpl_->mac_.Final(out); +} + + +// Update the current digest +void HMAC_MD5::update(const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); +} + + +// HMAC_SHA Implementation +struct HMAC_SHA::HMAC_SHAImpl { + TaoCrypt::HMAC<TaoCrypt::SHA> mac_; + HMAC_SHAImpl() {} +}; + + +HMAC_SHA::HMAC_SHA(const byte* secret, unsigned int len) + : pimpl_(new (ys) HMAC_SHAImpl) +{ + pimpl_->mac_.SetKey(secret, len); +} + + +HMAC_SHA::~HMAC_SHA() { delete pimpl_; } + + +uint HMAC_SHA::get_digestSize() const +{ + return SHA_LEN; +} + + +uint HMAC_SHA::get_padSize() const +{ + return PAD_SHA; +} + + +// Fill out with SHA digest from in that is sz bytes, out must be >= digest sz +void HMAC_SHA::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); + pimpl_->mac_.Final(out); +} + +// Fill out with SHA digest from previous updates +void HMAC_SHA::get_digest(byte* out) +{ + pimpl_->mac_.Final(out); +} + + +// Update the current digest +void HMAC_SHA::update(const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); +} + + + +// HMAC_RMD Implementation +struct HMAC_RMD::HMAC_RMDImpl { + TaoCrypt::HMAC<TaoCrypt::RIPEMD160> mac_; + HMAC_RMDImpl() {} +}; + + +HMAC_RMD::HMAC_RMD(const byte* secret, unsigned int len) + : pimpl_(new (ys) HMAC_RMDImpl) +{ + pimpl_->mac_.SetKey(secret, len); +} + + +HMAC_RMD::~HMAC_RMD() { delete pimpl_; } + + +uint HMAC_RMD::get_digestSize() const +{ + return RMD_LEN; +} + + +uint HMAC_RMD::get_padSize() const +{ + return PAD_RMD; +} + + +// Fill out with RMD digest from in that is sz bytes, out must be >= digest sz +void HMAC_RMD::get_digest(byte* out, const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); + pimpl_->mac_.Final(out); +} + +// Fill out with RMD digest from previous updates +void HMAC_RMD::get_digest(byte* out) +{ + pimpl_->mac_.Final(out); +} + + +// Update the current digest +void HMAC_RMD::update(const byte* in, unsigned int sz) +{ + pimpl_->mac_.Update(in, sz); +} + + +struct DES::DESImpl { + TaoCrypt::DES_CBC_Encryption encryption; + TaoCrypt::DES_CBC_Decryption decryption; +}; + + +DES::DES() : pimpl_(new (ys) DESImpl) {} + +DES::~DES() { delete pimpl_; } + + +void DES::set_encryptKey(const byte* k, const byte* iv) +{ + pimpl_->encryption.SetKey(k, DES_KEY_SZ, iv); +} + + +void DES::set_decryptKey(const byte* k, const byte* iv) +{ + pimpl_->decryption.SetKey(k, DES_KEY_SZ, iv); +} + +// DES encrypt plain of length sz into cipher +void DES::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// DES decrypt cipher of length sz into plain +void DES::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + +struct DES_EDE::DES_EDEImpl { + TaoCrypt::DES_EDE3_CBC_Encryption encryption; + TaoCrypt::DES_EDE3_CBC_Decryption decryption; +}; + + +DES_EDE::DES_EDE() : pimpl_(new (ys) DES_EDEImpl) {} + +DES_EDE::~DES_EDE() { delete pimpl_; } + + +void DES_EDE::set_encryptKey(const byte* k, const byte* iv) +{ + pimpl_->encryption.SetKey(k, DES_EDE_KEY_SZ, iv); +} + + +void DES_EDE::set_decryptKey(const byte* k, const byte* iv) +{ + pimpl_->decryption.SetKey(k, DES_EDE_KEY_SZ, iv); +} + + +// 3DES encrypt plain of length sz into cipher +void DES_EDE::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// 3DES decrypt cipher of length sz into plain +void DES_EDE::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + +// Implementation of alledged RC4 +struct RC4::RC4Impl { + TaoCrypt::ARC4::Encryption encryption; + TaoCrypt::ARC4::Decryption decryption; +}; + + +RC4::RC4() : pimpl_(new (ys) RC4Impl) {} + +RC4::~RC4() { delete pimpl_; } + + +void RC4::set_encryptKey(const byte* k, const byte*) +{ + pimpl_->encryption.SetKey(k, RC4_KEY_SZ); +} + + +void RC4::set_decryptKey(const byte* k, const byte*) +{ + pimpl_->decryption.SetKey(k, RC4_KEY_SZ); +} + + +// RC4 encrypt plain of length sz into cipher +void RC4::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// RC4 decrypt cipher of length sz into plain +void RC4::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + + +// Implementation of AES +struct AES::AESImpl { + TaoCrypt::AES_CBC_Encryption encryption; + TaoCrypt::AES_CBC_Decryption decryption; + unsigned int keySz_; + + AESImpl(unsigned int ks) : keySz_(ks) {} +}; + + +AES::AES(unsigned int ks) : pimpl_(new (ys) AESImpl(ks)) {} + +AES::~AES() { delete pimpl_; } + + +int AES::get_keySize() const +{ + return pimpl_->keySz_; +} + + +void AES::set_encryptKey(const byte* k, const byte* iv) +{ + pimpl_->encryption.SetKey(k, pimpl_->keySz_, iv); +} + + +void AES::set_decryptKey(const byte* k, const byte* iv) +{ + pimpl_->decryption.SetKey(k, pimpl_->keySz_, iv); +} + + +// AES encrypt plain of length sz into cipher +void AES::encrypt(byte* cipher, const byte* plain, unsigned int sz) +{ + pimpl_->encryption.Process(cipher, plain, sz); +} + + +// AES decrypt cipher of length sz into plain +void AES::decrypt(byte* plain, const byte* cipher, unsigned int sz) +{ + pimpl_->decryption.Process(plain, cipher, sz); +} + + +struct RandomPool::RandomImpl { + TaoCrypt::RandomNumberGenerator RNG_; +}; + +RandomPool::RandomPool() : pimpl_(new (ys) RandomImpl) {} + +RandomPool::~RandomPool() { delete pimpl_; } + +int RandomPool::GetError() const +{ + return pimpl_->RNG_.GetError(); +} + +void RandomPool::Fill(opaque* dst, uint sz) const +{ + pimpl_->RNG_.GenerateBlock(dst, sz); +} + + +// Implementation of DSS Authentication +struct DSS::DSSImpl { + void SetPublic (const byte*, unsigned int); + void SetPrivate(const byte*, unsigned int); + TaoCrypt::DSA_PublicKey publicKey_; + TaoCrypt::DSA_PrivateKey privateKey_; +}; + + +// Decode and store the public key +void DSS::DSSImpl::SetPublic(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + publicKey_.Initialize(source); +} + + +// Decode and store the public key +void DSS::DSSImpl::SetPrivate(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + privateKey_.Initialize(source); + publicKey_ = TaoCrypt::DSA_PublicKey(privateKey_); + +} + + +// Set public or private key +DSS::DSS(const byte* key, unsigned int sz, bool publicKey) + : pimpl_(new (ys) DSSImpl) +{ + if (publicKey) + pimpl_->SetPublic(key, sz); + else + pimpl_->SetPrivate(key, sz); +} + + +DSS::~DSS() +{ + delete pimpl_; +} + + +uint DSS::get_signatureLength() const +{ + return pimpl_->publicKey_.SignatureLength(); +} + + +// DSS Sign message of length sz into sig +void DSS::sign(byte* sig, const byte* sha_digest, unsigned int /* shaSz */, + const RandomPool& random) +{ + using namespace TaoCrypt; + + DSA_Signer signer(pimpl_->privateKey_); + signer.Sign(sha_digest, sig, random.pimpl_->RNG_); +} + + +// DSS Verify message of length sz against sig, is it correct? +bool DSS::verify(const byte* sha_digest, unsigned int /* shaSz */, + const byte* sig, unsigned int /* sigSz */) +{ + using namespace TaoCrypt; + + DSA_Verifier ver(pimpl_->publicKey_); + return ver.Verify(sha_digest, sig); +} + + +// Implementation of RSA key interface +struct RSA::RSAImpl { + void SetPublic (const byte*, unsigned int); + void SetPrivate(const byte*, unsigned int); + TaoCrypt::RSA_PublicKey publicKey_; + TaoCrypt::RSA_PrivateKey privateKey_; +}; + + +// Decode and store the public key +void RSA::RSAImpl::SetPublic(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + publicKey_.Initialize(source); +} + + +// Decode and store the private key +void RSA::RSAImpl::SetPrivate(const byte* key, unsigned int sz) +{ + TaoCrypt::Source source(key, sz); + privateKey_.Initialize(source); + publicKey_ = TaoCrypt::RSA_PublicKey(privateKey_); +} + + +// Set public or private key +RSA::RSA(const byte* key, unsigned int sz, bool publicKey) + : pimpl_(new (ys) RSAImpl) +{ + if (publicKey) + pimpl_->SetPublic(key, sz); + else + pimpl_->SetPrivate(key, sz); +} + +RSA::~RSA() +{ + delete pimpl_; +} + + +// get cipher text length, varies on key size +unsigned int RSA::get_cipherLength() const +{ + return pimpl_->publicKey_.FixedCiphertextLength(); +} + + +// get signautre length, varies on key size +unsigned int RSA::get_signatureLength() const +{ + return get_cipherLength(); +} + + +// RSA Sign message of length sz into sig +void RSA::sign(byte* sig, const byte* message, unsigned int sz, + const RandomPool& random) +{ + TaoCrypt::RSAES_Decryptor dec(pimpl_->privateKey_); + dec.SSL_Sign(message, sz, sig, random.pimpl_->RNG_); +} + + +// RSA Verify message of length sz against sig +bool RSA::verify(const byte* message, unsigned int sz, const byte* sig, + unsigned int) +{ + TaoCrypt::RSAES_Encryptor enc(pimpl_->publicKey_); + return enc.SSL_Verify(message, sz, sig); +} + + +// RSA public encrypt plain of length sz into cipher +void RSA::encrypt(byte* cipher, const byte* plain, unsigned int sz, + const RandomPool& random) +{ + + TaoCrypt::RSAES_Encryptor enc(pimpl_->publicKey_); + enc.Encrypt(plain, sz, cipher, random.pimpl_->RNG_); +} + + +// RSA private decrypt cipher of length sz into plain +void RSA::decrypt(byte* plain, const byte* cipher, unsigned int sz, + const RandomPool& random) +{ + TaoCrypt::RSAES_Decryptor dec(pimpl_->privateKey_); + dec.Decrypt(cipher, sz, plain, random.pimpl_->RNG_); +} + + +struct Integer::IntegerImpl { + TaoCrypt::Integer int_; + + IntegerImpl() {} + explicit IntegerImpl(const TaoCrypt::Integer& i) : int_(i) {} +}; + +Integer::Integer() : pimpl_(new (ys) IntegerImpl) {} + +Integer::~Integer() { delete pimpl_; } + + + +Integer::Integer(const Integer& other) : pimpl_(new (ys) + IntegerImpl(other.pimpl_->int_)) +{} + + +Integer& Integer::operator=(const Integer& that) +{ + pimpl_->int_ = that.pimpl_->int_; + + return *this; +} + + +void Integer::assign(const byte* num, unsigned int sz) +{ + pimpl_->int_ = TaoCrypt::Integer(num, sz); +} + + +struct DiffieHellman::DHImpl { + TaoCrypt::DH dh_; + TaoCrypt::RandomNumberGenerator& ranPool_; + byte* publicKey_; + byte* privateKey_; + byte* agreedKey_; + + DHImpl(TaoCrypt::RandomNumberGenerator& r) : ranPool_(r), publicKey_(0), + privateKey_(0), agreedKey_(0) {} + ~DHImpl() {delete[] agreedKey_; delete[] privateKey_; delete[] publicKey_;} + + DHImpl(const DHImpl& that) : dh_(that.dh_), ranPool_(that.ranPool_), + publicKey_(0), privateKey_(0), agreedKey_(0) + { + uint length = dh_.GetByteLength(); + AllocKeys(length, length, length); + } + + void AllocKeys(unsigned int pubSz, unsigned int privSz, unsigned int agrSz) + { + publicKey_ = new (ys) byte[pubSz]; + privateKey_ = new (ys) byte[privSz]; + agreedKey_ = new (ys) byte[agrSz]; + } +}; + + + +/* +// server Side DH, server's view +DiffieHellman::DiffieHellman(const char* file, const RandomPool& random) + : pimpl_(new (ys) DHImpl(random.pimpl_->RNG_)) +{ + using namespace TaoCrypt; + Source source; + FileSource(file, source); + if (source.size() == 0) + return; // TODO add error state, and force check + HexDecoder hd(source); + + pimpl_->dh_.Initialize(source); + + uint length = pimpl_->dh_.GetByteLength(); + + pimpl_->AllocKeys(length, length, length); + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); +} +*/ + + +// server Side DH, client's view +DiffieHellman::DiffieHellman(const byte* p, unsigned int pSz, const byte* g, + unsigned int gSz, const byte* pub, + unsigned int pubSz, const RandomPool& random) + : pimpl_(new (ys) DHImpl(random.pimpl_->RNG_)) +{ + using TaoCrypt::Integer; + + pimpl_->dh_.Initialize(Integer(p, pSz).Ref(), Integer(g, gSz).Ref()); + pimpl_->publicKey_ = new (ys) opaque[pubSz]; + memcpy(pimpl_->publicKey_, pub, pubSz); +} + + +// Server Side DH, server's view +DiffieHellman::DiffieHellman(const Integer& p, const Integer& g, + const RandomPool& random) +: pimpl_(new (ys) DHImpl(random.pimpl_->RNG_)) +{ + using TaoCrypt::Integer; + + pimpl_->dh_.Initialize(p.pimpl_->int_, g.pimpl_->int_); + + uint length = pimpl_->dh_.GetByteLength(); + + pimpl_->AllocKeys(length, length, length); + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); +} + +DiffieHellman::~DiffieHellman() { delete pimpl_; } + + +// Client side and view, use server that for p and g +DiffieHellman::DiffieHellman(const DiffieHellman& that) + : pimpl_(new (ys) DHImpl(*that.pimpl_)) +{ + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); +} + + +DiffieHellman& DiffieHellman::operator=(const DiffieHellman& that) +{ + pimpl_->dh_ = that.pimpl_->dh_; + pimpl_->dh_.GenerateKeyPair(pimpl_->ranPool_, pimpl_->privateKey_, + pimpl_->publicKey_); + return *this; +} + + +void DiffieHellman::makeAgreement(const byte* other) +{ + pimpl_->dh_.Agree(pimpl_->agreedKey_, pimpl_->privateKey_, other); +} + + +uint DiffieHellman::get_agreedKeyLength() const +{ + return pimpl_->dh_.GetByteLength(); +} + + +const byte* DiffieHellman::get_agreedKey() const +{ + return pimpl_->agreedKey_; +} + + +const byte* DiffieHellman::get_publicKey() const +{ + return pimpl_->publicKey_; +} + + +void DiffieHellman::set_sizes(int& pSz, int& gSz, int& pubSz) const +{ + using TaoCrypt::Integer; + Integer p = pimpl_->dh_.GetP(); + Integer g = pimpl_->dh_.GetG(); + + pSz = p.ByteCount(); + gSz = g.ByteCount(); + pubSz = pimpl_->dh_.GetByteLength(); +} + + +void DiffieHellman::get_parms(byte* bp, byte* bg, byte* bpub) const +{ + using TaoCrypt::Integer; + Integer p = pimpl_->dh_.GetP(); + Integer g = pimpl_->dh_.GetG(); + + p.Encode(bp, p.ByteCount()); + g.Encode(bg, g.ByteCount()); + memcpy(bpub, pimpl_->publicKey_, pimpl_->dh_.GetByteLength()); +} + + +// convert PEM file to DER x509 type +x509* PemToDer(const char* fname, CertType type) +{ + using namespace TaoCrypt; + + char header[80]; + char footer[80]; + + if (type == Cert) { + strncpy(header, "-----BEGIN CERTIFICATE-----", sizeof(header)); + strncpy(footer, "-----END CERTIFICATE-----", sizeof(footer)); + } else { + strncpy(header, "-----BEGIN RSA PRIVATE KEY-----", sizeof(header)); + strncpy(footer, "-----END RSA PRIVATE KEY-----", sizeof(header)); + } + + FILE* file = fopen(fname, "rb"); + if (!file) + return 0; + + long begin = -1; + long end = 0; + bool foundEnd = false; + + char line[80]; + + while(fgets(line, sizeof(line), file)) + if (strncmp(header, line, strlen(header)) == 0) { + begin = ftell(file); + break; + } + + while(fgets(line, sizeof(line), file)) + if (strncmp(footer, line, strlen(footer)) == 0) { + foundEnd = true; + break; + } + else + end = ftell(file); + + if (begin == -1 || !foundEnd) { + fclose(file); + return 0; + } + + input_buffer tmp(end - begin); + fseek(file, begin, SEEK_SET); + size_t bytes = fread(tmp.get_buffer(), end - begin, 1, file); + if (bytes != 1) { + fclose(file); + return 0; + } + + Source der(tmp.get_buffer(), end - begin); + Base64Decoder b64Dec(der); + + uint sz = der.size(); + mySTL::auto_ptr<x509> x(new (ys) x509(sz)); + memcpy(x->use_buffer(), der.get_buffer(), sz); + + fclose(file); + return x.release(); +} + + +} // namespace + +#ifdef __GNUC__ +template class TaoCrypt::HMAC<TaoCrypt::MD5>; +template class TaoCrypt::HMAC<TaoCrypt::SHA>; +template class TaoCrypt::HMAC<TaoCrypt::RIPEMD160>; +template class TaoCrypt::Mode_BASE<16>; +template class TaoCrypt::Mode_BASE<8>; +#endif + +#endif // !USE_CRYPTOPP_LIB diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp new file mode 100644 index 00000000000..35c4cbd4922 --- /dev/null +++ b/extra/yassl/src/handshake.cpp @@ -0,0 +1,1011 @@ +/* handshake.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* The handshake source implements functions for creating and reading + * the various handshake messages. + */ + +#include "runtime.hpp" +#include "handshake.hpp" +#include "yassl_int.hpp" + + +namespace yaSSL { + +using mySTL::min; + + +// Build a client hello message from cipher suites and compression method +void buildClientHello(SSL& ssl, ClientHello& hello, + CompressionMethod compression = no_compression) +{ + ssl.getCrypto().get_random().Fill(hello.random_, RAN_LEN); + if (ssl.getSecurity().get_resuming()) { + hello.id_len_ = ID_LEN; + memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(), + ID_LEN); + } + else + hello.id_len_ = 0; + hello.suite_len_ = ssl.getSecurity().get_parms().suites_size_; + memcpy(hello.cipher_suites_, ssl.getSecurity().get_parms().suites_, + hello.suite_len_); + hello.comp_len_ = 1; + hello.compression_methods_ = compression; + + hello.set_length(sizeof(ProtocolVersion) + + RAN_LEN + + hello.id_len_ + sizeof(hello.id_len_) + + hello.suite_len_ + sizeof(hello.suite_len_) + + hello.comp_len_ + sizeof(hello.comp_len_)); +} + + +// Build a server hello message +void buildServerHello(SSL& ssl, ServerHello& hello) +{ + if (ssl.getSecurity().get_resuming()) { + memcpy(hello.random_,ssl.getSecurity().get_connection().server_random_, + RAN_LEN); + memcpy(hello.session_id_, ssl.getSecurity().get_resume().GetID(), + ID_LEN); + } + else { + ssl.getCrypto().get_random().Fill(hello.random_, RAN_LEN); + ssl.getCrypto().get_random().Fill(hello.session_id_, ID_LEN); + } + hello.id_len_ = ID_LEN; + ssl.set_sessionID(hello.session_id_); + + hello.cipher_suite_[0] = ssl.getSecurity().get_parms().suite_[0]; + hello.cipher_suite_[1] = ssl.getSecurity().get_parms().suite_[1]; + hello.compression_method_ = no_compression; + + hello.set_length(sizeof(ProtocolVersion) + RAN_LEN + ID_LEN + + sizeof(hello.id_len_) + SUITE_LEN + SIZEOF_ENUM); +} + + +// add handshake from buffer into md5 and sha hashes, use handshake header +void hashHandShake(SSL& ssl, const input_buffer& input, uint sz) +{ + const opaque* buffer = input.get_buffer() + input.get_current() - + HANDSHAKE_HEADER; + sz += HANDSHAKE_HEADER; + ssl.useHashes().use_MD5().update(buffer, sz); + ssl.useHashes().use_SHA().update(buffer, sz); +} + + +// locals +namespace { + +// Write a plaintext record to buffer +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, + const Message& msg) +{ + buffer.allocate(RECORD_HEADER + rlHdr.length_); + buffer << rlHdr << msg; +} + + +// Write a plaintext record to buffer +void buildOutput(output_buffer& buffer, const RecordLayerHeader& rlHdr, + const HandShakeHeader& hsHdr, const HandShakeBase& shake) +{ + buffer.allocate(RECORD_HEADER + rlHdr.length_); + buffer << rlHdr << hsHdr << shake; +} + + +// Build Record Layer header for Message without handshake header +void buildHeader(SSL& ssl, RecordLayerHeader& rlHeader, const Message& msg) +{ + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; + rlHeader.type_ = msg.get_type(); + rlHeader.version_.major_ = pv.major_; + rlHeader.version_.minor_ = pv.minor_; + rlHeader.length_ = msg.get_length(); +} + + +// Build HandShake and RecordLayer Headers for handshake output +void buildHeaders(SSL& ssl, HandShakeHeader& hsHeader, + RecordLayerHeader& rlHeader, const HandShakeBase& shake) +{ + int sz = shake.get_length(); + + hsHeader.set_type(shake.get_type()); + hsHeader.set_length(sz); + + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; + rlHeader.type_ = handshake; + rlHeader.version_.major_ = pv.major_; + rlHeader.version_.minor_ = pv.minor_; + rlHeader.length_ = sz + HANDSHAKE_HEADER; +} + + +// add handshake from buffer into md5 and sha hashes, exclude record header +void hashHandShake(SSL& ssl, const output_buffer& output) +{ + uint sz = output.get_size() - RECORD_HEADER; + + const opaque* buffer = output.get_buffer() + RECORD_HEADER; + + ssl.useHashes().use_MD5().update(buffer, sz); + ssl.useHashes().use_SHA().update(buffer, sz); +} + + +// calculate MD5 hash for finished +void buildMD5(SSL& ssl, Finished& fin, const opaque* sender) +{ + + opaque md5_result[MD5_LEN]; + opaque md5_inner[SIZEOF_SENDER + SECRET_LEN + PAD_MD5]; + opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make md5 inner + memcpy(md5_inner, sender, SIZEOF_SENDER); + memcpy(&md5_inner[SIZEOF_SENDER], master_secret, SECRET_LEN); + memcpy(&md5_inner[SIZEOF_SENDER + SECRET_LEN], PAD1, PAD_MD5); + + ssl.useHashes().use_MD5().get_digest(md5_result, md5_inner, + sizeof(md5_inner)); + + // make md5 outer + memcpy(md5_outer, master_secret, SECRET_LEN); + memcpy(&md5_outer[SECRET_LEN], PAD2, PAD_MD5); + memcpy(&md5_outer[SECRET_LEN + PAD_MD5], md5_result, MD5_LEN); + + ssl.useHashes().use_MD5().get_digest(fin.set_md5(), md5_outer, + sizeof(md5_outer)); +} + + +// calculate SHA hash for finished +void buildSHA(SSL& ssl, Finished& fin, const opaque* sender) +{ + + opaque sha_result[SHA_LEN]; + opaque sha_inner[SIZEOF_SENDER + SECRET_LEN + PAD_SHA]; + opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make sha inner + memcpy(sha_inner, sender, SIZEOF_SENDER); + memcpy(&sha_inner[SIZEOF_SENDER], master_secret, SECRET_LEN); + memcpy(&sha_inner[SIZEOF_SENDER + SECRET_LEN], PAD1, PAD_SHA); + + ssl.useHashes().use_SHA().get_digest(sha_result, sha_inner, + sizeof(sha_inner)); + + // make sha outer + memcpy(sha_outer, master_secret, SECRET_LEN); + memcpy(&sha_outer[SECRET_LEN], PAD2, PAD_SHA); + memcpy(&sha_outer[SECRET_LEN + PAD_SHA], sha_result, SHA_LEN); + + ssl.useHashes().use_SHA().get_digest(fin.set_sha(), sha_outer, + sizeof(sha_outer)); +} + + +// decrypt input message in place, store size in case needed later +void decrypt_message(SSL& ssl, input_buffer& input, uint sz) +{ + input_buffer plain(sz); + opaque* cipher = input.get_buffer() + input.get_current(); + + ssl.useCrypto().use_cipher().decrypt(plain.get_buffer(), cipher, sz); + memcpy(cipher, plain.get_buffer(), sz); + ssl.useSecurity().use_parms().encrypt_size_ = sz; +} + + +// write headers, handshake hash, mac, pad, and encrypt +void cipherFinished(SSL& ssl, Finished& fin, output_buffer& output) +{ + uint digestSz = ssl.getCrypto().get_digest().get_digestSize(); + uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ; + uint sz = RECORD_HEADER + HANDSHAKE_HEADER + finishedSz + digestSz; + uint pad = 0; + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + sz += 1; // pad byte + uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); + pad = (sz - RECORD_HEADER) % blockSz; + pad = blockSz - pad; + sz += pad; + } + + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + buildHeaders(ssl, hsHeader, rlHeader, fin); + rlHeader.length_ = sz - RECORD_HEADER; // record header includes mac + // and pad, hanshake doesn't + output.allocate(sz); + output << rlHeader << hsHeader << fin; + + hashHandShake(ssl, output); + opaque digest[SHA_LEN]; // max size + if (ssl.isTLS()) + TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER, + output.get_size() - RECORD_HEADER, handshake); + else + hmac(ssl, digest, output.get_buffer() + RECORD_HEADER, + output.get_size() - RECORD_HEADER, handshake); + output.write(digest, digestSz); + + if (ssl.getSecurity().get_parms().cipher_type_ == block) + for (uint i = 0; i <= pad; i++) output[AUTO] = pad; // pad byte gets + // pad value too + input_buffer cipher(rlHeader.length_); + ssl.useCrypto().use_cipher().encrypt(cipher.get_buffer(), + output.get_buffer() + RECORD_HEADER, output.get_size() - RECORD_HEADER); + output.set_current(RECORD_HEADER); + output.write(cipher.get_buffer(), cipher.get_capacity()); +} + + +// build an encrypted data or alert message for output +void buildMessage(SSL& ssl, output_buffer& output, const Message& msg) +{ + uint digestSz = ssl.getCrypto().get_digest().get_digestSize(); + uint sz = RECORD_HEADER + msg.get_length() + digestSz; + uint pad = 0; + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + sz += 1; // pad byte + uint blockSz = ssl.getCrypto().get_cipher().get_blockSize(); + pad = (sz - RECORD_HEADER) % blockSz; + pad = blockSz - pad; + sz += pad; + } + + RecordLayerHeader rlHeader; + buildHeader(ssl, rlHeader, msg); + rlHeader.length_ = sz - RECORD_HEADER; // record header includes mac + // and pad, hanshake doesn't + output.allocate(sz); + output << rlHeader << msg; + + opaque digest[SHA_LEN]; // max size + if (ssl.isTLS()) + TLS_hmac(ssl, digest, output.get_buffer() + RECORD_HEADER, + output.get_size() - RECORD_HEADER, msg.get_type()); + else + hmac(ssl, digest, output.get_buffer() + RECORD_HEADER, + output.get_size() - RECORD_HEADER, msg.get_type()); + output.write(digest, digestSz); + + if (ssl.getSecurity().get_parms().cipher_type_ == block) + for (uint i = 0; i <= pad; i++) output[AUTO] = pad; // pad byte gets + // pad value too + input_buffer cipher(rlHeader.length_); + ssl.useCrypto().use_cipher().encrypt(cipher.get_buffer(), + output.get_buffer() + RECORD_HEADER, output.get_size() - RECORD_HEADER); + output.set_current(RECORD_HEADER); + output.write(cipher.get_buffer(), cipher.get_capacity()); +} + + +// build alert message +void buildAlert(SSL& ssl, output_buffer& output, const Alert& alert) +{ + if (ssl.getSecurity().get_parms().pending_ == false) // encrypted + buildMessage(ssl, output, alert); + else { + RecordLayerHeader rlHeader; + buildHeader(ssl, rlHeader, alert); + buildOutput(output, rlHeader, alert); + } +} + + +// build TLS finished message +void buildFinishedTLS(SSL& ssl, Finished& fin, const opaque* sender) +{ + opaque handshake_hash[FINISHED_SZ]; + + ssl.useHashes().use_MD5().get_digest(handshake_hash); + ssl.useHashes().use_SHA().get_digest(&handshake_hash[MD5_LEN]); + + const opaque* side; + if ( strncmp((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0) + side = tls_client; + else + side = tls_server; + + PRF(fin.set_md5(), TLS_FINISHED_SZ, + ssl.getSecurity().get_connection().master_secret_, SECRET_LEN, + side, FINISHED_LABEL_SZ, + handshake_hash, FINISHED_SZ); + + fin.set_length(TLS_FINISHED_SZ); // shorter length for TLS +} + + +// compute p_hash for MD5 or SHA-1 for TLSv1 PRF +void p_hash(output_buffer& result, const output_buffer& secret, + const output_buffer& seed, MACAlgorithm hash) +{ + uint len = hash == md5 ? MD5_LEN : SHA_LEN; + uint times = result.get_capacity() / len; + uint lastLen = result.get_capacity() % len; + opaque previous[SHA_LEN]; // max size + opaque current[SHA_LEN]; // max size + mySTL::auto_ptr<Digest> hmac; + + if (lastLen) times += 1; + + if (hash == md5) + hmac.reset(new (ys) HMAC_MD5(secret.get_buffer(), secret.get_size())); + else + hmac.reset(new (ys) HMAC_SHA(secret.get_buffer(), secret.get_size())); + // A0 = seed + hmac->get_digest(previous, seed.get_buffer(), seed.get_size());// A1 + uint lastTime = times - 1; + + for (uint i = 0; i < times; i++) { + hmac->update(previous, len); + hmac->get_digest(current, seed.get_buffer(), seed.get_size()); + + if (lastLen && (i == lastTime)) + result.write(current, lastLen); + else { + result.write(current, len); + //memcpy(previous, current, len); + hmac->get_digest(previous, previous, len); + } + } +} + + +// calculate XOR for TLSv1 PRF +void get_xor(byte *digest, uint digLen, output_buffer& md5, + output_buffer& sha) +{ + for (uint i = 0; i < digLen; i++) + digest[i] = md5[AUTO] ^ sha[AUTO]; +} + + +// build MD5 part of certificate verify +void buildMD5_CertVerify(SSL& ssl, byte* digest) +{ + opaque md5_result[MD5_LEN]; + opaque md5_inner[SECRET_LEN + PAD_MD5]; + opaque md5_outer[SECRET_LEN + PAD_MD5 + MD5_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make md5 inner + memcpy(md5_inner, master_secret, SECRET_LEN); + memcpy(&md5_inner[SECRET_LEN], PAD1, PAD_MD5); + + ssl.useHashes().use_MD5().get_digest(md5_result, md5_inner, + sizeof(md5_inner)); + + // make md5 outer + memcpy(md5_outer, master_secret, SECRET_LEN); + memcpy(&md5_outer[SECRET_LEN], PAD2, PAD_MD5); + memcpy(&md5_outer[SECRET_LEN + PAD_MD5], md5_result, MD5_LEN); + + ssl.useHashes().use_MD5().get_digest(digest, md5_outer, sizeof(md5_outer)); +} + + +// build SHA part of certificate verify +void buildSHA_CertVerify(SSL& ssl, byte* digest) +{ + opaque sha_result[SHA_LEN]; + opaque sha_inner[SECRET_LEN + PAD_SHA]; + opaque sha_outer[SECRET_LEN + PAD_SHA + SHA_LEN]; + + const opaque* master_secret = + ssl.getSecurity().get_connection().master_secret_; + + // make sha inner + memcpy(sha_inner, master_secret, SECRET_LEN); + memcpy(&sha_inner[SECRET_LEN], PAD1, PAD_SHA); + + ssl.useHashes().use_SHA().get_digest(sha_result, sha_inner, + sizeof(sha_inner)); + + // make sha outer + memcpy(sha_outer, master_secret, SECRET_LEN); + memcpy(&sha_outer[SECRET_LEN], PAD2, PAD_SHA); + memcpy(&sha_outer[SECRET_LEN + PAD_SHA], sha_result, SHA_LEN); + + ssl.useHashes().use_SHA().get_digest(digest, sha_outer, sizeof(sha_outer)); +} + + +} // namespace for locals + + +// some clients still send sslv2 client hello +void ProcessOldClientHello(input_buffer& input, SSL& ssl) +{ + byte b0 = input[AUTO]; + byte b1 = input[AUTO]; + + uint16 sz = ((b0 & 0x7f) << 8) | b1; + + // hashHandShake manually + const opaque* buffer = input.get_buffer() + input.get_current(); + ssl.useHashes().use_MD5().update(buffer, sz); + ssl.useHashes().use_SHA().update(buffer, sz); + + b1 = input[AUTO]; // does this value mean client_hello? + + ClientHello ch; + ch.client_version_.major_ = input[AUTO]; + ch.client_version_.minor_ = input[AUTO]; + + byte len[2]; + + input.read(len, sizeof(len)); + ato16(len, ch.suite_len_); + + input.read(len, sizeof(len)); + uint16 sessionLen; + ato16(len, sessionLen); + ch.id_len_ = sessionLen; + + input.read(len, sizeof(len)); + uint16 randomLen; + ato16(len, randomLen); + + int j = 0; + for (uint16 i = 0; i < ch.suite_len_; i += 3) { + byte first = input[AUTO]; + if (first) // sslv2 type + input.read(len, SUITE_LEN); // skip + else { + input.read(&ch.cipher_suites_[j], SUITE_LEN); + j += SUITE_LEN; + } + } + ch.suite_len_ = j; + + if (ch.id_len_) + input.read(ch.session_id_, ch.id_len_); + + if (randomLen < RAN_LEN) + memset(ch.random_, 0, RAN_LEN - randomLen); + input.read(&ch.random_[RAN_LEN - randomLen], randomLen); + + + ch.Process(input, ssl); +} + + +// Build a finished message, see 7.6.9 +void buildFinished(SSL& ssl, Finished& fin, const opaque* sender) +{ + // store current states, building requires get_digest which resets state + MD5 md5(ssl.getHashes().get_MD5()); + SHA sha(ssl.getHashes().get_SHA()); + + if (ssl.isTLS()) + buildFinishedTLS(ssl, fin, sender); + else { + buildMD5(ssl, fin, sender); + buildSHA(ssl, fin, sender); + } + + // restore + ssl.useHashes().use_MD5() = md5; + ssl.useHashes().use_SHA() = sha; +} + + +/* compute SSLv3 HMAC into digest see + * buffer is of sz size and includes HandShake Header but not a Record Header + * verify means to check peers hmac +*/ +void hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, + ContentType content, bool verify) +{ + Digest& mac = ssl.useCrypto().use_digest(); + opaque inner[SHA_LEN + PAD_MD5 + SEQ_SZ + SIZEOF_ENUM + LENGTH_SZ]; + opaque outer[SHA_LEN + PAD_MD5 + SHA_LEN]; + opaque result[SHA_LEN]; // max possible sizes + uint digestSz = mac.get_digestSize(); // actual sizes + uint padSz = mac.get_padSize(); + uint innerSz = digestSz + padSz + SEQ_SZ + SIZEOF_ENUM + LENGTH_SZ; + uint outerSz = digestSz + padSz + digestSz; + + // data + const opaque* mac_secret = ssl.get_macSecret(verify); + opaque seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 }; + opaque length[LENGTH_SZ]; + c16toa(sz, length); + c32toa(ssl.get_SEQIncrement(verify), &seq[sizeof(uint32)]); + + // make inner + memcpy(inner, mac_secret, digestSz); + memcpy(&inner[digestSz], PAD1, padSz); + memcpy(&inner[digestSz + padSz], seq, SEQ_SZ); + inner[digestSz + padSz + SEQ_SZ] = content; + memcpy(&inner[digestSz + padSz + SEQ_SZ + SIZEOF_ENUM], length, LENGTH_SZ); + + mac.update(inner, innerSz); + mac.get_digest(result, buffer, sz); // append content buffer + + // make outer + memcpy(outer, mac_secret, digestSz); + memcpy(&outer[digestSz], PAD2, padSz); + memcpy(&outer[digestSz + padSz], result, digestSz); + + mac.get_digest(digest, outer, outerSz); +} + + +// TLS type HAMC +void TLS_hmac(SSL& ssl, byte* digest, const byte* buffer, uint sz, + ContentType content, bool verify) +{ + mySTL::auto_ptr<Digest> hmac; + opaque seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 }; + opaque length[LENGTH_SZ]; + opaque inner[SIZEOF_ENUM + VERSION_SZ + LENGTH_SZ]; // type + version + len + + c16toa(sz, length); + c32toa(ssl.get_SEQIncrement(verify), &seq[sizeof(uint32)]); + + MACAlgorithm algo = ssl.getSecurity().get_parms().mac_algorithm_; + + if (algo == sha) + hmac.reset(new (ys) HMAC_SHA(ssl.get_macSecret(verify), SHA_LEN)); + else if (algo == rmd) + hmac.reset(new (ys) HMAC_RMD(ssl.get_macSecret(verify), RMD_LEN)); + else + hmac.reset(new (ys) HMAC_MD5(ssl.get_macSecret(verify), MD5_LEN)); + + hmac->update(seq, SEQ_SZ); // seq_num + inner[0] = content; // type + inner[SIZEOF_ENUM] = ssl.getSecurity().get_connection().version_.major_; + inner[SIZEOF_ENUM + SIZEOF_ENUM] = + ssl.getSecurity().get_connection().version_.minor_; // version + memcpy(&inner[SIZEOF_ENUM + VERSION_SZ], length, LENGTH_SZ); // length + hmac->update(inner, sizeof(inner)); + hmac->get_digest(digest, buffer, sz); // content +} + + +// compute TLSv1 PRF (pseudo random function using HMAC) +void PRF(byte* digest, uint digLen, const byte* secret, uint secLen, + const byte* label, uint labLen, const byte* seed, uint seedLen) +{ + uint half = secLen / 2 + secLen % 2; + + output_buffer md5_half(half); + output_buffer sha_half(half); + output_buffer labelSeed(labLen + seedLen); + + md5_half.write(secret, half); + sha_half.write(secret + half - secLen % 2, half); + labelSeed.write(label, labLen); + labelSeed.write(seed, seedLen); + + output_buffer md5_result(digLen); + output_buffer sha_result(digLen); + + p_hash(md5_result, md5_half, labelSeed, md5); + p_hash(sha_result, sha_half, labelSeed, sha); + + md5_result.set_current(0); + sha_result.set_current(0); + get_xor(digest, digLen, md5_result, sha_result); +} + + +// build certificate hashes +void build_certHashes(SSL& ssl, Hashes& hashes) +{ + // store current states, building requires get_digest which resets state + MD5 md5(ssl.getHashes().get_MD5()); + SHA sha(ssl.getHashes().get_SHA()); + + if (ssl.isTLS()) { + ssl.useHashes().use_MD5().get_digest(hashes.md5_); + ssl.useHashes().use_SHA().get_digest(hashes.sha_); + } + else { + buildMD5_CertVerify(ssl, hashes.md5_); + buildSHA_CertVerify(ssl, hashes.sha_); + } + + // restore + ssl.useHashes().use_MD5() = md5; + ssl.useHashes().use_SHA() = sha; +} + + +mySTL::auto_ptr<input_buffer> null_buffer; + +// do process input requests +mySTL::auto_ptr<input_buffer> +DoProcessReply(SSL& ssl, mySTL::auto_ptr<input_buffer> buffered) +{ + ssl.getSocket().wait(); // wait for input if blocking + uint ready = ssl.getSocket().get_ready(); + if (!ready) return buffered; + + // add buffered data if its there + uint buffSz = buffered.get() ? buffered.get()->get_size() : 0; + input_buffer buffer(buffSz + ready); + if (buffSz) { + buffer.assign(buffered.get()->get_buffer(), buffSz); + buffered = null_buffer; + } + + // add new data + uint read = ssl.getSocket().receive(buffer.get_buffer() + buffSz, ready); + buffer.add_size(read); + uint offset = 0; + const MessageFactory& mf = ssl.getFactory().getMessage(); + + // old style sslv2 client hello? + if (ssl.getSecurity().get_parms().entity_ == server_end && + ssl.getStates().getServer() == clientNull) + if (buffer.peek() != handshake) + ProcessOldClientHello(buffer, ssl); + + while(!buffer.eof()) { + // each record + RecordLayerHeader hdr; + buffer >> hdr; + ssl.verifyState(hdr); + + // make sure we have enough input in buffer to process this record + if (hdr.length_ > buffer.get_remaining()) { + uint sz = buffer.get_remaining() + RECORD_HEADER; + buffered.reset(new (ys) input_buffer(sz, buffer.get_buffer() + + buffer.get_current() - RECORD_HEADER, sz)); + break; + } + + while (buffer.get_current() < hdr.length_ + RECORD_HEADER + offset) { + // each message in record + if (ssl.getSecurity().get_parms().pending_ == false) // cipher on + decrypt_message(ssl, buffer, hdr.length_); + mySTL::auto_ptr<Message> msg(mf.CreateObject(hdr.type_)); + if (!msg.get()) { + ssl.SetError(factory_error); + return buffered = null_buffer; + } + buffer >> *msg; + msg->Process(buffer, ssl); + if (ssl.GetError()) return buffered = null_buffer; + } + offset += hdr.length_ + RECORD_HEADER; + } + return buffered; // done, don't call again +} + + +// process input requests +void processReply(SSL& ssl) +{ + if (ssl.GetError()) return; + mySTL::auto_ptr<input_buffer> buffered; + + for (;;) { + mySTL::auto_ptr<input_buffer> tmp = DoProcessReply(ssl, buffered); + if (tmp.get()) // had only part of a record's data, call again + buffered = tmp; + else + break; + } +} + + +// send client_hello, no buffering +void sendClientHello(SSL& ssl) +{ + ssl.verifyState(serverNull); + if (ssl.GetError()) return; + + ClientHello ch(ssl.getSecurity().get_connection().version_); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + output_buffer out; + + buildClientHello(ssl, ch); + ssl.set_random(ch.get_random(), client_end); + buildHeaders(ssl, hsHeader, rlHeader, ch); + buildOutput(out, rlHeader, hsHeader, ch); + hashHandShake(ssl, out); + + ssl.Send(out.get_buffer(), out.get_size()); +} + + +// send client key exchange +void sendClientKeyExchange(SSL& ssl, BufferOutput buffer) +{ + ssl.verifyState(serverHelloDoneComplete); + if (ssl.GetError()) return; + + ClientKeyExchange ck(ssl); + ck.build(ssl); + ssl.makeMasterSecret(); + + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + buildHeaders(ssl, hsHeader, rlHeader, ck); + buildOutput(*out.get(), rlHeader, hsHeader, ck); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send server key exchange +void sendServerKeyExchange(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + ServerKeyExchange sk(ssl); + sk.build(ssl); + + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + buildHeaders(ssl, hsHeader, rlHeader, sk); + buildOutput(*out.get(), rlHeader, hsHeader, sk); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send change cipher +void sendChangeCipher(SSL& ssl, BufferOutput buffer) +{ + if (ssl.getSecurity().get_parms().entity_ == server_end) + if (ssl.getSecurity().get_resuming()) + ssl.verifyState(clientKeyExchangeComplete); + else + ssl.verifyState(clientFinishedComplete); + if (ssl.GetError()) return; + + ChangeCipherSpec ccs; + RecordLayerHeader rlHeader; + buildHeader(ssl, rlHeader, ccs); + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + buildOutput(*out.get(), rlHeader, ccs); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send finished +void sendFinished(SSL& ssl, ConnectionEnd side, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + Finished fin; + buildFinished(ssl, fin, side == client_end ? client : server); + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + cipherFinished(ssl, fin, *out.get()); // hashes handshake + + if (ssl.getSecurity().get_resuming()) { + if (side == server_end) + buildFinished(ssl, ssl.useHashes().use_verify(), client); // client + } + else { + GetSessions().add(ssl); // store session + if (side == client_end) + buildFinished(ssl, ssl.useHashes().use_verify(), server); // server + } + ssl.useSecurity().use_connection().CleanMaster(); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send data +int sendData(SSL& ssl, const void* buffer, int sz) +{ + ssl.verfiyHandShakeComplete(); + if (ssl.GetError()) return 0; + int sent = 0; + + for (;;) { + int len = min(sz - sent, MAX_RECORD_SIZE); + output_buffer out; + const Data data(len, static_cast<const opaque*>(buffer) + sent); + + buildMessage(ssl, out, data); + ssl.Send(out.get_buffer(), out.get_size()); + + if (ssl.GetError()) return 0; + sent += len; + if (sent == sz) break; + } + ssl.useLog().ShowData(sent, true); + return sent; +} + + +// send alert +int sendAlert(SSL& ssl, const Alert& alert) +{ + output_buffer out; + buildAlert(ssl, out, alert); + ssl.Send(out.get_buffer(), out.get_size()); + + return alert.get_length(); +} + + +// process input data +int receiveData(SSL& ssl, Data& data) +{ + ssl.verfiyHandShakeComplete(); + if (ssl.GetError()) return 0; + + if (!ssl.bufferedData()) + processReply(ssl); + ssl.fillData(data); + ssl.useLog().ShowData(data.get_length()); + + if (ssl.GetError()) return 0; + return data.get_length(); +} + + +// send server hello +void sendServerHello(SSL& ssl, BufferOutput buffer) +{ + if (ssl.getSecurity().get_resuming()) + ssl.verifyState(clientKeyExchangeComplete); + else + ssl.verifyState(clientHelloComplete); + if (ssl.GetError()) return; + + ServerHello sh(ssl.getSecurity().get_connection().version_); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + + buildServerHello(ssl, sh); + ssl.set_random(sh.get_random(), server_end); + buildHeaders(ssl, hsHeader, rlHeader, sh); + buildOutput(*out.get(), rlHeader, hsHeader, sh); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send server hello done +void sendServerHelloDone(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + ServerHelloDone shd; + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, shd); + buildOutput(*out.get(), rlHeader, hsHeader, shd); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send certificate +void sendCertificate(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + Certificate cert(ssl.getCrypto().get_certManager().get_cert()); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, cert); + buildOutput(*out.get(), rlHeader, hsHeader, cert); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send certificate request +void sendCertificateRequest(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + CertificateRequest request; + request.Build(); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, request); + buildOutput(*out.get(), rlHeader, hsHeader, request); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +// send certificate verify +void sendCertificateVerify(SSL& ssl, BufferOutput buffer) +{ + if (ssl.GetError()) return; + + CertificateVerify verify; + verify.Build(ssl); + RecordLayerHeader rlHeader; + HandShakeHeader hsHeader; + mySTL::auto_ptr<output_buffer> out(new (ys) output_buffer); + + buildHeaders(ssl, hsHeader, rlHeader, verify); + buildOutput(*out.get(), rlHeader, hsHeader, verify); + hashHandShake(ssl, *out.get()); + + if (buffer == buffered) + ssl.addBuffer(out.release()); + else + ssl.Send(out->get_buffer(), out->get_size()); +} + + +} // namespace diff --git a/extra/yassl/src/lock.cpp b/extra/yassl/src/lock.cpp new file mode 100644 index 00000000000..221ec0cdb4f --- /dev/null +++ b/extra/yassl/src/lock.cpp @@ -0,0 +1,90 @@ +/* lock.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* Locking functions + */ + +#include "runtime.hpp" +#include "lock.hpp" + + +namespace yaSSL { + + +#ifdef MULTI_THREADED + #ifdef WIN32 + + Mutex::Mutex() + { + InitializeCriticalSection(&cs_); + } + + + Mutex::~Mutex() + { + DeleteCriticalSection(&cs_); + } + + + Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) + { + EnterCriticalSection(&mutex_.cs_); + } + + + Mutex::Lock::~Lock() + { + LeaveCriticalSection(&mutex_.cs_); + } + + #else // WIN32 + + Mutex::Mutex() + { + pthread_mutex_init(&mutex_, 0); + } + + + Mutex::~Mutex() + { + pthread_mutex_destroy(&mutex_); + } + + + Mutex::Lock::Lock(Mutex& lm) : mutex_(lm) + { + pthread_mutex_lock(&mutex_.mutex_); + } + + + Mutex::Lock::~Lock() + { + pthread_mutex_unlock(&mutex_.mutex_); + } + + + #endif // WIN32 +#endif // MULTI_THREADED + + + +} // namespace yaSSL + diff --git a/extra/yassl/src/log.cpp b/extra/yassl/src/log.cpp new file mode 100644 index 00000000000..eb4776d3d19 --- /dev/null +++ b/extra/yassl/src/log.cpp @@ -0,0 +1,148 @@ +/* log.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* Debug logging functions + */ + +#include "runtime.hpp" +#include "log.hpp" + +#ifdef YASSL_LOG + #include <ctime> + #include <cstdio> + #include <cstring> +#endif + + + +namespace yaSSL { + + +#ifdef YASSL_LOG + + enum { MAX_MSG = 81 }; + + Log::Log(const char* str) + { + log_ = fopen(str, "w"); + Trace("********** Logger Attached **********"); + } + + + Log::~Log() + { + Trace("********** Logger Detached **********"); + fclose(log_); + } + + + // Trace a message + void Log::Trace(const char* str) + { + if (!log_) return; + + time_t clicks = time(0); + char timeStr[32]; + + // get rid of newline + strncpy(timeStr, ctime(&clicks), sizeof(timeStr)); + unsigned int len = strlen(timeStr); + timeStr[len - 1] = 0; + + char msg[MAX_MSG]; + + strncpy(msg, timeStr, sizeof(timeStr)); + strncat(msg, ":", 1); + strncat(msg, str, MAX_MSG - sizeof(timeStr) - 2); + strncat(msg, "\n", 1); + msg[MAX_MSG - 1] = 0; + + fputs(msg, log_); + } + + + #if defined(WIN32) || defined(__MACH__) || defined(__hpux__) + typedef int socklen_t; + #endif + + + // write tcp address + void Log::ShowTCP(socket_t fd, bool ended) + { + sockaddr_in peeraddr; + socklen_t len = sizeof(peeraddr); + if (getpeername(fd, (sockaddr*)&peeraddr, &len) != 0) + return; + + const char* p = reinterpret_cast<const char*>(&peeraddr.sin_addr); + char msg[MAX_MSG]; + char number[16]; + + if (ended) + strncpy(msg, "yaSSL conn DONE w/ peer ", 26); + else + strncpy(msg, "yaSSL conn BEGUN w/ peer ", 26); + for (int i = 0; i < 4; ++i) { + sprintf(number, "%u", static_cast<unsigned short>(p[i])); + strncat(msg, number, 8); + if (i < 3) + strncat(msg, ".", 1); + } + strncat(msg, " port ", 8); + sprintf(number, "%d", htons(peeraddr.sin_port)); + strncat(msg, number, 8); + + msg[MAX_MSG - 1] = 0; + Trace(msg); + } + + + // log processed data + void Log::ShowData(uint bytes, bool sent) + { + char msg[MAX_MSG]; + char number[16]; + + if (sent) + strncpy(msg, "Sent ", 10); + else + strncpy(msg, "Received ", 10); + sprintf(number, "%u", bytes); + strncat(msg, number, 8); + strncat(msg, " bytes of application data", 27); + + msg[MAX_MSG - 1] = 0; + Trace(msg); + } + + +#else // no YASSL_LOG + + + Log::Log(const char*) {} + Log::~Log() {} + void Log::Trace(const char*) {} + void Log::ShowTCP(socket_t, bool) {} + void Log::ShowData(uint, bool) {} + + +#endif // YASSL_LOG +} // namespace diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp new file mode 100644 index 00000000000..0dd30e6b696 --- /dev/null +++ b/extra/yassl/src/socket_wrapper.cpp @@ -0,0 +1,168 @@ +/* socket_wrapper.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* The socket wrapper source implements a Socket class that hides the + * differences between Berkely style sockets and Windows sockets, allowing + * transparent TCP access. + */ + + +#include "runtime.hpp" +#include "socket_wrapper.hpp" +#include "yassl_error.hpp" + +#ifndef WIN32 + #include <errno.h> + #include <netdb.h> + #include <unistd.h> + #include <arpa/inet.h> + #include <netinet/in.h> + #include <sys/ioctl.h> + #include <string.h> +#endif // WIN32 + +#ifdef __sun + #include <sys/filio.h> +#endif + +#ifdef WIN32 + const int SOCKET_EINVAL = WSAEINVAL; + const int SOCKET_EWOULDBLOCK = WSAEWOULDBLOCK; +#else + const int SOCKET_EINVAL = EINVAL; + const int SOCKET_EWOULDBLOCK = EWOULDBLOCK; +#endif // WIN32 + + +namespace yaSSL { + + +Socket::Socket(socket_t s) + : socket_(s) +{} + + +void Socket::set_fd(socket_t s) +{ + socket_ = s; +} + + +socket_t Socket::get_fd() const +{ + return socket_; +} + + +Socket::~Socket() +{ + closeSocket(); +} + + +void Socket::closeSocket() +{ + if (socket_ != INVALID_SOCKET) { +#ifdef WIN32 + closesocket(socket_); +#else + close(socket_); +#endif + socket_ = INVALID_SOCKET; + } +} + + +uint Socket::get_ready() const +{ + unsigned long ready = 0; + +#ifdef WIN32 + ioctlsocket(socket_, FIONREAD, &ready); +#else + ioctl(socket_, FIONREAD, &ready); +#endif + + return ready; +} + + +uint Socket::send(const byte* buf, unsigned int sz, int flags) const +{ + assert(socket_ != INVALID_SOCKET); + int sent = ::send(socket_, reinterpret_cast<const char *>(buf), sz, flags); + + if (sent == -1) + return 0; + + return sent; +} + + +uint Socket::receive(byte* buf, unsigned int sz, int flags) const +{ + assert(socket_ != INVALID_SOCKET); + int recvd = ::recv(socket_, reinterpret_cast<char *>(buf), sz, flags); + + if (recvd == -1) + return 0; + + return recvd; +} + + +// wait if blocking for input, or error +void Socket::wait() const +{ + byte b; + receive(&b, 1, MSG_PEEK); +} + + +void Socket::shutDown(int how) +{ + assert(socket_ != INVALID_SOCKET); + shutdown(socket_, how); +} + + +int Socket::get_lastError() +{ +#ifdef WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + + +void Socket::set_lastError(int errorCode) +{ +#ifdef WIN32 + WSASetLastError(errorCode); +#else + errno = errorCode; +#endif +} + + +} // namespace diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp new file mode 100644 index 00000000000..065b3c260bf --- /dev/null +++ b/extra/yassl/src/ssl.cpp @@ -0,0 +1,1039 @@ +/* ssl.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* SSL source implements all openssl compatibility API functions + * + * TODO: notes are mostly api additions to allow compilation with mysql + * they don't affect normal modes but should be provided for completeness + + * stunnel functions at end of file + */ + + + + +/* see man pages for function descriptions */ + +#include "runtime.hpp" +#include "openssl/ssl.h" +#include "handshake.hpp" +#include "yassl_int.hpp" +#include <cstdio> + + +namespace yaSSL { + +using mySTL::min; + + +SSL_METHOD* SSLv3_method() +{ + return SSLv3_client_method(); +} + + +SSL_METHOD* SSLv3_server_method() +{ + return new SSL_METHOD(server_end, ProtocolVersion(3,0)); +} + + +SSL_METHOD* SSLv3_client_method() +{ + return new SSL_METHOD(client_end, ProtocolVersion(3,0)); +} + + +SSL_METHOD* TLSv1_server_method() +{ + return new SSL_METHOD(server_end, ProtocolVersion(3,1)); +} + + +SSL_METHOD* TLSv1_client_method() +{ + return new SSL_METHOD(client_end, ProtocolVersion(3,1)); +} + + +SSL_METHOD* SSLv23_server_method() +{ + // compatibility only, no version 2 support + return SSLv3_server_method(); +} + + +SSL_CTX* SSL_CTX_new(SSL_METHOD* method) +{ + return new SSL_CTX(method); +} + + +void SSL_CTX_free(SSL_CTX* ctx) +{ + delete ctx; +} + + +SSL* SSL_new(SSL_CTX* ctx) +{ + return new SSL(ctx); +} + + +void SSL_free(SSL* ssl) +{ + delete ssl; +} + + +int SSL_set_fd(SSL* ssl, int fd) +{ + ssl->useSocket().set_fd(fd); + return SSL_SUCCESS; +} + + +int SSL_connect(SSL* ssl) +{ + sendClientHello(*ssl); + processReply(*ssl); + + if(ssl->getCrypto().get_certManager().sendVerify()) + sendCertificate(*ssl); + + if (!ssl->getSecurity().get_resuming()) + sendClientKeyExchange(*ssl); + + if(ssl->getCrypto().get_certManager().sendVerify()) + sendCertificateVerify(*ssl); + + sendChangeCipher(*ssl); + sendFinished(*ssl, client_end); + ssl->flushBuffer(); + if (!ssl->getSecurity().get_resuming()) + processReply(*ssl); + + ssl->verifyState(serverFinishedComplete); + ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); + + if (ssl->GetError()) + return SSL_FATAL_ERROR; + return SSL_SUCCESS; +} + + +int SSL_write(SSL* ssl, const void* buffer, int sz) +{ + return sendData(*ssl, buffer, sz); +} + + +int SSL_read(SSL* ssl, void* buffer, int sz) +{ + Data data(min(sz, MAX_RECORD_SIZE), static_cast<opaque*>(buffer)); + return receiveData(*ssl, data); +} + + +int SSL_accept(SSL* ssl) +{ + processReply(*ssl); + sendServerHello(*ssl); + + if (!ssl->getSecurity().get_resuming()) { + sendCertificate(*ssl); + + if (ssl->getSecurity().get_connection().send_server_key_) + sendServerKeyExchange(*ssl); + + if(ssl->getCrypto().get_certManager().verifyPeer()) + sendCertificateRequest(*ssl); + + sendServerHelloDone(*ssl); + ssl->flushBuffer(); + + processReply(*ssl); + } + sendChangeCipher(*ssl); + sendFinished(*ssl, server_end); + ssl->flushBuffer(); + if (ssl->getSecurity().get_resuming()) + processReply(*ssl); + + ssl->useLog().ShowTCP(ssl->getSocket().get_fd()); + + if (ssl->GetError()) + return SSL_FATAL_ERROR; + return SSL_SUCCESS; +} + + +int SSL_do_handshake(SSL* ssl) +{ + if (ssl->getSecurity().get_parms().entity_ == client_end) + return SSL_connect(ssl); + else + return SSL_accept(ssl); +} + + +int SSL_clear(SSL* ssl) +{ + ssl->useSocket().closeSocket(); + return SSL_SUCCESS; +} + + +int SSL_shutdown(SSL* ssl) +{ + Alert alert(warning, close_notify); + sendAlert(*ssl, alert); + ssl->useLog().ShowTCP(ssl->getSocket().get_fd(), true); + ssl->useSocket().closeSocket(); + + return SSL_SUCCESS; +} + + +SSL_SESSION* SSL_get_session(SSL* ssl) +{ + return GetSessions().lookup( + ssl->getSecurity().get_connection().sessionID_); +} + + +int SSL_set_session(SSL* ssl, SSL_SESSION* session) +{ + ssl->set_session(session); + return SSL_SUCCESS; +} + + +int SSL_session_reused(SSL* ssl) +{ + return ssl->getSecurity().get_resuming(); +} + + +long SSL_SESSION_set_timeout(SSL_SESSION* sess, long t) +{ + if (!sess) + return SSL_ERROR_NONE; + + sess->SetTimeOut(t); + return SSL_SUCCESS; +} + + +long SSL_get_default_timeout(SSL* /*ssl*/) +{ + return DEFAULT_TIMEOUT; +} + + +const char* SSL_get_cipher_name(SSL* ssl) +{ + return SSL_get_cipher(ssl); +} + + +const char* SSL_get_cipher(SSL* ssl) +{ + return ssl->getSecurity().get_parms().cipher_name_; +} + + +// SSLv2 only, not implemented +char* SSL_get_shared_ciphers(SSL* /*ssl*/, char* buf, int len) +{ + return strncpy(buf, "Not Implemented, SSLv2 only", len); +} + + +const char* SSL_get_cipher_list(SSL* ssl, int /*priority */) +{ + return ssl->getSecurity().get_parms().cipher_list_; +} + + +int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list) +{ + if (ctx->SetCipherList(list)) + return SSL_SUCCESS; + else + return SSL_FAILURE; +} + + +const char* SSL_get_version(SSL* ssl) +{ + static const char* version3 = "SSLv3"; + static const char* version31 = "TLSv1"; + + return ssl->isTLS() ? version31 : version3; +} + +const char* SSLeay_version(int) +{ + static const char* version = "SSLeay yaSSL compatibility"; + return version; +} + + +int SSL_get_error(SSL* ssl, int /*previous*/) +{ + return ssl->getStates().What(); +} + + +X509* SSL_get_peer_certificate(SSL* ssl) +{ + return ssl->getCrypto().get_certManager().get_peerX509(); +} + + +void X509_free(X509* /*x*/) +{ + // peer cert set for deletion during destruction + // no need to delete now +} + + +X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX* ctx) +{ + return ctx->current_cert; +} + + +int X509_STORE_CTX_get_error(X509_STORE_CTX* ctx) +{ + return ctx->error; +} + + +int X509_STORE_CTX_get_error_depth(X509_STORE_CTX* ctx) +{ + return ctx->error_depth; +} + + +// copy name into buffer, at most sz bytes, if buffer is null +// will malloc buffer, caller responsible for freeing +char* X509_NAME_oneline(X509_NAME* name, char* buffer, int sz) +{ + if (!name->GetName()) return buffer; + + int len = strlen(name->GetName()) + 1; + int copySz = min(len, sz); + + if (!buffer) { + buffer = (char*)malloc(len); + if (!buffer) return buffer; + copySz = len; + } + + if (copySz == 0) + return buffer; + + memcpy(buffer, name->GetName(), copySz - 1); + buffer[copySz - 1] = 0; + + return buffer; +} + + +X509_NAME* X509_get_issuer_name(X509* x) +{ + return x->GetIssuer(); +} + + +X509_NAME* X509_get_subject_name(X509* x) +{ + return x->GetSubject(); +} + + +void SSL_load_error_strings() // compatibility only +{} + + +void SSL_set_connect_state(SSL*) +{ + // already a client by default +} + + +void SSL_set_accept_state(SSL* ssl) +{ + ssl->useSecurity().use_parms().entity_ = server_end; +} + + +long SSL_get_verify_result(SSL*) +{ + // won't get here if not OK + return X509_V_OK; +} + + +long SSL_CTX_sess_set_cache_size(SSL_CTX* /*ctx*/, long /*sz*/) +{ + // unlimited size, can't set for now + return 0; +} + + +long SSL_CTX_get_session_cache_mode(SSL_CTX*) +{ + // always 0, unlimited size for now + return 0; +} + + +long SSL_CTX_set_tmp_dh(SSL_CTX* ctx, DH* dh) +{ + if (ctx->SetDH(*dh)) + return SSL_SUCCESS; + else + return SSL_FAILURE; +} + + +int read_file(SSL_CTX* ctx, const char* file, int format, CertType type) +{ + if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM) + return SSL_BAD_FILETYPE; + + FILE* input = fopen(file, "rb"); + if (!input) + return SSL_BAD_FILE; + + if (type == CA) { + x509* ptr = PemToDer(file, Cert); + if (!ptr) { + fclose(input); + return SSL_BAD_FILE; + } + ctx->AddCA(ptr); // takes ownership + } + else { + x509*& x = (type == Cert) ? ctx->certificate_ : ctx->privateKey_; + + if (format == SSL_FILETYPE_ASN1) { + fseek(input, 0, SEEK_END); + long sz = ftell(input); + rewind(input); + x = new (ys) x509(sz); // takes ownership + size_t bytes = fread(x->use_buffer(), sz, 1, input); + if (bytes != 1) { + fclose(input); + return SSL_BAD_FILE; + } + } + else { + x = PemToDer(file, type); + if (!x) { + fclose(input); + return SSL_BAD_FILE; + } + } + } + fclose(input); + return SSL_SUCCESS; +} + + +int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int format) +{ + return read_file(ctx, file, format, Cert); +} + + +int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int format) +{ + return read_file(ctx, file, format, PrivateKey); +} + + +void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, VerifyCallback /*vc*/) +{ + if (mode & SSL_VERIFY_PEER) + ctx->setVerifyPeer(); + + if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + ctx->setFailNoCert(); +} + + +int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, + const char* /*path*/) +{ + // just files for now + return read_file(ctx, file, SSL_FILETYPE_PEM, CA); +} + + +int SSL_CTX_set_default_verify_paths(SSL_CTX* /*ctx*/) +{ + // TODO: figure out way to set/store default path, then call load_verify + return SSL_NOT_IMPLEMENTED; +} + + +int SSL_CTX_set_session_id_context(SSL_CTX*, const unsigned char*, + unsigned int) +{ + // No application specific context needed for yaSSL + return SSL_SUCCESS; +} + + +int SSL_CTX_check_private_key(SSL_CTX* /*ctx*/) +{ + // TODO: check private against public for RSA match + return SSL_NOT_IMPLEMENTED; +} + + +// TODO: all session stats +long SSL_CTX_sess_accept(SSL_CTX* ctx) +{ + return ctx->GetStats().accept_; +} + + +long SSL_CTX_sess_connect(SSL_CTX* ctx) +{ + return ctx->GetStats().connect_; +} + + +long SSL_CTX_sess_accept_good(SSL_CTX* ctx) +{ + return ctx->GetStats().acceptGood_; +} + + +long SSL_CTX_sess_connect_good(SSL_CTX* ctx) +{ + return ctx->GetStats().connectGood_; +} + + +long SSL_CTX_sess_accept_renegotiate(SSL_CTX* ctx) +{ + return ctx->GetStats().acceptRenegotiate_; +} + + +long SSL_CTX_sess_connect_renegotiate(SSL_CTX* ctx) +{ + return ctx->GetStats().connectRenegotiate_; +} + + +long SSL_CTX_sess_hits(SSL_CTX* ctx) +{ + return ctx->GetStats().hits_; +} + + +long SSL_CTX_sess_cb_hits(SSL_CTX* ctx) +{ + return ctx->GetStats().cbHits_; +} + + +long SSL_CTX_sess_cache_full(SSL_CTX* ctx) +{ + return ctx->GetStats().cacheFull_; +} + + +long SSL_CTX_sess_misses(SSL_CTX* ctx) +{ + return ctx->GetStats().misses_; +} + + +long SSL_CTX_sess_timeouts(SSL_CTX* ctx) +{ + return ctx->GetStats().timeouts_; +} + + +long SSL_CTX_sess_number(SSL_CTX* ctx) +{ + return ctx->GetStats().number_; +} + + +long SSL_CTX_sess_get_cache_size(SSL_CTX* ctx) +{ + return ctx->GetStats().getCacheSize_; +} +// end session stats TODO: + + +int SSL_CTX_get_verify_mode(SSL_CTX* ctx) +{ + return ctx->GetStats().verifyMode_; +} + + +int SSL_get_verify_mode(SSL* ssl) +{ + return ssl->getSecurity().GetContext()->GetStats().verifyMode_; +} + + +int SSL_CTX_get_verify_depth(SSL_CTX* ctx) +{ + return ctx->GetStats().verifyDepth_; +} + + +int SSL_get_verify_depth(SSL* ssl) +{ + return ssl->getSecurity().GetContext()->GetStats().verifyDepth_; +} + + +long SSL_CTX_set_options(SSL_CTX*, long) +{ + // TDOD: + return SSL_SUCCESS; +} + + +void SSL_CTX_set_info_callback(SSL_CTX*, void (*)()) +{ + // TDOD: +} + + +void OpenSSL_add_all_algorithms() // compatibility only +{} + + +DH* DH_new(void) +{ + DH* dh = new DH; + if (dh) + dh->p = dh->g = 0; + return dh; +} + + +void DH_free(DH* dh) +{ + delete dh->g; + delete dh->p; + delete dh; +} + + +// convert positive big-endian num of length sz into retVal, which may need to +// be created +BIGNUM* BN_bin2bn(const unsigned char* num, int sz, BIGNUM* retVal) +{ + using mySTL::auto_ptr; + bool created = false; + auto_ptr<BIGNUM> bn; + + if (!retVal) { + created = true; + bn.reset(new (ys) BIGNUM); + retVal = bn.get(); + } + + retVal->assign(num, sz); + + if (created) + return bn.release(); + else + return retVal; +} + + +unsigned long ERR_get_error_line_data(const char**, int*, const char**, int *) +{ + //return SSL_NOT_IMPLEMENTED; + return 0; +} + + +void ERR_print_errors_fp(FILE* /*fp*/) +{ + // need ssl access to implement TODO: + //fprintf(fp, "%s", ssl.get_states().errorString_.c_str()); +} + + +char* ERR_error_string(unsigned long /*err*/, char* buffer) +{ + // TODO: + static char* msg = "Not Implemented"; + if (buffer) + return strncpy(buffer, msg, strlen(msg)); + + return msg; +} + + +const char* X509_verify_cert_error_string(long /* error */) +{ + // TODO: + static const char* msg = "Not Implemented"; + return msg; +} + + +const EVP_MD* EVP_md5(void) +{ + // TODO: FIX add to some list for destruction + return new MD5; +} + + +const EVP_CIPHER* EVP_des_ede3_cbc(void) +{ + // TODO: FIX add to some list for destruction + return new DES_EDE; +} + + +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) +{ + EVP_MD* myMD = const_cast<EVP_MD*>(md); + uint digestSz = myMD->get_digestSize(); + byte digest[SHA_LEN]; // max size + + int keyLen = type->get_keySize(); + int ivLen = type->get_ivSize(); + int keyLeft = keyLen; + int ivLeft = ivLen; + int keyOutput = 0; + + while (keyOutput < (keyLen + ivLen)) { + int digestLeft = digestSz; + // D_(i - 1) + if (keyOutput) // first time D_0 is empty + myMD->update(digest, digestSz); + // data + myMD->update(data, sz); + // salt + if (salt) + myMD->update(salt, EVP_SALT_SZ); + myMD->get_digest(digest); + // count + for (int j = 1; j < count; j++) { + myMD->update(digest, digestSz); + myMD->get_digest(digest); + } + + if (keyLeft) { + int store = min(keyLeft, static_cast<int>(digestSz)); + memcpy(&key[keyLen - keyLeft], digest, store); + + keyOutput += store; + keyLeft -= store; + digestLeft -= store; + } + + if (ivLeft && digestLeft) { + int store = min(ivLeft, digestLeft); + memcpy(&iv[ivLen - ivLeft], digest, store); + + keyOutput += store; + ivLeft -= store; + } + } + assert(keyOutput == (keyLen + ivLen)); + return keyOutput; +} + + + +void DES_set_key_unchecked(const_DES_cblock* key, DES_key_schedule* schedule) +{ + memcpy(schedule, key, sizeof(const_DES_cblock)); +} + + +void DES_ede3_cbc_encrypt(const byte* input, byte* output, long sz, + DES_key_schedule* ks1, DES_key_schedule* ks2, + DES_key_schedule* ks3, DES_cblock* ivec, int enc) +{ + DES_EDE des; + byte key[DES_EDE_KEY_SZ]; + + memcpy(key, *ks1, DES_BLOCK); + memcpy(&key[DES_BLOCK], *ks2, DES_BLOCK); + memcpy(&key[DES_BLOCK * 2], *ks3, DES_BLOCK); + + if (enc) { + des.set_encryptKey(key, *ivec); + des.encrypt(output, input, sz); + } + else { + des.set_decryptKey(key, *ivec); + des.decrypt(output, input, sz); + } +} + + + // functions for stunnel + + void RAND_screen() + { + // TODO: + } + + + const char* RAND_file_name(char*, size_t) + { + // TODO: + return 0; + } + + + int RAND_write_file(const char*) + { + // TODO: + return 0; + } + + + int RAND_load_file(const char*, long) + { + // TODO: + return 0; + } + + + void RSA_free(RSA*) + { + // TODO: + } + + + RSA* RSA_generate_key(int, unsigned long, void(*)(int, int, void*), void*) + { + // TODO: + return 0; + } + + + int X509_LOOKUP_add_dir(X509_LOOKUP*, const char*, long) + { + // TODO: + return SSL_SUCCESS; + } + + + int X509_LOOKUP_load_file(X509_LOOKUP*, const char*, long) + { + // TODO: + return SSL_SUCCESS; + } + + + X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void) + { + // TODO: + return 0; + } + + + X509_LOOKUP_METHOD* X509_LOOKUP_file(void) + { + // TODO: + return 0; + } + + + X509_LOOKUP* X509_STORE_add_lookup(X509_STORE*, X509_LOOKUP_METHOD*) + { + // TODO: + return 0; + } + + + int X509_STORE_get_by_subject(X509_STORE_CTX*, int, X509_NAME*, X509_OBJECT*) + { + // TODO: + return SSL_SUCCESS; + } + + + X509_STORE* X509_STORE_new(void) + { + // TODO: + return 0; + } + + char* SSL_alert_type_string_long(int) + { + // TODO: + return 0; + } + + + char* SSL_alert_desc_string_long(int) + { + // TODO: + return 0; + } + + + char* SSL_state_string_long(SSL*) + { + // TODO: + return 0; + } + + + void SSL_CTX_set_tmp_rsa_callback(SSL_CTX*, RSA*(*)(SSL*, int, int)) + { + // TDOD: + } + + + long SSL_CTX_set_session_cache_mode(SSL_CTX*, long) + { + // TDOD: + return SSL_SUCCESS; + } + + + long SSL_CTX_set_timeout(SSL_CTX*, long) + { + // TDOD: + return SSL_SUCCESS; + } + + + int SSL_CTX_use_certificate_chain_file(SSL_CTX*, const char*) + { + // TDOD: + return SSL_SUCCESS; + } + + + void SSL_CTX_set_default_passwd_cb(SSL_CTX*, pem_password_cb) + { + // TDOD: + } + + + int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX*, const char*, int) + { + // TDOD: + return SSL_SUCCESS; + } + + + int SSL_set_rfd(SSL*, int) + { + return SSL_SUCCESS; // TODO: + } + + + int SSL_set_wfd(SSL*, int) + { + return SSL_SUCCESS; // TODO: + } + + + int SSL_pending(SSL*) + { + return SSL_SUCCESS; // TODO: + } + + + int SSL_want_read(SSL*) + { + return 0; // TODO: + } + + + int SSL_want_write(SSL*) + { + return 0; // TODO: + } + + + void SSL_set_shutdown(SSL*, int) + { + // TODO: + } + + + SSL_CIPHER* SSL_get_current_cipher(SSL*) + { + // TODO: + return 0; + } + + + char* SSL_CIPHER_description(SSL_CIPHER*, char*, int) + { + // TODO: + return 0; + } + + + void SSLeay_add_ssl_algorithms() // compatibility only + {} + + + void ERR_remove_state(unsigned long) + { + // TODO: + } + + + int ERR_GET_REASON(int l) + { + return l & 0xfff; + } + + + unsigned long ERR_peek_error() + { + return 0; // TODO: + } + + + unsigned long ERR_get_error() + { + return ERR_peek_error(); + } + + + // end stunnel needs + + +} // namespace diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp new file mode 100644 index 00000000000..49e7bb36776 --- /dev/null +++ b/extra/yassl/src/timer.cpp @@ -0,0 +1,82 @@ + /* timer.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* timer.cpp implements a high res and low res timer + * +*/ + +#include "runtime.hpp" +#include "timer.hpp" + +namespace yaSSL { + +#ifdef WIN32 + + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + + timer_d timer() + { + static bool init(false); + static LARGE_INTEGER freq; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = true; + } + + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + + return static_cast<double>(count.QuadPart) / freq.QuadPart; + } + + + uint lowResTimer() + { + return static_cast<uint>(timer()); + } + +#else // WIN32 + + #include <sys/time.h> + + timer_d timer() + { + struct timeval tv; + gettimeofday(&tv, 0); + + return static_cast<double>(tv.tv_sec) + + static_cast<double>(tv.tv_usec) / 1000000; + } + + + uint lowResTimer() + { + struct timeval tv; + gettimeofday(&tv, 0); + + return tv.tv_sec; + } + + +#endif // WIN32 +} // namespace yaSSL diff --git a/extra/yassl/src/yassl_error.cpp b/extra/yassl/src/yassl_error.cpp new file mode 100644 index 00000000000..c53aef2068d --- /dev/null +++ b/extra/yassl/src/yassl_error.cpp @@ -0,0 +1,53 @@ +/* yassl_error.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* yaSSL error implements and an exception class + */ + +#include "runtime.hpp" +#include "yassl_error.hpp" + +namespace yaSSL { + + +Error::Error(const char* s, YasslError e, Library l) + : mySTL::runtime_error(s), error_(e), lib_(l) +{ +} + + +YasslError Error::get_number() const +{ + return error_; +} + + +Library Error::get_lib() const +{ + + return lib_; +} + + + + +} // namespace yaSSL diff --git a/extra/yassl/src/yassl_imp.cpp b/extra/yassl/src/yassl_imp.cpp new file mode 100644 index 00000000000..ba2fbd8cc07 --- /dev/null +++ b/extra/yassl/src/yassl_imp.cpp @@ -0,0 +1,2116 @@ +/* yassl_imp.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* yaSSL source implements all SSL.v3 secification structures. + */ + +#include "runtime.hpp" +#include "yassl_int.hpp" +#include "handshake.hpp" + +#include "asn.hpp" // provide crypto wrapper?? + + +namespace yaSSL { + + +namespace { // locals + +bool isTLS(ProtocolVersion pv) +{ + if (pv.major_ >= 3 && pv.minor_ >= 1) + return true; + + return false; +} + + +} // namespace (locals) + + +void hashHandShake(SSL&, const input_buffer&, uint); + + +ProtocolVersion::ProtocolVersion(uint8 maj, uint8 min) + : major_(maj), minor_(min) +{} + + +// construct key exchange with known ssl parms +void ClientKeyExchange::createKey(SSL& ssl) +{ + const ClientKeyFactory& ckf = ssl.getFactory().getClientKey(); + client_key_ = ckf.CreateObject(ssl.getSecurity().get_parms().kea_); + + if (!client_key_) + ssl.SetError(factory_error); +} + + +// construct key exchange with known ssl parms +void ServerKeyExchange::createKey(SSL& ssl) +{ + const ServerKeyFactory& skf = ssl.getFactory().getServerKey(); + server_key_ = skf.CreateObject(ssl.getSecurity().get_parms().kea_); + + if (!server_key_) + ssl.SetError(factory_error); +} + + +// build/set PreMaster secret and encrypt, client side +void EncryptedPreMasterSecret::build(SSL& ssl) +{ + opaque tmp[SECRET_LEN]; + memset(tmp, 0, sizeof(tmp)); + ssl.getCrypto().get_random().Fill(tmp, SECRET_LEN); + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; + tmp[0] = pv.major_; + tmp[1] = pv.minor_; + ssl.set_preMaster(tmp, SECRET_LEN); + + const CertManager& cert = ssl.getCrypto().get_certManager(); + RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); + bool tls = ssl.isTLS(); // if TLS, put length for encrypted data + alloc(rsa.get_cipherLength() + (tls ? 2 : 0)); + byte* holder = secret_; + if (tls) { + byte len[2]; + c16toa(rsa.get_cipherLength(), len); + memcpy(secret_, len, sizeof(len)); + holder += 2; + } + rsa.encrypt(holder, tmp, SECRET_LEN, ssl.getCrypto().get_random()); +} + + +// build/set premaster and Client Public key, client side +void ClientDiffieHellmanPublic::build(SSL& ssl) +{ + DiffieHellman& dhServer = ssl.useCrypto().use_dh(); + DiffieHellman dhClient(dhServer); + + uint keyLength = dhClient.get_agreedKeyLength(); // pub and agree same + + alloc(keyLength, true); + dhClient.makeAgreement(dhServer.get_publicKey()); + c16toa(keyLength, Yc_); + memcpy(Yc_ + KEY_OFFSET, dhClient.get_publicKey(), keyLength); + + ssl.set_preMaster(dhClient.get_agreedKey(), keyLength); +} + + +// build server exhange, server side +void DH_Server::build(SSL& ssl) +{ + DiffieHellman& dhServer = ssl.useCrypto().use_dh(); + + int pSz, gSz, pubSz; + dhServer.set_sizes(pSz, gSz, pubSz); + dhServer.get_parms(parms_.alloc_p(pSz), parms_.alloc_g(gSz), + parms_.alloc_pub(pubSz)); + + short sigSz = 0; + mySTL::auto_ptr<Auth> auth; + const CertManager& cert = ssl.getCrypto().get_certManager(); + + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) + auth.reset(new (ys) RSA(cert.get_privateKey(), + cert.get_privateKeyLength(), false)); + else { + auth.reset(new (ys) DSS(cert.get_privateKey(), + cert.get_privateKeyLength(), false)); + sigSz += DSS_ENCODED_EXTRA; + } + + + sigSz += auth->get_signatureLength(); + + + length_ = 8; // pLen + gLen + YsLen + SigLen + length_ += pSz + gSz + pubSz + sigSz; + + output_buffer tmp(length_); + byte len[2]; + // P + c16toa(pSz, len); + tmp.write(len, sizeof(len)); + tmp.write(parms_.get_p(), pSz); + // G + c16toa(gSz, len); + tmp.write(len, sizeof(len)); + tmp.write(parms_.get_g(), gSz); + // Ys + c16toa(pubSz, len); + tmp.write(len, sizeof(len)); + tmp.write(parms_.get_pub(), pubSz); + + // Sig + byte hash[FINISHED_SZ]; + MD5 md5; + SHA sha; + signature_ = new (ys) byte[sigSz]; + + const Connection& conn = ssl.getSecurity().get_connection(); + // md5 + md5.update(conn.client_random_, RAN_LEN); + md5.update(conn.server_random_, RAN_LEN); + md5.update(tmp.get_buffer(), tmp.get_size()); + md5.get_digest(hash); + + // sha + sha.update(conn.client_random_, RAN_LEN); + sha.update(conn.server_random_, RAN_LEN); + sha.update(tmp.get_buffer(), tmp.get_size()); + sha.get_digest(&hash[MD5_LEN]); + + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) + auth->sign(signature_, hash, sizeof(hash), + ssl.getCrypto().get_random()); + else { + auth->sign(signature_, &hash[MD5_LEN], SHA_LEN, + ssl.getCrypto().get_random()); + byte encoded[DSS_SIG_SZ + DSS_ENCODED_EXTRA]; + TaoCrypt::EncodeDSA_Signature(signature_, encoded); + memcpy(signature_, encoded, sizeof(encoded)); + } + + c16toa(sigSz, len); + tmp.write(len, sizeof(len)); + tmp.write(signature_, sigSz); + + // key message + keyMessage_ = new (ys) opaque[length_]; + memcpy(keyMessage_, tmp.get_buffer(), tmp.get_size()); +} + + +// read PreMaster secret and decrypt, server side +void EncryptedPreMasterSecret::read(SSL& ssl, input_buffer& input) +{ + const CertManager& cert = ssl.getCrypto().get_certManager(); + RSA rsa(cert.get_privateKey(), cert.get_privateKeyLength(), false); + uint16 cipherLen = rsa.get_cipherLength(); + if (ssl.isTLS()) { + byte len[2]; + input.read(len, sizeof(len)); + ato16(len, cipherLen); + } + alloc(cipherLen); + input.read(secret_, length_); + + opaque preMasterSecret[SECRET_LEN]; + rsa.decrypt(preMasterSecret, secret_, length_, + ssl.getCrypto().get_random()); + + ssl.set_preMaster(preMasterSecret, SECRET_LEN); + ssl.makeMasterSecret(); +} + + +EncryptedPreMasterSecret::EncryptedPreMasterSecret() + : secret_(0), length_(0) +{} + + +EncryptedPreMasterSecret::~EncryptedPreMasterSecret() +{ + delete[] secret_; +} + + +int EncryptedPreMasterSecret::get_length() const +{ + return length_; +} + + +opaque* EncryptedPreMasterSecret::get_clientKey() const +{ + return secret_; +} + + +void EncryptedPreMasterSecret::alloc(int sz) +{ + length_ = sz; + secret_ = new (ys) opaque[sz]; +} + + +// read client's public key, server side +void ClientDiffieHellmanPublic::read(SSL& ssl, input_buffer& input) +{ + DiffieHellman& dh = ssl.useCrypto().use_dh(); + + uint16 keyLength; + byte tmp[2]; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, keyLength); + + alloc(keyLength); + input.read(Yc_, length_); + dh.makeAgreement(Yc_); + + ssl.set_preMaster(dh.get_agreedKey(), keyLength); + ssl.makeMasterSecret(); +} + + +ClientDiffieHellmanPublic::ClientDiffieHellmanPublic() + : length_(0), Yc_(0) +{} + + +ClientDiffieHellmanPublic::~ClientDiffieHellmanPublic() +{ + delete[] Yc_; +} + + +int ClientDiffieHellmanPublic::get_length() const +{ + return length_; +} + + +opaque* ClientDiffieHellmanPublic::get_clientKey() const +{ + return Yc_; +} + + +void ClientDiffieHellmanPublic::alloc(int sz, bool offset) +{ + length_ = sz + (offset ? KEY_OFFSET : 0); + Yc_ = new (ys) opaque[length_]; +} + + +// read server's p, g, public key and sig, client side +void DH_Server::read(SSL& ssl, input_buffer& input) +{ + uint16 length, messageTotal = 6; // pSz + gSz + pubSz + byte tmp[2]; + + // p + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + messageTotal += length; + + input.read(parms_.alloc_p(length), length); + + // g + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + messageTotal += length; + + input.read(parms_.alloc_g(length), length); + + // pub + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + messageTotal += length; + + input.read(parms_.alloc_pub(length), length); + + // save message for hash verify + input_buffer message(messageTotal); + input.set_current(input.get_current() - messageTotal); + input.read(message.get_buffer(), messageTotal); + message.add_size(messageTotal); + + // signature + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, length); + + signature_ = new (ys) byte[length]; + input.read(signature_, length); + + // verify signature + byte hash[FINISHED_SZ]; + MD5 md5; + SHA sha; + + const Connection& conn = ssl.getSecurity().get_connection(); + // md5 + md5.update(conn.client_random_, RAN_LEN); + md5.update(conn.server_random_, RAN_LEN); + md5.update(message.get_buffer(), message.get_size()); + md5.get_digest(hash); + + // sha + sha.update(conn.client_random_, RAN_LEN); + sha.update(conn.server_random_, RAN_LEN); + sha.update(message.get_buffer(), message.get_size()); + sha.get_digest(&hash[MD5_LEN]); + + const CertManager& cert = ssl.getCrypto().get_certManager(); + + if (ssl.getSecurity().get_parms().sig_algo_ == rsa_sa_algo) { + RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); + if (!rsa.verify(hash, sizeof(hash), signature_, length)) + ssl.SetError(verify_error); + } + else { + byte decodedSig[DSS_SIG_SZ]; + length = TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, length); + + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); + if (!dss.verify(&hash[MD5_LEN], SHA_LEN, decodedSig, length)) + ssl.SetError(verify_error); + } + + // save input + ssl.useCrypto().SetDH(new (ys) DiffieHellman(parms_.get_p(), + parms_.get_pSize(), parms_.get_g(), parms_.get_gSize(), + parms_.get_pub(), parms_.get_pubSize(), + ssl.getCrypto().get_random())); +} + + +DH_Server::DH_Server() + : signature_(0), length_(0), keyMessage_(0) +{} + + +DH_Server::~DH_Server() +{ + delete[] keyMessage_; + delete[] signature_; +} + + +int DH_Server::get_length() const +{ + return length_; +} + + +opaque* DH_Server::get_serverKey() const +{ + return keyMessage_; +} + + +// set available suites +Parameters::Parameters(ConnectionEnd ce, const Ciphers& ciphers, + ProtocolVersion pv) : entity_(ce) +{ + pending_ = true; // suite not set yet + + if (ciphers.setSuites_) { // use user set list + suites_size_ = ciphers.suiteSz_; + memcpy(suites_, ciphers.suites_, ciphers.suiteSz_); + SetCipherNames(); + } + else + SetSuites(pv); // defaults +} + + +void Parameters::SetSuites(ProtocolVersion pv) +{ + int i = 0; + // available suites, best first + // when adding more, make sure cipher_names is updated and + // MAX_CIPHER_LIST is big enough + + if (isTLS(pv)) { + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_256_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_256_CBC_SHA; + + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_128_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_128_CBC_SHA; + + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_256_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_AES_128_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_RSA_WITH_3DES_EDE_CBC_RMD160; + + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_256_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_AES_128_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160; + + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_256_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_AES_128_CBC_RMD160; + suites_[i++] = 0x00; + suites_[i++] = TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160; + } + + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_RC4_128_SHA; + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_RC4_128_MD5; + + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = SSL_RSA_WITH_DES_CBC_SHA; + + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA; + + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_RSA_WITH_DES_CBC_SHA; + suites_[i++] = 0x00; + suites_[i++] = SSL_DHE_DSS_WITH_DES_CBC_SHA; + + suites_size_ = i; + + SetCipherNames(); +} + + +void Parameters::SetCipherNames() +{ + const int suites = suites_size_ / 2; + int pos = 0; + + for (int j = 0; j < suites; j++) { + int index = suites_[j*2 + 1]; // every other suite is suite id + int len = strlen(cipher_names[index]); + memcpy(&cipher_list_[pos], cipher_names[index], len); + pos += len; + cipher_list_[pos++] = ':'; + } + if (suites) + cipher_list_[--pos] = 0; +} + + +// input operator for RecordLayerHeader, adjust stream +input_buffer& operator>>(input_buffer& input, RecordLayerHeader& hdr) +{ + hdr.type_ = ContentType(input[AUTO]); + hdr.version_.major_ = input[AUTO]; + hdr.version_.minor_ = input[AUTO]; + + // length + byte tmp[2]; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, hdr.length_); + + return input; +} + + +// output operator for RecordLayerHeader +output_buffer& operator<<(output_buffer& output, const RecordLayerHeader& hdr) +{ + output[AUTO] = hdr.type_; + output[AUTO] = hdr.version_.major_; + output[AUTO] = hdr.version_.minor_; + + // length + byte tmp[2]; + c16toa(hdr.length_, tmp); + output[AUTO] = tmp[0]; + output[AUTO] = tmp[1]; + + return output; +} + + +// virtual input operator for Messages +input_buffer& operator>>(input_buffer& input, Message& msg) +{ + return msg.set(input); +} + +// virtual output operator for Messages +output_buffer& operator<<(output_buffer& output, const Message& msg) +{ + return msg.get(output); +} + + +// input operator for HandShakeHeader +input_buffer& operator>>(input_buffer& input, HandShakeHeader& hs) +{ + hs.type_ = HandShakeType(input[AUTO]); + + hs.length_[0] = input[AUTO]; + hs.length_[1] = input[AUTO]; + hs.length_[2] = input[AUTO]; + + return input; +} + + +// output operator for HandShakeHeader +output_buffer& operator<<(output_buffer& output, const HandShakeHeader& hdr) +{ + output[AUTO] = hdr.type_; + output.write(hdr.length_, sizeof(hdr.length_)); + return output; +} + + +// HandShake Header Processing function +void HandShakeHeader::Process(input_buffer& input, SSL& ssl) +{ + ssl.verifyState(*this); + const HandShakeFactory& hsf = ssl.getFactory().getHandShake(); + mySTL::auto_ptr<HandShakeBase> hs(hsf.CreateObject(type_)); + if (!hs.get()) { + ssl.SetError(factory_error); + return; + } + hashHandShake(ssl, input, c24to32(length_)); + + input >> *hs; + hs->Process(input, ssl); +} + + +ContentType HandShakeHeader::get_type() const +{ + return handshake; +} + + +uint16 HandShakeHeader::get_length() const +{ + return c24to32(length_); +} + + +HandShakeType HandShakeHeader::get_handshakeType() const +{ + return type_; +} + + +void HandShakeHeader::set_type(HandShakeType hst) +{ + type_ = hst; +} + + +void HandShakeHeader::set_length(uint32 u32) +{ + c32to24(u32, length_); +} + + +input_buffer& HandShakeHeader::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& HandShakeHeader::get(output_buffer& out) const +{ + return out << *this; +} + + + +int HandShakeBase::get_length() const +{ + return length_; +} + + +void HandShakeBase::set_length(int l) +{ + length_ = l; +} + + +// for building buffer's type field +HandShakeType HandShakeBase::get_type() const +{ + return no_shake; +} + + +input_buffer& HandShakeBase::set(input_buffer& in) +{ + return in; +} + + +output_buffer& HandShakeBase::get(output_buffer& out) const +{ + return out; +} + + +void HandShakeBase::Process(input_buffer&, SSL&) +{} + + +input_buffer& HelloRequest::set(input_buffer& in) +{ + return in; +} + + +output_buffer& HelloRequest::get(output_buffer& out) const +{ + return out; +} + + +void HelloRequest::Process(input_buffer&, SSL&) +{} + + +HandShakeType HelloRequest::get_type() const +{ + return hello_request; +} + + +// input operator for CipherSpec +input_buffer& operator>>(input_buffer& input, ChangeCipherSpec& cs) +{ + cs.type_ = CipherChoice(input[AUTO]); + return input; +} + +// output operator for CipherSpec +output_buffer& operator<<(output_buffer& output, const ChangeCipherSpec& cs) +{ + output[AUTO] = cs.type_; + return output; +} + + +ChangeCipherSpec::ChangeCipherSpec() + : type_(change_cipher_spec_choice) +{} + + +input_buffer& ChangeCipherSpec::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& ChangeCipherSpec::get(output_buffer& out) const +{ + return out << *this; +} + + +ContentType ChangeCipherSpec::get_type() const +{ + return change_cipher_spec; +} + + +uint16 ChangeCipherSpec::get_length() const +{ + return SIZEOF_ENUM; +} + + +// CipherSpec processing handler +void ChangeCipherSpec::Process(input_buffer&, SSL& ssl) +{ + ssl.useSecurity().use_parms().pending_ = false; + if (ssl.getSecurity().get_resuming()) { + if (ssl.getSecurity().get_parms().entity_ == client_end) + buildFinished(ssl, ssl.useHashes().use_verify(), server); // server + } + else if (ssl.getSecurity().get_parms().entity_ == server_end) + buildFinished(ssl, ssl.useHashes().use_verify(), client); // client +} + + +Alert::Alert(AlertLevel al, AlertDescription ad) + : level_(al), description_(ad) +{} + + +ContentType Alert::get_type() const +{ + return alert; +} + + +uint16 Alert::get_length() const +{ + return SIZEOF_ENUM * 2; +} + + +input_buffer& Alert::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& Alert::get(output_buffer& out) const +{ + return out << *this; +} + + +// input operator for Alert +input_buffer& operator>>(input_buffer& input, Alert& a) +{ + a.level_ = AlertLevel(input[AUTO]); + a.description_ = AlertDescription(input[AUTO]); + + return input; +} + + +// output operator for Alert +output_buffer& operator<<(output_buffer& output, const Alert& a) +{ + output[AUTO] = a.level_; + output[AUTO] = a.description_; + return output; +} + + +// Alert processing handler +void Alert::Process(input_buffer& input, SSL& ssl) +{ + if (ssl.getSecurity().get_parms().pending_ == false) { // encrypted alert + int aSz = get_length(); // alert size already read on input + opaque verify[SHA_LEN]; + const opaque* data = input.get_buffer() + input.get_current() - aSz; + + if (ssl.isTLS()) + TLS_hmac(ssl, verify, data, aSz, alert, true); + else + hmac(ssl, verify, data, aSz, alert, true); + + // read mac and fill + int digestSz = ssl.getCrypto().get_digest().get_digestSize(); + opaque mac[SHA_LEN]; + input.read(mac, digestSz); + + opaque fill; + int padSz = ssl.getSecurity().get_parms().encrypt_size_ - aSz - + digestSz; + for (int i = 0; i < padSz; i++) + fill = input[AUTO]; + + // verify + if (memcmp(mac, verify, digestSz)) { + ssl.SetError(verify_error); + return; + } + } + if (level_ == fatal) { + ssl.useStates().useRecord() = recordNotReady; + ssl.useStates().useHandShake() = handShakeNotReady; + ssl.SetError(YasslError(description_)); + } +} + + +Data::Data() + : length_(0), buffer_(0), write_buffer_(0) +{} + + +Data::Data(uint16 len, opaque* b) + : length_(len), buffer_(b), write_buffer_(0) +{} + + +Data::Data(uint16 len, const opaque* w) + : length_(len), buffer_(0), write_buffer_(w) +{} + +input_buffer& Data::set(input_buffer& in) +{ + return in; +} + + +output_buffer& Data::get(output_buffer& out) const +{ + return out << *this; +} + + +ContentType Data::get_type() const +{ + return application_data; +} + + +uint16 Data::get_length() const +{ + return length_; +} + + +const opaque* Data::get_buffer() const +{ + return write_buffer_; +} + + +void Data::set_length(uint16 l) +{ + length_ = l; +} + +opaque* Data::set_buffer() +{ + return buffer_; +} + + +// output operator for Data +output_buffer& operator<<(output_buffer& output, const Data& data) +{ + output.write(data.write_buffer_, data.length_); + return output; +} + + +// Process handler for Data +void Data::Process(input_buffer& input, SSL& ssl) +{ + int msgSz = ssl.getSecurity().get_parms().encrypt_size_; + int pad = 0, padByte = 0; + if (ssl.getSecurity().get_parms().cipher_type_ == block) { + pad = *(input.get_buffer() + input.get_current() + msgSz - 1); + padByte = 1; + } + int digestSz = ssl.getCrypto().get_digest().get_digestSize(); + int dataSz = msgSz - digestSz - pad - padByte; + opaque verify[SHA_LEN]; + + // read data + if (dataSz) { + input_buffer* data; + ssl.addData(data = new (ys) input_buffer(dataSz)); + input.read(data->get_buffer(), dataSz); + data->add_size(dataSz); + + if (ssl.isTLS()) + TLS_hmac(ssl, verify, data->get_buffer(), dataSz, application_data, + true); + else + hmac(ssl, verify, data->get_buffer(), dataSz, application_data, + true); + } + + // read mac and fill + opaque mac[SHA_LEN]; + opaque fill; + input.read(mac, digestSz); + for (int i = 0; i < pad; i++) + fill = input[AUTO]; + if (padByte) + fill = input[AUTO]; + + // verify + if (dataSz) { + if (memcmp(mac, verify, digestSz)) { + ssl.SetError(verify_error); + return; + } + } + else + ssl.get_SEQIncrement(true); // even though no data, increment verify +} + + +// virtual input operator for HandShakes +input_buffer& operator>>(input_buffer& input, HandShakeBase& hs) +{ + return hs.set(input); +} + + +// virtual output operator for HandShakes +output_buffer& operator<<(output_buffer& output, const HandShakeBase& hs) +{ + return hs.get(output); +} + + +Certificate::Certificate(const x509* cert) : cert_(cert) +{ + set_length(cert_->get_length() + 2 * CERT_HEADER); // list and cert size +} + + +const opaque* Certificate::get_buffer() const +{ + return cert_->get_buffer(); +} + + +// output operator for Certificate +output_buffer& operator<<(output_buffer& output, const Certificate& cert) +{ + uint sz = cert.get_length() - 2 * CERT_HEADER; + opaque tmp[CERT_HEADER]; + + c32to24(sz + CERT_HEADER, tmp); + output.write(tmp, CERT_HEADER); + c32to24(sz, tmp); + output.write(tmp, CERT_HEADER); + output.write(cert.get_buffer(), sz); + + return output; +} + + +// certificate processing handler +void Certificate::Process(input_buffer& input, SSL& ssl) +{ + CertManager& cm = ssl.useCrypto().use_certManager(); + + uint32 list_sz; + byte tmp[3]; + + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + tmp[2] = input[AUTO]; + c24to32(tmp, list_sz); + + while (list_sz) { + // cert size + uint32 cert_sz; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + tmp[2] = input[AUTO]; + c24to32(tmp, cert_sz); + + x509* myCert; + cm.AddPeerCert(myCert = new (ys) x509(cert_sz)); + input.read(myCert->use_buffer(), myCert->get_length()); + + list_sz -= cert_sz + CERT_HEADER; + } + if (int err = cm.Validate()) + ssl.SetError(YasslError(err)); + else if (ssl.getSecurity().get_parms().entity_ == client_end) + ssl.useStates().useClient() = serverCertComplete; +} + + +Certificate::Certificate() + : cert_(0) +{} + + +input_buffer& Certificate::set(input_buffer& in) +{ + return in; +} + + +output_buffer& Certificate::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType Certificate::get_type() const +{ + return certificate; +} + + +ServerDHParams::ServerDHParams() + : pSz_(0), gSz_(0), pubSz_(0), p_(0), g_(0), Ys_(0) +{} + + +ServerDHParams::~ServerDHParams() +{ + delete[] Ys_; + delete[] g_; + delete[] p_; +} + + +int ServerDHParams::get_pSize() const +{ + return pSz_; +} + + +int ServerDHParams::get_gSize() const +{ + return gSz_; +} + + +int ServerDHParams::get_pubSize() const +{ + return pubSz_; +} + + +const opaque* ServerDHParams::get_p() const +{ + return p_; +} + + +const opaque* ServerDHParams::get_g() const +{ + return g_; +} + + +const opaque* ServerDHParams::get_pub() const +{ + return Ys_; +} + + +opaque* ServerDHParams::alloc_p(int sz) +{ + p_ = new (ys) opaque[pSz_ = sz]; + return p_; +} + + +opaque* ServerDHParams::alloc_g(int sz) +{ + g_ = new (ys) opaque[gSz_ = sz]; + return g_; +} + + +opaque* ServerDHParams::alloc_pub(int sz) +{ + Ys_ = new (ys) opaque[pubSz_ = sz]; + return Ys_; +} + + +int ServerKeyBase::get_length() const +{ + return 0; +} + + +opaque* ServerKeyBase::get_serverKey() const +{ + return 0; +} + + +// input operator for ServerHello +input_buffer& operator>>(input_buffer& input, ServerHello& hello) +{ + // Protocol + hello.server_version_.major_ = input[AUTO]; + hello.server_version_.minor_ = input[AUTO]; + + // Random + input.read(hello.random_, RAN_LEN); + + // Session + hello.id_len_ = input[AUTO]; + input.read(hello.session_id_, ID_LEN); + + // Suites + hello.cipher_suite_[0] = input[AUTO]; + hello.cipher_suite_[1] = input[AUTO]; + + // Compression + hello.compression_method_ = CompressionMethod(input[AUTO]); + + return input; +} + + +// output operator for ServerHello +output_buffer& operator<<(output_buffer& output, const ServerHello& hello) +{ + // Protocol + output[AUTO] = hello.server_version_.major_; + output[AUTO] = hello.server_version_.minor_; + + // Random + output.write(hello.random_, RAN_LEN); + + // Session + output[AUTO] = hello.id_len_; + output.write(hello.session_id_, ID_LEN); + + // Suites + output[AUTO] = hello.cipher_suite_[0]; + output[AUTO] = hello.cipher_suite_[1]; + + // Compression + output[AUTO] = hello.compression_method_; + + return output; +} + + +// Server Hello processing handler +void ServerHello::Process(input_buffer&, SSL& ssl) +{ + ssl.set_pending(cipher_suite_[1]); + ssl.set_random(random_, server_end); + ssl.set_sessionID(session_id_); + + if (ssl.getSecurity().get_resuming()) + if (memcmp(session_id_, ssl.getSecurity().get_resume().GetID(), + ID_LEN) == 0) { + ssl.set_masterSecret(ssl.getSecurity().get_resume().GetSecret()); + if (ssl.isTLS()) + ssl.deriveTLSKeys(); + else + ssl.deriveKeys(); + ssl.useStates().useClient() = serverHelloDoneComplete; + return; + } + else { + ssl.useSecurity().set_resuming(false); + ssl.useLog().Trace("server denied resumption"); + } + ssl.useStates().useClient() = serverHelloComplete; +} + + +ServerHello::ServerHello() +{ + memset(random_, 0, RAN_LEN); + memset(session_id_, 0, ID_LEN); +} + + +ServerHello::ServerHello(ProtocolVersion pv) + : server_version_(pv) +{ + memset(random_, 0, RAN_LEN); + memset(session_id_, 0, ID_LEN); +} + + +input_buffer& ServerHello::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& ServerHello::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ServerHello::get_type() const +{ + return server_hello; +} + + +const opaque* ServerHello::get_random() const +{ + return random_; +} + + +// Server Hello Done processing handler +void ServerHelloDone::Process(input_buffer&, SSL& ssl) +{ + ssl.useStates().useClient() = serverHelloDoneComplete; +} + + +ServerHelloDone::ServerHelloDone() +{ + set_length(0); +} + + +input_buffer& ServerHelloDone::set(input_buffer& in) +{ + return in; +} + + +output_buffer& ServerHelloDone::get(output_buffer& out) const +{ + return out; +} + + +HandShakeType ServerHelloDone::get_type() const +{ + return server_hello_done; +} + + +int ClientKeyBase::get_length() const +{ + return 0; +} + + +opaque* ClientKeyBase::get_clientKey() const +{ + return 0; +} + + +// input operator for Client Hello +input_buffer& operator>>(input_buffer& input, ClientHello& hello) +{ + // Protocol + hello.client_version_.major_ = input[AUTO]; + hello.client_version_.minor_ = input[AUTO]; + + // Random + input.read(hello.random_, RAN_LEN); + + // Session + hello.id_len_ = input[AUTO]; + if (hello.id_len_) input.read(hello.session_id_, ID_LEN); + + // Suites + byte tmp[2]; + tmp[0] = input[AUTO]; + tmp[1] = input[AUTO]; + ato16(tmp, hello.suite_len_); + input.read(hello.cipher_suites_, hello.suite_len_); + + // Compression + hello.comp_len_ = input[AUTO]; + hello.compression_methods_ = CompressionMethod(input[AUTO]); + + return input; +} + + +// output operaotr for Client Hello +output_buffer& operator<<(output_buffer& output, const ClientHello& hello) +{ + // Protocol + output[AUTO] = hello.client_version_.major_; + output[AUTO] = hello.client_version_.minor_; + + // Random + output.write(hello.random_, RAN_LEN); + + // Session + output[AUTO] = hello.id_len_; + if (hello.id_len_) output.write(hello.session_id_, ID_LEN); + + // Suites + byte tmp[2]; + c16toa(hello.suite_len_, tmp); + output[AUTO] = tmp[0]; + output[AUTO] = tmp[1]; + output.write(hello.cipher_suites_, hello.suite_len_); + + // Compression + output[AUTO] = hello.comp_len_; + output[AUTO] = hello.compression_methods_; + + return output; +} + + +// Client Hello processing handler +void ClientHello::Process(input_buffer&, SSL& ssl) +{ + if (ssl.isTLS() && client_version_.minor_ == 0) { + ssl.useSecurity().use_connection().TurnOffTLS(); + ProtocolVersion pv = ssl.getSecurity().get_connection().version_; + ssl.useSecurity().use_parms().SetSuites(pv); // reset w/ SSL suites + } + ssl.set_random(random_, client_end); + + while (id_len_) { // trying to resume + SSL_SESSION* session = GetSessions().lookup(session_id_); + if (!session) { + ssl.useLog().Trace("session lookup failed"); + break; + } + ssl.set_session(session); + ssl.useSecurity().set_resuming(true); + ssl.matchSuite(session->GetSuite(), SUITE_LEN); + ssl.set_pending(ssl.getSecurity().get_parms().suite_[1]); + ssl.set_masterSecret(session->GetSecret()); + + opaque serverRandom[RAN_LEN]; + ssl.getCrypto().get_random().Fill(serverRandom, sizeof(serverRandom)); + ssl.set_random(serverRandom, server_end); + if (ssl.isTLS()) + ssl.deriveTLSKeys(); + else + ssl.deriveKeys(); + ssl.useStates().useServer() = clientKeyExchangeComplete; + return; + } + ssl.matchSuite(cipher_suites_, suite_len_); + ssl.set_pending(ssl.getSecurity().get_parms().suite_[1]); + + ssl.useStates().useServer() = clientHelloComplete; +} + + +input_buffer& ClientHello::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& ClientHello::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ClientHello::get_type() const +{ + return client_hello; +} + + +const opaque* ClientHello::get_random() const +{ + return random_; +} + + +ClientHello::ClientHello() +{ + memset(random_, 0, RAN_LEN); +} + + +ClientHello::ClientHello(ProtocolVersion pv) + : client_version_(pv) +{ + memset(random_, 0, RAN_LEN); +} + + +// output operator for ServerKeyExchange +output_buffer& operator<<(output_buffer& output, const ServerKeyExchange& sk) +{ + output.write(sk.getKey(), sk.getKeyLength()); + return output; +} + + +// Server Key Exchange processing handler +void ServerKeyExchange::Process(input_buffer& input, SSL& ssl) +{ + createKey(ssl); + if (ssl.GetError()) return; + server_key_->read(ssl, input); + + ssl.useStates().useClient() = serverKeyExchangeComplete; +} + + +ServerKeyExchange::ServerKeyExchange(SSL& ssl) +{ + createKey(ssl); +} + + +ServerKeyExchange::ServerKeyExchange() + : server_key_(0) +{} + + +ServerKeyExchange::~ServerKeyExchange() +{ + delete server_key_; +} + + +void ServerKeyExchange::build(SSL& ssl) +{ + server_key_->build(ssl); + set_length(server_key_->get_length()); +} + + +const opaque* ServerKeyExchange::getKey() const +{ + return server_key_->get_serverKey(); +} + + +int ServerKeyExchange::getKeyLength() const +{ + return server_key_->get_length(); +} + + +input_buffer& ServerKeyExchange::set(input_buffer& in) +{ + return in; // process does +} + + +output_buffer& ServerKeyExchange::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ServerKeyExchange::get_type() const +{ + return server_key_exchange; +} + + +// CertificateRequest +CertificateRequest::CertificateRequest() + : typeTotal_(0) +{ + memset(certificate_types_, 0, sizeof(certificate_types_)); +} + + +CertificateRequest::~CertificateRequest() +{ + + mySTL::for_each(certificate_authorities_.begin(), + certificate_authorities_.end(), + del_ptr_zero()) ; +} + + +void CertificateRequest::Build() +{ + certificate_types_[0] = rsa_sign; + certificate_types_[1] = dss_sign; + + typeTotal_ = 2; + + uint16 authCount = 0; + uint16 authSz = 0; + + for (int j = 0; j < authCount; j++) { + int sz = REQUEST_HEADER + MIN_DIS_SIZE; + DistinguishedName dn; + certificate_authorities_.push_back(dn = new (ys) byte[sz]); + + opaque tmp[REQUEST_HEADER]; + c16toa(MIN_DIS_SIZE, tmp); + memcpy(dn, tmp, sizeof(tmp)); + + // fill w/ junk for now + memcpy(dn, tmp, MIN_DIS_SIZE); + authSz += sz; + } + + set_length(SIZEOF_ENUM + typeTotal_ + REQUEST_HEADER + authSz); +} + + +input_buffer& CertificateRequest::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& CertificateRequest::get(output_buffer& out) const +{ + return out << *this; +} + + +// input operator for CertificateRequest +input_buffer& operator>>(input_buffer& input, CertificateRequest& request) +{ + // types + request.typeTotal_ = input[AUTO]; + for (int i = 0; i < request.typeTotal_; i++) + request.certificate_types_[i] = ClientCertificateType(input[AUTO]); + + byte tmp[REQUEST_HEADER]; + input.read(tmp, sizeof(tmp)); + uint16 sz; + ato16(tmp, sz); + + // authorities + while (sz) { + uint16 dnSz; + input.read(tmp, sizeof(tmp)); + ato16(tmp, dnSz); + + DistinguishedName dn; + request.certificate_authorities_.push_back(dn = new (ys) + byte[REQUEST_HEADER + dnSz]); + memcpy(dn, tmp, REQUEST_HEADER); + input.read(&dn[REQUEST_HEADER], dnSz); + + sz -= dnSz + REQUEST_HEADER; + } + + return input; +} + + +// output operator for CertificateRequest +output_buffer& operator<<(output_buffer& output, + const CertificateRequest& request) +{ + // types + output[AUTO] = request.typeTotal_; + for (int i = 0; i < request.typeTotal_; i++) + output[AUTO] = request.certificate_types_[i]; + + // authorities + opaque tmp[REQUEST_HEADER]; + c16toa(request.get_length() - SIZEOF_ENUM - + request.typeTotal_ - REQUEST_HEADER, tmp); + output.write(tmp, sizeof(tmp)); + + mySTL::list<DistinguishedName>::const_iterator first = + request.certificate_authorities_.begin(); + mySTL::list<DistinguishedName>::const_iterator last = + request.certificate_authorities_.end(); + while (first != last) { + uint16 sz; + ato16(*first, sz); + output.write(*first, sz + REQUEST_HEADER); + + ++first; + } + + return output; +} + + +// CertificateRequest processing handler +void CertificateRequest::Process(input_buffer&, SSL& ssl) +{ + ssl.useCrypto().use_certManager().setSendVerify(); +} + + +HandShakeType CertificateRequest::get_type() const +{ + return certificate_request; +} + + +// CertificateVerify +CertificateVerify::CertificateVerify() : signature_(0) +{} + + +CertificateVerify::~CertificateVerify() +{ + delete[] signature_; +} + + +void CertificateVerify::Build(SSL& ssl) +{ + build_certHashes(ssl, hashes_); + + uint16 sz = 0; + byte len[VERIFY_HEADER]; + mySTL::auto_ptr<byte> sig; + + // sign + const CertManager& cert = ssl.getCrypto().get_certManager(); + if (cert.get_keyType() == rsa_sa_algo) { + RSA rsa(cert.get_privateKey(), cert.get_privateKeyLength(), false); + + sz = rsa.get_cipherLength() + VERIFY_HEADER; + sig.reset(new (ys) byte[sz]); + + c16toa(sz - VERIFY_HEADER, len); + memcpy(sig.get(), len, VERIFY_HEADER); + rsa.sign(sig.get() + VERIFY_HEADER, hashes_.md5_, sizeof(Hashes), + ssl.getCrypto().get_random()); + } + else { // DSA + DSS dss(cert.get_privateKey(), cert.get_privateKeyLength(), false); + + sz = DSS_SIG_SZ + DSS_ENCODED_EXTRA + VERIFY_HEADER; + sig.reset(new (ys) byte[sz]); + + c16toa(sz - VERIFY_HEADER, len); + memcpy(sig.get(), len, VERIFY_HEADER); + dss.sign(sig.get() + VERIFY_HEADER, hashes_.sha_, SHA_LEN, + ssl.getCrypto().get_random()); + + byte encoded[DSS_SIG_SZ + DSS_ENCODED_EXTRA]; + TaoCrypt::EncodeDSA_Signature(sig.get() + VERIFY_HEADER, encoded); + memcpy(sig.get() + VERIFY_HEADER, encoded, sizeof(encoded)); + } + set_length(sz); + signature_ = sig.release(); +} + + +input_buffer& CertificateVerify::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& CertificateVerify::get(output_buffer& out) const +{ + return out << *this; +} + + +// input operator for CertificateVerify +input_buffer& operator>>(input_buffer& input, CertificateVerify& request) +{ + byte tmp[VERIFY_HEADER]; + input.read(tmp, sizeof(tmp)); + + uint16 sz = 0; + ato16(tmp, sz); + request.set_length(sz); + + request.signature_ = new (ys) byte[sz]; + input.read(request.signature_, sz); + + return input; +} + + +// output operator for CertificateVerify +output_buffer& operator<<(output_buffer& output, + const CertificateVerify& verify) +{ + output.write(verify.signature_, verify.get_length()); + + return output; +} + + +// CertificateVerify processing handler +void CertificateVerify::Process(input_buffer&, SSL& ssl) +{ + const Hashes& hashVerify = ssl.getHashes().get_certVerify(); + const CertManager& cert = ssl.getCrypto().get_certManager(); + + if (cert.get_peerKeyType() == rsa_sa_algo) { + RSA rsa(cert.get_peerKey(), cert.get_peerKeyLength()); + + if (!rsa.verify(hashVerify.md5_, sizeof(hashVerify), signature_, + get_length())) + ssl.SetError(verify_error); + } + else { // DSA + byte decodedSig[DSS_SIG_SZ]; + TaoCrypt::DecodeDSA_Signature(decodedSig, signature_, get_length()); + + DSS dss(cert.get_peerKey(), cert.get_peerKeyLength()); + if (!dss.verify(hashVerify.sha_, SHA_LEN, decodedSig, get_length())) + ssl.SetError(verify_error); + } +} + + +HandShakeType CertificateVerify::get_type() const +{ + return certificate_verify; +} + + +// output operator for ClientKeyExchange +output_buffer& operator<<(output_buffer& output, const ClientKeyExchange& ck) +{ + output.write(ck.getKey(), ck.getKeyLength()); + return output; +} + + +// Client Key Exchange processing handler +void ClientKeyExchange::Process(input_buffer& input, SSL& ssl) +{ + createKey(ssl); + if (ssl.GetError()) return; + client_key_->read(ssl, input); + + if (ssl.getCrypto().get_certManager().verifyPeer()) + build_certHashes(ssl, ssl.useHashes().use_certVerify()); + + ssl.useStates().useServer() = clientKeyExchangeComplete; +} + + +ClientKeyExchange::ClientKeyExchange(SSL& ssl) +{ + createKey(ssl); +} + + +ClientKeyExchange::ClientKeyExchange() + : client_key_(0) +{} + + +ClientKeyExchange::~ClientKeyExchange() +{ + delete client_key_; +} + + +void ClientKeyExchange::build(SSL& ssl) +{ + client_key_->build(ssl); + set_length(client_key_->get_length()); +} + +const opaque* ClientKeyExchange::getKey() const +{ + return client_key_->get_clientKey(); +} + + +int ClientKeyExchange::getKeyLength() const +{ + return client_key_->get_length(); +} + + +input_buffer& ClientKeyExchange::set(input_buffer& in) +{ + return in; +} + + +output_buffer& ClientKeyExchange::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType ClientKeyExchange::get_type() const +{ + return client_key_exchange; +} + + +// input operator for Finished +input_buffer& operator>>(input_buffer& input, Finished&) +{ + /* do in process */ + + return input; +} + +// output operator for Finished +output_buffer& operator<<(output_buffer& output, const Finished& fin) +{ + if (fin.get_length() == FINISHED_SZ) { + output.write(fin.hashes_.md5_, MD5_LEN); + output.write(fin.hashes_.sha_, SHA_LEN); + } + else // TLS_FINISHED_SZ + output.write(fin.hashes_.md5_, TLS_FINISHED_SZ); + + return output; +} + + +// Finished processing handler +void Finished::Process(input_buffer& input, SSL& ssl) +{ + // verify hashes + const Finished& verify = ssl.getHashes().get_verify(); + uint finishedSz = ssl.isTLS() ? TLS_FINISHED_SZ : FINISHED_SZ; + + input.read(hashes_.md5_, finishedSz); + + if (memcmp(&hashes_, &verify.hashes_, finishedSz)) { + ssl.SetError(verify_error); + return; + } + + // read verify mac + opaque verifyMAC[SHA_LEN]; + uint macSz = finishedSz + HANDSHAKE_HEADER; + + if (ssl.isTLS()) + TLS_hmac(ssl, verifyMAC, input.get_buffer() + input.get_current() + - macSz, macSz, handshake, true); + else + hmac(ssl, verifyMAC, input.get_buffer() + input.get_current() - macSz, + macSz, handshake, true); + + // read mac and fill + opaque mac[SHA_LEN]; // max size + int digestSz = ssl.getCrypto().get_digest().get_digestSize(); + input.read(mac, digestSz); + + opaque fill; + int padSz = ssl.getSecurity().get_parms().encrypt_size_ - + HANDSHAKE_HEADER - finishedSz - digestSz; + for (int i = 0; i < padSz; i++) + fill = input[AUTO]; + + // verify mac + if (memcmp(mac, verifyMAC, digestSz)) { + ssl.SetError(verify_error); + return; + } + + // update states + ssl.useStates().useHandShake() = handShakeReady; + if (ssl.getSecurity().get_parms().entity_ == client_end) + ssl.useStates().useClient() = serverFinishedComplete; + else + ssl.useStates().useServer() = clientFinishedComplete; +} + + +Finished::Finished() +{ + set_length(FINISHED_SZ); +} + + +uint8* Finished::set_md5() +{ + return hashes_.md5_; +} + + +uint8* Finished::set_sha() +{ + return hashes_.sha_; +} + + +input_buffer& Finished::set(input_buffer& in) +{ + return in >> *this; +} + + +output_buffer& Finished::get(output_buffer& out) const +{ + return out << *this; +} + + +HandShakeType Finished::get_type() const +{ + return finished; +} + + +void clean(volatile opaque* p, uint sz, RandomPool& ran) +{ + uint i(0); + + for (i = 0; i < sz; ++i) + p[i] = 0; + + ran.Fill(const_cast<opaque*>(p), sz); + + for (i = 0; i < sz; ++i) + p[i] = 0; +} + + + +Connection::Connection(ProtocolVersion v, RandomPool& ran) + : pre_master_secret_(0), sequence_number_(0), peer_sequence_number_(0), + pre_secret_len_(0), send_server_key_(false), master_clean_(false), + TLS_(v.major_ >= 3 && v.minor_ >= 1), version_(v), random_(ran) +{} + + +Connection::~Connection() +{ + CleanMaster(); CleanPreMaster(); delete[] pre_master_secret_; +} + + +void Connection::AllocPreSecret(uint sz) +{ + pre_master_secret_ = new (ys) opaque[pre_secret_len_ = sz]; +} + + +void Connection::TurnOffTLS() +{ + TLS_ = false; + version_.minor_ = 0; +} + + +// wipeout master secret +void Connection::CleanMaster() +{ + if (!master_clean_) { + volatile opaque* p = master_secret_; + clean(p, SECRET_LEN, random_); + master_clean_ = true; + } +} + + +// wipeout pre master secret +void Connection::CleanPreMaster() +{ + if (pre_master_secret_) { + volatile opaque* p = pre_master_secret_; + clean(p, pre_secret_len_, random_); + + delete[] pre_master_secret_; + pre_master_secret_ = 0; + } +} + + +// Create functions for message factory +Message* CreateCipherSpec() { return new (ys) ChangeCipherSpec; } +Message* CreateAlert() { return new (ys) Alert; } +Message* CreateHandShake() { return new (ys) HandShakeHeader; } +Message* CreateData() { return new (ys) Data; } + +// Create functions for handshake factory +HandShakeBase* CreateHelloRequest() { return new (ys) HelloRequest; } +HandShakeBase* CreateClientHello() { return new (ys) ClientHello; } +HandShakeBase* CreateServerHello() { return new (ys) ServerHello; } +HandShakeBase* CreateCertificate() { return new (ys) Certificate; } +HandShakeBase* CreateServerKeyExchange() { return new (ys) ServerKeyExchange;} +HandShakeBase* CreateCertificateRequest() { return new (ys) + CertificateRequest; } +HandShakeBase* CreateServerHelloDone() { return new (ys) ServerHelloDone; } +HandShakeBase* CreateCertificateVerify() { return new (ys) CertificateVerify;} +HandShakeBase* CreateClientKeyExchange() { return new (ys) ClientKeyExchange;} +HandShakeBase* CreateFinished() { return new (ys) Finished; } + +// Create functions for server key exchange factory +ServerKeyBase* CreateRSAServerKEA() { return new (ys) RSA_Server; } +ServerKeyBase* CreateDHServerKEA() { return new (ys) DH_Server; } +ServerKeyBase* CreateFortezzaServerKEA() { return new (ys) Fortezza_Server; } + +// Create functions for client key exchange factory +ClientKeyBase* CreateRSAClient() { return new (ys) + EncryptedPreMasterSecret; } +ClientKeyBase* CreateDHClient() { return new (ys) + ClientDiffieHellmanPublic; } +ClientKeyBase* CreateFortezzaClient() { return new (ys) FortezzaKeys; } + + +// Constructor calls this to Register compile time callbacks +void InitMessageFactory(MessageFactory& mf) +{ + mf.Reserve(4); + mf.Register(alert, CreateAlert); + mf.Register(change_cipher_spec, CreateCipherSpec); + mf.Register(handshake, CreateHandShake); + mf.Register(application_data, CreateData); +} + + +// Constructor calls this to Register compile time callbacks +void InitHandShakeFactory(HandShakeFactory& hsf) +{ + hsf.Reserve(10); + hsf.Register(hello_request, CreateHelloRequest); + hsf.Register(client_hello, CreateClientHello); + hsf.Register(server_hello, CreateServerHello); + hsf.Register(certificate, CreateCertificate); + hsf.Register(server_key_exchange, CreateServerKeyExchange); + hsf.Register(certificate_request, CreateCertificateRequest); + hsf.Register(server_hello_done, CreateServerHelloDone); + hsf.Register(certificate_verify, CreateCertificateVerify); + hsf.Register(client_key_exchange, CreateClientKeyExchange); + hsf.Register(finished, CreateFinished); +} + + +// Constructor calls this to Register compile time callbacks +void InitServerKeyFactory(ServerKeyFactory& skf) +{ + skf.Reserve(3); + skf.Register(rsa_kea, CreateRSAServerKEA); + skf.Register(diffie_hellman_kea, CreateDHServerKEA); + skf.Register(fortezza_kea, CreateFortezzaServerKEA); +} + + +// Constructor calls this to Register compile time callbacks +void InitClientKeyFactory(ClientKeyFactory& ckf) +{ + ckf.Reserve(3); + ckf.Register(rsa_kea, CreateRSAClient); + ckf.Register(diffie_hellman_kea, CreateDHClient); + ckf.Register(fortezza_kea, CreateFortezzaClient); +} + +} // namespace + +#ifdef __GNUC__ +template class mySTL::list<unsigned char*>; +template yaSSL::del_ptr_zero mySTL::for_each(mySTL::list<unsigned char*>::iterator, mySTL::list<unsigned char*>::iterator, yaSSL::del_ptr_zero); +template mySTL::pair<int, yaSSL::Message* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*); +template mySTL::pair<int, yaSSL::HandShakeBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*); +template void mySTL::destroy<mySTL::pair<int, yaSSL::Message* (*)()>*>(mySTL::pair<int, yaSSL::Message* (*)()>*, mySTL::pair<int, yaSSL::Message* (*)()>*); +template void mySTL::destroy<mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*>(mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*, mySTL::pair<int, yaSSL::HandShakeBase* (*)()>*); +template mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*); +template void mySTL::destroy<mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ServerKeyBase* (*)()>*); +template mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>* mySTL::uninit_copy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*); +template class mySTL::list<TaoCrypt::Signer*>; +template class mySTL::list<yaSSL::SSL_SESSION*>; +template class mySTL::list<yaSSL::input_buffer*>; +template class mySTL::list<yaSSL::output_buffer*>; +template class mySTL::list<yaSSL::x509*>; +template void mySTL::destroy<mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*>(mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*, mySTL::pair<int, yaSSL::ClientKeyBase* (*)()>*); +template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<TaoCrypt::Signer*>::iterator, mySTL::list<TaoCrypt::Signer*>::iterator, yaSSL::del_ptr_zero); +template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::del_ptr_zero); +template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::del_ptr_zero); +template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::del_ptr_zero); +template yaSSL::del_ptr_zero mySTL::for_each<mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero>(mySTL::list<yaSSL::x509*>::iterator, mySTL::list<yaSSL::x509*>::iterator, yaSSL::del_ptr_zero); +#endif + diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp new file mode 100644 index 00000000000..5f918b0a356 --- /dev/null +++ b/extra/yassl/src/yassl_int.cpp @@ -0,0 +1,1973 @@ +/* yassl_int.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* yaSSL internal source implements SSL supporting types not specified in the + * draft along with type conversion functions. + */ + +#include "runtime.hpp" +#include "yassl_int.hpp" +#include "handshake.hpp" +#include "timer.hpp" +#include "openssl/ssl.h" // for DH + + +void* operator new(size_t sz, yaSSL::new_t) +{ + void* ptr = ::operator new(sz); + + if (!ptr) abort(); + + return ptr; +} + +void* operator new[](size_t sz, yaSSL::new_t n) +{ +#if defined(_MSC_VER) && (_MSC_VER < 1300) + void* ptr = ::operator new(sz); // no ::operator new[] +#else + void* ptr = ::operator new[](sz); +#endif + + if (!ptr) abort(); + + return ptr; +} + + +namespace yaSSL { + + +using mySTL::min; + + +new_t ys; // for library new + + +// convert a 32 bit integer into a 24 bit one +void c32to24(uint32 u32, uint24& u24) +{ + u24[0] = (u32 >> 16) & 0xff; + u24[1] = (u32 >> 8) & 0xff; + u24[2] = u32 & 0xff; +} + + +// convert a 24 bit integer into a 32 bit one +void c24to32(const uint24 u24, uint32& u32) +{ + u32 = 0; + u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2]; +} + + +// convert with return for ease of use +uint32 c24to32(const uint24 u24) +{ + uint32 ret; + c24to32(u24, ret); + + return ret; +} + + +// using a for opaque since underlying type is unsgined char and o is not a +// good leading identifier + +// convert opaque to 16 bit integer +void ato16(const opaque* c, uint16& u16) +{ + u16 = 0; + u16 = (c[0] << 8) | (c[1]); +} + + +// convert (copy) opaque to 24 bit integer +void ato24(const opaque* c, uint24& u24) +{ + u24[0] = c[0]; + u24[1] = c[1]; + u24[2] = c[2]; +} + + +// convert 16 bit integer to opaque +void c16toa(uint16 u16, opaque* c) +{ + c[0] = (u16 >> 8) & 0xff; + c[1] = u16 & 0xff; +} + + +// convert 24 bit integer to opaque +void c24toa(const uint24 u24, opaque* c) +{ + c[0] = u24[0]; + c[1] = u24[1]; + c[2] = u24[2]; +} + + +// convert 32 bit integer to opaque +void c32toa(uint32 u32, opaque* c) +{ + c[0] = (u32 >> 24) & 0xff; + c[1] = (u32 >> 16) & 0xff; + c[2] = (u32 >> 8) & 0xff; + c[3] = u32 & 0xff; +} + + +States::States() : recordLayer_(recordReady), handshakeLayer_(preHandshake), + clientState_(serverNull), serverState_(clientNull), + what_(no_error) {} + +const RecordLayerState& States::getRecord() const +{ + return recordLayer_; +} + + +const HandShakeState& States::getHandShake() const +{ + return handshakeLayer_; +} + + +const ClientState& States::getClient() const +{ + return clientState_; +} + + +const ServerState& States::getServer() const +{ + return serverState_; +} + + +const char* States::getString() const +{ + return errorString_; +} + + +YasslError States::What() const +{ + return what_; +} + + +RecordLayerState& States::useRecord() +{ + return recordLayer_; +} + + +HandShakeState& States::useHandShake() +{ + return handshakeLayer_; +} + + +ClientState& States::useClient() +{ + return clientState_; +} + + +ServerState& States::useServer() +{ + return serverState_; +} + + +char* States::useString() +{ + return errorString_; +} + + +void States::SetError(YasslError ye) +{ + what_ = ye; +} + + +sslFactory::sslFactory() : + messageFactory_(InitMessageFactory), + handShakeFactory_(InitHandShakeFactory), + serverKeyFactory_(InitServerKeyFactory), + clientKeyFactory_(InitClientKeyFactory) +{} + + +const MessageFactory& sslFactory::getMessage() const +{ + return messageFactory_; +} + + +const HandShakeFactory& sslFactory::getHandShake() const +{ + return handShakeFactory_; +} + + +const ServerKeyFactory& sslFactory::getServerKey() const +{ + return serverKeyFactory_; +} + + +const ClientKeyFactory& sslFactory::getClientKey() const +{ + return clientKeyFactory_; +} + + +// extract context parameters and store +SSL::SSL(SSL_CTX* ctx) + : secure_(ctx->getMethod()->getVersion(), crypto_.use_random(), + ctx->getMethod()->getSide(), ctx->GetCiphers(), ctx) +{ + if (int err = crypto_.get_random().GetError()) { + SetError(YasslError(err)); + return; + } + + CertManager& cm = crypto_.use_certManager(); + cm.CopySelfCert(ctx->getCert()); + + bool serverSide = secure_.use_parms().entity_ == server_end; + + if (ctx->getKey()) { + if (int err = cm.SetPrivateKey(*ctx->getKey())) { + SetError(YasslError(err)); + return; + } + } + else if (serverSide) { + SetError(no_key_file); + return; + } + + if (ctx->getMethod()->verifyPeer()) + cm.setVerifyPeer(); + if (ctx->getMethod()->failNoCert()) + cm.setFailNoCert(); + + if (serverSide) + crypto_.SetDH(ctx->GetDH_Parms()); + + const SSL_CTX::CertList& ca = ctx->GetCA_List(); + SSL_CTX::CertList::const_iterator first(ca.begin()); + SSL_CTX::CertList::const_iterator last(ca.end()); + + while (first != last) { + if (int err = cm.CopyCaCert(*first)) { + SetError(YasslError(err)); + return; + } + ++first; + } +} + + +// store pending security parameters from Server Hello +void SSL::set_pending(Cipher suite) +{ + Parameters& parms = secure_.use_parms(); + + switch (suite) { + + case TLS_RSA_WITH_AES_256_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_256_CBC_SHA], + MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_AES_128_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) AES); + strncpy(parms.cipher_name_, cipher_names[TLS_RSA_WITH_AES_128_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_3DES_EDE_CBC_SHA: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) DES_EDE); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_3DES_EDE_CBC_SHA] + , MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_DES_CBC_SHA: + parms.bulk_cipher_algorithm_ = des; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) DES); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_DES_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_RC4_128_SHA: + parms.bulk_cipher_algorithm_ = rc4; + parms.mac_algorithm_ = sha; + parms.kea_ = rsa_kea; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = RC4_KEY_SZ; + parms.iv_size_ = 0; + parms.cipher_type_ = stream; + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) RC4); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_RC4_128_SHA], + MAX_SUITE_NAME); + break; + + case SSL_RSA_WITH_RC4_128_MD5: + parms.bulk_cipher_algorithm_ = rc4; + parms.mac_algorithm_ = md5; + parms.kea_ = rsa_kea; + parms.hash_size_ = MD5_LEN; + parms.key_size_ = RC4_KEY_SZ; + parms.iv_size_ = 0; + parms.cipher_type_ = stream; + crypto_.setDigest(new (ys) MD5); + crypto_.setCipher(new (ys) RC4); + strncpy(parms.cipher_name_, cipher_names[SSL_RSA_WITH_RC4_128_MD5], + MAX_SUITE_NAME); + break; + + case SSL_DHE_RSA_WITH_DES_CBC_SHA: + parms.bulk_cipher_algorithm_ = des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) DES); + strncpy(parms.cipher_name_, cipher_names[SSL_DHE_RSA_WITH_DES_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_256_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_128_CBC_SHA], MAX_SUITE_NAME); + break; + + case SSL_DHE_DSS_WITH_DES_CBC_SHA: + parms.bulk_cipher_algorithm_ = des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) DES); + strncpy(parms.cipher_name_, cipher_names[SSL_DHE_DSS_WITH_DES_CBC_SHA], + MAX_SUITE_NAME); + break; + + case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_256_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = sha; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = SHA_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) SHA); + crypto_.setCipher(new (ys) AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_128_CBC_SHA], MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_AES_256_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = rsa_kea; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_RSA_WITH_AES_256_CBC_RMD160], MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_AES_128_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = rsa_kea; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_RSA_WITH_AES_128_CBC_RMD160], MAX_SUITE_NAME); + break; + + case TLS_RSA_WITH_3DES_EDE_CBC_RMD160: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = rmd; + parms.kea_ = rsa_kea; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[TLS_RSA_WITH_3DES_EDE_CBC_RMD160], MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_256_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_256_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_RSA_WITH_AES_128_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = rsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_RSA_WITH_AES_128_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160: + parms.bulk_cipher_algorithm_ = triple_des; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = DES_EDE_KEY_SZ; + parms.iv_size_ = DES_IV_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) DES_EDE); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_256_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_256_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) AES(AES_256_KEY_SZ)); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_256_CBC_RMD160], + MAX_SUITE_NAME); + break; + + case TLS_DHE_DSS_WITH_AES_128_CBC_RMD160: + parms.bulk_cipher_algorithm_ = aes; + parms.mac_algorithm_ = rmd; + parms.kea_ = diffie_hellman_kea; + parms.sig_algo_ = dsa_sa_algo; + parms.hash_size_ = RMD_LEN; + parms.key_size_ = AES_128_KEY_SZ; + parms.iv_size_ = AES_BLOCK_SZ; + parms.cipher_type_ = block; + secure_.use_connection().send_server_key_ = true; // eph + crypto_.setDigest(new (ys) RMD); + crypto_.setCipher(new (ys) AES); + strncpy(parms.cipher_name_, + cipher_names[TLS_DHE_DSS_WITH_AES_128_CBC_RMD160], + MAX_SUITE_NAME); + break; + + default: + SetError(unknown_cipher); + } +} + + +// store peer's random +void SSL::set_random(const opaque* random, ConnectionEnd sender) +{ + if (sender == client_end) + memcpy(secure_.use_connection().client_random_, random, RAN_LEN); + else + memcpy(secure_.use_connection().server_random_, random, RAN_LEN); +} + + +// store client pre master secret +void SSL::set_preMaster(const opaque* pre, uint sz) +{ + secure_.use_connection().AllocPreSecret(sz); + memcpy(secure_.use_connection().pre_master_secret_, pre, sz); +} + + +// store master secret +void SSL::set_masterSecret(const opaque* sec) +{ + memcpy(secure_.use_connection().master_secret_, sec, SECRET_LEN); +} + +// store server issued id +void SSL::set_sessionID(const opaque* sessionID) +{ + memcpy(secure_.use_connection().sessionID_, sessionID, ID_LEN); +} + + +// store error +void SSL::SetError(YasslError ye) +{ + states_.SetError(ye); + //strncpy(states_.useString(), e.what(), mySTL::named_exception::NAME_SIZE); + // TODO: add string here +} + + +// locals +namespace { + +// DeriveKeys and MasterSecret helper sets prefix letters +static bool setPrefix(opaque* sha_input, int i) +{ + switch (i) { + case 0: + memcpy(sha_input, "A", 1); + break; + case 1: + memcpy(sha_input, "BB", 2); + break; + case 2: + memcpy(sha_input, "CCC", 3); + break; + case 3: + memcpy(sha_input, "DDDD", 4); + break; + case 4: + memcpy(sha_input, "EEEEE", 5); + break; + case 5: + memcpy(sha_input, "FFFFFF", 6); + break; + case 6: + memcpy(sha_input, "GGGGGGG", 7); + break; + default: + return false; // prefix_error + } + return true; +} + + +const char handshake_order[] = "Out of order HandShake Message!"; + + +} // namespcae for locals + + +void SSL::order_error() +{ + SetError(out_of_order); +} + + +// Create and store the master secret see page 32, 6.1 +void SSL::makeMasterSecret() +{ + if (isTLS()) + makeTLSMasterSecret(); + else { + opaque sha_output[SHA_LEN]; + + const uint& preSz = secure_.get_connection().pre_secret_len_; + output_buffer md5_input(preSz + SHA_LEN); + output_buffer sha_input(PREFIX + preSz + 2 * RAN_LEN); + + MD5 md5; + SHA sha; + + md5_input.write(secure_.get_connection().pre_master_secret_, preSz); + + for (int i = 0; i < MASTER_ROUNDS; ++i) { + opaque prefix[PREFIX]; + if (!setPrefix(prefix, i)) { + SetError(prefix_error); + return; + } + + sha_input.set_current(0); + sha_input.write(prefix, i + 1); + + sha_input.write(secure_.get_connection().pre_master_secret_,preSz); + sha_input.write(secure_.get_connection().client_random_, RAN_LEN); + sha_input.write(secure_.get_connection().server_random_, RAN_LEN); + sha.get_digest(sha_output, sha_input.get_buffer(), + sha_input.get_size()); + + md5_input.set_current(preSz); + md5_input.write(sha_output, SHA_LEN); + md5.get_digest(&secure_.use_connection().master_secret_[i*MD5_LEN], + md5_input.get_buffer(), md5_input.get_size()); + } + deriveKeys(); + } + secure_.use_connection().CleanPreMaster(); +} + + +// create TLSv1 master secret +void SSL::makeTLSMasterSecret() +{ + opaque seed[SEED_LEN]; + + memcpy(seed, secure_.get_connection().client_random_, RAN_LEN); + memcpy(&seed[RAN_LEN], secure_.get_connection().server_random_, RAN_LEN); + + PRF(secure_.use_connection().master_secret_, SECRET_LEN, + secure_.get_connection().pre_master_secret_, + secure_.get_connection().pre_secret_len_, + master_label, MASTER_LABEL_SZ, + seed, SEED_LEN); + + deriveTLSKeys(); +} + + +// derive mac, write, and iv keys for server and client, see page 34, 6.2.2 +void SSL::deriveKeys() +{ + int length = 2 * secure_.get_parms().hash_size_ + + 2 * secure_.get_parms().key_size_ + + 2 * secure_.get_parms().iv_size_; + int rounds = length / MD5_LEN + ((length % MD5_LEN) ? 1 : 0); + input_buffer key_data(rounds * MD5_LEN); + + opaque sha_output[SHA_LEN]; + opaque md5_input[SECRET_LEN + SHA_LEN]; + opaque sha_input[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN]; + + MD5 md5; + SHA sha; + + memcpy(md5_input, secure_.get_connection().master_secret_, SECRET_LEN); + + for (int i = 0; i < rounds; ++i) { + int j = i + 1; + if (!setPrefix(sha_input, i)) { + SetError(prefix_error); + return; + } + + memcpy(&sha_input[j], secure_.get_connection().master_secret_, + SECRET_LEN); + memcpy(&sha_input[j+SECRET_LEN], + secure_.get_connection().server_random_, RAN_LEN); + memcpy(&sha_input[j + SECRET_LEN + RAN_LEN], + secure_.get_connection().client_random_, RAN_LEN); + sha.get_digest(sha_output, sha_input, + sizeof(sha_input) - KEY_PREFIX + j); + + memcpy(&md5_input[SECRET_LEN], sha_output, SHA_LEN); + md5.get_digest(key_data.get_buffer() + i * MD5_LEN, + md5_input, sizeof(md5_input)); + } + storeKeys(key_data.get_buffer()); +} + + +// derive mac, write, and iv keys for server and client +void SSL::deriveTLSKeys() +{ + int length = 2 * secure_.get_parms().hash_size_ + + 2 * secure_.get_parms().key_size_ + + 2 * secure_.get_parms().iv_size_; + opaque seed[SEED_LEN]; + input_buffer key_data(length); + + memcpy(seed, secure_.get_connection().server_random_, RAN_LEN); + memcpy(&seed[RAN_LEN], secure_.get_connection().client_random_, RAN_LEN); + + PRF(key_data.get_buffer(), length, secure_.get_connection().master_secret_, + SECRET_LEN, key_label, KEY_LABEL_SZ, seed, SEED_LEN); + + storeKeys(key_data.get_buffer()); +} + + +// store mac, write, and iv keys for client and server +void SSL::storeKeys(const opaque* key_data) +{ + int sz = secure_.get_parms().hash_size_; + memcpy(secure_.use_connection().client_write_MAC_secret_, key_data, sz); + int i = sz; + memcpy(secure_.use_connection().server_write_MAC_secret_,&key_data[i], sz); + i += sz; + + sz = secure_.get_parms().key_size_; + memcpy(secure_.use_connection().client_write_key_, &key_data[i], sz); + i += sz; + memcpy(secure_.use_connection().server_write_key_, &key_data[i], sz); + i += sz; + + sz = secure_.get_parms().iv_size_; + memcpy(secure_.use_connection().client_write_IV_, &key_data[i], sz); + i += sz; + memcpy(secure_.use_connection().server_write_IV_, &key_data[i], sz); + + setKeys(); +} + + +// set encrypt/decrypt keys and ivs +void SSL::setKeys() +{ + Connection& conn = secure_.use_connection(); + + if (secure_.get_parms().entity_ == client_end) { + crypto_.use_cipher().set_encryptKey(conn.client_write_key_, + conn.client_write_IV_); + crypto_.use_cipher().set_decryptKey(conn.server_write_key_, + conn.server_write_IV_); + } + else { + crypto_.use_cipher().set_encryptKey(conn.server_write_key_, + conn.server_write_IV_); + crypto_.use_cipher().set_decryptKey(conn.client_write_key_, + conn.client_write_IV_); + } +} + + + +// local functors +namespace yassl_int_cpp_local1 { + +struct SumData { + uint total_; + SumData() : total_(0) {} + void operator()(input_buffer* data) { total_ += data->get_remaining(); } +}; + + +struct SumBuffer { + uint total_; + SumBuffer() : total_(0) {} + void operator()(output_buffer* buffer) { total_ += buffer->get_size(); } +}; + +} // namespace for locals +using namespace yassl_int_cpp_local1; + +uint SSL::bufferedData() +{ + return mySTL::for_each(buffers_.getData().begin(),buffers_.getData().end(), + SumData()).total_; +} + +// use input buffer to fill data +void SSL::fillData(Data& data) +{ + if (GetError()) return; + uint dataSz = data.get_length(); // input, data size to fill + uint elements = buffers_.getData().size(); + + data.set_length(0); // output, actual data filled + dataSz = min(dataSz, bufferedData()); + + for (uint i = 0; i < elements; i++) { + input_buffer* front = buffers_.getData().front(); + uint frontSz = front->get_remaining(); + uint readSz = min(dataSz - data.get_length(), frontSz); + + front->read(data.set_buffer() + data.get_length(), readSz); + data.set_length(data.get_length() + readSz); + + if (readSz == frontSz) { + buffers_.useData().pop_front(); + delete front; + } + if (data.get_length() == dataSz) + break; + } +} + + +// flush output buffer +void SSL::flushBuffer() +{ + if (GetError()) return; + + uint sz = mySTL::for_each(buffers_.getHandShake().begin(), + buffers_.getHandShake().end(), + SumBuffer()).total_; + output_buffer out(sz); + uint elements = buffers_.getHandShake().size(); + + for (uint i = 0; i < elements; i++) { + output_buffer* front = buffers_.getHandShake().front(); + out.write(front->get_buffer(), front->get_size()); + + buffers_.useHandShake().pop_front(); + delete front; + } + Send(out.get_buffer(), out.get_size()); +} + + +void SSL::Send(const byte* buffer, uint sz) +{ + if (socket_.send(buffer, sz) != sz) + SetError(send_error); +} + + +// get sequence number, if verify get peer's +uint SSL::get_SEQIncrement(bool verify) +{ + if (verify) + return secure_.use_connection().peer_sequence_number_++; + else + return secure_.use_connection().sequence_number_++; +} + + +const byte* SSL::get_macSecret(bool verify) +{ + if ( (secure_.get_parms().entity_ == client_end && !verify) || + (secure_.get_parms().entity_ == server_end && verify) ) + return secure_.get_connection().client_write_MAC_secret_; + else + return secure_.get_connection().server_write_MAC_secret_; +} + + +void SSL::verifyState(const RecordLayerHeader& rlHeader) +{ + if (GetError()) return; + + if (states_.getRecord() == recordNotReady || + (rlHeader.type_ == application_data && // data and handshake + states_.getHandShake() != handShakeReady) ) // isn't complete yet + SetError(record_layer); +} + + +void SSL::verifyState(const HandShakeHeader& hsHeader) +{ + if (GetError()) return; + + if (states_.getHandShake() == handShakeNotReady) { + SetError(handshake_layer); + return; + } + + if (secure_.get_parms().entity_ == client_end) + verifyClientState(hsHeader.get_handshakeType()); + else + verifyServerState(hsHeader.get_handshakeType()); +} + + +void SSL::verifyState(ClientState cs) +{ + if (GetError()) return; + if (states_.getClient() != cs) order_error(); +} + + +void SSL::verifyState(ServerState ss) +{ + if (GetError()) return; + if (states_.getServer() != ss) order_error(); +} + + +void SSL::verfiyHandShakeComplete() +{ + if (GetError()) return; + if (states_.getHandShake() != handShakeReady) order_error(); +} + + +void SSL::verifyClientState(HandShakeType hsType) +{ + if (GetError()) return; + + switch(hsType) { + case server_hello : + if (states_.getClient() != serverNull) + order_error(); + break; + case certificate : + if (states_.getClient() != serverHelloComplete) + order_error(); + break; + case server_key_exchange : + if (states_.getClient() != serverCertComplete) + order_error(); + break; + case certificate_request : + if (states_.getClient() != serverCertComplete && + states_.getClient() != serverKeyExchangeComplete) + order_error(); + break; + case server_hello_done : + if (states_.getClient() != serverCertComplete && + states_.getClient() != serverKeyExchangeComplete) + order_error(); + break; + case finished : + if (states_.getClient() != serverHelloDoneComplete || + secure_.get_parms().pending_) // no change + order_error(); // cipher yet + break; + default : + order_error(); + }; +} + + +void SSL::verifyServerState(HandShakeType hsType) +{ + if (GetError()) return; + + switch(hsType) { + case client_hello : + if (states_.getServer() != clientNull) + order_error(); + break; + case certificate : + if (states_.getServer() != clientHelloComplete) + order_error(); + break; + case client_key_exchange : + if (states_.getServer() != clientHelloComplete) + order_error(); + break; + case certificate_verify : + if (states_.getServer() != clientKeyExchangeComplete) + order_error(); + break; + case finished : + if (states_.getServer() != clientKeyExchangeComplete || + secure_.get_parms().pending_) // no change + order_error(); // cipher yet + break; + default : + order_error(); + }; +} + + +// try to find a suite match +void SSL::matchSuite(const opaque* peer, uint length) +{ + if (length == 0 || (length % 2) != 0) { + SetError(bad_input); + return; + } + + // start with best, if a match we are good, Ciphers are at odd index + // since all SSL and TLS ciphers have 0x00 first byte + for (uint i = 1; i < secure_.get_parms().suites_size_; i += 2) + for (uint j = 1; j < length; j+= 2) + if (secure_.use_parms().suites_[i] == peer[j]) { + secure_.use_parms().suite_[0] = 0x00; + secure_.use_parms().suite_[1] = peer[j]; + return; + } + + SetError(match_error); +} + + +void SSL::set_session(SSL_SESSION* s) +{ + if (s && GetSessions().lookup(s->GetID(), &secure_.use_resume())) + secure_.set_resuming(true); +} + + +const Crypto& SSL::getCrypto() const +{ + return crypto_; +} + + +const Security& SSL::getSecurity() const +{ + return secure_; +} + + +const States& SSL::getStates() const +{ + return states_; +} + + +const sslHashes& SSL::getHashes() const +{ + return hashes_; +} + + +const sslFactory& SSL::getFactory() const +{ + return GetSSL_Factory(); +} + + +const Socket& SSL::getSocket() const +{ + return socket_; +} + + +YasslError SSL::GetError() const +{ + return states_.What(); +} + + +Crypto& SSL::useCrypto() +{ + return crypto_; +} + + +Security& SSL::useSecurity() +{ + return secure_; +} + + +States& SSL::useStates() +{ + return states_; +} + + +sslHashes& SSL::useHashes() +{ + return hashes_; +} + + +Socket& SSL::useSocket() +{ + return socket_; +} + + +Log& SSL::useLog() +{ + return log_; +} + + +bool SSL::isTLS() const +{ + return secure_.get_connection().TLS_; +} + + +void SSL::addData(input_buffer* data) +{ + buffers_.useData().push_back(data); +} + + +void SSL::addBuffer(output_buffer* b) +{ + buffers_.useHandShake().push_back(b); +} + + +// store connection parameters +SSL_SESSION::SSL_SESSION(const SSL& ssl, RandomPool& ran) + : timeout_(DEFAULT_TIMEOUT), random_(ran) +{ + const Connection& conn = ssl.getSecurity().get_connection(); + + memcpy(sessionID_, conn.sessionID_, ID_LEN); + memcpy(master_secret_, conn.master_secret_, SECRET_LEN); + memcpy(suite_, ssl.getSecurity().get_parms().suite_, SUITE_LEN); + + bornOn_ = lowResTimer(); +} + + +// for resumption copy in ssl::parameters +SSL_SESSION::SSL_SESSION(RandomPool& ran) + : bornOn_(0), timeout_(0), random_(ran) +{ + memset(sessionID_, 0, ID_LEN); + memset(master_secret_, 0, SECRET_LEN); + memset(suite_, 0, SUITE_LEN); +} + + +SSL_SESSION& SSL_SESSION::operator=(const SSL_SESSION& that) +{ + memcpy(sessionID_, that.sessionID_, ID_LEN); + memcpy(master_secret_, that.master_secret_, SECRET_LEN); + memcpy(suite_, that.suite_, SUITE_LEN); + + bornOn_ = that.bornOn_; + timeout_ = that.timeout_; + + return *this; +} + + +const opaque* SSL_SESSION::GetID() const +{ + return sessionID_; +} + + +const opaque* SSL_SESSION::GetSecret() const +{ + return master_secret_; +} + + +const Cipher* SSL_SESSION::GetSuite() const +{ + return suite_; +} + + +uint SSL_SESSION::GetBornOn() const +{ + return bornOn_; +} + + +uint SSL_SESSION::GetTimeOut() const +{ + return timeout_; +} + + +void SSL_SESSION::SetTimeOut(uint t) +{ + timeout_ = t; +} + + +extern void clean(volatile opaque*, uint, RandomPool&); + + +// clean up secret data +SSL_SESSION::~SSL_SESSION() +{ + volatile opaque* p = master_secret_; + clean(p, SECRET_LEN, random_); +} + + +Sessions& GetSessions() +{ + static Sessions instance; // simple singleton + return instance; +} + + +sslFactory& GetSSL_Factory() +{ + static sslFactory instance; // simple singleton + return instance; +} + + +typedef Mutex::Lock Lock; + + +void Sessions::add(const SSL& ssl) +{ + Lock guard(mutex_); + list_.push_back(new (ys) SSL_SESSION(ssl, random_)); +} + + +Sessions::~Sessions() +{ + mySTL::for_each(list_.begin(), list_.end(), del_ptr_zero()); +} + + +namespace yassl_int_cpp_local2 { // locals + +typedef mySTL::list<SSL_SESSION*>::iterator iterator; + +struct sess_match { + const opaque* id_; + explicit sess_match(const opaque* p) : id_(p) {} + + bool operator()(SSL_SESSION* sess) + { + if ( memcmp(sess->GetID(), id_, ID_LEN) == 0) + return true; + return false; + } +}; + + +} // local namespace +using namespace yassl_int_cpp_local2; + +// lookup session by id, return a copy if space provided +SSL_SESSION* Sessions::lookup(const opaque* id, SSL_SESSION* copy) +{ + Lock guard(mutex_); + iterator find = mySTL::find_if(list_.begin(), list_.end(), sess_match(id)); + + if (find != list_.end()) { + uint current = lowResTimer(); + if ( ((*find)->GetBornOn() + (*find)->GetTimeOut()) < current) { + del_ptr_zero()(*find); + list_.erase(find); + return 0; + } + if (copy) + *copy = *(*find); + return *find; + } + return 0; +} + + +// remove a session by id +void Sessions::remove(const opaque* id) +{ + Lock guard(mutex_); + iterator find = mySTL::find_if(list_.begin(), list_.end(), sess_match(id)); + + if (find != list_.end()) { + del_ptr_zero()(*find); + list_.erase(find); + } +} + + +SSL_METHOD::SSL_METHOD(ConnectionEnd ce, ProtocolVersion pv) + : version_(pv), side_(ce), verifyPeer_(false), failNoCert_(false) +{} + + +ProtocolVersion SSL_METHOD::getVersion() const +{ + return version_; +} + + +ConnectionEnd SSL_METHOD::getSide() const +{ + return side_; +} + + +void SSL_METHOD::setVerifyPeer() +{ + verifyPeer_ = true; +} + + +void SSL_METHOD::setFailNoCert() +{ + failNoCert_ = true; +} + + +bool SSL_METHOD::verifyPeer() const +{ + return verifyPeer_; +} + + +bool SSL_METHOD::failNoCert() const +{ + return failNoCert_; +} + + +SSL_CTX::SSL_CTX(SSL_METHOD* meth) + : method_(meth), certificate_(0), privateKey_(0) +{} + + +SSL_CTX::~SSL_CTX() +{ + delete method_; + delete certificate_; + delete privateKey_; + + mySTL::for_each(caList_.begin(), caList_.end(), del_ptr_zero()); +} + + +void SSL_CTX::AddCA(x509* ca) +{ + caList_.push_back(ca); +} + + +const SSL_CTX::CertList& +SSL_CTX::GetCA_List() const +{ + return caList_; +} + + +const x509* SSL_CTX::getCert() const +{ + return certificate_; +} + + +const x509* SSL_CTX::getKey() const +{ + return privateKey_; +} + + +const SSL_METHOD* SSL_CTX::getMethod() const +{ + return method_; +} + + +const Ciphers& SSL_CTX::GetCiphers() const +{ + return ciphers_; +} + + +const DH_Parms& SSL_CTX::GetDH_Parms() const +{ + return dhParms_; +} + + +const Stats& SSL_CTX::GetStats() const +{ + return stats_; +} + + +void SSL_CTX::setVerifyPeer() +{ + method_->setVerifyPeer(); +} + + +void SSL_CTX::setFailNoCert() +{ + method_->setFailNoCert(); +} + + +bool SSL_CTX::SetDH(const DH& dh) +{ + dhParms_.p_ = dh.p->int_; + dhParms_.g_ = dh.g->int_; + + return dhParms_.set_ = true; +} + + +bool SSL_CTX::SetCipherList(const char* list) +{ + if (!list) + return false; + + bool ret = false; + char name[MAX_SUITE_NAME]; + + char needle[] = ":"; + char* haystack = const_cast<char*>(list); + char* prev; + + const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]); + int idx = 0; + + for(;;) { + int len; + prev = haystack; + haystack = strstr(haystack, needle); + + if (!haystack) // last cipher + len = min(sizeof(name), strlen(prev)); + else + len = min(sizeof(name), (size_t)(haystack - prev)); + + strncpy(name, prev, len); + name[(len == sizeof(name)) ? len - 1 : len] = 0; + + for (int i = 0; i < suiteSz; i++) + if (strncmp(name, cipher_names[i], sizeof(name)) == 0) { + + ciphers_.suites_[idx++] = 0x00; // first byte always zero + ciphers_.suites_[idx++] = i; + + if (!ret) ret = true; // found at least one + break; + } + if (!haystack) break; + haystack++; + } + + if (ret) { + ciphers_.setSuites_ = true; + ciphers_.suiteSz_ = idx; + } + + return ret; +} + + +void SSL_CTX::IncrementStats(StatsField fd) +{ + + Lock guard(mutex_); + + switch (fd) { + + case Accept: + ++stats_.accept_; + break; + + case Connect: + ++stats_.connect_; + break; + + case AcceptGood: + ++stats_.acceptGood_; + break; + + case ConnectGood: + ++stats_.connectGood_; + break; + + case AcceptRenegotiate: + ++stats_.acceptRenegotiate_; + break; + + case ConnectRenegotiate: + ++stats_.connectRenegotiate_; + break; + + case Hits: + ++stats_.hits_; + break; + + case CbHits: + ++stats_.cbHits_; + break; + + case CacheFull: + ++stats_.cacheFull_; + break; + + case Misses: + ++stats_.misses_; + break; + + case Timeouts: + ++stats_.timeouts_; + break; + + case Number: + ++stats_.number_; + break; + + case GetCacheSize: + ++stats_.getCacheSize_; + break; + + case VerifyMode: + ++stats_.verifyMode_; + break; + + case VerifyDepth: + ++stats_.verifyDepth_; + break; + + default: + break; + } +} + + +Crypto::Crypto() + : digest_(0), cipher_(0), dh_(0) +{} + + +Crypto::~Crypto() +{ + delete dh_; + delete cipher_; + delete digest_; +} + + +const Digest& Crypto::get_digest() const +{ + return *digest_; +} + + +const BulkCipher& Crypto::get_cipher() const +{ + return *cipher_; +} + + +const DiffieHellman& Crypto::get_dh() const +{ + return *dh_; +} + + +const RandomPool& Crypto::get_random() const +{ + return random_; +} + + +const CertManager& Crypto::get_certManager() const +{ + return cert_; +} + + + +Digest& Crypto::use_digest() +{ + return *digest_; +} + + +BulkCipher& Crypto::use_cipher() +{ + return *cipher_; +} + + +DiffieHellman& Crypto::use_dh() +{ + return *dh_; +} + + +RandomPool& Crypto::use_random() +{ + return random_; +} + + +CertManager& Crypto::use_certManager() +{ + return cert_; +} + + + +void Crypto::SetDH(DiffieHellman* dh) +{ + dh_ = dh; +} + + +void Crypto::SetDH(const DH_Parms& dh) +{ + if (dh.set_) + dh_ = new (ys) DiffieHellman(dh.p_, dh.g_, random_); +} + + +bool Crypto::DhSet() +{ + return dh_ != 0; +} + + +void Crypto::setDigest(Digest* digest) +{ + digest_ = digest; +} + + +void Crypto::setCipher(BulkCipher* c) +{ + cipher_ = c; +} + + +const MD5& sslHashes::get_MD5() const +{ + return md5HandShake_; +} + + +const SHA& sslHashes::get_SHA() const +{ + return shaHandShake_; +} + + +const Finished& sslHashes::get_verify() const +{ + return verify_; +} + + +const Hashes& sslHashes::get_certVerify() const +{ + return certVerify_; +} + + +MD5& sslHashes::use_MD5(){ + return md5HandShake_; +} + + +SHA& sslHashes::use_SHA() +{ + return shaHandShake_; +} + + +Finished& sslHashes::use_verify() +{ + return verify_; +} + + +Hashes& sslHashes::use_certVerify() +{ + return certVerify_; +} + + +Buffers::~Buffers() +{ + mySTL::for_each(handShakeList_.begin(), handShakeList_.end(), + del_ptr_zero()) ; + mySTL::for_each(dataList_.begin(), dataList_.end(), + del_ptr_zero()) ; +} + + +const Buffers::inputList& Buffers::getData() const +{ + return dataList_; +} + + +const Buffers::outputList& Buffers::getHandShake() const +{ + return handShakeList_; +} + + +Buffers::inputList& Buffers::useData() +{ + return dataList_; +} + + +Buffers::outputList& Buffers::useHandShake() +{ + return handShakeList_; +} + + +Security::Security(ProtocolVersion pv, RandomPool& ran, ConnectionEnd ce, + const Ciphers& ciphers, SSL_CTX* ctx) + : conn_(pv, ran), parms_(ce, ciphers, pv), resumeSession_(ran), ctx_(ctx), + resuming_(false) +{} + + +const Connection& Security::get_connection() const +{ + return conn_; +} + + +const SSL_CTX* Security::GetContext() const +{ + return ctx_; +} + + +const Parameters& Security::get_parms() const +{ + return parms_; +} + + +const SSL_SESSION& Security::get_resume() const +{ + return resumeSession_; +} + + +bool Security::get_resuming() const +{ + return resuming_; +} + + +Connection& Security::use_connection() +{ + return conn_; +} + + +Parameters& Security::use_parms() +{ + return parms_; +} + + +SSL_SESSION& Security::use_resume() +{ + return resumeSession_; +} + + +void Security::set_resuming(bool b) +{ + resuming_ = b; +} + + +X509_NAME::X509_NAME(const char* n, size_t sz) + : name_(0) +{ + if (sz) { + name_ = new (ys) char[sz]; + memcpy(name_, n, sz); + } +} + + +X509_NAME::~X509_NAME() +{ + delete[] name_; +} + + +char* X509_NAME::GetName() +{ + return name_; +} + + +X509::X509(const char* i, size_t iSz, const char* s, size_t sSz) + : issuer_(i, iSz), subject_(s, sSz) +{} + + +X509_NAME* X509::GetIssuer() +{ + return &issuer_; +} + + +X509_NAME* X509::GetSubject() +{ + return &subject_; +} + +} // namespace + +#ifdef __GNUC__ +template yaSSL::yassl_int_cpp_local1::SumData mySTL::for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData); +template yaSSL::yassl_int_cpp_local1::SumBuffer mySTL::for_each<mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer>(mySTL::list<yaSSL::output_buffer*>::iterator, mySTL::list<yaSSL::output_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumBuffer); +template mySTL::list<yaSSL::SSL_SESSION*>::iterator mySTL::find_if<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match); +#endif diff --git a/extra/yassl/taocrypt/Makefile.am b/extra/yassl/taocrypt/Makefile.am new file mode 100644 index 00000000000..af3ded7abfd --- /dev/null +++ b/extra/yassl/taocrypt/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = src +EXTRA_DIST = taocrypt.dsw taocrypt.dsp diff --git a/extra/yassl/taocrypt/include/aes.hpp b/extra/yassl/taocrypt/include/aes.hpp new file mode 100644 index 00000000000..b2c93eff9fe --- /dev/null +++ b/extra/yassl/taocrypt/include/aes.hpp @@ -0,0 +1,89 @@ +/* aes.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* aes.hpp defines AES +*/ + + +#ifndef TAO_CRYPT_AES_HPP +#define TAO_CRYPT_AES_HPP + +#include <string.h> +#include "misc.hpp" +#include "modes.hpp" +#include "block.hpp" + +namespace TaoCrypt { + +enum { AES_BLOCK_SIZE = 16 }; + + +// AES encryption and decryption, see FIPS-197 +class AES : public Mode_BASE<AES_BLOCK_SIZE> { +public: + enum { BLOCK_SIZE = AES_BLOCK_SIZE }; + + AES(CipherDir DIR, Mode MODE) : dir_(DIR), mode_(MODE) {} + + void Process(byte*, const byte*, word32); + void SetKey(const byte* iv, word32 sz, CipherDir fake = ENCRYPTION); + + void ProcessAndXorBlock(const byte*, const byte*, byte*) const; +private: + CipherDir dir_; + Mode mode_; + + static const word32 Te0[256]; + static const word32 Te1[256]; + static const word32 Te2[256]; + static const word32 Te3[256]; + static const word32 Te4[256]; + + static const word32 Td0[256]; + static const word32 Td1[256]; + static const word32 Td2[256]; + static const word32 Td3[256]; + static const word32 Td4[256]; + + static const word32 rcon_[]; + + word32 rounds_; + Word32Block key_; + + void encrypt(const byte*, const byte*, byte*) const; + void decrypt(const byte*, const byte*, byte*) const; + + AES(const AES&); // hide copy + AES& operator=(const AES&); // and assign +}; + + +typedef BlockCipher<ENCRYPTION, AES, ECB> AES_ECB_Encryption; +typedef BlockCipher<DECRYPTION, AES, ECB> AES_ECB_Decryption; + +typedef BlockCipher<ENCRYPTION, AES, CBC> AES_CBC_Encryption; +typedef BlockCipher<DECRYPTION, AES, CBC> AES_CBC_Decryption; + + + +} // naemspace + +#endif // TAO_CRYPT_AES_HPP diff --git a/extra/yassl/taocrypt/include/algebra.hpp b/extra/yassl/taocrypt/include/algebra.hpp new file mode 100644 index 00000000000..74f244507f6 --- /dev/null +++ b/extra/yassl/taocrypt/include/algebra.hpp @@ -0,0 +1,316 @@ +/* algebra.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's algebra.h from CryptoPP */ + +#ifndef TAO_CRYPT_ALGEBRA_HPP +#define TAO_CRYPT_ALGEBRA_HPP + +#include "misc.hpp" + +namespace TaoCrypt { + +class Integer; + +// "const Element&" returned by member functions are references +// to internal data members. Since each object may have only +// one such data member for holding results, the following code +// will produce incorrect results: +// abcd = group.Add(group.Add(a,b), group.Add(c,d)); +// But this should be fine: +// abcd = group.Add(a, group.Add(b, group.Add(c,d)); + +//! Abstract Group +template <class T> class TAOCRYPT_NO_VTABLE AbstractGroup +{ +public: + typedef T Element; + + virtual ~AbstractGroup() {} + + virtual bool Equal(const Element &a, const Element &b) const =0; + virtual const Element& Identity() const =0; + virtual const Element& Add(const Element &a, const Element &b) const =0; + virtual const Element& Inverse(const Element &a) const =0; + virtual bool InversionIsFast() const {return false;} + + virtual const Element& Double(const Element &a) const; + virtual const Element& Subtract(const Element &a, const Element &b) const; + virtual Element& Accumulate(Element &a, const Element &b) const; + virtual Element& Reduce(Element &a, const Element &b) const; + + virtual Element ScalarMultiply(const Element &a, const Integer &e) const; + virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, + const Element &y, const Integer &e2) const; + + virtual void SimultaneousMultiply(Element *results, const Element &base, + const Integer *exponents, unsigned int exponentsCount) const; +}; + +//! Abstract Ring +template <class T> class TAOCRYPT_NO_VTABLE AbstractRing + : public AbstractGroup<T> +{ +public: + typedef T Element; + + AbstractRing() {m_mg.m_pRing = this;} + AbstractRing(const AbstractRing &source) {m_mg.m_pRing = this;} + AbstractRing& operator=(const AbstractRing &source) {return *this;} + + virtual bool IsUnit(const Element &a) const =0; + virtual const Element& MultiplicativeIdentity() const =0; + virtual const Element& Multiply(const Element&, const Element&) const =0; + virtual const Element& MultiplicativeInverse(const Element &a) const =0; + + virtual const Element& Square(const Element &a) const; + virtual const Element& Divide(const Element &a, const Element &b) const; + + virtual Element Exponentiate(const Element &a, const Integer &e) const; + virtual Element CascadeExponentiate(const Element &x, const Integer &e1, + const Element &y, const Integer &e2) const; + + virtual void SimultaneousExponentiate(Element *results, const Element&, + const Integer *exponents, unsigned int exponentsCount) const; + + virtual const AbstractGroup<T>& MultiplicativeGroup() const + {return m_mg;} + +private: + class MultiplicativeGroupT : public AbstractGroup<T> + { + public: + const AbstractRing<T>& GetRing() const + {return *m_pRing;} + + bool Equal(const Element &a, const Element &b) const + {return GetRing().Equal(a, b);} + + const Element& Identity() const + {return GetRing().MultiplicativeIdentity();} + + const Element& Add(const Element &a, const Element &b) const + {return GetRing().Multiply(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return a = GetRing().Multiply(a, b);} + + const Element& Inverse(const Element &a) const + {return GetRing().MultiplicativeInverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return GetRing().Divide(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return a = GetRing().Divide(a, b);} + + const Element& Double(const Element &a) const + {return GetRing().Square(a);} + + Element ScalarMultiply(const Element &a, const Integer &e) const + {return GetRing().Exponentiate(a, e);} + + Element CascadeScalarMultiply(const Element &x, const Integer &e1, + const Element &y, const Integer &e2) const + {return GetRing().CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousMultiply(Element *results, const Element &base, + const Integer *exponents, unsigned int exponentsCount) const + {GetRing().SimultaneousExponentiate(results, base, exponents, + exponentsCount);} + + const AbstractRing<T> *m_pRing; + }; + + MultiplicativeGroupT m_mg; +}; + +// ******************************************************** + +//! Base and Exponent +template <class T, class E = Integer> +struct BaseAndExponent +{ +public: + BaseAndExponent() {} + BaseAndExponent(const T &base, const E &exponent) : base(base), + exponent(exponent) {} + bool operator<(const BaseAndExponent<T, E> &rhs) const + {return exponent < rhs.exponent;} + T base; + E exponent; +}; + +// VC60 workaround: incomplete member template support +template <class Element, class Iterator> + Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, + Iterator begin, Iterator end); +template <class Element, class Iterator> + Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, + Iterator begin, Iterator end); + +// ******************************************************** + +//! Abstract Euclidean Domain +template <class T> class TAOCRYPT_NO_VTABLE AbstractEuclideanDomain + : public AbstractRing<T> +{ +public: + typedef T Element; + + virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, + const Element &d) const =0; + + virtual const Element& Mod(const Element &a, const Element &b) const =0; + virtual const Element& Gcd(const Element &a, const Element &b) const; + +protected: + mutable Element result; +}; + +// ******************************************************** + +//! EuclideanDomainOf +template <class T> class EuclideanDomainOf : public AbstractEuclideanDomain<T> +{ +public: + typedef T Element; + + EuclideanDomainOf() {} + + bool Equal(const Element &a, const Element &b) const + {return a==b;} + + const Element& Identity() const + {return Element::Zero();} + + const Element& Add(const Element &a, const Element &b) const + {return result = a+b;} + + Element& Accumulate(Element &a, const Element &b) const + {return a+=b;} + + const Element& Inverse(const Element &a) const + {return result = -a;} + + const Element& Subtract(const Element &a, const Element &b) const + {return result = a-b;} + + Element& Reduce(Element &a, const Element &b) const + {return a-=b;} + + const Element& Double(const Element &a) const + {return result = a.Doubled();} + + const Element& MultiplicativeIdentity() const + {return Element::One();} + + const Element& Multiply(const Element &a, const Element &b) const + {return result = a*b;} + + const Element& Square(const Element &a) const + {return result = a.Squared();} + + bool IsUnit(const Element &a) const + {return a.IsUnit();} + + const Element& MultiplicativeInverse(const Element &a) const + {return result = a.MultiplicativeInverse();} + + const Element& Divide(const Element &a, const Element &b) const + {return result = a/b;} + + const Element& Mod(const Element &a, const Element &b) const + {return result = a%b;} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, + const Element &d) const + {Element::Divide(r, q, a, d);} + +private: + mutable Element result; +}; + +//! Quotient Ring +template<class T> class QuotientRing : public AbstractRing<typename T::Element> +{ +public: + typedef T EuclideanDomain; + typedef typename T::Element Element; + + QuotientRing(const EuclideanDomain &domain, const Element &modulus) + : m_domain(domain), m_modulus(modulus) {} + + const EuclideanDomain & GetDomain() const + {return m_domain;} + + const Element& GetModulus() const + {return m_modulus;} + + bool Equal(const Element &a, const Element &b) const + {return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), + m_modulus), m_domain.Identity());} + + const Element& Identity() const + {return m_domain.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return m_domain.Add(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return m_domain.Accumulate(a, b);} + + const Element& Inverse(const Element &a) const + {return m_domain.Inverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return m_domain.Subtract(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return m_domain.Reduce(a, b);} + + const Element& Double(const Element &a) const + {return m_domain.Double(a);} + + bool IsUnit(const Element &a) const + {return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));} + + const Element& MultiplicativeIdentity() const + {return m_domain.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);} + + const Element& Square(const Element &a) const + {return m_domain.Mod(m_domain.Square(a), m_modulus);} + + const Element& MultiplicativeInverse(const Element &a) const; + +protected: + EuclideanDomain m_domain; + Element m_modulus; +}; + + +} // namespace + + +#endif // TAO_CRYPT_ALGEBRA_HPP diff --git a/extra/yassl/taocrypt/include/arc4.hpp b/extra/yassl/taocrypt/include/arc4.hpp new file mode 100644 index 00000000000..c919c8ea2ae --- /dev/null +++ b/extra/yassl/taocrypt/include/arc4.hpp @@ -0,0 +1,59 @@ +/* arc4.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* arc4.hpp defines ARC4 +*/ + + +#ifndef TAO_CRYPT_ARC4_HPP +#define TAO_CRYPT_ARC4_HPP + +#include "misc.hpp" + +namespace TaoCrypt { + + +// ARC4 encryption and decryption +class ARC4 { +public: + enum { STATE_SIZE = 256 }; + + typedef ARC4 Encryption; + typedef ARC4 Decryption; + + ARC4() {} + + void Process(byte*, const byte*, word32); + void SetKey(const byte*, word32); +private: + byte x_; + byte y_; + byte state_[STATE_SIZE]; + + ARC4(const ARC4&); // hide copy + const ARC4 operator=(const ARC4&); // and assign +}; + +} // namespace + + +#endif // TAO_CRYPT_ARC4_HPP + diff --git a/extra/yassl/taocrypt/include/asn.hpp b/extra/yassl/taocrypt/include/asn.hpp new file mode 100644 index 00000000000..71633339a40 --- /dev/null +++ b/extra/yassl/taocrypt/include/asn.hpp @@ -0,0 +1,327 @@ +/* asn.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* asn.hpp provides ASN1 BER, PublicKey, and x509v3 decoding +*/ + + +#ifndef TAO_CRYPT_ASN_HPP +#define TAO_CRYPT_ASN_HPP + + +#include "misc.hpp" +#include "block.hpp" +#include "list.hpp" +#include "error.hpp" + + + +namespace TaoCrypt { + +// these tags and flags are not complete +enum ASNTag +{ + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + TAG_NULL = 0x05, + OBJECT_IDENTIFIER = 0x06, + OBJECT_DESCRIPTOR = 0x07, + EXTERNAL = 0x08, + REAL = 0x09, + ENUMERATED = 0x0a, + UTF8_STRING = 0x0c, + SEQUENCE = 0x10, + SET = 0x11, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + VIDEOTEXT_STRING = 0x15, + IA5_STRING = 0x16, + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + GRAPHIC_STRING = 0x19, + VISIBLE_STRING = 0x1a, + GENERAL_STRING = 0x1b, + LONG_LENGTH = 0x80 +}; + +enum ASNIdFlag +{ + UNIVERSAL = 0x00, + DATA = 0x01, + HEADER = 0x02, + CONSTRUCTED = 0x20, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + PRIVATE = 0xc0 +}; + + +enum DNTags +{ + COMMON_NAME = 0x03, +}; + + +enum Constants +{ + MIN_DATE_SZ = 13, + MAX_DATE_SZ = 15, + MAX_ALGO_SZ = 16, + MAX_LENGTH_SZ = 5, + MAX_SEQ_SZ = 5, // enum(seq|con) + length(4) + MAX_ALGO_SIZE = 9, + MAX_DIGEST_SZ = 25, // SHA + enum(Bit or Octet) + length(4) + DSA_SIG_SZ = 40, +}; + + +class Source; +class RSA_PublicKey; +class RSA_PrivateKey; +class DSA_PublicKey; +class DSA_PrivateKey; +class Integer; +class DH; + + +// General BER decoding +class BER_Decoder { +protected: + Source& source_; +public: + explicit BER_Decoder(Source& s) : source_(s) {} + virtual ~BER_Decoder() {} + + Integer& GetInteger(Integer&); + word32 GetSequence(); + word32 GetSet(); + word32 GetVersion(); + word32 GetExplicitVersion(); + + Error GetError(); +private: + virtual void ReadHeader() = 0; + + BER_Decoder(const BER_Decoder&); // hide copy + BER_Decoder& operator=(const BER_Decoder&); // and assign +}; + + +// RSA Private Key BER Decoder +class RSA_Private_Decoder : public BER_Decoder { +public: + explicit RSA_Private_Decoder(Source& s) : BER_Decoder(s) {} + void Decode(RSA_PrivateKey&); +private: + void ReadHeader(); +}; + + +// RSA Public Key BER Decoder +class RSA_Public_Decoder : public BER_Decoder { +public: + explicit RSA_Public_Decoder(Source& s) : BER_Decoder(s) {} + void Decode(RSA_PublicKey&); +private: + void ReadHeader(); +}; + + +// DSA Private Key BER Decoder +class DSA_Private_Decoder : public BER_Decoder { +public: + explicit DSA_Private_Decoder(Source& s) : BER_Decoder(s) {} + void Decode(DSA_PrivateKey&); +private: + void ReadHeader(); +}; + + +// DSA Public Key BER Decoder +class DSA_Public_Decoder : public BER_Decoder { +public: + explicit DSA_Public_Decoder(Source& s) : BER_Decoder(s) {} + void Decode(DSA_PublicKey&); +private: + void ReadHeader(); +}; + + +// DH Key BER Decoder +class DH_Decoder : public BER_Decoder { +public: + explicit DH_Decoder(Source& s) : BER_Decoder(s) {} + void Decode(DH&); +private: + void ReadHeader(); +}; + + +// General PublicKey +class PublicKey { + byte* key_; + word32 sz_; +public: + explicit PublicKey(const byte* k = 0, word32 s = 0); + ~PublicKey() { delete[] key_; } + + const byte* GetKey() const { return key_; } + word32 size() const { return sz_; } + + void SetKey(const byte*); + void SetSize(word32 s); + + void AddToEnd(const byte*, word32); +private: + PublicKey(const PublicKey&); // hide copy + PublicKey& operator=(const PublicKey&); // and assign +}; + + +enum { SHA_SIZE = 20 }; + + +// A Signing Authority +class Signer { + PublicKey key_; + char* name_; + byte hash_[SHA_SIZE]; +public: + Signer(const byte* k, word32 kSz, const char* n, const byte* h); + ~Signer(); + + const PublicKey& GetPublicKey() const { return key_; } + const char* GetCommonName() const { return name_; } + const byte* GetHash() const { return hash_; } + +private: + Signer(const Signer&); // hide copy + Signer& operator=(const Signer&); // and assign +}; + + +typedef mySTL::list<Signer*> SignerList; + + +enum SigType { SHAwDSA = 517, MD2wRSA = 646, MD5wRSA = 648, SHAwRSA =649}; +enum HashType { MD2h = 646, MD5h = 649, SHAh = 88 }; +enum KeyType { DSAk = 515, RSAk = 645 }; // sums of algo OID + + +// an x509v Certificate BER Decoder +class CertDecoder : public BER_Decoder { +public: + explicit CertDecoder(Source&, bool decode = true, SignerList* = 0); + ~CertDecoder(); + + const PublicKey& GetPublicKey() const { return key_; } + KeyType GetKeyType() const { return KeyType(keyOID_); } + const char* GetIssuer() const { return issuer_; } + const char* GetCommonName() const { return subject_; } + const byte* GetHash() const { return subjectHash_; } + + void DecodeToKey(); + + enum DateType { BEFORE, AFTER }; + enum NameType { ISSUER, SUBJECT }; +private: + PublicKey key_; + word32 certBegin_; // offset to start of cert + word32 sigIndex_; // offset to start of signature + word32 sigLength_; // length of signature + word32 signatureOID_; // sum of algorithm object id + word32 keyOID_; // sum of key algo object id + byte subjectHash_[SHA_SIZE]; // hash of all Names + byte issuerHash_[SHA_SIZE]; // hash of all Names + byte* signature_; + char* issuer_; // CommonName + char* subject_; // CommonName + + void ReadHeader(); + void Decode(SignerList*); + void StoreKey(); + void AddDSA(); + bool ValidateSelfSignature(); + bool ValidateSignature(SignerList*); + bool ConfirmSignature(Source&); + void GetKey(); + void GetName(NameType); + void GetValidity(); + void GetDate(DateType); + void GetCompareHash(const byte*, word32, byte*, word32); + word32 GetAlgoId(); + word32 GetSignature(); + word32 GetDigest(); +}; + + +word32 GetLength(Source&); + +word32 SetLength(word32, byte*); +word32 SetSequence(word32, byte*); + +word32 EncodeDSA_Signature(const byte* signature, byte* output); +word32 EncodeDSA_Signature(const Integer& r, const Integer& s, byte* output); +word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz); + + +// General DER encoding +class DER_Encoder { +public: + DER_Encoder() {} + virtual ~DER_Encoder() {} + + word32 SetAlgoID(HashType, byte*); + + Error GetError() const { return error_; } +private: + //virtual void WriteHeader() = 0; + Error error_; + + DER_Encoder(const DER_Encoder&); // hide copy + DER_Encoder& operator=(const DER_Encoder&); // and assign +}; + + + +class Signature_Encoder : public DER_Encoder { + const byte* digest_; + word32 digestSz_; + SigType digestOID_; +public: + explicit Signature_Encoder(const byte*, word32, HashType, Source&); + +private: + void WriteHeader(); + word32 SetDigest(const byte*, word32, byte*); + + Signature_Encoder(const Signature_Encoder&); // hide copy + Signature_Encoder& operator=(const Signature_Encoder&); // and assign +}; + + +} // namespace + + +#endif // TAO_CRYPT_ASN_HPP diff --git a/extra/yassl/taocrypt/include/block.hpp b/extra/yassl/taocrypt/include/block.hpp new file mode 100644 index 00000000000..6e96ec9cc35 --- /dev/null +++ b/extra/yassl/taocrypt/include/block.hpp @@ -0,0 +1,211 @@ +/* block.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* block.hpp provides word and byte blocks with configurable allocators +*/ + + +#ifndef TAO_CRYPT_BLOCK_HPP +#define TAO_CRYPT_BLOCK_HPP + +#include "algorithm.hpp" // mySTL::swap +#include "stdexcept.hpp" // mySTL::runtime_error +#include "misc.hpp" +#include <string.h> // memcpy +#include <cstddef> // ptrdiff_t + + +#if defined(_MSC_VER) && defined(_CRTAPI1) +#define TAOCRYPT_MSVCRT6 +#endif + + +namespace TaoCrypt { + + +// a Base class for Allocators +template<class T> +class AllocatorBase +{ +public: + typedef T value_type; + typedef size_t size_type; +#ifdef TAOCRYPT_MSVCRT6 + typedef ptrdiff_t difference_type; +#else + typedef std::ptrdiff_t difference_type; +#endif + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + + pointer address(reference r) const {return (&r);} + const_pointer address(const_reference r) const {return (&r); } + void construct(pointer p, const T& val) {new (p) T(val);} + void destroy(pointer p) {p->~T();} + size_type max_size() const {return ~size_type(0)/sizeof(T);} +protected: + static void CheckSize(size_t n) + { + assert(n <= ~size_t(0) / sizeof(T)); + } +}; + + +// General purpose realloc +template<typename T, class A> +typename A::pointer StdReallocate(A& a, T* p, typename A::size_type oldSize, + typename A::size_type newSize, bool preserve) +{ + if (oldSize == newSize) + return p; + + if (preserve) { + A b = A(); + typename A::pointer newPointer = b.allocate(newSize, 0); + memcpy(newPointer, p, sizeof(T) * min(oldSize, newSize)); + a.deallocate(p, oldSize); + mySTL::swap(a, b); + return newPointer; + } + else { + a.deallocate(p, oldSize); + return a.allocate(newSize, 0); + } +} + + +// Allocator that zeros out memory on deletion +template <class T> +class AllocatorWithCleanup : public AllocatorBase<T> +{ +public: + typedef typename AllocatorBase<T>::pointer pointer; + typedef typename AllocatorBase<T>::size_type size_type; + + pointer allocate(size_type n, const void* = 0) + { + CheckSize(n); + if (n == 0) + return 0; + return new (tc) T[n]; + } + + void deallocate(void* p, size_type n) + { + memset(p, 0, n * sizeof(T)); + delete [] (T*)p; + } + + pointer reallocate(T* p, size_type oldSize, size_type newSize, + bool preserve) + { + return StdReallocate(*this, p, oldSize, newSize, preserve); + } + + // VS.NET STL enforces the policy of "All STL-compliant allocators have to + // provide a template class member called rebind". + template <class U> struct rebind { typedef AllocatorWithCleanup<U> other;}; +}; + + +// Block class template +template<typename T, class A = AllocatorWithCleanup<T> > +class Block { +public: + explicit Block(word32 s = 0) : sz_(s), buffer_(allocator_.allocate(sz_)) + { CleanNew(sz_); } + + Block(const T* buff, word32 s) : sz_(s), buffer_(allocator_.allocate(sz_)) + { memcpy(buffer_, buff, sz_ * sizeof(T)); } + + Block(const Block& that) : sz_(that.sz_), buffer_(allocator_.allocate(sz_)) + { memcpy(buffer_, that.buffer_, sz_ * sizeof(T)); } + + Block& operator=(const Block& that) { + Block tmp(that); + Swap(tmp); + return *this; + } + + T& operator[] (word32 i) { assert(i < sz_); return buffer_[i]; } + const T& operator[] (word32 i) const + { assert(i < sz_); return buffer_[i]; } + + T* operator+ (word32 i) { return buffer_ + i; } + const T* operator+ (word32 i) const { return buffer_ + i; } + + word32 size() const { return sz_; } + + T* get_buffer() const { return buffer_; } + T* begin() const { return get_buffer(); } + + void CleanGrow(word32 newSize) + { + if (newSize > sz_) { + buffer_ = allocator_.reallocate(buffer_, sz_, newSize, true); + memset(buffer_ + sz_, 0, (newSize - sz_) * sizeof(T)); + sz_ = newSize; + } + } + + void CleanNew(word32 newSize) + { + New(newSize); + memset(buffer_, 0, sz_ * sizeof(T)); + } + + void New(word32 newSize) + { + buffer_ = allocator_.reallocate(buffer_, sz_, newSize, false); + sz_ = newSize; + } + + void resize(word32 newSize) + { + buffer_ = allocator_.reallocate(buffer_, sz_, newSize, true); + sz_ = newSize; + } + + void Swap(Block& other) { + mySTL::swap(sz_, other.sz_); + mySTL::swap(buffer_, other.buffer_); + mySTL::swap(allocator_, other.allocator_); + } + + ~Block() { allocator_.deallocate(buffer_, sz_); } +private: + word32 sz_; // size in Ts + T* buffer_; + A allocator_; +}; + + +typedef Block<byte> ByteBlock; +typedef Block<word> WordBlock; +typedef Block<word32> Word32Block; + + +} // namespace + +#endif // TAO_CRYPT_BLOCK_HPP diff --git a/extra/yassl/taocrypt/include/coding.hpp b/extra/yassl/taocrypt/include/coding.hpp new file mode 100644 index 00000000000..9aab2a30c7e --- /dev/null +++ b/extra/yassl/taocrypt/include/coding.hpp @@ -0,0 +1,94 @@ +/* coding.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* coding.hpp defines hex and base64 encoding/decoing +*/ + +#ifndef TAO_CRYPT_CODING_HPP +#define TAO_CRYPT_CODING_HPP + +#include "misc.hpp" +#include "block.hpp" + +namespace TaoCrypt { + +class Source; + + +// Hex Encoding, see RFC 3548 +class HexEncoder { + ByteBlock encoded_; + Source& plain_; +public: + explicit HexEncoder(Source& s) : plain_(s) { Encode(); } +private: + void Encode(); + + HexEncoder(const HexEncoder&); // hide copy + HexEncoder& operator=(const HexEncoder&); // and assign +}; + + +// Hex Decoding, see RFC 3548 +class HexDecoder { + ByteBlock decoded_; + Source& coded_; +public: + explicit HexDecoder(Source& s) : coded_(s) { Decode(); } +private: + void Decode(); + + HexDecoder(const HexDecoder&); // hide copy + HexDecoder& operator=(const HexDecoder&); // and assign +}; + + +// Base 64 encoding, see RFC 3548 +class Base64Encoder { + ByteBlock encoded_; + Source& plain_; +public: + explicit Base64Encoder(Source& s) : plain_(s) { Encode(); } +private: + void Encode(); + + Base64Encoder(const Base64Encoder&); // hide copy + Base64Encoder& operator=(const Base64Encoder&); // and assign +}; + + +// Base 64 decoding, see RFC 3548 +class Base64Decoder { + ByteBlock decoded_; + Source& coded_; +public: + explicit Base64Decoder(Source& s) : coded_(s) { Decode(); } +private: + void Decode(); + + Base64Decoder(const Base64Decoder&); // hide copy + Base64Decoder& operator=(const Base64Decoder&); // and assign +}; + + +} // namespace + +#endif // TAO_CRYPT_CODING_HPP diff --git a/extra/yassl/taocrypt/include/des.hpp b/extra/yassl/taocrypt/include/des.hpp new file mode 100644 index 00000000000..e8100b4e198 --- /dev/null +++ b/extra/yassl/taocrypt/include/des.hpp @@ -0,0 +1,121 @@ +/* des.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* des.hpp defines DES, DES_EDE2, and DES_EDE3 + see FIPS 46-2 and FIPS 81 +*/ + + +#ifndef TAO_CRYPT_DES_HPP +#define TAO_CRYPT_DES_HPP + +#include <string.h> +#include "misc.hpp" +#include "modes.hpp" + +namespace TaoCrypt { + +enum { DES_BLOCK_SIZE = 8 }; + +// Base for all DES types +class DES_BASE : public Mode_BASE<DES_BLOCK_SIZE> { +public: + enum { BLOCK_SIZE = DES_BLOCK_SIZE, KEY_SIZE = 32, BOXES = 8, + BOX_SIZE = 64 }; + + DES_BASE(CipherDir DIR, Mode MODE) : dir_(DIR), mode_(MODE) {} + + void Process(byte*, const byte*, word32); +protected: + CipherDir dir_; + Mode mode_; +private: + DES_BASE(const DES_BASE&); // hide copy + DES_BASE& operator=(const DES_BASE&); // and assign +}; + + +// DES +class DES : public DES_BASE { +public: + DES(CipherDir DIR, Mode MODE) : DES_BASE(DIR, MODE) {} + + void SetKey(const byte*, word32, CipherDir dir); + void RawProcessBlock(word32&, word32&) const; + void ProcessAndXorBlock(const byte*, const byte*, byte*) const; +private: + word32 k_[KEY_SIZE]; +}; + + +// DES_EDE2 +class DES_EDE2 : public DES_BASE { +public: + DES_EDE2(CipherDir DIR, Mode MODE) + : DES_BASE(DIR, MODE), des1_(DIR, MODE), des2_(DIR, MODE) {} + + void SetKey(const byte*, word32, CipherDir dir); + void ProcessAndXorBlock(const byte*, const byte*, byte*) const; +private: + DES des1_; + DES des2_; +}; + + +// DES_EDE3 +class DES_EDE3 : public DES_BASE { +public: + DES_EDE3(CipherDir DIR, Mode MODE) + : DES_BASE(DIR, MODE), des1_(DIR, MODE), des2_(DIR, MODE), + des3_(DIR, MODE) {} + + void SetKey(const byte*, word32, CipherDir dir); + void ProcessAndXorBlock(const byte*, const byte*, byte*) const; +private: + DES des1_; + DES des2_; + DES des3_; +}; + + +typedef BlockCipher<ENCRYPTION, DES, ECB> DES_ECB_Encryption; +typedef BlockCipher<DECRYPTION, DES, ECB> DES_ECB_Decryption; + +typedef BlockCipher<ENCRYPTION, DES, CBC> DES_CBC_Encryption; +typedef BlockCipher<DECRYPTION, DES, CBC> DES_CBC_Decryption; + +typedef BlockCipher<ENCRYPTION, DES_EDE2, ECB> DES_EDE2_ECB_Encryption; +typedef BlockCipher<DECRYPTION, DES_EDE2, ECB> DES_EDE2_ECB_Decryption; + +typedef BlockCipher<ENCRYPTION, DES_EDE2, CBC> DES_EDE2_CBC_Encryption; +typedef BlockCipher<DECRYPTION, DES_EDE2, CBC> DES_EDE2_CBC_Decryption; + +typedef BlockCipher<ENCRYPTION, DES_EDE3, ECB> DES_EDE3_ECB_Encryption; +typedef BlockCipher<DECRYPTION, DES_EDE3, ECB> DES_EDE3_ECB_Decryption; + +typedef BlockCipher<ENCRYPTION, DES_EDE3, CBC> DES_EDE3_CBC_Encryption; +typedef BlockCipher<DECRYPTION, DES_EDE3, CBC> DES_EDE3_CBC_Decryption; + + +} // namespace + + +#endif // TAO_CRYPT_DES_HPP diff --git a/extra/yassl/taocrypt/include/dh.hpp b/extra/yassl/taocrypt/include/dh.hpp new file mode 100644 index 00000000000..54a1705546b --- /dev/null +++ b/extra/yassl/taocrypt/include/dh.hpp @@ -0,0 +1,89 @@ +/* dh.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* dh.hpp provides Diffie-Hellman support +*/ + + +#ifndef TAO_CRYPT_DH_HPP +#define TAO_CRYPT_DH_HPP + +#include "misc.hpp" +#include "integer.hpp" + +namespace TaoCrypt { + + +class Source; + + +// Diffie-Hellman +class DH { +public: + DH() {} + DH(Integer& p, Integer& g) : p_(p), g_(g) {} + explicit DH(Source&); + + DH(const DH& that) : p_(that.p_), g_(that.g_) {} + DH& operator=(const DH& that) + { + DH tmp(that); + Swap(tmp); + return *this; + } + + void Swap(DH& other) + { + p_.Swap(other.p_); + g_.Swap(other.g_); + } + + void Initialize(Source&); + void Initialize(Integer& p, Integer& g) + { + SetP(p); + SetG(g); + } + + void GenerateKeyPair(RandomNumberGenerator&, byte*, byte*); + void Agree(byte*, const byte*, const byte*); + + void SetP(const Integer& p) { p_ = p; } + void SetG(const Integer& g) { g_ = g; } + + Integer& GetP() { return p_; } + Integer& GetG() { return g_; } + + // for p and agree + word32 GetByteLength() const { return p_.ByteCount(); } +private: + // group parms + Integer p_; + Integer g_; + + void GeneratePrivate(RandomNumberGenerator&, byte*); + void GeneratePublic(const byte*, byte*); +}; + + +} // namespace + +#endif // TAO_CRYPT_DH_HPP diff --git a/extra/yassl/taocrypt/include/dsa.hpp b/extra/yassl/taocrypt/include/dsa.hpp new file mode 100644 index 00000000000..f1fdd2dfa25 --- /dev/null +++ b/extra/yassl/taocrypt/include/dsa.hpp @@ -0,0 +1,129 @@ +/* dsa.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* dsa.hpp provides Digitial Signautre Algorithm see FIPS 186-2 +*/ + +#ifndef TAO_CRYPT_DSA_HPP +#define TAO_CRYPT_DSA_HPP + +#include "integer.hpp" + + +namespace TaoCrypt { + +class Source; + + +class DSA_PublicKey { +protected: + Integer p_; + Integer q_; + Integer g_; + Integer y_; +public: + DSA_PublicKey() {} + explicit DSA_PublicKey(Source&); + + void Initialize(Source&); + void Initialize(const Integer& p, const Integer& q, const Integer& g, + const Integer& y); + + const Integer& GetModulus() const; + const Integer& GetSubGroupOrder() const; + const Integer& GetSubGroupGenerator() const; + const Integer& GetPublicPart() const; + + void SetModulus(const Integer&); + void SetSubGroupOrder(const Integer&); + void SetSubGroupGenerator(const Integer&); + void SetPublicPart(const Integer&); + + word32 SignatureLength() const; + + DSA_PublicKey(const DSA_PublicKey&); + DSA_PublicKey& operator=(const DSA_PublicKey&); + + void Swap(DSA_PublicKey& other); +}; + + + +class DSA_PrivateKey : public DSA_PublicKey { + Integer x_; +public: + DSA_PrivateKey() {} + explicit DSA_PrivateKey(Source&); + + void Initialize(Source&); + void Initialize(const Integer& p, const Integer& q, const Integer& g, + const Integer& y, const Integer& x); + + const Integer& GetPrivatePart() const; + + void SetPrivatePart(const Integer&); +private: + DSA_PrivateKey(const DSA_PrivateKey&); // hide copy + DSA_PrivateKey& operator=(const DSA_PrivateKey&); // and assign +}; + + + +class DSA_Signer { + const DSA_PrivateKey& key_; + Integer r_; + Integer s_; +public: + explicit DSA_Signer(const DSA_PrivateKey&); + + word32 Sign(const byte* sha_digest, byte* sig, RandomNumberGenerator&); + + const Integer& GetR() const; + const Integer& GetS() const; +private: + DSA_Signer(const DSA_Signer&); // hide copy + DSA_Signer& operator=(DSA_Signer&); // and assign +}; + + +class DSA_Verifier { + const DSA_PublicKey& key_; + Integer r_; + Integer s_; +public: + explicit DSA_Verifier(const DSA_PublicKey&); + + bool Verify(const byte* sha_digest, const byte* sig); + + const Integer& GetR() const; + const Integer& GetS() const; +private: + DSA_Verifier(const DSA_Verifier&); // hide copy + DSA_Verifier& operator=(const DSA_Verifier&); // and assign +}; + + + + + +} // namespace + +#endif // TAO_CRYPT_DSA_HPP diff --git a/extra/yassl/taocrypt/include/error.hpp b/extra/yassl/taocrypt/include/error.hpp new file mode 100644 index 00000000000..cb7f82731c7 --- /dev/null +++ b/extra/yassl/taocrypt/include/error.hpp @@ -0,0 +1,86 @@ +/* error.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* error.hpp provides a taocrypt error numbers + * + */ + + +#ifndef TAO_CRYPT_ERROR_HPP +#define TAO_CRYPT_ERROR_HPP + + +namespace TaoCrypt { + + +enum ErrorNumber { + +NO_ERROR = 0, // "not in error state" + +// RandomNumberGenerator +WINCRYPT_E = 1001, // "bad wincrypt acquire" +CRYPTGEN_E = 1002, // "CryptGenRandom error" +OPEN_RAN_E = 1003, // "open /dev/urandom error" +READ_RAN_E = 1004, // "read /dev/urandom error" + +// Integer +INTEGER_E = 1010, // "bad DER Integer Header" + + +// ASN.1 +SEQUENCE_E = 1020, // "bad Sequence Header" +SET_E = 1021, // "bad Set Header" +VERSION_E = 1022, // "version length not 1" +SIG_OID_E = 1023, // "signature OID mismatch" +BIT_STR_E = 1024, // "bad BitString Header" +UNKNOWN_OID_E = 1025, // "unknown key OID type" +OBJECT_ID_E = 1026, // "bad Ojbect ID Header" +TAG_NULL_E = 1027, // "expected TAG NULL" +EXPECT_0_E = 1028, // "expected 0" +OCTET_STR_E = 1029, // "bad Octet String Header" +TIME_E = 1030, // "bad TIME" + +DATE_SZ_E = 1031, // "bad Date Size" +SIG_LEN_E = 1032, // "bad Signature Length" +UNKOWN_SIG_E = 1033, // "unknown signature OID" +UNKOWN_HASH_E = 1034, // "unknown hash OID" +DSA_SZ_E = 1035, // "bad DSA r or s size" +BEFORE_DATE_E = 1036, // "before date in the future" +AFTER_DATE_E = 1037, // "after date in the past" +SIG_CONFIRM_E = 1038, // "bad signature confirmation" + +}; + + +struct Error { + ErrorNumber what_; // description number, 0 for no error + + explicit Error(ErrorNumber w = NO_ERROR) : what_(w) {} + + ErrorNumber What() const { return what_; } + void SetError(ErrorNumber w) { what_ = w; } +}; + + + +} // namespace TaoCrypt + +#endif // TAO_CRYPT_ERROR_HPP diff --git a/extra/yassl/taocrypt/include/file.hpp b/extra/yassl/taocrypt/include/file.hpp new file mode 100644 index 00000000000..b27ab3aebf3 --- /dev/null +++ b/extra/yassl/taocrypt/include/file.hpp @@ -0,0 +1,124 @@ +/* file.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* file.hpp provies File Sources and Sinks +*/ + + +#ifndef TAO_CRYPT_FILE_HPP +#define TAO_CRYPT_FILE_HPP + +#include "misc.hpp" +#include "block.hpp" +#include "error.hpp" +#include <cstdio> + +namespace TaoCrypt { + + +class Source { + ByteBlock buffer_; + word32 current_; + Error error_; +public: + explicit Source(word32 sz = 0) : buffer_(sz), current_(0) {} + Source(const byte* b, word32 sz) : buffer_(b, sz), current_(0) {} + + word32 size() const { return buffer_.size(); } + void grow(word32 sz) { buffer_.CleanGrow(sz); } + + const byte* get_buffer() const { return buffer_.get_buffer(); } + const byte* get_current() const { return &buffer_[current_]; } + word32 get_index() const { return current_; } + void set_index(word32 i) { current_ = i; } + + byte operator[] (word32 i) { current_ = i; return next(); } + byte next() { return buffer_[current_++]; } + byte prev() { return buffer_[--current_]; } + + void add(const byte* data, word32 len) + { + memcpy(buffer_.get_buffer() + current_, data, len); + current_ += len; + } + + void advance(word32 i) { current_ += i; } + void reset(ByteBlock&); + + Error GetError() { return error_; } + void SetError(ErrorNumber w) { error_.SetError(w); } + + friend class FileSource; // for get() +private: + Source(const Source& that) : buffer_(that.buffer_), current_(that.current_) {} + Source& operator=(const Source& that) + { + Source tmp(that); + Swap(tmp); + return *this; + } + + void Swap(Source& other) + { + buffer_.Swap(other.buffer_); + mySTL::swap(current_, other.current_); + } + +}; + + +// File Source +class FileSource { + FILE* file_; +public: + FileSource(const char* fname, Source& source); + ~FileSource(); + + word32 size(bool use_current = false); +private: + word32 get(Source&); + word32 size_left(); + + FileSource(const FileSource&); // hide + FileSource& operator=(const FileSource&); // hide +}; + + +// File Sink +class FileSink { + FILE* file_; +public: + FileSink(const char* fname, Source& source); + ~FileSink(); + + word32 size(bool use_current = false); +private: + void put(Source&); + + FileSink(const FileSink&); // hide + FileSink& operator=(const FileSink&); // hide +}; + + + +} // namespace + +#endif // TAO_CRYPT_FILE_HPP diff --git a/extra/yassl/taocrypt/include/hash.hpp b/extra/yassl/taocrypt/include/hash.hpp new file mode 100644 index 00000000000..1703de23713 --- /dev/null +++ b/extra/yassl/taocrypt/include/hash.hpp @@ -0,0 +1,73 @@ +/* hash.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* hash.hpp provides a base for digest types +*/ + + +#ifndef TAO_CRYPT_HASH_HPP +#define TAO_CRYPT_HASH_HPP + +#include "misc.hpp" + +namespace TaoCrypt { + + +// HASH +class HASH { +public: + virtual ~HASH() {} + + virtual void Update(const byte*, word32) = 0; + virtual void Final(byte*) = 0; + + virtual void Init() = 0; + + virtual word32 getBlockSize() const = 0; + virtual word32 getDigestSize() const = 0; +}; + + +// HASH with Transform +class HASHwithTransform : public HASH { +public: + HASHwithTransform(word32 digSz, word32 buffSz) + : digest_(new (tc) word32[digSz]), buffer_(new (tc) byte[buffSz]) {} + virtual ~HASHwithTransform() { delete[] buffer_; delete[] digest_; } + + virtual ByteOrder getByteOrder() const = 0; + virtual word32 getPadSize() const = 0; + + virtual void Update(const byte*, word32); + virtual void Final(byte*); +protected: + word32 buffLen_; + word32 length_; // in Bits + word32* digest_; + byte* buffer_; + + virtual void Transform() = 0; +}; + + +} // namespace + +#endif // TAO_CRYPT_HASH_HPP diff --git a/extra/yassl/taocrypt/include/hmac.hpp b/extra/yassl/taocrypt/include/hmac.hpp new file mode 100644 index 00000000000..dcfef225d89 --- /dev/null +++ b/extra/yassl/taocrypt/include/hmac.hpp @@ -0,0 +1,128 @@ +/* hmac.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* hamc.hpp implements HMAC, see RFC 2104 +*/ + + +#ifndef TAO_CRYPT_HMAC_HPP +#define TAO_CRYPT_HMAC_HPP + +#include "hash.hpp" + +namespace TaoCrypt { + + +// HMAC class template +template <class T> +class HMAC { +public: + enum { IPAD = 0x36, OPAD = 0x5C }; + + HMAC() { Init(); } + void Update(const byte*, word32); + void Final(byte*); + void Init(); + + void SetKey(const byte*, word32); +private: + byte ipad_[T::BLOCK_SIZE]; + byte opad_[T::BLOCK_SIZE]; + byte innerHash_[T::DIGEST_SIZE]; + bool innerHashKeyed_; + T mac_; + + void KeyInnerHash(); + + HMAC(const HMAC&); + HMAC& operator= (const HMAC&); +}; + + +// Setup +template <class T> +void HMAC<T>::Init() +{ + mac_.Init(); + innerHashKeyed_ = false; +} + + +// Key generation +template <class T> +void HMAC<T>::SetKey(const byte* key, word32 length) +{ + Init(); + + if (length <= T::BLOCK_SIZE) + memcpy(ipad_, key, length); + else { + mac_.Update(key, length); + mac_.Final(ipad_); + length = T::DIGEST_SIZE; + } + memset(ipad_ + length, 0, T::BLOCK_SIZE - length); + + for (word32 i = 0; i < T::BLOCK_SIZE; i++) { + opad_[i] = ipad_[i] ^ OPAD; + ipad_[i] ^= IPAD; + } +} + + +// Inner Key Hash +template <class T> +void HMAC<T>::KeyInnerHash() +{ + mac_.Update(ipad_, T::BLOCK_SIZE); + innerHashKeyed_ = true; +} + + +// Update +template <class T> +void HMAC<T>::Update(const byte* msg, word32 length) +{ + if (!innerHashKeyed_) + KeyInnerHash(); + mac_.Update(msg, length); +} + + +// Final +template <class T> +void HMAC<T>::Final(byte* hash) +{ + if (!innerHashKeyed_) + KeyInnerHash(); + mac_.Final(innerHash_); + + mac_.Update(opad_, T::BLOCK_SIZE); + mac_.Update(innerHash_, T::DIGEST_SIZE); + mac_.Final(hash); + + innerHashKeyed_ = false; +} + + +} // namespace + +#endif // TAO_CRYPT_HMAC_HPP diff --git a/extra/yassl/taocrypt/include/integer.hpp b/extra/yassl/taocrypt/include/integer.hpp new file mode 100644 index 00000000000..1706b4c0eea --- /dev/null +++ b/extra/yassl/taocrypt/include/integer.hpp @@ -0,0 +1,320 @@ +/* integer.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's integer.h from CryptoPP */ + + +#ifndef TAO_CRYPT_INTEGER_HPP +#define TAO_CRYPT_INTEGER_HPP + +#include "misc.hpp" +#include "block.hpp" +#include "random.hpp" +#include "file.hpp" +#include <cstring> +#include "algorithm.hpp" // mySTL::swap + + +#ifdef TAOCRYPT_X86ASM_AVAILABLE + +#ifdef _M_IX86 + #if (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 500)) || \ + (defined(__ICL) && (__ICL >= 500)) + #define SSE2_INTRINSICS_AVAILABLE + #define TAOCRYPT_MM_MALLOC_AVAILABLE + #elif defined(_MSC_VER) + // _mm_free seems to be the only way to tell if the Processor Pack is + //installed or not + #include <malloc.h> + #if defined(_mm_free) + #define SSE2_INTRINSICS_AVAILABLE + #define TAOCRYPT_MM_MALLOC_AVAILABLE + #endif + #endif +#endif + +// SSE2 intrinsics work in GCC 3.3 or later +#if defined(__SSE2__) && (__GNUC_MAJOR__ > 3 || __GNUC_MINOR__ > 2) + #define SSE2_INTRINSICS_AVAILABLE +#endif + +#endif // X86ASM + + + + +namespace TaoCrypt { + +#if defined(SSE2_INTRINSICS_AVAILABLE) + + // Allocator handling proper alignment + template <class T> + class AlignedAllocator : public AllocatorBase<T> + { + public: + typedef typename AllocatorBase<T>::pointer pointer; + typedef typename AllocatorBase<T>::size_type size_type; + + pointer allocate(size_type n, const void* = 0); + void deallocate(void* p, size_type n); + pointer reallocate(T* p, size_type oldSize, size_type newSize, + bool preserve) + { + return StdReallocate(*this, p, oldSize, newSize, preserve); + } + + #if !(defined(TAOCRYPT_MALLOC_ALIGNMENT_IS_16) || \ + defined(TAOCRYPT_MEMALIGN_AVAILABLE) || \ + defined(TAOCRYPT_MM_MALLOC_AVAILABLE)) + #define TAOCRYPT_NO_ALIGNED_ALLOC + AlignedAllocator() : m_pBlock(0) {} + protected: + void *m_pBlock; + #endif + }; + + template class TAOCRYPT_DLL AlignedAllocator<word>; + typedef Block<word, AlignedAllocator<word> > AlignedWordBlock; +#else + typedef WordBlock AlignedWordBlock; +#endif + + +// general MIN +template<typename T> inline +const T& min(const T& a, const T& b) +{ + return a < b ? a : b; +} + + +// general MAX +template<typename T> inline +const T& max(const T& a, const T& b) +{ + return a > b ? a : b; +} + + +// Large Integer class +class Integer { +public: + enum Sign {POSITIVE = 0, NEGATIVE = 1 }; + enum Signedness { UNSIGNED, SIGNED }; + enum RandomNumberType { ANY, PRIME }; + + class DivideByZero {}; + + Integer(); + Integer(const Integer& t); + Integer(signed long value); + Integer(Sign s, word highWord, word lowWord); + + explicit Integer(const char* str); + explicit Integer(const wchar_t* str); + + // BER Decode Source + explicit Integer(Source&); + + Integer(const byte* encodedInteger, unsigned int byteCount, + Signedness s = UNSIGNED); + + ~Integer() {} + + static const Integer &Zero(); + static const Integer &One(); + static const Integer &Two(); + + Integer& Ref() { return *this; } + + Integer(RandomNumberGenerator& rng, const Integer& min, + const Integer& max); + + static Integer Power2(unsigned int e); + + unsigned int MinEncodedSize(Signedness = UNSIGNED) const; + unsigned int Encode(byte* output, unsigned int outputLen, + Signedness = UNSIGNED) const; + + void Decode(const byte* input, unsigned int inputLen, + Signedness = UNSIGNED); + void Decode(Source&); + + bool IsConvertableToLong() const; + signed long ConvertToLong() const; + + unsigned int BitCount() const; + unsigned int ByteCount() const; + unsigned int WordCount() const; + + bool GetBit(unsigned int i) const; + byte GetByte(unsigned int i) const; + unsigned long GetBits(unsigned int i, unsigned int n) const; + + bool IsZero() const { return !*this; } + bool NotZero() const { return !IsZero(); } + bool IsNegative() const { return sign_ == NEGATIVE; } + bool NotNegative() const { return !IsNegative(); } + bool IsPositive() const { return NotNegative() && NotZero(); } + bool NotPositive() const { return !IsPositive(); } + bool IsEven() const { return GetBit(0) == 0; } + bool IsOdd() const { return GetBit(0) == 1; } + + Integer& operator=(const Integer& t); + Integer& operator+=(const Integer& t); + Integer& operator-=(const Integer& t); + Integer& operator*=(const Integer& t) { return *this = Times(t); } + Integer& operator/=(const Integer& t) + { return *this = DividedBy(t);} + Integer& operator%=(const Integer& t) { return *this = Modulo(t); } + Integer& operator/=(word t) { return *this = DividedBy(t); } + Integer& operator%=(word t) { return *this = Modulo(t); } + Integer& operator<<=(unsigned int); + Integer& operator>>=(unsigned int); + + + void Randomize(RandomNumberGenerator &rng, unsigned int bitcount); + void Randomize(RandomNumberGenerator &rng, const Integer &min, + const Integer &max); + + void SetBit(unsigned int n, bool value = 1); + void SetByte(unsigned int n, byte value); + + void Negate(); + void SetPositive() { sign_ = POSITIVE; } + void SetNegative() { if (!!(*this)) sign_ = NEGATIVE; } + void Swap(Integer& a); + + bool operator!() const; + Integer operator+() const {return *this;} + Integer operator-() const; + Integer& operator++(); + Integer& operator--(); + Integer operator++(int) + { Integer temp = *this; ++*this; return temp; } + Integer operator--(int) + { Integer temp = *this; --*this; return temp; } + + int Compare(const Integer& a) const; + + Integer Plus(const Integer &b) const; + Integer Minus(const Integer &b) const; + Integer Times(const Integer &b) const; + Integer DividedBy(const Integer &b) const; + Integer Modulo(const Integer &b) const; + Integer DividedBy(word b) const; + word Modulo(word b) const; + + Integer operator>>(unsigned int n) const { return Integer(*this)>>=n; } + Integer operator<<(unsigned int n) const { return Integer(*this)<<=n; } + + Integer AbsoluteValue() const; + Integer Doubled() const { return Plus(*this); } + Integer Squared() const { return Times(*this); } + Integer SquareRoot() const; + + bool IsSquare() const; + bool IsUnit() const; + + Integer MultiplicativeInverse() const; + + friend Integer a_times_b_mod_c(const Integer& x, const Integer& y, + const Integer& m); + friend Integer a_exp_b_mod_c(const Integer& x, const Integer& e, + const Integer& m); + + static void Divide(Integer& r, Integer& q, const Integer& a, + const Integer& d); + static void Divide(word& r, Integer& q, const Integer& a, word d); + static void DivideByPowerOf2(Integer& r, Integer& q, const Integer& a, + unsigned int n); + static Integer Gcd(const Integer& a, const Integer& n); + + Integer InverseMod(const Integer& n) const; + word InverseMod(word n) const; + +private: + friend class ModularArithmetic; + friend class MontgomeryRepresentation; + friend class HalfMontgomeryRepresentation; + + Integer(word value, unsigned int length); + + int PositiveCompare(const Integer& t) const; + friend void PositiveAdd(Integer& sum, const Integer& a, const Integer& b); + friend void PositiveSubtract(Integer& diff, const Integer& a, + const Integer& b); + friend void PositiveMultiply(Integer& product, const Integer& a, + const Integer& b); + friend void PositiveDivide(Integer& remainder, Integer& quotient, const + Integer& dividend, const Integer& divisor); + AlignedWordBlock reg_; + Sign sign_; +}; + +inline bool operator==(const Integer& a, const Integer& b) + {return a.Compare(b)==0;} +inline bool operator!=(const Integer& a, const Integer& b) + {return a.Compare(b)!=0;} +inline bool operator> (const Integer& a, const Integer& b) + {return a.Compare(b)> 0;} +inline bool operator>=(const Integer& a, const Integer& b) + {return a.Compare(b)>=0;} +inline bool operator< (const Integer& a, const Integer& b) + {return a.Compare(b)< 0;} +inline bool operator<=(const Integer& a, const Integer& b) + {return a.Compare(b)<=0;} + +inline Integer operator+(const Integer &a, const Integer &b) + {return a.Plus(b);} +inline Integer operator-(const Integer &a, const Integer &b) + {return a.Minus(b);} +inline Integer operator*(const Integer &a, const Integer &b) + {return a.Times(b);} +inline Integer operator/(const Integer &a, const Integer &b) + {return a.DividedBy(b);} +inline Integer operator%(const Integer &a, const Integer &b) + {return a.Modulo(b);} +inline Integer operator/(const Integer &a, word b) {return a.DividedBy(b);} +inline word operator%(const Integer &a, word b) {return a.Modulo(b);} + +inline void swap(Integer &a, Integer &b) +{ + a.Swap(b); +} + + +Integer CRT(const Integer& xp, const Integer& p, const Integer& xq, + const Integer& q, const Integer& u); +inline Integer ModularExponentiation(const Integer& a, const Integer& e, + const Integer& m) +{ + return a_exp_b_mod_c(a, e, m); +} + +Integer ModularRoot(const Integer& a, const Integer& dp, const Integer& dq, + const Integer& p, const Integer& q, const Integer& u); + + + +} // namespace + +#endif // TAO_CRYPT_INTEGER_HPP diff --git a/extra/yassl/taocrypt/include/md2.hpp b/extra/yassl/taocrypt/include/md2.hpp new file mode 100644 index 00000000000..1e1c17e9cbe --- /dev/null +++ b/extra/yassl/taocrypt/include/md2.hpp @@ -0,0 +1,67 @@ +/* md5.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* md2.hpp provides MD2 digest support, see RFC 1319 +*/ + +#ifndef TAO_CRYPT_MD2_HPP +#define TAO_CRYPT_MD2_HPP + + +#include "hash.hpp" +#include "block.hpp" + + +namespace TaoCrypt { + + +// MD2 digest +class MD2 : public HASH { +public: + enum { BLOCK_SIZE = 16, DIGEST_SIZE = 16, PAD_SIZE = 16, X_SIZE = 48 }; + MD2(); + + word32 getBlockSize() const { return BLOCK_SIZE; } + word32 getDigestSize() const { return DIGEST_SIZE; } + + void Update(const byte*, word32); + void Final(byte*); + + void Init(); + void Swap(MD2&); +private: + ByteBlock X_, C_, buffer_; + word32 count_; // bytes % PAD_SIZE + + MD2(const MD2&); + MD2& operator=(const MD2&); +}; + +inline void swap(MD2& a, MD2& b) +{ + a.Swap(b); +} + + +} // namespace + +#endif // TAO_CRYPT_MD2_HPP + diff --git a/extra/yassl/taocrypt/include/md5.hpp b/extra/yassl/taocrypt/include/md5.hpp new file mode 100644 index 00000000000..0198daa466e --- /dev/null +++ b/extra/yassl/taocrypt/include/md5.hpp @@ -0,0 +1,63 @@ +/* md5.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* md5.hpp provides MD5 digest support, see RFC 1321 +*/ + +#ifndef TAO_CRYPT_MD5_HPP +#define TAO_CRYPT_MD5_HPP + +#include "hash.hpp" + +namespace TaoCrypt { + + +// MD5 digest +class MD5 : public HASHwithTransform { +public: + enum { BLOCK_SIZE = 64, DIGEST_SIZE = 16, PAD_SIZE = 56, + TAO_BYTE_ORDER = LittleEndianOrder }; // in Bytes + MD5() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) + { Init(); } + ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); } + word32 getBlockSize() const { return BLOCK_SIZE; } + word32 getDigestSize() const { return DIGEST_SIZE; } + word32 getPadSize() const { return PAD_SIZE; } + + MD5(const MD5&); + MD5& operator= (const MD5&); + + void Init(); + void Swap(MD5&); +private: + void Transform(); +}; + +inline void swap(MD5& a, MD5& b) +{ + a.Swap(b); +} + + +} // namespace + +#endif // TAO_CRYPT_MD5_HPP + diff --git a/extra/yassl/taocrypt/include/misc.hpp b/extra/yassl/taocrypt/include/misc.hpp new file mode 100644 index 00000000000..01a3e8ee731 --- /dev/null +++ b/extra/yassl/taocrypt/include/misc.hpp @@ -0,0 +1,776 @@ +/* misc.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's misc.h from CryptoPP */ + +#ifndef TAO_CRYPT_MISC_HPP +#define TAO_CRYPT_MISC_HPP + +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +namespace TaoCrypt { + +// library allocation +struct new_t {}; // TaoCrypt New type +extern new_t tc; // pass in parameter + +} // namespace TaoCrypt + +void* operator new (size_t, TaoCrypt::new_t); +void* operator new[](size_t, TaoCrypt::new_t); + + +namespace TaoCrypt { + + +// define this if running on a big-endian CPU +#if !defined(LITTLE_ENDIAN_ORDER) && (defined(__BIG_ENDIAN__) || \ + defined(__sparc) || defined(__sparc__) || defined(__hppa__) || \ + defined(__mips__) || (defined(__MWERKS__) && !defined(__INTEL__))) + #define BIG_ENDIAN_ORDER +#endif + +#ifndef BIG_ENDIAN_ORDER + #define LITTLE_ENDIAN_ORDER +#endif + + +typedef unsigned char byte; +typedef unsigned short word16; +typedef unsigned int word32; + +#if defined(__GNUC__) || defined(__MWERKS__) + #define WORD64_AVAILABLE + typedef unsigned long long word64; + #define W64LIT(x) x##LL +#elif defined(_MSC_VER) || defined(__BCPLUSPLUS__) + #define WORD64_AVAILABLE + typedef unsigned __int64 word64; + #define W64LIT(x) x##ui64 +#elif defined(__DECCXX) + #define WORD64_AVAILABLE + typedef unsigned long word64; +#endif + +// define largest word type +#ifdef WORD64_AVAILABLE + typedef word64 lword; +#else + typedef word32 lword; +#endif + +#if defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \ + defined(__x86_64__) || defined(__mips64) +// These platforms have 64-bit CPU registers. Unfortunately most C++ compilers +// don't allow any way to access the 64-bit by 64-bit multiply instruction +// without using assembly, so in order to use word64 as word, the assembly +// instruction must be defined in Dword::Multiply(). + typedef word32 hword; + typedef word64 word; +#else + #define TAOCRYPT_NATIVE_DWORD_AVAILABLE + #ifdef WORD64_AVAILABLE + #define TAOCRYPT_SLOW_WORD64 + // define this if your CPU is not64-bit to use alternative code + // that avoids word64 + typedef word16 hword; + typedef word32 word; + typedef word64 dword; + #else + typedef word8 hword; + typedef word16 word; + typedef word32 dword; + #endif +#endif + +const word32 WORD_SIZE = sizeof(word); +const word32 WORD_BITS = WORD_SIZE * 8; + + +#if defined(_MSC_VER) || defined(__BCPLUSPLUS__) + #define INTEL_INTRINSICS + #define FAST_ROTATE +#elif defined(__MWERKS__) && TARGET_CPU_PPC + #define PPC_INTRINSICS + #define FAST_ROTATE +#elif defined(__GNUC__) && defined(__i386__) + // GCC does peephole optimizations which should result in using rotate + // instructions + #define FAST_ROTATE +#endif + + +// no gas on these systems ?, disable for now +#if defined(__sun__) || defined (__QNX__) + #define TAOCRYPT_DISABLE_X86ASM +#endif + + + +// CodeWarrior defines _MSC_VER +#if !defined(TAOCRYPT_DISABLE_X86ASM) && ((defined(_MSC_VER) && \ + !defined(__MWERKS__) && defined(_M_IX86)) || \ + (defined(__GNUC__) && defined(__i386__))) + #define TAOCRYPT_X86ASM_AVAILABLE +#endif + + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +# define TAOCRYPT_MALLOC_ALIGNMENT_IS_16 +#endif + +#if defined(__linux__) || defined(__sun__) || defined(__CYGWIN__) +# define TAOCRYPT_MEMALIGN_AVAILABLE +#endif + + +#if defined(_WIN32) || defined(__CYGWIN__) + #define TAOCRYPT_WIN32_AVAILABLE +#endif + +#if defined(__unix__) || defined(__MACH__) + #define TAOCRYPT_UNIX_AVAILABLE +#endif + + +// VC60 workaround: it doesn't allow typename in some places +#if defined(_MSC_VER) && (_MSC_VER < 1300) + #define CPP_TYPENAME +#else + #define CPP_TYPENAME typename +#endif + + +#ifdef _MSC_VER + #define TAOCRYPT_NO_VTABLE __declspec(novtable) +#else + #define TAOCRYPT_NO_VTABLE +#endif + + +// ***************** DLL related ******************** + +#ifdef TAOCRYPT_WIN32_AVAILABLE + +#ifdef TAOCRYPT_EXPORTS + #define TAOCRYPT_IS_DLL + #define TAOCRYPT_DLL __declspec(dllexport) +#elif defined(TAOCRYPT_IMPORTS) + #define TAOCRYPT_IS_DLL + #define TAOCRYPT_DLL __declspec(dllimport) +#else + #define TAOCRYPT_DLL +#endif // EXPORTS + +#define TAOCRYPT_API __stdcall +#define TAOCRYPT_CDECL __cdecl + +#else // TAOCRYPT_WIN32_AVAILABLE + +#define TAOCRYPT_DLL +#define TAOCRYPT_API +#define TAOCRYPT_CDECL + +#endif // TAOCRYPT_WIN32_AVAILABLE + + +// ****************** tempalte stuff ******************* + + +#if defined(TAOCRYPT_MANUALLY_INSTANTIATE_TEMPLATES) && \ + !defined(TAOCRYPT_IMPORTS) + #define TAOCRYPT_DLL_TEMPLATE_CLASS template class TAOCRYPT_DLL +#elif defined(__MWERKS__) + #define TAOCRYPT_DLL_TEMPLATE_CLASS extern class TAOCRYPT_DLL +#else + #define TAOCRYPT_DLL_TEMPLATE_CLASS extern template class TAOCRYPT_DLL +#endif + + +#if defined(TAOCRYPT_MANUALLY_INSTANTIATE_TEMPLATES) && \ + !defined(TAOCRYPT_EXPORTS) + #define TAOCRYPT_STATIC_TEMPLATE_CLASS template class +#elif defined(__MWERKS__) + #define TAOCRYPT_STATIC_TEMPLATE_CLASS extern class +#else + #define TAOCRYPT_STATIC_TEMPLATE_CLASS extern template class +#endif + + +// ************** compile-time assertion *************** + +template <bool b> +struct CompileAssert +{ + static char dummy[2*b-1]; +}; + +#define TAOCRYPT_COMPILE_ASSERT(assertion) \ + TAOCRYPT_COMPILE_ASSERT_INSTANCE(assertion, __LINE__) + +#if defined(TAOCRYPT_EXPORTS) || defined(TAOCRYPT_IMPORTS) + #define TAOCRYPT_COMPILE_ASSERT_INSTANCE(assertion, instance) +#else + #define TAOCRYPT_COMPILE_ASSERT_INSTANCE(assertion, instance) \ + (void)sizeof(CompileAssert<(assertion)>) +#endif + +#define TAOCRYPT_ASSERT_JOIN(X, Y) TAOCRYPT_DO_ASSERT_JOIN(X, Y) + +#define TAOCRYPT_DO_ASSERT_JOIN(X, Y) X##Y + + +/*************** helpers *****************************/ + +inline unsigned int BitsToBytes(unsigned int bitCount) +{ + return ((bitCount+7)/(8)); +} + +inline unsigned int BytesToWords(unsigned int byteCount) +{ + return ((byteCount+WORD_SIZE-1)/WORD_SIZE); +} + +inline unsigned int BitsToWords(unsigned int bitCount) +{ + return ((bitCount+WORD_BITS-1)/(WORD_BITS)); +} + +inline void CopyWords(word* r, const word* a, word32 n) +{ + for (word32 i = 0; i < n; i++) + r[i] = a[i]; +} + +inline unsigned int CountWords(const word* X, unsigned int N) +{ + while (N && X[N-1]==0) + N--; + return N; +} + +inline void SetWords(word* r, word a, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] = a; +} + +enum ByteOrder { LittleEndianOrder = 0, BigEndianOrder = 1 }; +enum CipherDir {ENCRYPTION, DECRYPTION}; + +inline CipherDir ReverseDir(CipherDir dir) +{ + return (dir == ENCRYPTION) ? DECRYPTION : ENCRYPTION; +} + +template <typename ENUM_TYPE, int VALUE> +struct EnumToType +{ + static ENUM_TYPE ToEnum() { return (ENUM_TYPE)VALUE; } +}; + +typedef EnumToType<ByteOrder, LittleEndianOrder> LittleEndian; +typedef EnumToType<ByteOrder, BigEndianOrder> BigEndian; + + +#ifndef BIG_ENDIAN_ORDER + typedef LittleEndian HostByteOrder; +#else + typedef BigEndian HostByteOrder; +#endif + +inline ByteOrder GetHostByteOrder() +{ + return HostByteOrder::ToEnum(); +} + +inline bool HostByteOrderIs(ByteOrder order) +{ + return order == GetHostByteOrder(); +} + + +void xorbuf(byte*, const byte*, unsigned int); + + +template <class T> +inline bool IsPowerOf2(T n) +{ + return n > 0 && (n & (n-1)) == 0; +} + +template <class T1, class T2> +inline T2 ModPowerOf2(T1 a, T2 b) +{ + assert(IsPowerOf2(b)); + return T2(a) & (b-1); +} + +template <class T> +inline T RoundDownToMultipleOf(T n, T m) +{ + return n - (IsPowerOf2(m) ? ModPowerOf2(n, m) : (n%m)); +} + +template <class T> +inline T RoundUpToMultipleOf(T n, T m) +{ + return RoundDownToMultipleOf(n+m-1, m); +} + +template <class T> +inline unsigned int GetAlignment(T* dummy = 0) // VC60 workaround +{ +#if (_MSC_VER >= 1300) + return __alignof(T); +#elif defined(__GNUC__) + return __alignof__(T); +#else + return sizeof(T); +#endif +} + +inline bool IsAlignedOn(const void* p, unsigned int alignment) +{ + return IsPowerOf2(alignment) ? ModPowerOf2((size_t)p, alignment) == 0 + : (size_t)p % alignment == 0; +} + +template <class T> +inline bool IsAligned(const void* p, T* dummy = 0) // VC60 workaround +{ + return IsAlignedOn(p, GetAlignment<T>()); +} + + +template <class T> inline T rotlFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x<<y) | (x>>(sizeof(T)*8-y)); +} + +template <class T> inline T rotrFixed(T x, unsigned int y) +{ + assert(y < sizeof(T)*8); + return (x>>y) | (x<<(sizeof(T)*8-y)); +} + +#ifdef INTEL_INTRINSICS + +#pragma intrinsic(_lrotl, _lrotr) + +template<> inline word32 rotlFixed(word32 x, word32 y) +{ + assert(y < 32); + return y ? _lrotl(x, y) : x; +} + +template<> inline word32 rotrFixed(word32 x, word32 y) +{ + assert(y < 32); + return y ? _lrotr(x, y) : x; +} + +#endif // INTEL_INTRINSICS + +#ifdef min +#undef min +#endif + +inline word32 min(word32 a, word32 b) +{ + return a < b ? a : b; +} + + +inline word32 ByteReverse(word32 value) +{ +#ifdef PPC_INTRINSICS + // PPC: load reverse indexed instruction + return (word32)__lwbrx(&value,0); +#elif defined(FAST_ROTATE) + // 5 instructions with rotate instruction, 9 without + return (rotrFixed(value, 8U) & 0xff00ff00) | + (rotlFixed(value, 8U) & 0x00ff00ff); +#else + // 6 instructions with rotate instruction, 8 without + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return rotlFixed(value, 16U); +#endif +} + + +template <typename T> +inline void ByteReverse(T* out, const T* in, word32 byteCount) +{ + assert(byteCount % sizeof(T) == 0); + word32 count = byteCount/sizeof(T); + for (word32 i=0; i<count; i++) + out[i] = ByteReverse(in[i]); +} + +inline void ByteReverse(byte* out, const byte* in, word32 byteCount) +{ + word32* o = reinterpret_cast<word32*>(out); + const word32* i = reinterpret_cast<const word32*>(in); + ByteReverse(o, i, byteCount); +} + + +template <class T> +inline T ByteReverseIf(T value, ByteOrder order) +{ + return HostByteOrderIs(order) ? value : ByteReverse(value); +} + + +template <typename T> +inline void ByteReverseIf(T* out, const T* in, word32 bc, ByteOrder order) +{ + if (!HostByteOrderIs(order)) + ByteReverse(out, in, bc); + else if (out != in) + memcpy(out, in, bc); +} + + +template <class T> +inline void GetUserKey(ByteOrder order, T* out, word32 outlen, const byte* in, + word32 inlen) +{ + const unsigned int U = sizeof(T); + assert(inlen <= outlen*U); + memcpy(out, in, inlen); + memset((byte *)out+inlen, 0, outlen*U-inlen); + ByteReverseIf(out, out, RoundUpToMultipleOf(inlen, U), order); +} + + +#ifdef _MSC_VER + // disable conversion warning + #pragma warning(disable:4244) +#endif + + +inline byte UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, + byte*) +{ + return block[0]; +} + +inline word16 UnalignedGetWordNonTemplate(ByteOrder order, const byte* block, + word16*) +{ + return (order == BigEndianOrder) + ? block[1] | (block[0] << 8) + : block[0] | (block[1] << 8); +} + +inline word32 UnalignedGetWordNonTemplate(ByteOrder order, const byte* block, + word32*) +{ + return (order == BigEndianOrder) + ? word32(block[3]) | (word32(block[2]) << 8) | (word32(block[1]) << 16) + | (word32(block[0]) << 24) + : word32(block[0]) | (word32(block[1]) << 8) | (word32(block[2]) << 16) + | (word32(block[3]) << 24); +} + +template <class T> +inline T UnalignedGetWord(ByteOrder order, const byte *block, T* dummy = 0) +{ + return UnalignedGetWordNonTemplate(order, block, dummy); +} + +inline void UnalignedPutWord(ByteOrder order, byte *block, byte value, + const byte *xorBlock = 0) +{ + block[0] = xorBlock ? (value ^ xorBlock[0]) : value; +} + +#define GETBYTE(x, y) (unsigned int)byte((x)>>(8*(y))) + +inline void UnalignedPutWord(ByteOrder order, byte *block, word16 value, + const byte *xorBlock = 0) +{ + if (order == BigEndianOrder) + { + block[0] = GETBYTE(value, 1); + block[1] = GETBYTE(value, 0); + } + else + { + block[0] = GETBYTE(value, 0); + block[1] = GETBYTE(value, 1); + } + + if (xorBlock) + { + block[0] ^= xorBlock[0]; + block[1] ^= xorBlock[1]; + } +} + +inline void UnalignedPutWord(ByteOrder order, byte* block, word32 value, + const byte* xorBlock = 0) +{ + if (order == BigEndianOrder) + { + block[0] = GETBYTE(value, 3); + block[1] = GETBYTE(value, 2); + block[2] = GETBYTE(value, 1); + block[3] = GETBYTE(value, 0); + } + else + { + block[0] = GETBYTE(value, 0); + block[1] = GETBYTE(value, 1); + block[2] = GETBYTE(value, 2); + block[3] = GETBYTE(value, 3); + } + + if (xorBlock) + { + block[0] ^= xorBlock[0]; + block[1] ^= xorBlock[1]; + block[2] ^= xorBlock[2]; + block[3] ^= xorBlock[3]; + } +} + + +template <class T> +inline T GetWord(bool assumeAligned, ByteOrder order, const byte *block) +{ + if (assumeAligned) + { + assert(IsAligned<T>(block)); + return ByteReverseIf(*reinterpret_cast<const T *>(block), order); + } + else + return UnalignedGetWord<T>(order, block); +} + +template <class T> +inline void GetWord(bool assumeAligned, ByteOrder order, T &result, + const byte *block) +{ + result = GetWord<T>(assumeAligned, order, block); +} + +template <class T> +inline void PutWord(bool assumeAligned, ByteOrder order, byte* block, T value, + const byte *xorBlock = 0) +{ + if (assumeAligned) + { + assert(IsAligned<T>(block)); + if (xorBlock) + *reinterpret_cast<T *>(block) = ByteReverseIf(value, order) + ^ *reinterpret_cast<const T *>(xorBlock); + else + *reinterpret_cast<T *>(block) = ByteReverseIf(value, order); + } + else + UnalignedPutWord(order, block, value, xorBlock); +} + +template <class T, class B, bool A=true> +class GetBlock +{ +public: + GetBlock(const void *block) + : m_block((const byte *)block) {} + + template <class U> + inline GetBlock<T, B, A> & operator()(U &x) + { + TAOCRYPT_COMPILE_ASSERT(sizeof(U) >= sizeof(T)); + x = GetWord<T>(A, B::ToEnum(), m_block); + m_block += sizeof(T); + return *this; + } + +private: + const byte *m_block; +}; + +template <class T, class B, bool A = true> +class PutBlock +{ +public: + PutBlock(const void *xorBlock, void *block) + : m_xorBlock((const byte *)xorBlock), m_block((byte *)block) {} + + template <class U> + inline PutBlock<T, B, A> & operator()(U x) + { + PutWord(A, B::ToEnum(), m_block, (T)x, m_xorBlock); + m_block += sizeof(T); + if (m_xorBlock) + m_xorBlock += sizeof(T); + return *this; + } + +private: + const byte *m_xorBlock; + byte *m_block; +}; + +template <class T, class B, bool A=true> +struct BlockGetAndPut +{ + // function needed because of C++ grammatical ambiguity between + // expression-statements and declarations + static inline GetBlock<T, B, A> Get(const void *block) + {return GetBlock<T, B, A>(block);} + typedef PutBlock<T, B, A> Put; +}; + + + +template <bool overflow> struct SafeShifter; + +template<> struct SafeShifter<true> +{ + template <class T> + static inline T RightShift(T value, unsigned int bits) + { + return 0; + } + + template <class T> + static inline T LeftShift(T value, unsigned int bits) + { + return 0; + } +}; + +template<> struct SafeShifter<false> +{ + template <class T> + static inline T RightShift(T value, unsigned int bits) + { + return value >> bits; + } + + template <class T> + static inline T LeftShift(T value, unsigned int bits) + { + return value << bits; + } +}; + +template <unsigned int bits, class T> +inline T SafeRightShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::RightShift(value, bits); +} + +template <unsigned int bits, class T> +inline T SafeLeftShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::LeftShift(value, bits); +} + + +inline +word ShiftWordsLeftByBits(word* r, unsigned int n, unsigned int shiftBits) +{ + assert (shiftBits<WORD_BITS); + word u, carry=0; + if (shiftBits) + for (unsigned int i=0; i<n; i++) + { + u = r[i]; + r[i] = (u << shiftBits) | carry; + carry = u >> (WORD_BITS-shiftBits); + } + return carry; +} + + +inline +word ShiftWordsRightByBits(word* r, unsigned int n, unsigned int shiftBits) +{ + assert (shiftBits<WORD_BITS); + word u, carry=0; + if (shiftBits) + for (int i=n-1; i>=0; i--) + { + u = r[i]; + r[i] = (u >> shiftBits) | carry; + carry = u << (WORD_BITS-shiftBits); + } + return carry; +} + + +inline +void ShiftWordsLeftByWords(word* r, unsigned int n, unsigned int shiftWords) +{ + shiftWords = min(shiftWords, n); + if (shiftWords) + { + for (unsigned int i=n-1; i>=shiftWords; i--) + r[i] = r[i-shiftWords]; + SetWords(r, 0, shiftWords); + } +} + + +inline +void ShiftWordsRightByWords(word* r, unsigned int n, unsigned int shiftWords) +{ + shiftWords = min(shiftWords, n); + if (shiftWords) + { + for (unsigned int i=0; i+shiftWords<n; i++) + r[i] = r[i+shiftWords]; + SetWords(r+n-shiftWords, 0, shiftWords); + } +} + + +template <class T1, class T2> +inline T1 SaturatingSubtract(T1 a, T2 b) +{ + TAOCRYPT_COMPILE_ASSERT_INSTANCE(T1(-1)>0, 0); // T1 is unsigned type + TAOCRYPT_COMPILE_ASSERT_INSTANCE(T2(-1)>0, 1); // T2 is unsigned type + return T1((a > b) ? (a - b) : 0); +} + + +// declares +unsigned int BytePrecision(unsigned long value); +unsigned int BitPrecision(unsigned long); +unsigned long Crop(unsigned long value, unsigned int size); + +void CallNewHandler(); + + + +} // namespace + +#endif // TAO_CRYPT_MISC_HPP diff --git a/extra/yassl/taocrypt/include/modarith.hpp b/extra/yassl/taocrypt/include/modarith.hpp new file mode 100644 index 00000000000..88a2cc95c7c --- /dev/null +++ b/extra/yassl/taocrypt/include/modarith.hpp @@ -0,0 +1,169 @@ +/* modarith.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* based on Wei Dai's modarith.h from CryptoPP */ + + +#ifndef TAO_CRYPT_MODARITH_HPP +#define TAO_CRYPT_MODARITH_HPP + +#include "misc.hpp" +#include "integer.hpp" +#include "algebra.hpp" + +namespace TaoCrypt { + + +//! ModularArithmetic +class ModularArithmetic : public AbstractRing<Integer> +{ +public: + + typedef int RandomizationParameter; + typedef Integer Element; + + ModularArithmetic(const Integer &modulus = Integer::One()) + : modulus(modulus), result((word)0, modulus.reg_.size()) {} + + ModularArithmetic(const ModularArithmetic &ma) + : AbstractRing<Integer>(), + modulus(ma.modulus), result((word)0, modulus.reg_.size()) {} + + const Integer& GetModulus() const {return modulus;} + void SetModulus(const Integer &newModulus) + { + modulus = newModulus; + result.reg_.resize(modulus.reg_.size()); + } + + virtual bool IsMontgomeryRepresentation() const {return false;} + + virtual Integer ConvertIn(const Integer &a) const + {return a%modulus;} + + virtual Integer ConvertOut(const Integer &a) const + {return a;} + + const Integer& Half(const Integer &a) const; + + bool Equal(const Integer &a, const Integer &b) const + {return a==b;} + + const Integer& Identity() const + {return Integer::Zero();} + + const Integer& Add(const Integer &a, const Integer &b) const; + + Integer& Accumulate(Integer &a, const Integer &b) const; + + const Integer& Inverse(const Integer &a) const; + + const Integer& Subtract(const Integer &a, const Integer &b) const; + + Integer& Reduce(Integer &a, const Integer &b) const; + + const Integer& Double(const Integer &a) const + {return Add(a, a);} + + const Integer& MultiplicativeIdentity() const + {return Integer::One();} + + const Integer& Multiply(const Integer &a, const Integer &b) const + {return result1 = a*b%modulus;} + + const Integer& Square(const Integer &a) const + {return result1 = a.Squared()%modulus;} + + bool IsUnit(const Integer &a) const + {return Integer::Gcd(a, modulus).IsUnit();} + + const Integer& MultiplicativeInverse(const Integer &a) const + {return result1 = a.InverseMod(modulus);} + + const Integer& Divide(const Integer &a, const Integer &b) const + {return Multiply(a, MultiplicativeInverse(b));} + + Integer CascadeExponentiate(const Integer &x, const Integer &e1, + const Integer &y, const Integer &e2) const; + + void SimultaneousExponentiate(Element *results, const Element &base, + const Integer *exponents, unsigned int exponentsCount) const; + + unsigned int MaxElementBitLength() const + {return (modulus-1).BitCount();} + + unsigned int MaxElementByteLength() const + {return (modulus-1).ByteCount();} + + + static const RandomizationParameter DefaultRandomizationParameter; + +protected: + Integer modulus; + mutable Integer result, result1; + +}; + + + +//! do modular arithmetics in Montgomery representation for increased speed +class MontgomeryRepresentation : public ModularArithmetic +{ +public: + MontgomeryRepresentation(const Integer &modulus); // modulus must be odd + + bool IsMontgomeryRepresentation() const {return true;} + + Integer ConvertIn(const Integer &a) const + {return (a<<(WORD_BITS*modulus.reg_.size()))%modulus;} + + Integer ConvertOut(const Integer &a) const; + + const Integer& MultiplicativeIdentity() const + {return result1 = Integer::Power2(WORD_BITS*modulus.reg_.size())%modulus;} + + const Integer& Multiply(const Integer &a, const Integer &b) const; + + const Integer& Square(const Integer &a) const; + + const Integer& MultiplicativeInverse(const Integer &a) const; + + Integer CascadeExponentiate(const Integer &x, const Integer &e1, + const Integer &y, const Integer &e2) const + {return AbstractRing<Integer>::CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousExponentiate(Element *results, const Element &base, + const Integer *exponents, unsigned int exponentsCount) const + {AbstractRing<Integer>::SimultaneousExponentiate(results, base, + exponents, exponentsCount);} + +private: + Integer u; + mutable AlignedWordBlock workspace; +}; + + + + +} // namespace + +#endif // TAO_CRYPT_MODARITH_HPP diff --git a/extra/yassl/taocrypt/include/modes.hpp b/extra/yassl/taocrypt/include/modes.hpp new file mode 100644 index 00000000000..2a21ad46b76 --- /dev/null +++ b/extra/yassl/taocrypt/include/modes.hpp @@ -0,0 +1,133 @@ +/* modes.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* modes.hpp provides ECB and CBC modes for block cipher encryption/decryption +*/ + + +#ifndef TAO_CRYPT_MODES_HPP +#define TAO_CRYPT_MODES_HPP + +#include <string.h> +#include "misc.hpp" + +namespace TaoCrypt { + + +enum Mode { ECB, CBC }; + + +// BlockCipher abstraction +template<CipherDir DIR, class T, Mode MODE> +class BlockCipher { +public: + BlockCipher() : cipher_(DIR, MODE) {} + + void Process(byte* c, const byte* p, word32 sz) + { cipher_.Process(c, p, sz); } + void SetKey(const byte* k, word32 sz) + { cipher_.SetKey(k, sz, DIR); } + void SetKey(const byte* k, word32 sz, const byte* iv) + { cipher_.SetKey(k, sz, DIR); cipher_.SetIV(iv); } +private: + T cipher_; + + BlockCipher(const BlockCipher&); // hide copy + BlockCipher& operator=(const BlockCipher&); // and assign +}; + + +// Mode Base for block ciphers, static size +template<int BLOCK_SIZE> +class Mode_BASE { +public: + Mode_BASE() {} + virtual ~Mode_BASE() {} + + virtual void ProcessAndXorBlock(const byte*, const byte*, byte*) const = 0; + + void ECB_Process(byte*, const byte*, word32); + void CBC_Encrypt(byte*, const byte*, word32); + void CBC_Decrypt(byte*, const byte*, word32); + + void SetIV(const byte* iv) { memcpy(reg_, iv, BLOCK_SIZE); } +private: + byte reg_[BLOCK_SIZE]; + byte tmp_[BLOCK_SIZE]; + + Mode_BASE(const Mode_BASE&); // hide copy + Mode_BASE& operator=(const Mode_BASE&); // and assign +}; + + +// ECB Process blocks +template<int BLOCK_SIZE> +void Mode_BASE<BLOCK_SIZE>::ECB_Process(byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / BLOCK_SIZE; + + while (blocks--) { + ProcessAndXorBlock(in, 0, out); + out += BLOCK_SIZE; + in += BLOCK_SIZE; + } +} + + +// CBC Encrypt +template<int BLOCK_SIZE> +void Mode_BASE<BLOCK_SIZE>::CBC_Encrypt(byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / BLOCK_SIZE; + + while (blocks--) { + xorbuf(reg_, in, BLOCK_SIZE); + ProcessAndXorBlock(reg_, 0, reg_); + memcpy(out, reg_, BLOCK_SIZE); + out += BLOCK_SIZE; + in += BLOCK_SIZE; + } +} + + +// CBC Decrypt +template<int BLOCK_SIZE> +void Mode_BASE<BLOCK_SIZE>::CBC_Decrypt(byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / BLOCK_SIZE; + byte hold[BLOCK_SIZE]; + + while (blocks--) { + memcpy(tmp_, in, BLOCK_SIZE); + ProcessAndXorBlock(tmp_, 0, out); + xorbuf(out, reg_, BLOCK_SIZE); + memcpy(hold, reg_, BLOCK_SIZE); // swap reg_ and tmp_ + memcpy(reg_, tmp_, BLOCK_SIZE); + memcpy(tmp_, hold, BLOCK_SIZE); + out += BLOCK_SIZE; + in += BLOCK_SIZE; + } +} + + +} // namespace + +#endif // TAO_CRYPT_MODES_HPP diff --git a/extra/yassl/taocrypt/include/random.hpp b/extra/yassl/taocrypt/include/random.hpp new file mode 100644 index 00000000000..5fdda8da47a --- /dev/null +++ b/extra/yassl/taocrypt/include/random.hpp @@ -0,0 +1,87 @@ +/* random.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* random.hpp provides a crypto secure Random Number Generator using an OS + specific seed +*/ + + +#ifndef TAO_CRYPT_RANDOM_HPP +#define TAO_CRYPT_RANDOM_HPP + +#include "arc4.hpp" +#include "error.hpp" + +namespace TaoCrypt { + + +// OS specific seeder +class OS_Seed { +public: + OS_Seed(); + ~OS_Seed(); + + void GenerateSeed(byte*, word32 sz); + Error GetError() const { return error_; } +private: +#if defined(WIN32) + #if defined(_WIN64) + typedef unsigned __int64 ProviderHandle; + // type HCRYPTPROV, avoid #include <windows.h> + #else + typedef unsigned long ProviderHandle; + #endif + ProviderHandle handle_; +#else + int fd_; +#endif + Error error_; + + OS_Seed(const OS_Seed&); // hide copy + OS_Seed& operator=(const OS_Seed&); // hide assign +}; + + +// secure Random Nnumber Generator +class RandomNumberGenerator { +public: + RandomNumberGenerator(); + ~RandomNumberGenerator() {} + + void GenerateBlock(byte*, word32 sz); + byte GenerateByte(); + + ErrorNumber GetError() const { return seed_.GetError().What(); } +private: + OS_Seed seed_; + ARC4 cipher_; + + RandomNumberGenerator(const RandomNumberGenerator&); // hide copy + RandomNumberGenerator operator=(const RandomNumberGenerator&); // && assign +}; + + + + +} // namespace + +#endif // TAO_CRYPT_RANDOM_HPP + diff --git a/extra/yassl/taocrypt/include/ripemd.hpp b/extra/yassl/taocrypt/include/ripemd.hpp new file mode 100644 index 00000000000..4f8e1fd0386 --- /dev/null +++ b/extra/yassl/taocrypt/include/ripemd.hpp @@ -0,0 +1,63 @@ +/* ripemd.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* ripemd.hpp provides RIPEMD digest support +*/ + +#ifndef TAO_CRYPT_RIPEMD_HPP +#define TAO_CRYPT_RIPEMD_HPP + +#include "hash.hpp" + +namespace TaoCrypt { + + +// RIPEMD160 digest +class RIPEMD160 : public HASHwithTransform { +public: + enum { BLOCK_SIZE = 64, DIGEST_SIZE = 20, PAD_SIZE = 56, + TAO_BYTE_ORDER = LittleEndianOrder }; // in Bytes + RIPEMD160() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) + { Init(); } + ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); } + word32 getBlockSize() const { return BLOCK_SIZE; } + word32 getDigestSize() const { return DIGEST_SIZE; } + word32 getPadSize() const { return PAD_SIZE; } + + RIPEMD160(const RIPEMD160&); + RIPEMD160& operator= (const RIPEMD160&); + + void Init(); + void Swap(RIPEMD160&); +private: + void Transform(); +}; + +inline void swap(RIPEMD160& a, RIPEMD160& b) +{ + a.Swap(b); +} + + +} // namespace + +#endif // TAO_CRYPT_RIPEMD_HPP + diff --git a/extra/yassl/taocrypt/include/rsa.hpp b/extra/yassl/taocrypt/include/rsa.hpp new file mode 100644 index 00000000000..916476c90b7 --- /dev/null +++ b/extra/yassl/taocrypt/include/rsa.hpp @@ -0,0 +1,253 @@ +/* rsa.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* rsa.hpp provides RSA ES encrypt/decrypt, SSL (block type 1) sign and verify +*/ + +#ifndef TAO_CRYPT_RSA_HPP +#define TAO_CRYPT_RSA_HPP + +#include "integer.hpp" +#include "random.hpp" +#include "stdexcept.hpp" + + +namespace TaoCrypt { + +class Source; + + +// Public Key Length helper +class PK_Lengths { + const Integer& image_; +public: + explicit PK_Lengths(const Integer& i) : image_(i) {} + + word32 PaddedBlockBitLength() const {return image_.BitCount() - 1;} + word32 PaddedBlockByteLength() const + {return BitsToBytes(PaddedBlockBitLength());} + + word32 FixedCiphertextLength() const {return image_.ByteCount();} + word32 FixedMaxPlaintextLength() const + {return SaturatingSubtract(PaddedBlockBitLength() / 8, 10U); } +}; + + +// RSA Public Key +class RSA_PublicKey { +protected: + Integer n_; + Integer e_; +public: + RSA_PublicKey() {} + explicit RSA_PublicKey(Source&); + + void Initialize(const Integer& n, const Integer& e) {n_ = n; e_ = e;} + void Initialize(Source&); + + Integer ApplyFunction(const Integer& x) const; + + const Integer& GetModulus() const {return n_;} + const Integer& GetPublicExponent() const {return e_;} + + void SetModulus(const Integer& n) {n_ = n;} + void SetPublicExponent(const Integer& e) {e_ = e;} + + word32 FixedCiphertextLength() + { + return PK_Lengths(n_).FixedCiphertextLength(); + } + + RSA_PublicKey(const RSA_PublicKey& other) : n_(other.n_), e_(other.e_) {} + RSA_PublicKey& operator=(const RSA_PublicKey& that) + { + RSA_PublicKey tmp(that); + Swap(tmp); + return *this; + } + + void Swap(RSA_PublicKey& other) + { + n_.Swap(other.n_); + e_.Swap(other.e_); + } +}; + + +// RSA Private Key +class RSA_PrivateKey : public RSA_PublicKey { + Integer d_; + Integer p_; + Integer q_; + Integer dp_; + Integer dq_; + Integer u_; +public: + RSA_PrivateKey() {} + explicit RSA_PrivateKey(Source&); + + void Initialize(const Integer& n, const Integer& e, const Integer& d, + const Integer& p, const Integer& q, const Integer& dp, + const Integer& dq, const Integer& u) + {n_ = n; e_ = e; d_ = d; p_ = p; q_ = q; dp_ = dp; dq_ = dq; u_ = u;} + void Initialize(Source&); + + Integer CalculateInverse(RandomNumberGenerator&, const Integer&) const; + + const Integer& GetPrime1() const {return p_;} + const Integer& GetPrime2() const {return q_;} + const Integer& GetPrivateExponent() const {return d_;} + const Integer& GetModPrime1PrivateExponent() const {return dp_;} + const Integer& GetModPrime2PrivateExponent() const {return dq_;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const + {return u_;} + + void SetPrime1(const Integer& p) {p_ = p;} + void SetPrime2(const Integer& q) {q_ = q;} + void SetPrivateExponent(const Integer& d) {d_ = d;} + void SetModPrime1PrivateExponent(const Integer& dp) {dp_ = dp;} + void SetModPrime2PrivateExponent(const Integer& dq) {dq_ = dq;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer& u) {u_ = u;} +private: + RSA_PrivateKey(const RSA_PrivateKey&); // hide copy + RSA_PrivateKey& operator=(const RSA_PrivateKey&); // and assign +}; + + +// block type 2 padding +class RSA_BlockType2 { +public: + void Pad(const byte*, word32, byte*, word32, + RandomNumberGenerator&) const; + word32 UnPad(const byte*, word32, byte*) const; +}; + + +// block type 1 padding +class RSA_BlockType1 { +public: + void Pad(const byte*, word32, byte*, word32, + RandomNumberGenerator&) const; + word32 UnPad(const byte*, word32, byte*) const; +}; + + +// RSA Encryptor, can use any padding +template<class Pad = RSA_BlockType2> +class RSA_Encryptor { + const RSA_PublicKey& key_; + Pad padding_; +public: + explicit RSA_Encryptor(const RSA_PublicKey& k) : key_(k) {} + + void Encrypt(const byte*, word32, byte*, RandomNumberGenerator&); + bool SSL_Verify(const byte* msg, word32 sz, const byte* sig); +}; + + +// RSA Decryptor, can use any padding +template<class Pad = RSA_BlockType2> +class RSA_Decryptor { + const RSA_PrivateKey& key_; + Pad padding_; +public: + explicit RSA_Decryptor(const RSA_PrivateKey& k) : key_(k) {} + + word32 Decrypt(const byte*, word32, byte*, RandomNumberGenerator&); + void SSL_Sign(const byte*, word32, byte*, RandomNumberGenerator&); +}; + + +// Public Encrypt +template<class Pad> +void RSA_Encryptor<Pad>::Encrypt(const byte* plain, word32 sz, byte* cipher, + RandomNumberGenerator& rng) +{ + PK_Lengths lengths(key_.GetModulus()); + assert(sz <= lengths.FixedMaxPlaintextLength()); + + ByteBlock paddedBlock(lengths.PaddedBlockByteLength()); + padding_.Pad(plain, sz, paddedBlock.get_buffer(), + lengths.PaddedBlockBitLength(), rng); + + key_.ApplyFunction(Integer(paddedBlock.get_buffer(), paddedBlock.size())). + Encode(cipher, lengths.FixedCiphertextLength()); +} + + +// Private Decrypt +template<class Pad> +word32 RSA_Decryptor<Pad>::Decrypt(const byte* cipher, word32 sz, byte* plain, + RandomNumberGenerator& rng) +{ + PK_Lengths lengths(key_.GetModulus()); + assert(sz == lengths.FixedCiphertextLength()); + + if (sz != lengths.FixedCiphertextLength()) + return 0; + + ByteBlock paddedBlock(lengths.PaddedBlockByteLength()); + Integer x = key_.CalculateInverse(rng, Integer(cipher, + lengths.FixedCiphertextLength()).Ref()); + if (x.ByteCount() > paddedBlock.size()) + x = Integer::Zero(); // don't return false, prevents timing attack + x.Encode(paddedBlock.get_buffer(), paddedBlock.size()); + return padding_.UnPad(paddedBlock.get_buffer(), + lengths.PaddedBlockBitLength(), plain); +} + + +// Private SSL type (block 1) Encrypt +template<class Pad> +void RSA_Decryptor<Pad>::SSL_Sign(const byte* message, word32 sz, byte* sig, + RandomNumberGenerator& rng) +{ + RSA_PublicKey inverse; + inverse.Initialize(key_.GetModulus(), key_.GetPrivateExponent()); + RSA_Encryptor<RSA_BlockType1> enc(inverse); // SSL Type + enc.Encrypt(message, sz, sig, rng); +} + + +word32 SSL_Decrypt(const RSA_PublicKey& key, const byte* sig, byte* plain); + + +// Public SSL type (block 1) Decrypt +template<class Pad> +bool RSA_Encryptor<Pad>::SSL_Verify(const byte* message, word32 sz, + const byte* sig) +{ + ByteBlock plain(PK_Lengths(key_.GetModulus()).FixedMaxPlaintextLength()); + SSL_Decrypt(key_, sig, plain.get_buffer()); + + if ( (memcmp(plain.get_buffer(), message, sz)) == 0) + return true; + return false; +} + + +typedef RSA_Encryptor<> RSAES_Encryptor; +typedef RSA_Decryptor<> RSAES_Decryptor; + + +} // namespace + +#endif // TAO_CRYPT_RSA_HPP diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp new file mode 100644 index 00000000000..5b9e13df644 --- /dev/null +++ b/extra/yassl/taocrypt/include/runtime.hpp @@ -0,0 +1,69 @@ +/* runtime.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* runtime.hpp provides C++ runtime support functions when building a pure C + * version of yaSSL, user must define YASSL_PURE_C +*/ + + + +#if !defined(yaSSL_NEW_HPP) && defined(USE_MYSYS_NEW) + +#define yaSSL_NEW_HPP + + +#include <cstdlib> + + +static void* operator new (size_t sz) +{ + return malloc (sz ? sz : 1); +} + +static void* operator new[](size_t sz) +{ + return malloc (sz ? sz : 1); +} + +static void operator delete (void* ptr) +{ + if (ptr) free(ptr); +} + +static void operator delete[] (void* ptr) +{ + if (ptr) free(ptr); +} + + +extern "C" { +#include <assert.h> + +static int __cxa_pure_virtual() +{ + // oops, pure virtual called! + assert("Pure virtual method called." == "Aborted"); + return 0; +} + +} // extern "C" + +#endif // yaSSL_NEW_HPP diff --git a/extra/yassl/taocrypt/include/sha.hpp b/extra/yassl/taocrypt/include/sha.hpp new file mode 100644 index 00000000000..b75d9e3f670 --- /dev/null +++ b/extra/yassl/taocrypt/include/sha.hpp @@ -0,0 +1,65 @@ +/* sha.hpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* sha.hpp provides SHA-1 digests, see RFC 3174 +*/ + +#ifndef TAO_CRYPT_SHA_HPP +#define TAO_CRYPT_SHA_HPP + +#include "hash.hpp" + +namespace TaoCrypt { + + +// SHA-1 digest +class SHA : public HASHwithTransform { +public: + enum { BLOCK_SIZE = 64, DIGEST_SIZE = 20, PAD_SIZE = 56, + TAO_BYTE_ORDER = BigEndianOrder}; // in Bytes + SHA() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) + { Init(); } + ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); } + word32 getBlockSize() const { return BLOCK_SIZE; } + word32 getDigestSize() const { return DIGEST_SIZE; } + word32 getPadSize() const { return PAD_SIZE; } + + void Init(); + + SHA(const SHA&); + SHA& operator= (const SHA&); + + void Swap(SHA&); +private: + void Transform(); +}; + + +inline void swap(SHA& a, SHA& b) +{ + a.Swap(b); +} + +} // namespace + + +#endif // TAO_CRYPT_SHA_HPP + diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am new file mode 100644 index 00000000000..4bf901b76ea --- /dev/null +++ b/extra/yassl/taocrypt/src/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = -I../include -I../../mySTL + +noinst_LIBRARIES = libtaocrypt.a +libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ + coding.cpp dh.cpp des.cpp dsa.cpp file.cpp hash.cpp integer.cpp \ + md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp +EXTRA_DIST = ../include/*.hpp +AM_CXXFLAGS=@USE_MYSYS_NEW@ diff --git a/extra/yassl/taocrypt/src/aes.cpp b/extra/yassl/taocrypt/src/aes.cpp new file mode 100644 index 00000000000..d09a40e1578 --- /dev/null +++ b/extra/yassl/taocrypt/src/aes.cpp @@ -0,0 +1,401 @@ +/* aes.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's aes.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "aes.hpp" +#include "stdexcept.hpp" + + +namespace TaoCrypt { + + +void AES::Process(byte* out, const byte* in, word32 sz) +{ + if (mode_ == ECB) + ECB_Process(out, in, sz); + else if (mode_ == CBC) + if (dir_ == ENCRYPTION) + CBC_Encrypt(out, in, sz); + else + CBC_Decrypt(out, in, sz); +} + + + +void AES::SetKey(const byte* userKey, word32 keylen, CipherDir /*dummy*/) +{ + assert( (keylen == 16) || (keylen == 24) || (keylen == 32) ); + + rounds_ = keylen/4 + 6; + key_.New(4*(rounds_+1)); + + word32 temp, *rk = key_.get_buffer(); + unsigned int i=0; + + GetUserKey(BigEndianOrder, rk, keylen/4, userKey, keylen); + + switch(keylen) + { + case 16: + while (true) + { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + rcon_[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) + break; + rk += 4; + } + break; + + case 24: + while (true) // for (;;) here triggers a bug in VC60 SP4 w/ Pro Pack + { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + rcon_[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) + break; + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + break; + + case 32: + while (true) + { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[GETBYTE(temp, 2)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 3)] & 0x000000ff) ^ + rcon_[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) + break; + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[GETBYTE(temp, 3)] & 0xff000000) ^ + (Te4[GETBYTE(temp, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(temp, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(temp, 0)] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + break; + } + + if (dir_ == DECRYPTION) + { + unsigned int i, j; + rk = key_.get_buffer(); + + /* invert the order of the round keys: */ + for (i = 0, j = 4*rounds_; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + // apply the inverse MixColumn transform to all round keys but the + // first and the last: + for (i = 1; i < rounds_; i++) { + rk += 4; + rk[0] = + Td0[Te4[GETBYTE(rk[0], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[0], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[0], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[0], 0)] & 0xff]; + rk[1] = + Td0[Te4[GETBYTE(rk[1], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[1], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[1], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[1], 0)] & 0xff]; + rk[2] = + Td0[Te4[GETBYTE(rk[2], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[2], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[2], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[2], 0)] & 0xff]; + rk[3] = + Td0[Te4[GETBYTE(rk[3], 3)] & 0xff] ^ + Td1[Te4[GETBYTE(rk[3], 2)] & 0xff] ^ + Td2[Te4[GETBYTE(rk[3], 1)] & 0xff] ^ + Td3[Te4[GETBYTE(rk[3], 0)] & 0xff]; + } + } +} + + +typedef BlockGetAndPut<word32, BigEndian> gpBlock; + +void AES::ProcessAndXorBlock(const byte* in, const byte* xOr, byte* out) const +{ + if (dir_ == ENCRYPTION) + encrypt(in, xOr, out); + else + decrypt(in, xOr, out); +} + + +void AES::encrypt(const byte* inBlock, const byte* xorBlock, + byte* outBlock) const +{ + word32 s0, s1, s2, s3, t0, t1, t2, t3; + const word32 *rk = key_.get_buffer(); + + /* + * map byte array block to cipher state + * and add initial round key: + */ + gpBlock::Get(inBlock)(s0)(s1)(s2)(s3); + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + /* + * Nr - 1 full rounds: + */ + unsigned int r = rounds_ >> 1; + for (;;) { + t0 = + Te0[GETBYTE(s0, 3)] ^ + Te1[GETBYTE(s1, 2)] ^ + Te2[GETBYTE(s2, 1)] ^ + Te3[GETBYTE(s3, 0)] ^ + rk[4]; + t1 = + Te0[GETBYTE(s1, 3)] ^ + Te1[GETBYTE(s2, 2)] ^ + Te2[GETBYTE(s3, 1)] ^ + Te3[GETBYTE(s0, 0)] ^ + rk[5]; + t2 = + Te0[GETBYTE(s2, 3)] ^ + Te1[GETBYTE(s3, 2)] ^ + Te2[GETBYTE(s0, 1)] ^ + Te3[GETBYTE(s1, 0)] ^ + rk[6]; + t3 = + Te0[GETBYTE(s3, 3)] ^ + Te1[GETBYTE(s0, 2)] ^ + Te2[GETBYTE(s1, 1)] ^ + Te3[GETBYTE(s2, 0)] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[GETBYTE(t0, 3)] ^ + Te1[GETBYTE(t1, 2)] ^ + Te2[GETBYTE(t2, 1)] ^ + Te3[GETBYTE(t3, 0)] ^ + rk[0]; + s1 = + Te0[GETBYTE(t1, 3)] ^ + Te1[GETBYTE(t2, 2)] ^ + Te2[GETBYTE(t3, 1)] ^ + Te3[GETBYTE(t0, 0)] ^ + rk[1]; + s2 = + Te0[GETBYTE(t2, 3)] ^ + Te1[GETBYTE(t3, 2)] ^ + Te2[GETBYTE(t0, 1)] ^ + Te3[GETBYTE(t1, 0)] ^ + rk[2]; + s3 = + Te0[GETBYTE(t3, 3)] ^ + Te1[GETBYTE(t0, 2)] ^ + Te2[GETBYTE(t1, 1)] ^ + Te3[GETBYTE(t2, 0)] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + + s0 = + (Te4[GETBYTE(t0, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t3, 0)] & 0x000000ff) ^ + rk[0]; + s1 = + (Te4[GETBYTE(t1, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t0, 0)] & 0x000000ff) ^ + rk[1]; + s2 = + (Te4[GETBYTE(t2, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t1, 0)] & 0x000000ff) ^ + rk[2]; + s3 = + (Te4[GETBYTE(t3, 3)] & 0xff000000) ^ + (Te4[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Te4[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Te4[GETBYTE(t2, 0)] & 0x000000ff) ^ + rk[3]; + + gpBlock::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); + +} + + +void AES::decrypt(const byte* inBlock, const byte* xorBlock, + byte* outBlock) const +{ + word32 s0, s1, s2, s3, t0, t1, t2, t3; + const word32* rk = key_.get_buffer(); + + /* + * map byte array block to cipher state + * and add initial round key: + */ + gpBlock::Get(inBlock)(s0)(s1)(s2)(s3); + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + /* + * Nr - 1 full rounds: + */ + unsigned int r = rounds_ >> 1; + for (;;) { + t0 = + Td0[GETBYTE(s0, 3)] ^ + Td1[GETBYTE(s3, 2)] ^ + Td2[GETBYTE(s2, 1)] ^ + Td3[GETBYTE(s1, 0)] ^ + rk[4]; + t1 = + Td0[GETBYTE(s1, 3)] ^ + Td1[GETBYTE(s0, 2)] ^ + Td2[GETBYTE(s3, 1)] ^ + Td3[GETBYTE(s2, 0)] ^ + rk[5]; + t2 = + Td0[GETBYTE(s2, 3)] ^ + Td1[GETBYTE(s1, 2)] ^ + Td2[GETBYTE(s0, 1)] ^ + Td3[GETBYTE(s3, 0)] ^ + rk[6]; + t3 = + Td0[GETBYTE(s3, 3)] ^ + Td1[GETBYTE(s2, 2)] ^ + Td2[GETBYTE(s1, 1)] ^ + Td3[GETBYTE(s0, 0)] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[GETBYTE(t0, 3)] ^ + Td1[GETBYTE(t3, 2)] ^ + Td2[GETBYTE(t2, 1)] ^ + Td3[GETBYTE(t1, 0)] ^ + rk[0]; + s1 = + Td0[GETBYTE(t1, 3)] ^ + Td1[GETBYTE(t0, 2)] ^ + Td2[GETBYTE(t3, 1)] ^ + Td3[GETBYTE(t2, 0)] ^ + rk[1]; + s2 = + Td0[GETBYTE(t2, 3)] ^ + Td1[GETBYTE(t1, 2)] ^ + Td2[GETBYTE(t0, 1)] ^ + Td3[GETBYTE(t3, 0)] ^ + rk[2]; + s3 = + Td0[GETBYTE(t3, 3)] ^ + Td1[GETBYTE(t2, 2)] ^ + Td2[GETBYTE(t1, 1)] ^ + Td3[GETBYTE(t0, 0)] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[GETBYTE(t0, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t1, 0)] & 0x000000ff) ^ + rk[0]; + s1 = + (Td4[GETBYTE(t1, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t2, 0)] & 0x000000ff) ^ + rk[1]; + s2 = + (Td4[GETBYTE(t2, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t3, 0)] & 0x000000ff) ^ + rk[2]; + s3 = + (Td4[GETBYTE(t3, 3)] & 0xff000000) ^ + (Td4[GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Td4[GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Td4[GETBYTE(t0, 0)] & 0x000000ff) ^ + rk[3]; + + gpBlock::Put(xorBlock, outBlock)(s0)(s1)(s2)(s3); +} + + + +} // namespace + diff --git a/extra/yassl/taocrypt/src/aestables.cpp b/extra/yassl/taocrypt/src/aestables.cpp new file mode 100644 index 00000000000..7ba25bc9ffb --- /dev/null +++ b/extra/yassl/taocrypt/src/aestables.cpp @@ -0,0 +1,724 @@ +/* aestables.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's aestables.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "aes.hpp" + + +namespace TaoCrypt { + + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +const word32 AES::Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +const word32 AES::Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +const word32 AES::Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; + +const word32 AES::Te3[256] = { + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; + +const word32 AES::Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; + +const word32 AES::Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; + +const word32 AES::Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; + +const word32 AES::Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; + +const word32 AES::Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; + +const word32 AES::Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; + +const word32 AES::rcon_[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + + + + +} // namespace diff --git a/extra/yassl/taocrypt/src/algebra.cpp b/extra/yassl/taocrypt/src/algebra.cpp new file mode 100644 index 00000000000..1924be9b618 --- /dev/null +++ b/extra/yassl/taocrypt/src/algebra.cpp @@ -0,0 +1,354 @@ +/* algebra.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's algebra.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "algebra.hpp" +#include "integer.hpp" +#include "vector.hpp" // mySTL::vector (simple) + + +namespace TaoCrypt { + +template <class T> const T& AbstractGroup<T>::Double(const Element &a) const +{ + return Add(a, a); +} + +template <class T> const T& AbstractGroup<T>::Subtract(const Element &a, + const Element &b) const +{ + // make copy of a in case Inverse() overwrites it + Element a1(a); + return Add(a1, Inverse(b)); +} + +template <class T> T& AbstractGroup<T>::Accumulate(Element &a, + const Element &b) const +{ + return a = Add(a, b); +} + +template <class T> T& AbstractGroup<T>::Reduce(Element &a, + const Element &b) const +{ + return a = Subtract(a, b); +} + +template <class T> const T& AbstractRing<T>::Square(const Element &a) const +{ + return Multiply(a, a); +} + +template <class T> const T& AbstractRing<T>::Divide(const Element &a, + const Element &b) const +{ + // make copy of a in case MultiplicativeInverse() overwrites it + Element a1(a); + return Multiply(a1, MultiplicativeInverse(b)); +} + +template <class T> const T& AbstractEuclideanDomain<T>::Mod(const Element &a, + const Element &b) const +{ + Element q; + DivisionAlgorithm(result, q, a, b); + return result; +} + +template <class T> const T& AbstractEuclideanDomain<T>::Gcd(const Element &a, + const Element &b) const +{ + Element g[3]={b, a}; + unsigned int i0=0, i1=1, i2=2; + + while (!Equal(g[i1], this->Identity())) + { + g[i2] = Mod(g[i0], g[i1]); + unsigned int t = i0; i0 = i1; i1 = i2; i2 = t; + } + + return result = g[i0]; +} + +template <class T> const typename + QuotientRing<T>::Element& QuotientRing<T>::MultiplicativeInverse( + const Element &a) const +{ + Element g[3]={m_modulus, a}; +#ifdef __BCPLUSPLUS__ + // BC++50 workaround + Element v[3]; + v[0]=m_domain.Identity(); + v[1]=m_domain.MultiplicativeIdentity(); +#else + Element v[3]={m_domain.Identity(), m_domain.MultiplicativeIdentity()}; +#endif + Element y; + unsigned int i0=0, i1=1, i2=2; + + while (!Equal(g[i1], Identity())) + { + // y = g[i0] / g[i1]; + // g[i2] = g[i0] % g[i1]; + m_domain.DivisionAlgorithm(g[i2], y, g[i0], g[i1]); + // v[i2] = v[i0] - (v[i1] * y); + v[i2] = m_domain.Subtract(v[i0], m_domain.Multiply(v[i1], y)); + unsigned int t = i0; i0 = i1; i1 = i2; i2 = t; + } + + return m_domain.IsUnit(g[i0]) ? m_domain.Divide(v[i0], g[i0]) : + m_domain.Identity(); +} + +template <class T> T AbstractGroup<T>::ScalarMultiply(const Element &base, + const Integer &exponent) const +{ + Element result; + SimultaneousMultiply(&result, base, &exponent, 1); + return result; +} + +template <class T> T AbstractGroup<T>::CascadeScalarMultiply(const Element &x, + const Integer &e1, const Element &y, const Integer &e2) const +{ + const unsigned expLen = max(e1.BitCount(), e2.BitCount()); + if (expLen==0) + return Identity(); + + const unsigned w = (expLen <= 46 ? 1 : (expLen <= 260 ? 2 : 3)); + const unsigned tableSize = 1<<w; + mySTL::vector<Element> powerTable(tableSize << w); + + powerTable[1] = x; + powerTable[tableSize] = y; + if (w==1) + powerTable[3] = Add(x,y); + else + { + powerTable[2] = Double(x); + powerTable[2*tableSize] = Double(y); + + unsigned i, j; + + for (i=3; i<tableSize; i+=2) + powerTable[i] = Add(powerTable[i-2], powerTable[2]); + for (i=1; i<tableSize; i+=2) + for (j=i+tableSize; j<(tableSize<<w); j+=tableSize) + powerTable[j] = Add(powerTable[j-tableSize], y); + + for (i=3*tableSize; i<(tableSize<<w); i+=2*tableSize) + powerTable[i] = Add(powerTable[i-2*tableSize], + powerTable[2*tableSize]); + for (i=tableSize; i<(tableSize<<w); i+=2*tableSize) + for (j=i+2; j<i+tableSize; j+=2) + powerTable[j] = Add(powerTable[j-1], x); + } + + Element result; + unsigned power1 = 0, power2 = 0, prevPosition = expLen-1; + bool firstTime = true; + + for (int i = expLen-1; i>=0; i--) + { + power1 = 2*power1 + e1.GetBit(i); + power2 = 2*power2 + e2.GetBit(i); + + if (i==0 || 2*power1 >= tableSize || 2*power2 >= tableSize) + { + unsigned squaresBefore = prevPosition-i; + unsigned squaresAfter = 0; + prevPosition = i; + while ((power1 || power2) && power1%2 == 0 && power2%2==0) + { + power1 /= 2; + power2 /= 2; + squaresBefore--; + squaresAfter++; + } + if (firstTime) + { + result = powerTable[(power2<<w) + power1]; + firstTime = false; + } + else + { + while (squaresBefore--) + result = Double(result); + if (power1 || power2) + Accumulate(result, powerTable[(power2<<w) + power1]); + } + while (squaresAfter--) + result = Double(result); + power1 = power2 = 0; + } + } + return result; +} + + +struct WindowSlider +{ + WindowSlider(const Integer &exp, bool fastNegate, + unsigned int windowSizeIn=0) + : exp(exp), windowModulus(Integer::One()), windowSize(windowSizeIn), + windowBegin(0), fastNegate(fastNegate), firstTime(true), + finished(false) + { + if (windowSize == 0) + { + unsigned int expLen = exp.BitCount(); + windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : + (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : + (expLen <= 1434 ? 6 : 7))))); + } + windowModulus <<= windowSize; + } + + void FindNextWindow() + { + unsigned int expLen = exp.WordCount() * WORD_BITS; + unsigned int skipCount = firstTime ? 0 : windowSize; + firstTime = false; + while (!exp.GetBit(skipCount)) + { + if (skipCount >= expLen) + { + finished = true; + return; + } + skipCount++; + } + + exp >>= skipCount; + windowBegin += skipCount; + expWindow = exp % (1 << windowSize); + + if (fastNegate && exp.GetBit(windowSize)) + { + negateNext = true; + expWindow = (1 << windowSize) - expWindow; + exp += windowModulus; + } + else + negateNext = false; + } + + Integer exp, windowModulus; + unsigned int windowSize, windowBegin, expWindow; + bool fastNegate, negateNext, firstTime, finished; +}; + +template <class T> +void AbstractGroup<T>::SimultaneousMultiply(T *results, const T &base, + const Integer *expBegin, unsigned int expCount) const +{ + mySTL::vector<mySTL::vector<Element> > buckets(expCount); + mySTL::vector<WindowSlider> exponents; + exponents.reserve(expCount); + unsigned int i; + + for (i=0; i<expCount; i++) + { + assert(expBegin->NotNegative()); + exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 0)); + exponents[i].FindNextWindow(); + buckets[i].resize(1<<(exponents[i].windowSize-1), Identity()); + } + + unsigned int expBitPosition = 0; + Element g = base; + bool notDone = true; + + while (notDone) + { + notDone = false; + for (i=0; i<expCount; i++) + { + if (!exponents[i].finished && expBitPosition == + exponents[i].windowBegin) + { + Element &bucket = buckets[i][exponents[i].expWindow/2]; + if (exponents[i].negateNext) + Accumulate(bucket, Inverse(g)); + else + Accumulate(bucket, g); + exponents[i].FindNextWindow(); + } + notDone = notDone || !exponents[i].finished; + } + + if (notDone) + { + g = Double(g); + expBitPosition++; + } + } + + for (i=0; i<expCount; i++) + { + Element &r = *results++; + r = buckets[i][buckets[i].size()-1]; + if (buckets[i].size() > 1) + { + for (int j = buckets[i].size()-2; j >= 1; j--) + { + Accumulate(buckets[i][j], buckets[i][j+1]); + Accumulate(r, buckets[i][j]); + } + Accumulate(buckets[i][0], buckets[i][1]); + r = Add(Double(r), buckets[i][0]); + } + } +} + +template <class T> T AbstractRing<T>::Exponentiate(const Element &base, + const Integer &exponent) const +{ + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; +} + +template <class T> T AbstractRing<T>::CascadeExponentiate(const Element &x, + const Integer &e1, const Element &y, const Integer &e2) const +{ + return MultiplicativeGroup().AbstractGroup<T>::CascadeScalarMultiply( + x, e1, y, e2); +} + +template <class Element, class Iterator> Element GeneralCascadeExponentiation( + const AbstractRing<Element> &ring, Iterator begin, Iterator end) +{ + return GeneralCascadeMultiplication<Element>(ring.MultiplicativeGroup(), + begin, end); +} + +template <class T> +void AbstractRing<T>::SimultaneousExponentiate(T *results, const T &base, + const Integer *exponents, unsigned int expCount) const +{ + MultiplicativeGroup().AbstractGroup<T>::SimultaneousMultiply(results, base, + exponents, expCount); +} + +} // namespace diff --git a/extra/yassl/taocrypt/src/arc4.cpp b/extra/yassl/taocrypt/src/arc4.cpp new file mode 100644 index 00000000000..1e521b48f0c --- /dev/null +++ b/extra/yassl/taocrypt/src/arc4.cpp @@ -0,0 +1,93 @@ +/* arc4.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's arc4.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "arc4.hpp" + + +namespace TaoCrypt { + +void ARC4::SetKey(const byte* key, word32 length) +{ + x_ = 1; + y_ = 0; + + word32 i; + + for (i = 0; i < STATE_SIZE; i++) + state_[i] = i; + + word32 keyIndex = 0, stateIndex = 0; + + for (i = 0; i < STATE_SIZE; i++) { + word32 a = state_[i]; + stateIndex += key[keyIndex] + a; + stateIndex &= 0xFF; + state_[i] = state_[stateIndex]; + state_[stateIndex] = a; + + if (++keyIndex >= length) + keyIndex = 0; + } +} + + +// local +namespace { + +inline unsigned int MakeByte(word32& x, word32& y, byte* s) +{ + word32 a = s[x]; + y = (y+a) & 0xff; + + word32 b = s[y]; + s[x] = b; + s[y] = a; + x = (x+1) & 0xff; + + return s[(a+b) & 0xff]; +} + +} // namespace + + +void ARC4::Process(byte* out, const byte* in, word32 length) +{ + if (length == 0) return; + + byte *const s = state_; + word32 x = x_; + word32 y = y_; + + if (in == out) + while (length--) + *out++ ^= MakeByte(x, y, s); + else + while(length--) + *out++ = *in++ ^ MakeByte(x, y, s); + x_ = x; + y_ = y; +} + + +} // namespace diff --git a/extra/yassl/taocrypt/src/asn.cpp b/extra/yassl/taocrypt/src/asn.cpp new file mode 100644 index 00000000000..d0d22a6c61d --- /dev/null +++ b/extra/yassl/taocrypt/src/asn.cpp @@ -0,0 +1,1051 @@ + /* asn.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* asn.cpp implements ASN1 BER, PublicKey, and x509v3 decoding +*/ + + +#include "runtime.hpp" +#include "asn.hpp" +#include "file.hpp" +#include "integer.hpp" +#include "rsa.hpp" +#include "dsa.hpp" +#include "dh.hpp" +#include "md5.hpp" +#include "md2.hpp" +#include "sha.hpp" +#include "coding.hpp" +#include <time.h> // gmtime(); +#include "memory.hpp" // mySTL::auto_ptr + +namespace TaoCrypt { + +namespace { // locals + + +// to the minute +bool operator>(tm& a, tm& b) +{ + if (a.tm_year > b.tm_year) + return true; + + if (a.tm_year == b.tm_year && a.tm_mon > b.tm_mon) + return true; + + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && a.tm_mday >b.tm_mday) + return true; + + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && + a.tm_mday == b.tm_mday && a.tm_hour > b.tm_hour) + return true; + + if (a.tm_year == b.tm_year && a.tm_mon == b.tm_mon && + a.tm_mday == b.tm_mday && a.tm_hour == b.tm_hour && + a.tm_min > b.tm_min) + return true; + + return false; +} + + +bool operator<(tm& a, tm&b) +{ + return !(a>b); +} + + +// like atoi but only use first byte +word32 btoi(byte b) +{ + return b - 0x30; +} + + +// two byte date/time, add to value +void GetTime(int& value, const byte* date, int& i) +{ + value += btoi(date[i++]) * 10; + value += btoi(date[i++]); +} + + +// Make sure before and after dates are valid +bool ValidateDate(const byte* date, byte format, CertDecoder::DateType dt) +{ + tm certTime; + memset(&certTime, 0, sizeof(certTime)); + int i = 0; + + if (format == UTC_TIME) { + if (btoi(date[0]) >= 5) + certTime.tm_year = 1900; + else + certTime.tm_year = 2000; + } + else { // format == GENERALIZED_TIME + certTime.tm_year += btoi(date[i++]) * 1000; + certTime.tm_year += btoi(date[i++]) * 100; + } + + GetTime(certTime.tm_year, date, i); certTime.tm_year -= 1900; // adjust + GetTime(certTime.tm_mon, date, i); certTime.tm_mon -= 1; // adjust + GetTime(certTime.tm_mday, date, i); + GetTime(certTime.tm_hour, date, i); + GetTime(certTime.tm_min, date, i); + GetTime(certTime.tm_sec, date, i); + + assert(date[i] == 'Z'); // only Zulu supported for this profile + + time_t ltime = time(0); + tm* localTime = gmtime(<ime); + + if (dt == CertDecoder::BEFORE) { + if (*localTime < certTime) + return false; + } + else + if (*localTime > certTime) + return false; + + return true; +} + + +class BadCertificate {}; + +} // local namespace + + + +// used by Integer as well +word32 GetLength(Source& source) +{ + word32 length = 0; + + byte b = source.next(); + if (b >= LONG_LENGTH) { + word32 bytes = b & 0x7F; + + while (bytes--) { + b = source.next(); + length = (length << 8) | b; + } + } + else + length = b; + + return length; +} + + +word32 SetLength(word32 length, byte* output) +{ + word32 i = 0; + + if (length < LONG_LENGTH) + output[i++] = length; + else { + output[i++] = BytePrecision(length) | 0x80; + + for (int j = BytePrecision(length); j; --j) { + output[i] = length >> (j - 1) * 8; + i++; + } + } + return i; +} + + +PublicKey::PublicKey(const byte* k, word32 s) : key_(0), sz_(0) +{ + if (s) { + SetSize(s); + SetKey(k); + } +} + + +void PublicKey::SetSize(word32 s) +{ + sz_ = s; + key_ = new (tc) byte[sz_]; +} + + +void PublicKey::SetKey(const byte* k) +{ + memcpy(key_, k, sz_); +} + + +void PublicKey::AddToEnd(const byte* data, word32 len) +{ + mySTL::auto_ptr<byte> tmp(new (tc) byte[sz_ + len]); + + memcpy(tmp.get(), key_, sz_); + memcpy(tmp.get() + sz_, data, len); + + byte* del = 0; + mySTL::swap(del, key_); + delete[] del; + + key_ = tmp.release(); + sz_ += len; +} + + +Signer::Signer(const byte* k, word32 kSz, const char* n, const byte* h) + : key_(k, kSz), name_(0) +{ + if (n) { + int sz = strlen(n); + name_ = new (tc) char[sz + 1]; + memcpy(name_, n, sz); + name_[sz] = 0; + } + + memcpy(hash_, h, SHA::DIGEST_SIZE); +} + +Signer::~Signer() +{ + delete[] name_; +} + + +Error BER_Decoder::GetError() +{ + return source_.GetError(); +} + + +Integer& BER_Decoder::GetInteger(Integer& integer) +{ + if (!source_.GetError().What()) + integer.Decode(source_); + return integer; +} + + +// Read a Sequence, return length +word32 BER_Decoder::GetSequence() +{ + if (source_.GetError().What()) return 0; + + byte b = source_.next(); + if (b != (SEQUENCE | CONSTRUCTED)) { + source_.SetError(SEQUENCE_E); + return 0; + } + + return GetLength(source_); +} + + +// Read a Sequence, return length +word32 BER_Decoder::GetSet() +{ + if (source_.GetError().What()) return 0; + + byte b = source_.next(); + if (b != (SET | CONSTRUCTED)) { + source_.SetError(SET_E); + return 0; + } + + return GetLength(source_); +} + + +// Read Version, return it +word32 BER_Decoder::GetVersion() +{ + if (source_.GetError().What()) return 0; + + byte b = source_.next(); + if (b != INTEGER) { + source_.SetError(INTEGER_E); + return 0; + } + + b = source_.next(); + if (b != 0x01) { + source_.SetError(VERSION_E); + return 0; + } + + return source_.next(); +} + + +// Read ExplicitVersion, return it or 0 if not there (not an error) +word32 BER_Decoder::GetExplicitVersion() +{ + if (source_.GetError().What()) return 0; + + byte b = source_.next(); + + if (b == (CONTEXT_SPECIFIC | CONSTRUCTED)) { // not an error if not here + source_.next(); + return GetVersion(); + } + else + source_.prev(); // put back + + return 0; +} + + +// Decode a BER encoded RSA Private Key +void RSA_Private_Decoder::Decode(RSA_PrivateKey& key) +{ + ReadHeader(); + if (source_.GetError().What()) return; + // public + key.SetModulus(GetInteger(Integer().Ref())); + key.SetPublicExponent(GetInteger(Integer().Ref())); + + // private + key.SetPrivateExponent(GetInteger(Integer().Ref())); + key.SetPrime1(GetInteger(Integer().Ref())); + key.SetPrime2(GetInteger(Integer().Ref())); + key.SetModPrime1PrivateExponent(GetInteger(Integer().Ref())); + key.SetModPrime2PrivateExponent(GetInteger(Integer().Ref())); + key.SetMultiplicativeInverseOfPrime2ModPrime1(GetInteger(Integer().Ref())); +} + + +void RSA_Private_Decoder::ReadHeader() +{ + GetSequence(); + GetVersion(); +} + + +// Decode a BER encoded DSA Private Key +void DSA_Private_Decoder::Decode(DSA_PrivateKey& key) +{ + ReadHeader(); + if (source_.GetError().What()) return; + // group parameters + key.SetModulus(GetInteger(Integer().Ref())); + key.SetSubGroupOrder(GetInteger(Integer().Ref())); + key.SetSubGroupGenerator(GetInteger(Integer().Ref())); + + // key + key.SetPublicPart(GetInteger(Integer().Ref())); + key.SetPrivatePart(GetInteger(Integer().Ref())); +} + + +void DSA_Private_Decoder::ReadHeader() +{ + GetSequence(); + GetVersion(); +} + + +// Decode a BER encoded RSA Public Key +void RSA_Public_Decoder::Decode(RSA_PublicKey& key) +{ + ReadHeader(); + if (source_.GetError().What()) return; + + // public key + key.SetModulus(GetInteger(Integer().Ref())); + key.SetPublicExponent(GetInteger(Integer().Ref())); +} + + +void RSA_Public_Decoder::ReadHeader() +{ + GetSequence(); +} + + +// Decode a BER encoded DSA Public Key +void DSA_Public_Decoder::Decode(DSA_PublicKey& key) +{ + ReadHeader(); + if (source_.GetError().What()) return; + + // group parameters + key.SetModulus(GetInteger(Integer().Ref())); + key.SetSubGroupOrder(GetInteger(Integer().Ref())); + key.SetSubGroupGenerator(GetInteger(Integer().Ref())); + + // key + key.SetPublicPart(GetInteger(Integer().Ref())); +} + + +void DSA_Public_Decoder::ReadHeader() +{ + GetSequence(); +} + + +void DH_Decoder::ReadHeader() +{ + GetSequence(); +} + + +// Decode a BER encoded Diffie-Hellman Key +void DH_Decoder::Decode(DH& key) +{ + ReadHeader(); + if (source_.GetError().What()) return; + + // group parms + key.SetP(GetInteger(Integer().Ref())); + key.SetG(GetInteger(Integer().Ref())); +} + + +CertDecoder::CertDecoder(Source& s, bool decode, SignerList* signers) + : BER_Decoder(s), certBegin_(0), sigIndex_(0), sigLength_(0), + signature_(0), issuer_(0), subject_(0) +{ + if (decode) + Decode(signers); +} + + +CertDecoder::~CertDecoder() +{ + delete[] subject_; + delete[] issuer_; + delete[] signature_; +} + + +// process certificate header, set signature offset +void CertDecoder::ReadHeader() +{ + if (source_.GetError().What()) return; + + GetSequence(); // total + certBegin_ = source_.get_index(); + + sigIndex_ = GetSequence(); // this cert + sigIndex_ += source_.get_index(); + + GetExplicitVersion(); // version + GetInteger(Integer().Ref()); // serial number +} + + +// Decode a x509v3 Certificate +void CertDecoder::Decode(SignerList* signers) +{ + if (source_.GetError().What()) return; + DecodeToKey(); + if (source_.GetError().What()) return; + + if (source_.get_index() != sigIndex_) + source_.set_index(sigIndex_); + + word32 confirmOID = GetAlgoId(); + GetSignature(); + if (source_.GetError().What()) return; + + if ( confirmOID != signatureOID_ ) { + source_.SetError(SIG_OID_E); + return; + } + + if ( memcmp(issuerHash_, subjectHash_, SHA::DIGEST_SIZE) == 0 ) { + if (!ValidateSelfSignature()) + source_.SetError(SIG_CONFIRM_E); + } + else + if (!ValidateSignature(signers)) + source_.SetError(SIG_CONFIRM_E); +} + + +void CertDecoder::DecodeToKey() +{ + ReadHeader(); + signatureOID_ = GetAlgoId(); + GetName(ISSUER); + GetValidity(); + GetName(SUBJECT); + GetKey(); +} + + +// Read public key +void CertDecoder::GetKey() +{ + if (source_.GetError().What()) return; + + GetSequence(); + keyOID_ = GetAlgoId(); + + if (keyOID_ == RSAk) { + byte b = source_.next(); + if (b != BIT_STRING) { + source_.SetError(BIT_STR_E); + return; + } + b = source_.next(); // length, future + b = source_.next(); + while(b != 0) + b = source_.next(); + } + else if (keyOID_ == DSAk) + ; // do nothing + else { + source_.SetError(UNKNOWN_OID_E); + return; + } + + StoreKey(); + if (keyOID_ == DSAk) + AddDSA(); +} + + +// Save public key +void CertDecoder::StoreKey() +{ + if (source_.GetError().What()) return; + + word32 read = source_.get_index(); + word32 length = GetSequence(); + + read = source_.get_index() - read; + length += read; + + while (read--) source_.prev(); + + key_.SetSize(length); + key_.SetKey(source_.get_current()); + source_.advance(length); +} + + +// DSA has public key after group +void CertDecoder::AddDSA() +{ + if (source_.GetError().What()) return; + + byte b = source_.next(); + if (b != BIT_STRING) { + source_.SetError(BIT_STR_E); + return; + } + b = source_.next(); // length, future + b = source_.next(); + while(b != 0) + b = source_.next(); + + word32 idx = source_.get_index(); + b = source_.next(); + if (b != INTEGER) { + source_.SetError(INTEGER_E); + return; + } + + word32 length = GetLength(source_); + length += source_.get_index() - idx; + + key_.AddToEnd(source_.get_buffer() + idx, length); +} + + +// process algo OID by summing, return it +word32 CertDecoder::GetAlgoId() +{ + if (source_.GetError().What()) return 0; + word32 length = GetSequence(); + + byte b = source_.next(); + if (b != OBJECT_IDENTIFIER) { + source_.SetError(OBJECT_ID_E); + return 0; + } + + length = GetLength(source_); + word32 oid = 0; + + while(length--) + oid += source_.next(); // just sum it up for now + + if (oid != SHAwDSA && oid != DSAk) { + b = source_.next(); // should have NULL tag and 0 + + if (b != TAG_NULL) { + source_.SetError(TAG_NULL_E); + return 0; + } + + b = source_.next(); + if (b != 0) { + source_.SetError(EXPECT_0_E); + return 0; + } + } + + return oid; +} + + +// read cert signature, store in signature_ +word32 CertDecoder::GetSignature() +{ + if (source_.GetError().What()) return 0; + byte b = source_.next(); + + if (b != BIT_STRING) { + source_.SetError(BIT_STR_E); + return 0; + } + + sigLength_ = GetLength(source_); + + b = source_.next(); + if (b != 0) { + source_.SetError(EXPECT_0_E); + return 0; + } + sigLength_--; + + signature_ = new (tc) byte[sigLength_]; + memcpy(signature_, source_.get_current(), sigLength_); + source_.advance(sigLength_); + + return sigLength_; +} + + +// read cert digest, store in signature_ +word32 CertDecoder::GetDigest() +{ + if (source_.GetError().What()) return 0; + byte b = source_.next(); + + if (b != OCTET_STRING) { + source_.SetError(OCTET_STR_E); + return 0; + } + + sigLength_ = GetLength(source_); + + signature_ = new (tc) byte[sigLength_]; + memcpy(signature_, source_.get_current(), sigLength_); + source_.advance(sigLength_); + + return sigLength_; +} + + +// process NAME, either issuer or subject +void CertDecoder::GetName(NameType nt) +{ + if (source_.GetError().What()) return; + + SHA sha; + word32 length = GetSequence(); // length of all distinguished names + length += source_.get_index(); + + while (source_.get_index() < length) { + GetSet(); + GetSequence(); + + byte b = source_.next(); + if (b != OBJECT_IDENTIFIER) { + source_.SetError(OBJECT_ID_E); + return; + } + + word32 oidSz = GetLength(source_); + byte joint[2]; + memcpy(joint, source_.get_current(), sizeof(joint)); + + // v1 name types + if (joint[0] == 0x55 && joint[1] == 0x04) { + source_.advance(2); + byte id = source_.next(); + b = source_.next(); // strType + word32 strLen = GetLength(source_); + + if (id == COMMON_NAME) { + char*& ptr = (nt == ISSUER) ? issuer_ : subject_; + ptr = new (tc) char[strLen + 1]; + memcpy(ptr, source_.get_current(), strLen); + ptr[strLen] = 0; + } + sha.Update(source_.get_current(), strLen); + source_.advance(strLen); + } + else { + // skip + source_.advance(oidSz + 1); + word32 length = GetLength(source_); + source_.advance(length); + } + } + if (nt == ISSUER) + sha.Final(issuerHash_); + else + sha.Final(subjectHash_); +} + + +// process a Date, either BEFORE or AFTER +void CertDecoder::GetDate(DateType dt) +{ + if (source_.GetError().What()) return; + + byte b = source_.next(); + if (b != UTC_TIME && b != GENERALIZED_TIME) { + source_.SetError(TIME_E); + return; + } + + word32 length = GetLength(source_); + byte date[MAX_DATE_SZ]; + if (length > MAX_DATE_SZ || length < MIN_DATE_SZ) { + source_.SetError(DATE_SZ_E); + return; + } + + memcpy(date, source_.get_current(), length); + source_.advance(length); + + if (!ValidateDate(date, b, dt)) + if (dt == BEFORE) + source_.SetError(BEFORE_DATE_E); + else + source_.SetError(AFTER_DATE_E); +} + + +void CertDecoder::GetValidity() +{ + if (source_.GetError().What()) return; + + GetSequence(); + GetDate(BEFORE); + GetDate(AFTER); +} + + +bool CertDecoder::ValidateSelfSignature() +{ + Source pub(key_.GetKey(), key_.size()); + return ConfirmSignature(pub); +} + + +// extract compare signature hash from plain and place into digest +void CertDecoder::GetCompareHash(const byte* plain, word32 sz, byte* digest, + word32 digSz) +{ + if (source_.GetError().What()) return; + + Source s(plain, sz); + CertDecoder dec(s, false); + + dec.GetSequence(); + dec.GetAlgoId(); + dec.GetDigest(); + + if (dec.sigLength_ > digSz) { + source_.SetError(SIG_LEN_E); + return; + } + + memcpy(digest, dec.signature_, dec.sigLength_); +} + + +// validate signature signed by someone else +bool CertDecoder::ValidateSignature(SignerList* signers) +{ + assert(signers); + + SignerList::iterator first = signers->begin(); + SignerList::iterator last = signers->end(); + + while (first != last) { + if ( memcmp(issuerHash_, (*first)->GetHash(), SHA::DIGEST_SIZE) == 0) { + + const PublicKey& iKey = (*first)->GetPublicKey(); + Source pub(iKey.GetKey(), iKey.size()); + return ConfirmSignature(pub); + } + ++first; + } + return false; +} + + +// RSA confirm +bool CertDecoder::ConfirmSignature(Source& pub) +{ + HashType ht; + mySTL::auto_ptr<HASH> hasher; + + if (signatureOID_ == MD5wRSA) { + hasher.reset(new (tc) MD5); + ht = MD5h; + } + else if (signatureOID_ == MD2wRSA) { + hasher.reset(new (tc) MD2); + ht = MD2h; + } + else if (signatureOID_ == SHAwRSA || signatureOID_ == SHAwDSA) { + hasher.reset(new (tc) SHA); + ht = SHAh; + } + else { + source_.SetError(UNKOWN_SIG_E); + return false; + } + + byte digest[SHA::DIGEST_SIZE]; // largest size + + hasher->Update(source_.get_buffer() + certBegin_, sigIndex_ - certBegin_); + hasher->Final(digest); + + if (keyOID_ == RSAk) { + // put in ASN.1 signature format + Source build; + Signature_Encoder(digest, hasher->getDigestSize(), ht, build); + + RSA_PublicKey pubKey(pub); + RSAES_Encryptor enc(pubKey); + + return enc.SSL_Verify(build.get_buffer(), build.size(), signature_); + } + else { // DSA + // extract r and s from sequence + byte seqDecoded[DSA_SIG_SZ]; + DecodeDSA_Signature(seqDecoded, signature_, sigLength_); + + DSA_PublicKey pubKey(pub); + DSA_Verifier ver(pubKey); + + return ver.Verify(digest, seqDecoded); + } +} + + +Signature_Encoder::Signature_Encoder(const byte* dig, word32 digSz, + HashType digOID, Source& source) +{ + // build bottom up + + // Digest + byte digArray[MAX_DIGEST_SZ]; + word32 digestSz = SetDigest(dig, digSz, digArray); + + // AlgoID + byte algoArray[MAX_ALGO_SZ]; + word32 algoSz = SetAlgoID(digOID, algoArray); + + // Sequence + byte seqArray[MAX_SEQ_SZ]; + word32 seqSz = SetSequence(digestSz + algoSz, seqArray); + + source.grow(seqSz + algoSz + digestSz); // make sure enough room + source.add(seqArray, seqSz); + source.add(algoArray, algoSz); + source.add(digArray, digestSz); +} + + + +word32 Signature_Encoder::SetDigest(const byte* d, word32 dSz, byte* output) +{ + output[0] = OCTET_STRING; + output[1] = dSz; + memcpy(&output[2], d, dSz); + + return dSz + 2; +} + + + +word32 DER_Encoder::SetAlgoID(HashType aOID, byte* output) +{ + // adding TAG_NULL and 0 to end + static const byte shaAlgoID[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x05, 0x00 }; + static const byte md5AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x05, 0x05, 0x00 }; + static const byte md2AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x02, 0x05, 0x00}; + + int algoSz = 0; + const byte* algoName = 0; + + switch (aOID) { + case SHAh: + algoSz = sizeof(shaAlgoID); + algoName = shaAlgoID; + break; + + case MD2h: + algoSz = sizeof(md2AlgoID); + algoName = md2AlgoID; + break; + + case MD5h: + algoSz = sizeof(md5AlgoID); + algoName = md5AlgoID; + break; + + default: + error_.SetError(UNKOWN_HASH_E); + return 0; + } + + + byte ID_Length[MAX_LENGTH_SZ]; + word32 idSz = SetLength(algoSz - 2, ID_Length); // don't include TAG_NULL/0 + + byte seqArray[MAX_SEQ_SZ + 1]; // add object_id to end + word32 seqSz = SetSequence(idSz + algoSz + 1, seqArray); + seqArray[seqSz++] = OBJECT_IDENTIFIER; + + memcpy(output, seqArray, seqSz); + memcpy(output + seqSz, ID_Length, idSz); + memcpy(output + seqSz + idSz, algoName, algoSz); + + return seqSz + idSz + algoSz; +} + + +word32 SetSequence(word32 len, byte* output) +{ + + output[0] = SEQUENCE | CONSTRUCTED; + return SetLength(len, output + 1) + 1; +} + + +word32 EncodeDSA_Signature(const byte* signature, byte* output) +{ + Integer r(signature, 20); + Integer s(signature + 20, 20); + + return EncodeDSA_Signature(r, s, output); +} + + +word32 EncodeDSA_Signature(const Integer& r, const Integer& s, byte* output) +{ + word32 rSz = r.ByteCount(); + word32 sSz = s.ByteCount(); + + byte rLen[MAX_LENGTH_SZ + 1]; + byte sLen[MAX_LENGTH_SZ + 1]; + + rLen[0] = INTEGER; + sLen[0] = INTEGER; + + word32 rLenSz = SetLength(rSz, &rLen[1]) + 1; + word32 sLenSz = SetLength(sSz, &sLen[1]) + 1; + + byte seqArray[MAX_SEQ_SZ]; + + word32 seqSz = SetSequence(rLenSz + rSz + sLenSz + sSz, seqArray); + + // seq + memcpy(output, seqArray, seqSz); + // r + memcpy(output + seqSz, rLen, rLenSz); + r.Encode(output + seqSz + rLenSz, rSz); + // s + memcpy(output + seqSz + rLenSz + rSz, sLen, sLenSz); + s.Encode(output + seqSz + rLenSz + rSz + sLenSz, sSz); + + return seqSz + rLenSz + rSz + sLenSz + sSz; +} + + +// put sequence encoded dsa signature into decoded in 2 20 byte integers +word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz) +{ + Source source(encoded, sz); + + if (source.next() != (SEQUENCE | CONSTRUCTED)) { + source.SetError(SEQUENCE_E); + return 0; + } + + GetLength(source); // total + + // r + if (source.next() != INTEGER) { + source.SetError(INTEGER_E); + return 0; + } + word32 rLen = GetLength(source); + if (rLen != 20) + if (rLen == 21) { // zero at front, eat + source.next(); + --rLen; + } + else if (rLen == 19) { // add zero to front so 20 bytes + decoded[0] = 0; + decoded++; + } + else { + source.SetError(DSA_SZ_E); + return 0; + } + memcpy(decoded, source.get_buffer() + source.get_index(), rLen); + source.advance(rLen); + + // s + if (source.next() != INTEGER) { + source.SetError(INTEGER_E); + return 0; + } + word32 sLen = GetLength(source); + if (sLen != 20) + if (sLen == 21) { + source.next(); // zero at front, eat + --sLen; + } + else if (sLen == 19) { + decoded[rLen] = 0; // add zero to front so 20 bytes + decoded++; + } + else { + source.SetError(DSA_SZ_E); + return 0; + } + memcpy(decoded + rLen, source.get_buffer() + source.get_index(), sLen); + source.advance(sLen); + + return 40; +} + + +} // namespace diff --git a/extra/yassl/taocrypt/src/coding.cpp b/extra/yassl/taocrypt/src/coding.cpp new file mode 100644 index 00000000000..944a47c288e --- /dev/null +++ b/extra/yassl/taocrypt/src/coding.cpp @@ -0,0 +1,250 @@ +/* coding.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* coding.cpp implements hex and base64 encoding/decoing +*/ + +#include "runtime.hpp" +#include "coding.hpp" +#include "file.hpp" + + +namespace TaoCrypt { + + +namespace { // locals + +const byte bad = 0xFF; // invalid encoding + +const byte hexEncode[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' + }; + +const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + bad, bad, bad, bad, bad, bad, bad, + 10, 11, 12, 13, 14, 15 + }; // A starts at 0x41 not 0x3A + + +const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '+', '/' + }; + +const byte base64Decode[] = { 62, bad, bad, bad, 63, // + starts at 0x2B + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + bad, bad, bad, bad, bad, bad, bad, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, + bad, bad, bad, bad, bad, bad, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51 + }; + +const byte pad = '='; +const int pemLineSz = 64; + +} // local namespace + + +// Hex Encode +void HexEncoder::Encode() +{ + word32 bytes = plain_.size(); + encoded_.New(bytes * 2); + + word32 i = 0; + + while (bytes--) { + byte p = plain_.next(); + + byte b = p >> 4; + byte b2 = p & 0xF; + + encoded_[i++] = hexEncode[b]; + encoded_[i++] = hexEncode[b2]; + } + + plain_.reset(encoded_); +} + + +// Hex Decode +void HexDecoder::Decode() +{ + word32 bytes = coded_.size(); + assert((bytes % 2) == 0); + decoded_.New(bytes / 2); + + word32 i(0); + + while (bytes) { + byte b = coded_.next() - 0x30; // 0 starts at 0x30 + byte b2 = coded_.next() - 0x30; + + // sanity checks + assert( b < sizeof(hexDecode)/sizeof(hexDecode[0]) ); + assert( b2 < sizeof(hexDecode)/sizeof(hexDecode[0]) ); + assert( b != bad && b2 != bad ); + + b = hexDecode[b]; + b2 = hexDecode[b2]; + + decoded_[i++] = (b << 4) | b2; + bytes -= 2; + } + + coded_.reset(decoded_); +} + + +// Base 64 Encode +void Base64Encoder::Encode() +{ + word32 bytes = plain_.size(); + word32 outSz = bytes * 4 / 3; + outSz += (outSz % 4); // 4 byte integrals + + outSz += outSz / pemLineSz + ( (outSz % pemLineSz) ? 1 : 0); // new lines + encoded_.New(outSz); + + word32 i = 0; + word32 j = 0; + + while (bytes > 2) { + byte b1 = plain_.next(); + byte b2 = plain_.next(); + byte b3 = plain_.next(); + + // encoded idx + byte e1 = b1 >> 2; + byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4); + byte e3 = ((b2 & 0xF) << 2) | (b3 >> 6); + byte e4 = b3 & 0x3F; + + // store + encoded_[i++] = base64Encode[e1]; + encoded_[i++] = base64Encode[e2]; + encoded_[i++] = base64Encode[e3]; + encoded_[i++] = base64Encode[e4]; + + bytes -= 3; + + if ((++j % 16) == 0) + encoded_[i++] = '\n'; + } + + // last integral + if (bytes) { + bool twoBytes = (bytes == 2); + + byte b1 = plain_.next(); + byte b2 = (twoBytes) ? plain_.next() : 0; + + byte e1 = b1 >> 2; + byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4); + byte e3 = (b2 & 0xF) << 2; + + encoded_[i++] = base64Encode[e1]; + encoded_[i++] = base64Encode[e2]; + encoded_[i++] = (twoBytes) ? base64Encode[e3] : pad; + encoded_[i++] = pad; + } + + encoded_[i++] = '\n'; + assert(i == outSz); + + plain_.reset(encoded_); +} + + +// Base 64 Decode +void Base64Decoder::Decode() +{ + word32 bytes = coded_.size(); + word32 plainSz = bytes - (bytes / pemLineSz + ( (bytes % pemLineSz) ? + 1 : 0)); + plainSz = plainSz * 3 / 4 + (( (plainSz * 3) % 4) ? 1 : 0); + decoded_.New(plainSz); + + word32 i = 0; + word32 j = 0; + + while (bytes > 3) { + byte e1 = coded_.next(); + byte e2 = coded_.next(); + byte e3 = coded_.next(); + byte e4 = coded_.next(); + + // do asserts first + if (e1 == 0) // end file 0's + break; + + bool pad3 = false; + bool pad4 = false; + if (e3 == pad) + pad3 = true; + if (e4 == pad) + pad4 = true; + + e1 = base64Decode[e1 - 0x2B]; + e2 = base64Decode[e2 - 0x2B]; + e3 = (e3 == pad) ? 0 : base64Decode[e3 - 0x2B]; + e4 = (e4 == pad) ? 0 : base64Decode[e4 - 0x2B]; + + byte b1 = (e1 << 2) | (e2 >> 4); + byte b2 = ((e2 & 0xF) << 4) | (e3 >> 2); + byte b3 = ((e3 & 0x3) << 6) | e4; + + decoded_[i++] = b1; + if (!pad3) + decoded_[i++] = b2; + if (!pad4) + decoded_[i++] = b3; + else + break; + + bytes -= 4; + if ((++j % 16) == 0) { + byte endLine = coded_.next(); + bytes--; + if (endLine == '\r') { + endLine = coded_.next(); + bytes--; + } + assert(endLine == '\n'); + } + } + + if (i != decoded_.size()) + decoded_.resize(i); + coded_.reset(decoded_); +} + + +} // namespace diff --git a/extra/yassl/taocrypt/src/des.cpp b/extra/yassl/taocrypt/src/des.cpp new file mode 100644 index 00000000000..e5d3331500c --- /dev/null +++ b/extra/yassl/taocrypt/src/des.cpp @@ -0,0 +1,435 @@ +/* des.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's des.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "des.hpp" +#include <string.h> +#include "algorithm.hpp" // mySTL::swap + + +namespace TaoCrypt { + + +/* permuted choice table (key) */ +static const byte pc1[] = { + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +/* number left rotations of pc1 */ +static const byte totrot[] = { + 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 +}; + +/* permuted choice key (table) */ +static const byte pc2[] = { + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +/* End of DES-defined tables */ + +/* bit 0 is left-most in byte */ +static const int bytebit[] = { + 0200,0100,040,020,010,04,02,01 +}; + + +void DES::SetKey(const byte* key, word32 /*length*/, CipherDir dir) +{ + byte buffer[56+56+8]; + byte *const pc1m = buffer; /* place to modify pc1 into */ + byte *const pcr = pc1m + 56; /* place to rotate pc1 into */ + byte *const ks = pcr + 56; + register int i,j,l; + int m; + + for (j = 0; j < 56; j++) { /* convert pc1 to bits of key */ + l = pc1[j] - 1; /* integer bit location */ + m = l & 07; /* find bit */ + pc1m[j] = (key[l >> 3] & /* find which key byte l is in */ + bytebit[m]) /* and which bit of that byte */ + ? 1 : 0; /* and store 1-bit result */ + } + for (i = 0; i < 16; i++) { /* key chunk for each iteration */ + memset(ks, 0, 8); /* Clear key schedule */ + for (j = 0; j < 56; j++) /* rotate pc1 the right amount */ + pcr[j] = pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l: l-28]; + /* rotate left and right halves independently */ + for (j = 0; j < 48; j++){ /* select bits individually */ + /* check bit that goes to ks[j] */ + if (pcr[pc2[j] - 1]){ + /* mask it in if it's there */ + l= j % 6; + ks[j/6] |= bytebit[l] >> 2; + } + } + /* Now convert to odd/even interleaved form for use in F */ + k_[2*i] = ((word32)ks[0] << 24) + | ((word32)ks[2] << 16) + | ((word32)ks[4] << 8) + | ((word32)ks[6]); + k_[2*i + 1] = ((word32)ks[1] << 24) + | ((word32)ks[3] << 16) + | ((word32)ks[5] << 8) + | ((word32)ks[7]); + } + + // reverse key schedule order + if (dir == DECRYPTION) + for (i = 0; i < 16; i += 2) { + mySTL::swap(k_[i], k_[32 - 2 - i]); + mySTL::swap(k_[i+1], k_[32 - 1 - i]); + } + +} + +static inline void IPERM(word32& left, word32& right) +{ + word32 work; + + right = rotlFixed(right, 4U); + work = (left ^ right) & 0xf0f0f0f0; + left ^= work; + right = rotrFixed(right^work, 20U); + work = (left ^ right) & 0xffff0000; + left ^= work; + right = rotrFixed(right^work, 18U); + work = (left ^ right) & 0x33333333; + left ^= work; + right = rotrFixed(right^work, 6U); + work = (left ^ right) & 0x00ff00ff; + left ^= work; + right = rotlFixed(right^work, 9U); + work = (left ^ right) & 0xaaaaaaaa; + left = rotlFixed(left^work, 1U); + right ^= work; +} + +static inline void FPERM(word32& left, word32& right) +{ + word32 work; + + right = rotrFixed(right, 1U); + work = (left ^ right) & 0xaaaaaaaa; + right ^= work; + left = rotrFixed(left^work, 9U); + work = (left ^ right) & 0x00ff00ff; + right ^= work; + left = rotlFixed(left^work, 6U); + work = (left ^ right) & 0x33333333; + right ^= work; + left = rotlFixed(left^work, 18U); + work = (left ^ right) & 0xffff0000; + right ^= work; + left = rotlFixed(left^work, 20U); + work = (left ^ right) & 0xf0f0f0f0; + right ^= work; + left = rotrFixed(left^work, 4U); +} + +const word32 Spbox[DES::BOXES][DES::BOX_SIZE] = { +{ +0x01010400,0x00000000,0x00010000,0x01010404, +0x01010004,0x00010404,0x00000004,0x00010000, +0x00000400,0x01010400,0x01010404,0x00000400, +0x01000404,0x01010004,0x01000000,0x00000004, +0x00000404,0x01000400,0x01000400,0x00010400, +0x00010400,0x01010000,0x01010000,0x01000404, +0x00010004,0x01000004,0x01000004,0x00010004, +0x00000000,0x00000404,0x00010404,0x01000000, +0x00010000,0x01010404,0x00000004,0x01010000, +0x01010400,0x01000000,0x01000000,0x00000400, +0x01010004,0x00010000,0x00010400,0x01000004, +0x00000400,0x00000004,0x01000404,0x00010404, +0x01010404,0x00010004,0x01010000,0x01000404, +0x01000004,0x00000404,0x00010404,0x01010400, +0x00000404,0x01000400,0x01000400,0x00000000, +0x00010004,0x00010400,0x00000000,0x01010004}, +{ +0x80108020,0x80008000,0x00008000,0x00108020, +0x00100000,0x00000020,0x80100020,0x80008020, +0x80000020,0x80108020,0x80108000,0x80000000, +0x80008000,0x00100000,0x00000020,0x80100020, +0x00108000,0x00100020,0x80008020,0x00000000, +0x80000000,0x00008000,0x00108020,0x80100000, +0x00100020,0x80000020,0x00000000,0x00108000, +0x00008020,0x80108000,0x80100000,0x00008020, +0x00000000,0x00108020,0x80100020,0x00100000, +0x80008020,0x80100000,0x80108000,0x00008000, +0x80100000,0x80008000,0x00000020,0x80108020, +0x00108020,0x00000020,0x00008000,0x80000000, +0x00008020,0x80108000,0x00100000,0x80000020, +0x00100020,0x80008020,0x80000020,0x00100020, +0x00108000,0x00000000,0x80008000,0x00008020, +0x80000000,0x80100020,0x80108020,0x00108000}, +{ +0x00000208,0x08020200,0x00000000,0x08020008, +0x08000200,0x00000000,0x00020208,0x08000200, +0x00020008,0x08000008,0x08000008,0x00020000, +0x08020208,0x00020008,0x08020000,0x00000208, +0x08000000,0x00000008,0x08020200,0x00000200, +0x00020200,0x08020000,0x08020008,0x00020208, +0x08000208,0x00020200,0x00020000,0x08000208, +0x00000008,0x08020208,0x00000200,0x08000000, +0x08020200,0x08000000,0x00020008,0x00000208, +0x00020000,0x08020200,0x08000200,0x00000000, +0x00000200,0x00020008,0x08020208,0x08000200, +0x08000008,0x00000200,0x00000000,0x08020008, +0x08000208,0x00020000,0x08000000,0x08020208, +0x00000008,0x00020208,0x00020200,0x08000008, +0x08020000,0x08000208,0x00000208,0x08020000, +0x00020208,0x00000008,0x08020008,0x00020200}, +{ +0x00802001,0x00002081,0x00002081,0x00000080, +0x00802080,0x00800081,0x00800001,0x00002001, +0x00000000,0x00802000,0x00802000,0x00802081, +0x00000081,0x00000000,0x00800080,0x00800001, +0x00000001,0x00002000,0x00800000,0x00802001, +0x00000080,0x00800000,0x00002001,0x00002080, +0x00800081,0x00000001,0x00002080,0x00800080, +0x00002000,0x00802080,0x00802081,0x00000081, +0x00800080,0x00800001,0x00802000,0x00802081, +0x00000081,0x00000000,0x00000000,0x00802000, +0x00002080,0x00800080,0x00800081,0x00000001, +0x00802001,0x00002081,0x00002081,0x00000080, +0x00802081,0x00000081,0x00000001,0x00002000, +0x00800001,0x00002001,0x00802080,0x00800081, +0x00002001,0x00002080,0x00800000,0x00802001, +0x00000080,0x00800000,0x00002000,0x00802080}, +{ +0x00000100,0x02080100,0x02080000,0x42000100, +0x00080000,0x00000100,0x40000000,0x02080000, +0x40080100,0x00080000,0x02000100,0x40080100, +0x42000100,0x42080000,0x00080100,0x40000000, +0x02000000,0x40080000,0x40080000,0x00000000, +0x40000100,0x42080100,0x42080100,0x02000100, +0x42080000,0x40000100,0x00000000,0x42000000, +0x02080100,0x02000000,0x42000000,0x00080100, +0x00080000,0x42000100,0x00000100,0x02000000, +0x40000000,0x02080000,0x42000100,0x40080100, +0x02000100,0x40000000,0x42080000,0x02080100, +0x40080100,0x00000100,0x02000000,0x42080000, +0x42080100,0x00080100,0x42000000,0x42080100, +0x02080000,0x00000000,0x40080000,0x42000000, +0x00080100,0x02000100,0x40000100,0x00080000, +0x00000000,0x40080000,0x02080100,0x40000100}, +{ +0x20000010,0x20400000,0x00004000,0x20404010, +0x20400000,0x00000010,0x20404010,0x00400000, +0x20004000,0x00404010,0x00400000,0x20000010, +0x00400010,0x20004000,0x20000000,0x00004010, +0x00000000,0x00400010,0x20004010,0x00004000, +0x00404000,0x20004010,0x00000010,0x20400010, +0x20400010,0x00000000,0x00404010,0x20404000, +0x00004010,0x00404000,0x20404000,0x20000000, +0x20004000,0x00000010,0x20400010,0x00404000, +0x20404010,0x00400000,0x00004010,0x20000010, +0x00400000,0x20004000,0x20000000,0x00004010, +0x20000010,0x20404010,0x00404000,0x20400000, +0x00404010,0x20404000,0x00000000,0x20400010, +0x00000010,0x00004000,0x20400000,0x00404010, +0x00004000,0x00400010,0x20004010,0x00000000, +0x20404000,0x20000000,0x00400010,0x20004010}, +{ +0x00200000,0x04200002,0x04000802,0x00000000, +0x00000800,0x04000802,0x00200802,0x04200800, +0x04200802,0x00200000,0x00000000,0x04000002, +0x00000002,0x04000000,0x04200002,0x00000802, +0x04000800,0x00200802,0x00200002,0x04000800, +0x04000002,0x04200000,0x04200800,0x00200002, +0x04200000,0x00000800,0x00000802,0x04200802, +0x00200800,0x00000002,0x04000000,0x00200800, +0x04000000,0x00200800,0x00200000,0x04000802, +0x04000802,0x04200002,0x04200002,0x00000002, +0x00200002,0x04000000,0x04000800,0x00200000, +0x04200800,0x00000802,0x00200802,0x04200800, +0x00000802,0x04000002,0x04200802,0x04200000, +0x00200800,0x00000000,0x00000002,0x04200802, +0x00000000,0x00200802,0x04200000,0x00000800, +0x04000002,0x04000800,0x00000800,0x00200002}, +{ +0x10001040,0x00001000,0x00040000,0x10041040, +0x10000000,0x10001040,0x00000040,0x10000000, +0x00040040,0x10040000,0x10041040,0x00041000, +0x10041000,0x00041040,0x00001000,0x00000040, +0x10040000,0x10000040,0x10001000,0x00001040, +0x00041000,0x00040040,0x10040040,0x10041000, +0x00001040,0x00000000,0x00000000,0x10040040, +0x10000040,0x10001000,0x00041040,0x00040000, +0x00041040,0x00040000,0x10041000,0x00001000, +0x00000040,0x10040040,0x00001000,0x00041040, +0x10001000,0x00000040,0x10000040,0x10040000, +0x10040040,0x10000000,0x00040000,0x10001040, +0x00000000,0x10041040,0x00040040,0x10000040, +0x10040000,0x10001000,0x10001040,0x00000000, +0x10041040,0x00041000,0x00041000,0x00001040, +0x00001040,0x00040040,0x10000000,0x10041000} +}; + + + +void DES::RawProcessBlock(word32& lIn, word32& rIn) const +{ + word32 l = lIn, r = rIn; + const word32* kptr = k_; + + for (unsigned i=0; i<8; i++) + { + word32 work = rotrFixed(r, 4U) ^ kptr[4*i+0]; + l ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = r ^ kptr[4*i+1]; + l ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + + work = rotrFixed(l, 4U) ^ kptr[4*i+2]; + r ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = l ^ kptr[4*i+3]; + r ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + } + + lIn = l; rIn = r; +} + + +void DES_BASE::Process(byte* out, const byte* in, word32 sz) +{ + if (mode_ == ECB) + ECB_Process(out, in, sz); + else if (mode_ == CBC) + if (dir_ == ENCRYPTION) + CBC_Encrypt(out, in, sz); + else + CBC_Decrypt(out, in, sz); +} + + + +typedef BlockGetAndPut<word32, BigEndian> Block; + + +void DES::ProcessAndXorBlock(const byte* in, const byte* xOr, byte* out) const +{ + word32 l,r; + Block::Get(in)(l)(r); + IPERM(l,r); + + const word32* kptr = k_; + + for (unsigned i = 0; i < 8; i++) + { + word32 work = rotrFixed(r, 4U) ^ kptr[4*i+0]; + l ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = r ^ kptr[4*i+1]; + l ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + + work = rotrFixed(l, 4U) ^ kptr[4*i+2]; + r ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = l ^ kptr[4*i+3]; + r ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + } + + FPERM(l,r); + Block::Put(xOr, out)(r)(l); +} + + +void DES_EDE2::SetKey(const byte* key, word32 sz, CipherDir dir) +{ + des1_.SetKey(key, sz, dir); + des2_.SetKey(key + 8, sz, ReverseDir(dir)); +} + + +void DES_EDE2::ProcessAndXorBlock(const byte* in, const byte* xOr, + byte* out) const +{ + word32 l,r; + Block::Get(in)(l)(r); + IPERM(l,r); + des1_.RawProcessBlock(l, r); + des2_.RawProcessBlock(r, l); + des1_.RawProcessBlock(l, r); + FPERM(l,r); + Block::Put(xOr, out)(r)(l); +} + + +void DES_EDE3::SetKey(const byte* key, word32 sz, CipherDir dir) +{ + des1_.SetKey(key+(dir==ENCRYPTION?0:2*8), sz, dir); + des2_.SetKey(key+8, sz, ReverseDir(dir)); + des3_.SetKey(key+(dir==DECRYPTION?0:2*8), sz, dir); +} + +void DES_EDE3::ProcessAndXorBlock(const byte* in, const byte* xOr, + byte* out) const +{ + word32 l,r; + Block::Get(in)(l)(r); + IPERM(l,r); + des1_.RawProcessBlock(l, r); + des2_.RawProcessBlock(r, l); + des3_.RawProcessBlock(l, r); + FPERM(l,r); + Block::Put(xOr, out)(r)(l); +} + + +} // namespace diff --git a/extra/yassl/taocrypt/src/dh.cpp b/extra/yassl/taocrypt/src/dh.cpp new file mode 100644 index 00000000000..e5a6a562c52 --- /dev/null +++ b/extra/yassl/taocrypt/src/dh.cpp @@ -0,0 +1,85 @@ +/* dh.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* dh.cpp implements Diffie-Hellman support +*/ + +#include "runtime.hpp" +#include "dh.hpp" +#include "asn.hpp" +#include <cmath> + +namespace TaoCrypt { + + +// Generate a DH Key Pair +void DH::GenerateKeyPair(RandomNumberGenerator& rng, byte* priv, byte* pub) +{ + GeneratePrivate(rng, priv); + GeneratePublic(priv, pub); +} + + +// Generate private value +void DH::GeneratePrivate(RandomNumberGenerator& rng, byte* priv) +{ + Integer x(rng, Integer::One(), p_ - 1); + x.Encode(priv, p_.ByteCount()); +} + + +// Generate public value +void DH::GeneratePublic(const byte* priv, byte* pub) +{ + const word32 bc(p_.ByteCount()); + Integer x(priv, bc); + Integer y(a_exp_b_mod_c(g_, x, p_)); + y.Encode(pub, bc); +} + + +// Generate Agreement +void DH::Agree(byte* agree, const byte* priv, const byte* otherPub) +{ + const word32 bc(p_.ByteCount()); + Integer x(priv, bc); + Integer y(otherPub, bc); + + Integer z(a_exp_b_mod_c(y, x, p_)); + z.Encode(agree, bc); +} + + +DH::DH(Source& source) +{ + Initialize(source); +} + + +void DH::Initialize(Source& source) +{ + DH_Decoder decoder(source); + decoder.Decode(*this); +} + + +} // namespace diff --git a/extra/yassl/taocrypt/src/dsa.cpp b/extra/yassl/taocrypt/src/dsa.cpp new file mode 100644 index 00000000000..4716ebb22df --- /dev/null +++ b/extra/yassl/taocrypt/src/dsa.cpp @@ -0,0 +1,277 @@ +/* dsa.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 "runtime.hpp" +#include "dsa.hpp" +#include "sha.hpp" +#include "asn.hpp" +#include "modarith.hpp" +#include "stdexcept.hpp" + +#include "algebra.cpp" // for GCC 3.2 on aix ? + + +namespace TaoCrypt { + + +void DSA_PublicKey::Swap(DSA_PublicKey& other) +{ + p_.Swap(other.p_); + q_.Swap(other.q_); + g_.Swap(other.g_); + y_.Swap(other.y_); +} + + +DSA_PublicKey::DSA_PublicKey(const DSA_PublicKey& other) + : p_(other.p_), q_(other.q_), g_(other.g_), y_(other.y_) +{} + + +DSA_PublicKey& DSA_PublicKey::operator=(const DSA_PublicKey& that) +{ + DSA_PublicKey tmp(that); + Swap(tmp); + return *this; +} + + +DSA_PublicKey::DSA_PublicKey(Source& source) +{ + Initialize(source); +} + + +void DSA_PublicKey::Initialize(Source& source) +{ + DSA_Public_Decoder decoder(source); + decoder.Decode(*this); +} + + +void DSA_PublicKey::Initialize(const Integer& p, const Integer& q, + const Integer& g, const Integer& y) +{ + p_ = p; + q_ = q; + g_ = g; + y_ = y; +} + + +const Integer& DSA_PublicKey::GetModulus() const +{ + return p_; +} + +const Integer& DSA_PublicKey::GetSubGroupOrder() const +{ + return q_; +} + + +const Integer& DSA_PublicKey::GetSubGroupGenerator() const +{ + return g_; +} + + +const Integer& DSA_PublicKey::GetPublicPart() const +{ + return y_; +} + + +void DSA_PublicKey::SetModulus(const Integer& p) +{ + p_ = p; +} + + +void DSA_PublicKey::SetSubGroupOrder(const Integer& q) +{ + q_ = q; +} + + +void DSA_PublicKey::SetSubGroupGenerator(const Integer& g) +{ + g_ = g; +} + + +void DSA_PublicKey::SetPublicPart(const Integer& y) +{ + y_ = y; +} + + +word32 DSA_PublicKey::SignatureLength() const +{ + return GetSubGroupOrder().ByteCount() * 2; // r and s +} + + + +DSA_PrivateKey::DSA_PrivateKey(Source& source) +{ + Initialize(source); +} + + +void DSA_PrivateKey::Initialize(Source& source) +{ + DSA_Private_Decoder decoder(source); + decoder.Decode(*this); +} + + +void DSA_PrivateKey::Initialize(const Integer& p, const Integer& q, + const Integer& g, const Integer& y, + const Integer& x) +{ + DSA_PublicKey::Initialize(p, q, g, y); + x_ = x; +} + + +const Integer& DSA_PrivateKey::GetPrivatePart() const +{ + return x_; +} + + +void DSA_PrivateKey::SetPrivatePart(const Integer& x) +{ + x_ = x; +} + + +DSA_Signer::DSA_Signer(const DSA_PrivateKey& key) + : key_(key) +{} + + +word32 DSA_Signer::Sign(const byte* sha_digest, byte* sig, + RandomNumberGenerator& rng) +{ + const Integer& p = key_.GetModulus(); + const Integer& q = key_.GetSubGroupOrder(); + const Integer& g = key_.GetSubGroupGenerator(); + const Integer& x = key_.GetPrivatePart(); + + Integer k(rng, 1, q - 1); + + r_ = a_exp_b_mod_c(g, k, p); + r_ %= q; + + Integer H(sha_digest, SHA::DIGEST_SIZE); // sha Hash(m) + + Integer kInv = k.InverseMod(q); + s_ = (kInv * (H + x*r_)) % q; + + assert(!!r_ && !!s_); + + int rSz = r_.ByteCount(); + + if (rSz == 19) { + sig[0] = 0; + sig++; + } + + r_.Encode(sig, rSz); + + int sSz = s_.ByteCount(); + + if (sSz == 19) { + sig[rSz] = 0; + sig++; + } + + s_.Encode(sig + rSz, sSz); + + return 40; +} + + +DSA_Verifier::DSA_Verifier(const DSA_PublicKey& key) + : key_(key) +{} + + +bool DSA_Verifier::Verify(const byte* sha_digest, const byte* sig) +{ + const Integer& p = key_.GetModulus(); + const Integer& q = key_.GetSubGroupOrder(); + const Integer& g = key_.GetSubGroupGenerator(); + const Integer& y = key_.GetPublicPart(); + + int sz = q.ByteCount(); + + r_.Decode(sig, sz); + s_.Decode(sig + sz, sz); + + if (r_ >= q || r_ < 1 || s_ >= q || s_ < 1) + return false; + + Integer H(sha_digest, SHA::DIGEST_SIZE); // sha Hash(m) + + Integer w = s_.InverseMod(q); + Integer u1 = (H * w) % q; + Integer u2 = (r_ * w) % q; + + // verify r == ((g^u1 * y^u2) mod p) mod q + ModularArithmetic ma(p); + Integer v = ma.CascadeExponentiate(g, u1, y, u2); + v %= q; + + return r_ == v; +} + + + + +const Integer& DSA_Signer::GetR() const +{ + return r_; +} + + +const Integer& DSA_Signer::GetS() const +{ + return s_; +} + + +const Integer& DSA_Verifier::GetR() const +{ + return r_; +} + + +const Integer& DSA_Verifier::GetS() const +{ + return s_; +} + + +} // namespace diff --git a/extra/yassl/taocrypt/src/file.cpp b/extra/yassl/taocrypt/src/file.cpp new file mode 100644 index 00000000000..4d48b9e7bca --- /dev/null +++ b/extra/yassl/taocrypt/src/file.cpp @@ -0,0 +1,118 @@ +/* file.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* file.cpp implements File Sources and Sinks +*/ + +#include "runtime.hpp" +#include "file.hpp" + + +namespace TaoCrypt { + + +FileSource::FileSource(const char* fname, Source& source) +{ + file_ = fopen(fname, "rb"); + if (file_) get(source); +} + + +FileSource::~FileSource() +{ + if (file_) + fclose(file_); +} + + + +// return size of source from beginning or current position +word32 FileSource::size(bool use_current) +{ + long current = ftell(file_); + long begin = current; + + if (!use_current) { + fseek(file_, 0, SEEK_SET); + begin = ftell(file_); + } + + fseek(file_, 0, SEEK_END); + long end = ftell(file_); + + fseek(file_, current, SEEK_SET); + + return end - begin; +} + + +word32 FileSource::size_left() +{ + return size(true); +} + + +// fill file source from source +word32 FileSource::get(Source& source) +{ + word32 sz(size()); + if (source.size() < sz) + source.grow(sz); + + size_t bytes = fread(source.buffer_.get_buffer(), 1, sz, file_); + + if (bytes == 1) + return sz; + else + return 0; +} + + +FileSink::FileSink(const char* fname, Source& source) +{ + file_ = fopen(fname, "wb"); + if (file_) put(source); +} + + +FileSink::~FileSink() +{ + if (file_) + fclose(file_); +} + + +// fill source from file sink +void FileSink::put(Source& source) +{ + fwrite(source.get_buffer(), 1, source.size(), file_); +} + + +// swap with other and reset to beginning +void Source::reset(ByteBlock& otherBlock) +{ + buffer_.Swap(otherBlock); + current_ = 0; +} + + +} // namespace diff --git a/extra/yassl/taocrypt/src/hash.cpp b/extra/yassl/taocrypt/src/hash.cpp new file mode 100644 index 00000000000..09b9fe52b2b --- /dev/null +++ b/extra/yassl/taocrypt/src/hash.cpp @@ -0,0 +1,88 @@ +/* hash.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* hash.cpp implements a base for digest types +*/ + +#include "runtime.hpp" +#include <string.h> + +#include "hash.hpp" + + +namespace TaoCrypt { + + +// Update digest with data of size len, do in blocks +void HASHwithTransform::Update(const byte* data, word32 len) +{ + // do block size increments + word32 blockSz = getBlockSize(); + while (len) { + word32 add = min(len, blockSz - buffLen_); + memcpy(&buffer_[buffLen_], data, add); + + buffLen_ += add; + data += add; + len -= add; + + if (buffLen_ == blockSz) { + ByteReverseIf(buffer_, buffer_, blockSz, getByteOrder()); + Transform(); + } + } +} + + +// Final process, place digest in hash +void HASHwithTransform::Final(byte* hash) +{ + word32 blockSz = getBlockSize(); + word32 digestSz = getDigestSize(); + word32 padSz = getPadSize(); + ByteOrder order = getByteOrder(); + word32 prePadLen = length_ + buffLen_ * 8; // in bits + + buffer_[buffLen_++] = 0x80; // add 1 + + // pad with zeros + if (buffLen_ > padSz) { + while (buffLen_ < blockSz) buffer_[buffLen_++] = 0; + ByteReverseIf(buffer_, buffer_, blockSz, order); + Transform(); + } + while (buffLen_ < padSz) buffer_[buffLen_++] = 0; + + ByteReverseIf(buffer_, buffer_, blockSz, order); + + word32 hiSize = 0; // for future 64 bit length TODO: + memcpy(&buffer_[padSz], order ? &hiSize : &prePadLen, sizeof(prePadLen)); + memcpy(&buffer_[padSz+4], order ? &prePadLen : &hiSize, sizeof(prePadLen)); + + + Transform(); + ByteReverseIf(digest_, digest_, digestSz, order); + memcpy(hash, digest_, digestSz); + + Init(); // reset state +} + +} // namespace diff --git a/extra/yassl/taocrypt/src/integer.cpp b/extra/yassl/taocrypt/src/integer.cpp new file mode 100644 index 00000000000..20a968d78e3 --- /dev/null +++ b/extra/yassl/taocrypt/src/integer.cpp @@ -0,0 +1,4183 @@ +/* integer.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + + +/* based on Wei Dai's integer.cpp from CryptoPP */ + +#ifdef _MSC_VER + // 4250: dominance + // 4660: explicitly instantiating a class already implicitly instantiated + // 4661: no suitable definition provided for explicit template request + // 4786: identifer was truncated in debug information + // 4355: 'this' : used in base member initializer list +# pragma warning(disable: 4250 4660 4661 4786 4355) +#endif + +#include "runtime.hpp" +#include "integer.hpp" +#include "modarith.hpp" +#include "asn.hpp" +#include "stdexcept.hpp" + +#include "algebra.cpp" + + +#ifdef __DECCXX + #include <c_asm.h> // for asm multiply overflow +#endif + + +#ifdef SSE2_INTRINSICS_AVAILABLE + #ifdef __GNUC__ + #include <xmmintrin.h> + #include <signal.h> + #include <setjmp.h> + #ifdef TAOCRYPT_MEMALIGN_AVAILABLE + #include <malloc.h> + #else + #include <stdlib.h> + #endif + #else + #include <emmintrin.h> + #endif +#elif defined(_MSC_VER) && defined(_M_IX86) + #pragma message("You do not seem to have the Visual C++ Processor Pack ") + #pragma message("installed, so use of SSE2 intrinsics will be disabled.") +#elif defined(__GNUC__) && defined(__i386__) +/* #warning You do not have GCC 3.3 or later, or did not specify the -msse2 \ + compiler option. Use of SSE2 intrinsics will be disabled. +*/ +#endif + + +namespace TaoCrypt { + + +#ifdef SSE2_INTRINSICS_AVAILABLE + +template <class T> +CPP_TYPENAME AllocatorBase<T>::pointer AlignedAllocator<T>::allocate( + size_type n, const void *) +{ + CheckSize(n); + if (n == 0) + return 0; + if (n >= 4) + { + void* p; + #ifdef TAOCRYPT_MM_MALLOC_AVAILABLE + while (!(p = _mm_malloc(sizeof(T)*n, 16))) + #elif defined(TAOCRYPT_MEMALIGN_AVAILABLE) + while (!(p = memalign(16, sizeof(T)*n))) + #elif defined(TAOCRYPT_MALLOC_ALIGNMENT_IS_16) + while (!(p = malloc(sizeof(T)*n))) + #else + while (!(p = (byte *)malloc(sizeof(T)*n + 8))) + // assume malloc alignment is at least 8 + #endif + CallNewHandler(); + + #ifdef TAOCRYPT_NO_ALIGNED_ALLOC + assert(m_pBlock == 0); + m_pBlock = p; + if (!IsAlignedOn(p, 16)) + { + assert(IsAlignedOn(p, 8)); + p = (byte *)p + 8; + } + #endif + + assert(IsAlignedOn(p, 16)); + return (T*)p; + } + return new (tc) T[n]; +} + + +template <class T> +void AlignedAllocator<T>::deallocate(void* p, size_type n) +{ + memset(p, 0, n*sizeof(T)); + if (n >= 4) + { + #ifdef TAOCRYPT_MM_MALLOC_AVAILABLE + _mm_free(p); + #elif defined(TAOCRYPT_NO_ALIGNED_ALLOC) + assert(m_pBlock == p || (byte*)m_pBlock+8 == p); + free(m_pBlock); + m_pBlock = 0; + #else + free(p); + #endif + } + else + delete [] (T *)p; +} + +#endif // SSE2 + + +// ******** start of integer needs + +// start 5.2.1 adds DWord and Word ******** + +// ******************************************************** + +class DWord { +public: +DWord() {} + +#ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + explicit DWord(word low) + { + whole_ = low; + } +#else + explicit DWord(word low) + { + halfs_.low = low; + halfs_.high = 0; + } +#endif + + DWord(word low, word high) + { + halfs_.low = low; + halfs_.high = high; + } + + static DWord Multiply(word a, word b) + { + DWord r; + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + r.whole_ = (dword)a * b; + #elif defined(__alpha__) + r.halfs_.low = a*b; + #ifdef __GNUC__ + __asm__("umulh %1,%2,%0" : "=r" (r.halfs_.high) + : "r" (a), "r" (b)); + #elif defined(__DECCXX) + r.halfs_.high = asm("umulh %a0, %a1, %v0", a, b); + #else + #error unsupported alpha compiler for asm multiply overflow + #endif + #elif defined(__ia64__) + r.halfs_.low = a*b; + __asm__("xmpy.hu %0=%1,%2" : "=f" (r.halfs_.high) + : "f" (a), "f" (b)); + #elif defined(_ARCH_PPC64) + r.halfs_.low = a*b; + __asm__("mulhdu %0,%1,%2" : "=r" (r.halfs_.high) + : "r" (a), "r" (b) : "cc"); + #elif defined(__x86_64__) + __asm__("mulq %3" : "=d" (r.halfs_.high), "=a" (r.halfs_.low) : + "a" (a), "rm" (b) : "cc"); + #elif defined(__mips64) + __asm__("dmultu %2,%3" : "=h" (r.halfs_.high), "=l" (r.halfs_.low) + : "r" (a), "r" (b)); + #elif defined(_M_IX86) + // for testing + word64 t = (word64)a * b; + r.halfs_.high = ((word32 *)(&t))[1]; + r.halfs_.low = (word32)t; + #else + #error can not implement DWord + #endif + return r; + } + + static DWord MultiplyAndAdd(word a, word b, word c) + { + DWord r = Multiply(a, b); + return r += c; + } + + DWord & operator+=(word a) + { + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + whole_ = whole_ + a; + #else + halfs_.low += a; + halfs_.high += (halfs_.low < a); + #endif + return *this; + } + + DWord operator+(word a) + { + DWord r; + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + r.whole_ = whole_ + a; + #else + r.halfs_.low = halfs_.low + a; + r.halfs_.high = halfs_.high + (r.halfs_.low < a); + #endif + return r; + } + + DWord operator-(DWord a) + { + DWord r; + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + r.whole_ = whole_ - a.whole_; + #else + r.halfs_.low = halfs_.low - a.halfs_.low; + r.halfs_.high = halfs_.high - a.halfs_.high - + (r.halfs_.low > halfs_.low); + #endif + return r; + } + + DWord operator-(word a) + { + DWord r; + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + r.whole_ = whole_ - a; + #else + r.halfs_.low = halfs_.low - a; + r.halfs_.high = halfs_.high - (r.halfs_.low > halfs_.low); + #endif + return r; + } + + // returns quotient, which must fit in a word + word operator/(word divisor); + + word operator%(word a); + + bool operator!() const + { + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + return !whole_; + #else + return !halfs_.high && !halfs_.low; + #endif + } + + word GetLowHalf() const {return halfs_.low;} + word GetHighHalf() const {return halfs_.high;} + word GetHighHalfAsBorrow() const {return 0-halfs_.high;} + +private: + union + { + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + dword whole_; + #endif + struct + { + #ifdef LITTLE_ENDIAN_ORDER + word low; + word high; + #else + word high; + word low; + #endif + } halfs_; + }; +}; + + +class Word { +public: + Word() {} + + Word(word value) + { + whole_ = value; + } + + Word(hword low, hword high) + { + whole_ = low | (word(high) << (WORD_BITS/2)); + } + + static Word Multiply(hword a, hword b) + { + Word r; + r.whole_ = (word)a * b; + return r; + } + + Word operator-(Word a) + { + Word r; + r.whole_ = whole_ - a.whole_; + return r; + } + + Word operator-(hword a) + { + Word r; + r.whole_ = whole_ - a; + return r; + } + + // returns quotient, which must fit in a word + hword operator/(hword divisor) + { + return hword(whole_ / divisor); + } + + bool operator!() const + { + return !whole_; + } + + word GetWhole() const {return whole_;} + hword GetLowHalf() const {return hword(whole_);} + hword GetHighHalf() const {return hword(whole_>>(WORD_BITS/2));} + hword GetHighHalfAsBorrow() const {return 0-hword(whole_>>(WORD_BITS/2));} + +private: + word whole_; +}; + + +// dummy is VC60 compiler bug workaround +// do a 3 word by 2 word divide, returns quotient and leaves remainder in A +template <class S, class D> +S DivideThreeWordsByTwo(S* A, S B0, S B1, D* dummy_VC6_WorkAround = 0) +{ + // assert {A[2],A[1]} < {B1,B0}, so quotient can fit in a S + assert(A[2] < B1 || (A[2]==B1 && A[1] < B0)); + + // estimate the quotient: do a 2 S by 1 S divide + S Q; + if (S(B1+1) == 0) + Q = A[2]; + else + Q = D(A[1], A[2]) / S(B1+1); + + // now subtract Q*B from A + D p = D::Multiply(B0, Q); + D u = (D) A[0] - p.GetLowHalf(); + A[0] = u.GetLowHalf(); + u = (D) A[1] - p.GetHighHalf() - u.GetHighHalfAsBorrow() - + D::Multiply(B1, Q); + A[1] = u.GetLowHalf(); + A[2] += u.GetHighHalf(); + + // Q <= actual quotient, so fix it + while (A[2] || A[1] > B1 || (A[1]==B1 && A[0]>=B0)) + { + u = (D) A[0] - B0; + A[0] = u.GetLowHalf(); + u = (D) A[1] - B1 - u.GetHighHalfAsBorrow(); + A[1] = u.GetLowHalf(); + A[2] += u.GetHighHalf(); + Q++; + assert(Q); // shouldn't overflow + } + + return Q; +} + +// do a 4 word by 2 word divide, returns 2 word quotient in Q0 and Q1 +template <class S, class D> +inline D DivideFourWordsByTwo(S *T, const D &Al, const D &Ah, const D &B) +{ + if (!B) // if divisor is 0, we assume divisor==2**(2*WORD_BITS) + return D(Ah.GetLowHalf(), Ah.GetHighHalf()); + else + { + S Q[2]; + T[0] = Al.GetLowHalf(); + T[1] = Al.GetHighHalf(); + T[2] = Ah.GetLowHalf(); + T[3] = Ah.GetHighHalf(); + Q[1] = DivideThreeWordsByTwo<S, D>(T+1, B.GetLowHalf(), + B.GetHighHalf()); + Q[0] = DivideThreeWordsByTwo<S, D>(T, B.GetLowHalf(), B.GetHighHalf()); + return D(Q[0], Q[1]); + } +} + + +// returns quotient, which must fit in a word +inline word DWord::operator/(word a) +{ + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + return word(whole_ / a); + #else + hword r[4]; + return DivideFourWordsByTwo<hword, Word>(r, halfs_.low, + halfs_.high, a).GetWhole(); + #endif +} + +inline word DWord::operator%(word a) +{ + #ifdef TAOCRYPT_NATIVE_DWORD_AVAILABLE + return word(whole_ % a); + #else + if (a < (word(1) << (WORD_BITS/2))) + { + hword h = hword(a); + word r = halfs_.high % h; + r = ((halfs_.low >> (WORD_BITS/2)) + (r << (WORD_BITS/2))) % h; + return hword((hword(halfs_.low) + (r << (WORD_BITS/2))) % h); + } + else + { + hword r[4]; + DivideFourWordsByTwo<hword, Word>(r, halfs_.low, halfs_.high, a); + return Word(r[0], r[1]).GetWhole(); + } + #endif +} + + + +// end 5.2.1 DWord and Word adds + + + + + +static const unsigned int RoundupSizeTable[] = {2, 2, 2, 4, 4, 8, 8, 8, 8}; + +static inline unsigned int RoundupSize(unsigned int n) +{ + if (n<=8) + return RoundupSizeTable[n]; + else if (n<=16) + return 16; + else if (n<=32) + return 32; + else if (n<=64) + return 64; + else return 1U << BitPrecision(n-1); +} + + +template <class T> +static Integer StringToInteger(const T *str) +{ + word radix; + + unsigned int length; + for (length = 0; str[length] != 0; length++) {} + + Integer v; + + if (length == 0) + return v; + + switch (str[length-1]) + { + case 'h': + case 'H': + radix=16; + break; + case 'o': + case 'O': + radix=8; + break; + case 'b': + case 'B': + radix=2; + break; + default: + radix=10; + } + + if (length > 2 && str[0] == '0' && str[1] == 'x') + radix = 16; + + for (unsigned i=0; i<length; i++) + { + word digit; + + if (str[i] >= '0' && str[i] <= '9') + digit = str[i] - '0'; + else if (str[i] >= 'A' && str[i] <= 'F') + digit = str[i] - 'A' + 10; + else if (str[i] >= 'a' && str[i] <= 'f') + digit = str[i] - 'a' + 10; + else + digit = radix; + + if (digit < radix) + { + v *= radix; + v += digit; + } + } + + if (str[0] == '-') + v.Negate(); + + return v; +} + +static int Compare(const word *A, const word *B, unsigned int N) +{ + while (N--) + if (A[N] > B[N]) + return 1; + else if (A[N] < B[N]) + return -1; + + return 0; +} + +static word Increment(word *A, unsigned int N, word B=1) +{ + assert(N); + word t = A[0]; + A[0] = t+B; + if (A[0] >= t) + return 0; + for (unsigned i=1; i<N; i++) + if (++A[i]) + return 0; + return 1; +} + +static word Decrement(word *A, unsigned int N, word B=1) +{ + assert(N); + word t = A[0]; + A[0] = t-B; + if (A[0] <= t) + return 0; + for (unsigned i=1; i<N; i++) + if (A[i]--) + return 0; + return 1; +} + +static void TwosComplement(word *A, unsigned int N) +{ + Decrement(A, N); + for (unsigned i=0; i<N; i++) + A[i] = ~A[i]; +} + + +static word LinearMultiply(word *C, const word *A, word B, unsigned int N) +{ + word carry=0; + for(unsigned i=0; i<N; i++) + { + DWord p = DWord::MultiplyAndAdd(A[i], B, carry); + C[i] = p.GetLowHalf(); + carry = p.GetHighHalf(); + } + return carry; +} + + +static word AtomicInverseModPower2(word A) +{ + assert(A%2==1); + + word R=A%8; + + for (unsigned i=3; i<WORD_BITS; i*=2) + R = R*(2-R*A); + + assert(R*A==1); + return R; +} + + +// ******************************************************** + +class Portable +{ +public: + static word Add(word *C, const word *A, const word *B, unsigned int N); + static word Subtract(word *C, const word *A, const word*B, unsigned int N); + + static inline void Multiply2(word *C, const word *A, const word *B); + static inline word Multiply2Add(word *C, const word *A, const word *B); + static void Multiply4(word *C, const word *A, const word *B); + static void Multiply8(word *C, const word *A, const word *B); + static inline unsigned int MultiplyRecursionLimit() {return 8;} + + static inline void Multiply2Bottom(word *C, const word *A, const word *B); + static void Multiply4Bottom(word *C, const word *A, const word *B); + static void Multiply8Bottom(word *C, const word *A, const word *B); + static inline unsigned int MultiplyBottomRecursionLimit() {return 8;} + + static void Square2(word *R, const word *A); + static void Square4(word *R, const word *A); + static void Square8(word *R, const word *A) {assert(false);} + static inline unsigned int SquareRecursionLimit() {return 4;} +}; + +word Portable::Add(word *C, const word *A, const word *B, unsigned int N) +{ + assert (N%2 == 0); + + DWord u(0, 0); + for (unsigned int i = 0; i < N; i+=2) + { + u = DWord(A[i]) + B[i] + u.GetHighHalf(); + C[i] = u.GetLowHalf(); + u = DWord(A[i+1]) + B[i+1] + u.GetHighHalf(); + C[i+1] = u.GetLowHalf(); + } + return u.GetHighHalf(); +} + +word Portable::Subtract(word *C, const word *A, const word *B, unsigned int N) +{ + assert (N%2 == 0); + + DWord u(0, 0); + for (unsigned int i = 0; i < N; i+=2) + { + u = (DWord) A[i] - B[i] - u.GetHighHalfAsBorrow(); + C[i] = u.GetLowHalf(); + u = (DWord) A[i+1] - B[i+1] - u.GetHighHalfAsBorrow(); + C[i+1] = u.GetLowHalf(); + } + return 0-u.GetHighHalf(); +} + +void Portable::Multiply2(word *C, const word *A, const word *B) +{ +/* + word s; + dword d; + + if (A1 >= A0) + if (B0 >= B1) + { + s = 0; + d = (dword)(A1-A0)*(B0-B1); + } + else + { + s = (A1-A0); + d = (dword)s*(word)(B0-B1); + } + else + if (B0 > B1) + { + s = (B0-B1); + d = (word)(A1-A0)*(dword)s; + } + else + { + s = 0; + d = (dword)(A0-A1)*(B1-B0); + } +*/ + // this segment is the branchless equivalent of above + word D[4] = {A[1]-A[0], A[0]-A[1], B[0]-B[1], B[1]-B[0]}; + unsigned int ai = A[1] < A[0]; + unsigned int bi = B[0] < B[1]; + unsigned int di = ai & bi; + DWord d = DWord::Multiply(D[di], D[di+2]); + D[1] = D[3] = 0; + unsigned int si = ai + !bi; + word s = D[si]; + + DWord A0B0 = DWord::Multiply(A[0], B[0]); + C[0] = A0B0.GetLowHalf(); + + DWord A1B1 = DWord::Multiply(A[1], B[1]); + DWord t = (DWord) A0B0.GetHighHalf() + A0B0.GetLowHalf() + d.GetLowHalf() + + A1B1.GetLowHalf(); + C[1] = t.GetLowHalf(); + + t = A1B1 + t.GetHighHalf() + A0B0.GetHighHalf() + d.GetHighHalf() + + A1B1.GetHighHalf() - s; + C[2] = t.GetLowHalf(); + C[3] = t.GetHighHalf(); +} + +inline void Portable::Multiply2Bottom(word *C, const word *A, const word *B) +{ + DWord t = DWord::Multiply(A[0], B[0]); + C[0] = t.GetLowHalf(); + C[1] = t.GetHighHalf() + A[0]*B[1] + A[1]*B[0]; +} + +word Portable::Multiply2Add(word *C, const word *A, const word *B) +{ + word D[4] = {A[1]-A[0], A[0]-A[1], B[0]-B[1], B[1]-B[0]}; + unsigned int ai = A[1] < A[0]; + unsigned int bi = B[0] < B[1]; + unsigned int di = ai & bi; + DWord d = DWord::Multiply(D[di], D[di+2]); + D[1] = D[3] = 0; + unsigned int si = ai + !bi; + word s = D[si]; + + DWord A0B0 = DWord::Multiply(A[0], B[0]); + DWord t = A0B0 + C[0]; + C[0] = t.GetLowHalf(); + + DWord A1B1 = DWord::Multiply(A[1], B[1]); + t = (DWord) t.GetHighHalf() + A0B0.GetLowHalf() + d.GetLowHalf() + + A1B1.GetLowHalf() + C[1]; + C[1] = t.GetLowHalf(); + + t = (DWord) t.GetHighHalf() + A1B1.GetLowHalf() + A0B0.GetHighHalf() + + d.GetHighHalf() + A1B1.GetHighHalf() - s + C[2]; + C[2] = t.GetLowHalf(); + + t = (DWord) t.GetHighHalf() + A1B1.GetHighHalf() + C[3]; + C[3] = t.GetLowHalf(); + return t.GetHighHalf(); +} + + +#define MulAcc(x, y) \ + p = DWord::MultiplyAndAdd(A[x], B[y], c); \ + c = p.GetLowHalf(); \ + p = (DWord) d + p.GetHighHalf(); \ + d = p.GetLowHalf(); \ + e += p.GetHighHalf(); + +#define SaveMulAcc(s, x, y) \ + R[s] = c; \ + p = DWord::MultiplyAndAdd(A[x], B[y], d); \ + c = p.GetLowHalf(); \ + p = (DWord) e + p.GetHighHalf(); \ + d = p.GetLowHalf(); \ + e = p.GetHighHalf(); + +#define SquAcc(x, y) \ + q = DWord::Multiply(A[x], A[y]); \ + p = q + c; \ + c = p.GetLowHalf(); \ + p = (DWord) d + p.GetHighHalf(); \ + d = p.GetLowHalf(); \ + e += p.GetHighHalf(); \ + p = q + c; \ + c = p.GetLowHalf(); \ + p = (DWord) d + p.GetHighHalf(); \ + d = p.GetLowHalf(); \ + e += p.GetHighHalf(); + +#define SaveSquAcc(s, x, y) \ + R[s] = c; \ + q = DWord::Multiply(A[x], A[y]); \ + p = q + d; \ + c = p.GetLowHalf(); \ + p = (DWord) e + p.GetHighHalf(); \ + d = p.GetLowHalf(); \ + e = p.GetHighHalf(); \ + p = q + c; \ + c = p.GetLowHalf(); \ + p = (DWord) d + p.GetHighHalf(); \ + d = p.GetLowHalf(); \ + e += p.GetHighHalf(); + + +void Portable::Multiply4(word *R, const word *A, const word *B) +{ + DWord p; + word c, d, e; + + p = DWord::Multiply(A[0], B[0]); + R[0] = p.GetLowHalf(); + c = p.GetHighHalf(); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + SaveMulAcc(2, 0, 3); + MulAcc(1, 2); + MulAcc(2, 1); + MulAcc(3, 0); + + SaveMulAcc(3, 3, 1); + MulAcc(2, 2); + MulAcc(1, 3); + + SaveMulAcc(4, 2, 3); + MulAcc(3, 2); + + R[5] = c; + p = DWord::MultiplyAndAdd(A[3], B[3], d); + R[6] = p.GetLowHalf(); + R[7] = e + p.GetHighHalf(); +} + +void Portable::Square2(word *R, const word *A) +{ + DWord p, q; + word c, d, e; + + p = DWord::Multiply(A[0], A[0]); + R[0] = p.GetLowHalf(); + c = p.GetHighHalf(); + d = e = 0; + + SquAcc(0, 1); + + R[1] = c; + p = DWord::MultiplyAndAdd(A[1], A[1], d); + R[2] = p.GetLowHalf(); + R[3] = e + p.GetHighHalf(); +} + +void Portable::Square4(word *R, const word *A) +{ +#ifdef _MSC_VER + // VC60 workaround: MSVC 6.0 has an optimization bug that makes + // (dword)A*B where either A or B has been cast to a dword before + // very expensive. Revisit this function when this + // bug is fixed. + Multiply4(R, A, A); +#else + const word *B = A; + DWord p, q; + word c, d, e; + + p = DWord::Multiply(A[0], A[0]); + R[0] = p.GetLowHalf(); + c = p.GetHighHalf(); + d = e = 0; + + SquAcc(0, 1); + + SaveSquAcc(1, 2, 0); + MulAcc(1, 1); + + SaveSquAcc(2, 0, 3); + SquAcc(1, 2); + + SaveSquAcc(3, 3, 1); + MulAcc(2, 2); + + SaveSquAcc(4, 2, 3); + + R[5] = c; + p = DWord::MultiplyAndAdd(A[3], A[3], d); + R[6] = p.GetLowHalf(); + R[7] = e + p.GetHighHalf(); +#endif +} + +void Portable::Multiply8(word *R, const word *A, const word *B) +{ + DWord p; + word c, d, e; + + p = DWord::Multiply(A[0], B[0]); + R[0] = p.GetLowHalf(); + c = p.GetHighHalf(); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + SaveMulAcc(2, 0, 3); + MulAcc(1, 2); + MulAcc(2, 1); + MulAcc(3, 0); + + SaveMulAcc(3, 0, 4); + MulAcc(1, 3); + MulAcc(2, 2); + MulAcc(3, 1); + MulAcc(4, 0); + + SaveMulAcc(4, 0, 5); + MulAcc(1, 4); + MulAcc(2, 3); + MulAcc(3, 2); + MulAcc(4, 1); + MulAcc(5, 0); + + SaveMulAcc(5, 0, 6); + MulAcc(1, 5); + MulAcc(2, 4); + MulAcc(3, 3); + MulAcc(4, 2); + MulAcc(5, 1); + MulAcc(6, 0); + + SaveMulAcc(6, 0, 7); + MulAcc(1, 6); + MulAcc(2, 5); + MulAcc(3, 4); + MulAcc(4, 3); + MulAcc(5, 2); + MulAcc(6, 1); + MulAcc(7, 0); + + SaveMulAcc(7, 1, 7); + MulAcc(2, 6); + MulAcc(3, 5); + MulAcc(4, 4); + MulAcc(5, 3); + MulAcc(6, 2); + MulAcc(7, 1); + + SaveMulAcc(8, 2, 7); + MulAcc(3, 6); + MulAcc(4, 5); + MulAcc(5, 4); + MulAcc(6, 3); + MulAcc(7, 2); + + SaveMulAcc(9, 3, 7); + MulAcc(4, 6); + MulAcc(5, 5); + MulAcc(6, 4); + MulAcc(7, 3); + + SaveMulAcc(10, 4, 7); + MulAcc(5, 6); + MulAcc(6, 5); + MulAcc(7, 4); + + SaveMulAcc(11, 5, 7); + MulAcc(6, 6); + MulAcc(7, 5); + + SaveMulAcc(12, 6, 7); + MulAcc(7, 6); + + R[13] = c; + p = DWord::MultiplyAndAdd(A[7], B[7], d); + R[14] = p.GetLowHalf(); + R[15] = e + p.GetHighHalf(); +} + +void Portable::Multiply4Bottom(word *R, const word *A, const word *B) +{ + DWord p; + word c, d, e; + + p = DWord::Multiply(A[0], B[0]); + R[0] = p.GetLowHalf(); + c = p.GetHighHalf(); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + R[2] = c; + R[3] = d + A[0] * B[3] + A[1] * B[2] + A[2] * B[1] + A[3] * B[0]; +} + +void Portable::Multiply8Bottom(word *R, const word *A, const word *B) +{ + DWord p; + word c, d, e; + + p = DWord::Multiply(A[0], B[0]); + R[0] = p.GetLowHalf(); + c = p.GetHighHalf(); + d = e = 0; + + MulAcc(0, 1); + MulAcc(1, 0); + + SaveMulAcc(1, 2, 0); + MulAcc(1, 1); + MulAcc(0, 2); + + SaveMulAcc(2, 0, 3); + MulAcc(1, 2); + MulAcc(2, 1); + MulAcc(3, 0); + + SaveMulAcc(3, 0, 4); + MulAcc(1, 3); + MulAcc(2, 2); + MulAcc(3, 1); + MulAcc(4, 0); + + SaveMulAcc(4, 0, 5); + MulAcc(1, 4); + MulAcc(2, 3); + MulAcc(3, 2); + MulAcc(4, 1); + MulAcc(5, 0); + + SaveMulAcc(5, 0, 6); + MulAcc(1, 5); + MulAcc(2, 4); + MulAcc(3, 3); + MulAcc(4, 2); + MulAcc(5, 1); + MulAcc(6, 0); + + R[6] = c; + R[7] = d + A[0] * B[7] + A[1] * B[6] + A[2] * B[5] + A[3] * B[4] + + A[4] * B[3] + A[5] * B[2] + A[6] * B[1] + A[7] * B[0]; +} + + +#undef MulAcc +#undef SaveMulAcc +#undef SquAcc +#undef SaveSquAcc + +// optimized + +#ifdef TAOCRYPT_X86ASM_AVAILABLE + +// ************** x86 feature detection *************** + +static bool s_sse2Enabled = true; + +static void CpuId(word32 input, word32 *output) +{ +#ifdef __GNUC__ + __asm__ + ( + // save ebx in case -fPIC is being used + "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx" + : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d"(output[3]) + : "a" (input) + ); +#else + __asm + { + mov eax, input + cpuid + mov edi, output + mov [edi], eax + mov [edi+4], ebx + mov [edi+8], ecx + mov [edi+12], edx + } +#endif +} + +#ifdef SSE2_INTRINSICS_AVAILABLE +#ifndef _MSC_VER +static jmp_buf s_env; +static void SigIllHandler(int) +{ + longjmp(s_env, 1); +} +#endif + +static bool HasSSE2() +{ + if (!s_sse2Enabled) + return false; + + word32 cpuid[4]; + CpuId(1, cpuid); + if ((cpuid[3] & (1 << 26)) == 0) + return false; + +#ifdef _MSC_VER + __try + { + __asm xorpd xmm0, xmm0 // executing SSE2 instruction + } + __except (1) + { + return false; + } + return true; +#else + typedef void (*SigHandler)(int); + + SigHandler oldHandler = signal(SIGILL, SigIllHandler); + if (oldHandler == SIG_ERR) + return false; + + bool result = true; + if (setjmp(s_env)) + result = false; + else + __asm __volatile ("xorps %xmm0, %xmm0"); + + signal(SIGILL, oldHandler); + return result; +#endif +} +#endif + +static bool IsP4() +{ + word32 cpuid[4]; + + CpuId(0, cpuid); + mySTL::swap(cpuid[2], cpuid[3]); + if (memcmp(cpuid+1, "GenuineIntel", 12) != 0) + return false; + + CpuId(1, cpuid); + return ((cpuid[0] >> 8) & 0xf) == 0xf; +} + +// ************** Pentium/P4 optimizations *************** + +class PentiumOptimized : public Portable +{ +public: + static word TAOCRYPT_CDECL Add(word *C, const word *A, const word *B, + unsigned int N); + static word TAOCRYPT_CDECL Subtract(word *C, const word *A, const word *B, + unsigned int N); + static void TAOCRYPT_CDECL Multiply4(word *C, const word *A, + const word *B); + static void TAOCRYPT_CDECL Multiply8(word *C, const word *A, + const word *B); + static void TAOCRYPT_CDECL Multiply8Bottom(word *C, const word *A, + const word *B); +}; + +class P4Optimized +{ +public: + static word TAOCRYPT_CDECL Add(word *C, const word *A, const word *B, + unsigned int N); + static word TAOCRYPT_CDECL Subtract(word *C, const word *A, const word *B, + unsigned int N); +#ifdef SSE2_INTRINSICS_AVAILABLE + static void TAOCRYPT_CDECL Multiply4(word *C, const word *A, + const word *B); + static void TAOCRYPT_CDECL Multiply8(word *C, const word *A, + const word *B); + static void TAOCRYPT_CDECL Multiply8Bottom(word *C, const word *A, + const word *B); +#endif +}; + +typedef word (TAOCRYPT_CDECL * PAddSub)(word *C, const word *A, const word *B, + unsigned int N); +typedef void (TAOCRYPT_CDECL * PMul)(word *C, const word *A, const word *B); + +static PAddSub s_pAdd, s_pSub; +#ifdef SSE2_INTRINSICS_AVAILABLE +static PMul s_pMul4, s_pMul8, s_pMul8B; +#endif + +static void SetPentiumFunctionPointers() +{ + if (IsP4()) + { + s_pAdd = &P4Optimized::Add; + s_pSub = &P4Optimized::Subtract; + } + else + { + s_pAdd = &PentiumOptimized::Add; + s_pSub = &PentiumOptimized::Subtract; + } + +#ifdef SSE2_INTRINSICS_AVAILABLE + if (HasSSE2()) + { + s_pMul4 = &P4Optimized::Multiply4; + s_pMul8 = &P4Optimized::Multiply8; + s_pMul8B = &P4Optimized::Multiply8Bottom; + } + else + { + s_pMul4 = &PentiumOptimized::Multiply4; + s_pMul8 = &PentiumOptimized::Multiply8; + s_pMul8B = &PentiumOptimized::Multiply8Bottom; + } +#endif +} + +static const char s_RunAtStartupSetPentiumFunctionPointers = + (SetPentiumFunctionPointers(), 0); + +void DisableSSE2() +{ + s_sse2Enabled = false; + SetPentiumFunctionPointers(); +} + +class LowLevel : public PentiumOptimized +{ +public: + inline static word Add(word *C, const word *A, const word *B, + unsigned int N) + {return s_pAdd(C, A, B, N);} + inline static word Subtract(word *C, const word *A, const word *B, + unsigned int N) + {return s_pSub(C, A, B, N);} + inline static void Square4(word *R, const word *A) + {Multiply4(R, A, A);} +#ifdef SSE2_INTRINSICS_AVAILABLE + inline static void Multiply4(word *C, const word *A, const word *B) + {s_pMul4(C, A, B);} + inline static void Multiply8(word *C, const word *A, const word *B) + {s_pMul8(C, A, B);} + inline static void Multiply8Bottom(word *C, const word *A, const word *B) + {s_pMul8B(C, A, B);} +#endif +}; + +// use some tricks to share assembly code between MSVC and GCC +#ifdef _MSC_VER + #define TAOCRYPT_NAKED __declspec(naked) + #define AS1(x) __asm x + #define AS2(x, y) __asm x, y + #define AddPrologue \ + __asm push ebp \ + __asm push ebx \ + __asm push esi \ + __asm push edi \ + __asm mov ecx, [esp+20] \ + __asm mov edx, [esp+24] \ + __asm mov ebx, [esp+28] \ + __asm mov esi, [esp+32] + #define AddEpilogue \ + __asm pop edi \ + __asm pop esi \ + __asm pop ebx \ + __asm pop ebp \ + __asm ret + #define MulPrologue \ + __asm push ebp \ + __asm push ebx \ + __asm push esi \ + __asm push edi \ + __asm mov ecx, [esp+28] \ + __asm mov esi, [esp+24] \ + __asm push [esp+20] + #define MulEpilogue \ + __asm add esp, 4 \ + __asm pop edi \ + __asm pop esi \ + __asm pop ebx \ + __asm pop ebp \ + __asm ret +#else + #define TAOCRYPT_NAKED + #define AS1(x) #x ";" + #define AS2(x, y) #x ", " #y ";" + #define AddPrologue \ + __asm__ __volatile__ \ + ( \ + "push %%ebx;" /* save this manually, in case of -fPIC */ \ + "mov %2, %%ebx;" \ + ".intel_syntax noprefix;" \ + "push ebp;" + #define AddEpilogue \ + "pop ebp;" \ + ".att_syntax prefix;" \ + "pop %%ebx;" \ + : \ + : "c" (C), "d" (A), "m" (B), "S" (N) \ + : "%edi", "memory", "cc" \ + ); + #define MulPrologue \ + __asm__ __volatile__ \ + ( \ + "push %%ebx;" /* save this manually, in case of -fPIC */ \ + "push %%ebp;" \ + "push %0;" \ + ".intel_syntax noprefix;" + #define MulEpilogue \ + "add esp, 4;" \ + "pop ebp;" \ + "pop ebx;" \ + ".att_syntax prefix;" \ + : \ + : "rm" (Z), "S" (X), "c" (Y) \ + : "%eax", "%edx", "%edi", "memory", "cc" \ + ); +#endif + +TAOCRYPT_NAKED word PentiumOptimized::Add(word *C, const word *A, + const word *B, unsigned int N) +{ + AddPrologue + + // now: ebx = B, ecx = C, edx = A, esi = N + AS2( sub ecx, edx) // hold the distance between C & A so we + // can add this to A to get C + AS2( xor eax, eax) // clear eax + + AS2( sub eax, esi) // eax is a negative index from end of B + AS2( lea ebx, [ebx+4*esi]) // ebx is end of B + + AS2( sar eax, 1) // unit of eax is now dwords; this also + // clears the carry flag + AS1( jz loopendAdd) // if no dwords then nothing to do + + AS1(loopstartAdd:) + AS2( mov esi,[edx]) // load lower word of A + AS2( mov ebp,[edx+4]) // load higher word of A + + AS2( mov edi,[ebx+8*eax]) // load lower word of B + AS2( lea edx,[edx+8]) // advance A and C + + AS2( adc esi,edi) // add lower words + AS2( mov edi,[ebx+8*eax+4]) // load higher word of B + + AS2( adc ebp,edi) // add higher words + AS1( inc eax) // advance B + + AS2( mov [edx+ecx-8],esi) // store lower word result + AS2( mov [edx+ecx-4],ebp) // store higher word result + + AS1( jnz loopstartAdd) // loop until eax overflows and becomes zero + + AS1(loopendAdd:) + AS2( adc eax, 0) // store carry into eax (return result register) + + AddEpilogue +} + +TAOCRYPT_NAKED word PentiumOptimized::Subtract(word *C, const word *A, + const word *B, unsigned int N) +{ + AddPrologue + + // now: ebx = B, ecx = C, edx = A, esi = N + AS2( sub ecx, edx) // hold the distance between C & A so we + // can add this to A to get C + AS2( xor eax, eax) // clear eax + + AS2( sub eax, esi) // eax is a negative index from end of B + AS2( lea ebx, [ebx+4*esi]) // ebx is end of B + + AS2( sar eax, 1) // unit of eax is now dwords; this also + // clears the carry flag + AS1( jz loopendSub) // if no dwords then nothing to do + + AS1(loopstartSub:) + AS2( mov esi,[edx]) // load lower word of A + AS2( mov ebp,[edx+4]) // load higher word of A + + AS2( mov edi,[ebx+8*eax]) // load lower word of B + AS2( lea edx,[edx+8]) // advance A and C + + AS2( sbb esi,edi) // subtract lower words + AS2( mov edi,[ebx+8*eax+4]) // load higher word of B + + AS2( sbb ebp,edi) // subtract higher words + AS1( inc eax) // advance B + + AS2( mov [edx+ecx-8],esi) // store lower word result + AS2( mov [edx+ecx-4],ebp) // store higher word result + + AS1( jnz loopstartSub) // loop until eax overflows and becomes zero + + AS1(loopendSub:) + AS2( adc eax, 0) // store carry into eax (return result register) + + AddEpilogue +} + +// On Pentium 4, the adc and sbb instructions are very expensive, so avoid them. + +TAOCRYPT_NAKED word P4Optimized::Add(word *C, const word *A, const word *B, + unsigned int N) +{ + AddPrologue + + // now: ebx = B, ecx = C, edx = A, esi = N + AS2( xor eax, eax) + AS1( neg esi) + AS1( jz loopendAddP4) // if no dwords then nothing to do + + AS2( mov edi, [edx]) + AS2( mov ebp, [ebx]) + AS1( jmp carry1AddP4) + + AS1(loopstartAddP4:) + AS2( mov edi, [edx+8]) + AS2( add ecx, 8) + AS2( add edx, 8) + AS2( mov ebp, [ebx]) + AS2( add edi, eax) + AS1( jc carry1AddP4) + AS2( xor eax, eax) + + AS1(carry1AddP4:) + AS2( add edi, ebp) + AS2( mov ebp, 1) + AS2( mov [ecx], edi) + AS2( mov edi, [edx+4]) + AS2( cmovc eax, ebp) + AS2( mov ebp, [ebx+4]) + AS2( add ebx, 8) + AS2( add edi, eax) + AS1( jc carry2AddP4) + AS2( xor eax, eax) + + AS1(carry2AddP4:) + AS2( add edi, ebp) + AS2( mov ebp, 1) + AS2( cmovc eax, ebp) + AS2( mov [ecx+4], edi) + AS2( add esi, 2) + AS1( jnz loopstartAddP4) + + AS1(loopendAddP4:) + + AddEpilogue +} + +TAOCRYPT_NAKED word P4Optimized::Subtract(word *C, const word *A, + const word *B, unsigned int N) +{ + AddPrologue + + // now: ebx = B, ecx = C, edx = A, esi = N + AS2( xor eax, eax) + AS1( neg esi) + AS1( jz loopendSubP4) // if no dwords then nothing to do + + AS2( mov edi, [edx]) + AS2( mov ebp, [ebx]) + AS1( jmp carry1SubP4) + + AS1(loopstartSubP4:) + AS2( mov edi, [edx+8]) + AS2( add edx, 8) + AS2( add ecx, 8) + AS2( mov ebp, [ebx]) + AS2( sub edi, eax) + AS1( jc carry1SubP4) + AS2( xor eax, eax) + + AS1(carry1SubP4:) + AS2( sub edi, ebp) + AS2( mov ebp, 1) + AS2( mov [ecx], edi) + AS2( mov edi, [edx+4]) + AS2( cmovc eax, ebp) + AS2( mov ebp, [ebx+4]) + AS2( add ebx, 8) + AS2( sub edi, eax) + AS1( jc carry2SubP4) + AS2( xor eax, eax) + + AS1(carry2SubP4:) + AS2( sub edi, ebp) + AS2( mov ebp, 1) + AS2( cmovc eax, ebp) + AS2( mov [ecx+4], edi) + AS2( add esi, 2) + AS1( jnz loopstartSubP4) + + AS1(loopendSubP4:) + + AddEpilogue +} + +// multiply assembly code originally contributed by Leonard Janke + +#define MulStartup \ + AS2(xor ebp, ebp) \ + AS2(xor edi, edi) \ + AS2(xor ebx, ebx) + +#define MulShiftCarry \ + AS2(mov ebp, edx) \ + AS2(mov edi, ebx) \ + AS2(xor ebx, ebx) + +#define MulAccumulateBottom(i,j) \ + AS2(mov eax, [ecx+4*j]) \ + AS2(imul eax, dword ptr [esi+4*i]) \ + AS2(add ebp, eax) + +#define MulAccumulate(i,j) \ + AS2(mov eax, [ecx+4*j]) \ + AS1(mul dword ptr [esi+4*i]) \ + AS2(add ebp, eax) \ + AS2(adc edi, edx) \ + AS2(adc bl, bh) + +#define MulStoreDigit(i) \ + AS2(mov edx, edi) \ + AS2(mov edi, [esp]) \ + AS2(mov [edi+4*i], ebp) + +#define MulLastDiagonal(digits) \ + AS2(mov eax, [ecx+4*(digits-1)]) \ + AS1(mul dword ptr [esi+4*(digits-1)]) \ + AS2(add ebp, eax) \ + AS2(adc edx, edi) \ + AS2(mov edi, [esp]) \ + AS2(mov [edi+4*(2*digits-2)], ebp) \ + AS2(mov [edi+4*(2*digits-1)], edx) + +TAOCRYPT_NAKED void PentiumOptimized::Multiply4(word* Z, const word* X, + const word* Y) +{ + MulPrologue + // now: [esp] = Z, esi = X, ecx = Y + MulStartup + MulAccumulate(0,0) + MulStoreDigit(0) + MulShiftCarry + + MulAccumulate(1,0) + MulAccumulate(0,1) + MulStoreDigit(1) + MulShiftCarry + + MulAccumulate(2,0) + MulAccumulate(1,1) + MulAccumulate(0,2) + MulStoreDigit(2) + MulShiftCarry + + MulAccumulate(3,0) + MulAccumulate(2,1) + MulAccumulate(1,2) + MulAccumulate(0,3) + MulStoreDigit(3) + MulShiftCarry + + MulAccumulate(3,1) + MulAccumulate(2,2) + MulAccumulate(1,3) + MulStoreDigit(4) + MulShiftCarry + + MulAccumulate(3,2) + MulAccumulate(2,3) + MulStoreDigit(5) + MulShiftCarry + + MulLastDiagonal(4) + MulEpilogue +} + +TAOCRYPT_NAKED void PentiumOptimized::Multiply8(word* Z, const word* X, + const word* Y) +{ + MulPrologue + // now: [esp] = Z, esi = X, ecx = Y + MulStartup + MulAccumulate(0,0) + MulStoreDigit(0) + MulShiftCarry + + MulAccumulate(1,0) + MulAccumulate(0,1) + MulStoreDigit(1) + MulShiftCarry + + MulAccumulate(2,0) + MulAccumulate(1,1) + MulAccumulate(0,2) + MulStoreDigit(2) + MulShiftCarry + + MulAccumulate(3,0) + MulAccumulate(2,1) + MulAccumulate(1,2) + MulAccumulate(0,3) + MulStoreDigit(3) + MulShiftCarry + + MulAccumulate(4,0) + MulAccumulate(3,1) + MulAccumulate(2,2) + MulAccumulate(1,3) + MulAccumulate(0,4) + MulStoreDigit(4) + MulShiftCarry + + MulAccumulate(5,0) + MulAccumulate(4,1) + MulAccumulate(3,2) + MulAccumulate(2,3) + MulAccumulate(1,4) + MulAccumulate(0,5) + MulStoreDigit(5) + MulShiftCarry + + MulAccumulate(6,0) + MulAccumulate(5,1) + MulAccumulate(4,2) + MulAccumulate(3,3) + MulAccumulate(2,4) + MulAccumulate(1,5) + MulAccumulate(0,6) + MulStoreDigit(6) + MulShiftCarry + + MulAccumulate(7,0) + MulAccumulate(6,1) + MulAccumulate(5,2) + MulAccumulate(4,3) + MulAccumulate(3,4) + MulAccumulate(2,5) + MulAccumulate(1,6) + MulAccumulate(0,7) + MulStoreDigit(7) + MulShiftCarry + + MulAccumulate(7,1) + MulAccumulate(6,2) + MulAccumulate(5,3) + MulAccumulate(4,4) + MulAccumulate(3,5) + MulAccumulate(2,6) + MulAccumulate(1,7) + MulStoreDigit(8) + MulShiftCarry + + MulAccumulate(7,2) + MulAccumulate(6,3) + MulAccumulate(5,4) + MulAccumulate(4,5) + MulAccumulate(3,6) + MulAccumulate(2,7) + MulStoreDigit(9) + MulShiftCarry + + MulAccumulate(7,3) + MulAccumulate(6,4) + MulAccumulate(5,5) + MulAccumulate(4,6) + MulAccumulate(3,7) + MulStoreDigit(10) + MulShiftCarry + + MulAccumulate(7,4) + MulAccumulate(6,5) + MulAccumulate(5,6) + MulAccumulate(4,7) + MulStoreDigit(11) + MulShiftCarry + + MulAccumulate(7,5) + MulAccumulate(6,6) + MulAccumulate(5,7) + MulStoreDigit(12) + MulShiftCarry + + MulAccumulate(7,6) + MulAccumulate(6,7) + MulStoreDigit(13) + MulShiftCarry + + MulLastDiagonal(8) + MulEpilogue +} + +TAOCRYPT_NAKED void PentiumOptimized::Multiply8Bottom(word* Z, const word* X, + const word* Y) +{ + MulPrologue + // now: [esp] = Z, esi = X, ecx = Y + MulStartup + MulAccumulate(0,0) + MulStoreDigit(0) + MulShiftCarry + + MulAccumulate(1,0) + MulAccumulate(0,1) + MulStoreDigit(1) + MulShiftCarry + + MulAccumulate(2,0) + MulAccumulate(1,1) + MulAccumulate(0,2) + MulStoreDigit(2) + MulShiftCarry + + MulAccumulate(3,0) + MulAccumulate(2,1) + MulAccumulate(1,2) + MulAccumulate(0,3) + MulStoreDigit(3) + MulShiftCarry + + MulAccumulate(4,0) + MulAccumulate(3,1) + MulAccumulate(2,2) + MulAccumulate(1,3) + MulAccumulate(0,4) + MulStoreDigit(4) + MulShiftCarry + + MulAccumulate(5,0) + MulAccumulate(4,1) + MulAccumulate(3,2) + MulAccumulate(2,3) + MulAccumulate(1,4) + MulAccumulate(0,5) + MulStoreDigit(5) + MulShiftCarry + + MulAccumulate(6,0) + MulAccumulate(5,1) + MulAccumulate(4,2) + MulAccumulate(3,3) + MulAccumulate(2,4) + MulAccumulate(1,5) + MulAccumulate(0,6) + MulStoreDigit(6) + MulShiftCarry + + MulAccumulateBottom(7,0) + MulAccumulateBottom(6,1) + MulAccumulateBottom(5,2) + MulAccumulateBottom(4,3) + MulAccumulateBottom(3,4) + MulAccumulateBottom(2,5) + MulAccumulateBottom(1,6) + MulAccumulateBottom(0,7) + MulStoreDigit(7) + MulEpilogue +} + +#undef AS1 +#undef AS2 + +#else // not x86 - no processor specific code at this layer + +typedef Portable LowLevel; + +#endif + +#ifdef SSE2_INTRINSICS_AVAILABLE + +#ifdef __GNUC__ +#define TAOCRYPT_FASTCALL +#else +#define TAOCRYPT_FASTCALL __fastcall +#endif + +static void TAOCRYPT_FASTCALL P4_Mul(__m128i *C, const __m128i *A, + const __m128i *B) +{ + __m128i a3210 = _mm_load_si128(A); + __m128i b3210 = _mm_load_si128(B); + + __m128i sum; + + __m128i z = _mm_setzero_si128(); + __m128i a2b2_a0b0 = _mm_mul_epu32(a3210, b3210); + C[0] = a2b2_a0b0; + + __m128i a3120 = _mm_shuffle_epi32(a3210, _MM_SHUFFLE(3, 1, 2, 0)); + __m128i b3021 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(3, 0, 2, 1)); + __m128i a1b0_a0b1 = _mm_mul_epu32(a3120, b3021); + __m128i a1b0 = _mm_unpackhi_epi32(a1b0_a0b1, z); + __m128i a0b1 = _mm_unpacklo_epi32(a1b0_a0b1, z); + C[1] = _mm_add_epi64(a1b0, a0b1); + + __m128i a31 = _mm_srli_epi64(a3210, 32); + __m128i b31 = _mm_srli_epi64(b3210, 32); + __m128i a3b3_a1b1 = _mm_mul_epu32(a31, b31); + C[6] = a3b3_a1b1; + + __m128i a1b1 = _mm_unpacklo_epi32(a3b3_a1b1, z); + __m128i b3012 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(3, 0, 1, 2)); + __m128i a2b0_a0b2 = _mm_mul_epu32(a3210, b3012); + __m128i a0b2 = _mm_unpacklo_epi32(a2b0_a0b2, z); + __m128i a2b0 = _mm_unpackhi_epi32(a2b0_a0b2, z); + sum = _mm_add_epi64(a1b1, a0b2); + C[2] = _mm_add_epi64(sum, a2b0); + + __m128i a2301 = _mm_shuffle_epi32(a3210, _MM_SHUFFLE(2, 3, 0, 1)); + __m128i b2103 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(2, 1, 0, 3)); + __m128i a3b0_a1b2 = _mm_mul_epu32(a2301, b3012); + __m128i a2b1_a0b3 = _mm_mul_epu32(a3210, b2103); + __m128i a3b0 = _mm_unpackhi_epi32(a3b0_a1b2, z); + __m128i a1b2 = _mm_unpacklo_epi32(a3b0_a1b2, z); + __m128i a2b1 = _mm_unpackhi_epi32(a2b1_a0b3, z); + __m128i a0b3 = _mm_unpacklo_epi32(a2b1_a0b3, z); + __m128i sum1 = _mm_add_epi64(a3b0, a1b2); + sum = _mm_add_epi64(a2b1, a0b3); + C[3] = _mm_add_epi64(sum, sum1); + + __m128i a3b1_a1b3 = _mm_mul_epu32(a2301, b2103); + __m128i a2b2 = _mm_unpackhi_epi32(a2b2_a0b0, z); + __m128i a3b1 = _mm_unpackhi_epi32(a3b1_a1b3, z); + __m128i a1b3 = _mm_unpacklo_epi32(a3b1_a1b3, z); + sum = _mm_add_epi64(a2b2, a3b1); + C[4] = _mm_add_epi64(sum, a1b3); + + __m128i a1302 = _mm_shuffle_epi32(a3210, _MM_SHUFFLE(1, 3, 0, 2)); + __m128i b1203 = _mm_shuffle_epi32(b3210, _MM_SHUFFLE(1, 2, 0, 3)); + __m128i a3b2_a2b3 = _mm_mul_epu32(a1302, b1203); + __m128i a3b2 = _mm_unpackhi_epi32(a3b2_a2b3, z); + __m128i a2b3 = _mm_unpacklo_epi32(a3b2_a2b3, z); + C[5] = _mm_add_epi64(a3b2, a2b3); +} + +void P4Optimized::Multiply4(word *C, const word *A, const word *B) +{ + __m128i temp[7]; + const word *w = (word *)temp; + const __m64 *mw = (__m64 *)w; + + P4_Mul(temp, (__m128i *)A, (__m128i *)B); + + C[0] = w[0]; + + __m64 s1, s2; + + __m64 w1 = _mm_cvtsi32_si64(w[1]); + __m64 w4 = mw[2]; + __m64 w6 = mw[3]; + __m64 w8 = mw[4]; + __m64 w10 = mw[5]; + __m64 w12 = mw[6]; + __m64 w14 = mw[7]; + __m64 w16 = mw[8]; + __m64 w18 = mw[9]; + __m64 w20 = mw[10]; + __m64 w22 = mw[11]; + __m64 w26 = _mm_cvtsi32_si64(w[26]); + + s1 = _mm_add_si64(w1, w4); + C[1] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w6, w8); + s1 = _mm_add_si64(s1, s2); + C[2] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w10, w12); + s1 = _mm_add_si64(s1, s2); + C[3] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w14, w16); + s1 = _mm_add_si64(s1, s2); + C[4] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w18, w20); + s1 = _mm_add_si64(s1, s2); + C[5] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w22, w26); + s1 = _mm_add_si64(s1, s2); + C[6] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + C[7] = _mm_cvtsi64_si32(s1) + w[27]; + _mm_empty(); +} + +void P4Optimized::Multiply8(word *C, const word *A, const word *B) +{ + __m128i temp[28]; + const word *w = (word *)temp; + const __m64 *mw = (__m64 *)w; + const word *x = (word *)temp+7*4; + const __m64 *mx = (__m64 *)x; + const word *y = (word *)temp+7*4*2; + const __m64 *my = (__m64 *)y; + const word *z = (word *)temp+7*4*3; + const __m64 *mz = (__m64 *)z; + + P4_Mul(temp, (__m128i *)A, (__m128i *)B); + + P4_Mul(temp+7, (__m128i *)A+1, (__m128i *)B); + + P4_Mul(temp+14, (__m128i *)A, (__m128i *)B+1); + + P4_Mul(temp+21, (__m128i *)A+1, (__m128i *)B+1); + + C[0] = w[0]; + + __m64 s1, s2, s3, s4; + + __m64 w1 = _mm_cvtsi32_si64(w[1]); + __m64 w4 = mw[2]; + __m64 w6 = mw[3]; + __m64 w8 = mw[4]; + __m64 w10 = mw[5]; + __m64 w12 = mw[6]; + __m64 w14 = mw[7]; + __m64 w16 = mw[8]; + __m64 w18 = mw[9]; + __m64 w20 = mw[10]; + __m64 w22 = mw[11]; + __m64 w26 = _mm_cvtsi32_si64(w[26]); + __m64 w27 = _mm_cvtsi32_si64(w[27]); + + __m64 x0 = _mm_cvtsi32_si64(x[0]); + __m64 x1 = _mm_cvtsi32_si64(x[1]); + __m64 x4 = mx[2]; + __m64 x6 = mx[3]; + __m64 x8 = mx[4]; + __m64 x10 = mx[5]; + __m64 x12 = mx[6]; + __m64 x14 = mx[7]; + __m64 x16 = mx[8]; + __m64 x18 = mx[9]; + __m64 x20 = mx[10]; + __m64 x22 = mx[11]; + __m64 x26 = _mm_cvtsi32_si64(x[26]); + __m64 x27 = _mm_cvtsi32_si64(x[27]); + + __m64 y0 = _mm_cvtsi32_si64(y[0]); + __m64 y1 = _mm_cvtsi32_si64(y[1]); + __m64 y4 = my[2]; + __m64 y6 = my[3]; + __m64 y8 = my[4]; + __m64 y10 = my[5]; + __m64 y12 = my[6]; + __m64 y14 = my[7]; + __m64 y16 = my[8]; + __m64 y18 = my[9]; + __m64 y20 = my[10]; + __m64 y22 = my[11]; + __m64 y26 = _mm_cvtsi32_si64(y[26]); + __m64 y27 = _mm_cvtsi32_si64(y[27]); + + __m64 z0 = _mm_cvtsi32_si64(z[0]); + __m64 z1 = _mm_cvtsi32_si64(z[1]); + __m64 z4 = mz[2]; + __m64 z6 = mz[3]; + __m64 z8 = mz[4]; + __m64 z10 = mz[5]; + __m64 z12 = mz[6]; + __m64 z14 = mz[7]; + __m64 z16 = mz[8]; + __m64 z18 = mz[9]; + __m64 z20 = mz[10]; + __m64 z22 = mz[11]; + __m64 z26 = _mm_cvtsi32_si64(z[26]); + + s1 = _mm_add_si64(w1, w4); + C[1] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w6, w8); + s1 = _mm_add_si64(s1, s2); + C[2] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w10, w12); + s1 = _mm_add_si64(s1, s2); + C[3] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x0, y0); + s2 = _mm_add_si64(w14, w16); + s1 = _mm_add_si64(s1, s3); + s1 = _mm_add_si64(s1, s2); + C[4] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x1, y1); + s4 = _mm_add_si64(x4, y4); + s1 = _mm_add_si64(s1, w18); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w20); + s1 = _mm_add_si64(s1, s3); + C[5] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x6, y6); + s4 = _mm_add_si64(x8, y8); + s1 = _mm_add_si64(s1, w22); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w26); + s1 = _mm_add_si64(s1, s3); + C[6] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x10, y10); + s4 = _mm_add_si64(x12, y12); + s1 = _mm_add_si64(s1, w27); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, s3); + C[7] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x14, y14); + s4 = _mm_add_si64(x16, y16); + s1 = _mm_add_si64(s1, z0); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, s3); + C[8] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x18, y18); + s4 = _mm_add_si64(x20, y20); + s1 = _mm_add_si64(s1, z1); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, z4); + s1 = _mm_add_si64(s1, s3); + C[9] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x22, y22); + s4 = _mm_add_si64(x26, y26); + s1 = _mm_add_si64(s1, z6); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, z8); + s1 = _mm_add_si64(s1, s3); + C[10] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x27, y27); + s1 = _mm_add_si64(s1, z10); + s1 = _mm_add_si64(s1, z12); + s1 = _mm_add_si64(s1, s3); + C[11] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(z14, z16); + s1 = _mm_add_si64(s1, s3); + C[12] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(z18, z20); + s1 = _mm_add_si64(s1, s3); + C[13] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(z22, z26); + s1 = _mm_add_si64(s1, s3); + C[14] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + C[15] = z[27] + _mm_cvtsi64_si32(s1); + _mm_empty(); +} + +void P4Optimized::Multiply8Bottom(word *C, const word *A, const word *B) +{ + __m128i temp[21]; + const word *w = (word *)temp; + const __m64 *mw = (__m64 *)w; + const word *x = (word *)temp+7*4; + const __m64 *mx = (__m64 *)x; + const word *y = (word *)temp+7*4*2; + const __m64 *my = (__m64 *)y; + + P4_Mul(temp, (__m128i *)A, (__m128i *)B); + + P4_Mul(temp+7, (__m128i *)A+1, (__m128i *)B); + + P4_Mul(temp+14, (__m128i *)A, (__m128i *)B+1); + + C[0] = w[0]; + + __m64 s1, s2, s3, s4; + + __m64 w1 = _mm_cvtsi32_si64(w[1]); + __m64 w4 = mw[2]; + __m64 w6 = mw[3]; + __m64 w8 = mw[4]; + __m64 w10 = mw[5]; + __m64 w12 = mw[6]; + __m64 w14 = mw[7]; + __m64 w16 = mw[8]; + __m64 w18 = mw[9]; + __m64 w20 = mw[10]; + __m64 w22 = mw[11]; + __m64 w26 = _mm_cvtsi32_si64(w[26]); + + __m64 x0 = _mm_cvtsi32_si64(x[0]); + __m64 x1 = _mm_cvtsi32_si64(x[1]); + __m64 x4 = mx[2]; + __m64 x6 = mx[3]; + __m64 x8 = mx[4]; + + __m64 y0 = _mm_cvtsi32_si64(y[0]); + __m64 y1 = _mm_cvtsi32_si64(y[1]); + __m64 y4 = my[2]; + __m64 y6 = my[3]; + __m64 y8 = my[4]; + + s1 = _mm_add_si64(w1, w4); + C[1] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w6, w8); + s1 = _mm_add_si64(s1, s2); + C[2] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s2 = _mm_add_si64(w10, w12); + s1 = _mm_add_si64(s1, s2); + C[3] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x0, y0); + s2 = _mm_add_si64(w14, w16); + s1 = _mm_add_si64(s1, s3); + s1 = _mm_add_si64(s1, s2); + C[4] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x1, y1); + s4 = _mm_add_si64(x4, y4); + s1 = _mm_add_si64(s1, w18); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w20); + s1 = _mm_add_si64(s1, s3); + C[5] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + s3 = _mm_add_si64(x6, y6); + s4 = _mm_add_si64(x8, y8); + s1 = _mm_add_si64(s1, w22); + s3 = _mm_add_si64(s3, s4); + s1 = _mm_add_si64(s1, w26); + s1 = _mm_add_si64(s1, s3); + C[6] = _mm_cvtsi64_si32(s1); + s1 = _mm_srli_si64(s1, 32); + + C[7] = _mm_cvtsi64_si32(s1) + w[27] + x[10] + y[10] + x[12] + y[12]; + _mm_empty(); +} + +#endif // #ifdef SSE2_INTRINSICS_AVAILABLE + +// end optimized + +// ******************************************************** + +#define A0 A +#define A1 (A+N2) +#define B0 B +#define B1 (B+N2) + +#define T0 T +#define T1 (T+N2) +#define T2 (T+N) +#define T3 (T+N+N2) + +#define R0 R +#define R1 (R+N2) +#define R2 (R+N) +#define R3 (R+N+N2) + +//VC60 workaround: compiler bug triggered without the extra dummy parameters + +// R[2*N] - result = A*B +// T[2*N] - temporary work space +// A[N] --- multiplier +// B[N] --- multiplicant + + +void RecursiveMultiply(word *R, word *T, const word *A, const word *B, + unsigned int N) +{ + assert(N>=2 && N%2==0); + + if (LowLevel::MultiplyRecursionLimit() >= 8 && N==8) + LowLevel::Multiply8(R, A, B); + else if (LowLevel::MultiplyRecursionLimit() >= 4 && N==4) + LowLevel::Multiply4(R, A, B); + else if (N==2) + LowLevel::Multiply2(R, A, B); + else + { + const unsigned int N2 = N/2; + int carry; + + int aComp = Compare(A0, A1, N2); + int bComp = Compare(B0, B1, N2); + + switch (2*aComp + aComp + bComp) + { + case -4: + LowLevel::Subtract(R0, A1, A0, N2); + LowLevel::Subtract(R1, B0, B1, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + LowLevel::Subtract(T1, T1, R0, N2); + carry = -1; + break; + case -2: + LowLevel::Subtract(R0, A1, A0, N2); + LowLevel::Subtract(R1, B0, B1, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + carry = 0; + break; + case 2: + LowLevel::Subtract(R0, A0, A1, N2); + LowLevel::Subtract(R1, B1, B0, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + carry = 0; + break; + case 4: + LowLevel::Subtract(R0, A1, A0, N2); + LowLevel::Subtract(R1, B0, B1, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + LowLevel::Subtract(T1, T1, R1, N2); + carry = -1; + break; + default: + SetWords(T0, 0, N); + carry = 0; + } + + RecursiveMultiply(R0, T2, A0, B0, N2); + RecursiveMultiply(R2, T2, A1, B1, N2); + + // now T[01] holds (A1-A0)*(B0-B1),R[01] holds A0*B0, R[23] holds A1*B1 + + carry += LowLevel::Add(T0, T0, R0, N); + carry += LowLevel::Add(T0, T0, R2, N); + carry += LowLevel::Add(R1, R1, T0, N); + + assert (carry >= 0 && carry <= 2); + Increment(R3, N2, carry); + } +} + + +void RecursiveSquare(word *R, word *T, const word *A, unsigned int N) +{ + assert(N && N%2==0); + if (LowLevel::SquareRecursionLimit() >= 8 && N==8) + LowLevel::Square8(R, A); + if (LowLevel::SquareRecursionLimit() >= 4 && N==4) + LowLevel::Square4(R, A); + else if (N==2) + LowLevel::Square2(R, A); + else + { + const unsigned int N2 = N/2; + + RecursiveSquare(R0, T2, A0, N2); + RecursiveSquare(R2, T2, A1, N2); + RecursiveMultiply(T0, T2, A0, A1, N2); + + word carry = LowLevel::Add(R1, R1, T0, N); + carry += LowLevel::Add(R1, R1, T0, N); + Increment(R3, N2, carry); + } +} + + +// R[N] - bottom half of A*B +// T[N] - temporary work space +// A[N] - multiplier +// B[N] - multiplicant + + +void RecursiveMultiplyBottom(word *R, word *T, const word *A, const word *B, + unsigned int N) +{ + assert(N>=2 && N%2==0); + if (LowLevel::MultiplyBottomRecursionLimit() >= 8 && N==8) + LowLevel::Multiply8Bottom(R, A, B); + else if (LowLevel::MultiplyBottomRecursionLimit() >= 4 && N==4) + LowLevel::Multiply4Bottom(R, A, B); + else if (N==2) + LowLevel::Multiply2Bottom(R, A, B); + else + { + const unsigned int N2 = N/2; + + RecursiveMultiply(R, T, A0, B0, N2); + RecursiveMultiplyBottom(T0, T1, A1, B0, N2); + LowLevel::Add(R1, R1, T0, N2); + RecursiveMultiplyBottom(T0, T1, A0, B1, N2); + LowLevel::Add(R1, R1, T0, N2); + } +} + +/* +template <class P> +void RecursiveMultiplyTop(word *R, word *T, const word *L, const word *A, + const word *B, unsigned int N, const P *dummy=0) +{ + assert(N>=2 && N%2==0); + + if (N==4) + { + P::Multiply4(T, A, B); + ((dword *)R)[0] = ((dword *)T)[2]; + ((dword *)R)[1] = ((dword *)T)[3]; + } + else if (N==2) + { + P::Multiply2(T, A, B); + ((dword *)R)[0] = ((dword *)T)[1]; + } + else + { + const unsigned int N2 = N/2; + int carry; + + int aComp = Compare(A0, A1, N2); + int bComp = Compare(B0, B1, N2); + + switch (2*aComp + aComp + bComp) + { + case -4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R0, N2); + carry = -1; + break; + case -2: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + carry = 0; + break; + case 2: + P::Subtract(R0, A0, A1, N2); + P::Subtract(R1, B1, B0, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + carry = 0; + break; + case 4: + P::Subtract(R0, A1, A0, N2); + P::Subtract(R1, B0, B1, N2); + RecursiveMultiply<P>(T0, T2, R0, R1, N2); + P::Subtract(T1, T1, R1, N2); + carry = -1; + break; + default: + SetWords(T0, 0, N); + carry = 0; + } + + RecursiveMultiply<P>(T2, R0, A1, B1, N2); + + // now T[01] holds (A1-A0)*(B0-B1), T[23] holds A1*B1 + + word c2 = P::Subtract(R0, L+N2, L, N2); + c2 += P::Subtract(R0, R0, T0, N2); + word t = (Compare(R0, T2, N2) == -1); + + carry += t; + carry += Increment(R0, N2, c2+t); + carry += P::Add(R0, R0, T1, N2); + carry += P::Add(R0, R0, T3, N2); + assert (carry >= 0 && carry <= 2); + + CopyWords(R1, T3, N2); + Increment(R1, N2, carry); + } +} +*/ + + +void RecursiveMultiplyTop(word *R, word *T, const word *L, const word *A, + const word *B, unsigned int N) +{ + assert(N>=2 && N%2==0); + + if (N==4) + { + LowLevel::Multiply4(T, A, B); + memcpy(R, T+4, 4*WORD_SIZE); + } + else if (N==2) + { + LowLevel::Multiply2(T, A, B); + memcpy(R, T+2, 2*WORD_SIZE); + } + else + { + const unsigned int N2 = N/2; + int carry; + + int aComp = Compare(A0, A1, N2); + int bComp = Compare(B0, B1, N2); + + switch (2*aComp + aComp + bComp) + { + case -4: + LowLevel::Subtract(R0, A1, A0, N2); + LowLevel::Subtract(R1, B0, B1, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + LowLevel::Subtract(T1, T1, R0, N2); + carry = -1; + break; + case -2: + LowLevel::Subtract(R0, A1, A0, N2); + LowLevel::Subtract(R1, B0, B1, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + carry = 0; + break; + case 2: + LowLevel::Subtract(R0, A0, A1, N2); + LowLevel::Subtract(R1, B1, B0, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + carry = 0; + break; + case 4: + LowLevel::Subtract(R0, A1, A0, N2); + LowLevel::Subtract(R1, B0, B1, N2); + RecursiveMultiply(T0, T2, R0, R1, N2); + LowLevel::Subtract(T1, T1, R1, N2); + carry = -1; + break; + default: + SetWords(T0, 0, N); + carry = 0; + } + + RecursiveMultiply(T2, R0, A1, B1, N2); + + // now T[01] holds (A1-A0)*(B0-B1), T[23] holds A1*B1 + + word c2 = LowLevel::Subtract(R0, L+N2, L, N2); + c2 += LowLevel::Subtract(R0, R0, T0, N2); + word t = (Compare(R0, T2, N2) == -1); + + carry += t; + carry += Increment(R0, N2, c2+t); + carry += LowLevel::Add(R0, R0, T1, N2); + carry += LowLevel::Add(R0, R0, T3, N2); + assert (carry >= 0 && carry <= 2); + + CopyWords(R1, T3, N2); + Increment(R1, N2, carry); + } +} + + +inline word Add(word *C, const word *A, const word *B, unsigned int N) +{ + return LowLevel::Add(C, A, B, N); +} + +inline word Subtract(word *C, const word *A, const word *B, unsigned int N) +{ + return LowLevel::Subtract(C, A, B, N); +} + +inline void Multiply(word *R, word *T, const word *A, const word *B, + unsigned int N) +{ + RecursiveMultiply(R, T, A, B, N); +} + +inline void Square(word *R, word *T, const word *A, unsigned int N) +{ + RecursiveSquare(R, T, A, N); +} + + +void AsymmetricMultiply(word *R, word *T, const word *A, unsigned int NA, + const word *B, unsigned int NB) +{ + if (NA == NB) + { + if (A == B) + Square(R, T, A, NA); + else + Multiply(R, T, A, B, NA); + + return; + } + + if (NA > NB) + { + mySTL::swap(A, B); + mySTL::swap(NA, NB); + } + + assert(NB % NA == 0); + assert((NB/NA)%2 == 0); // NB is an even multiple of NA + + if (NA==2 && !A[1]) + { + switch (A[0]) + { + case 0: + SetWords(R, 0, NB+2); + return; + case 1: + CopyWords(R, B, NB); + R[NB] = R[NB+1] = 0; + return; + default: + R[NB] = LinearMultiply(R, B, A[0], NB); + R[NB+1] = 0; + return; + } + } + + Multiply(R, T, A, B, NA); + CopyWords(T+2*NA, R+NA, NA); + + unsigned i; + + for (i=2*NA; i<NB; i+=2*NA) + Multiply(T+NA+i, T, A, B+i, NA); + for (i=NA; i<NB; i+=2*NA) + Multiply(R+i, T, A, B+i, NA); + + if (Add(R+NA, R+NA, T+2*NA, NB-NA)) + Increment(R+NB, NA); +} + + +void PositiveMultiply(Integer& product, const Integer& a, const Integer& b) +{ + unsigned int aSize = RoundupSize(a.WordCount()); + unsigned int bSize = RoundupSize(b.WordCount()); + + product.reg_.CleanNew(RoundupSize(aSize + bSize)); + product.sign_ = Integer::POSITIVE; + + WordBlock workspace(aSize + bSize); + AsymmetricMultiply(product.reg_.get_buffer(), workspace.get_buffer(), + a.reg_.get_buffer(), aSize, b.reg_.get_buffer(), bSize); +} + +void Multiply(Integer &product, const Integer &a, const Integer &b) +{ + PositiveMultiply(product, a, b); + + if (a.NotNegative() != b.NotNegative()) + product.Negate(); +} + + +static inline unsigned int EvenWordCount(const word *X, unsigned int N) +{ + while (N && X[N-2]==0 && X[N-1]==0) + N-=2; + return N; +} + + +unsigned int AlmostInverse(word *R, word *T, const word *A, unsigned int NA, + const word *M, unsigned int N) +{ + assert(NA<=N && N && N%2==0); + + word *b = T; + word *c = T+N; + word *f = T+2*N; + word *g = T+3*N; + unsigned int bcLen=2, fgLen=EvenWordCount(M, N); + unsigned int k=0, s=0; + + SetWords(T, 0, 3*N); + b[0]=1; + CopyWords(f, A, NA); + CopyWords(g, M, N); + + while (1) + { + word t=f[0]; + while (!t) + { + if (EvenWordCount(f, fgLen)==0) + { + SetWords(R, 0, N); + return 0; + } + + ShiftWordsRightByWords(f, fgLen, 1); + if (c[bcLen-1]) bcLen+=2; + assert(bcLen <= N); + ShiftWordsLeftByWords(c, bcLen, 1); + k+=WORD_BITS; + t=f[0]; + } + + unsigned int i=0; + while (t%2 == 0) + { + t>>=1; + i++; + } + k+=i; + + if (t==1 && f[1]==0 && EvenWordCount(f, fgLen)==2) + { + if (s%2==0) + CopyWords(R, b, N); + else + Subtract(R, M, b, N); + return k; + } + + ShiftWordsRightByBits(f, fgLen, i); + t=ShiftWordsLeftByBits(c, bcLen, i); + if (t) + { + c[bcLen] = t; + bcLen+=2; + assert(bcLen <= N); + } + + if (f[fgLen-2]==0 && g[fgLen-2]==0 && f[fgLen-1]==0 && g[fgLen-1]==0) + fgLen-=2; + + if (Compare(f, g, fgLen)==-1) + { + mySTL::swap(f, g); + mySTL::swap(b, c); + s++; + } + + Subtract(f, f, g, fgLen); + + if (Add(b, b, c, bcLen)) + { + b[bcLen] = 1; + bcLen+=2; + assert(bcLen <= N); + } + } +} + +// R[N] - result = A/(2^k) mod M +// A[N] - input +// M[N] - modulus + +void DivideByPower2Mod(word *R, const word *A, unsigned int k, const word *M, + unsigned int N) +{ + CopyWords(R, A, N); + + while (k--) + { + if (R[0]%2==0) + ShiftWordsRightByBits(R, N, 1); + else + { + word carry = Add(R, R, M, N); + ShiftWordsRightByBits(R, N, 1); + R[N-1] += carry<<(WORD_BITS-1); + } + } +} + +// R[N] - result = A*(2^k) mod M +// A[N] - input +// M[N] - modulus + +void MultiplyByPower2Mod(word *R, const word *A, unsigned int k, const word *M, + unsigned int N) +{ + CopyWords(R, A, N); + + while (k--) + if (ShiftWordsLeftByBits(R, N, 1) || Compare(R, M, N)>=0) + Subtract(R, R, M, N); +} + + +// ********** end of integer needs + + +Integer::Integer() + : reg_(2), sign_(POSITIVE) +{ + reg_[0] = reg_[1] = 0; +} + + +Integer::Integer(const Integer& t) + : reg_(RoundupSize(t.WordCount())), sign_(t.sign_) +{ + CopyWords(reg_.get_buffer(), t.reg_.get_buffer(), reg_.size()); +} + + +Integer::Integer(signed long value) + : reg_(2) +{ + if (value >= 0) + sign_ = POSITIVE; + else + { + sign_ = NEGATIVE; + value = -value; + } + reg_[0] = word(value); + reg_[1] = word(SafeRightShift<WORD_BITS, unsigned long>(value)); +} + + +Integer::Integer(Sign s, word high, word low) + : reg_(2), sign_(s) +{ + reg_[0] = low; + reg_[1] = high; +} + + +Integer::Integer(word value, unsigned int length) + : reg_(RoundupSize(length)), sign_(POSITIVE) +{ + reg_[0] = value; + SetWords(reg_ + 1, 0, reg_.size() - 1); +} + + +Integer::Integer(const char *str) + : reg_(2), sign_(POSITIVE) +{ + *this = StringToInteger(str); +} + + +Integer::Integer(const wchar_t *str) + : reg_(2), sign_(POSITIVE) +{ + *this = StringToInteger(str); +} + + +Integer::Integer(const byte *encodedInteger, unsigned int byteCount, + Signedness s) +{ + Decode(encodedInteger, byteCount, s); +} + +class BadBER {}; + +// BER Decode Source +Integer::Integer(Source& source) + : reg_(2), sign_(POSITIVE) +{ + Decode(source); +} + +void Integer::Decode(Source& source) +{ + byte b = source.next(); + if (b != INTEGER) { + source.SetError(INTEGER_E); + return; + } + + word32 length = GetLength(source); + + if ( (b = source.next()) == 0x00) + length--; + else + source.prev(); + + unsigned int words = (length + WORD_SIZE - 1) / WORD_SIZE; + words = RoundupSize(words); + if (words > reg_.size()) reg_.CleanNew(words); + + for (int j = length; j > 0; j--) { + b = source.next(); + reg_ [(j-1) / WORD_SIZE] |= (word)b << ((j-1) % WORD_SIZE) * 8; + } +} + + +void Integer::Decode(const byte* input, unsigned int inputLen, Signedness s) +{ + unsigned int idx(0); + byte b = input[idx++]; + sign_ = ((s==SIGNED) && (b & 0x80)) ? NEGATIVE : POSITIVE; + + while (inputLen>0 && (sign_==POSITIVE ? b==0 : b==0xff)) + { + inputLen--; + b = input[idx++]; + } + + reg_.CleanNew(RoundupSize(BytesToWords(inputLen))); + + --idx; + for (unsigned int i=inputLen; i > 0; i--) + { + b = input[idx++]; + reg_[(i-1)/WORD_SIZE] |= (word)b << ((i-1)%WORD_SIZE)*8; + } + + if (sign_ == NEGATIVE) + { + for (unsigned i=inputLen; i<reg_.size()*WORD_SIZE; i++) + reg_[i/WORD_SIZE] |= (word)0xff << (i%WORD_SIZE)*8; + TwosComplement(reg_.get_buffer(), reg_.size()); + } +} + + +unsigned int Integer::Encode(byte* output, unsigned int outputLen, + Signedness signedness) const +{ + unsigned int idx(0); + if (signedness == UNSIGNED || NotNegative()) + { + for (unsigned int i=outputLen; i > 0; i--) + output[idx++] = GetByte(i-1); + } + else + { + // take two's complement of *this + Integer temp = Integer::Power2(8*max(ByteCount(), outputLen)) + *this; + for (unsigned i=0; i<outputLen; i++) + output[idx++] = temp.GetByte(outputLen-i-1); + } + return outputLen; +} + + +const Integer &Integer::Zero() +{ + static const Integer zero; + return zero; +} + + +const Integer &Integer::One() +{ + static const Integer one(1,2); + return one; +} + + +const Integer &Integer::Two() +{ + static const Integer two(2,2); + return two; +} + + +Integer::Integer(RandomNumberGenerator& rng, const Integer& min, + const Integer& max) +{ + Randomize(rng, min, max); +} + + +void Integer::Randomize(RandomNumberGenerator& rng, unsigned int nbits) +{ + const unsigned int nbytes = nbits/8 + 1; + ByteBlock buf(nbytes); + rng.GenerateBlock(buf.get_buffer(), nbytes); + if (nbytes) + buf[0] = (byte)Crop(buf[0], nbits % 8); + Decode(buf.get_buffer(), nbytes, UNSIGNED); +} + +void Integer::Randomize(RandomNumberGenerator& rng, const Integer& min, + const Integer& max) +{ + assert(min <= max); + + Integer range = max - min; + const unsigned int nbits = range.BitCount(); + + do + { + Randomize(rng, nbits); + } + while (*this > range); + + *this += min; +} + + +Integer Integer::Power2(unsigned int e) +{ + Integer r((word)0, BitsToWords(e + 1)); + r.SetBit(e); + return r; +} + + +void Integer::SetBit(unsigned int n, bool value) +{ + if (value) + { + reg_.CleanGrow(RoundupSize(BitsToWords(n + 1))); + reg_[n / WORD_BITS] |= (word(1) << (n % WORD_BITS)); + } + else + { + if (n / WORD_BITS < reg_.size()) + reg_[n / WORD_BITS] &= ~(word(1) << (n % WORD_BITS)); + } +} + + +void Integer::SetByte(unsigned int n, byte value) +{ + reg_.CleanGrow(RoundupSize(BytesToWords(n+1))); + reg_[n/WORD_SIZE] &= ~(word(0xff) << 8*(n%WORD_SIZE)); + reg_[n/WORD_SIZE] |= (word(value) << 8*(n%WORD_SIZE)); +} + + +void Integer::Negate() +{ + if (!!(*this)) // don't flip sign if *this==0 + sign_ = Sign(1 - sign_); +} + + +bool Integer::operator!() const +{ + return IsNegative() ? false : (reg_[0]==0 && WordCount()==0); +} + + +Integer& Integer::operator=(const Integer& t) +{ + if (this != &t) + { + reg_.New(RoundupSize(t.WordCount())); + CopyWords(reg_.get_buffer(), t.reg_.get_buffer(), reg_.size()); + sign_ = t.sign_; + } + return *this; +} + + +Integer& Integer::operator+=(const Integer& t) +{ + reg_.CleanGrow(t.reg_.size()); + if (NotNegative()) + { + if (t.NotNegative()) + PositiveAdd(*this, *this, t); + else + PositiveSubtract(*this, *this, t); + } + else + { + if (t.NotNegative()) + PositiveSubtract(*this, t, *this); + else + { + PositiveAdd(*this, *this, t); + sign_ = Integer::NEGATIVE; + } + } + return *this; +} + + +Integer Integer::operator-() const +{ + Integer result(*this); + result.Negate(); + return result; +} + + +Integer& Integer::operator-=(const Integer& t) +{ + reg_.CleanGrow(t.reg_.size()); + if (NotNegative()) + { + if (t.NotNegative()) + PositiveSubtract(*this, *this, t); + else + PositiveAdd(*this, *this, t); + } + else + { + if (t.NotNegative()) + { + PositiveAdd(*this, *this, t); + sign_ = Integer::NEGATIVE; + } + else + PositiveSubtract(*this, t, *this); + } + return *this; +} + + +Integer& Integer::operator++() +{ + if (NotNegative()) + { + if (Increment(reg_.get_buffer(), reg_.size())) + { + reg_.CleanGrow(2*reg_.size()); + reg_[reg_.size()/2]=1; + } + } + else + { + word borrow = Decrement(reg_.get_buffer(), reg_.size()); + assert(!borrow); + if (WordCount()==0) + *this = Zero(); + } + return *this; +} + +Integer& Integer::operator--() +{ + if (IsNegative()) + { + if (Increment(reg_.get_buffer(), reg_.size())) + { + reg_.CleanGrow(2*reg_.size()); + reg_[reg_.size()/2]=1; + } + } + else + { + if (Decrement(reg_.get_buffer(), reg_.size())) + *this = -One(); + } + return *this; +} + + +Integer& Integer::operator<<=(unsigned int n) +{ + const unsigned int wordCount = WordCount(); + const unsigned int shiftWords = n / WORD_BITS; + const unsigned int shiftBits = n % WORD_BITS; + + reg_.CleanGrow(RoundupSize(wordCount+BitsToWords(n))); + ShiftWordsLeftByWords(reg_.get_buffer(), wordCount + shiftWords, + shiftWords); + ShiftWordsLeftByBits(reg_+shiftWords, wordCount+BitsToWords(shiftBits), + shiftBits); + return *this; +} + +Integer& Integer::operator>>=(unsigned int n) +{ + const unsigned int wordCount = WordCount(); + const unsigned int shiftWords = n / WORD_BITS; + const unsigned int shiftBits = n % WORD_BITS; + + ShiftWordsRightByWords(reg_.get_buffer(), wordCount, shiftWords); + if (wordCount > shiftWords) + ShiftWordsRightByBits(reg_.get_buffer(), wordCount-shiftWords, + shiftBits); + if (IsNegative() && WordCount()==0) // avoid -0 + *this = Zero(); + return *this; +} + + +void PositiveAdd(Integer& sum, const Integer& a, const Integer& b) +{ + word carry; + if (a.reg_.size() == b.reg_.size()) + carry = Add(sum.reg_.get_buffer(), a.reg_.get_buffer(), + b.reg_.get_buffer(), a.reg_.size()); + else if (a.reg_.size() > b.reg_.size()) + { + carry = Add(sum.reg_.get_buffer(), a.reg_.get_buffer(), + b.reg_.get_buffer(), b.reg_.size()); + CopyWords(sum.reg_+b.reg_.size(), a.reg_+b.reg_.size(), + a.reg_.size()-b.reg_.size()); + carry = Increment(sum.reg_+b.reg_.size(), a.reg_.size()-b.reg_.size(), + carry); + } + else + { + carry = Add(sum.reg_.get_buffer(), a.reg_.get_buffer(), + b.reg_.get_buffer(), a.reg_.size()); + CopyWords(sum.reg_+a.reg_.size(), b.reg_+a.reg_.size(), + b.reg_.size()-a.reg_.size()); + carry = Increment(sum.reg_+a.reg_.size(), b.reg_.size()-a.reg_.size(), + carry); + } + + if (carry) + { + sum.reg_.CleanGrow(2*sum.reg_.size()); + sum.reg_[sum.reg_.size()/2] = 1; + } + sum.sign_ = Integer::POSITIVE; +} + +void PositiveSubtract(Integer &diff, const Integer &a, const Integer& b) +{ + unsigned aSize = a.WordCount(); + aSize += aSize%2; + unsigned bSize = b.WordCount(); + bSize += bSize%2; + + if (aSize == bSize) + { + if (Compare(a.reg_.get_buffer(), b.reg_.get_buffer(), aSize) >= 0) + { + Subtract(diff.reg_.get_buffer(), a.reg_.get_buffer(), + b.reg_.get_buffer(), aSize); + diff.sign_ = Integer::POSITIVE; + } + else + { + Subtract(diff.reg_.get_buffer(), b.reg_.get_buffer(), + a.reg_.get_buffer(), aSize); + diff.sign_ = Integer::NEGATIVE; + } + } + else if (aSize > bSize) + { + word borrow = Subtract(diff.reg_.get_buffer(), a.reg_.get_buffer(), + b.reg_.get_buffer(), bSize); + CopyWords(diff.reg_+bSize, a.reg_+bSize, aSize-bSize); + borrow = Decrement(diff.reg_+bSize, aSize-bSize, borrow); + assert(!borrow); + diff.sign_ = Integer::POSITIVE; + } + else + { + word borrow = Subtract(diff.reg_.get_buffer(), b.reg_.get_buffer(), + a.reg_.get_buffer(), aSize); + CopyWords(diff.reg_+aSize, b.reg_+aSize, bSize-aSize); + borrow = Decrement(diff.reg_+aSize, bSize-aSize, borrow); + assert(!borrow); + diff.sign_ = Integer::NEGATIVE; + } +} + + +unsigned int Integer::MinEncodedSize(Signedness signedness) const +{ + unsigned int outputLen = max(1U, ByteCount()); + if (signedness == UNSIGNED) + return outputLen; + if (NotNegative() && (GetByte(outputLen-1) & 0x80)) + outputLen++; + if (IsNegative() && *this < -Power2(outputLen*8-1)) + outputLen++; + return outputLen; +} + + +int Integer::Compare(const Integer& t) const +{ + if (NotNegative()) + { + if (t.NotNegative()) + return PositiveCompare(t); + else + return 1; + } + else + { + if (t.NotNegative()) + return -1; + else + return -PositiveCompare(t); + } +} + + +int Integer::PositiveCompare(const Integer& t) const +{ + unsigned size = WordCount(), tSize = t.WordCount(); + + if (size == tSize) + return TaoCrypt::Compare(reg_.get_buffer(), t.reg_.get_buffer(), size); + else + return size > tSize ? 1 : -1; +} + + +bool Integer::GetBit(unsigned int n) const +{ + if (n/WORD_BITS >= reg_.size()) + return 0; + else + return bool((reg_[n/WORD_BITS] >> (n % WORD_BITS)) & 1); +} + + +unsigned long Integer::GetBits(unsigned int i, unsigned int n) const +{ + assert(n <= sizeof(unsigned long)*8); + unsigned long v = 0; + for (unsigned int j=0; j<n; j++) + v |= GetBit(i+j) << j; + return v; +} + + +byte Integer::GetByte(unsigned int n) const +{ + if (n/WORD_SIZE >= reg_.size()) + return 0; + else + return byte(reg_[n/WORD_SIZE] >> ((n%WORD_SIZE)*8)); +} + + +unsigned int Integer::BitCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_BITS + BitPrecision(reg_[wordCount-1]); + else + return 0; +} + + +unsigned int Integer::ByteCount() const +{ + unsigned wordCount = WordCount(); + if (wordCount) + return (wordCount-1)*WORD_SIZE + BytePrecision(reg_[wordCount-1]); + else + return 0; +} + + +unsigned int Integer::WordCount() const +{ + return CountWords(reg_.get_buffer(), reg_.size()); +} + + +bool Integer::IsConvertableToLong() const +{ + if (ByteCount() > sizeof(long)) + return false; + + unsigned long value = reg_[0]; + value += SafeLeftShift<WORD_BITS, unsigned long>(reg_[1]); + + if (sign_ == POSITIVE) + return (signed long)value >= 0; + else + return -(signed long)value < 0; +} + + +signed long Integer::ConvertToLong() const +{ + assert(IsConvertableToLong()); + + unsigned long value = reg_[0]; + value += SafeLeftShift<WORD_BITS, unsigned long>(reg_[1]); + return sign_ == POSITIVE ? value : -(signed long)value; +} + + +void Integer::Swap(Integer& a) +{ + reg_.Swap(a.reg_); + mySTL::swap(sign_, a.sign_); +} + + +Integer Integer::Plus(const Integer& b) const +{ + Integer sum((word)0, max(reg_.size(), b.reg_.size())); + if (NotNegative()) + { + if (b.NotNegative()) + PositiveAdd(sum, *this, b); + else + PositiveSubtract(sum, *this, b); + } + else + { + if (b.NotNegative()) + PositiveSubtract(sum, b, *this); + else + { + PositiveAdd(sum, *this, b); + sum.sign_ = Integer::NEGATIVE; + } + } + return sum; +} + + +Integer Integer::Minus(const Integer& b) const +{ + Integer diff((word)0, max(reg_.size(), b.reg_.size())); + if (NotNegative()) + { + if (b.NotNegative()) + PositiveSubtract(diff, *this, b); + else + PositiveAdd(diff, *this, b); + } + else + { + if (b.NotNegative()) + { + PositiveAdd(diff, *this, b); + diff.sign_ = Integer::NEGATIVE; + } + else + PositiveSubtract(diff, b, *this); + } + return diff; +} + + +Integer Integer::Times(const Integer &b) const +{ + Integer product; + Multiply(product, *this, b); + return product; +} + + +#undef A0 +#undef A1 +#undef B0 +#undef B1 + +#undef T0 +#undef T1 +#undef T2 +#undef T3 + +#undef R0 +#undef R1 +#undef R2 +#undef R3 + +/* +// do a 3 word by 2 word divide, returns quotient and leaves remainder in A +static word SubatomicDivide(word *A, word B0, word B1) +{ + // assert {A[2],A[1]} < {B1,B0}, so quotient can fit in a word + assert(A[2] < B1 || (A[2]==B1 && A[1] < B0)); + + dword p, u; + word Q; + + // estimate the quotient: do a 2 word by 1 word divide + if (B1+1 == 0) + Q = A[2]; + else + Q = word(MAKE_DWORD(A[1], A[2]) / (B1+1)); + + // now subtract Q*B from A + p = (dword) B0*Q; + u = (dword) A[0] - LOW_WORD(p); + A[0] = LOW_WORD(u); + u = (dword) A[1] - HIGH_WORD(p) - (word)(0-HIGH_WORD(u)) - (dword)B1*Q; + A[1] = LOW_WORD(u); + A[2] += HIGH_WORD(u); + + // Q <= actual quotient, so fix it + while (A[2] || A[1] > B1 || (A[1]==B1 && A[0]>=B0)) + { + u = (dword) A[0] - B0; + A[0] = LOW_WORD(u); + u = (dword) A[1] - B1 - (word)(0-HIGH_WORD(u)); + A[1] = LOW_WORD(u); + A[2] += HIGH_WORD(u); + Q++; + assert(Q); // shouldn't overflow + } + + return Q; +} +*/ + + +/* +// do a 4 word by 2 word divide, returns 2 word quotient in Q0 and Q1 +static inline void AtomicDivide(word *Q, const word *A, const word *B) +{ + if (!B[0] && !B[1]) // if divisor is 0, we assume divisor==2**(2*WORD_BITS) + { + Q[0] = A[2]; + Q[1] = A[3]; + } + else + { + word T[4]; + T[0] = A[0]; T[1] = A[1]; T[2] = A[2]; T[3] = A[3]; + Q[1] = SubatomicDivide(T+1, B[0], B[1]); + Q[0] = SubatomicDivide(T, B[0], B[1]); + +#ifndef NDEBUG + // multiply quotient and divisor and add remainder + // make sure it equals dividend + assert(!T[2] && !T[3] && (T[1] < B[1] || (T[1]==B[1] && T[0]<B[0]))); + word P[4]; + LowLevel::Multiply2(P, Q, B); + Add(P, P, T, 4); + assert(memcmp(P, A, 4*WORD_SIZE)==0); +#endif + } +} +*/ + + +static inline void AtomicDivide(word *Q, const word *A, const word *B) +{ + word T[4]; + DWord q = DivideFourWordsByTwo<word, DWord>(T, DWord(A[0], A[1]), + DWord(A[2], A[3]), DWord(B[0], B[1])); + Q[0] = q.GetLowHalf(); + Q[1] = q.GetHighHalf(); + +#ifndef NDEBUG + if (B[0] || B[1]) + { + // multiply quotient and divisor and add remainder, make sure it + // equals dividend + assert(!T[2] && !T[3] && (T[1] < B[1] || (T[1]==B[1] && T[0]<B[0]))); + word P[4]; + Portable::Multiply2(P, Q, B); + Add(P, P, T, 4); + assert(memcmp(P, A, 4*WORD_SIZE)==0); + } +#endif +} + + +// for use by Divide(), corrects the underestimated quotient {Q1,Q0} +static void CorrectQuotientEstimate(word *R, word *T, word *Q, const word *B, + unsigned int N) +{ + assert(N && N%2==0); + + if (Q[1]) + { + T[N] = T[N+1] = 0; + unsigned i; + for (i=0; i<N; i+=4) + LowLevel::Multiply2(T+i, Q, B+i); + for (i=2; i<N; i+=4) + if (LowLevel::Multiply2Add(T+i, Q, B+i)) + T[i+5] += (++T[i+4]==0); + } + else + { + T[N] = LinearMultiply(T, B, Q[0], N); + T[N+1] = 0; + } + + word borrow = Subtract(R, R, T, N+2); + assert(!borrow && !R[N+1]); + + while (R[N] || Compare(R, B, N) >= 0) + { + R[N] -= Subtract(R, R, B, N); + Q[1] += (++Q[0]==0); + assert(Q[0] || Q[1]); // no overflow + } +} + +// R[NB] -------- remainder = A%B +// Q[NA-NB+2] --- quotient = A/B +// T[NA+2*NB+4] - temp work space +// A[NA] -------- dividend +// B[NB] -------- divisor + + +void Divide(word* R, word* Q, word* T, const word* A, unsigned int NA, + const word* B, unsigned int NB) +{ + assert(NA && NB && NA%2==0 && NB%2==0); + assert(B[NB-1] || B[NB-2]); + assert(NB <= NA); + + // set up temporary work space + word *const TA=T; + word *const TB=T+NA+2; + word *const TP=T+NA+2+NB; + + // copy B into TB and normalize it so that TB has highest bit set to 1 + unsigned shiftWords = (B[NB-1]==0); + TB[0] = TB[NB-1] = 0; + CopyWords(TB+shiftWords, B, NB-shiftWords); + unsigned shiftBits = WORD_BITS - BitPrecision(TB[NB-1]); + assert(shiftBits < WORD_BITS); + ShiftWordsLeftByBits(TB, NB, shiftBits); + + // copy A into TA and normalize it + TA[0] = TA[NA] = TA[NA+1] = 0; + CopyWords(TA+shiftWords, A, NA); + ShiftWordsLeftByBits(TA, NA+2, shiftBits); + + if (TA[NA+1]==0 && TA[NA] <= 1) + { + Q[NA-NB+1] = Q[NA-NB] = 0; + while (TA[NA] || Compare(TA+NA-NB, TB, NB) >= 0) + { + TA[NA] -= Subtract(TA+NA-NB, TA+NA-NB, TB, NB); + ++Q[NA-NB]; + } + } + else + { + NA+=2; + assert(Compare(TA+NA-NB, TB, NB) < 0); + } + + word BT[2]; + BT[0] = TB[NB-2] + 1; + BT[1] = TB[NB-1] + (BT[0]==0); + + // start reducing TA mod TB, 2 words at a time + for (unsigned i=NA-2; i>=NB; i-=2) + { + AtomicDivide(Q+i-NB, TA+i-2, BT); + CorrectQuotientEstimate(TA+i-NB, TP, Q+i-NB, TB, NB); + } + + // copy TA into R, and denormalize it + CopyWords(R, TA+shiftWords, NB); + ShiftWordsRightByBits(R, NB, shiftBits); +} + + +void PositiveDivide(Integer& remainder, Integer& quotient, + const Integer& a, const Integer& b) +{ + unsigned aSize = a.WordCount(); + unsigned bSize = b.WordCount(); + + assert(bSize); + + if (a.PositiveCompare(b) == -1) + { + remainder = a; + remainder.sign_ = Integer::POSITIVE; + quotient = Integer::Zero(); + return; + } + + aSize += aSize%2; // round up to next even number + bSize += bSize%2; + + remainder.reg_.CleanNew(RoundupSize(bSize)); + remainder.sign_ = Integer::POSITIVE; + quotient.reg_.CleanNew(RoundupSize(aSize-bSize+2)); + quotient.sign_ = Integer::POSITIVE; + + WordBlock T(aSize+2*bSize+4); + Divide(remainder.reg_.get_buffer(), quotient.reg_.get_buffer(), + T.get_buffer(), a.reg_.get_buffer(), aSize, b.reg_.get_buffer(), + bSize); +} + +void Integer::Divide(Integer &remainder, Integer "ient, + const Integer ÷nd, const Integer &divisor) +{ + PositiveDivide(remainder, quotient, dividend, divisor); + + if (dividend.IsNegative()) + { + quotient.Negate(); + if (remainder.NotZero()) + { + --quotient; + remainder = divisor.AbsoluteValue() - remainder; + } + } + + if (divisor.IsNegative()) + quotient.Negate(); +} + +void Integer::DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, + unsigned int n) +{ + q = a; + q >>= n; + + const unsigned int wordCount = BitsToWords(n); + if (wordCount <= a.WordCount()) + { + r.reg_.resize(RoundupSize(wordCount)); + CopyWords(r.reg_.get_buffer(), a.reg_.get_buffer(), wordCount); + SetWords(r.reg_+wordCount, 0, r.reg_.size()-wordCount); + if (n % WORD_BITS != 0) + r.reg_[wordCount-1] %= (1 << (n % WORD_BITS)); + } + else + { + r.reg_.resize(RoundupSize(a.WordCount())); + CopyWords(r.reg_.get_buffer(), a.reg_.get_buffer(), r.reg_.size()); + } + r.sign_ = POSITIVE; + + if (a.IsNegative() && r.NotZero()) + { + --q; + r = Power2(n) - r; + } +} + +Integer Integer::DividedBy(const Integer &b) const +{ + Integer remainder, quotient; + Integer::Divide(remainder, quotient, *this, b); + return quotient; +} + +Integer Integer::Modulo(const Integer &b) const +{ + Integer remainder, quotient; + Integer::Divide(remainder, quotient, *this, b); + return remainder; +} + +void Integer::Divide(word &remainder, Integer "ient, + const Integer ÷nd, word divisor) +{ + assert(divisor); + + if ((divisor & (divisor-1)) == 0) // divisor is a power of 2 + { + quotient = dividend >> (BitPrecision(divisor)-1); + remainder = dividend.reg_[0] & (divisor-1); + return; + } + + unsigned int i = dividend.WordCount(); + quotient.reg_.CleanNew(RoundupSize(i)); + remainder = 0; + while (i--) + { + quotient.reg_[i] = DWord(dividend.reg_[i], remainder) / divisor; + remainder = DWord(dividend.reg_[i], remainder) % divisor; + } + + if (dividend.NotNegative()) + quotient.sign_ = POSITIVE; + else + { + quotient.sign_ = NEGATIVE; + if (remainder) + { + --quotient; + remainder = divisor - remainder; + } + } +} + +Integer Integer::DividedBy(word b) const +{ + word remainder; + Integer quotient; + Integer::Divide(remainder, quotient, *this, b); + return quotient; +} + +word Integer::Modulo(word divisor) const +{ + assert(divisor); + + word remainder; + + if ((divisor & (divisor-1)) == 0) // divisor is a power of 2 + remainder = reg_[0] & (divisor-1); + else + { + unsigned int i = WordCount(); + + if (divisor <= 5) + { + DWord sum(0, 0); + while (i--) + sum += reg_[i]; + remainder = sum % divisor; + } + else + { + remainder = 0; + while (i--) + remainder = DWord(reg_[i], remainder) % divisor; + } + } + + if (IsNegative() && remainder) + remainder = divisor - remainder; + + return remainder; +} + + +Integer Integer::AbsoluteValue() const +{ + Integer result(*this); + result.sign_ = POSITIVE; + return result; +} + + +Integer Integer::SquareRoot() const +{ + if (!IsPositive()) + return Zero(); + + // overestimate square root + Integer x, y = Power2((BitCount()+1)/2); + assert(y*y >= *this); + + do + { + x = y; + y = (x + *this/x) >> 1; + } while (y<x); + + return x; +} + +bool Integer::IsSquare() const +{ + Integer r = SquareRoot(); + return *this == r.Squared(); +} + +bool Integer::IsUnit() const +{ + return (WordCount() == 1) && (reg_[0] == 1); +} + +Integer Integer::MultiplicativeInverse() const +{ + return IsUnit() ? *this : Zero(); +} + +Integer a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m) +{ + return x*y%m; +} + +Integer a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m) +{ + ModularArithmetic mr(m); + return mr.Exponentiate(x, e); +} + +Integer Integer::Gcd(const Integer &a, const Integer &b) +{ + return EuclideanDomainOf<Integer>().Gcd(a, b); +} + +Integer Integer::InverseMod(const Integer &m) const +{ + assert(m.NotNegative()); + + if (IsNegative() || *this>=m) + return (*this%m).InverseMod(m); + + if (m.IsEven()) + { + if (!m || IsEven()) + return Zero(); // no inverse + if (*this == One()) + return One(); + + Integer u = m.InverseMod(*this); + return !u ? Zero() : (m*(*this-u)+1)/(*this); + } + + WordBlock T(m.reg_.size() * 4); + Integer r((word)0, m.reg_.size()); + unsigned k = AlmostInverse(r.reg_.get_buffer(), T.get_buffer(), + reg_.get_buffer(), reg_.size(), + m.reg_.get_buffer(), m.reg_.size()); + DivideByPower2Mod(r.reg_.get_buffer(), r.reg_.get_buffer(), k, + m.reg_.get_buffer(), m.reg_.size()); + return r; +} + +word Integer::InverseMod(const word mod) const +{ + word g0 = mod, g1 = *this % mod; + word v0 = 0, v1 = 1; + word y; + + while (g1) + { + if (g1 == 1) + return v1; + y = g0 / g1; + g0 = g0 % g1; + v0 += y * v1; + + if (!g0) + break; + if (g0 == 1) + return mod-v0; + y = g1 / g0; + g1 = g1 % g0; + v1 += y * v0; + } + return 0; +} + +// ********* ModArith stuff + +const Integer& ModularArithmetic::Half(const Integer &a) const +{ + if (a.reg_.size()==modulus.reg_.size()) + { + TaoCrypt::DivideByPower2Mod(result.reg_.begin(), a.reg_.begin(), 1, + modulus.reg_.begin(), a.reg_.size()); + return result; + } + else + return result1 = (a.IsEven() ? (a >> 1) : ((a+modulus) >> 1)); +} + +const Integer& ModularArithmetic::Add(const Integer &a, const Integer &b) const +{ + if (a.reg_.size()==modulus.reg_.size() && + b.reg_.size()==modulus.reg_.size()) + { + if (TaoCrypt::Add(result.reg_.begin(), a.reg_.begin(), b.reg_.begin(), + a.reg_.size()) + || Compare(result.reg_.get_buffer(), modulus.reg_.get_buffer(), + a.reg_.size()) >= 0) + { + TaoCrypt::Subtract(result.reg_.begin(), result.reg_.begin(), + modulus.reg_.begin(), a.reg_.size()); + } + return result; + } + else + { + result1 = a+b; + if (result1 >= modulus) + result1 -= modulus; + return result1; + } +} + +Integer& ModularArithmetic::Accumulate(Integer &a, const Integer &b) const +{ + if (a.reg_.size()==modulus.reg_.size() && + b.reg_.size()==modulus.reg_.size()) + { + if (TaoCrypt::Add(a.reg_.get_buffer(), a.reg_.get_buffer(), + b.reg_.get_buffer(), a.reg_.size()) + || Compare(a.reg_.get_buffer(), modulus.reg_.get_buffer(), + a.reg_.size()) >= 0) + { + TaoCrypt::Subtract(a.reg_.get_buffer(), a.reg_.get_buffer(), + modulus.reg_.get_buffer(), a.reg_.size()); + } + } + else + { + a+=b; + if (a>=modulus) + a-=modulus; + } + + return a; +} + +const Integer& ModularArithmetic::Subtract(const Integer &a, + const Integer &b) const +{ + if (a.reg_.size()==modulus.reg_.size() && + b.reg_.size()==modulus.reg_.size()) + { + if (TaoCrypt::Subtract(result.reg_.begin(), a.reg_.begin(), + b.reg_.begin(), a.reg_.size())) + TaoCrypt::Add(result.reg_.begin(), result.reg_.begin(), + modulus.reg_.begin(), a.reg_.size()); + return result; + } + else + { + result1 = a-b; + if (result1.IsNegative()) + result1 += modulus; + return result1; + } +} + +Integer& ModularArithmetic::Reduce(Integer &a, const Integer &b) const +{ + if (a.reg_.size()==modulus.reg_.size() && + b.reg_.size()==modulus.reg_.size()) + { + if (TaoCrypt::Subtract(a.reg_.get_buffer(), a.reg_.get_buffer(), + b.reg_.get_buffer(), a.reg_.size())) + TaoCrypt::Add(a.reg_.get_buffer(), a.reg_.get_buffer(), + modulus.reg_.get_buffer(), a.reg_.size()); + } + else + { + a-=b; + if (a.IsNegative()) + a+=modulus; + } + + return a; +} + +const Integer& ModularArithmetic::Inverse(const Integer &a) const +{ + if (!a) + return a; + + CopyWords(result.reg_.begin(), modulus.reg_.begin(), modulus.reg_.size()); + if (TaoCrypt::Subtract(result.reg_.begin(), result.reg_.begin(), + a.reg_.begin(), a.reg_.size())) + Decrement(result.reg_.begin()+a.reg_.size(), 1, + modulus.reg_.size()-a.reg_.size()); + + return result; +} + +Integer ModularArithmetic::CascadeExponentiate(const Integer &x, + const Integer &e1, const Integer &y, const Integer &e2) const +{ + if (modulus.IsOdd()) + { + MontgomeryRepresentation dr(modulus); + return dr.ConvertOut(dr.CascadeExponentiate(dr.ConvertIn(x), e1, + dr.ConvertIn(y), e2)); + } + else + return AbstractRing<Integer>::CascadeExponentiate(x, e1, y, e2); +} + +void ModularArithmetic::SimultaneousExponentiate(Integer *results, + const Integer &base, const Integer *exponents, + unsigned int exponentsCount) const +{ + if (modulus.IsOdd()) + { + MontgomeryRepresentation dr(modulus); + dr.SimultaneousExponentiate(results, dr.ConvertIn(base), exponents, + exponentsCount); + for (unsigned int i=0; i<exponentsCount; i++) + results[i] = dr.ConvertOut(results[i]); + } + else + AbstractRing<Integer>::SimultaneousExponentiate(results, base, + exponents, exponentsCount); +} + + +// ******************************************************** + +#define A0 A +#define A1 (A+N2) +#define B0 B +#define B1 (B+N2) + +#define T0 T +#define T1 (T+N2) +#define T2 (T+N) +#define T3 (T+N+N2) + +#define R0 R +#define R1 (R+N2) +#define R2 (R+N) +#define R3 (R+N+N2) + + +inline void MultiplyBottom(word *R, word *T, const word *A, const word *B, + unsigned int N) +{ + RecursiveMultiplyBottom(R, T, A, B, N); +} + +inline void MultiplyTop(word *R, word *T, const word *L, const word *A, + const word *B, unsigned int N) +{ + RecursiveMultiplyTop(R, T, L, A, B, N); +} + + +// R[N] --- result = X/(2**(WORD_BITS*N)) mod M +// T[3*N] - temporary work space +// X[2*N] - number to be reduced +// M[N] --- modulus +// U[N] --- multiplicative inverse of M mod 2**(WORD_BITS*N) + +void MontgomeryReduce(word *R, word *T, const word *X, const word *M, + const word *U, unsigned int N) +{ + MultiplyBottom(R, T, X, U, N); + MultiplyTop(T, T+N, X, R, M, N); + word borrow = Subtract(T, X+N, T, N); + // defend against timing attack by doing this Add even when not needed + word carry = Add(T+N, T, M, N); + assert(carry || !borrow); + CopyWords(R, T + (borrow ? N : 0), N); +} + +// R[N] ----- result = A inverse mod 2**(WORD_BITS*N) +// T[3*N/2] - temporary work space +// A[N] ----- an odd number as input + +void RecursiveInverseModPower2(word *R, word *T, const word *A, unsigned int N) +{ + if (N==2) + { + T[0] = AtomicInverseModPower2(A[0]); + T[1] = 0; + LowLevel::Multiply2Bottom(T+2, T, A); + TwosComplement(T+2, 2); + Increment(T+2, 2, 2); + LowLevel::Multiply2Bottom(R, T, T+2); + } + else + { + const unsigned int N2 = N/2; + RecursiveInverseModPower2(R0, T0, A0, N2); + T0[0] = 1; + SetWords(T0+1, 0, N2-1); + MultiplyTop(R1, T1, T0, R0, A0, N2); + MultiplyBottom(T0, T1, R0, A1, N2); + Add(T0, R1, T0, N2); + TwosComplement(T0, N2); + MultiplyBottom(R1, T1, R0, T0, N2); + } +} + + +#undef A0 +#undef A1 +#undef B0 +#undef B1 + +#undef T0 +#undef T1 +#undef T2 +#undef T3 + +#undef R0 +#undef R1 +#undef R2 +#undef R3 + + +// modulus must be odd +MontgomeryRepresentation::MontgomeryRepresentation(const Integer &m) + : ModularArithmetic(m), + u((word)0, modulus.reg_.size()), + workspace(5*modulus.reg_.size()) +{ + assert(modulus.IsOdd()); + RecursiveInverseModPower2(u.reg_.get_buffer(), workspace.get_buffer(), + modulus.reg_.get_buffer(), modulus.reg_.size()); +} + +const Integer& MontgomeryRepresentation::Multiply(const Integer &a, + const Integer &b) const +{ + word *const T = workspace.begin(); + word *const R = result.reg_.begin(); + const unsigned int N = modulus.reg_.size(); + assert(a.reg_.size()<=N && b.reg_.size()<=N); + + AsymmetricMultiply(T, T+2*N, a.reg_.get_buffer(), a.reg_.size(), + b.reg_.get_buffer(), b.reg_.size()); + SetWords(T+a.reg_.size()+b.reg_.size(),0, 2*N-a.reg_.size()-b.reg_.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg_.get_buffer(), + u.reg_.get_buffer(), N); + return result; +} + +const Integer& MontgomeryRepresentation::Square(const Integer &a) const +{ + word *const T = workspace.begin(); + word *const R = result.reg_.begin(); + const unsigned int N = modulus.reg_.size(); + assert(a.reg_.size()<=N); + + TaoCrypt::Square(T, T+2*N, a.reg_.get_buffer(), a.reg_.size()); + SetWords(T+2*a.reg_.size(), 0, 2*N-2*a.reg_.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg_.get_buffer(), + u.reg_.get_buffer(), N); + return result; +} + +Integer MontgomeryRepresentation::ConvertOut(const Integer &a) const +{ + word *const T = workspace.begin(); + word *const R = result.reg_.begin(); + const unsigned int N = modulus.reg_.size(); + assert(a.reg_.size()<=N); + + CopyWords(T, a.reg_.get_buffer(), a.reg_.size()); + SetWords(T+a.reg_.size(), 0, 2*N-a.reg_.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg_.get_buffer(), + u.reg_.get_buffer(), N); + return result; +} + +const Integer& MontgomeryRepresentation::MultiplicativeInverse( + const Integer &a) const +{ +// return (EuclideanMultiplicativeInverse(a, modulus)<< +// (2*WORD_BITS*modulus.reg_.size()))%modulus; + word *const T = workspace.begin(); + word *const R = result.reg_.begin(); + const unsigned int N = modulus.reg_.size(); + assert(a.reg_.size()<=N); + + CopyWords(T, a.reg_.get_buffer(), a.reg_.size()); + SetWords(T+a.reg_.size(), 0, 2*N-a.reg_.size()); + MontgomeryReduce(R, T+2*N, T, modulus.reg_.get_buffer(), + u.reg_.get_buffer(), N); + unsigned k = AlmostInverse(R, T, R, N, modulus.reg_.get_buffer(), N); + +// cout << "k=" << k << " N*32=" << 32*N << endl; + + if (k>N*WORD_BITS) + DivideByPower2Mod(R, R, k-N*WORD_BITS, modulus.reg_.get_buffer(), N); + else + MultiplyByPower2Mod(R, R, N*WORD_BITS-k, modulus.reg_.get_buffer(), N); + + return result; +} + + +// mod Root stuff +Integer ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, + const Integer &p, const Integer &q, const Integer &u) +{ + Integer p2 = ModularExponentiation((a % p), dp, p); + Integer q2 = ModularExponentiation((a % q), dq, q); + return CRT(p2, p, q2, q, u); +} + +Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, + const Integer &q, const Integer &u) +{ + // isn't operator overloading great? + return p * (u * (xq-xp) % q) + xp; +} + + + +} // namespace + +#ifdef __GNUC__ +template TaoCrypt::Integer TaoCrypt::StringToInteger<char>(char const*); +template TaoCrypt::Integer TaoCrypt::StringToInteger<wchar_t>(wchar_t const*); +template class TaoCrypt::EuclideanDomainOf<TaoCrypt::Integer>; +template class TaoCrypt::AbstractEuclideanDomain<TaoCrypt::Integer>; +template unsigned int TaoCrypt::DivideThreeWordsByTwo<unsigned int, TaoCrypt::DWord>(unsigned int*, unsigned int, unsigned int, TaoCrypt::DWord*); +#endif + + diff --git a/extra/yassl/taocrypt/src/md2.cpp b/extra/yassl/taocrypt/src/md2.cpp new file mode 100644 index 00000000000..16834b6bc89 --- /dev/null +++ b/extra/yassl/taocrypt/src/md2.cpp @@ -0,0 +1,128 @@ +/* md2.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* based on Wei Dai's md2.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "md2.hpp" +#include <string.h> + +namespace TaoCrypt { + + +MD2::MD2() + : X_(X_SIZE), C_(BLOCK_SIZE), buffer_(BLOCK_SIZE) +{ + Init(); +} + +void MD2::Init() +{ + memset(X_.get_buffer(), 0, X_SIZE); + memset(C_.get_buffer(), 0, BLOCK_SIZE); + memset(buffer_.get_buffer(), 0, BLOCK_SIZE); + count_ = 0; +} + + +void MD2::Update(const byte* data, word32 len) +{ + + static const byte S[256] = + { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 + }; + + while (len) { + word32 L = (PAD_SIZE - count_) < len ? (PAD_SIZE - count_) : len; + memcpy(buffer_.get_buffer() + count_, data, L); + count_ += L; + data += L; + len -= L; + + if (count_==PAD_SIZE) { + count_ = 0; + memcpy(X_.get_buffer() + PAD_SIZE, buffer_.get_buffer(), PAD_SIZE); + byte t = C_[15]; + + int i; + for(i = 0; i < PAD_SIZE; i++) { + X_[32 + i] = X_[PAD_SIZE + i] ^ X_[i]; + t = C_[i] ^= S[buffer_[i] ^ t]; + } + + t=0; + for(i = 0; i < 18; i++) { + for(int j = 0; j < X_SIZE; j += 8) { + t = X_[j+0] ^= S[t]; + t = X_[j+1] ^= S[t]; + t = X_[j+2] ^= S[t]; + t = X_[j+3] ^= S[t]; + t = X_[j+4] ^= S[t]; + t = X_[j+5] ^= S[t]; + t = X_[j+6] ^= S[t]; + t = X_[j+7] ^= S[t]; + } + t = (t + i) & 0xFF; + } + } + } +} + + +void MD2::Final(byte *hash) +{ + byte padding[BLOCK_SIZE]; + word32 padLen = PAD_SIZE - count_; + + for (word32 i = 0; i < padLen; i++) + padding[i] = static_cast<byte>(padLen); + + Update(padding, padLen); + Update(C_.get_buffer(), BLOCK_SIZE); + + memcpy(hash, X_.get_buffer(), DIGEST_SIZE); + + Init(); +} + + + + +} // namespace diff --git a/extra/yassl/taocrypt/src/md5.cpp b/extra/yassl/taocrypt/src/md5.cpp new file mode 100644 index 00000000000..b9777e93216 --- /dev/null +++ b/extra/yassl/taocrypt/src/md5.cpp @@ -0,0 +1,169 @@ +/* md5.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* based on Wei Dai's md5.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "md5.hpp" +#include "algorithm.hpp" // mySTL::swap + +namespace TaoCrypt { + +void MD5::Init() +{ + digest_[0] = 0x67452301L; + digest_[1] = 0xefcdab89L; + digest_[2] = 0x98badcfeL; + digest_[3] = 0x10325476L; + + buffLen_ = 0; + length_ = 0; +} + + +MD5::MD5(const MD5& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), + BLOCK_SIZE) +{ + buffLen_ = that.buffLen_; + length_ = that.length_; + + memcpy(digest_, that.digest_, DIGEST_SIZE); + memcpy(buffer_, that.buffer_, BLOCK_SIZE); +} + +MD5& MD5::operator= (const MD5& that) +{ + MD5 tmp(that); + Swap(tmp); + + return *this; +} + + +void MD5::Swap(MD5& other) +{ + mySTL::swap(buffer_, other.buffer_); + mySTL::swap(buffLen_, other.buffLen_); + mySTL::swap(digest_, other.digest_); + mySTL::swap(length_, other.length_); +} + + +void MD5::Transform() +{ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + w = rotlFixed(w + f(x, y, z) + data, s) + x + + // Copy context->state[] to working vars + word32 a = digest_[0]; + word32 b = digest_[1]; + word32 c = digest_[2]; + word32 d = digest_[3]; + + MD5STEP(F1, a, b, c, d, *(word32*)&buffer_[0*4] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, *(word32*)&buffer_[1*4] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, *(word32*)&buffer_[2*4] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, *(word32*)&buffer_[3*4] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, *(word32*)&buffer_[4*4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, *(word32*)&buffer_[5*4] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, *(word32*)&buffer_[6*4] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, *(word32*)&buffer_[7*4] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, *(word32*)&buffer_[8*4] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, *(word32*)&buffer_[9*4] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, *(word32*)&buffer_[10*4] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, *(word32*)&buffer_[11*4] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, *(word32*)&buffer_[12*4] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, *(word32*)&buffer_[13*4] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, *(word32*)&buffer_[14*4] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, *(word32*)&buffer_[15*4] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, *(word32*)&buffer_[1*4] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, *(word32*)&buffer_[6*4] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, *(word32*)&buffer_[11*4] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, *(word32*)&buffer_[0*4] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, *(word32*)&buffer_[5*4] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, *(word32*)&buffer_[10*4] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, *(word32*)&buffer_[15*4] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, *(word32*)&buffer_[4*4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, *(word32*)&buffer_[9*4] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, *(word32*)&buffer_[14*4] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, *(word32*)&buffer_[3*4] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, *(word32*)&buffer_[8*4] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, *(word32*)&buffer_[13*4] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, *(word32*)&buffer_[2*4] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, *(word32*)&buffer_[7*4] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, *(word32*)&buffer_[12*4] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, *(word32*)&buffer_[5*4] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, *(word32*)&buffer_[8*4] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, *(word32*)&buffer_[11*4] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, *(word32*)&buffer_[14*4] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, *(word32*)&buffer_[1*4] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, *(word32*)&buffer_[4*4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, *(word32*)&buffer_[7*4] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, *(word32*)&buffer_[10*4] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, *(word32*)&buffer_[13*4] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, *(word32*)&buffer_[0*4] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, *(word32*)&buffer_[3*4] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, *(word32*)&buffer_[6*4] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, *(word32*)&buffer_[9*4] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, *(word32*)&buffer_[12*4] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, *(word32*)&buffer_[15*4] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, *(word32*)&buffer_[2*4] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, *(word32*)&buffer_[0*4] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, *(word32*)&buffer_[7*4] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, *(word32*)&buffer_[14*4] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, *(word32*)&buffer_[5*4] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, *(word32*)&buffer_[12*4] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, *(word32*)&buffer_[3*4] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, *(word32*)&buffer_[10*4] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, *(word32*)&buffer_[1*4] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, *(word32*)&buffer_[8*4] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, *(word32*)&buffer_[15*4] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, *(word32*)&buffer_[6*4] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, *(word32*)&buffer_[13*4] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, *(word32*)&buffer_[4*4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, *(word32*)&buffer_[11*4] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, *(word32*)&buffer_[2*4] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, *(word32*)&buffer_[9*4] + 0xeb86d391, 21); + + // Add the working vars back into digest state[] + digest_[0] += a; + digest_[1] += b; + digest_[2] += c; + digest_[3] += d; + + // Wipe variables + a = b = c = d = 0; + + buffLen_ = 0; + length_ += 512; +} + +} // namespace + diff --git a/extra/yassl/taocrypt/src/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp new file mode 100644 index 00000000000..e4573abac3f --- /dev/null +++ b/extra/yassl/taocrypt/src/misc.cpp @@ -0,0 +1,132 @@ +/* misc.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's misc.cpp from CryptoPP */ + + +#include "runtime.hpp" +#include "misc.hpp" +#include <new> // for NewHandler + + +void* operator new(size_t sz, TaoCrypt::new_t) +{ + void* ptr = ::operator new(sz); + + if (!ptr) abort(); + + return ptr; +} + +void* operator new[](size_t sz, TaoCrypt::new_t tc) +{ +#if defined(_MSC_VER) && (_MSC_VER < 1300) + void* ptr = ::operator new(sz); // no ::operator new[] +#else + void* ptr = ::operator new[](sz); +#endif + + if (!ptr) abort(); + + return ptr; +} + + + +namespace TaoCrypt { + + +new_t tc; // for library new + + +inline void XorWords(word* r, const word* a, unsigned int n) +{ + for (unsigned int i=0; i<n; i++) + r[i] ^= a[i]; +} + + +void xorbuf(byte* buf, const byte* mask, unsigned int count) +{ + if (((size_t)buf | (size_t)mask | count) % WORD_SIZE == 0) + XorWords((word *)buf, (const word *)mask, count/WORD_SIZE); + else + { + for (unsigned int i=0; i<count; i++) + buf[i] ^= mask[i]; + } +} + + +unsigned int BytePrecision(unsigned long value) +{ + unsigned int i; + for (i=sizeof(value); i; --i) + if (value >> (i-1)*8) + break; + + return i; +} + + +unsigned int BitPrecision(unsigned long value) +{ + if (!value) + return 0; + + unsigned int l = 0, + h = 8 * sizeof(value); + + while (h-l > 1) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h; +} + + +unsigned long Crop(unsigned long value, unsigned int size) +{ + if (size < 8*sizeof(value)) + return (value & ((1L << size) - 1)); + else + return value; +} + + +#if !(defined(_MSC_VER) && (_MSC_VER < 1300)) +using std::new_handler; +using std::set_new_handler; +#endif + +void CallNewHandler() +{ + abort(); +} + + +} // namespace + diff --git a/extra/yassl/taocrypt/src/random.cpp b/extra/yassl/taocrypt/src/random.cpp new file mode 100644 index 00000000000..5c9e3b0f02a --- /dev/null +++ b/extra/yassl/taocrypt/src/random.cpp @@ -0,0 +1,131 @@ +/* random.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* random.cpp implements a crypto secure Random Number Generator using an OS + specific seed, switch to /dev/random for more security but may block +*/ + +#include "runtime.hpp" +#include "random.hpp" +#include "stdexcept.hpp" + +#if defined(WIN32) + #define _WIN32_WINNT 0x0400 + #include <windows.h> + #include <wincrypt.h> +#else + #include <errno.h> + #include <fcntl.h> + #include <unistd.h> +#endif // WIN32 + +namespace TaoCrypt { + + +// Get seed and key cipher +RandomNumberGenerator::RandomNumberGenerator() +{ + byte key[32]; + seed_.GenerateSeed(key, sizeof(key)); + cipher_.SetKey(key, sizeof(key)); +} + + +// place a generated block in output +void RandomNumberGenerator::GenerateBlock(byte* output, word32 sz) +{ + cipher_.Process(output, output, sz); +} + + +byte RandomNumberGenerator::GenerateByte() +{ + byte b; + GenerateBlock(&b, 1); + + return b; +} + + +#if defined(WIN32) + +OS_Seed::OS_Seed() +{ + if(!CryptAcquireContext(&handle_, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + error_.SetError(WINCRYPT_E); +} + + +OS_Seed::~OS_Seed() +{ + CryptReleaseContext(handle_, 0); +} + + +void OS_Seed::GenerateSeed(byte* output, word32 sz) +{ + if (!CryptGenRandom(handle_, sz, output)) + error_.SetError(CRYPTGEN_E); +} + + +#else // WIN32 + + +OS_Seed::OS_Seed() +{ + fd_ = open("/dev/urandom",O_RDONLY); + if (fd_ == -1) + error_.SetError(OPEN_RAN_E); +} + + +OS_Seed::~OS_Seed() +{ + close(fd_); +} + + +// may block +void OS_Seed::GenerateSeed(byte* output, word32 sz) +{ + while (sz) { + int len = read(fd_, output, sz); + if (len == -1) { + error_.SetError(READ_RAN_E); + return; + } + + sz -= len; + output += len; + + if (sz) + sleep(1); + } +} + +#endif // WIN32 + + + +} // namespace diff --git a/extra/yassl/taocrypt/src/ripemd.cpp b/extra/yassl/taocrypt/src/ripemd.cpp new file mode 100644 index 00000000000..53f573cac32 --- /dev/null +++ b/extra/yassl/taocrypt/src/ripemd.cpp @@ -0,0 +1,289 @@ +/* ripemd.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* based on Wei Dai's ripemd.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "ripemd.hpp" +#include "algorithm.hpp" // mySTL::swap + +namespace TaoCrypt { + +void RIPEMD160::Init() +{ + digest_[0] = 0x67452301L; + digest_[1] = 0xefcdab89L; + digest_[2] = 0x98badcfeL; + digest_[3] = 0x10325476L; + digest_[4] = 0xc3d2e1f0L; + + buffLen_ = 0; + length_ = 0; +} + + +RIPEMD160::RIPEMD160(const RIPEMD160& that) + : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE) +{ + buffLen_ = that.buffLen_; + length_ = that.length_; + + memcpy(digest_, that.digest_, DIGEST_SIZE); + memcpy(buffer_, that.buffer_, BLOCK_SIZE); +} + + +RIPEMD160& RIPEMD160::operator= (const RIPEMD160& that) +{ + RIPEMD160 tmp(that); + Swap(tmp); + + return *this; +} + + +void RIPEMD160::Swap(RIPEMD160& other) +{ + mySTL::swap(buffer_, other.buffer_); + mySTL::swap(buffLen_, other.buffLen_); + mySTL::swap(digest_, other.digest_); + mySTL::swap(length_, other.length_); +} + + +// for all +#define F(x, y, z) (x ^ y ^ z) +#define G(x, y, z) (z ^ (x & (y^z))) +#define H(x, y, z) (z ^ (x | ~y)) +#define I(x, y, z) (y ^ (z & (x^y))) +#define J(x, y, z) (x ^ (y | ~z)) + +#define k0 0 +#define k1 0x5a827999UL +#define k2 0x6ed9eba1UL +#define k3 0x8f1bbcdcUL +#define k4 0xa953fd4eUL +#define k5 0x50a28be6UL +#define k6 0x5c4dd124UL +#define k7 0x6d703ef3UL +#define k8 0x7a6d76e9UL +#define k9 0 + +// for 160 and 320 +#define Subround(f, a, b, c, d, e, x, s, k) \ + a += f(b, c, d) + x + k;\ + a = rotlFixed((word32)a, s) + e;\ + c = rotlFixed((word32)c, 10U) + + +void RIPEMD160::Transform() +{ + unsigned long a1, b1, c1, d1, e1, a2, b2, c2, d2, e2; + a1 = a2 = digest_[0]; + b1 = b2 = digest_[1]; + c1 = c2 = digest_[2]; + d1 = d2 = digest_[3]; + e1 = e2 = digest_[4]; + + Subround(F, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 0*4], 11, k0); + Subround(F, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 1*4], 14, k0); + Subround(F, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 2*4], 15, k0); + Subround(F, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 3*4], 12, k0); + Subround(F, b1, c1, d1, e1, a1, *(word32*)&buffer_[ 4*4], 5, k0); + Subround(F, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 5*4], 8, k0); + Subround(F, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 6*4], 7, k0); + Subround(F, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 7*4], 9, k0); + Subround(F, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 8*4], 11, k0); + Subround(F, b1, c1, d1, e1, a1, *(word32*)&buffer_[ 9*4], 13, k0); + Subround(F, a1, b1, c1, d1, e1, *(word32*)&buffer_[10*4], 14, k0); + Subround(F, e1, a1, b1, c1, d1, *(word32*)&buffer_[11*4], 15, k0); + Subround(F, d1, e1, a1, b1, c1, *(word32*)&buffer_[12*4], 6, k0); + Subround(F, c1, d1, e1, a1, b1, *(word32*)&buffer_[13*4], 7, k0); + Subround(F, b1, c1, d1, e1, a1, *(word32*)&buffer_[14*4], 9, k0); + Subround(F, a1, b1, c1, d1, e1, *(word32*)&buffer_[15*4], 8, k0); + + Subround(G, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 7*4], 7, k1); + Subround(G, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 4*4], 6, k1); + Subround(G, c1, d1, e1, a1, b1, *(word32*)&buffer_[13*4], 8, k1); + Subround(G, b1, c1, d1, e1, a1, *(word32*)&buffer_[ 1*4], 13, k1); + Subround(G, a1, b1, c1, d1, e1, *(word32*)&buffer_[10*4], 11, k1); + Subround(G, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 6*4], 9, k1); + Subround(G, d1, e1, a1, b1, c1, *(word32*)&buffer_[15*4], 7, k1); + Subround(G, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 3*4], 15, k1); + Subround(G, b1, c1, d1, e1, a1, *(word32*)&buffer_[12*4], 7, k1); + Subround(G, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 0*4], 12, k1); + Subround(G, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 9*4], 15, k1); + Subround(G, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 5*4], 9, k1); + Subround(G, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 2*4], 11, k1); + Subround(G, b1, c1, d1, e1, a1, *(word32*)&buffer_[14*4], 7, k1); + Subround(G, a1, b1, c1, d1, e1, *(word32*)&buffer_[11*4], 13, k1); + Subround(G, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 8*4], 12, k1); + + Subround(H, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 3*4], 11, k2); + Subround(H, c1, d1, e1, a1, b1, *(word32*)&buffer_[10*4], 13, k2); + Subround(H, b1, c1, d1, e1, a1, *(word32*)&buffer_[14*4], 6, k2); + Subround(H, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 4*4], 7, k2); + Subround(H, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 9*4], 14, k2); + Subround(H, d1, e1, a1, b1, c1, *(word32*)&buffer_[15*4], 9, k2); + Subround(H, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 8*4], 13, k2); + Subround(H, b1, c1, d1, e1, a1, *(word32*)&buffer_[ 1*4], 15, k2); + Subround(H, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 2*4], 14, k2); + Subround(H, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 7*4], 8, k2); + Subround(H, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 0*4], 13, k2); + Subround(H, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 6*4], 6, k2); + Subround(H, b1, c1, d1, e1, a1, *(word32*)&buffer_[13*4], 5, k2); + Subround(H, a1, b1, c1, d1, e1, *(word32*)&buffer_[11*4], 12, k2); + Subround(H, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 5*4], 7, k2); + Subround(H, d1, e1, a1, b1, c1, *(word32*)&buffer_[12*4], 5, k2); + + Subround(I, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 1*4], 11, k3); + Subround(I, b1, c1, d1, e1, a1, *(word32*)&buffer_[ 9*4], 12, k3); + Subround(I, a1, b1, c1, d1, e1, *(word32*)&buffer_[11*4], 14, k3); + Subround(I, e1, a1, b1, c1, d1, *(word32*)&buffer_[10*4], 15, k3); + Subround(I, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 0*4], 14, k3); + Subround(I, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 8*4], 15, k3); + Subround(I, b1, c1, d1, e1, a1, *(word32*)&buffer_[12*4], 9, k3); + Subround(I, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 4*4], 8, k3); + Subround(I, e1, a1, b1, c1, d1, *(word32*)&buffer_[13*4], 9, k3); + Subround(I, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 3*4], 14, k3); + Subround(I, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 7*4], 5, k3); + Subround(I, b1, c1, d1, e1, a1, *(word32*)&buffer_[15*4], 6, k3); + Subround(I, a1, b1, c1, d1, e1, *(word32*)&buffer_[14*4], 8, k3); + Subround(I, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 5*4], 6, k3); + Subround(I, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 6*4], 5, k3); + Subround(I, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 2*4], 12, k3); + + Subround(J, b1, c1, d1, e1, a1, *(word32*)&buffer_[ 4*4], 9, k4); + Subround(J, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 0*4], 15, k4); + Subround(J, e1, a1, b1, c1, d1, *(word32*)&buffer_[ 5*4], 5, k4); + Subround(J, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 9*4], 11, k4); + Subround(J, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 7*4], 6, k4); + Subround(J, b1, c1, d1, e1, a1, *(word32*)&buffer_[12*4], 8, k4); + Subround(J, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 2*4], 13, k4); + Subround(J, e1, a1, b1, c1, d1, *(word32*)&buffer_[10*4], 12, k4); + Subround(J, d1, e1, a1, b1, c1, *(word32*)&buffer_[14*4], 5, k4); + Subround(J, c1, d1, e1, a1, b1, *(word32*)&buffer_[ 1*4], 12, k4); + Subround(J, b1, c1, d1, e1, a1, *(word32*)&buffer_[ 3*4], 13, k4); + Subround(J, a1, b1, c1, d1, e1, *(word32*)&buffer_[ 8*4], 14, k4); + Subround(J, e1, a1, b1, c1, d1, *(word32*)&buffer_[11*4], 11, k4); + Subround(J, d1, e1, a1, b1, c1, *(word32*)&buffer_[ 6*4], 8, k4); + Subround(J, c1, d1, e1, a1, b1, *(word32*)&buffer_[15*4], 5, k4); + Subround(J, b1, c1, d1, e1, a1, *(word32*)&buffer_[13*4], 6, k4); + + Subround(J, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 5*4], 8, k5); + Subround(J, e2, a2, b2, c2, d2, *(word32*)&buffer_[14*4], 9, k5); + Subround(J, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 7*4], 9, k5); + Subround(J, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 0*4], 11, k5); + Subround(J, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 9*4], 13, k5); + Subround(J, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 2*4], 15, k5); + Subround(J, e2, a2, b2, c2, d2, *(word32*)&buffer_[11*4], 15, k5); + Subround(J, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 4*4], 5, k5); + Subround(J, c2, d2, e2, a2, b2, *(word32*)&buffer_[13*4], 7, k5); + Subround(J, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 6*4], 7, k5); + Subround(J, a2, b2, c2, d2, e2, *(word32*)&buffer_[15*4], 8, k5); + Subround(J, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 8*4], 11, k5); + Subround(J, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 1*4], 14, k5); + Subround(J, c2, d2, e2, a2, b2, *(word32*)&buffer_[10*4], 14, k5); + Subround(J, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 3*4], 12, k5); + Subround(J, a2, b2, c2, d2, e2, *(word32*)&buffer_[12*4], 6, k5); + + Subround(I, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 6*4], 9, k6); + Subround(I, d2, e2, a2, b2, c2, *(word32*)&buffer_[11*4], 13, k6); + Subround(I, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 3*4], 15, k6); + Subround(I, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 7*4], 7, k6); + Subround(I, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 0*4], 12, k6); + Subround(I, e2, a2, b2, c2, d2, *(word32*)&buffer_[13*4], 8, k6); + Subround(I, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 5*4], 9, k6); + Subround(I, c2, d2, e2, a2, b2, *(word32*)&buffer_[10*4], 11, k6); + Subround(I, b2, c2, d2, e2, a2, *(word32*)&buffer_[14*4], 7, k6); + Subround(I, a2, b2, c2, d2, e2, *(word32*)&buffer_[15*4], 7, k6); + Subround(I, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 8*4], 12, k6); + Subround(I, d2, e2, a2, b2, c2, *(word32*)&buffer_[12*4], 7, k6); + Subround(I, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 4*4], 6, k6); + Subround(I, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 9*4], 15, k6); + Subround(I, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 1*4], 13, k6); + Subround(I, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 2*4], 11, k6); + + Subround(H, d2, e2, a2, b2, c2, *(word32*)&buffer_[15*4], 9, k7); + Subround(H, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 5*4], 7, k7); + Subround(H, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 1*4], 15, k7); + Subround(H, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 3*4], 11, k7); + Subround(H, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 7*4], 8, k7); + Subround(H, d2, e2, a2, b2, c2, *(word32*)&buffer_[14*4], 6, k7); + Subround(H, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 6*4], 6, k7); + Subround(H, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 9*4], 14, k7); + Subround(H, a2, b2, c2, d2, e2, *(word32*)&buffer_[11*4], 12, k7); + Subround(H, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 8*4], 13, k7); + Subround(H, d2, e2, a2, b2, c2, *(word32*)&buffer_[12*4], 5, k7); + Subround(H, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 2*4], 14, k7); + Subround(H, b2, c2, d2, e2, a2, *(word32*)&buffer_[10*4], 13, k7); + Subround(H, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 0*4], 13, k7); + Subround(H, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 4*4], 7, k7); + Subround(H, d2, e2, a2, b2, c2, *(word32*)&buffer_[13*4], 5, k7); + + Subround(G, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 8*4], 15, k8); + Subround(G, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 6*4], 5, k8); + Subround(G, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 4*4], 8, k8); + Subround(G, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 1*4], 11, k8); + Subround(G, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 3*4], 14, k8); + Subround(G, c2, d2, e2, a2, b2, *(word32*)&buffer_[11*4], 14, k8); + Subround(G, b2, c2, d2, e2, a2, *(word32*)&buffer_[15*4], 6, k8); + Subround(G, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 0*4], 14, k8); + Subround(G, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 5*4], 6, k8); + Subround(G, d2, e2, a2, b2, c2, *(word32*)&buffer_[12*4], 9, k8); + Subround(G, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 2*4], 12, k8); + Subround(G, b2, c2, d2, e2, a2, *(word32*)&buffer_[13*4], 9, k8); + Subround(G, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 9*4], 12, k8); + Subround(G, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 7*4], 5, k8); + Subround(G, d2, e2, a2, b2, c2, *(word32*)&buffer_[10*4], 15, k8); + Subround(G, c2, d2, e2, a2, b2, *(word32*)&buffer_[14*4], 8, k8); + + Subround(F, b2, c2, d2, e2, a2, *(word32*)&buffer_[12*4], 8, k9); + Subround(F, a2, b2, c2, d2, e2, *(word32*)&buffer_[15*4], 5, k9); + Subround(F, e2, a2, b2, c2, d2, *(word32*)&buffer_[10*4], 12, k9); + Subround(F, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 4*4], 9, k9); + Subround(F, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 1*4], 12, k9); + Subround(F, b2, c2, d2, e2, a2, *(word32*)&buffer_[ 5*4], 5, k9); + Subround(F, a2, b2, c2, d2, e2, *(word32*)&buffer_[ 8*4], 14, k9); + Subround(F, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 7*4], 6, k9); + Subround(F, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 6*4], 8, k9); + Subround(F, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 2*4], 13, k9); + Subround(F, b2, c2, d2, e2, a2, *(word32*)&buffer_[13*4], 6, k9); + Subround(F, a2, b2, c2, d2, e2, *(word32*)&buffer_[14*4], 5, k9); + Subround(F, e2, a2, b2, c2, d2, *(word32*)&buffer_[ 0*4], 15, k9); + Subround(F, d2, e2, a2, b2, c2, *(word32*)&buffer_[ 3*4], 13, k9); + Subround(F, c2, d2, e2, a2, b2, *(word32*)&buffer_[ 9*4], 11, k9); + Subround(F, b2, c2, d2, e2, a2, *(word32*)&buffer_[11*4], 11, k9); + + c1 = digest_[1] + c1 + d2; + digest_[1] = digest_[2] + d1 + e2; + digest_[2] = digest_[3] + e1 + a2; + digest_[3] = digest_[4] + a1 + b2; + digest_[4] = digest_[0] + b1 + c2; + digest_[0] = c1; + + buffLen_ = 0; + length_ += 512; +} + + +} // namespace TaoCrypt diff --git a/extra/yassl/taocrypt/src/rsa.cpp b/extra/yassl/taocrypt/src/rsa.cpp new file mode 100644 index 00000000000..da8cd697a7c --- /dev/null +++ b/extra/yassl/taocrypt/src/rsa.cpp @@ -0,0 +1,234 @@ +/* rsa.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's rsa.cpp from CryptoPP */ + +#include "runtime.hpp" +#include "rsa.hpp" +#include "asn.hpp" +#include "modarith.hpp" +#include "stdexcept.hpp" + +#include "algebra.cpp" // for GCC 3.2 on aix ? + + +namespace TaoCrypt { + + +Integer RSA_PublicKey::ApplyFunction(const Integer& x) const +{ + return a_exp_b_mod_c(x, e_, n_); +} + + +RSA_PublicKey::RSA_PublicKey(Source& source) +{ + Initialize(source); +} + + +void RSA_PublicKey::Initialize(Source& source) +{ + RSA_Public_Decoder decoder(source); + decoder.Decode(*this); +} + + +Integer RSA_PrivateKey::CalculateInverse(RandomNumberGenerator& rng, + const Integer& x) const +{ + ModularArithmetic modn(n_); + + Integer r(rng, Integer::One(), n_ - Integer::One()); + Integer re = modn.Exponentiate(r, e_); + re = modn.Multiply(re, x); // blind + + // here we follow the notation of PKCS #1 and let u=q inverse mod p + // but in ModRoot, u=p inverse mod q, so we reverse the order of p and q + + Integer y = ModularRoot(re, dq_, dp_, q_, p_, u_); + y = modn.Divide(y, r); // unblind + assert(modn.Exponentiate(y, e_) == x); // check + + return y; +} + + +RSA_PrivateKey::RSA_PrivateKey(Source& source) +{ + Initialize(source); +} + + +void RSA_PrivateKey::Initialize(Source& source) +{ + RSA_Private_Decoder decoder(source); + decoder.Decode(*this); +} + + +void RSA_BlockType2::Pad(const byte *input, word32 inputLen, byte *pkcsBlock, + word32 pkcsBlockLen, RandomNumberGenerator& rng) const +{ + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + pkcsBlock[0] = 0; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + pkcsBlock[0] = 2; // block type 2 + + // pad with non-zero random bytes + word32 padLen = pkcsBlockLen - inputLen - 1; + rng.GenerateBlock(&pkcsBlock[1], padLen); + for (word32 i = 1; i < padLen; i++) + if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01; + + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator + memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); +} + +word32 RSA_BlockType2::UnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen, + byte *output) const +{ + bool invalid = false; + unsigned int maxOutputLen = SaturatingSubtract(pkcsBlockLen / 8, 10U); + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + invalid = (pkcsBlock[0] != 0) || invalid; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + // Require block type 2. + invalid = (pkcsBlock[0] != 2) || invalid; + + // skip past the padding until we find the separator + unsigned i=1; + while (i<pkcsBlockLen && pkcsBlock[i++]) { // null body + } + assert(i==pkcsBlockLen || pkcsBlock[i-1]==0); + + unsigned int outputLen = pkcsBlockLen - i; + invalid = (outputLen > maxOutputLen) || invalid; + + if (invalid) + return 0; + + memcpy (output, pkcsBlock+i, outputLen); + return outputLen; +} + + +void RSA_BlockType1::Pad(const byte* input, word32 inputLen, byte* pkcsBlock, + word32 pkcsBlockLen, RandomNumberGenerator&) const +{ + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + pkcsBlock[0] = 0; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + pkcsBlock[0] = 1; // block type 1 for SSL + + // pad with 0xff bytes + memset(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2); + + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; // separator + memcpy(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); +} + + +word32 RSA_BlockType1::UnPad(const byte* pkcsBlock, word32 pkcsBlockLen, + byte* output) const +{ + bool invalid = false; + unsigned int maxOutputLen = SaturatingSubtract(pkcsBlockLen / 8, 10U); + + // convert from bit length to byte length + if (pkcsBlockLen % 8 != 0) + { + invalid = (pkcsBlock[0] != 0) || invalid; + pkcsBlock++; + } + pkcsBlockLen /= 8; + + // Require block type 1 for SSL. + invalid = (pkcsBlock[0] != 1) || invalid; + + // skip past the padding until we find the separator + unsigned i=1; + while (i<pkcsBlockLen && pkcsBlock[i++]) { // null body + } + assert(i==pkcsBlockLen || pkcsBlock[i-1]==0); + + unsigned int outputLen = pkcsBlockLen - i; + invalid = (outputLen > maxOutputLen) || invalid; + + if (invalid) + return 0; + + memcpy(output, pkcsBlock+i, outputLen); + return outputLen; +} + + +word32 SSL_Decrypt(const RSA_PublicKey& key, const byte* sig, byte* plain) +{ + PK_Lengths lengths(key.GetModulus()); + + ByteBlock paddedBlock(BitsToBytes(lengths.PaddedBlockBitLength())); + Integer x = key.ApplyFunction(Integer(sig, + lengths.FixedCiphertextLength())); + if (x.ByteCount() > paddedBlock.size()) + x = Integer::Zero(); + x.Encode(paddedBlock.get_buffer(), paddedBlock.size()); + return RSA_BlockType1().UnPad(paddedBlock.get_buffer(), + lengths.PaddedBlockBitLength(), plain); +} + + +} // namespace + +#ifdef __GNUC__ +template TaoCrypt::AllocatorWithCleanup<unsigned char>::pointer TaoCrypt::StdReallocate<unsigned char, TaoCrypt::AllocatorWithCleanup<unsigned char> >(TaoCrypt::AllocatorWithCleanup<unsigned char>&, unsigned char*, TaoCrypt::AllocatorWithCleanup<unsigned char>::size_type, TaoCrypt::AllocatorWithCleanup<unsigned char>::size_type, bool); +template TaoCrypt::AllocatorWithCleanup<unsigned int>::pointer TaoCrypt::StdReallocate<unsigned int, TaoCrypt::AllocatorWithCleanup<unsigned int> >(TaoCrypt::AllocatorWithCleanup<unsigned int>&, unsigned int*, TaoCrypt::AllocatorWithCleanup<unsigned int>::size_type, TaoCrypt::AllocatorWithCleanup<unsigned int>::size_type, bool); +template TaoCrypt::Integer* mySTL::uninit_copy<TaoCrypt::Integer*, TaoCrypt::Integer*>(TaoCrypt::Integer*, TaoCrypt::Integer*, TaoCrypt::Integer*); +template TaoCrypt::Integer* mySTL::uninit_fill_n<TaoCrypt::Integer*, unsigned int, TaoCrypt::Integer>(TaoCrypt::Integer*, unsigned int, TaoCrypt::Integer const&); +template TaoCrypt::WindowSlider* mySTL::uninit_copy<TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*); +template class TaoCrypt::AbstractGroup<TaoCrypt::Integer>; +template class TaoCrypt::AbstractRing<TaoCrypt::Integer>; +template class TaoCrypt::RSA_Decryptor<TaoCrypt::RSA_BlockType2>; +template class TaoCrypt::RSA_Encryptor<TaoCrypt::RSA_BlockType1>; +template class TaoCrypt::RSA_Encryptor<TaoCrypt::RSA_BlockType2>; +template mySTL::vector<TaoCrypt::Integer>* mySTL::uninit_fill_n<mySTL::vector<TaoCrypt::Integer>*, unsigned int, mySTL::vector<TaoCrypt::Integer> >(mySTL::vector<TaoCrypt::Integer>*, unsigned int, mySTL::vector<TaoCrypt::Integer> const&); +template void mySTL::destroy<TaoCrypt::Integer*>(TaoCrypt::Integer*, TaoCrypt::Integer*); +template void mySTL::destroy<TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*); +template void mySTL::destroy<mySTL::vector<TaoCrypt::Integer>*>(mySTL::vector<TaoCrypt::Integer>*, mySTL::vector<TaoCrypt::Integer>*); +#endif + + diff --git a/extra/yassl/taocrypt/src/sha.cpp b/extra/yassl/taocrypt/src/sha.cpp new file mode 100644 index 00000000000..4dfd2c3f3db --- /dev/null +++ b/extra/yassl/taocrypt/src/sha.cpp @@ -0,0 +1,144 @@ +/* sha.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + +/* based on Wei Dai's sha.cpp from CryptoPP */ + +#include "runtime.hpp" +#include <string.h> +#include "algorithm.hpp" // mySTL::swap +#include "sha.hpp" + + +namespace TaoCrypt { + +#define blk0(i) (W[i] = (*reinterpret_cast<word32*>(&buffer_[i*4]))) +#define blk1(i) (W[i&15] = \ + rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1)) + +#define f1(x,y,z) (z^(x &(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) + +// (R0+R1), R2, R3, R4 are the different operations used in SHA1 +#define R0(v,w,x,y,z,i) z+= f1(w,x,y) + blk0(i) + 0x5A827999+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R1(v,w,x,y,z,i) z+= f1(w,x,y) + blk1(i) + 0x5A827999+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R2(v,w,x,y,z,i) z+= f2(w,x,y) + blk1(i) + 0x6ED9EBA1+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R3(v,w,x,y,z,i) z+= f3(w,x,y) + blk1(i) + 0x8F1BBCDC+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R4(v,w,x,y,z,i) z+= f4(w,x,y) + blk1(i) + 0xCA62C1D6+ \ + rotlFixed(v,5); w = rotlFixed(w,30); + + +void SHA::Init() +{ + digest_[0] = 0x67452301L; + digest_[1] = 0xEFCDAB89L; + digest_[2] = 0x98BADCFEL; + digest_[3] = 0x10325476L; + digest_[4] = 0xC3D2E1F0L; + + buffLen_ = 0; + length_ = 0; +} + + +SHA::SHA(const SHA& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32), + BLOCK_SIZE) +{ + buffLen_ = that.buffLen_; + length_ = that.length_; + + memcpy(digest_, that.digest_, DIGEST_SIZE); + memcpy(buffer_, that.buffer_, BLOCK_SIZE); +} + +SHA& SHA::operator= (const SHA& that) +{ + SHA tmp(that); + Swap(tmp); + + return *this; +} + + +void SHA::Swap(SHA& other) +{ + mySTL::swap(buffer_, other.buffer_); + mySTL::swap(buffLen_, other.buffLen_); + mySTL::swap(digest_, other.digest_); + mySTL::swap(length_, other.length_); +} + + +void SHA::Transform() +{ + word32 W[BLOCK_SIZE / sizeof(word32)]; + + // Copy context->state[] to working vars + word32 a = digest_[0]; + word32 b = digest_[1]; + word32 c = digest_[2]; + word32 d = digest_[3]; + word32 e = digest_[4]; + + // 4 rounds of 20 operations each. Loop unrolled. + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + // Add the working vars back into digest state[] + digest_[0] += a; + digest_[1] += b; + digest_[2] += c; + digest_[3] += d; + digest_[4] += e; + + // Wipe variables + a = b = c = d = e = 0; + memset(W, 0, sizeof(W)); + + buffLen_ = 0; + length_ += 512; +} + + +} // namespace diff --git a/extra/yassl/taocrypt/taocrypt.dsp b/extra/yassl/taocrypt/taocrypt.dsp new file mode 100644 index 00000000000..115ad0cb272 --- /dev/null +++ b/extra/yassl/taocrypt/taocrypt.dsp @@ -0,0 +1,260 @@ +# Microsoft Developer Studio Project File - Name="taocrypt" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=taocrypt - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "taocrypt.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "taocrypt.mak" CFG="taocrypt - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "taocrypt - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "taocrypt - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "taocrypt - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "taocrypt___Win32_Release" +# PROP BASE Intermediate_Dir "taocrypt___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX- /O2 /I "include" /I "..\mySTL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "taocrypt - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "taocrypt___Win32_Debug" +# PROP BASE Intermediate_Dir "taocrypt___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX- /ZI /Od /I "include" /I "..\mySTL" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "taocrypt - Win32 Release" +# Name "taocrypt - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\src\aes.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\aestables.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\algebra.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\arc4.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\asn.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\coding.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\des.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\dh.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\dsa.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\file.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\hash.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\integer.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\md2.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\md5.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\misc.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\random.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\ripemd.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\rsa.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\sha.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\include\aes.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\algebra.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\arc4.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\asn.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\block.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\coding.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\des.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\dh.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\dsa.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\error.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\file.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\hash.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\hmac.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\integer.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\md2.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\md5.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\misc.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\modarith.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\modes.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\random.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\ripemd.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\rsa.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\sha.hpp +# End Source File +# End Group +# End Target +# End Project diff --git a/extra/yassl/taocrypt/taocrypt.dsw b/extra/yassl/taocrypt/taocrypt.dsw new file mode 100644 index 00000000000..d10d7534c3d --- /dev/null +++ b/extra/yassl/taocrypt/taocrypt.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "taocrypt"=.\taocrypt.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "test"=.\test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name taocrypt + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/extra/yassl/yassl.dsp b/extra/yassl/yassl.dsp new file mode 100644 index 00000000000..f51c19eebbf --- /dev/null +++ b/extra/yassl/yassl.dsp @@ -0,0 +1,192 @@ +# Microsoft Developer Studio Project File - Name="yassl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=yassl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "yassl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "yassl.mak" CFG="yassl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "yassl - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "yassl - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "yassl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX- /O2 /I "include" /I "taocrypt\include" /I "mySTL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "yassl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX- /ZI /Od /I "include" /I "taocrypt\include" /I "mySTL" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "yassl - Win32 Release" +# Name "yassl - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\src\buffer.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\cert_wrapper.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\crypto_wrapper.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\handshake.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\lock.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\log.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\socket_wrapper.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\ssl.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\timer.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\yassl_error.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\yassl_imp.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\yassl_int.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\include\buffer.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\cert_wrapper.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\crypto_wrapper.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\factory.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\handshake.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\lock.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\log.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\socket_wrapper.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\timer.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\yassl_error.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\yassl_imp.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\yassl_int.hpp +# End Source File +# Begin Source File + +SOURCE=.\include\yassl_types.hpp +# End Source File +# End Group +# End Target +# End Project diff --git a/extra/yassl/yassl.dsw b/extra/yassl/yassl.dsw new file mode 100644 index 00000000000..c0bba9acdce --- /dev/null +++ b/extra/yassl/yassl.dsw @@ -0,0 +1,137 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "client"=.\examples\client\client.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name yassl + End Project Dependency +}}} + +############################################################################### + +Project: "echoclient"=.\examples\echoclient\echoclient.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name yassl + End Project Dependency +}}} + +############################################################################### + +Project: "echoserver"=.\examples\echoserver\echoserver.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name yassl + End Project Dependency +}}} + +############################################################################### + +Project: "server"=.\examples\server\server.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name yassl + End Project Dependency +}}} + +############################################################################### + +Project: "taocrypt"=.\taocrypt\taocrypt.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "test"=.\taocrypt\test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name taocrypt + End Project Dependency +}}} + +############################################################################### + +Project: "testsuite"=.\testsuite\testsuite.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name taocrypt + End Project Dependency + Begin Project Dependency + Project_Dep_Name yassl + End Project Dependency +}}} + +############################################################################### + +Project: "yassl"=.\yassl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name taocrypt + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/include/config-win.h b/include/config-win.h index bc392ce73d8..a4f81a0ec6a 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -106,20 +106,33 @@ functions */ /* Type information */ +#if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT typedef unsigned short ushort; typedef unsigned int uint; +#endif /* defined(__EMX__) || !defined(HAVE_UINT) */ + typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */ typedef __int64 longlong; +#ifndef HAVE_SIGSET_T typedef int sigset_t; +#endif #define longlong_defined -/* off_t should not be __int64 because of conflicts in header files; - Use my_off_t or os_off_t instead */ +/* + off_t should not be __int64 because of conflicts in header files; + Use my_off_t or os_off_t instead +*/ +#ifndef HAVE_OFF_T typedef long off_t; +#endif typedef __int64 os_off_t; #ifdef _WIN64 typedef UINT_PTR rf_SetTimer; #else +#ifndef HAVE_SIZE_T typedef unsigned int size_t; +#endif typedef uint rf_SetTimer; #endif diff --git a/include/my_global.h b/include/my_global.h index 74846fe1762..55ec427e3e1 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -230,17 +230,6 @@ C_MODE_END #define __LONG_MAX__ 2147483647 #endif -/* Fix problem when linking c++ programs with gcc 3.x */ -#ifdef DEFINE_CXA_PURE_VIRTUAL -#define FIX_GCC_LINKING_PROBLEM \ -C_MODE_START int __cxa_pure_virtual() {\ - DBUG_ASSERT("Pure virtual method called." == "Aborted");\ - return 0;\ -} C_MODE_END -#else -#define FIX_GCC_LINKING_PROBLEM -#endif - /* egcs 1.1.2 has a problem with memcpy on Alpha */ #if defined(__GNUC__) && defined(__alpha__) && ! (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)) #define BAD_MEMCPY @@ -425,6 +414,8 @@ int __void__; #endif #if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT typedef unsigned int uint; typedef unsigned short ushort; #endif diff --git a/include/my_pthread.h b/include/my_pthread.h index 670a4ccf63e..47a38d1a642 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -604,19 +604,19 @@ extern int my_rw_trywrlock(my_rw_lock_t *); #define pthread_attr_setstacksize(A,B) pthread_dummy(0) #endif -/* Define mutex types */ +/* Define mutex types, see my_thr_init.c */ #define MY_MUTEX_INIT_SLOW NULL -#define MY_MUTEX_INIT_FAST NULL -#define MY_MUTEX_INIT_ERRCHK NULL #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP extern pthread_mutexattr_t my_fast_mutexattr; -#undef MY_MUTEX_INIT_FAST #define MY_MUTEX_INIT_FAST &my_fast_mutexattr +#else +#define MY_MUTEX_INIT_FAST NULL #endif #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP -extern pthread_mutexattr_t my_errchk_mutexattr; -#undef MY_INIT_MUTEX_ERRCHK -#define MY_INIT_MUTEX_ERRCHK &my_errchk_mutexattr +extern pthread_mutexattr_t my_errorcheck_mutexattr; +#define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr +#else +#define MY_MUTEX_INIT_ERRCHK NULL #endif extern my_bool my_thread_global_init(void); diff --git a/include/my_sys.h b/include/my_sys.h index f63743a4c6c..8f595bfdbf0 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -638,6 +638,7 @@ extern uint dirname_part(my_string to,const char *name); extern uint dirname_length(const char *name); #define base_name(A) (A+dirname_length(A)) extern int test_if_hard_path(const char *dir_name); +extern my_bool has_path(const char *name); extern char *convert_dirname(char *to, const char *from, const char *from_end); extern void to_unix_path(my_string name); extern my_string fn_ext(const char *name); @@ -781,6 +782,7 @@ extern int my_search_option_files(const char *conf_file, int *argc, char ***argv, uint *args_used, Process_option_func func, void *func_ctx); extern void free_defaults(char **argv); +extern void my_print_default_files(const char *conf_file); extern void print_defaults(const char *conf_file, const char **groups); extern my_bool my_compress(byte *, ulong *, ulong *); extern my_bool my_uncompress(byte *, ulong *, ulong *); diff --git a/include/violite.h b/include/violite.h index 97784694e79..5ee051cb6e7 100644 --- a/include/violite.h +++ b/include/violite.h @@ -99,6 +99,7 @@ void vio_timeout(Vio *vio,uint timeout); #endif #define HEADER_DES_LOCL_H dummy_something +#define YASSL_MYSQL_COMPATIBLE #include <openssl/ssl.h> #include <openssl/err.h> diff --git a/libmysqld/emb_qcache.cc b/libmysqld/emb_qcache.cc index 2d3d82b7952..ecc45096165 100644 --- a/libmysqld/emb_qcache.cc +++ b/libmysqld/emb_qcache.cc @@ -22,7 +22,7 @@ void Querycache_stream::store_char(char c) { if (data_end == cur_data) - use_next_block(); + use_next_block(TRUE); *(cur_data++)= c; #ifndef DBUG_OFF stored_size++; @@ -42,13 +42,13 @@ void Querycache_stream::store_short(ushort s) } if (data_end == cur_data) { - use_next_block(); + use_next_block(TRUE); int2store(cur_data, s); cur_data+= 2; return; } *cur_data= ((byte *)(&s))[0]; - use_next_block(); + use_next_block(TRUE); *(cur_data++)= ((byte *)(&s))[1]; } @@ -66,7 +66,7 @@ void Querycache_stream::store_int(uint i) } if (!rest_len) { - use_next_block(); + use_next_block(TRUE); int4store(cur_data, i); cur_data+= 4; return; @@ -74,7 +74,7 @@ void Querycache_stream::store_int(uint i) char buf[4]; int4store(buf, i); memcpy(cur_data, buf, rest_len); - use_next_block(); + use_next_block(TRUE); memcpy(cur_data, buf+rest_len, 4-rest_len); cur_data+= 4-rest_len; } @@ -93,13 +93,13 @@ void Querycache_stream::store_ll(ulonglong ll) } if (!rest_len) { - use_next_block(); + use_next_block(TRUE); int8store(cur_data, ll); cur_data+= 8; return; } memcpy(cur_data, &ll, rest_len); - use_next_block(); + use_next_block(TRUE); memcpy(cur_data, ((byte*)&ll)+rest_len, 8-rest_len); cur_data+= 8-rest_len; } @@ -112,14 +112,14 @@ void Querycache_stream::store_str_only(const char *str, uint str_len) do { size_t rest_len= data_end - cur_data; - if (rest_len > str_len) + if (rest_len >= str_len) { memcpy(cur_data, str, str_len); cur_data+= str_len; return; } memcpy(cur_data, str, rest_len); - use_next_block(); + use_next_block(TRUE); str_len-= rest_len; str+= rest_len; } while(str_len); @@ -145,7 +145,7 @@ void Querycache_stream::store_safe_str(const char *str, uint str_len) char Querycache_stream::load_char() { if (cur_data == data_end) - use_next_block(); + use_next_block(FALSE); return *(cur_data++); } @@ -160,13 +160,13 @@ ushort Querycache_stream::load_short() } if (data_end == cur_data) { - use_next_block(); + use_next_block(FALSE); result= uint2korr(cur_data); cur_data+= 2; return result; } ((byte*)&result)[0]= *cur_data; - use_next_block(); + use_next_block(FALSE); ((byte*)&result)[1]= *(cur_data++); return result; } @@ -183,14 +183,14 @@ uint Querycache_stream::load_int() } if (!rest_len) { - use_next_block(); + use_next_block(FALSE); result= uint4korr(cur_data); cur_data+= 4; return result; } char buf[4]; memcpy(buf, cur_data, rest_len); - use_next_block(); + use_next_block(FALSE); memcpy(buf+rest_len, cur_data, 4-rest_len); cur_data+= 4-rest_len; result= uint4korr(buf); @@ -209,13 +209,13 @@ ulonglong Querycache_stream::load_ll() } if (!rest_len) { - use_next_block(); + use_next_block(FALSE); result= uint8korr(cur_data); cur_data+= 8; return result; } memcpy(&result, cur_data, rest_len); - use_next_block(); + use_next_block(FALSE); memcpy(((byte*)&result)+rest_len, cur_data, 8-rest_len); cur_data+= 8-rest_len; return result; @@ -226,7 +226,7 @@ void Querycache_stream::load_str_only(char *buffer, uint str_len) do { size_t rest_len= data_end - cur_data; - if (rest_len > str_len) + if (rest_len >= str_len) { memcpy(buffer, cur_data, str_len); cur_data+= str_len; @@ -234,7 +234,7 @@ void Querycache_stream::load_str_only(char *buffer, uint str_len) break; } memcpy(buffer, cur_data, rest_len); - use_next_block(); + use_next_block(FALSE); str_len-= rest_len; buffer+= rest_len; } while(str_len); diff --git a/libmysqld/emb_qcache.h b/libmysqld/emb_qcache.h index 32ce19847ff..6201058ce56 100644 --- a/libmysqld/emb_qcache.h +++ b/libmysqld/emb_qcache.h @@ -22,22 +22,43 @@ class Querycache_stream uint headers_len; public: #ifndef DBUG_OFF + Query_cache_block *first_block; uint stored_size; #endif Querycache_stream(Query_cache_block *ini_block, uint ini_headers_len) : block(ini_block), headers_len(ini_headers_len) { - use_next_block(); + cur_data= ((byte*)block)+headers_len; + data_end= cur_data + (block->used-headers_len); #ifndef DBUG_OFF + first_block= ini_block; stored_size= 0; #endif } - void use_next_block() + void use_next_block(bool writing) { + /* + This shouldn't be called if there is only one block, or to loop + around to the first block again. That means we're trying to write + more data than we allocated space for. + */ + DBUG_ASSERT(block->next != block); + DBUG_ASSERT(block->next != first_block); + + block= block->next; + /* + While writing, update the type of each block as we write to it. + While reading, make sure that the block is of the expected type. + */ + if (writing) + block->type= Query_cache_block::RES_CONT; + else + DBUG_ASSERT(block->type == Query_cache_block::RES_CONT); + cur_data= ((byte*)block)+headers_len; data_end= cur_data + (block->used-headers_len); } - + void store_char(char c); void store_short(ushort s); void store_int(uint i); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 352c7954d72..74bb541b220 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -31,6 +31,7 @@ #define __GNU_LIBRARY__ /* Skip warnings in getopt.h */ #endif #include <my_getopt.h> +#include <assert.h> #if INT_MAX > 32767 #define BITS_SAVED 32 @@ -1996,7 +1997,9 @@ static void write_bits (register ulong value, register uint bits) { reg3 uint byte_buff; bits= (uint) -file_buffer.bits; - byte_buff=file_buffer.current_byte | (uint) (value >> bits); + DBUG_ASSERT(bits <= 8 * sizeof(value)); + byte_buff= (file_buffer.current_byte | + ((bits != 8 * sizeof(value)) ? (uint) (value >> bits) : 0)); #if BITS_SAVED == 32 *file_buffer.pos++= (byte) (byte_buff >> 24) ; *file_buffer.pos++= (byte) (byte_buff >> 16) ; @@ -2004,7 +2007,9 @@ static void write_bits (register ulong value, register uint bits) *file_buffer.pos++= (byte) (byte_buff >> 8) ; *file_buffer.pos++= (byte) byte_buff; - value&=(1 << bits)-1; + DBUG_ASSERT(bits <= 8 * sizeof(ulong)); + if (bits != 8 * sizeof(value)) + value&= (((ulong) 1) << bits) - 1; #if BITS_SAVED == 16 if (bits >= sizeof(uint)) { diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index a59ccb7d966..0dc2f4f9768 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -80,7 +80,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) continue; /* Skip comments */ } - if (!test_if_hard_path(buff)) + if (!has_path(buff)) { VOID(strmake(name_buff+dir_length,buff, sizeof(name_buff)-1-dir_length)); diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 5fb4d99d4f4..fb0b6c5c2a7 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -703,6 +703,12 @@ then fi MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --socket=$MASTER_MYSOCK --port=$MYSQL_TCP_PORT --silent $EXTRA_MYSQL_CLIENT_TEST_OPT" +# Need to pass additional arguments to MYSQL_CLIENT_TEST for embedded server +# -A marks each argument for passing to the function which initializes the +# embedded library +if [ "x$USE_EMBEDDED_SERVER" = "x1" ]; then + MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST -A --language=$LANGUAGE -A --datadir=$SLAVE_MYDDIR -A --character-sets-dir=$CHARSETSDIR" +fi MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT" MYSQL_SHOW="$MYSQL_SHOW -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLSHOW_OPT" MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR --character-sets-dir=$CHARSETSDIR $EXTRA_MYSQLBINLOG_OPT" diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index ce5917db4bc..793e50cf653 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -184,6 +184,22 @@ fld1 fld3 250503 heaving 250504 population 250505 bomb +create table t3 engine=archive select * from t2; +select * from t3 where fld3='bonfire'; +auto fld1 companynr fld3 fld4 fld5 fld6 +1191 068504 00 bonfire corresponds positively +select count(*) from t3; +count(*) +1199 +rename table t3 to t4; +Warnings: +Error 7 Error on rename of './test/t3.ARN' to './test/t4.ARN' (Errcode: 2) +select * from t4 where fld3='bonfire'; +auto fld1 companynr fld3 fld4 fld5 fld6 +1191 068504 00 bonfire corresponds positively +select count(*) from t4; +count(*) +1199 INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat',''); INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); @@ -5020,4 +5036,4 @@ auto fld1 companynr fld3 fld4 fld5 fld6 3 011402 37 Romans scholastics jarring 4 011403 37 intercepted audiology tinily INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); -drop table t1, t2; +drop table t1, t2, t4; diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index e372c307ba7..a0c8f317db2 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -128,3 +128,20 @@ t2.value64=t1.value64; value64 value32 value64 value32 9223372036854775807 2 9223372036854775807 4 drop table t1, t2; +create table t1 select 1 as 'a'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(1) NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select 9223372036854775809 as 'a'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(19) unsigned NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a +9223372036854775809 +drop table t1; diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index feefd47c611..6dc608a9289 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -4,12 +4,11 @@ CAST(1-2 AS UNSIGNED) select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER) -1 -select CONVERT('-1',UNSIGNED); -CONVERT('-1',UNSIGNED) -18446744073709551615 select CAST('10 ' as unsigned integer); CAST('10 ' as unsigned integer) 10 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '10 ' select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1 18446744073709551611 18446744073709551611 @@ -100,6 +99,41 @@ select 10E+0+'a'; 10 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' +select cast('18446744073709551616' as unsigned); +cast('18446744073709551616' as unsigned) +18446744073709551615 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('18446744073709551616' as signed); +cast('18446744073709551616' as signed) +-1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('9223372036854775809' as signed); +cast('9223372036854775809' as signed) +-9223372036854775807 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('-1' as unsigned); +cast('-1' as unsigned) +18446744073709551615 +Warnings: +Warning 1105 Cast to unsigned converted negative integer to it's positive complement +select cast('abc' as signed); +cast('abc' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'abc' +select cast('1a' as signed); +cast('1a' as signed) +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '1a' +select cast('' as signed); +cast('' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' set names binary; select cast(_latin1'test' as char character set latin2); cast(_latin1'test' as char character set latin2) @@ -255,6 +289,39 @@ timediff(cast('2004-12-30 12:00:00' as time), '12:00:00') select timediff(cast('1 12:00:00' as time), '12:00:00'); timediff(cast('1 12:00:00' as time), '12:00:00') 24:00:00 +select cast(18446744073709551615 as unsigned); +cast(18446744073709551615 as unsigned) +18446744073709551615 +select cast(18446744073709551615 as signed); +cast(18446744073709551615 as signed) +-1 +select cast('18446744073709551615' as unsigned); +cast('18446744073709551615' as unsigned) +18446744073709551615 +select cast('18446744073709551615' as signed); +cast('18446744073709551615' as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('9223372036854775807' as signed); +cast('9223372036854775807' as signed) +9223372036854775807 +select cast(concat('184467440','73709551615') as unsigned); +cast(concat('184467440','73709551615') as unsigned) +18446744073709551615 +select cast(concat('184467440','73709551615') as signed); +cast(concat('184467440','73709551615') as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast(repeat('1',20) as unsigned); +cast(repeat('1',20) as unsigned) +11111111111111111111 +select cast(repeat('1',20) as signed); +cast(repeat('1',20) as signed) +-7335632962598440505 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement select cast('1.2' as decimal(3,2)); cast('1.2' as decimal(3,2)) 1.20 diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 0e558e47594..73cde35993e 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -801,5 +801,5 @@ CREATE TABLE t1 (st varchar(100)); INSERT INTO t1 VALUES ("Fake string"); CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)); INSERT INTO t2 SELECT GeomFromText(st) FROM t1; -ERROR HY000: Unknown error +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field drop table t1, t2; diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 3b196a60d68..93216fe2003 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -461,9 +461,9 @@ Note 1003 select issimple(multipoint(point(3,6),point(4,10))) AS `issimple(Multi create table t1 (a geometry not null); insert into t1 values (GeomFromText('Point(1 2)')); insert into t1 values ('Garbage'); -ERROR HY000: Unknown error +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field insert IGNORE into t1 values ('Garbage'); -ERROR HY000: Unknown error +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field alter table t1 add spatial index(a); drop table t1; create table t1(a geometry not null, spatial index(a)); @@ -655,3 +655,13 @@ t1 where object_id=85984; object_id geometrytype(geo) ISSIMPLE(GEO) ASTEXT(centroid(geo)) 85984 MULTIPOLYGON 0 POINT(-114.87787186923 36.33101763469) drop table t1; +create table t1 (fl geometry); +insert into t1 values (1); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +insert into t1 values (1.11); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +insert into t1 values ("qwerty"); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +insert into t1 values (pointfromtext('point(1,1)')); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +drop table t1; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index af69cc83e83..5cee9b15dcd 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -702,3 +702,12 @@ c val-74 val-98 drop table t1,t2; +create table t1 (b int4 unsigned not null); +insert into t1 values(3000000000); +select * from t1; +b +3000000000 +select min(b) from t1; +min(b) +3000000000 +drop table t1; diff --git a/mysql-test/r/innodb-replace.result b/mysql-test/r/innodb-replace.result index a27806640ad..b7edcc49e56 100644 --- a/mysql-test/r/innodb-replace.result +++ b/mysql-test/r/innodb-replace.result @@ -1,3 +1,4 @@ +drop table if exists t1; create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb; select * from t1; c1 c2 stamp diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 6db48cff57e..2bf1155d2b5 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -943,3 +943,17 @@ Warnings: Warning 1260 2 line(s) were cut by GROUP_CONCAT() drop table t1, t2; set group_concat_max_len=default; +create table t1 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, art int(11) not null, primary key (gid,x,y)); +insert t1 values (1, -5, -8, 2), (1, 2, 2, 1), (1, 1, 1, 1); +create table t2 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, id int(11) not null, primary key (gid,id,x,y), key id (id)); +insert t2 values (1, -5, -8, 1), (1, 1, 1, 1), (1, 2, 2, 1); +create table t3 ( set_id smallint(5) unsigned not null, id tinyint(4) unsigned not null, name char(12) not null, primary key (id,set_id)); +insert t3 values (0, 1, 'a'), (1, 1, 'b'), (0, 2, 'c'), (1, 2, 'd'), (1, 3, 'e'), (1, 4, 'f'), (1, 5, 'g'), (1, 6, 'h'); +explain select name from t1 left join t2 on t1.x = t2.x and t1.y = t2.y +left join t3 on t1.art = t3.id where t2.id =1 and t2.x = -5 and t2.y =-8 +and t1.gid =1 and t2.gid =1 and t3.set_id =1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const PRIMARY PRIMARY 10 const,const,const 1 +1 SIMPLE t2 const PRIMARY,id PRIMARY 14 const,const,const,const 1 Using index +1 SIMPLE t3 const PRIMARY PRIMARY 3 const,const 1 +drop tables t1,t2,t3; diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result index c0df8d968cb..7705961d08d 100644 --- a/mysql-test/r/lowercase_table.result +++ b/mysql-test/r/lowercase_table.result @@ -79,5 +79,8 @@ ERROR 42000: Not unique table/alias: 'C' select C.a, c.a from t1 c, t2 C; ERROR 42000: Not unique table/alias: 'C' drop table t1, t2; +create table t1 (a int); +create table t2 like T1; +drop table t1, t2; show tables; Tables_in_test diff --git a/mysql-test/r/ndb_multi.result b/mysql-test/r/ndb_multi.result index 5696fda1c07..2080be241e8 100644 --- a/mysql-test/r/ndb_multi.result +++ b/mysql-test/r/ndb_multi.result @@ -13,6 +13,26 @@ a show status like 'handler_discover%'; Variable_name Value Handler_discover 0 +select * from t1; +a +2 +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +select * from t1; +a +2 +show status like 'handler_discover%'; +Variable_name Value +Handler_discover 0 +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +select * from t1; +ERROR HY000: Got error 241 'Invalid schema object version' from ndbcluster +select * from t1; +a +2 flush status; select * from t1; a @@ -20,7 +40,7 @@ a update t1 set a=3 where a=2; show status like 'handler_discover%'; Variable_name Value -Handler_discover 1 +Handler_discover 0 create table t3 (a int not null primary key, b varchar(22), c int, last_col text) engine=ndb; insert into t3 values(1, 'Hi!', 89, 'Longtext column'); diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 8db57104477..385ac1f4dfb 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -980,4 +980,31 @@ show status like 'qcache_queries_in_cache'; Variable_name Value Qcache_queries_in_cache 0 drop table t1; +set GLOBAL query_cache_size=64*1024; +create table t1 (a text); +insert into t1 values (repeat('abcdefghijklmnopqrstuvwxyz', 550)); +create table t2 (a text); +insert into t2 values (repeat('ijklmnopqrstuvwxyzabcdefgh', 550)); +select a from t1; +select a from t2; +show status like 'Qcache_%_blocks'; +Variable_name Value +Qcache_free_blocks 1 +Qcache_total_blocks 7 +insert into t1 select reverse(a) from t1; +show status like 'Qcache_%_blocks'; +Variable_name Value +Qcache_free_blocks 2 +Qcache_total_blocks 5 +select a from t1; +show status like 'Qcache_%_blocks'; +Variable_name Value +Qcache_free_blocks 1 +Qcache_total_blocks 8 +select a from t1; +a +abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz +zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba +flush query cache; +drop table t1, t2; set GLOBAL query_cache_size=0; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 9f28acbcb7d..a5cdee4b1bf 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3041,4 +3041,20 @@ Warning 1265 Data truncated for column 'id' at row 2 delete from t1| drop procedure bug9004_1| drop procedure bug9004_2| +drop procedure if exists bug7293| +insert into t1 values ('secret', 0)| +create procedure bug7293(p1 varchar(100)) +begin +if exists (select id from t1 where soundex(p1)=soundex(id)) then +select 'yes'; +end if; +end;| +call bug7293('secret')| +yes +yes +call bug7293 ('secrete')| +yes +yes +drop procedure bug7293| +delete from t1| drop table t1,t2; diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 40a9c3b9af5..f3f019e43ba 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -63,6 +63,9 @@ host CREATE TABLE `host` ( `Lock_tables_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Create_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Show_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N', + `Create_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', + `Alter_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', + `Execute_priv` enum('N','Y') character set utf8 NOT NULL default 'N', PRIMARY KEY (`Host`,`Db`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Host privileges; Merged with database privileges' show create table user; diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index 2dd58f54327..f43fd09982a 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -97,3 +97,29 @@ Variable_name Value Created_tmp_disk_tables 0 Created_tmp_tables 2 drop table t1; +create temporary table t1 as select 'This is temp. table' A; +create view t1 as select 'This is view' A; +select * from t1; +A +This is temp. table +show create table t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `A` varchar(19) NOT NULL default '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create view t1; +View Create View +t1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`t1` AS select _latin1'This is view' AS `A` +drop view t1; +select * from t1; +A +This is temp. table +create view t1 as select 'This is view again' A; +select * from t1; +A +This is temp. table +drop table t1; +select * from t1; +A +This is view again +drop view t1; diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index a01f8ee08a1..a7b6fa1b376 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -764,3 +764,23 @@ non PS, 1.0 in parameter 1.0 PS, 1.0 in parameter 1.0 deallocate prepare stmt; drop table t1; +create table t1 ( +strippedproductid char(15) not null default '', +zlevelprice decimal(10,2) default null, +primary key (strippedproductid) +); +create table t2 ( +productid char(15) not null default '', +zlevelprice char(21) default null, +primary key (productid) +); +insert into t1 values ('002trans','49.99'); +insert into t1 values ('003trans','39.98'); +insert into t1 values ('004trans','31.18'); +insert INTO t2 SELECT * FROM t1; +select * from t2; +productid zlevelprice +002trans 49.99 +003trans 39.98 +004trans 31.18 +drop table t1, t2; diff --git a/mysql-test/r/user_limits.result b/mysql-test/r/user_limits.result index 75062e97200..a94eb4616d1 100644 --- a/mysql-test/r/user_limits.result +++ b/mysql-test/r/user_limits.result @@ -42,11 +42,11 @@ i select * from t1; i connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); -ERROR 42000: User 'mysqltest_1' has exceeded the 'max_connections' resource (current value: 2) +ERROR 42000: User 'mysqltest_1' has exceeded the 'max_connections_per_hour' resource (current value: 2) select * from t1; i connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK); -ERROR 42000: User 'mysqltest_1' has exceeded the 'max_connections' resource (current value: 2) +ERROR 42000: User 'mysqltest_1' has exceeded the 'max_connections_per_hour' resource (current value: 2) drop user mysqltest_1@localhost; flush privileges; grant usage on *.* to mysqltest_1@localhost with max_user_connections 2; diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 68eae111111..d9a647ce2c3 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -182,3 +182,44 @@ coercibility(@v1) coercibility(@v2) coercibility(@v3) coercibility(@v4) set session @honk=99; set one_shot @honk=99; ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longblob +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= cast(NULL as signed integer); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` bigint(20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` bigint(20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= concat(NULL); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longblob +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var=1; +set @first_var= cast(NULL as CHAR); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longtext +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index f7ec603ca79..9d25524da5f 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1289,6 +1289,18 @@ select fld3 from t2 where (fld3 like "C%" and fld3 = "Chantilly"); select fld1,fld3 from t2 where fld1 like "25050%"; select fld1,fld3 from t2 where fld1 like "25050_"; + +# +# Test rename of table +# +create table t3 engine=archive select * from t2; +select * from t3 where fld3='bonfire'; +select count(*) from t3; +rename table t3 to t4; +select * from t4 where fld3='bonfire'; +select count(*) from t4; + + # # Test for insert after select # @@ -1308,8 +1320,9 @@ INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat','') , (2,011401,37,'b SELECT * FROM t2; # Just test syntax, we will never know if the out put is right or wrong +# Must be the last test INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); # # Cleanup, test is over # -drop table t1, t2; +drop table t1, t2, t4; diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index a26b78254e7..99c8a13d0b5 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -104,3 +104,13 @@ t2.value64=t1.value64; drop table t1, t2; +# +# Test of CREATE ... SELECT and unsigned integers +# +create table t1 select 1 as 'a'; +show create table t1; +drop table t1; +create table t1 select 9223372036854775809 as 'a'; +show create table t1; +select * from t1; +drop table t1; diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index e7dd49394ee..cafecd6000d 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -4,7 +4,6 @@ select CAST(1-2 AS UNSIGNED); select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); -select CONVERT('-1',UNSIGNED); select CAST('10 ' as unsigned integer); select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1; @@ -34,6 +33,15 @@ select 10+'a'; select 10.0+cast('a' as decimal); select 10E+0+'a'; +# out-of-range cases +select cast('18446744073709551616' as unsigned); +select cast('18446744073709551616' as signed); +select cast('9223372036854775809' as signed); +select cast('-1' as unsigned); +select cast('abc' as signed); +select cast('1a' as signed); +select cast('' as signed); + # # Character set convertion # @@ -132,6 +140,22 @@ select timediff(cast('2004-12-30 12:00:00' as time), '12:00:00'); # Still we should not throw away "days" part of time value select timediff(cast('1 12:00:00' as time), '12:00:00'); +# +# Bug #7036: Casting from string to unsigned would cap value of result at +# maximum signed value instead of maximum unsigned value +# +select cast(18446744073709551615 as unsigned); +select cast(18446744073709551615 as signed); +select cast('18446744073709551615' as unsigned); +select cast('18446744073709551615' as signed); +select cast('9223372036854775807' as signed); + +select cast(concat('184467440','73709551615') as unsigned); +select cast(concat('184467440','73709551615') as signed); + +select cast(repeat('1',20) as unsigned); +select cast(repeat('1',20) as signed); + #decimal-related additions select cast('1.2' as decimal(3,2)); select 1e18 * cast('1.2' as decimal(3,2)); diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index da59c6ae5e4..522f7a6f637 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -168,6 +168,6 @@ drop table t1; CREATE TABLE t1 (st varchar(100)); INSERT INTO t1 VALUES ("Fake string"); CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)); ---error 1105 +--error 1416 INSERT INTO t2 SELECT GeomFromText(st) FROM t1; drop table t1, t2; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 86c34eacbc5..b7071019e9d 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -165,9 +165,9 @@ explain extended select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimpl create table t1 (a geometry not null); insert into t1 values (GeomFromText('Point(1 2)')); --- error 1105 +-- error 1416 insert into t1 values ('Garbage'); --- error 1105 +-- error 1416 insert IGNORE into t1 values ('Garbage'); alter table t1 add spatial index(a); @@ -359,3 +359,15 @@ select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from t1 where object_id=85984; drop table t1; + +create table t1 (fl geometry); +--error 1416 +insert into t1 values (1); +--error 1416 +insert into t1 values (1.11); +--error 1416 +insert into t1 values ("qwerty"); +--error 1416 +insert into t1 values (pointfromtext('point(1,1)')); + +drop table t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 46e58cd00fd..fbd39019e6d 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -515,3 +515,10 @@ explain select c from t2 where a = 2 and b = 'val-2' group by c; select c from t2 where a = 2 and b = 'val-2' group by c; drop table t1,t2; +# Test for BUG#9298 "Wrong handling of int4 unsigned columns in GROUP functions" +# (the actual problem was with protocol code, not GROUP BY) +create table t1 (b int4 unsigned not null); +insert into t1 values(3000000000); +select * from t1; +select min(b) from t1; +drop table t1; diff --git a/mysql-test/t/innodb-replace.test b/mysql-test/t/innodb-replace.test index e7e96da1443..516f058a68e 100644 --- a/mysql-test/t/innodb-replace.test +++ b/mysql-test/t/innodb-replace.test @@ -2,6 +2,10 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + # # Bug #1078 # diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index 25344af55b4..3a34c204905 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -661,3 +661,18 @@ select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; drop table t1, t2; set group_concat_max_len=default; + +# +# BUG#10162 - ON is merged with WHERE, left join is convered to a regular join +# +create table t1 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, art int(11) not null, primary key (gid,x,y)); +insert t1 values (1, -5, -8, 2), (1, 2, 2, 1), (1, 1, 1, 1); +create table t2 (gid smallint(5) unsigned not null, x int(11) not null, y int(11) not null, id int(11) not null, primary key (gid,id,x,y), key id (id)); +insert t2 values (1, -5, -8, 1), (1, 1, 1, 1), (1, 2, 2, 1); +create table t3 ( set_id smallint(5) unsigned not null, id tinyint(4) unsigned not null, name char(12) not null, primary key (id,set_id)); +insert t3 values (0, 1, 'a'), (1, 1, 'b'), (0, 2, 'c'), (1, 2, 'd'), (1, 3, 'e'), (1, 4, 'f'), (1, 5, 'g'), (1, 6, 'h'); +explain select name from t1 left join t2 on t1.x = t2.x and t1.y = t2.y +left join t3 on t1.art = t3.id where t2.id =1 and t2.x = -5 and t2.y =-8 +and t1.gid =1 and t2.gid =1 and t3.set_id =1; +drop tables t1,t2,t3; + diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index f6142b3ddfd..d60ad06b3a7 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -74,4 +74,12 @@ select * from t1 c, t2 C; select C.a, c.a from t1 c, t2 C; drop table t1, t2; +# +# Bug #9761: CREATE TABLE ... LIKE ... not handled correctly when +# lower_case_table_names is set + +create table t1 (a int); +create table t2 like T1; +drop table t1, t2; + show tables; diff --git a/mysql-test/t/ndb_multi.test b/mysql-test/t/ndb_multi.test index 24651913a79..85950c72cf9 100644 --- a/mysql-test/t/ndb_multi.test +++ b/mysql-test/t/ndb_multi.test @@ -18,6 +18,30 @@ select * from t1; select * from t2; show status like 'handler_discover%'; +# Check dropping and recreating table on same server +connect (con1,localhost,,,test); +connect (con2,localhost,,,test); +connection con1; +select * from t1; +connection con2; +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +connection con1; +select * from t1; + +# Check dropping and recreating table on different server +connection server2; +show status like 'handler_discover%'; +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +connection server1; +# Currently a retry is required remotely +--error 1296 +select * from t1; +select * from t1; + # Connect to server2 and use the tables from there connection server2; flush status; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 475ba466ea9..d4e3b95e4a2 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -711,4 +711,49 @@ repair table t1; show status like 'qcache_queries_in_cache'; drop table t1; +# Bug #9549: Make sure cached queries that span more than one cache block +# are handled properly in the embedded server. + +# We just want a small query cache, so we can fragment it easily +set GLOBAL query_cache_size=64*1024; +# This actually gives us a usable cache size of about 48K + +# Each table is about 14K +create table t1 (a text); +insert into t1 values (repeat('abcdefghijklmnopqrstuvwxyz', 550)); +create table t2 (a text); +insert into t2 values (repeat('ijklmnopqrstuvwxyzabcdefgh', 550)); + +# Load a query from each table into the query cache +--disable_result_log +select a from t1; # Q1 +select a from t2; # Q2 +--enable_result_log +show status like 'Qcache_%_blocks'; + +# Now the cache looks like (14K for Q1)(14K for Q2)(20K free) + +# Flush Q1 from the cache by adding an out-of-order chunk to t1 +insert into t1 select reverse(a) from t1; +show status like 'Qcache_%_blocks'; + +# Now the cache looks like (14K free)(14K for Q2)(20K free) + +# Load our new data into the query cache +--disable_result_log +select a from t1; # Q3 +--enable_result_log +show status like 'Qcache_%_blocks'; + +# Now the cache should be like (14K for Q3)(14K for Q2)(14K for Q3)(6K free) + +# Note that Q3 is split across two chunks! + +# Load Q3 from the cache, and actually pay attention to the results +select a from t1; + +flush query cache; + +drop table t1, t2; + set GLOBAL query_cache_size=0; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 7b3bff4eb55..2e45d1c6cd1 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3723,6 +3723,23 @@ delete from t1| drop procedure bug9004_1| drop procedure bug9004_2| +# +# BUG#7293: Stored procedure crash with soundex +# +--disable_warnings +drop procedure if exists bug7293| +--enable_warnings +insert into t1 values ('secret', 0)| +create procedure bug7293(p1 varchar(100)) +begin + if exists (select id from t1 where soundex(p1)=soundex(id)) then + select 'yes'; + end if; +end;| +call bug7293('secret')| +call bug7293 ('secrete')| +drop procedure bug7293| +delete from t1| # # BUG#NNNN: New bug synopsis diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test index 74276c7668c..eeb33515570 100644 --- a/mysql-test/t/temp_table.test +++ b/mysql-test/t/temp_table.test @@ -89,3 +89,18 @@ flush status; select * from t1 group by d; show status like "created_tmp%tables"; drop table t1; + +# Fix for BUG#8921: Check that temporary table is ingored by view commands. +create temporary table t1 as select 'This is temp. table' A; +create view t1 as select 'This is view' A; +select * from t1; +show create table t1; +show create view t1; +drop view t1; +select * from t1; +create view t1 as select 'This is view again' A; +select * from t1; +drop table t1; +select * from t1; +drop view t1; + diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 107f4a06ec5..f86113ac66b 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -343,3 +343,31 @@ execute stmt using @a; select * from t1; deallocate prepare stmt; drop table t1; + +# +# A test case for Bug#5673 "Rounding problem in 4.0.21 inserting decimal +# value into a char field": this is a regression bug in 4.0 tree caused by +# a fix for some other decimal conversion issue. The patch never was +# approved to get into 4.0 (maybe because it was considered too intrusive) +# + +create table t1 ( + strippedproductid char(15) not null default '', + zlevelprice decimal(10,2) default null, + primary key (strippedproductid) +); + +create table t2 ( + productid char(15) not null default '', + zlevelprice char(21) default null, + primary key (productid) +); + +insert into t1 values ('002trans','49.99'); +insert into t1 values ('003trans','39.98'); +insert into t1 values ('004trans','31.18'); + +insert INTO t2 SELECT * FROM t1; + +select * from t2; +drop table t1, t2; diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index ef360f2231d..b9d06558f34 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -119,3 +119,29 @@ select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4); set session @honk=99; --error 1382 set one_shot @honk=99; + +# +# Bug #6598: problem with cast(NULL as signed integer); +# + +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= cast(NULL as signed integer); +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= concat(NULL); +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var=1; +set @first_var= cast(NULL as CHAR); +create table t1 select @first_var; +show create table t1; +drop table t1; diff --git a/mysys/default.c b/mysys/default.c index 0f33c94d17e..a4ab6eb1939 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -45,11 +45,12 @@ char *defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ -#define MAX_DEFAULT_DIRS 4 +#define MAX_DEFAULT_DIRS 5 const char *default_directories[MAX_DEFAULT_DIRS + 1]; #ifdef __WIN__ static const char *f_extensions[]= { ".ini", ".cnf", 0 }; +static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN]; #else static const char *f_extensions[]= { ".cnf", 0 }; #endif @@ -107,19 +108,20 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv, uint *args_used, Process_option_func func, void *func_ctx) { - const char **dirs, *forced_default_file; + const char **dirs, *forced_default_file, *forced_extra_defaults; int error= 0; DBUG_ENTER("my_search_option_files"); /* Check if we want to force the use a specific default file */ get_defaults_files(*argc, *argv, - (char **)&forced_default_file, &defaults_extra_file); + (char **)&forced_default_file, + (char **)&forced_extra_defaults); if (forced_default_file) forced_default_file= strchr(forced_default_file,'=')+1; - if (defaults_extra_file) - defaults_extra_file= strchr(defaults_extra_file,'=')+1; + if (forced_extra_defaults) + defaults_extra_file= strchr(forced_extra_defaults,'=')+1; - (*args_used)+= (forced_default_file ? 1 : 0) + (defaults_extra_file ? 1 : 0); + args_used+= (forced_default_file ? 1 : 0) + (forced_extra_defaults ? 1 : 0); if (forced_default_file) { @@ -140,20 +142,6 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv, } else { -#ifdef __WIN__ - char system_dir[FN_REFLEN]; - GetWindowsDirectory(system_dir,sizeof(system_dir)); - if ((search_default_file(func, func_ctx, system_dir, conf_file))) - goto err; -#endif -#if defined(__EMX__) || defined(OS2) - { - const char *etc; - if ((etc= getenv("ETC")) && - (search_default_file(func, func_ctx, etc, conf_file)) < 0) - goto err; - } -#endif for (dirs= default_directories ; *dirs; dirs++) { if (**dirs) @@ -396,8 +384,11 @@ static int search_default_file(Process_option_func opt_handler, const char *config_file) { char **ext; + const char *empty_list[]= { "", 0 }; + my_bool have_ext= fn_ext(config_file)[0] != 0; + const char **exts_to_use= have_ext ? empty_list : f_extensions; - for (ext= (char**) f_extensions; *ext; *ext++) + for (ext= (char**) exts_to_use; *ext; *ext++) { int error; if ((error= search_default_file_with_ext(opt_handler, handler_ctx, @@ -410,6 +401,56 @@ static int search_default_file(Process_option_func opt_handler, /* + Skip over keyword and get argument after keyword + + SYNOPSIS + get_argument() + keyword Include directive keyword + kwlen Length of keyword + ptr Pointer to the keword in the line under process + line line number + + RETURN + 0 error + # Returns pointer to the argument after the keyword. +*/ + +static char *get_argument(const char *keyword, uint kwlen, + char *ptr, char *name, uint line) +{ + char *end; + + /* Skip over "include / includedir keyword" and following whitespace */ + + for (ptr+= kwlen - 1; + my_isspace(&my_charset_latin1, ptr[0]); + ptr++) + {} + + /* + Trim trailing whitespace from directory name + The -1 below is for the newline added by fgets() + Note that my_isspace() is true for \r and \n + */ + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; /* Cut off end space */ + + /* Print error msg if there is nothing after !include* directive */ + if (end <= ptr) + { + fprintf(stderr, + "error: Wrong '!%s' directive in config file: %s at line %d\n", + keyword, name, line); + return 0; + } + return ptr; +} + + +/* Open a configuration file (if exists) and read given options from it SYNOPSIS @@ -497,40 +538,34 @@ static int search_default_file_with_ext(Process_option_func opt_handler, continue; /* Configuration File Directives */ - if ((*ptr == '!') && (recursion_level < max_recursion_level)) + if ((*ptr == '!')) { + if (recursion_level >= max_recursion_level) + { + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; + fprintf(stderr, + "Warning: skipping '%s' directive as maximum include" + "recursion level was reached in file %s at line %d\n", + ptr, name, line); + continue; + } + /* skip over `!' and following whitespace */ for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++) {} - if ((!strncmp(ptr, includedir_keyword, sizeof(includedir_keyword) - 1)) - && my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) + if ((!strncmp(ptr, includedir_keyword, + sizeof(includedir_keyword) - 1)) && + my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) { - /* skip over "includedir" and following whitespace */ - for (ptr+= sizeof(includedir_keyword) - 1; - my_isspace(&my_charset_latin1, ptr[0]); ptr++) - {} - - /* trim trailing whitespace from directory name */ - end= ptr + strlen(ptr) - 1; - /* fgets() stores the newline character in the buffer */ - if ((end[0] == '\n') || (end[0] == '\r') || - my_isspace(&my_charset_latin1, end[0])) - { - for (; my_isspace(&my_charset_latin1, *(end - 1)); end--) - {} - end[0]= 0; - } - - /* print error msg if there is nothing after !includedir directive */ - if (end == ptr) - { - fprintf(stderr, - "error: Wrong !includedir directive in config " - "file: %s at line %d\n", - name,line); - goto err; - } + if (!(ptr= get_argument(includedir_keyword, + sizeof(includedir_keyword), + ptr, name, line))) + goto err; if (!(search_dir= my_dir(ptr, MYF(MY_WME)))) goto err; @@ -559,28 +594,13 @@ static int search_default_file_with_ext(Process_option_func opt_handler, my_dirend(search_dir); } - else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) - && my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword) - 1])) + else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) && + my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1])) { - /* skip over `include' and following whitespace */ - for (ptr+= sizeof(include_keyword) - 1; - my_isspace(&my_charset_latin1, ptr[0]); ptr++) - {} - - /* trim trailing whitespace from filename */ - end= ptr + strlen(ptr) - 1; - for (; my_isspace(&my_charset_latin1, *(end - 1)) ; end--) - {} - end[0]= 0; - - if (end == ptr) - { - fprintf(stderr, - "error: Wrong !include directive in config " - "file: %s at line %d\n", - name,line); - goto err; - } + if (!(ptr= get_argument(include_keyword, + sizeof(include_keyword), ptr, + name, line))) + goto err; search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr, recursion_level + 1); @@ -588,14 +608,6 @@ static int search_default_file_with_ext(Process_option_func opt_handler, continue; } - else - if (recursion_level >= max_recursion_level) - { - fprintf(stderr, - "warning: skipping !include directive as maximum include" - "recursion level was reached in file %s at line %d\n", - name, line); - } if (*ptr == '[') /* Group name */ { @@ -734,11 +746,11 @@ static char *remove_end_comment(char *ptr) #include <help_start.h> -void print_defaults(const char *conf_file, const char **groups) +void my_print_default_files(const char *conf_file) { -#ifdef __WIN__ + const char *empty_list[]= { "", 0 }; my_bool have_ext= fn_ext(conf_file)[0] != 0; -#endif + const char **exts_to_use= have_ext ? empty_list : f_extensions; char name[FN_REFLEN], **ext; const char **dirs; @@ -749,30 +761,9 @@ void print_defaults(const char *conf_file, const char **groups) fputs(conf_file,stdout); else { -#ifdef __WIN__ - GetWindowsDirectory(name,sizeof(name)); - if (!have_ext) - { - for (ext= (char**) f_extensions; *ext; *ext++) - printf("%s\\%s%s ", name, conf_file, *ext); - } - else - printf("%s\\%s ", name, conf_file); -#endif -#if defined(__EMX__) || defined(OS2) - { - const char *etc; - - if ((etc= getenv("ETC"))) - { - for (ext= (char**) f_extensions; *ext; *ext++) - printf("%s\\%s%s ", etc, conf_file, *ext); - } - } -#endif for (dirs=default_directories ; *dirs; dirs++) { - for (ext= (char**) f_extensions; *ext; *ext++) + for (ext= (char**) exts_to_use; *ext; *ext++) { const char *pos; char *end; @@ -791,6 +782,12 @@ void print_defaults(const char *conf_file, const char **groups) } puts(""); } +} + +void print_defaults(const char *conf_file, const char **groups) +{ + my_print_default_files(conf_file); + fputs("The following groups are read:",stdout); for ( ; *groups ; groups++) { @@ -806,15 +803,58 @@ void print_defaults(const char *conf_file, const char **groups) #include <help_end.h> + +/* + Create the list of default directories. + + On Microsoft Windows, this is: + 1. C:/ + 2. GetWindowsDirectory() + 3. GetSystemWindowsDirectory() + 4. getenv(DEFAULT_HOME_ENV) + 5. "" + + On Novell NetWare, this is: + 1. sys:/etc/ + 2. getenv(DEFAULT_HOME_ENV) + 3. "" + + On OS/2, this is: + 1. getenv(ETC) + 2. /etc/ + 3. getenv(DEFAULT_HOME_ENV) + 4. "" + 5. "~/" + + Everywhere else, this is: + 1. /etc/ + 2. getenv(DEFAULT_HOME_ENV) + 3. "" + 4. "~/" + + */ + static void init_default_directories() { const char *env, **ptr= default_directories; #ifdef __WIN__ *ptr++= "C:/"; + + if (GetWindowsDirectory(system_dir,sizeof(system_dir))) + *ptr++= &system_dir; + /* Only add shared system directory if different from default. */ + if (GetSystemWindowsDirectory(shared_system_dir,sizeof(shared_system_dir)) && + strcmp(system_dir, shared_system_dir)) + *ptr++= &shared_system_dir; + #elif defined(__NETWARE__) *ptr++= "sys:/etc/"; #else +#if defined(__EMX__) || defined(OS2) + if ((env= getenv("ETC"))) + *ptr++= env; +#endif *ptr++= "/etc/"; #endif if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 4967b60cd68..2308536cd37 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1025,8 +1025,8 @@ static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count) for a too long time (this time is determined by parameter age_threshold). */ -static inline void unreg_request(KEY_CACHE *keycache, - BLOCK_LINK *block, int at_end) +static void unreg_request(KEY_CACHE *keycache, + BLOCK_LINK *block, int at_end) { if (! --block->requests) { @@ -1045,10 +1045,13 @@ static inline void unreg_request(KEY_CACHE *keycache, } link_block(keycache, block, hot, (my_bool)at_end); block->last_hit_time= keycache->keycache_time; - if (++keycache->keycache_time - keycache->used_ins->last_hit_time > + keycache->keycache_time++; + + block= keycache->used_ins; + /* Check if we should link a hot block to the warm block */ + if (block && keycache->keycache_time - block->last_hit_time > keycache->age_threshold) { - block= keycache->used_ins; unlink_block(keycache, block); link_block(keycache, block, 0, 0); if (block->temperature != BLOCK_WARM) diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c index d6f647254e8..89f949eca27 100644 --- a/mysys/my_getwd.c +++ b/mysys/my_getwd.c @@ -192,3 +192,25 @@ int test_if_hard_path(register const char *dir_name) return FALSE; #endif } /* test_if_hard_path */ + + +/* + Test if a name contains an (absolute or relative) path. + + SYNOPSIS + has_path() + name The name to test. + + RETURN + TRUE name contains a path. + FALSE name does not contain a path. +*/ + +my_bool has_path(const char *name) +{ + return test(strchr(name, FN_LIBCHAR)) +#ifdef FN_DEVCHAR + || test(strchr(name, FN_DEVCHAR)) +#endif + ; +} diff --git a/mysys/my_new.cc b/mysys/my_new.cc index 14423c3afd5..66f3a14eeb4 100644 --- a/mysys/my_new.cc +++ b/mysys/my_new.cc @@ -45,5 +45,14 @@ void operator delete[] (void *ptr) throw () free(ptr); } +C_MODE_START + +int __cxa_pure_virtual() { + assert("Pure virtual method called." == "Aborted"); + return 0; +} + +C_MODE_END + #endif /* USE_MYSYS_NEW */ diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 36b37f68b46..878e1f6bfc6 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -41,7 +41,7 @@ pthread_mutex_t LOCK_gethostbyname_r; pthread_mutexattr_t my_fast_mutexattr; #endif #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP -pthread_mutexattr_t my_errchk_mutexattr; +pthread_mutexattr_t my_errorcheck_mutexattr; #endif /* @@ -62,19 +62,29 @@ my_bool my_thread_global_init(void) fprintf(stderr,"Can't initialize threads: error %d\n",errno); return 1; } + #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP - pthread_mutexattr_init(&my_fast_mutexattr); /* - Note that the following statement may give a compiler warning under - some configurations, but there isn't anything we can do about this as - this is a bug in the header files for the thread implementation + Set mutex type to "fast" a.k.a "adaptive" + + The mutex kind determines what happens if a thread attempts to lock + a mutex it already owns with pthread_mutex_lock(3). If the mutex + is of the ``fast'' kind, pthread_mutex_lock(3) simply suspends + the calling thread forever. If the mutex is of the ``error checking'' + kind, pthread_mutex_lock(3) returns immediately with the error + code EDEADLK. */ - pthread_mutexattr_setkind_np(&my_fast_mutexattr,PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutexattr_init(&my_fast_mutexattr); + pthread_mutexattr_settype(&my_fast_mutexattr, + PTHREAD_MUTEX_ADAPTIVE_NP); #endif #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP - pthread_mutexattr_init(&my_errchk_mutexattr); - pthread_mutexattr_setkind_np(&my_errchk_mutexattr, - PTHREAD_MUTEX_ERRORCHECK_NP); + /* + Set mutex type to "errorcheck" a.k.a "adaptive" + */ + pthread_mutexattr_init(&my_errorcheck_mutexattr); + pthread_mutexattr_settype(&my_errorcheck_mutexattr, + PTHREAD_MUTEX_ERRORCHECK); #endif pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST); @@ -110,7 +120,7 @@ void my_thread_global_end(void) pthread_mutexattr_destroy(&my_fast_mutexattr); #endif #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP - pthread_mutexattr_destroy(&my_errchk_mutexattr); + pthread_mutexattr_destroy(&my_errorcheck_mutexattr); #endif pthread_mutex_destroy(&THR_LOCK_malloc); pthread_mutex_destroy(&THR_LOCK_open); diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp index 7a945c1c22e..86130be4c4b 100644 --- a/ndb/include/ndbapi/NdbDictionary.hpp +++ b/ndb/include/ndbapi/NdbDictionary.hpp @@ -76,8 +76,11 @@ public: Changed, ///< The object has been modified in memory ///< and has to be commited in NDB Kernel for ///< changes to take effect - Retrieved ///< The object exist and has been read + Retrieved, ///< The object exist and has been read ///< into main memory from NDB Kernel + Invalid ///< The object has been invalidated + ///< and should not be used + }; /** diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index ff87a72f636..96c8f6020e5 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1526,6 +1526,7 @@ int NdbDictionaryImpl::alterTable(NdbTableImpl &impl) // If in local cache it must be in global if (!cachedImpl) abort(); + cachedImpl->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(cachedImpl); m_globalHash->unlock(); } @@ -1830,8 +1831,8 @@ NdbDictionaryImpl::dropTable(const char * name) DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName)); m_localHash.drop(internalTableName); - m_globalHash->lock(); + tab->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(tab); m_globalHash->unlock(); DBUG_RETURN(dropTable(name)); @@ -1875,10 +1876,11 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl) int ret = m_receiver.dropTable(impl); if(ret == 0 || m_error.code == 709){ const char * internalTableName = impl.m_internalName.c_str(); + m_localHash.drop(internalTableName); - m_globalHash->lock(); + impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); @@ -1976,6 +1978,7 @@ NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl) m_localHash.drop(internalTableName); m_globalHash->lock(); + impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); return 0; @@ -2242,8 +2245,8 @@ NdbDictionaryImpl::dropIndex(const char * indexName, m_ndb.internalizeTableName(indexName); // Index is also a table m_localHash.drop(internalIndexName); - m_globalHash->lock(); + idx->m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(idx->m_table); m_globalHash->unlock(); return dropIndex(indexName, tableName); @@ -2277,8 +2280,8 @@ NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName) int ret = m_receiver.dropIndex(impl, *timpl); if(ret == 0){ m_localHash.drop(internalIndexName); - m_globalHash->lock(); + impl.m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(impl.m_table); m_globalHash->unlock(); } diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index e76fc935b03..0eb14cd5e65 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -105,6 +105,9 @@ then c_h="$c_h Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_h="$c_h Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_h="$c_h Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," + c_h="$c_h Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," + c_h="$c_h Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," + c_h="$c_h Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_h="$c_h PRIMARY KEY Host (Host,Db)" c_h="$c_h ) engine=MyISAM" c_h="$c_h CHARACTER SET utf8 COLLATE utf8_bin" diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index d18536e1c81..292720371c8 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -271,21 +271,25 @@ SELECT @hadCreateRoutinePriv:=1 FROM user WHERE Create_routine_priv LIKE '%'; # Create PROCEDUREs privileges (v5.0) # ALTER TABLE db ADD Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv; +ALTER TABLE host ADD Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv; ALTER TABLE user ADD Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Show_view_priv; # # Alter PROCEDUREs privileges (v5.0) # ALTER TABLE db ADD Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv; +ALTER TABLE host ADD Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv; ALTER TABLE user ADD Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_routine_priv; ALTER TABLE db ADD Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv; +ALTER TABLE host ADD Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv; # # Assign create/alter routine privileges to people who have create privileges # UPDATE user SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv where user<>"" AND @hadCreateRoutinePriv = 0; UPDATE db SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv, Execute_priv=Select_priv where user<>"" AND @hadCreateRoutinePriv = 0; +UPDATE host SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv, Execute_priv=Select_priv where @hadCreateRoutinePriv = 0; # # Add max_user_connections resource limit diff --git a/server-tools/instance-manager/command.cc b/server-tools/instance-manager/command.cc index 818c4b0cae2..73dd49ef8b8 100644 --- a/server-tools/instance-manager/command.cc +++ b/server-tools/instance-manager/command.cc @@ -28,6 +28,3 @@ Command::Command(Instance_map *instance_map_arg) Command::~Command() {} -#ifdef __GNUC__ -FIX_GCC_LINKING_PROBLEM -#endif diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index a88bfc0391b..231031c9834 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -431,11 +431,20 @@ int ha_archive::free_share(ARCHIVE_SHARE *share) } -/* +/* We just implement one additional file extension. */ +static const char *ha_archive_exts[] = { + ARZ, + ARN, + ARM, + NullS +}; + const char **ha_archive::bas_ext() const -{ static const char *ext[]= { ARZ, ARN, ARM, NullS }; return ext; } +{ + return ha_archive_exts; +} /* diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index d043a66e71a..562b51878bf 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -186,8 +186,14 @@ static int free_share(EXAMPLE_SHARE *share) exist for the storage engine. This is also used by the default rename_table and delete_table method in handler.cc. */ +static const char *ha_example_exts[] = { + NullS +}; + const char **ha_example::bas_ext() const -{ static const char *ext[]= { NullS }; return ext; } +{ + return ha_example_exts; +} /* diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index b515932d25f..9ac446587ec 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -384,8 +384,15 @@ int ha_tina::find_current_row(byte *buf) If frm_error() is called in table.cc this is called to find out what file extensions exist for this handler. */ +static const char *ha_tina_exts[] = { + ".CSV", + NullS +}; + const char **ha_tina::bas_ext() const -{ static const char *ext[]= { ".CSV", NullS }; return ext; } +{ + return ha_tina_exts; +} /* diff --git a/sql/field.cc b/sql/field.cc index 00f729d5b07..c59d9b63fca 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7267,12 +7267,38 @@ void Field_geom::sql_type(String &res) const } +int Field_geom::store(double nr) +{ + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); + return -1; +} + + +int Field_geom::store(longlong nr) +{ + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); + return -1; +} + + +int Field_geom::store_decimal(const my_decimal *) +{ + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); + return -1; +} + + int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) { if (!length) bzero(ptr, Field_blob::pack_length()); else { + if (from == Geometry::bad_geometry_data.ptr()) + goto err; // Check given WKB uint32 wkb_type; if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2) @@ -7280,7 +7306,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) wkb_type= uint4korr(from + WKB_HEADER_SIZE); if (wkb_type < (uint32) Geometry::wkb_point || wkb_type > (uint32) Geometry::wkb_end) - return -1; + goto err; Field_blob::store_length(length); if (table->copy_blobs || length <= MAX_FIELD_WIDTH) { // Must make a copy @@ -7293,6 +7319,8 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) err: bzero(ptr, Field_blob::pack_length()); + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); return -1; } diff --git a/sql/field.h b/sql/field.h index 22787850442..ac9c2f351b3 100644 --- a/sql/field.h +++ b/sql/field.h @@ -118,6 +118,7 @@ public: String *val_int_as_str(String *val_buffer, my_bool unsigned_flag); virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } + virtual Item_result cast_to_int_type () const { return result_type(); } static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); bool eq(Field *field) @@ -1189,9 +1190,9 @@ public: enum_field_types type() const { return FIELD_TYPE_GEOMETRY; } void sql_type(String &str) const; int store(const char *to, uint length, CHARSET_INFO *charset); - int store(double nr) { return 1; } - int store(longlong nr) { return 1; } - int store_decimal(const my_decimal *) { return 1; } + int store(double nr); + int store(longlong nr); + int store_decimal(const my_decimal *); void get_key_image(char *buff,uint length,imagetype type); }; #endif /*HAVE_SPATIAL*/ @@ -1216,6 +1217,7 @@ public: } enum_field_types type() const { return FIELD_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } + enum Item_result cast_to_int_type () const { return INT_RESULT; } enum ha_base_keytype key_type() const; int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 54d9865ddd5..04d81b2f95a 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -371,10 +371,15 @@ void berkeley_cleanup_log_files(void) /***************************************************************************** ** Berkeley DB tables *****************************************************************************/ +static const char *ha_berkeley_exts[] = { + ha_berkeley_ext, + NullS +}; const char **ha_berkeley::bas_ext() const -{ static const char *ext[]= { ha_berkeley_ext, NullS }; return ext; } - +{ + return ha_berkeley_exts; +} ulong ha_berkeley::index_flags(uint idx, uint part, bool all_parts) const { diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index e34d5d723a4..5467ab8a978 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -25,10 +25,13 @@ #include "ha_blackhole.h" +static const char *ha_blackhole_exts[] = { + NullS +}; + const char **ha_blackhole::bas_ext() const -{ - static const char *ext[]= { NullS }; - return ext; +{ + return ha_blackhole_exts; } int ha_blackhole::open(const char *name, int mode, uint test_if_locked) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 33acc9cad0b..0ac209d82e0 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -941,14 +941,13 @@ static int free_share(FEDERATED_SHARE *share) also used by the default rename_table and delete_table method in handler.cc. */ +static const char *ha_federated_exts[] = { + NullS +}; const char **ha_federated::bas_ext() const { - static const char *ext[]= - { - NullS - }; - return ext; + return ha_federated_exts; } diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 0d700f6c9a5..52ff776c5d6 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -26,9 +26,14 @@ /***************************************************************************** ** HEAP tables *****************************************************************************/ +static const char *ha_heap_exts[] = { + NullS +}; const char **ha_heap::bas_ext() const -{ static const char *ext[1]= { NullS }; return ext; } +{ + return ha_heap_exts; +} /* Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 4052ed14259..689a00058e9 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1632,7 +1632,7 @@ innobase_report_binlog_offset_and_commit( #endif /* HAVE_REPLICATION */ trx->flush_log_later = TRUE; - innobase_commit(thd, trx_handle); + innobase_commit(thd, TRUE); trx->flush_log_later = FALSE; @@ -1805,7 +1805,7 @@ try_again: goto try_again; } -#endif HAVE_REPLICATION +#endif // HAVE_REPLICATION return(0); } @@ -2136,17 +2136,20 @@ ha_innobase::get_row_type() const /******************************************************************** Gives the file extension of an InnoDB single-table tablespace. */ +static const char* ha_innobase_exts[] = { + ".ibd", + NullS +}; const char** ha_innobase::bas_ext() const /*========================*/ /* out: file extension string */ { - static const char* ext[] = {".ibd", NullS}; - - return(ext); + return ha_innobase_exts; } + /********************************************************************* Normalizes a table name string. A normalized name consists of the database name catenated to '/' and table name. An example: diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2179eaa7f8f..2049efb73db 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -123,8 +123,16 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) } +static const char *ha_myisam_exts[] = { + ".MYI", + ".MYD", + NullS +}; + const char **ha_myisam::bas_ext() const -{ static const char *ext[]= { ".MYI",".MYD", NullS }; return ext; } +{ + return ha_myisam_exts; +} const char *ha_myisam::index_type(uint key_number) diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 4cd39660728..f7c0abf9810 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -32,8 +32,16 @@ ** MyISAM MERGE tables *****************************************************************************/ +static const char *ha_myisammrg_exts[] = { + ".MRG", + NullS +}; + const char **ha_myisammrg::bas_ext() const -{ static const char *ext[]= { ".MRG", NullS }; return ext; } +{ + return ha_myisammrg_exts; +} + const char *ha_myisammrg::index_type(uint key_number) { @@ -392,6 +400,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form, const char **table_names, **pos; TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first; THD *thd= current_thd; + uint dirlgt= dirname_length(name); DBUG_ENTER("ha_myisammrg::create"); if (!(table_names= (const char**) @@ -405,11 +414,30 @@ int ha_myisammrg::create(const char *name, register TABLE *form, tbl= find_temporary_table(thd, tables->db, tables->table_name); if (!tbl) { - uint length= my_snprintf(buff,FN_REFLEN,"%s%s/%s", - mysql_real_data_home, + /* + Construct the path to the MyISAM table. Try to meet two conditions: + 1.) Allow to include MyISAM tables from different databases, and + 2.) allow for moving DATADIR around in the file system. + The first means that we need paths in the .MRG file. The second + means that we should not have absolute paths in the .MRG file. + The best, we can do, is to use 'mysql_data_home', which is '.' + in mysqld and may be an absolute path in an embedded server. + This means that it might not be possible to move the DATADIR of + an embedded server without changing the paths in the .MRG file. + */ + uint length= my_snprintf(buff, FN_REFLEN, "%s/%s/%s", mysql_data_home, tables->db, tables->table_name); - if (!(table_name= thd->strmake(buff, length))) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); + /* + If a MyISAM table is in the same directory as the MERGE table, + we use the table name without a path. This means that the + DATADIR can easily be moved even for an embedded server as long + as the MyISAM tables are from the same database as the MERGE table. + */ + if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt)) + table_name= tables->table_name; + else + if (! (table_name= thd->strmake(buff, length))) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); } else table_name= (*tbl)->s->path; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index e2d954b1928..b61dbd1792c 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -418,11 +418,28 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd) # The mapped error code */ -void ha_ndbcluster::invalidateDictionaryCache() +void ha_ndbcluster::invalidate_dictionary_cache(bool global) { NDBDICT *dict= get_ndb()->getDictionary(); + DBUG_ENTER("invalidate_dictionary_cache"); DBUG_PRINT("info", ("invalidating %s", m_tabname)); - dict->invalidateTable(m_tabname); + + if (global) + { + const NDBTAB *tab= dict->getTable(m_tabname); + if (!tab) + DBUG_VOID_RETURN; + if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + // Global cache has already been invalidated + dict->removeCachedTable(m_tabname); + global= FALSE; + } + else + dict->invalidateTable(m_tabname); + } + else + dict->removeCachedTable(m_tabname); table->s->version=0L; /* Free when thread is ready */ /* Invalidate indexes */ for (uint i= 0; i < table->s->keys; i++) @@ -434,18 +451,28 @@ void ha_ndbcluster::invalidateDictionaryCache() switch(idx_type) { case(PRIMARY_KEY_ORDERED_INDEX): case(ORDERED_INDEX): - dict->invalidateIndex(index->getName(), m_tabname); + if (global) + dict->invalidateIndex(index->getName(), m_tabname); + else + dict->removeCachedIndex(index->getName(), m_tabname); break; case(UNIQUE_ORDERED_INDEX): - dict->invalidateIndex(index->getName(), m_tabname); + if (global) + dict->invalidateIndex(index->getName(), m_tabname); + else + dict->removeCachedIndex(index->getName(), m_tabname); case(UNIQUE_INDEX): - dict->invalidateIndex(unique_index->getName(), m_tabname); + if (global) + dict->invalidateIndex(unique_index->getName(), m_tabname); + else + dict->removeCachedIndex(unique_index->getName(), m_tabname); break; case(PRIMARY_KEY_INDEX): case(UNDEFINED_INDEX): break; } } + DBUG_VOID_RETURN; } int ha_ndbcluster::ndb_err(NdbTransaction *trans) @@ -457,7 +484,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) ERR_PRINT(err); switch (err.classification) { case NdbError::SchemaError: - invalidateDictionaryCache(); + invalidate_dictionary_cache(TRUE); if (err.code==284) { @@ -882,7 +909,14 @@ int ha_ndbcluster::get_metadata(const char *path) if (!(tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); - DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); + // Check if thread has stale local cache + if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + invalidate_dictionary_cache(FALSE); + if (!(tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); + } /* Compare FrmData in NDB with frm file from disk. */ @@ -901,7 +935,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (!invalidating_ndb_table) { DBUG_PRINT("info", ("Invalidating table")); - invalidateDictionaryCache(); + invalidate_dictionary_cache(TRUE); invalidating_ndb_table= TRUE; } else @@ -927,7 +961,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (error) DBUG_RETURN(error); - m_tableVersion= tab->getObjectVersion(); + m_table_version= tab->getObjectVersion(); m_table= (void *)tab; m_table_info= NULL; // Set in external lock @@ -3074,10 +3108,15 @@ int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size) DBUG_RETURN(extra(operation)); } +static const char *ha_ndbcluster_exts[] = { + ha_ndb_ext, + NullS +}; const char** ha_ndbcluster::bas_ext() const -{ static const char *ext[]= { ha_ndb_ext, NullS }; return ext; } - +{ + return ha_ndbcluster_exts; +} /* How many seeks it will take to read through the table @@ -3264,15 +3303,25 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) void *tab_info; if (!(tab= dict->getTable(m_tabname, &tab_info))) ERR_RETURN(dict->getNdbError()); - DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); - if (m_table != (void *)tab || m_tableVersion != tab->getObjectVersion()) + DBUG_PRINT("info", ("Table schema version: %d", + tab->getObjectVersion())); + // Check if thread has stale local cache + if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + invalidate_dictionary_cache(FALSE); + if (!(tab= dict->getTable(m_tabname, &tab_info))) + ERR_RETURN(dict->getNdbError()); + DBUG_PRINT("info", ("Table schema version: %d", + tab->getObjectVersion())); + } + if (m_table != (void *)tab || m_table_version < tab->getObjectVersion()) { /* The table has been altered, refresh the index list */ build_index_list(ndb, table, ILBP_OPEN); m_table= (void *)tab; - m_tableVersion = tab->getObjectVersion(); + m_table_version = tab->getObjectVersion(); } m_table_info= tab_info; } @@ -3316,7 +3365,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) thd_ndb->stmt= NULL; } } - m_table= NULL; m_table_info= NULL; /* @@ -4031,7 +4079,13 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) dict= ndb->getDictionary(); if (!(orig_tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); - + // Check if thread has stale local cache + if (orig_tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + dict->removeCachedTable(m_tabname); + if (!(orig_tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + } m_table= (void *)orig_tab; // Change current database to that of target table set_dbname(to); @@ -4154,7 +4208,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_active_trans(NULL), m_active_cursor(NULL), m_table(NULL), - m_tableVersion(-1), + m_table_version(-1), m_table_info(NULL), m_table_flags(HA_REC_NOT_IN_SEQ | HA_NULL_IN_KEY | @@ -4404,7 +4458,6 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, DBUG_RETURN(1); ERR_RETURN(err); } - DBUG_PRINT("info", ("Found table %s", tab->getName())); len= tab->getFrmLength(); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 4dbab18b828..81b2873d9dd 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -558,7 +558,7 @@ private: void print_results(); ulonglong get_auto_increment(); - void invalidateDictionaryCache(); + void invalidate_dictionary_cache(bool global); int ndb_err(NdbTransaction*); bool uses_blob_value(bool all_fields); @@ -596,7 +596,7 @@ private: NdbTransaction *m_active_trans; NdbScanOperation *m_active_cursor; void *m_table; - int m_tableVersion; + int m_table_version; void *m_table_info; char m_dbname[FN_HEADLEN]; //char m_schemaname[FN_HEADLEN]; diff --git a/sql/handler.cc b/sql/handler.cc index 3095aeb9476..7318de1c503 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -185,9 +185,10 @@ enum db_type ha_checktype(enum db_type database_type) thd= current_thd; return ((enum db_type) thd->variables.table_type != DB_TYPE_UNKNOWN ? (enum db_type) thd->variables.table_type : - (enum db_type) global_system_variables.table_type != - DB_TYPE_UNKNOWN ? - (enum db_type) global_system_variables.table_type : DB_TYPE_MYISAM); + ((enum db_type) global_system_variables.table_type != + DB_TYPE_UNKNOWN ? + (enum db_type) global_system_variables.table_type : DB_TYPE_MYISAM) + ); } /* ha_checktype */ @@ -1772,13 +1773,17 @@ int handler::delete_table(const char *name) int handler::rename_table(const char * from, const char * to) { - DBUG_ENTER("handler::rename_table"); - for (const char **ext=bas_ext(); *ext ; ext++) + int error= 0; + for (const char **ext= bas_ext(); *ext ; ext++) { - if (rename_file_ext(from,to,*ext)) - DBUG_RETURN(my_errno); + if (rename_file_ext(from, to, *ext)) + { + if ((error=my_errno) != ENOENT) + break; + error= 0; + } } - DBUG_RETURN(0); + return error; } /* diff --git a/sql/hostname.cc b/sql/hostname.cc index c74d230bbcb..fe2fad6f3b2 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -177,7 +177,14 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors) &tmp_errno))) { DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno)); - add_wrong_ip(in); + /* + Don't cache responses when the DSN server is down, as otherwise + transient DNS failure may leave any number of clients (those + that attempted to connect during the outage) unable to connect + indefinitely. + */ + if (tmp_errno == HOST_NOT_FOUND || tmp_error == NO_DATA) + add_wrong_ip(in); my_gethostbyname_r_free(); DBUG_RETURN(0); } diff --git a/sql/item.cc b/sql/item.cc index 541fbf7b178..7264f8b2d68 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -43,11 +43,11 @@ void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const item->max_length= item->float_length(arg->decimals); } +static const Hybrid_type_traits real_traits_instance; const Hybrid_type_traits *Hybrid_type_traits::instance() { - static const Hybrid_type_traits real_traits; - return &real_traits; + return &real_traits_instance; } @@ -67,11 +67,11 @@ Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const } /* Hybrid_type_traits_decimal */ +static const Hybrid_type_traits_decimal decimal_traits_instance; const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance() { - static const Hybrid_type_traits_decimal decimal_traits; - return &decimal_traits; + return &decimal_traits_instance; } @@ -143,11 +143,11 @@ Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to, } /* Hybrid_type_traits_integer */ +static const Hybrid_type_traits_integer integer_traits_instance; const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance() { - static const Hybrid_type_traits_integer integer_traits; - return &integer_traits; + return &integer_traits_instance; } void diff --git a/sql/item.h b/sql/item.h index e86c66ca6f3..850a2d6636d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -302,7 +302,8 @@ public: { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; - virtual Item_result result_type () const { return REAL_RESULT; } + virtual Item_result result_type() const { return REAL_RESULT; } + virtual Item_result cast_to_int_type() const { return result_type(); } virtual enum_field_types field_type() const; virtual enum Type type() const =0; /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ @@ -738,6 +739,10 @@ public: { return field->result_type(); } + Item_result cast_to_int_type() const + { + return field->cast_to_int_type(); + } enum_field_types field_type() const { return field->type(); diff --git a/sql/item_func.cc b/sql/item_func.cc index 24a3f7927ae..4e3011ac4bb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -904,6 +904,58 @@ void Item_func_signed::print(String *str) } +longlong Item_func_signed::val_int_from_str(int *error) +{ + char buff[MAX_FIELD_WIDTH], *end; + String tmp(buff,sizeof(buff), &my_charset_bin), *res; + longlong value; + + /* + For a string result, we must first get the string and then convert it + to a longlong + */ + + if (!(res= args[0]->val_str(&tmp))) + { + null_value= 1; + *error= 0; + return 0; + } + null_value= 0; + end= (char*) res->ptr()+ res->length(); + value= my_strtoll10(res->ptr(), &end, error); + if (*error > 0 || end != res->ptr()+ res->length()) + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER", + res->c_ptr()); + return value; +} + + +longlong Item_func_signed::val_int() +{ + longlong value; + int error; + + if (args[0]->cast_to_int_type() != STRING_RESULT) + { + value= args[0]->val_int(); + null_value= args[0]->null_value; + return value; + } + + value= val_int_from_str(&error); + if (value < 0 && error == 0) + { + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Cast to signed converted positive out-of-range integer to " + "it's negative complement"); + } + return value; +} + + void Item_func_unsigned::print(String *str) { str->append("cast(", 5); @@ -913,6 +965,27 @@ void Item_func_unsigned::print(String *str) } +longlong Item_func_unsigned::val_int() +{ + longlong value; + int error; + + if (args[0]->cast_to_int_type() != STRING_RESULT) + { + value= args[0]->val_int(); + null_value= args[0]->null_value; + return value; + } + + value= val_int_from_str(&error); + if (error < 0) + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Cast to unsigned converted negative integer to it's " + "positive complement"); + return value; +} + + String *Item_decimal_typecast::val_str(String *str) { my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); @@ -2349,12 +2422,12 @@ longlong Item_func_find_in_set::val_int() } str_end= substr_end; } - else if (str_end - str_begin == 0 && - find_str_len == 0 && + else if (str_end - str_begin == 0 && + find_str_len == 0 && wc == (my_wc_t) separator) return (longlong) ++position; else - return (longlong) 0; + return LL(0); } } return 0; @@ -3271,7 +3344,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, from the argument if the argument is NULL and the variable has previously been initialized. */ - if (!entry->collation.collation || !args[0]->null_value) + null_item= (args[0]->type() == NULL_ITEM); + if (!entry->collation.collation || !null_item) entry->collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT); collation.set(entry->collation.collation, DERIVATION_IMPLICIT); cached_result_type= args[0]->result_type(); @@ -3315,8 +3389,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); if (entry->value && entry->value != pos) my_free(entry->value,MYF(0)); - entry->value=0; - entry->length=0; + entry->value= 0; + entry->length= 0; } else { @@ -3355,9 +3429,9 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, if (type == DECIMAL_RESULT) ((my_decimal*)entry->value)->fix_buffer_pointer(); entry->length= length; - entry->type=type; entry->collation.set(cs, dv); } + entry->type=type; return 0; } @@ -3366,6 +3440,12 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type, CHARSET_INFO *cs, Derivation dv) { + /* + If we set a variable explicitely to NULL then keep the old + result type of the variable + */ + if ((null_value= args[0]->null_value) && null_item) + type= entry->type; // Don't change type of item if (::update_hash(entry, (null_value= args[0]->null_value), ptr, length, type, cs, dv)) { diff --git a/sql/item_func.h b/sql/item_func.h index cb0b7dc02a4..76d1151f3bf 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -262,12 +262,8 @@ public: null_value= args[0]->null_value; return tmp; } - longlong val_int() - { - longlong tmp= args[0]->val_int(); - null_value= args[0]->null_value; - return tmp; - } + longlong val_int(); + longlong val_int_from_str(int *error); void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=0; } void print(String *str); @@ -281,6 +277,7 @@ public: const char *func_name() const { return "cast_as_unsigned"; } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=1; } + longlong val_int(); void print(String *str); }; @@ -1071,6 +1068,7 @@ class Item_func_set_user_var :public Item_func char buffer[MAX_FIELD_WIDTH]; String value; my_decimal decimal_buff; + bool null_item; union { longlong vint; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 1a8cb50081b..b9f2ec8a6ca 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -55,8 +55,11 @@ String *Item_func_geometry_from_text::val_str(String *str) return 0; str->length(0); str->q_append(srid); - if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0))) - return 0; + if (!Geometry::create_from_wkt(&buffer, &trs, str, 0)) + /* We shouldn't return NULL here as NULL is a legal spatial object */ + /* Geometry::bad_spatial_data will produce error message beeing stored*/ + /* in GEOMETRY field */ + return &Geometry::bad_geometry_data; return str; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 64f23c3fc08..3dd4b6618a2 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -506,7 +506,6 @@ Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original) This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer values. */ - struct Hybrid_type_traits_fast_decimal: public Hybrid_type_traits_integer { @@ -521,13 +520,16 @@ struct Hybrid_type_traits_fast_decimal: public val->traits= Hybrid_type_traits_decimal::instance(); val->traits->div(val, u); } - static const Hybrid_type_traits_fast_decimal *instance() - { - static const Hybrid_type_traits_fast_decimal fast_decimal_traits; - return &fast_decimal_traits; - } + static const Hybrid_type_traits_fast_decimal *instance(); }; +static const Hybrid_type_traits_fast_decimal fast_decimal_traits_instance; + +const Hybrid_type_traits_fast_decimal + *Hybrid_type_traits_fast_decimal::instance() +{ + return &fast_decimal_traits_instance; +} void Item_sum_distinct::fix_length_and_dec() { diff --git a/sql/lock.cc b/sql/lock.cc index a8ccba32d4f..83a39005cd8 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -82,7 +82,8 @@ static int unlock_external(THD *thd, TABLE **table,uint count); static void print_lock_error(int error, const char *); -MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, + bool ignore_global_read_lock) { MYSQL_LOCK *sql_lock; TABLE *write_lock_used; @@ -93,7 +94,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used))) break; - if (global_read_lock && write_lock_used) + if (global_read_lock && write_lock_used && ! ignore_global_read_lock) { /* Someone has issued LOCK ALL TABLES FOR READ and we want a write lock @@ -949,3 +950,49 @@ bool make_global_read_lock_block_commit(THD *thd) DBUG_RETURN(error); } + + +/* + Set protection against global read lock. + + SYNOPSIS + set_protect_against_global_read_lock() + void + + RETURN + FALSE OK, no global read lock exists. + TRUE Error, global read lock exists already. +*/ + +bool set_protect_against_global_read_lock(void) +{ + bool global_read_lock_exists; + + pthread_mutex_lock(&LOCK_open); + if (! (global_read_lock_exists= test(global_read_lock))) + protect_against_global_read_lock++; + pthread_mutex_unlock(&LOCK_open); + return global_read_lock_exists; +} + + +/* + Unset protection against global read lock. + + SYNOPSIS + unset_protect_against_global_read_lock() + void + + RETURN + void +*/ + +void unset_protect_against_global_read_lock(void) +{ + pthread_mutex_lock(&LOCK_open); + protect_against_global_read_lock--; + pthread_mutex_unlock(&LOCK_open); + pthread_cond_broadcast(&COND_refresh); +} + + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 56fbd993aed..06c946114eb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1151,7 +1151,8 @@ extern pthread_t signal_thread; extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ -MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **table,uint count); +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, + bool ignore_global_read_lock= FALSE); void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); @@ -1165,6 +1166,8 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit); void start_waiting_global_read_lock(THD *thd); bool make_global_read_lock_block_commit(THD *thd); +bool set_protect_against_global_read_lock(void); +void unset_protect_against_global_read_lock(void); /* Lock based on name */ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 169c9e057b5..3bfa498e521 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6989,5 +6989,4 @@ template class I_List_iterator<THD>; template class I_List<i_string>; template class I_List<i_string_pair>; template class I_List<NAMED_LIST>; -FIX_GCC_LINKING_PROBLEM #endif diff --git a/sql/protocol.cc b/sql/protocol.cc index 22f1249ca28..9a96da004c5 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -820,7 +820,7 @@ bool Protocol_simple::store_long(longlong from) #endif char buff[20]; return net_store_data((char*) buff, - (uint) (int10_to_str((int) from,buff, -10)-buff)); + (uint) (int10_to_str((long int)from,buff, (from <0)?-10:10)-buff)); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 3a311ff7917..050bbe86948 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5344,3 +5344,5 @@ ER_SP_NOT_VAR_ARG 42000 eng "OUT or INOUT argument %d for routine %s is not a variable" ER_SP_NO_RETSET_IN_FUNC 0A000 eng "Not allowed to return a result set from a function" +ER_CANT_CREATE_GEOMETRY_OBJECT 22003 + eng "Cannot get geometry object from data you send to the GEOMETRY field" diff --git a/sql/spatial.cc b/sql/spatial.cc index bcfefd9dde8..427648850e4 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -22,6 +22,8 @@ /***************************** Gis_class_info *******************************/ +String Geometry::bad_geometry_data("Bad object", &my_charset_bin); + Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]= { NULL, NULL, NULL, NULL, NULL, NULL, NULL diff --git a/sql/spatial.h b/sql/spatial.h index b96434831a1..438ec171a72 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -173,6 +173,8 @@ public: static void operator delete(void *ptr, void *buffer) {} + static String bad_geometry_data; + enum wkbType { wkb_point= 1, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d79811aa4e2..ade1fb96b96 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3858,11 +3858,8 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors) TABLE *table= field->table; if (field == table->next_number_field) table->auto_increment_field_not_null= TRUE; - if ((value->save_in_field(field, 0) < 0) && !ignore_errors) - { - my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0)); + if (value->save_in_field(field, 0) == -1) DBUG_RETURN(TRUE); - } } DBUG_RETURN(thd->net.report_error); } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 4a4f61f985c..430e0fbcabf 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1950,6 +1950,11 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block, type = Query_cache_block::RES_CONT; } while (block != *result_block); #else + /* + Set type of first block, emb_store_querycache_result() will handle + the others. + */ + (*result_block)->type= type; Querycache_stream qs(*result_block, headers_len); emb_store_querycache_result(&qs, (THD*)data); #endif /*!EMBEDDED_LIBRARY*/ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 9a7a3d64de5..729f9751bba 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -89,7 +89,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } if (values.elements != table->s->fields) { - my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1); + my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L); return -1; } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -112,7 +112,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, int res; if (fields.elements != values.elements) { - my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1); + my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L); return -1; } @@ -1117,27 +1117,42 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) { int error; delayed_insert *tmp; + TABLE *table; DBUG_ENTER("delayed_get_table"); if (!table_list->db) table_list->db=thd->db; - /* no match; create a new thread to handle the table */ + /* Find the thread which handles this table. */ if (!(tmp=find_handler(thd,table_list))) { - /* Don't create more than max_insert_delayed_threads */ + /* + No match. Create a new thread to handle the table, but + no more than max_insert_delayed_threads. + */ if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); thd->proc_info="Creating delayed handler"; pthread_mutex_lock(&LOCK_delayed_create); - if (!(tmp=find_handler(thd,table_list))) // Was just created + /* + The first search above was done without LOCK_delayed_create. + Another thread might have created the handler in between. Search again. + */ + if (! (tmp= find_handler(thd, table_list))) { + /* + Avoid that a global read lock steps in while we are creating the + new thread. It would block trying to open the table. Hence, the + DI thread and this thread would wait until after the global + readlock is gone. If the read lock exists already, we leave with + no table and then switch to non-delayed insert. + */ + if (set_protect_against_global_read_lock()) + goto err; if (!(tmp=new delayed_insert())) { - thd->fatal_error(); my_error(ER_OUTOFMEMORY,MYF(0),sizeof(delayed_insert)); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err1; } pthread_mutex_lock(&LOCK_thread_count); thread_count++; @@ -1146,10 +1161,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) !(tmp->thd.query=my_strdup(table_list->table_name,MYF(MY_WME)))) { delete tmp; - thd->fatal_error(); my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err1; } tmp->table_list= *table_list; // Needed to open table tmp->table_list.db= tmp->thd.db; @@ -1165,10 +1178,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) pthread_mutex_unlock(&tmp->mutex); tmp->unlock(); delete tmp; - thd->fatal_error(); - pthread_mutex_unlock(&LOCK_delayed_create); my_error(ER_CANT_CREATE_THREAD, MYF(0), error); - DBUG_RETURN(0); + goto err1; } /* Wait until table is open */ @@ -1178,6 +1189,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) pthread_cond_wait(&tmp->cond_client,&tmp->mutex); } pthread_mutex_unlock(&tmp->mutex); + unset_protect_against_global_read_lock(); thd->proc_info="got old table"; if (tmp->thd.killed) { @@ -1189,28 +1201,34 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) thd->net.last_errno=tmp->thd.net.last_errno; } tmp->unlock(); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); // Continue with normal insert + goto err; } if (thd->killed) { tmp->unlock(); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err; } } pthread_mutex_unlock(&LOCK_delayed_create); } pthread_mutex_lock(&tmp->mutex); - TABLE *table=tmp->get_local_table(thd); + table= tmp->get_local_table(thd); pthread_mutex_unlock(&tmp->mutex); - tmp->unlock(); if (table) thd->di=tmp; else if (tmp->thd.is_fatal_error) thd->fatal_error(); + /* Unlock the delayed insert object after its last access. */ + tmp->unlock(); DBUG_RETURN((table_list->table=table)); + + err1: + thd->fatal_error(); + unset_protect_against_global_read_lock(); + err: + pthread_mutex_unlock(&LOCK_delayed_create); + DBUG_RETURN(0); // Continue with normal insert } @@ -1433,6 +1451,14 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; pthread_mutex_unlock(&LOCK_thread_count); + /* + Wait until the client runs into pthread_cond_wait(), + where we free it after the table is opened and di linked in the list. + If we did not wait here, the client might detect the opened table + before it is linked to the list. It would release LOCK_delayed_create + and allow another thread to create another handler for the same table, + since it does not find one in the list. + */ pthread_mutex_lock(&di->mutex); #if !defined( __WIN__) && !defined(OS2) /* Win32 calls this in pthread_create */ if (my_thread_init()) @@ -1547,8 +1573,17 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) if (di->tables_in_use && ! thd->lock) { - /* request for new delayed insert */ - if (!(thd->lock=mysql_lock_tables(thd,&di->table,1))) + /* + Request for new delayed insert. + Lock the table, but avoid to be blocked by a global read lock. + If we got here while a global read lock exists, then one or more + inserts started before the lock was requested. These are allowed + to complete their work before the server returns control to the + client which requested the global read lock. The delayed insert + handler will close the table and finish when the outstanding + inserts are done. + */ + if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, TRUE))) { /* Fatal error */ di->dead= 1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ccba268e18e..22febd50035 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -506,7 +506,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc) uc->user_resources.conn_per_hour <= uc->conn_per_hour) { net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, - "max_connections", + "max_connections_per_hour", (long) uc->user_resources.conn_per_hour); error=1; goto end; @@ -3010,6 +3010,10 @@ unsent_create_error: goto error; #else { + /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ + if (lex->only_view) + first_table->skip_temporary= 1; + if (check_db_used(thd, all_tables) || check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db, &first_table->grant.privilege, 0, 0)) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 56d09d7c563..17c5f51f1e1 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2223,7 +2223,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) my_pthread_setprio(pthread_self(), QUERY_PRIOR); thd->protocol= &thd->protocol_prep; // Switch to binary protocol - (void) stmt->cursor->fetch(num_rows); + stmt->cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e85bf888e24..32624bb3305 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -114,17 +114,31 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, static Next_select_func setup_end_select_func(JOIN *join); static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table, Procedure *proc); -static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); -static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); -static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last); -static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records); -static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static int end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static int end_unique_update(JOIN *join,JOIN_TAB *join_tab, - bool end_of_records); -static int end_write_group(JOIN *join, JOIN_TAB *join_tab, - bool end_of_records); + +static enum_nested_loop_state +sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, + int error, my_bool *report_error); +static enum_nested_loop_state +evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab); +static enum_nested_loop_state +sub_select(JOIN *join,JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last); +static enum_nested_loop_state +end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_write_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); + static int test_if_group_changed(List<Item_buff> &list); static int join_read_const_table(JOIN_TAB *tab, POSITION *pos); static int join_read_system(JOIN_TAB *tab); @@ -1800,13 +1814,7 @@ Cursor::open(JOIN *join_arg) happen for the first table in join_tab list */ DBUG_ASSERT(join_tab->table->null_row == 0); - - /* - There is always at least one record in the table, as otherwise we - wouldn't have opened the cursor. Therefore a failure is the only - reason read_first_record can return not 0. - */ - DBUG_RETURN(join_tab->read_first_record(join_tab)); + DBUG_RETURN(0); } @@ -1816,97 +1824,36 @@ Cursor::open(JOIN *join_arg) PRECONDITION: Cursor is open RETURN VALUES: - -4 there are more rows, send_eof sent to the client - 0 no more rows, send_eof was sent to the client, cursor is closed - other fatal fetch error, cursor is closed (error is not reported) + none, this function will send error or OK to network if necessary. */ -int +void Cursor::fetch(ulong num_rows) { THD *thd= join->thd; JOIN_TAB *join_tab= join->join_tab + join->const_tables; - COND *on_expr= *join_tab->on_expr_ref; - COND *select_cond= join_tab->select_cond; - READ_RECORD *info= &join_tab->read_record; - int error= 0; + enum_nested_loop_state error= NESTED_LOOP_OK; /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &thd->stmt_backup); join->fetch_limit+= num_rows; - /* - Run while there are new rows in the first table; - For each row, satisfying ON and WHERE clauses (those parts of them which - can be evaluated early), call next_select. - */ - do - { - int no_more_rows; - - join->examined_rows++; - - if (thd->killed) /* Aborted by user */ - { - my_message(ER_SERVER_SHUTDOWN, ER(ER_SERVER_SHUTDOWN), MYF(0)); - return -1; - } - - if (on_expr == 0 || on_expr->val_int()) - { - if (select_cond == 0 || select_cond->val_int()) - { - /* - TODO: call table->unlock_row() to unlock row failed selection, - when this feature will be used. - */ - error= join_tab->next_select(join, join_tab + 1, 0); - DBUG_ASSERT(error <= 0); - if (error) - { - /* real error or LIMIT/FETCH LIMIT worked */ - if (error == -4) - { - /* - FETCH LIMIT, read ahead one row, and close cursor - if there is no more rows XXX: to be fixed to support - non-equi-joins! - */ - if ((no_more_rows= info->read_record(info))) - error= no_more_rows > 0 ? -1: 0; - } - break; - } - } - } - /* read next row; break loop if there was an error */ - if ((no_more_rows= info->read_record(info))) - { - if (no_more_rows > 0) - error= -1; - else - { - enum { END_OF_RECORDS= 1 }; - error= join_tab->next_select(join, join_tab+1, (int) END_OF_RECORDS); - } - break; - } - } - while (thd->net.report_error == 0); - - if (thd->net.report_error) - error= -1; - if (error == -3) /* LIMIT clause worked */ - error= 0; + error= sub_select(join, join_tab, 0); + if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) + error= sub_select(join,join_tab,1); + if (error == NESTED_LOOP_QUERY_LIMIT) + error= NESTED_LOOP_OK; /* select_limit used */ + if (error == NESTED_LOOP_CURSOR_LIMIT) + join->resume_nested_loop= TRUE; #ifdef USING_TRANSACTIONS ha_release_temporary_latches(thd); #endif thd->restore_backup_item_arena(this, &thd->stmt_backup); - if (error == -4) + if (error == NESTED_LOOP_CURSOR_LIMIT) { /* Fetch limit worked, possibly more rows are there */ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; @@ -1916,20 +1863,19 @@ Cursor::fetch(ulong num_rows) else { close(); - if (error == 0) + if (error == NESTED_LOOP_OK) { thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; ::send_eof(thd); thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT; } - else + else if (error != NESTED_LOOP_KILLED) my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); /* free cursor memory */ free_items(free_list); free_list= 0; free_root(&main_mem_root, MYF(0)); } - return error; } @@ -2546,8 +2492,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); - old->null_rejecting= old->null_rejecting && - new_fields->null_rejecting; + old->null_rejecting= (old->null_rejecting && + new_fields->null_rejecting); } } else if (old->eq_func && new_fields->eq_func && @@ -2559,8 +2505,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); - old->null_rejecting= old->null_rejecting && - new_fields->null_rejecting; + old->null_rejecting= (old->null_rejecting && + new_fields->null_rejecting); } else if (old->eq_func && new_fields->eq_func && (old->val->is_null() || new_fields->val->is_null())) @@ -2572,7 +2518,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, if (old->val->is_null()) old->val= new_fields->val; /* The referred expression can be NULL: */ - old->null_rejecting= false; + old->null_rejecting= 0; } else { @@ -2734,6 +2680,8 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, If the condition has form "tbl.keypart = othertbl.field" and othertbl.field can be NULL, there will be no matches if othertbl.field has NULL value. + We use null_rejecting in add_not_null_conds() to add + 'othertbl.field IS NOT NULL' to tab->select_cond. */ (*key_fields)->null_rejecting= (cond->functype() == Item_func::EQ_FUNC) && ((*value)->type() == Item::FIELD_ITEM) && @@ -7396,6 +7344,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) if (conds) { conds= and_conds(conds, table->on_expr); + conds->top_level_item(); /* conds is always a new item as both cond and on_expr existed */ DBUG_ASSERT(!conds->fixed); conds->fix_fields(join->thd, 0, &conds); @@ -8948,7 +8897,8 @@ static Next_select_func setup_end_select_func(JOIN *join) static int do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) { - int error= 0; + int rc= 0; + enum_nested_loop_state error= NESTED_LOOP_OK; JOIN_TAB *join_tab; DBUG_ENTER("do_select"); @@ -8978,24 +8928,30 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) if (!join->conds || join->conds->val_int()) { Next_select_func end_select= join->join_tab[join->tables-1].next_select; - if (!(error=(*end_select)(join,join_tab,0)) || error == -3) - error=(*end_select)(join,join_tab,1); + error= (*end_select)(join,join_tab,0); + if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT) + error= (*end_select)(join,join_tab,1); } else if (join->send_row_on_empty_set()) - error= join->result->send_data(*join->fields); + rc= join->result->send_data(*join->fields); } else { error= sub_select(join,join_tab,0); - if (error >= 0) + if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) error= sub_select(join,join_tab,1); - if (error == -3) - error= 0; /* select_limit used */ + if (error == NESTED_LOOP_QUERY_LIMIT) + error= NESTED_LOOP_OK; /* select_limit used */ } + if (error == NESTED_LOOP_NO_MORE_ROWS) + error= NESTED_LOOP_OK; - if (error >= 0) + if (error == NESTED_LOOP_OK) { - error=0; + /* + Sic: this branch works even if rc != 0, e.g. when + send_data above returns an error. + */ if (!table) // If sending data to client { /* @@ -9004,10 +8960,12 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) */ join->join_free(0); // Unlock all cursors if (join->result->send_eof()) - error= 1; // Don't send error + rc= 1; // Don't send error } DBUG_PRINT("info",("%ld records output",join->send_records)); } + else + rc= -1; if (table) { int tmp, new_errno= 0; @@ -9025,40 +8983,42 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) table->file->print_error(new_errno,MYF(0)); } #ifndef DBUG_OFF - if (error) + if (rc) { DBUG_PRINT("error",("Error: do_select() failed")); } #endif - DBUG_RETURN(join->thd->net.report_error ? -1 : error); + DBUG_RETURN(join->thd->net.report_error ? -1 : rc); } -static int +static enum_nested_loop_state sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) { - int error; + enum_nested_loop_state rc; if (end_of_records) { - if ((error=flush_cached_records(join,join_tab,FALSE)) < 0) - return error; /* purecov: inspected */ - return sub_select(join,join_tab,end_of_records); + rc= flush_cached_records(join,join_tab,FALSE); + if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS) + rc= sub_select(join,join_tab,end_of_records); + return rc; } if (join->thd->killed) // If aborted by user { join->thd->send_kill_message(); - return -2; /* purecov: inspected */ + return NESTED_LOOP_KILLED; /* purecov: inspected */ } if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0) { if (!store_record_in_cache(&join_tab->cache)) - return 0; // There is more room in cache + return NESTED_LOOP_OK; // There is more room in cache return flush_cached_records(join,join_tab,FALSE); } - if ((error=flush_cached_records(join,join_tab,TRUE)) < 0) - return error; /* purecov: inspected */ - return sub_select(join,join_tab,end_of_records); /* Use ordinary select */ + rc= flush_cached_records(join, join_tab, TRUE); + if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS) + rc= sub_select(join, join_tab, end_of_records); + return rc; } /* @@ -9170,11 +9130,10 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) table of the embedding nested join, if any. RETURN - 0, if success - # of the error, otherwise + return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS. */ -static int +static enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) { join_tab->table->null_row=0; @@ -9182,206 +9141,258 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) return (*join_tab->next_select)(join,join_tab+1,end_of_records); int error; - JOIN_TAB *first_unmatched; - JOIN_TAB *tab; - /* Cache variables for faster loop */ - COND *select_cond= join_tab->select_cond; + enum_nested_loop_state rc; my_bool *report_error= &(join->thd->net.report_error); + READ_RECORD *info= &join_tab->read_record; - join->return_tab= join_tab; - - if (join_tab->last_inner) + if (join->resume_nested_loop) + { + /* If not the last table, plunge down the nested loop */ + if (join_tab < join->join_tab + join->tables - 1) + rc= (*join_tab->next_select)(join, join_tab + 1, 0); + else + { + join->resume_nested_loop= FALSE; + rc= NESTED_LOOP_OK; + } + } + else { - /* join_tab is the first inner table for an outer join operation. */ + join->return_tab= join_tab; - /* Set initial state of guard variables for this table.*/ - join_tab->found=0; - join_tab->not_null_compl= 1; + if (join_tab->last_inner) + { + /* join_tab is the first inner table for an outer join operation. */ - /* Set first_unmatched for the last inner table of this group */ - join_tab->last_inner->first_unmatched= join_tab; + /* Set initial state of guard variables for this table.*/ + join_tab->found=0; + join_tab->not_null_compl= 1; + + /* Set first_unmatched for the last inner table of this group */ + join_tab->last_inner->first_unmatched= join_tab; + } + join->thd->row_count= 0; + + error= (*join_tab->read_first_record)(join_tab); + rc= evaluate_join_record(join, join_tab, error, report_error); } - if (!(error=(*join_tab->read_first_record)(join_tab))) + while (rc == NESTED_LOOP_OK) { - bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize; - bool not_used_in_distinct=join_tab->not_used_in_distinct; - ha_rows found_records=join->found_records; - READ_RECORD *info= &join_tab->read_record; + error= info->read_record(info); + rc= evaluate_join_record(join, join_tab, error, report_error); + } - join->thd->row_count= 0; - do + if (rc == NESTED_LOOP_NO_MORE_ROWS && + join_tab->last_inner && !join_tab->found) + rc= evaluate_null_complemented_join_record(join, join_tab); + + if (rc == NESTED_LOOP_NO_MORE_ROWS) + rc= NESTED_LOOP_OK; + return rc; +} + + +/* + Process one record of the nested loop join. + + DESCRIPTION + This function will evaluate parts of WHERE/ON clauses that are + applicable to the partial record on hand and in case of success + submit this record to the next level of the nested loop. +*/ + +static enum_nested_loop_state +evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, + int error, my_bool *report_error) +{ + bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize; + bool not_used_in_distinct=join_tab->not_used_in_distinct; + ha_rows found_records=join->found_records; + COND *select_cond= join_tab->select_cond; + + if (error > 0 || (*report_error)) // Fatal error + return NESTED_LOOP_ERROR; + if (error < 0) + return NESTED_LOOP_NO_MORE_ROWS; + if (join->thd->killed) // Aborted by user + { + join->thd->send_kill_message(); + return NESTED_LOOP_KILLED; /* purecov: inspected */ + } + DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); + if (!select_cond || select_cond->val_int()) + { + /* + There is no select condition or the attached pushed down + condition is true => a match is found. + */ + bool found= 1; + while (join_tab->first_unmatched && found) { - if (join->thd->killed) // Aborted by user - { - join->thd->send_kill_message(); - return -2; /* purecov: inspected */ - } - DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); - if (!select_cond || select_cond->val_int()) + /* + The while condition is always false if join_tab is not + the last inner join table of an outer join operation. + */ + JOIN_TAB *first_unmatched= join_tab->first_unmatched; + /* + Mark that a match for current outer table is found. + This activates push down conditional predicates attached + to the all inner tables of the outer join. + */ + first_unmatched->found= 1; + for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) { - /* - There is no select condition or the attached pushed down - condition is true => a match is found. - */ - bool found= 1; - while (join_tab->first_unmatched && found) + /* Check all predicates that has just been activated. */ + /* + Actually all predicates non-guarded by first_unmatched->found + will be re-evaluated again. It could be fixed, but, probably, + it's not worth doing now. + */ + if (tab->select_cond && !tab->select_cond->val_int()) { - /* - The while condition is always false if join_tab is not - the last inner join table of an outer join operation. - */ - first_unmatched= join_tab->first_unmatched; - /* - Mark that a match for current outer table is found. - This activates push down conditional predicates attached - to the all inner tables of the outer join. - */ - first_unmatched->found= 1; - for (tab= first_unmatched; tab <= join_tab; tab++) - { - /* Check all predicates that has just been activated. */ + /* The condition attached to table tab is false */ + if (tab == join_tab) + found= 0; + else + { /* - Actually all predicates non-guarded by first_unmatched->found - will be re-evaluated again. It could be fixed, but, probably, - it's not worth doing now. - */ - if (tab->select_cond && !tab->select_cond->val_int()) - { - /* The condition attached to table tab is false */ - if (tab == join_tab) - found= 0; - else - { - /* - Set a return point if rejected predicate is attached - not to the last table of the current nest level. - */ - join->return_tab= tab; - return 0; - } - } + Set a return point if rejected predicate is attached + not to the last table of the current nest level. + */ + join->return_tab= tab; + return NESTED_LOOP_OK; } - /* - Check whether join_tab is not the last inner table - for another embedding outer join. - */ - if ((first_unmatched= first_unmatched->first_upper) && - first_unmatched->last_inner != join_tab) - first_unmatched= 0; - join_tab->first_unmatched= first_unmatched; } - - /* - It was not just a return to lower loop level when one - of the newly activated predicates is evaluated as false - (See above join->return_tab= tab). - */ - join->examined_rows++; - join->thd->row_count++; - - if (found) - { - if (not_exists_optimize) - break; - /* A match from join_tab is found for the current partial join. */ - if ((error=(*join_tab->next_select)(join, join_tab+1, 0)) < 0) - return error; - if (join->return_tab < join_tab) - return 0; - /* - Test if this was a SELECT DISTINCT query on a table that - was not in the field list; In this case we can abort if - we found a row, as no new rows can be added to the result. - */ - if (not_used_in_distinct && found_records != join->found_records) - return 0; - } - else - info->file->unlock_row(); } - else - { - /* - The condition pushed down to the table join_tab rejects all rows - with the beginning coinciding with the current partial join. - */ - join->examined_rows++; - join->thd->row_count++; - } - - } while (!(error=info->read_record(info)) && !(*report_error)); - } - if (error > 0 || (*report_error)) // Fatal error - return -1; - - if (join_tab->last_inner && !join_tab->found) - { - /* - The table join_tab is the first inner table of a outer join operation - and no matches has been found for the current outer row. - */ - JOIN_TAB *last_inner_tab= join_tab->last_inner; - for ( ; join_tab <= last_inner_tab ; join_tab++) - { - /* Change the the values of guard predicate variables. */ - join_tab->found= 1; - join_tab->not_null_compl= 0; - /* The outer row is complemented by nulls for each inner tables */ - restore_record(join_tab->table,s->default_values); // Make empty record - mark_as_null_row(join_tab->table); // For group by without error - select_cond= join_tab->select_cond; - /* Check all attached conditions for inner table rows. */ - if (select_cond && !select_cond->val_int()) - return 0; - } - join_tab--; - /* - The row complemented by nulls might be the first row - of embedding outer joins. - If so, perform the same actions as in the code - for the first regular outer join row above. - */ - for ( ; ; ) - { - first_unmatched= join_tab->first_unmatched; + /* + Check whether join_tab is not the last inner table + for another embedding outer join. + */ if ((first_unmatched= first_unmatched->first_upper) && first_unmatched->last_inner != join_tab) first_unmatched= 0; join_tab->first_unmatched= first_unmatched; - if (!first_unmatched) - break; - first_unmatched->found= 1; - for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) - { - if (tab->select_cond && !tab->select_cond->val_int()) - { - join->return_tab= tab; - return 0; - } - } } + /* - The row complemented by nulls satisfies all conditions - attached to inner tables. - Send the row complemented by nulls to be joined with the - remaining tables. - */ - if ((error=(*join_tab->next_select)(join, join_tab+1 ,0)) < 0) - return error; + It was not just a return to lower loop level when one + of the newly activated predicates is evaluated as false + (See above join->return_tab= tab). + */ + join->examined_rows++; + join->thd->row_count++; + + if (found) + { + enum enum_nested_loop_state rc; + if (not_exists_optimize) + return NESTED_LOOP_NO_MORE_ROWS; + /* A match from join_tab is found for the current partial join. */ + rc= (*join_tab->next_select)(join, join_tab+1, 0); + if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) + return rc; + if (join->return_tab < join_tab) + return NESTED_LOOP_OK; + /* + Test if this was a SELECT DISTINCT query on a table that + was not in the field list; In this case we can abort if + we found a row, as no new rows can be added to the result. + */ + if (not_used_in_distinct && found_records != join->found_records) + return NESTED_LOOP_OK; + } + else + join_tab->read_record.file->unlock_row(); } - return 0; + else + { + /* + The condition pushed down to the table join_tab rejects all rows + with the beginning coinciding with the current partial join. + */ + join->examined_rows++; + join->thd->row_count++; + } + return NESTED_LOOP_OK; } -static int +/* + DESCRIPTION + Construct a NULL complimented partial join record and feed it to the next + level of the nested loop. This function is used in case we have + an OUTER join and no matching record was found. +*/ + +static enum_nested_loop_state +evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab) +{ + /* + The table join_tab is the first inner table of a outer join operation + and no matches has been found for the current outer row. + */ + JOIN_TAB *last_inner_tab= join_tab->last_inner; + /* Cache variables for faster loop */ + COND *select_cond; + for ( ; join_tab <= last_inner_tab ; join_tab++) + { + /* Change the the values of guard predicate variables. */ + join_tab->found= 1; + join_tab->not_null_compl= 0; + /* The outer row is complemented by nulls for each inner tables */ + restore_record(join_tab->table,s->default_values); // Make empty record + mark_as_null_row(join_tab->table); // For group by without error + select_cond= join_tab->select_cond; + /* Check all attached conditions for inner table rows. */ + if (select_cond && !select_cond->val_int()) + return NESTED_LOOP_OK; + } + join_tab--; + /* + The row complemented by nulls might be the first row + of embedding outer joins. + If so, perform the same actions as in the code + for the first regular outer join row above. + */ + for ( ; ; ) + { + JOIN_TAB *first_unmatched= join_tab->first_unmatched; + if ((first_unmatched= first_unmatched->first_upper) && + first_unmatched->last_inner != join_tab) + first_unmatched= 0; + join_tab->first_unmatched= first_unmatched; + if (!first_unmatched) + break; + first_unmatched->found= 1; + for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) + { + if (tab->select_cond && !tab->select_cond->val_int()) + { + join->return_tab= tab; + return NESTED_LOOP_OK; + } + } + } + /* + The row complemented by nulls satisfies all conditions + attached to inner tables. + Send the row complemented by nulls to be joined with the + remaining tables. + */ + return (*join_tab->next_select)(join, join_tab+1, 0); +} + + +static enum_nested_loop_state flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) { + enum_nested_loop_state rc= NESTED_LOOP_OK; int error; READ_RECORD *info; if (!join_tab->cache.records) - return 0; /* Nothing to do */ + return NESTED_LOOP_OK; /* Nothing to do */ if (skip_last) (void) store_record_in_cache(&join_tab->cache); // Must save this for later if (join_tab->use_quick == 2) @@ -9396,7 +9407,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) if ((error=join_init_read_record(join_tab))) { reset_cache_write(&join_tab->cache); - return -error; /* No records or error */ + return error < 0 ? NESTED_LOOP_NO_MORE_ROWS: NESTED_LOOP_ERROR; } for (JOIN_TAB *tmp=join->join_tab; tmp != join_tab ; tmp++) @@ -9411,11 +9422,11 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) if (join->thd->killed) { join->thd->send_kill_message(); - return -2; // Aborted by user /* purecov: inspected */ + return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */ } SQL_SELECT *select=join_tab->select; - if (!error && (!join_tab->cache.select || - !join_tab->cache.select->skip_record())) + if (rc == NESTED_LOOP_OK && + (!join_tab->cache.select || !join_tab->cache.select->skip_record())) { uint i; reset_cache_read(&join_tab->cache); @@ -9423,11 +9434,14 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) { read_cached_record(join_tab); if (!select || !select->skip_record()) - if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0) + { + rc= (join_tab->next_select)(join,join_tab+1,0); + if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) { reset_cache_write(&join_tab->cache); - return error; /* purecov: inspected */ + return rc; } + } } } } while (!(error=info->read_record(info))); @@ -9436,10 +9450,10 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) read_cached_record(join_tab); // Restore current record reset_cache_write(&join_tab->cache); if (error > 0) // Fatal error - return -1; /* purecov: inspected */ + return NESTED_LOOP_ERROR; /* purecov: inspected */ for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++) tmp2->table->status=tmp2->status; - return 0; + return NESTED_LOOP_OK; } @@ -9905,13 +9919,32 @@ join_read_next_same_or_null(READ_RECORD *info) /***************************************************************************** - The different end of select functions - These functions returns < 0 when end is reached, 0 on ok and > 0 if a - fatal error (like table corruption) was detected + DESCRIPTION + Functions that end one nested loop iteration. Different functions + are used to support GROUP BY clause and to redirect records + to a table (e.g. in case of SELECT into a temporary table) or to the + network client. + + RETURN VALUES + NESTED_LOOP_OK - the record has been successfully handled + NESTED_LOOP_ERROR - a fatal error (like table corruption) + was detected + NESTED_LOOP_KILLED - thread shutdown was requested while processing + the record + NESTED_LOOP_QUERY_LIMIT - the record has been successfully handled; + additionally, the nested loop produced the + number of rows specified in the LIMIT clause + for the query + NESTED_LOOP_CURSOR_LIMIT - the record has been successfully handled; + additionally, there is a cursor and the nested + loop algorithm produced the number of rows + that is specified for current cursor fetch + operation. + All return values except NESTED_LOOP_OK abort the nested loop. *****************************************************************************/ /* ARGSUSED */ -static int +static enum_nested_loop_state end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -9920,14 +9953,14 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { int error; if (join->having && join->having->val_int() == 0) - DBUG_RETURN(0); // Didn't match having + DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having error=0; if (join->procedure) error=join->procedure->send_row(*join->fields); else if (join->do_send_rows) error=join->result->send_data(*join->fields); if (error) - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ if (++join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { @@ -9961,10 +9994,10 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), join->do_send_rows= 0; if (join->unit->fake_select_lex) join->unit->fake_select_lex->select_limit= HA_POS_ERROR; - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } - DBUG_RETURN(-3); // Abort nicely + DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely } else if (join->send_records >= join->fetch_limit) { @@ -9972,20 +10005,20 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), There is a server side cursor and all rows for this fetch request are sent. */ - DBUG_RETURN(-4); + DBUG_RETURN(NESTED_LOOP_CURSOR_LIMIT); } } else { if (join->procedure && join->procedure->end_of_records()) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); } - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* ARGSUSED */ -static int +static enum_nested_loop_state end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -10037,14 +10070,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } } if (error > 0) - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); if (join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { if (!(join->select_options & OPTION_FOUND_ROWS)) - DBUG_RETURN(-3); // Abort nicely + DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely join->do_send_rows=0; join->unit->select_limit_cnt = HA_POS_ERROR; } @@ -10054,14 +10087,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), There is a server side cursor and all rows for this fetch request are sent. */ - DBUG_RETURN(-4); + DBUG_RETURN(NESTED_LOOP_CURSOR_LIMIT); } } } else { if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); join->first_record=1; VOID(test_if_group_changed(join->group_fields)); } @@ -10069,33 +10102,32 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { copy_fields(&join->tmp_table_param); if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1])) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } if (update_sum_func(join->sum_funcs)) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* ARGSUSED */ -static int +static enum_nested_loop_state end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { TABLE *table=join->tmp_table; - int error; DBUG_ENTER("end_write"); if (join->thd->killed) // Aborted by user { join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } if (!end_of_records) { @@ -10120,6 +10152,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), #endif if (!join->having || join->having->val_int()) { + int error; join->found_records++; if ((error=table->file->write_row(table->record[0]))) { @@ -10128,28 +10161,28 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), goto end; if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error,1)) - DBUG_RETURN(-1); // Not a table_is_full error + DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error table->s->uniques=0; // To ensure rows are the same } if (++join->send_records >= join->tmp_table_param.end_write_records && join->do_send_rows) { if (!(join->select_options & OPTION_FOUND_ROWS)) - DBUG_RETURN(-3); + DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); join->do_send_rows=0; join->unit->select_limit_cnt = HA_POS_ERROR; - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } } end: - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* Group by searching after group record and updating it if possible */ /* ARGSUSED */ -static int +static enum_nested_loop_state end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -10159,11 +10192,11 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_ENTER("end_update"); if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); if (join->thd->killed) // Aborted by user { join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } join->found_records++; @@ -10187,9 +10220,9 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* @@ -10211,19 +10244,19 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) - DBUG_RETURN(-1); // Not a table_is_full error + DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error /* Change method to update rows */ table->file->ha_index_init(0); join->join_tab[join->tables-1].next_select=end_unique_update; } join->send_records++; - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* Like end_update, but this is done with unique constraints instead of keys */ -static int +static enum_nested_loop_state end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -10232,11 +10265,11 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_ENTER("end_unique_update"); if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); if (join->thd->killed) // Aborted by user { join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } init_tmptable_sum_functions(join->sum_funcs); @@ -10250,12 +10283,12 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if ((int) table->file->get_dup_key(error) < 0) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } if (table->file->rnd_pos(table->record[1],table->file->dupp_ref)) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } restore_record(table,record[1]); update_tmptable_sum_func(join->sum_funcs,table); @@ -10263,27 +10296,26 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } } - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* ARGSUSED */ -static int +static enum_nested_loop_state end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { TABLE *table=join->tmp_table; - int error; int idx= -1; DBUG_ENTER("end_write_group"); if (join->thd->killed) { // Aborted by user join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } if (!join->first_record || end_of_records || (idx=test_if_group_changed(join->group_fields)) >= 0) @@ -10302,28 +10334,27 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } copy_sum_funcs(join->sum_funcs, join->sum_funcs_end[send_group_parts]); - if (join->having && join->having->val_int() == 0) - error= -1; - else if ((error= table->file->write_row(table->record[0]))) + if (!join->having || join->having->val_int()) { - if (create_myisam_from_heap(join->thd, table, - &join->tmp_table_param, - error, 0)) - DBUG_RETURN(-1); + int error= table->file->write_row(table->record[0]); + if (error && create_myisam_from_heap(join->thd, table, + &join->tmp_table_param, + error, 0)) + DBUG_RETURN(NESTED_LOOP_ERROR); } if (join->rollup.state != ROLLUP::STATE_NONE) { if (join->rollup_write_data((uint) (idx+1), table)) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); } if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } else { if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); join->first_record=1; VOID(test_if_group_changed(join->group_fields)); } @@ -10332,17 +10363,17 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), copy_fields(&join->tmp_table_param); copy_funcs(join->tmp_table_param.items_to_copy); if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1])) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } if (update_sum_func(join->sum_funcs)) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } diff --git a/sql/sql_select.h b/sql/sql_select.h index c9a9b26d1b4..82efb62f7a3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -91,7 +91,15 @@ enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF, class JOIN; -typedef int (*Next_select_func)(JOIN *,struct st_join_table *,bool); +enum enum_nested_loop_state +{ + NESTED_LOOP_KILLED= -2, NESTED_LOOP_ERROR= -1, + NESTED_LOOP_OK= 0, NESTED_LOOP_NO_MORE_ROWS= 1, + NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4 +}; + +typedef enum_nested_loop_state +(*Next_select_func)(JOIN *, struct st_join_table *, bool); typedef int (*Read_record_func)(struct st_join_table *tab); @@ -162,6 +170,11 @@ class JOIN :public Sql_alloc uint send_group_parts; bool sort_and_group,first_record,full_join,group, no_field_update; bool do_send_rows; + /* + TRUE when we want to resume nested loop iterations when + fetching data from a cursor + */ + bool resume_nested_loop; table_map const_table_map,found_const_table_map,outer_join; ha_rows send_records,found_records,examined_rows,row_limit, select_limit; /* @@ -263,6 +276,7 @@ class JOIN :public Sql_alloc sort_and_group= 0; first_record= 0; do_send_rows= 1; + resume_nested_loop= FALSE; send_records= 0; found_records= 0; fetch_limit= HA_POS_ERROR; @@ -374,7 +388,7 @@ public: void reset_thd(THD *thd); int open(JOIN *join); - int fetch(ulong num_rows); + void fetch(ulong num_rows); void reset() { join= 0; } bool is_open() const { return join != 0; } void close(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 18c90d549ec..38944e3117d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2550,6 +2550,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, reg_ext, NullS); /* Resolve symlinks (for windows) */ fn_format(src_path, src_path, "", "", MYF(MY_UNPACK_FILENAME)); + if (lower_case_table_names) + my_casedn_str(files_charset_info, src_path); if (access(src_path, F_OK)) { my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table); diff --git a/sql/unireg.cc b/sql/unireg.cc index 929ca5c672e..95a383e0f01 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -685,6 +685,9 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values while ((field=it++)) { + /* + regfield don't have to be deleted as it's allocated with sql_alloc() + */ Field *regfield=make_field((char*) buff+field->offset,field->length, null_pos, null_count & 7, @@ -696,7 +699,8 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, field->interval, field->field_name, &table); - DBUG_ASSERT(regfield); + if (!regfield) + goto err; // End of memory if (!(field->flags & NOT_NULL_FLAG)) null_count++; @@ -730,7 +734,6 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),system_charset_info); else regfield->reset(); - delete regfield; } /* Fill not used startpos */ diff --git a/tests/index_corrupt.pl b/tests/index_corrupt.pl new file mode 100755 index 00000000000..19bf54f5d11 --- /dev/null +++ b/tests/index_corrupt.pl @@ -0,0 +1,212 @@ +#!/usr/bin/perl -w +# +# This is a test for a key cache bug (bug #10167) +# To expose the bug mysqld should be started with --key-buffer-size=64K +# + +$opt_loop_count=100000; # Change this to make test harder/easier + +##################### Standard benchmark inits ############################## + +use DBI; +use Getopt::Long; +use Benchmark; + +package main; + +$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert= + $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0; +$opt_host=$opt_user=$opt_password=""; $opt_db="test"; + +GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in", + "skip-delete","verbose","fast-insert","lock-tables","debug","fast", + "force","user=s","password=s") || die "Aborted"; +$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these + +$firsttable = "bench_f1"; +$secondtable = "bench_f2"; +$kill_file= "/tmp/mysqltest_index_corrupt.$$"; + +#### +#### Start timeing and start test +#### + +$start_time=new Benchmark; +if (!$opt_skip_create) +{ + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + $dbh->do("drop table if exists $firsttable, $secondtable"); + + print "Creating tables in $opt_db\n"; + $dbh->do("create table $firsttable ( +c_pollid INTEGER NOT NULL, +c_time BIGINT NOT NULL, +c_data DOUBLE NOT NULL, +c_error INTEGER NOT NULL, +c_warning INTEGER NOT NULL, +c_okay INTEGER NOT NULL, +c_unknown INTEGER NOT NULL, +c_rolled_up BIT NOT NULL, +INDEX t_mgmt_hist_r_i1 (c_pollid), +INDEX t_mgmt_hist_r_i2 (c_time), +INDEX t_mgmt_hist_r_i3 (c_rolled_up))") or die $DBI::errstr; + + $dbh->do("create table $secondtable ( +c_pollid INTEGER NOT NULL, +c_min_time BIGINT NOT NULL, +c_max_time BIGINT NOT NULL, +c_min_data DOUBLE NOT NULL, +c_max_data DOUBLE NOT NULL, +c_avg_data DOUBLE NOT NULL, +c_error INTEGER NOT NULL, +c_warning INTEGER NOT NULL, +c_okay INTEGER NOT NULL, +c_unknown INTEGER NOT NULL, +c_rolled_up BIT NOT NULL, +INDEX t_mgmt_hist_d_i1 (c_pollid), +INDEX t_mgmt_hist_d_i2 (c_min_time), +INDEX t_mgmt_hist_d_i3 (c_max_time), +INDEX t_mgmt_hist_d_i4 (c_rolled_up))") or die $DBI::errstr; + + + $dbh->disconnect; $dbh=0; # Close handler +} +$|= 1; # Autoflush + +#### +#### Start the tests +#### + +print "Running tests\n"; +insert_in_bench() if (($pid=fork()) == 0); $work{$pid}="insert"; +select_from_bench() if (($pid=fork()) == 0); $work{$pid}="insert-select; +delete_from_bench() if (($pid=fork()) == 0); $work{$pid}="delete"; + +$errors=0; +while (($pid=wait()) != -1) +{ + $ret=$?/256; + print "thread '" . $work{$pid} . "' finished with exit code $ret\n"; + $errors++ if ($ret != 0); +} + +if (!$opt_skip_delete && !$errors) +{ + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + $dbh->do("drop table $firsttable, $secondtable"); +} +print ($errors ? "Test failed\n" :"Test ok\n"); + +$end_time=new Benchmark; +print "Total time: " . + timestr(timediff($end_time, $start_time),"noc") . "\n"; + +unlink $kill_file; + +exit(0); + +# +# Insert records in the two tables +# + +sub insert_in_bench +{ + my ($dbh,$rows,$found,$i); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + for ($rows= 1; $rows <= $opt_loop_count ; $rows++) + { + $c_pollid = sprintf("%d",rand 1000); + $c_time = sprintf("%d",rand 100000); + $c_data = rand 1000000; + $test = rand 1; + $c_error=0; + $c_warning=0; + $c_okay=0; + $c_unknown=0; + if ($test < .8) { + $c_okay=1; + } elsif ($test <.9) { + $c_error=1; + } elsif ($test <.95) { + $c_warning=1; + } else { + $c_unknown=1; + } + $statement = "INSERT INTO $firsttable (c_pollid, c_time, c_data, c_error +, c_warning, c_okay, c_unknown, c_rolled_up) ". + "VALUES ($c_pollid,$c_time,$c_data,$c_error,$c_warning,$c_okay,$c_unknown,0)"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + } + + $dbh->disconnect; $dbh=0; + print "insert_in_bench: Inserted $rows rows\n"; + + # Kill other threads + open(KILLFILE, "> $kill_file"); + close(KILLFILE); + + exit(0); +} + + +sub select_from_bench +{ + my ($dbh,$rows,$cursor); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + for ($rows= 1; $rows < $opt_loop_count ; $rows++) + { + $t_value = rand 100000; + $t_value2 = $t_value+10000; + $statement = "INSERT INTO $secondtable (c_pollid, c_min_time, c_max_time +, c_min_data, c_max_data, c_avg_data, c_error, c_warning, c_okay, c_unknown, c_rolled_up) SELECT c_pollid, MIN(c_time), MAX(c_time), MIN(c_data), MAX(c_data), AVG(c_data), SUM(c_error), SUM(c_warning), SUM(c_okay), SUM(c_unknown), 0 FROM $firsttable WHERE (c_time>=$t_value) AND (c_time<$t_value2) AND (c_rolled_up=0) GROUP BY c_pollid"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + sleep 1; + if (-e $kill_file) + { + last; + } + } + print "select_from_bench: insert-select executed $rows times\n"; + exit(0); +} + + +sub delete_from_bench +{ + my ($dbh,$row, $t_value, $t2_value, $statement, $cursor); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + for ($rows= 1; $rows < $opt_loop_count ; $rows++) + { + $t_value = rand 50000; + $t2_value = $t_value + 50001; + $statement = "DELETE FROM $firsttable WHERE (c_time>$t_value) AND (c_time<$t2_value)"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + sleep 10; + if (-e $kill_file) + { + last; + } + } + print "delete: delete executed $rows times\n"; + exit(0); +} diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9b7c8281043..6ab5843803e 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -37,6 +37,7 @@ #define VER "2.1" #define MAX_TEST_QUERY_LENGTH 300 /* MAX QUERY BUFFER LENGTH */ #define MAX_KEY 64 +#define MAX_SERVER_ARGS 64 /* set default options */ static int opt_testcase = 0; @@ -55,6 +56,18 @@ static unsigned int test_count= 0; static unsigned int opt_count= 0; static unsigned int iter_count= 0; +static const char *opt_basedir= "./"; + +static int embedded_server_arg_count= 0; +static char *embedded_server_args[MAX_SERVER_ARGS]; + +static const char *embedded_server_groups[]= { + "server", + "embedded", + "mysql_client_test_SERVER", + NullS +}; + static time_t start_time, end_time; static double total_time; @@ -100,6 +113,8 @@ static void client_disconnect(); #define DIE_UNLESS(expr) \ ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) +#define DIE(expr) \ + die(__FILE__, __LINE__, #expr) void die(const char *file, int line, const char *expr) { @@ -7046,6 +7061,7 @@ static void test_set_option() bug #89 (reported by mark@mysql.com) */ +#ifndef EMBEDDED_LIBRARY static void test_prepare_grant() { int rc; @@ -7138,7 +7154,7 @@ static void test_prepare_grant() } } - +#endif /* Test a crash when invalid/corrupted .frm is used in the @@ -12597,7 +12613,7 @@ static void test_bug8330() const char *stmt_text; MYSQL_STMT *stmt[2]; int i, rc; - char *query= "select a,b from t1 where a=?"; + const char *query= "select a,b from t1 where a=?"; MYSQL_BIND bind[2]; long lval[2]; @@ -12708,7 +12724,7 @@ from t2);"); static void test_bug8378() { -#ifdef HAVE_CHARSET_gbk +#if defined(HAVE_CHARSET_gbk) && !defined(EMBEDDED_LIBRARY) MYSQL *lmysql; char out[9]; /* strlen(TEST_BUG8378)*2+1 */ int len; @@ -12788,7 +12804,7 @@ static void test_bug8722() } -MYSQL_STMT *open_cursor(char *query) +MYSQL_STMT *open_cursor(const char *query) { int rc; const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; @@ -12854,6 +12870,59 @@ static void test_bug9159() myquery(rc); } + +/* Crash when opening a cursor to a query with DISTICNT and no key */ + +static void test_bug9520() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char a[6]; + ulong a_len; + int rc, row_count= 0; + + myheader("test_bug9520"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5)," + " primary key (a, b, c))"); + rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), " + " ('a', 'b', 'c'), ('k', 'l', 'm')"); + myquery(rc); + + stmt= open_cursor("select distinct b from t1"); + + /* + Not crashes with: + stmt= open_cursor("select distinct a from t1"); + */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char*) a; + bind[0].buffer_length= sizeof(a); + bind[0].length= &a_len; + + mysql_stmt_bind_result(stmt, bind); + + while (!(rc= mysql_stmt_fetch(stmt))) + row_count++; + + DIE_UNLESS(rc == MYSQL_NO_DATA); + + printf("Fetched %d rows\n", row_count); + DBUG_ASSERT(row_count == 3); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -12863,6 +12932,8 @@ static char **defaults_argv; static struct my_option client_test_long_options[] = { + {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir, + (gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"count", 't', "Number of times test to be executed", (char **) &opt_count, (char **) &opt_count, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, {"database", 'D', "Database to use", (char **) &opt_db, (char **) &opt_db, @@ -12878,6 +12949,8 @@ static struct my_option client_test_long_options[] = 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection", (char **) &opt_port, (char **) &opt_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"server-arg", 'A', "Send embedded server this as a parameter.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"show-tests", 'T', "Show all tests' names", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, @@ -13079,6 +13152,7 @@ static struct my_tests_st my_tests[]= { { "test_bug8722", test_bug8722 }, { "test_bug8880", test_bug8880 }, { "test_bug9159", test_bug9159 }, + { "test_bug9520", test_bug9520 }, { 0, 0 } }; @@ -13113,6 +13187,25 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), else opt_silent++; break; + case 'A': + /* + When the embedded server is being tested, the test suite needs to be + able to pass command-line arguments to the embedded server so it can + locate the language files and data directory. The test suite + (mysql-test-run) never uses config files, just command-line options. + */ + if (!embedded_server_arg_count) + { + embedded_server_arg_count= 1; + embedded_server_args[0]= (char*) ""; + } + if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + !(embedded_server_args[embedded_server_arg_count++]= + my_strdup(argument, MYF(MY_FAE)))) + { + DIE("Can't use server argument"); + } + break; case 'T': { struct my_tests_st *fptr; @@ -13176,11 +13269,16 @@ int main(int argc, char **argv) DEBUGGER_OFF; MY_INIT(argv[0]); - + load_defaults("my", client_test_load_default_groups, &argc, &argv); defaults_argv= argv; get_options(&argc, &argv); + if (mysql_server_init(embedded_server_arg_count, + embedded_server_args, + (char**) embedded_server_groups)) + DIE("Can't initialize MySQL server"); + client_connect(); /* connect to server */ total_time= 0; @@ -13227,6 +13325,12 @@ int main(int argc, char **argv) client_disconnect(); /* disconnect from server */ free_defaults(defaults_argv); print_test_output(); + + while (embedded_server_arg_count > 1) + my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); + + mysql_server_end(); + my_end(0); exit(0); |