From f560422fa079b07a761a572ca4f9cf287c2cc47e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Tue, 10 Jan 2017 14:58:54 +0100 Subject: Big cleanup in config help and description Redundant help texts (one which only repeats the description) are deleted. Descriptions and help texts are trimmed. Some config options are moved, even across menus. No config option _names_ are changed. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- libbb/Config.src | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'libbb') diff --git a/libbb/Config.src b/libbb/Config.src index 172fbcc0e..c51640305 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -70,24 +70,13 @@ config FEATURE_FAST_TOP but code size is slightly bigger. config FEATURE_ETC_NETWORKS - bool "Support for /etc/networks" + bool "Support /etc/networks" default n help Enable support for network names in /etc/networks. This is a rarely used feature which allows you to use names instead of IP/mask pairs in route command. -config FEATURE_USE_TERMIOS - bool "Use termios to manipulate the screen" - default y - depends on MORE || TOP || POWERTOP - help - This option allows utilities such as 'more' and 'top' to determine - the size of the screen. If you leave this disabled, your utilities - that display things on the screen will be especially primitive and - will be unable to determine the current screen size, and will be - unable to move the cursor. - config FEATURE_EDITING bool "Command line editing" default y @@ -147,15 +136,11 @@ config FEATURE_TAB_COMPLETION bool "Tab completion" default y depends on FEATURE_EDITING - help - Enable tab completion. config FEATURE_USERNAME_COMPLETION bool "Username completion" default y depends on FEATURE_TAB_COMPLETION - help - Enable username completion. config FEATURE_EDITING_FANCY_PROMPT bool "Fancy shell prompts" -- cgit v1.2.3-55-g6feb From a8a075acfee7b31c4da00cf3500b67354339e3b9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Wed, 11 Jan 2017 10:52:24 +0100 Subject: busybox: stop depending on FEATURE_AUTOWIDTH for applet list Many other appletw don't - they unconditionally use get_terminal_wodth(), and here the amount of code saved by FEATURE_AUTOWIDTH=n is tiny. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- libbb/appletlib.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index bf6d4762c..7f0d62060 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -748,11 +748,7 @@ static int busybox_main(char **argv) int col; unsigned output_width; help: - output_width = 80; - if (ENABLE_FEATURE_AUTOWIDTH) { - /* Obtain the terminal width */ - output_width = get_terminal_width(2); - } + output_width = get_terminal_width(2); dup2(1, 2); full_write2_str(bb_banner); /* reuse const string */ -- cgit v1.2.3-55-g6feb From 01ccdd1d3c5221789f1ac62ced12b7984d910705 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Wed, 11 Jan 2017 16:17:59 +0100 Subject: libbb: consolidate the code to set termios unbuffered mode function old new delta set_termios_to_raw - 116 +116 count_lines 72 74 +2 powertop_main 1458 1430 -28 top_main 943 914 -29 more_main 759 714 -45 fsck_minix_main 2969 2921 -48 conspy_main 1197 1135 -62 rawmode 99 36 -63 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/6 up/down: 118/-275) Total: -157 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- editors/vi.c | 15 ++++----------- include/libbb.h | 4 ++++ libbb/lineedit.c | 2 +- libbb/xfuncs.c | 37 +++++++++++++++++++++++++++++++++++++ loginutils/getty.c | 2 +- loginutils/vlock.c | 8 ++++---- miscutils/chat.c | 1 + miscutils/conspy.c | 17 +++++++---------- miscutils/microcom.c | 1 + miscutils/rx.c | 1 + procps/powertop.c | 10 +++------- procps/top.c | 10 ++-------- shell/shell_common.c | 2 +- util-linux/fsck_minix.c | 6 +----- util-linux/more.c | 10 +++------- 15 files changed, 71 insertions(+), 55 deletions(-) (limited to 'libbb') diff --git a/editors/vi.c b/editors/vi.c index b56b04bdd..1e5ef44fb 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -354,7 +354,7 @@ struct globals { #if ENABLE_FEATURE_VI_USE_SIGNALS sigjmp_buf restart; // catch_sig() #endif - struct termios term_orig, term_vi; // remember what the cooked mode was + struct termios term_orig; // remember what the cooked mode was #if ENABLE_FEATURE_VI_COLON char *initial_cmds[3]; // currently 2 entries, NULL terminated #endif @@ -462,7 +462,6 @@ struct globals { #define context_end (G.context_end ) #define restart (G.restart ) #define term_orig (G.term_orig ) -#define term_vi (G.term_vi ) #define initial_cmds (G.initial_cmds ) #define readbuffer (G.readbuffer ) #define scr_out_buf (G.scr_out_buf ) @@ -2731,15 +2730,9 @@ static char *swap_context(char *p) // goto new context for '' command make this //----- Set terminal attributes -------------------------------- static void rawmode(void) { - tcgetattr(0, &term_orig); - term_vi = term_orig; - term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's - term_vi.c_iflag &= (~IXON & ~ICRNL); - term_vi.c_oflag &= (~ONLCR); - term_vi.c_cc[VMIN] = 1; - term_vi.c_cc[VTIME] = 0; - erase_char = term_vi.c_cc[VERASE]; - tcsetattr_stdin_TCSANOW(&term_vi); + // no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals + set_termios_to_raw(STDIN_FILENO, &term_orig, TERMIOS_RAW_CRNL); + erase_char = term_orig.c_cc[VERASE]; } static void cookmode(void) diff --git a/include/libbb.h b/include/libbb.h index abdc8c2b8..87f89c76d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1438,6 +1438,10 @@ int get_terminal_width_height(int fd, unsigned *width, unsigned *height) FAST_FU int get_terminal_width(int fd) FAST_FUNC; int tcsetattr_stdin_TCSANOW(const struct termios *tp) FAST_FUNC; +#define TERMIOS_CLEAR_ISIG (1 << 0) +#define TERMIOS_RAW_CRNL (1 << 1) +#define TERMIOS_RAW_INPUT (1 << 2) +int set_termios_to_raw(int fd, struct termios *oldterm, int flags) FAST_FUNC; /* NB: "unsigned request" is crucial! "int request" will break some arches! */ int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) __attribute__ ((format (printf, 4, 5))) FAST_FUNC; diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 31e392147..2a5d4e704 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -2325,7 +2325,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman /* ~ECHO, ~ECHONL: turn off echoing, including newline echoing */ /* ~ISIG: turn off INTR (ctrl-C), QUIT, SUSP */ new_settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG); - /* reads would block only if < 1 char is available */ + /* reads will block only if < 1 char is available */ new_settings.c_cc[VMIN] = 1; /* no timeout (reads block forever) */ new_settings.c_cc[VTIME] = 0; diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 45650edba..98d3531d6 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -311,6 +311,43 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) return tcsetattr(STDIN_FILENO, TCSANOW, tp); } +int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags) +{ +//TODO: lineedit, microcom and less might be adapted to use this too: +// grep for "tcsetattr" + + struct termios newterm; + + tcgetattr(fd, oldterm); + newterm = *oldterm; + + /* Turn off buffered input (ICANON) + * Turn off echoing (ECHO) + * and separate echoing of newline (ECHONL, normally off anyway) + */ + newterm.c_lflag &= ~(ICANON | ECHO | ECHONL); + if (flags & TERMIOS_CLEAR_ISIG) { + /* dont recognize INT/QUIT/SUSP chars */ + newterm.c_lflag &= ~ISIG; + } + /* reads will block only if < 1 char is available */ + newterm.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ + newterm.c_cc[VTIME] = 0; + if (flags & TERMIOS_RAW_CRNL) { + /* dont convert CR to NL on input */ + newterm.c_iflag &= ~(IXON | ICRNL); + /* dont convert NL to CR on output */ + newterm.c_oflag &= ~(ONLCR); + } + if (flags & TERMIOS_RAW_INPUT) { + /* dont convert anything on input */ + newterm.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); + } + + return tcsetattr(fd, TCSANOW, &newterm); +} + pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) { pid_t r; diff --git a/loginutils/getty.c b/loginutils/getty.c index 162c1697e..ba6c784a3 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -316,7 +316,7 @@ static void init_tty_attrs(int speed) /* non-raw output; add CR to each NL */ G.tty_attrs.c_oflag = OPOST | ONLCR; - /* reads would block only if < 1 char is available */ + /* reads will block only if < 1 char is available */ G.tty_attrs.c_cc[VMIN] = 1; /* no timeout (reads block forever) */ G.tty_attrs.c_cc[VTIME] = 0; diff --git a/loginutils/vlock.c b/loginutils/vlock.c index 52ae607c9..5ba6a8780 100644 --- a/loginutils/vlock.c +++ b/loginutils/vlock.c @@ -105,12 +105,12 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) ioctl(STDIN_FILENO, VT_SETMODE, &vtm); #endif +//TODO: use set_termios_to_raw() tcgetattr(STDIN_FILENO, &oterm); term = oterm; - term.c_iflag &= ~BRKINT; - term.c_iflag |= IGNBRK; - term.c_lflag &= ~ISIG; - term.c_lflag &= ~(ECHO | ECHOCTL); + term.c_iflag |= IGNBRK; /* ignore serial break (why? VTs don't have breaks, right?) */ + term.c_iflag &= ~BRKINT; /* redundant? "dont translate break to SIGINT" */ + term.c_lflag &= ~(ISIG | ECHO | ECHOCTL); /* ignore ^C ^Z, echo off */ tcsetattr_stdin_TCSANOW(&term); while (1) { diff --git a/miscutils/chat.c b/miscutils/chat.c index dc85f82fb..8df194534 100644 --- a/miscutils/chat.c +++ b/miscutils/chat.c @@ -213,6 +213,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) , signal_handler); #if ENABLE_FEATURE_CHAT_TTY_HIFI +//TODO: use set_termios_to_raw() tcgetattr(STDIN_FILENO, &tio); tio0 = tio; cfmakeraw(&tio); diff --git a/miscutils/conspy.c b/miscutils/conspy.c index d9d09d482..1f0278b47 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -363,7 +363,6 @@ int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int conspy_main(int argc UNUSED_PARAM, char **argv) { char tty_name[sizeof(DEV_TTY "NN")]; - struct termios termbuf; unsigned opts; unsigned ttynum; int poll_timeout_ms; @@ -414,16 +413,14 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) bb_signals(BB_FATAL_SIGS, cleanup); - // All characters must be passed through to us unaltered G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); - tcgetattr(G.kbd_fd, &G.term_orig); - termbuf = G.term_orig; - termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); - //termbuf.c_oflag &= ~(OPOST); - no, we still want \n -> \r\n - termbuf.c_lflag &= ~(ISIG|ICANON|ECHO); - termbuf.c_cc[VMIN] = 1; - termbuf.c_cc[VTIME] = 0; - tcsetattr(G.kbd_fd, TCSANOW, &termbuf); + + // All characters must be passed through to us unaltered + set_termios_to_raw(G.kbd_fd, &G.term_orig, 0 + | TERMIOS_CLEAR_ISIG // no signals on ^C ^Z etc + | TERMIOS_RAW_INPUT // turn off all input conversions + ); + //Note: termios.c_oflag &= ~(OPOST); - no, we still want \n -> \r\n poll_timeout_ms = 250; while (1) { diff --git a/miscutils/microcom.c b/miscutils/microcom.c index 04605d883..5a4bbefa9 100644 --- a/miscutils/microcom.c +++ b/miscutils/microcom.c @@ -33,6 +33,7 @@ // set raw tty mode static void xget1(int fd, struct termios *t, struct termios *oldt) { +//TODO: use set_termios_to_raw() tcgetattr(fd, oldt); *t = *oldt; cfmakeraw(t); diff --git a/miscutils/rx.c b/miscutils/rx.c index 660f66a89..36fc20a72 100644 --- a/miscutils/rx.c +++ b/miscutils/rx.c @@ -263,6 +263,7 @@ int rx_main(int argc UNUSED_PARAM, char **argv) termios_err = tcgetattr(read_fd, &tty); if (termios_err == 0) { +//TODO: use set_termios_to_raw() orig_tty = tty; cfmakeraw(&tty); tcsetattr(read_fd, TCSAFLUSH, &tty); diff --git a/procps/powertop.c b/procps/powertop.c index ce85f4191..ee806161f 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -683,7 +683,6 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) ullong cur_duration[MAX_CSTATE_COUNT]; char cstate_lines[MAX_CSTATE_COUNT + 2][64]; #if ENABLE_FEATURE_USE_TERMIOS - struct termios new_settings; struct pollfd pfd[1]; pfd[0].fd = 0; @@ -707,14 +706,11 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) puts("Collecting data for "DEFAULT_SLEEP_STR" seconds"); #if ENABLE_FEATURE_USE_TERMIOS - tcgetattr(0, (void *)&G.init_settings); - memcpy(&new_settings, &G.init_settings, sizeof(new_settings)); - /* Turn on unbuffered input, turn off echoing */ - new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); + /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */ + set_termios_to_raw(STDIN_FILENO, &G.init_settings, TERMIOS_CLEAR_ISIG); + bb_signals(BB_FATAL_SIGS, sig_handler); /* So we don't forget to reset term settings */ atexit(reset_term); - bb_signals(BB_FATAL_SIGS, sig_handler); - tcsetattr_stdin_TCSANOW(&new_settings); #endif /* Collect initial data */ diff --git a/procps/top.c b/procps/top.c index 491acb574..91bb8a883 100644 --- a/procps/top.c +++ b/procps/top.c @@ -1089,9 +1089,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) unsigned interval; char *str_interval, *str_iterations; unsigned scan_mask = TOP_MASK; -#if ENABLE_FEATURE_USE_TERMIOS - struct termios new_settings; -#endif INIT_G(); @@ -1141,11 +1138,8 @@ int top_main(int argc UNUSED_PARAM, char **argv) } #if ENABLE_FEATURE_USE_TERMIOS else { - tcgetattr(0, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(new_settings)); - /* unbuffered input, turn off echo */ - new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); - tcsetattr_stdin_TCSANOW(&new_settings); + /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */ + set_termios_to_raw(STDIN_FILENO, &initial_settings, TERMIOS_CLEAR_ISIG); } bb_signals(BB_FATAL_SIGS, sig_catcher); diff --git a/shell/shell_common.c b/shell/shell_common.c index 98d862744..549b17ca1 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -143,7 +143,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), // Setting it to more than 1 breaks poll(): // it blocks even if there's data. !?? //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; - /* reads would block only if < 1 char is available */ + /* reads will block only if < 1 char is available */ tty.c_cc[VMIN] = 1; /* no timeout (reads block forever) */ tty.c_cc[VTIME] = 0; diff --git a/util-linux/fsck_minix.c b/util-linux/fsck_minix.c index 0eaac17c0..2ab7530ea 100644 --- a/util-linux/fsck_minix.c +++ b/util-linux/fsck_minix.c @@ -1226,7 +1226,6 @@ void check2(void); int fsck_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int fsck_minix_main(int argc UNUSED_PARAM, char **argv) { - struct termios tmp; int retcode = 0; xfunc_error_retval = 8; @@ -1271,10 +1270,7 @@ int fsck_minix_main(int argc UNUSED_PARAM, char **argv) read_tables(); if (OPT_manual) { - tcgetattr(0, &sv_termios); - tmp = sv_termios; - tmp.c_lflag &= ~(ICANON | ECHO); - tcsetattr_stdin_TCSANOW(&tmp); + set_termios_to_raw(STDIN_FILENO, &sv_termios, 0); termios_set = 1; } diff --git a/util-linux/more.c b/util-linux/more.c index 7fa60bdba..debad81bd 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -43,7 +43,6 @@ struct globals { unsigned terminal_width; unsigned terminal_height; struct termios initial_settings; - struct termios new_settings; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { setup_common_bufsiz(); } while (0) @@ -101,12 +100,9 @@ int more_main(int argc UNUSED_PARAM, char **argv) return bb_cat(argv); G.tty_fileno = fileno(tty); - tcgetattr(G.tty_fileno, &G.initial_settings); - G.new_settings = G.initial_settings; - G.new_settings.c_lflag &= ~(ICANON | ECHO); - G.new_settings.c_cc[VMIN] = 1; - G.new_settings.c_cc[VTIME] = 0; - tcsetattr_tty_TCSANOW(&G.new_settings); + + /* Turn on unbuffered input; turn off echoing */ + set_termios_to_raw(G.tty_fileno, &G.initial_settings, 0); bb_signals(BB_FATAL_SIGS, gotsig); do { -- cgit v1.2.3-55-g6feb From b8935d00b0a60be24ee9073349c2a185cebbacd4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sun, 15 Jan 2017 20:16:27 +0100 Subject: sha512: use larger constant table only if sha512 is in fact selected function old new delta sha_K 640 256 -384 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- libbb/hash_md5_sha.c | 112 +++++++++++++++++++++++++++++-------------------- make_single_applets.sh | 5 ++- 2 files changed, 70 insertions(+), 47 deletions(-) (limited to 'libbb') diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 7e7d8da2f..d325584d7 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -9,6 +9,8 @@ #include "libbb.h" +#define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) + /* gcc 4.2.1 optimizes rotr64 better with inline than with macro * (for rotX32, there is no difference). Why? My guess is that * macro requires clever common subexpression elimination heuristics @@ -564,48 +566,59 @@ static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) * are the most significant half of first 64 elements * of the same array. */ -static const uint64_t sha_K[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, - 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, - 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, - 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, - 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, - 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, - 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, - 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, - 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, - 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, - 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, - 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, /* [64]+ are used for sha512 only */ - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, - 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, - 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +#undef K +#if NEED_SHA512 +typedef uint64_t sha_K_int; +# define K(v) v +#else +typedef uint32_t sha_K_int; +# define K(v) (uint32_t)(v >> 32) +#endif +static const sha_K_int sha_K[] = { + K(0x428a2f98d728ae22ULL), K(0x7137449123ef65cdULL), + K(0xb5c0fbcfec4d3b2fULL), K(0xe9b5dba58189dbbcULL), + K(0x3956c25bf348b538ULL), K(0x59f111f1b605d019ULL), + K(0x923f82a4af194f9bULL), K(0xab1c5ed5da6d8118ULL), + K(0xd807aa98a3030242ULL), K(0x12835b0145706fbeULL), + K(0x243185be4ee4b28cULL), K(0x550c7dc3d5ffb4e2ULL), + K(0x72be5d74f27b896fULL), K(0x80deb1fe3b1696b1ULL), + K(0x9bdc06a725c71235ULL), K(0xc19bf174cf692694ULL), + K(0xe49b69c19ef14ad2ULL), K(0xefbe4786384f25e3ULL), + K(0x0fc19dc68b8cd5b5ULL), K(0x240ca1cc77ac9c65ULL), + K(0x2de92c6f592b0275ULL), K(0x4a7484aa6ea6e483ULL), + K(0x5cb0a9dcbd41fbd4ULL), K(0x76f988da831153b5ULL), + K(0x983e5152ee66dfabULL), K(0xa831c66d2db43210ULL), + K(0xb00327c898fb213fULL), K(0xbf597fc7beef0ee4ULL), + K(0xc6e00bf33da88fc2ULL), K(0xd5a79147930aa725ULL), + K(0x06ca6351e003826fULL), K(0x142929670a0e6e70ULL), + K(0x27b70a8546d22ffcULL), K(0x2e1b21385c26c926ULL), + K(0x4d2c6dfc5ac42aedULL), K(0x53380d139d95b3dfULL), + K(0x650a73548baf63deULL), K(0x766a0abb3c77b2a8ULL), + K(0x81c2c92e47edaee6ULL), K(0x92722c851482353bULL), + K(0xa2bfe8a14cf10364ULL), K(0xa81a664bbc423001ULL), + K(0xc24b8b70d0f89791ULL), K(0xc76c51a30654be30ULL), + K(0xd192e819d6ef5218ULL), K(0xd69906245565a910ULL), + K(0xf40e35855771202aULL), K(0x106aa07032bbd1b8ULL), + K(0x19a4c116b8d2d0c8ULL), K(0x1e376c085141ab53ULL), + K(0x2748774cdf8eeb99ULL), K(0x34b0bcb5e19b48a8ULL), + K(0x391c0cb3c5c95a63ULL), K(0x4ed8aa4ae3418acbULL), + K(0x5b9cca4f7763e373ULL), K(0x682e6ff3d6b2b8a3ULL), + K(0x748f82ee5defb2fcULL), K(0x78a5636f43172f60ULL), + K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), + K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), + K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), +#if NEED_SHA512 /* [64]+ are used for sha512 only */ + K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), + K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), + K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), + K(0x113f9804bef90daeULL), K(0x1b710b35131c471bULL), + K(0x28db77f523047d84ULL), K(0x32caab7b40c72493ULL), + K(0x3c9ebe0a15c9bebcULL), K(0x431d67c49c100d4cULL), + K(0x4cc5d4becb3e42b6ULL), K(0x597f299cfc657e2aULL), + K(0x5fcb6fab3ad6faecULL), K(0x6c44198c4a475817ULL), +#endif }; +#undef K #undef Ch #undef Maj @@ -649,7 +662,7 @@ static void FAST_FUNC sha256_process_block64(sha256_ctx_t *ctx) * (I hope compiler is clever enough to just fetch * upper half) */ - uint32_t K_t = sha_K[t] >> 32; + uint32_t K_t = NEED_SHA512 ? (sha_K[t] >> 32) : sha_K[t]; uint32_t T1 = h + S1(e) + Ch(e, f, g) + K_t + W[t]; uint32_t T2 = S0(a) + Maj(a, b, c); h = g; @@ -679,6 +692,7 @@ static void FAST_FUNC sha256_process_block64(sha256_ctx_t *ctx) ctx->hash[7] += h; } +#if NEED_SHA512 static void FAST_FUNC sha512_process_block128(sha512_ctx_t *ctx) { unsigned t; @@ -740,7 +754,7 @@ static void FAST_FUNC sha512_process_block128(sha512_ctx_t *ctx) ctx->hash[6] += g; ctx->hash[7] += h; } - +#endif /* NEED_SHA512 */ void FAST_FUNC sha1_begin(sha1_ctx_t *ctx) { @@ -765,6 +779,7 @@ static const uint32_t init256[] = { 0x1f83d9ab, 0x5be0cd19, }; +#if NEED_SHA512 static const uint32_t init512_lo[] = { 0, 0, @@ -777,6 +792,7 @@ static const uint32_t init512_lo[] = { 0xfb41bd6b, 0x137e2179, }; +#endif /* NEED_SHA512 */ /* Initialize structure containing state of computation. (FIPS 180-2:5.3.2) */ @@ -787,6 +803,7 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) ctx->process_block = sha256_process_block64; } +#if NEED_SHA512 /* Initialize structure containing state of computation. (FIPS 180-2:5.3.3) */ void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) @@ -810,7 +827,7 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) ctx->total64[0] += len; if (ctx->total64[0] < len) ctx->total64[1]++; -#if 0 +# if 0 remaining = 128 - bufpos; /* Hash whole blocks */ @@ -825,7 +842,7 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) /* Save last, partial blosk */ memcpy(ctx->wbuffer + bufpos, buffer, len); -#else +# else while (1) { remaining = 128 - bufpos; if (remaining > len) @@ -843,8 +860,9 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) sha512_process_block128(ctx); /*bufpos = 0; - already is */ } -#endif +# endif } +#endif /* NEED_SHA512 */ /* Used also for sha256 */ void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) @@ -864,6 +882,7 @@ void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * hash_size); } +#if NEED_SHA512 void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) { unsigned bufpos = ctx->total64[0] & 127; @@ -897,6 +916,7 @@ void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) } memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); } +#endif /* NEED_SHA512 */ /* diff --git a/make_single_applets.sh b/make_single_applets.sh index 03a5c324f..8ad7a7406 100755 --- a/make_single_applets.sh +++ b/make_single_applets.sh @@ -30,9 +30,12 @@ done trap 'test -f .config.SV && mv .config.SV .config && touch .config' EXIT + # Turn on each applet individually and build single-applet executable +# (give config names on command line to build only those) +test $# = 0 && set -- $apps fail=0 -for app in $apps; do +for app; do # Only if it was indeed originally enabled... { echo "$cfg" | grep -q "^CONFIG_${app}=y\$"; } || continue -- cgit v1.2.3-55-g6feb From 16e7f697f8064a4e5fc2f8e181fe6a7b9602b1b3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Sun, 15 Jan 2017 20:59:32 +0100 Subject: libbb: eliminate redundant variable in sha_crypt function old new delta sha_crypt 1136 1130 -6 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- libbb/pw_encrypt_sha.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'libbb') diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c index 8aeaacad6..72e37e485 100644 --- a/libbb/pw_encrypt_sha.c +++ b/libbb/pw_encrypt_sha.c @@ -47,16 +47,17 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) unsigned cnt; unsigned rounds; char *cp; - char is_sha512; /* Analyze salt, construct already known part of result */ cnt = strlen(salt_data) + 1 + 43 + 1; - is_sha512 = salt_data[1]; - if (is_sha512 == '6') + _32or64 = 32; + if (salt_data[1] == '6') { /* sha512 */ + _32or64 *= 2; /*64*/ cnt += 43; + } result = resptr = xzalloc(cnt); /* will provide NUL terminator */ *resptr++ = '$'; - *resptr++ = is_sha512; + *resptr++ = salt_data[1]; *resptr++ = '$'; rounds = ROUNDS_DEFAULT; salt_data += 3; @@ -93,12 +94,10 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) sha_begin = (void*)sha256_begin; sha_hash = (void*)sha256_hash; sha_end = (void*)sha256_end; - _32or64 = 32; - if (is_sha512 == '6') { + if (_32or64 != 32) { sha_begin = (void*)sha512_begin; sha_hash = (void*)sha512_hash; sha_end = (void*)sha512_end; - _32or64 = 64; } /* Add KEY, SALT. */ @@ -200,7 +199,7 @@ do { \ unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ resptr = to64(resptr, w, N); \ } while (0) - if (is_sha512 == '5') { + if (_32or64 == 32) { /* sha256 */ unsigned i = 0; while (1) { unsigned j = i + 10; -- cgit v1.2.3-55-g6feb From 49ecee098d062b92fcf095e05e15779c32899646 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Tue, 24 Jan 2017 16:00:54 +0100 Subject: tls: add 2nd cipher_id, TLS_RSA_WITH_AES_128_CBC_SHA, so far it doesn't work Good news that TLS_RSA_WITH_AES_256_CBC_SHA256 still works with new code ;) This change adds inevitable extension to have different sized hashes and AES key sizes. In libbb, md5_end() and shaX_end() are extended to return result size instead of void - this helps *a lot* in tls (the cost is ~5 bytes per _end() function). Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- coreutils/md5_sha1_sum.c | 2 +- include/libbb.h | 42 +++-- libbb/hash_md5_sha.c | 15 +- libbb/hash_md5prime.c | 3 +- libbb/pw_encrypt_sha.c | 3 +- networking/tls.c | 413 ++++++++++++++++++++++++++++------------------- 6 files changed, 288 insertions(+), 190 deletions(-) (limited to 'libbb') diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index 76788554c..50111bd26 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c @@ -166,7 +166,7 @@ static uint8_t *hash_file(const char *filename, unsigned sha3_width) } context; uint8_t *hash_value; void FAST_FUNC (*update)(void*, const void*, size_t); - void FAST_FUNC (*final)(void*, void*); + unsigned FAST_FUNC (*final)(void*, void*); char hash_algo; src_fd = open_or_warn_stdin(filename); diff --git a/include/libbb.h b/include/libbb.h index ba3b1479e..b1ceb3278 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -713,18 +713,19 @@ struct hostent *xgethostbyname(const char *name) FAST_FUNC; // Also mount.c and inetd.c are using gethostbyname(), // + inet_common.c has additional IPv4-only stuff -#define SHA256_INSIZE 64 -#define SHA256_OUTSIZE 32 -#define AES_BLOCKSIZE 16 -#define AES128_KEYSIZE 16 -#define AES256_KEYSIZE 32 + +#define TLS_MAX_MAC_SIZE 32 +#define TLS_MAX_KEY_SIZE 32 struct tls_handshake_data; /* opaque */ typedef struct tls_state { - int ofd; - int ifd; + int ofd; + int ifd; - int min_encrypted_len_on_read; - uint8_t encrypt_on_write; + int min_encrypted_len_on_read; + uint16_t cipher_id; + uint8_t encrypt_on_write; + unsigned MAC_size; + unsigned key_size; uint8_t *outbuf; int outbuf_size; @@ -746,10 +747,12 @@ typedef struct tls_state { /*uint64_t read_seq64_be;*/ uint64_t write_seq64_be; - uint8_t client_write_MAC_key[SHA256_OUTSIZE]; - uint8_t server_write_MAC_key[SHA256_OUTSIZE]; - uint8_t client_write_key[AES256_KEYSIZE]; - uint8_t server_write_key[AES256_KEYSIZE]; + uint8_t *client_write_key; + uint8_t *server_write_key; + uint8_t client_write_MAC_key[TLS_MAX_MAC_SIZE]; + uint8_t server_write_MAC_k__[TLS_MAX_MAC_SIZE]; + uint8_t client_write_k__[TLS_MAX_KEY_SIZE]; + uint8_t server_write_k__[TLS_MAX_KEY_SIZE]; } tls_state_t; static inline tls_state_t *new_tls_state(void) @@ -760,6 +763,7 @@ static inline tls_state_t *new_tls_state(void) void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; void tls_run_copy_loop(tls_state_t *tls) FAST_FUNC; + void socket_want_pktinfo(int fd) FAST_FUNC; ssize_t send_to_from(int fd, void *buf, size_t len, int flags, const struct sockaddr *to, @@ -1799,19 +1803,23 @@ typedef struct sha3_ctx_t { } sha3_ctx_t; void md5_begin(md5_ctx_t *ctx) FAST_FUNC; void md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; -void md5_end(md5_ctx_t *ctx, void *resbuf) FAST_FUNC; +unsigned md5_end(md5_ctx_t *ctx, void *resbuf) FAST_FUNC; void sha1_begin(sha1_ctx_t *ctx) FAST_FUNC; #define sha1_hash md5_hash -void sha1_end(sha1_ctx_t *ctx, void *resbuf) FAST_FUNC; +unsigned sha1_end(sha1_ctx_t *ctx, void *resbuf) FAST_FUNC; void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; #define sha256_hash md5_hash #define sha256_end sha1_end void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; -void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; +unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; -void sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; +unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; +/* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */ +typedef struct md5_ctx_t md5sha_ctx_t; +#define md5sha_hash md5_hash +#define sha_end sha1_end extern uint32_t *global_crc32_table; uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index d325584d7..2a7247430 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -458,7 +458,7 @@ void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) * endian byte order, so that a byte-wise output yields to the wanted * ASCII representation of the message digest. */ -void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) +unsigned FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) { /* MD5 stores total in LE, need to swap on BE arches: */ common64_end(ctx, /*swap_needed:*/ BB_BIG_ENDIAN); @@ -472,6 +472,7 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) } memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * 4); + return sizeof(ctx->hash[0]) * 4; } @@ -865,7 +866,7 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) #endif /* NEED_SHA512 */ /* Used also for sha256 */ -void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) +unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) { unsigned hash_size; @@ -879,11 +880,13 @@ void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) for (i = 0; i < hash_size; ++i) ctx->hash[i] = SWAP_BE32(ctx->hash[i]); } - memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * hash_size); + hash_size *= sizeof(ctx->hash[0]); + memcpy(resbuf, ctx->hash, hash_size); + return hash_size; } #if NEED_SHA512 -void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) +unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) { unsigned bufpos = ctx->total64[0] & 127; @@ -915,6 +918,7 @@ void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) ctx->hash[i] = SWAP_BE64(ctx->hash[i]); } memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); + return sizeof(ctx->hash); } #endif /* NEED_SHA512 */ @@ -1450,7 +1454,7 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) #endif } -void FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) +unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) { /* Padding */ uint8_t *buf = (uint8_t*)ctx->state; @@ -1475,4 +1479,5 @@ void FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) /* Output */ memcpy(resbuf, ctx->state, 64); + return 64; } diff --git a/libbb/hash_md5prime.c b/libbb/hash_md5prime.c index e089a15f5..4b58d37ff 100644 --- a/libbb/hash_md5prime.c +++ b/libbb/hash_md5prime.c @@ -437,7 +437,7 @@ void FAST_FUNC md5_hash(const void *buffer, size_t inputLen, md5_ctx_t *context) * MD5 finalization. Ends an MD5 message-digest operation, * writing the message digest. */ -void FAST_FUNC md5_end(void *digest, md5_ctx_t *context) +unsigned FAST_FUNC md5_end(void *digest, md5_ctx_t *context) { unsigned idx, padLen; unsigned char bits[8]; @@ -457,4 +457,5 @@ void FAST_FUNC md5_end(void *digest, md5_ctx_t *context) /* Store state in digest */ memcpy32_cpu2le(digest, context->state, 16); + return 16; } diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c index 72e37e485..5457d7ab6 100644 --- a/libbb/pw_encrypt_sha.c +++ b/libbb/pw_encrypt_sha.c @@ -18,9 +18,10 @@ static char * NOINLINE sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) { +#undef sha_end void (*sha_begin)(void *ctx) FAST_FUNC; void (*sha_hash)(void *ctx, const void *buffer, size_t len) FAST_FUNC; - void (*sha_end)(void *ctx, void *resbuf) FAST_FUNC; + unsigned (*sha_end)(void *ctx, void *resbuf) FAST_FUNC; int _32or64; char *result, *resptr; diff --git a/networking/tls.c b/networking/tls.c index 8549a21da..a65da4ad4 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -18,10 +18,50 @@ #include "tls.h" -#define TLS_DEBUG 0 -#define TLS_DEBUG_HASH 0 -#define TLS_DEBUG_DER 0 -#define TLS_DEBUG_FIXED_SECRETS 0 +//Tested against kernel.org: +//TLS 1.2 +#define TLS_MAJ 3 +#define TLS_MIN 3 +//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box +//#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE +//#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE +//^^^^^^^^^^^^^^^^^^^^^^^ (tested b/c this one doesn't req server certs... no luck, server refuses it) +//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 // SSL_ALERT_HANDSHAKE_FAILURE +//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE +//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 // ok, recvs SERVER_KEY_EXCHANGE +//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 +//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE +//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 +//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE +//#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE +//#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this? + +// works against "openssl s_server -cipher NULL" +// and against wolfssl-3.9.10-stable/examples/server/server.c: +//#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) + +// works against wolfssl-3.9.10-stable/examples/server/server.c +// works for kernel.org +// does not work for cdn.kernel.org (e.g. downloading an actual tarball, not a web page) +// getting alert 40 "handshake failure" at once +// with GNU Wget 1.18, they agree on TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) cipher +// fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-SHA256 +// fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-GCM-SHA384 +// fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA256 +// ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-GCM-SHA256 +// ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA +// (TLS_RSA_WITH_AES_128_CBC_SHA - in TLS 1.2 it's mandated to be always supported) +#define CIPHER_ID1 TLS_RSA_WITH_AES_256_CBC_SHA256 // no SERVER_KEY_EXCHANGE from peer +// Does not work yet: +//#define CIPHER_ID2 TLS_RSA_WITH_AES_128_CBC_SHA +#define CIPHER_ID2 0 + + +#define TLS_DEBUG 1 +#define TLS_DEBUG_HASH 1 +#define TLS_DEBUG_DER 1 +#define TLS_DEBUG_FIXED_SECRETS 1 #if 0 # define dump_raw_out(...) dump_hex(__VA_ARGS__) #else @@ -124,52 +164,26 @@ #define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 /* 49201 */ #define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 /* 49202 */ -//Tested against kernel.org: -//TLS 1.2 -#define TLS_MAJ 3 -#define TLS_MIN 3 -//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box -//#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE -//#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE -//^^^^^^^^^^^^^^^^^^^^^^^ (tested b/c this one doesn't req server certs... no luck, server refuses it) -//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 // SSL_ALERT_HANDSHAKE_FAILURE -//#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE -//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 // ok, recvs SERVER_KEY_EXCHANGE -//#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 -//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 -//#define CIPHER_ID TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE -//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 -//#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE -//#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE -//#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this? +/* Might go to libbb.h */ +#define TLS_MAX_CRYPTBLOCK_SIZE 16 +#define TLS_MAX_OUTBUF (1 << 14) -// works against "openssl s_server -cipher NULL" -// and against wolfssl-3.9.10-stable/examples/server/server.c: -//#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) +enum { + SHA_INSIZE = 64, + SHA1_OUTSIZE = 20, + SHA256_OUTSIZE = 32, -// works against wolfssl-3.9.10-stable/examples/server/server.c -// works for kernel.org -// does not work for cdn.kernel.org (e.g. downloading an actual tarball, not a web page) -// getting alert 40 "handshake failure" at once -// with GNU Wget 1.18, they agree on TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) cipher -// fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-SHA256 -// fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-GCM-SHA384 -// fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA256 -// ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-GCM-SHA256 -// ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA -// (TLS_RSA_WITH_AES_128_CBC_SHA - in TLS 1.2 it's mandated to be always supported) -#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // no SERVER_KEY_EXCHANGE from peer + AES_BLOCKSIZE = 16, + AES128_KEYSIZE = 16, + AES256_KEYSIZE = 32, -enum { RSA_PREMASTER_SIZE = 48, RECHDR_LEN = 5, - MAX_TLS_RECORD = (1 << 14), /* 8 = 3+5. 3 extra bytes result in record data being 32-bit aligned */ OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */ - OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */ - MAX_OUTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX, + OUTBUF_SFX = TLS_MAX_MAC_SIZE + TLS_MAX_CRYPTBLOCK_SIZE, /* MAC + padding */ // RFC 5246 // | 6.2.1. Fragmentation @@ -205,7 +219,7 @@ enum { // | length // | The length (in bytes) of the following TLSCiphertext.fragment. // | The length MUST NOT exceed 2^14 + 2048. - MAX_INBUF = (1 << 14) + 2048, + MAX_INBUF = RECHDR_LEN + (1 << 14) + 2048, }; struct record_hdr { @@ -215,12 +229,17 @@ struct record_hdr { }; struct tls_handshake_data { - sha256_ctx_t handshake_sha256_ctx; + /* In bbox, md5/sha1/sha256 ctx's are the same structure */ + md5sha_ctx_t handshake_hash_ctx; + uint8_t client_and_server_rand32[2 * 32]; uint8_t master_secret[48]; //TODO: store just the DER key here, parse/use/delete it when sending client key //this way it will stay key type agnostic here. psRsaKey_t server_rsa_pub_key; + + unsigned saved_client_hello_size; + uint8_t saved_client_hello[1]; }; @@ -275,37 +294,41 @@ void tls_get_random(void *buf, unsigned len) xfunc_die(); } -//TODO rename this to sha256_hash, and sha256_hash -> sha256_update -static void hash_sha256(uint8_t out[SHA256_OUTSIZE], const void *data, unsigned size) +/* Nondestructively see the current hash value */ +static unsigned sha_peek(md5sha_ctx_t *ctx, void *buffer) { - sha256_ctx_t ctx; - sha256_begin(&ctx); - sha256_hash(&ctx, data, size); - sha256_end(&ctx, out); + md5sha_ctx_t ctx_copy = *ctx; /* struct copy */ + return sha_end(&ctx_copy, buffer); } -/* Nondestructively see the current hash value */ -static void sha256_peek(sha256_ctx_t *ctx, void *buffer) +static ALWAYS_INLINE unsigned get_handshake_hash(tls_state_t *tls, void *buffer) { - sha256_ctx_t ctx_copy = *ctx; - sha256_end(&ctx_copy, buffer); + return sha_peek(&tls->hsd->handshake_hash_ctx, buffer); } -#if TLS_DEBUG_HASH -static void sha256_hash_dbg(const char *fmt, sha256_ctx_t *ctx, const void *buffer, size_t len) +#if !TLS_DEBUG_HASH +# define hash_handshake(tls, fmt, buffer, len) \ + hash_handshake(tls, buffer, len) +#endif +static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer, unsigned len) { - uint8_t h[SHA256_OUTSIZE]; - - sha256_hash(ctx, buffer, len); - dump_hex(fmt, buffer, len); - dbg(" (%u) ", (int)len); - sha256_peek(ctx, h); - dump_hex("%s\n", h, SHA256_OUTSIZE); -} -#else -# define sha256_hash_dbg(fmt, ctx, buffer, len) \ - sha256_hash(ctx, buffer, len) + md5sha_hash(&tls->hsd->handshake_hash_ctx, buffer, len); +#if TLS_DEBUG_HASH + { + uint8_t h[TLS_MAX_MAC_SIZE]; + dump_hex(fmt, buffer, len); + dbg(" (%u bytes) ", (int)len); + len = sha_peek(&tls->hsd->handshake_hash_ctx, h); + if (len == SHA1_OUTSIZE) + dump_hex("sha1:%s\n", h, len); + else + if (len == SHA256_OUTSIZE) + dump_hex("sha256:%s\n", h, len); + else + dump_hex("sha???:%s\n", h, len); + } #endif +} // RFC 2104 // HMAC(key, text) based on a hash H (say, sha256) is: @@ -317,12 +340,13 @@ static void sha256_hash_dbg(const char *fmt, sha256_ctx_t *ctx, const void *buff // if we often need HMAC hmac with the same key. // // text is often given in disjoint pieces. -static void hmac_sha256_precomputed_v(uint8_t out[SHA256_OUTSIZE], - sha256_ctx_t *hashed_key_xor_ipad, - sha256_ctx_t *hashed_key_xor_opad, +static unsigned hmac_sha_precomputed_v(uint8_t *out, + md5sha_ctx_t *hashed_key_xor_ipad, + md5sha_ctx_t *hashed_key_xor_opad, va_list va) { uint8_t *text; + unsigned len; /* hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ /* hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ @@ -330,24 +354,24 @@ static void hmac_sha256_precomputed_v(uint8_t out[SHA256_OUTSIZE], /* calculate out = H((key XOR ipad) + text) */ while ((text = va_arg(va, uint8_t*)) != NULL) { unsigned text_size = va_arg(va, unsigned); - sha256_hash(hashed_key_xor_ipad, text, text_size); + md5sha_hash(hashed_key_xor_ipad, text, text_size); } - sha256_end(hashed_key_xor_ipad, out); + len = sha_end(hashed_key_xor_ipad, out); /* out = H((key XOR opad) + out) */ - sha256_hash(hashed_key_xor_opad, out, SHA256_OUTSIZE); - sha256_end(hashed_key_xor_opad, out); + md5sha_hash(hashed_key_xor_opad, out, len); + return sha_end(hashed_key_xor_opad, out); } -static void hmac_sha256(uint8_t out[SHA256_OUTSIZE], uint8_t *key, unsigned key_size, ...) +static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) { - sha256_ctx_t hashed_key_xor_ipad; - sha256_ctx_t hashed_key_xor_opad; - uint8_t key_xor_ipad[SHA256_INSIZE]; - uint8_t key_xor_opad[SHA256_INSIZE]; + md5sha_ctx_t hashed_key_xor_ipad; + md5sha_ctx_t hashed_key_xor_opad; + uint8_t key_xor_ipad[SHA_INSIZE]; + uint8_t key_xor_opad[SHA_INSIZE]; uint8_t tempkey[SHA256_OUTSIZE]; va_list va; - int i; + unsigned i; va_start(va, key_size); @@ -355,27 +379,38 @@ static void hmac_sha256(uint8_t out[SHA256_OUTSIZE], uint8_t *key, unsigned key_ // block length of the hash function. Applications that use keys longer // than INSIZE bytes will first hash the key using H and then use the // resultant OUTSIZE byte string as the actual key to HMAC." - if (key_size > SHA256_INSIZE) { - hash_sha256(tempkey, key, key_size); - key = tempkey; - key_size = SHA256_OUTSIZE; + if (key_size > SHA_INSIZE) { + md5sha_ctx_t ctx; + if (tls->MAC_size == SHA256_OUTSIZE) + sha256_begin(&ctx); + else + sha1_begin(&ctx); + md5sha_hash(&ctx, key, key_size); + key_size = sha_end(&ctx, tempkey); } for (i = 0; i < key_size; i++) { key_xor_ipad[i] = key[i] ^ 0x36; key_xor_opad[i] = key[i] ^ 0x5c; } - for (; i < SHA256_INSIZE; i++) { + for (; i < SHA_INSIZE; i++) { key_xor_ipad[i] = 0x36; key_xor_opad[i] = 0x5c; } - sha256_begin(&hashed_key_xor_ipad); - sha256_hash(&hashed_key_xor_ipad, key_xor_ipad, SHA256_INSIZE); - sha256_begin(&hashed_key_xor_opad); - sha256_hash(&hashed_key_xor_opad, key_xor_opad, SHA256_INSIZE); - hmac_sha256_precomputed_v(out, &hashed_key_xor_ipad, &hashed_key_xor_opad, va); + if (tls->MAC_size == SHA256_OUTSIZE) { + sha256_begin(&hashed_key_xor_ipad); + sha256_begin(&hashed_key_xor_opad); + } else { + sha1_begin(&hashed_key_xor_ipad); + sha1_begin(&hashed_key_xor_opad); + } + md5sha_hash(&hashed_key_xor_ipad, key_xor_ipad, SHA_INSIZE); + md5sha_hash(&hashed_key_xor_opad, key_xor_opad, SHA_INSIZE); + + i = hmac_sha_precomputed_v(out, &hashed_key_xor_ipad, &hashed_key_xor_opad, va); va_end(va); + return i; } // RFC 5246: @@ -406,40 +441,41 @@ static void hmac_sha256(uint8_t out[SHA256_OUTSIZE], uint8_t *key, unsigned key_ // PRF(secret, label, seed) = P_<hash>(secret, label + seed) // // The label is an ASCII string. -static void prf_hmac_sha256( +static void prf_hmac(tls_state_t *tls, uint8_t *outbuf, unsigned outbuf_size, uint8_t *secret, unsigned secret_size, const char *label, uint8_t *seed, unsigned seed_size) { - uint8_t a[SHA256_OUTSIZE]; + uint8_t a[TLS_MAX_MAC_SIZE]; uint8_t *out_p = outbuf; unsigned label_size = strlen(label); + unsigned MAC_size = tls->MAC_size; /* In P_hash() calculation, "seed" is "label + seed": */ #define SEED label, label_size, seed, seed_size #define SECRET secret, secret_size -#define A a, (int)(sizeof(a)) +#define A a, MAC_size /* A(1) = HMAC_hash(secret, seed) */ - hmac_sha256(a, SECRET, SEED, NULL); -//TODO: convert hmac_sha256 to precomputed + hmac(tls, a, SECRET, SEED, NULL); +//TODO: convert hmac to precomputed for(;;) { /* HMAC_hash(secret, A(1) + seed) */ - if (outbuf_size <= SHA256_OUTSIZE) { + if (outbuf_size <= MAC_size) { /* Last, possibly incomplete, block */ /* (use a[] as temp buffer) */ - hmac_sha256(a, SECRET, A, SEED, NULL); + hmac(tls, a, SECRET, A, SEED, NULL); memcpy(out_p, a, outbuf_size); return; } /* Not last block. Store directly to result buffer */ - hmac_sha256(out_p, SECRET, A, SEED, NULL); - out_p += SHA256_OUTSIZE; - outbuf_size -= SHA256_OUTSIZE; + hmac(tls, out_p, SECRET, A, SEED, NULL); + out_p += MAC_size; + outbuf_size -= MAC_size; /* A(2) = HMAC_hash(secret, A(1)) */ - hmac_sha256(a, SECRET, A, NULL); + hmac(tls, a, SECRET, A, NULL); } #undef A #undef SECRET @@ -484,11 +520,12 @@ static void tls_free_outbuf(tls_state_t *tls) static void *tls_get_outbuf(tls_state_t *tls, int len) { - if (len > MAX_OUTBUF) + if (len > TLS_MAX_OUTBUF) xfunc_die(); - if (tls->outbuf_size < len + OUTBUF_PFX + OUTBUF_SFX) { - tls->outbuf_size = len + OUTBUF_PFX + OUTBUF_SFX; - tls->outbuf = xrealloc(tls->outbuf, tls->outbuf_size); + len += OUTBUF_PFX + OUTBUF_SFX; + if (tls->outbuf_size < len) { + tls->outbuf_size = len; + tls->outbuf = xrealloc(tls->outbuf, len); } return tls->outbuf + OUTBUF_PFX; } @@ -500,7 +537,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) uint8_t padding_length; xhdr = (void*)(buf - RECHDR_LEN); - if (CIPHER_ID != TLS_RSA_WITH_NULL_SHA256) + if (tls->cipher_id != TLS_RSA_WITH_NULL_SHA256) xhdr = (void*)(buf - RECHDR_LEN - AES_BLOCKSIZE); /* place for IV */ xhdr->type = type; @@ -511,16 +548,16 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) xhdr->len16_lo = size & 0xff; /* Calculate MAC signature */ -//TODO: convert hmac_sha256 to precomputed - hmac_sha256(buf + size, - tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key), - &tls->write_seq64_be, sizeof(tls->write_seq64_be), - xhdr, RECHDR_LEN, - buf, size, - NULL); + hmac(tls, buf + size, /* result */ + tls->client_write_MAC_key, tls->MAC_size, + &tls->write_seq64_be, sizeof(tls->write_seq64_be), + xhdr, RECHDR_LEN, + buf, size, + NULL + ); tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(tls->write_seq64_be)); - size += SHA256_OUTSIZE; + size += tls->MAC_size; // RFC 5246 // 6.2.3.1. Null or Standard Stream Cipher @@ -555,7 +592,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) // -------- ----------- ---------- -------------- // SHA HMAC-SHA1 20 20 // SHA256 HMAC-SHA256 32 32 - if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) { + if (tls->cipher_id == TLS_RSA_WITH_NULL_SHA256) { /* No encryption, only signing */ xhdr->len16_hi = size >> 8; xhdr->len16_lo = size & 0xff; @@ -603,7 +640,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) /* Fill IV and padding in outbuf */ tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */ - dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, SHA256_OUTSIZE); + dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, tls->MAC_size); // RFC is talking nonsense: // "Padding that is added to force the length of the plaintext to be // an integral multiple of the block cipher's block length." @@ -628,7 +665,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) { psCipherContext_t ctx; psAesInit(&ctx, buf - AES_BLOCKSIZE, /* IV */ - tls->client_write_key, sizeof(tls->client_write_key) + tls->client_write_key, tls->key_size /* selects 128/256 */ ); psAesEncrypt(&ctx, buf, /* plaintext */ @@ -648,9 +685,9 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) dbg("wrote %u bytes\n", (int)RECHDR_LEN + size); } -static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size) +static void xwrite_handshake_record(tls_state_t *tls, unsigned size) { - if (!tls->encrypt_on_write) { + //if (!tls->encrypt_on_write) { uint8_t *buf = tls->outbuf + OUTBUF_PFX; struct record_hdr *xhdr = (void*)(buf - RECHDR_LEN); @@ -662,8 +699,20 @@ static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size) dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size); xwrite(tls->ofd, xhdr, RECHDR_LEN + size); dbg("wrote %u bytes\n", (int)RECHDR_LEN + size); + // return; + //} + //xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE); +} + +static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size) +{ + if (!tls->encrypt_on_write) { + uint8_t *buf; + + xwrite_handshake_record(tls, size); /* Handshake hash does not include record headers */ - sha256_hash_dbg(">> sha256:%s", &tls->hsd->handshake_sha256_ctx, buf, size); + buf = tls->outbuf + OUTBUF_PFX; + hash_handshake(tls, ">> hash:%s", buf, size); return; } xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE); @@ -765,7 +814,7 @@ static int tls_xread_record(tls_state_t *tls) sz = target - RECHDR_LEN; /* Needs to be decrypted? */ - if (tls->min_encrypted_len_on_read > SHA256_OUTSIZE) { + if (tls->min_encrypted_len_on_read > tls->MAC_size) { psCipherContext_t ctx; uint8_t *p = tls->inbuf + RECHDR_LEN; int padding_len; @@ -777,7 +826,7 @@ static int tls_xread_record(tls_state_t *tls) } /* Decrypt content+MAC+padding, moving it over IV in the process */ psAesInit(&ctx, p, /* IV */ - tls->server_write_key, sizeof(tls->server_write_key) + tls->server_write_key, tls->key_size /* selects 128/256 */ ); sz -= AES_BLOCKSIZE; /* we will overwrite IV now */ psAesDecrypt(&ctx, @@ -788,7 +837,7 @@ static int tls_xread_record(tls_state_t *tls) padding_len = p[sz - 1]; dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[0], padding_len); padding_len++; - sz -= SHA256_OUTSIZE + padding_len; /* drop MAC and padding */ + sz -= tls->MAC_size + padding_len; /* drop MAC and padding */ //if (sz < 0) // bb_error_msg_and_die("bad padding size:%u", padding_len); } else { @@ -834,8 +883,10 @@ static int tls_xread_record(tls_state_t *tls) /* RFC 5246 is not saying it explicitly, but sha256 hash * in our FINISHED record must include data of incoming packets too! */ - if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE) { - sha256_hash_dbg("<< sha256:%s", &tls->hsd->handshake_sha256_ctx, tls->inbuf + RECHDR_LEN, sz); + if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE + && tls->MAC_size != 0 /* do we know which hash to use? (server_hello() does not!) */ + ) { + hash_handshake(tls, "<< hash:%s", tls->inbuf + RECHDR_LEN, sz); } end: dbg("got block len:%u\n", sz); @@ -1088,7 +1139,7 @@ static ALWAYS_INLINE void fill_handshake_record_hdr(void *buf, unsigned type, un h->len24_lo = len & 0xff; } -static void send_client_hello(tls_state_t *tls, const char *sni) +static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) { struct client_hello { uint8_t type; @@ -1098,7 +1149,7 @@ static void send_client_hello(tls_state_t *tls, const char *sni) uint8_t session_id_len; /* uint8_t session_id[]; */ uint8_t cipherid_len16_hi, cipherid_len16_lo; - uint8_t cipherid[2 * 2]; /* actually variable */ + uint8_t cipherid[2 * (2 + !!CIPHER_ID2)]; /* actually variable */ uint8_t comprtypes_len; uint8_t comprtypes[1]; /* actually variable */ /* Extensions (SNI shown): @@ -1136,17 +1187,19 @@ static void send_client_hello(tls_state_t *tls, const char *sni) tls_get_random(record->rand32, sizeof(record->rand32)); if (TLS_DEBUG_FIXED_SECRETS) memset(record->rand32, 0x11, sizeof(record->rand32)); - memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32)); /* record->session_id_len = 0; - already is */ /* record->cipherid_len16_hi = 0; */ - record->cipherid_len16_lo = 2 * 2; - if ((CIPHER_ID >> 8) != 0) - record->cipherid[0] = CIPHER_ID >> 8; - record->cipherid[1] = CIPHER_ID & 0xff; + record->cipherid_len16_lo = sizeof(record->cipherid); /* RFC 5746 Renegotiation Indication Extension - some servers will refuse to work with us otherwise */ - /*record->cipherid[2] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV >> 8; - zero */ - record->cipherid[3] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV & 0xff; + /*record->cipherid[0] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV >> 8; - zero */ + record->cipherid[1] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV & 0xff; + if ((CIPHER_ID1 >> 8) != 0) record->cipherid[2] = CIPHER_ID1 >> 8; + /*************************/ record->cipherid[3] = CIPHER_ID1 & 0xff; +#if CIPHER_ID2 + if ((CIPHER_ID2 >> 8) != 0) record->cipherid[4] = CIPHER_ID2 >> 8; + /*************************/ record->cipherid[5] = CIPHER_ID2 & 0xff; +#endif record->comprtypes_len = 1; /* record->comprtypes[0] = 0; */ @@ -1168,7 +1221,14 @@ static void send_client_hello(tls_state_t *tls, const char *sni) } dbg(">> CLIENT_HELLO\n"); - xwrite_and_update_handshake_hash(tls, len); + /* Can hash it only when we know which MAC hash to use */ + /*xwrite_and_update_handshake_hash(tls, len); - WRONG! */ + xwrite_handshake_record(tls, len); + + tls->hsd = xzalloc(sizeof(*tls->hsd) + len); + tls->hsd->saved_client_hello_size = len; + memcpy(tls->hsd->saved_client_hello, record, len); + memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32)); } static void get_server_hello(tls_state_t *tls) @@ -1188,7 +1248,8 @@ static void get_server_hello(tls_state_t *tls) struct server_hello *hp; uint8_t *cipherid; - int len; + unsigned cipher; + int len, len24; len = tls_xread_handshake_block(tls, 74); @@ -1207,6 +1268,7 @@ static void get_server_hello(tls_state_t *tls) } cipherid = &hp->cipherid_hi; + len24 = hp->len24_lo; if (hp->session_id_len != 32) { if (hp->session_id_len != 0) tls_error_die(tls); @@ -1216,19 +1278,39 @@ static void get_server_hello(tls_state_t *tls) // may return an empty session_id to indicate that the session will // not be cached and therefore cannot be resumed." cipherid -= 32; - hp->len24_lo += 32; /* what len would be if session id would be present */ + len24 += 32; /* what len would be if session id would be present */ } - if (hp->len24_lo < 70 - || cipherid[0] != (CIPHER_ID >> 8) - || cipherid[1] != (CIPHER_ID & 0xff) - || cipherid[2] != 0 /* comprtype */ + if (len24 < 70 +// || cipherid[0] != (CIPHER_ID >> 8) +// || cipherid[1] != (CIPHER_ID & 0xff) +// || cipherid[2] != 0 /* comprtype */ ) { tls_error_die(tls); } - dbg("<< SERVER_HELLO\n"); + memcpy(tls->hsd->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32)); + + tls->cipher_id = cipher = 0x100 * cipherid[0] + cipherid[1]; + dbg("server chose cipher %04x\n", cipher); + + if (cipher == TLS_RSA_WITH_AES_128_CBC_SHA) { + tls->key_size = AES128_KEYSIZE; + tls->MAC_size = SHA1_OUTSIZE; + sha1_begin(&tls->hsd->handshake_hash_ctx); + } + else { /* TLS_RSA_WITH_AES_256_CBC_SHA256 */ + tls->key_size = AES256_KEYSIZE; + tls->MAC_size = SHA256_OUTSIZE; + sha256_begin(&tls->hsd->handshake_hash_ctx); + } + hash_handshake(tls, ">> client hello hash:%s", + tls->hsd->saved_client_hello, tls->hsd->saved_client_hello_size + ); + hash_handshake(tls, "<< server hello hash:%s", + tls->inbuf + RECHDR_LEN, len + ); } static void get_server_cert(tls_state_t *tls) @@ -1312,7 +1394,7 @@ static void send_client_key_exchange(tls_state_t *tls) // [0..47]; // The master secret is always exactly 48 bytes in length. The length // of the premaster secret will vary depending on key exchange method. - prf_hmac_sha256( + prf_hmac(tls, tls->hsd->master_secret, sizeof(tls->hsd->master_secret), rsa_premaster, sizeof(rsa_premaster), "master secret", @@ -1360,21 +1442,23 @@ static void send_client_key_exchange(tls_state_t *tls) memcpy(&tmp64[0] , &tls->hsd->client_and_server_rand32[32], 32); memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32); - prf_hmac_sha256( - tls->client_write_MAC_key, 2 * (SHA256_OUTSIZE + AES256_KEYSIZE), + prf_hmac(tls, + tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size), // also fills: - // server_write_MAC_key[SHA256_OUTSIZE] - // client_write_key[AES256_KEYSIZE] - // server_write_key[AES256_KEYSIZE] + // server_write_MAC_key[] + // client_write_key[] + // server_write_key[] tls->hsd->master_secret, sizeof(tls->hsd->master_secret), "key expansion", tmp64, 64 ); + tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size); + tls->server_write_key = tls->client_write_key + tls->key_size; dump_hex("client_write_MAC_key:%s\n", - tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key) + tls->client_write_MAC_key, tls->MAC_size ); dump_hex("client_write_key:%s\n", - tls->client_write_key, sizeof(tls->client_write_key) + tls->client_write_key, tls->key_size ); } } @@ -1435,15 +1519,17 @@ static void send_client_finished(tls_state_t *tls) uint8_t prf_result[12]; }; struct finished *record = tls_get_outbuf(tls, sizeof(*record)); - uint8_t handshake_hash[SHA256_OUTSIZE]; + uint8_t handshake_hash[TLS_MAX_MAC_SIZE]; + unsigned len; fill_handshake_record_hdr(record, HANDSHAKE_FINISHED, sizeof(*record)); - sha256_peek(&tls->hsd->handshake_sha256_ctx, handshake_hash); - prf_hmac_sha256(record->prf_result, sizeof(record->prf_result), - tls->hsd->master_secret, sizeof(tls->hsd->master_secret), - "client finished", - handshake_hash, sizeof(handshake_hash) + len = get_handshake_hash(tls, handshake_hash); + prf_hmac(tls, + record->prf_result, sizeof(record->prf_result), + tls->hsd->master_secret, sizeof(tls->hsd->master_secret), + "client finished", + handshake_hash, len ); dump_hex("from secret: %s\n", tls->hsd->master_secret, sizeof(tls->hsd->master_secret)); dump_hex("from labelSeed: %s", "client finished", sizeof("client finished")-1); @@ -1475,10 +1561,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni) // Application Data <------> Application Data int len; - tls->hsd = xzalloc(sizeof(*tls->hsd)); - sha256_begin(&tls->hsd->handshake_sha256_ctx); - - send_client_hello(tls, sni); + send_client_hello_and_alloc_hsd(tls, sni); get_server_hello(tls); // RFC 5246 @@ -1535,11 +1618,11 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni) if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) tls_error_die(tls); dbg("<< CHANGE_CIPHER_SPEC\n"); - if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) - tls->min_encrypted_len_on_read = SHA256_OUTSIZE; + if (tls->cipher_id == TLS_RSA_WITH_NULL_SHA256) + tls->min_encrypted_len_on_read = tls->MAC_size; else /* all incoming packets now should be encrypted and have IV + MAC + padding */ - tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE; + tls->min_encrypted_len_on_read = AES_BLOCKSIZE + tls->MAC_size + AES_BLOCKSIZE; /* Get (encrypted) FINISHED from the server */ len = tls_xread_record(tls); @@ -1550,7 +1633,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni) /* free handshake data */ // if (PARANOIA) -// memset(tls->hsd, 0, sizeof(*tls->hsd)); +// memset(tls->hsd, 0, tls->hsd->hsd_size); free(tls->hsd); tls->hsd = NULL; } @@ -1614,8 +1697,8 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls) * read, encrypt and send bigger chunks */ inbuf_size += INBUF_STEP; - if (inbuf_size > MAX_OUTBUF) - inbuf_size = MAX_OUTBUF; + if (inbuf_size > TLS_MAX_OUTBUF) + inbuf_size = TLS_MAX_OUTBUF; } tls_xwrite(tls, nread); } -- cgit v1.2.3-55-g6feb From 0f4364775fbc0b716024d5211325045c40b431c9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Wed, 25 Jan 2017 01:58:00 +0100 Subject: xxd: new applet Yet Another Hexdumper function old new delta xxd_main - 364 +364 packed_usage 31046 31116 +70 applet_names 2560 2564 +4 applet_main 1476 1480 +4 rewrite 1022 1013 -9 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 3/1 up/down: 442/-9) Total: 433 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- libbb/dump.c | 12 ++--- util-linux/hexdump.c | 21 ++++---- util-linux/hexdump_xxd.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 16 deletions(-) create mode 100644 util-linux/hexdump_xxd.c (limited to 'libbb') diff --git a/libbb/dump.c b/libbb/dump.c index 154be5d80..e9ac0c673 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -165,16 +165,14 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) byte_count_str = "\001"; DO_BYTE_COUNT: if (fu->bcnt) { - do { - if (fu->bcnt == *byte_count_str) { + for (;;) { + if (fu->bcnt == *byte_count_str) break; - } - } while (*++byte_count_str); + if (*++byte_count_str == 0) + bb_error_msg_and_die("bad byte count for conversion character %s", p1); + } } /* Unlike the original, output the remainder of the format string. */ - if (!*byte_count_str) { - bb_error_msg_and_die("bad byte count for conversion character %s", p1); - } pr->bcnt = *byte_count_str; } else if (*p1 == 'l') { ++p2; diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c index 4a7f641db..4b536e1c2 100644 --- a/util-linux/hexdump.c +++ b/util-linux/hexdump.c @@ -47,6 +47,7 @@ //usage: "\n -d Two-byte decimal display" //usage: "\n -e FORMAT_STRING" //usage: "\n -f FORMAT_FILE" +// exactly the same help text lines in hexdump and xxd: //usage: "\n -n LENGTH Interpret only LENGTH bytes of input" //usage: "\n -o Two-byte octal display" //usage: "\n -s OFFSET Skip OFFSET bytes" @@ -83,11 +84,11 @@ static void bb_dump_addfile(dumper_t *dumper, char *name) } static const char *const add_strings[] = { - "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"", /* b */ - "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"", /* c */ - "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"", /* d */ - "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"", /* o */ - "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"", /* x */ + "\"%07.7_ax \"16/1 \"%03o \"\"\n\"", /* b */ + "\"%07.7_ax \"16/1 \"%3_c \"\"\n\"", /* c */ + "\"%07.7_ax \"8/2 \" %05u \"\"\n\"", /* d */ + "\"%07.7_ax \"8/2 \" %06o \"\"\n\"", /* o */ + "\"%07.7_ax \"8/2 \" %04x \"\"\n\"", /* x */ }; static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\""; @@ -125,9 +126,11 @@ int hexdump_main(int argc, char **argv) /* Save a little bit of space below by omitting the 'else's. */ if (ch == 'C') { hd_applet: - bb_dump_add(dumper, "\"%08.8_Ax\n\""); - bb_dump_add(dumper, "\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" "); - bb_dump_add(dumper, "\" |\" 16/1 \"%_p\" \"|\\n\""); + bb_dump_add(dumper, "\"%08.8_Ax\n\""); // final address line after dump + //------------------- "address " 8 * "xx " " " 8 * "xx " + bb_dump_add(dumper, "\"%08.8_ax \"8/1 \"%02x \" \" \"8/1 \"%02x \""); + //------------------- " |ASCII...........|\n" + bb_dump_add(dumper, "\" |\"16/1 \"%_p\"\"|\n\""); } if (ch == 'e') { bb_dump_add(dumper, optarg); @@ -158,7 +161,7 @@ int hexdump_main(int argc, char **argv) if (!dumper->fshead) { bb_dump_add(dumper, add_first); - bb_dump_add(dumper, "\"%07.7_ax \" 8/2 \"%04x \" \"\\n\""); + bb_dump_add(dumper, "\"%07.7_ax \"8/2 \"%04x \"\"\n\""); } argv += optind; diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c new file mode 100644 index 000000000..3a7e64bb9 --- /dev/null +++ b/util-linux/hexdump_xxd.c @@ -0,0 +1,132 @@ +/* vi: set sw=4 ts=4: */ +/* + * xxd implementation for busybox + * + * Copyright (c) 2017 Denys Vlasenko <vda.linux@gmail.com> + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config XXD +//config: bool "xxd" +//config: default y +//config: help +//config: The xxd utility is used to display binary data in a readable +//config: way that is comparable to the output from most hex editors. + +//applet:IF_XXD(APPLET_NOEXEC(xxd, xxd, BB_DIR_USR_BIN, BB_SUID_DROP, xxd)) + +//kbuild:lib-$(CONFIG_XXD) += hexdump_xxd.o + +// $ xxd --version +// xxd V1.10 27oct98 by Juergen Weigert +// $ xxd --help +// Usage: +// xxd [options] [infile [outfile]] +// or +// xxd -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]] +// Options: +// -a toggle autoskip: A single '*' replaces nul-lines. Default off. +// -b binary digit dump (incompatible with -ps,-i,-r). Default hex. +// -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30). +// -E show characters in EBCDIC. Default ASCII. +// -e little-endian dump (incompatible with -ps,-i,-r). +// -g number of octets per group in normal output. Default 2 (-e: 4). +// -i output in C include file style. +// -l len stop after <len> octets. +// -o off add <off> to the displayed file position. +// -ps output in postscript plain hexdump style. +// -r reverse operation: convert (or patch) hexdump into binary. +// -r -s off revert with <off> added to file positions found in hexdump. +// -s [+][-]seek start at <seek> bytes abs. (or +: rel.) infile offset. +// -u use upper case hex letters. + +//usage:#define xxd_trivial_usage +//usage: "[OPTIONS] [FILE]" +//usage:#define xxd_full_usage "\n\n" +//usage: "Hex dump FILE (or stdin)\n" +//usage: "\n -g N Bytes per group" +//usage: "\n -c N Bytes per line" +// exactly the same help text lines in hexdump and xxd: +//usage: "\n -l LENGTH Interpret only LENGTH bytes of input" +//usage: "\n -s OFFSET Skip OFFSET bytes" + +#include "libbb.h" +#include "dump.h" + +/* This is a NOEXEC applet. Be very careful! */ + +int xxd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int xxd_main(int argc UNUSED_PARAM, char **argv) +{ + char buf[80]; + dumper_t *dumper; + char *opt_l, *opt_s; + unsigned bytes = 2; + unsigned cols = 0; + unsigned opt; + + dumper = alloc_dumper(); + +#define OPT_l (1 << 0) +#define OPT_s (1 << 1) +#define OPT_a (1 << 2) + opt_complementary = "?1"; /* 1 argument max */ + opt = getopt32(argv, "l:s:ag:+c:+", &opt_l, &opt_s, &bytes, &cols); + argv += optind; + +// dumper->dump_vflag = ALL; // default +// if (opt & OPT_a) +// dumper->dump_vflag = SKIPNUL; ..does not exist + if (opt & OPT_l) { + dumper->dump_length = xstrtou_range( + opt_l, + /*base:*/ 0, + /*lo:*/ 0, /*hi:*/ INT_MAX + ); + } + if (opt & OPT_s) { + dumper->dump_skip = xstrtoull_range( + opt_s, + /*base:*/ 0, + /*lo:*/ 0, /*hi:*/ OFF_T_MAX + ); + //BUGGY for /proc/version (unseekable?) + } + + bb_dump_add(dumper, "\"%08.8_ax: \""); // "address: " + if (cols == 0) + cols = 16; + if (bytes < 1 || bytes >= cols) { + sprintf(buf, "%u/1 \"%%02x\"", cols); // cols * "xx" + bb_dump_add(dumper, buf); + } + else if (bytes == 1) { + sprintf(buf, "%u/1 \"%%02x \"", cols); // cols * "xx " + bb_dump_add(dumper, buf); + } + else { +/* Format "print byte" with and without trailing space */ +#define BS "/1 \"%02x \"" +#define B "/1 \"%02x\"" + unsigned i; + char *bigbuf = xmalloc(1 + cols * (sizeof(BS)-1)); + char *p = bigbuf; + for (i = 1; i <= cols; i++) { + if (i == cols || i % bytes) + p = stpcpy(p, B); + else + p = stpcpy(p, BS); + } + // for -g3, this results in B B BS B B BS... B = "xxxxxx xxxxxx .....xx" + // todo: can be more clever and use + // one "cols-1/B" format instead of many "B B B..." formats + //bb_error_msg("ADDED:'%s'", bigbuf); + bb_dump_add(dumper, bigbuf); + free(bigbuf); + } + + sprintf(buf, "\" \" %u/1 \"%%_p\" \"\n\"", cols); // " ASCII\n" + bb_dump_add(dumper, buf); + + return bb_dump_dump(dumper, argv); +} -- cgit v1.2.3-55-g6feb From cb8e84e65a254dcba4939e237b93d03c46ae56aa Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Wed, 25 Jan 2017 16:21:00 +0100 Subject: libbb: shrink sump.c function old new delta dot_flags_width_chars - 16 +16 int_convs - 7 +7 lcc 7 - -7 index_str 16 - -16 rewrite 1013 937 -76 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 0/1 up/down: 23/-99) Total: -76 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- libbb/dump.c | 159 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 80 insertions(+), 79 deletions(-) (limited to 'libbb') diff --git a/libbb/dump.c b/libbb/dump.c index e9ac0c673..87c1dce13 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -14,12 +14,12 @@ #include "libbb.h" #include "dump.h" -static const char index_str[] ALIGN1 = ".#-+ 0123456789"; +static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789"; static const char size_conv_str[] ALIGN1 = "\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; -static const char lcc[] ALIGN1 = "diouxX"; +static const char int_convs[] ALIGN1 = "diouxX"; typedef struct priv_dumper_t { @@ -71,7 +71,7 @@ static NOINLINE int bb_dump_size(FS *fs) * skip any special chars -- save precision in * case it's a %s format. */ - while (strchr(index_str + 1, *++fmt)) + while (strchr(dot_flags_width_chars + 1, *++fmt)) continue; if (*fmt == '.' && isdigit(*++fmt)) { prec = atoi(fmt); @@ -82,14 +82,15 @@ static NOINLINE int bb_dump_size(FS *fs) if (!p) { if (*fmt == 's') { bcnt += prec; - } else if (*fmt == '_') { + } + if (*fmt == '_') { ++fmt; if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) { bcnt += 1; } } } else { - bcnt += size_conv_str[p - (size_conv_str + 12)]; + bcnt += p[-12]; } } cur_size += bcnt * fu->reps; @@ -99,32 +100,30 @@ static NOINLINE int bb_dump_size(FS *fs) static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) { - enum { NOTOKAY, USEBCNT, USEPREC } sokay; FU *fu; - PR *pr; - char *p1, *p2, *p3; - char savech, *fmtp; - const char *byte_count_str; - int nconv, prec = 0; for (fu = fs->nextfu; fu; fu = fu->nextfu) { + PR *pr; + char *p1, *p2, *p3; + char *fmtp; + int nconv = 0; /* * break each format unit into print units; each * conversion character gets its own. */ - for (nconv = 0, fmtp = fu->fmt; *fmtp; ) { - /* NOSTRICT */ - /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/ - pr = xzalloc(sizeof(PR)); + for (fmtp = fu->fmt; *fmtp; ) { + unsigned len; + const char *prec; + const char *byte_count_str; + + /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL */ + pr = xzalloc(sizeof(*pr)); if (!fu->nextpr) fu->nextpr = pr; /* skip preceding text and up to the next % sign */ - for (p1 = fmtp; *p1 && *p1 != '%'; ++p1) - continue; - - /* only text in the string */ - if (!*p1) { + p1 = strchr(fmtp, '%'); + if (!p1) { /* only text in the string */ pr->fmt = fmtp; pr->flags = F_TEXT; break; @@ -134,22 +133,20 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * get precision for %s -- if have a byte count, don't * need it. */ + prec = NULL; if (fu->bcnt) { - sokay = USEBCNT; /* skip to conversion character */ - for (++p1; strchr(index_str, *p1); ++p1) + while (strchr(dot_flags_width_chars, *++p1)) continue; } else { /* skip any special chars, field width */ - while (strchr(index_str + 1, *++p1)) + while (strchr(dot_flags_width_chars + 1, *++p1)) continue; if (*p1 == '.' && isdigit(*++p1)) { - sokay = USEPREC; - prec = atoi(p1); + prec = p1; while (isdigit(*++p1)) continue; - } else - sokay = NOTOKAY; + } } p2 = p1 + 1; /* set end pointer */ @@ -174,63 +171,63 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) } /* Unlike the original, output the remainder of the format string. */ pr->bcnt = *byte_count_str; - } else if (*p1 == 'l') { + } else + if (*p1 == 'l') { /* %ld etc */ + const char *e; + ++p2; ++p1; DO_INT_CONV: - { - const char *e; - e = strchr(lcc, *p1); - if (!e) { - goto DO_BAD_CONV_CHAR; - } - pr->flags = F_INT; - if (e > lcc + 1) { - pr->flags = F_UINT; - } - byte_count_str = "\004\002\001"; - goto DO_BYTE_COUNT; - } - /* NOTREACHED */ - } else if (strchr(lcc, *p1)) { + e = strchr(int_convs, *p1); /* "diouxX"? */ + if (!e) + goto DO_BAD_CONV_CHAR; + pr->flags = F_INT; + if (e > int_convs + 1) /* not d or i? */ + pr->flags = F_UINT; + byte_count_str = "\004\002\001"; + goto DO_BYTE_COUNT; + } else + if (strchr(int_convs, *p1)) { /* %d etc */ goto DO_INT_CONV; - } else if (strchr("eEfgG", *p1)) { + } else + if (strchr("eEfgG", *p1)) { /* floating point */ pr->flags = F_DBL; byte_count_str = "\010\004"; goto DO_BYTE_COUNT; - } else if (*p1 == 's') { + } else + if (*p1 == 's') { pr->flags = F_STR; - if (sokay == USEBCNT) { - pr->bcnt = fu->bcnt; - } else if (sokay == USEPREC) { - pr->bcnt = prec; - } else { /* NOTOKAY */ - bb_error_msg_and_die("%%s requires a precision or a byte count"); + pr->bcnt = fu->bcnt; + if (fu->bcnt == 0) { + if (!prec) + bb_error_msg_and_die("%%s needs precision or byte count"); + pr->bcnt = atoi(prec); } - } else if (*p1 == '_') { - ++p2; + } else + if (*p1 == '_') { + p2++; /* move past a in "%_a" */ switch (p1[1]) { - case 'A': + case 'A': /* %_A[dox]: print address and the end */ dumper->endfu = fu; fu->flags |= F_IGNORE; /* FALLTHROUGH */ - case 'a': + case 'a': /* %_a[dox]: current address */ pr->flags = F_ADDRESS; - ++p2; + p2++; /* move past x in "%_ax" */ if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) { goto DO_BAD_CONV_CHAR; } *p1 = p1[2]; break; - case 'c': + case 'c': /* %_c: chars, \ooo, \n \r \t etc */ pr->flags = F_C; /* *p1 = 'c'; set in conv_c */ goto DO_BYTE_COUNT_1; - case 'p': + case 'p': /* %_p: chars, dots for nonprintable */ pr->flags = F_P; *p1 = 'c'; goto DO_BYTE_COUNT_1; - case 'u': + case 'u': /* %_p: chars, 'nul', 'esc' etc for nonprintable */ pr->flags = F_U; /* *p1 = 'c'; set in conv_u */ goto DO_BYTE_COUNT_1; @@ -246,13 +243,8 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * copy to PR format string, set conversion character * pointer, update original. */ - savech = *p2; - p1[1] = '\0'; - pr->fmt = xstrdup(fmtp); - *p2 = savech; - //Too early! xrealloc can move pr->fmt! - //pr->cchar = pr->fmt + (p1 - fmtp); - + len = (p1 - fmtp) + 1; + pr->fmt = xstrndup(fmtp, len); /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost. * Skip subsequent text and up to the next % sign and tack the * additional text onto fmt: eg. if fmt is "%x is a HEX number", @@ -260,16 +252,17 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) */ for (p3 = p2; *p3 && *p3 != '%'; p3++) continue; - if (p3 > p2) { - savech = *p3; - *p3 = '\0'; - pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt) + (p3-p2) + 1); - strcat(pr->fmt, p2); - *p3 = savech; - p2 = p3; + if ((p3 - p2) != 0) { + char *d; + pr->fmt = d = xrealloc(pr->fmt, len + (p3 - p2) + 1); + d += len; + do { + *d++ = *p2++; + } while (p2 != p3); + *d = '\0'; + /* now p2 = p3 */ } - - pr->cchar = pr->fmt + (p1 - fmtp); + pr->cchar = pr->fmt + len - 1; /* must be after realloc! */ fmtp = p2; /* only one conversion character if byte count */ @@ -281,7 +274,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * if format unit byte count not specified, figure it out * so can adjust rep count later. */ - if (!fu->bcnt) + if (fu->bcnt == 0) for (pr = fu->nextpr; pr; pr = pr->nextpr) fu->bcnt += pr->bcnt; } @@ -303,16 +296,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt; } if (fu->reps > 1 && fu->nextpr) { + PR *pr; + char *p1, *p2; + for (pr = fu->nextpr;; pr = pr->nextpr) if (!pr->nextpr) break; - for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) + p2 = NULL; + for (p1 = pr->fmt; *p1; ++p1) p2 = isspace(*p1) ? p1 : NULL; if (p2) pr->nospace = p2; } - if (!fu->nextfu) - break; } } @@ -356,6 +351,7 @@ static NOINLINE int next(priv_dumper_t *dumper) if (dumper->next__done) return 0; /* no next file */ dumper->next__done = 1; +//why stat of stdin is specially prohibited? statok = 0; } if (dumper->pub.dump_skip) @@ -760,6 +756,11 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) if (!isspace(*p)) { bb_error_msg_and_die("bad format {%s}", fmt); } +// Above check prohibits formats such as '/1"%02x"' - it requires space after 1. +// Other than this, formats can be pretty much jammed together: +// "%07_ax:"8/2 "%04x|""\n" +// but this space is required. The check *can* be removed, but +// keeping it to stay compat with util-linux hexdump. tfu->bcnt = atoi(savep); /* skip trailing white space */ p = skip_whitespace(p + 1); -- cgit v1.2.3-55-g6feb From 9967c9949e0436879354e76c2847d697c309984c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Thu, 26 Jan 2017 01:13:58 +0100 Subject: libbb: spawn_and_wait() fflushes before forking NOEXEC; child reinits logmode Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- docs/nofork_noexec.txt | 7 +++++++ include/libbb.h | 14 +++++++++----- libbb/vfork_daemon_rexec.c | 36 +++++++++++++++++++----------------- 3 files changed, 35 insertions(+), 22 deletions(-) (limited to 'libbb') diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index 2fb184a03..a24dd9c27 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -99,6 +99,13 @@ applet_name. Thus, for example, caller does not need to worry about option_mask32 getting trashed. + Calling NOEXEC applets + +It's the same trusty spawn_and_wait(argv). If FEATURE_PREFER_APPLETS=y, +it does NOEXEC trick. It resets xfunc_error_retval = 1 and +logmode = LOGMODE_STDIO in the child. + + Relevant CONFIG options FEATURE_PREFER_APPLETS diff --git a/include/libbb.h b/include/libbb.h index 8c652e2d7..07fe20dac 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1093,10 +1093,19 @@ pid_t wait_any_nohang(int *wstat) FAST_FUNC; */ int wait4pid(pid_t pid) FAST_FUNC; int wait_for_exitstatus(pid_t pid) FAST_FUNC; +/************************************************************************/ +/* spawn_and_wait/run_nofork_applet/run_applet_no_and_exit need to work */ +/* carefully together to reinit some global state while not disturbing */ +/* other. Be careful if you change them. Consult docs/nofork_noexec.txt */ +/************************************************************************/ /* Same as wait4pid(spawn(argv)), but with NOFORK/NOEXEC if configured: */ int spawn_and_wait(char **argv) FAST_FUNC; /* Does NOT check that applet is NOFORK, just blindly runs it */ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; +#ifndef BUILD_INDIVIDUAL +extern int find_applet_by_name(const char *name) FAST_FUNC; +extern void run_applet_no_and_exit(int a, char **argv) NORETURN FAST_FUNC; +#endif /* Helpers for daemonization. * @@ -1303,11 +1312,6 @@ const struct hwtype *get_hwtype(const char *name) FAST_FUNC; const struct hwtype *get_hwntype(int type) FAST_FUNC; -#ifndef BUILD_INDIVIDUAL -extern int find_applet_by_name(const char *name) FAST_FUNC; -extern void run_applet_no_and_exit(int a, char **argv) NORETURN FAST_FUNC; -#endif - #ifdef HAVE_MNTENT_H extern int match_fstype(const struct mntent *mt, const char *fstypes) FAST_FUNC; extern struct mntent *find_mount_point(const char *name, int subdir_too) FAST_FUNC; diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index c192829b5..2e7dc2d9b 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -183,26 +183,28 @@ int FAST_FUNC spawn_and_wait(char **argv) #if ENABLE_FEATURE_PREFER_APPLETS int a = find_applet_by_name(argv[0]); - if (a >= 0 && (APPLET_IS_NOFORK(a) -# if BB_MMU - || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */ -# endif - )) { -# if BB_MMU + if (a >= 0) { if (APPLET_IS_NOFORK(a)) -# endif - { return run_nofork_applet(a, argv); +# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */ + if (APPLET_IS_NOEXEC(a)) { + fflush_all(); + rc = fork(); + if (rc) /* parent or error */ + return wait4pid(rc); + + /* child */ + /* reset some state and run without execing */ + + /* msg_eol = "\n"; - no caller needs this reinited yet */ + logmode = LOGMODE_STDIO; + /* die_func = NULL; - needed if the caller is a shell, + * init, or a NOFORK applet. But none of those call us + * as of yet (and that should probably always stay true). + */ + /* xfunc_error_retval and applet_name are init by: */ + run_applet_no_and_exit(a, argv); } -# if BB_MMU - /* MMU only */ - /* a->noexec is true */ - rc = fork(); - if (rc) /* parent or error */ - return wait4pid(rc); - /* child */ - xfunc_error_retval = EXIT_FAILURE; - run_applet_no_and_exit(a, argv); # endif } #endif /* FEATURE_PREFER_APPLETS */ -- cgit v1.2.3-55-g6feb From 35b54a3c247235b1bffe2a22784a1d5be10267f3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Mon, 30 Jan 2017 00:45:05 +0100 Subject: libbb: match_fstype() is unreadable in the extreme, fixing it Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- include/libbb.h | 2 +- libbb/match_fstype.c | 20 ++++++++------------ util-linux/mount.c | 2 +- util-linux/umount.c | 4 ++-- 4 files changed, 12 insertions(+), 16 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 07fe20dac..b054e0559 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1312,8 +1312,8 @@ const struct hwtype *get_hwtype(const char *name) FAST_FUNC; const struct hwtype *get_hwntype(int type) FAST_FUNC; +extern int fstype_matches(const char *fstype, const char *comma_list) FAST_FUNC; #ifdef HAVE_MNTENT_H -extern int match_fstype(const struct mntent *mt, const char *fstypes) FAST_FUNC; extern struct mntent *find_mount_point(const char *name, int subdir_too) FAST_FUNC; #endif extern void erase_mtab(const char * name) FAST_FUNC; diff --git a/libbb/match_fstype.c b/libbb/match_fstype.c index b066b4211..6046bc6db 100644 --- a/libbb/match_fstype.c +++ b/libbb/match_fstype.c @@ -12,34 +12,30 @@ #include "libbb.h" -#ifdef HAVE_MNTENT_H - -int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) +int FAST_FUNC fstype_matches(const char *fstype, const char *comma_list) { int match = 1; - if (!t_fstype) + if (!comma_list) return match; - if (t_fstype[0] == 'n' && t_fstype[1] == 'o') { + if (comma_list[0] == 'n' && comma_list[1] == 'o') { match--; - t_fstype += 2; + comma_list += 2; } while (1) { - char *after_mnt_type = is_prefixed_with(t_fstype, mt->mnt_type); + char *after_mnt_type = is_prefixed_with(comma_list, fstype); if (after_mnt_type && (*after_mnt_type == '\0' || *after_mnt_type == ',') ) { return match; } - t_fstype = strchr(t_fstype, ','); - if (!t_fstype) + comma_list = strchr(comma_list, ','); + if (!comma_list) break; - t_fstype++; + comma_list++; } return !match; } - -#endif /* HAVE_MNTENT_H */ diff --git a/util-linux/mount.c b/util-linux/mount.c index 4f5dced10..f0245f714 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -2312,7 +2312,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die(bb_msg_you_must_be_root); // Does type match? (NULL matches always) - if (!match_fstype(mtcur, fstype)) + if (!fstype_matches(mtcur->mnt_type, fstype)) continue; // Skip noauto and swap anyway diff --git a/util-linux/umount.c b/util-linux/umount.c index 78eef57a5..c958fd552 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -125,8 +125,8 @@ int umount_main(int argc UNUSED_PARAM, char **argv) } else { setup_common_bufsiz(); while (getmntent_r(fp, &me, bb_common_bufsiz1, COMMON_BUFSIZE)) { - /* Match fstype if passed */ - if (!match_fstype(&me, fstype)) + /* Match fstype (fstype==NULL matches always) */ + if (!fstype_matches(me.mnt_type, fstype)) continue; m = xzalloc(sizeof(*m)); m->next = mtl; -- cgit v1.2.3-55-g6feb From b6871c1965af0eb87123e13f5d81ec0c9b801b71 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Thu, 2 Feb 2017 13:04:30 +0100 Subject: ps: avoid -o stat to contain spaces. Closes 9631 function old new delta procps_scan 1227 1236 +9 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- libbb/procps.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'libbb') diff --git a/libbb/procps.c b/libbb/procps.c index 4edc54d48..b52c0f51b 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -370,6 +370,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | PSSCAN_TTY | PSSCAN_NICE | PSSCAN_CPU) ) { + int s_idx; char *cp, *comm1; int tty; #if !ENABLE_FEATURE_FAST_TOP @@ -468,17 +469,20 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS sp->niceness = tasknice; #endif - - if (sp->vsz == 0 && sp->state[0] != 'Z') + sp->state[1] = ' '; + sp->state[2] = ' '; + s_idx = 1; + if (sp->vsz == 0 && sp->state[0] != 'Z') { + /* not sure what the purpose of this flag */ sp->state[1] = 'W'; - else - sp->state[1] = ' '; - if (tasknice < 0) - sp->state[2] = '<'; - else if (tasknice) /* > 0 */ - sp->state[2] = 'N'; - else - sp->state[2] = ' '; + s_idx = 2; + } + if (tasknice != 0) { + if (tasknice < 0) + sp->state[s_idx] = '<'; + else /* > 0 */ + sp->state[s_idx] = 'N'; + } } #if ENABLE_FEATURE_TOPMEM -- cgit v1.2.3-55-g6feb From 8762512fdb088acefb9f3ea5f7b1e1bf2d336ff3 Mon Sep 17 00:00:00 2001 From: Rostislav Skudnov <rostislav@tuxera.com> Date: Wed, 1 Feb 2017 18:35:13 +0000 Subject: Replace int -> uint to avoid signed integer overflow An example of such an error (should be compiled with DEBUG_SANITIZE): runtime error: left shift of 1 by 31 places cannot be represented in type 'int' Signed-off-by: Rostislav Skudnov <rostislav@tuxera.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- archival/libarchive/decompress_bunzip2.c | 6 +++--- libbb/crc32.c | 2 +- libbb/getopt32.c | 4 ++-- libbb/pw_encrypt.c | 2 +- miscutils/rx.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'libbb') diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c index fe5953da2..4fb989c29 100644 --- a/archival/libarchive/decompress_bunzip2.c +++ b/archival/libarchive/decompress_bunzip2.c @@ -134,7 +134,7 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted) /* Avoid 32-bit overflow (dump bit buffer to top of output) */ if (bit_count >= 24) { - bits = bd->inbufBits & ((1 << bit_count) - 1); + bits = bd->inbufBits & ((1U << bit_count) - 1); bits_wanted -= bit_count; bits <<= bits_wanted; bit_count = 0; @@ -158,11 +158,11 @@ static int get_next_block(bunzip_data *bd) { struct group_data *hufGroup; int dbufCount, dbufSize, groupCount, *base, *limit, selector, - i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; + i, j, runPos, symCount, symTotal, nSelectors, byteCount[256]; int runCnt = runCnt; /* for compiler */ uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; uint32_t *dbuf; - unsigned origPtr; + unsigned origPtr, t; dbuf = bd->dbuf; dbufSize = bd->dbufSize; diff --git a/libbb/crc32.c b/libbb/crc32.c index ac9836cc9..0711ca84e 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -24,7 +24,7 @@ uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) { uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320; uint32_t c; - int i, j; + unsigned i, j; if (!crc_table) crc_table = xmalloc(256 * sizeof(uint32_t)); diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 15b6efc09..497fc016f 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -404,7 +404,7 @@ getopt32(char **argv, const char *applet_opts, ...) if (c >= 32) break; on_off->opt_char = *s; - on_off->switch_on = (1 << c); + on_off->switch_on = (1U << c); if (*++s == ':') { on_off->optarg = va_arg(p, void **); if (s[1] == '+' || s[1] == '*') { @@ -454,7 +454,7 @@ getopt32(char **argv, const char *applet_opts, ...) if (c >= 32) break; on_off->opt_char = l_o->val; - on_off->switch_on = (1 << c); + on_off->switch_on = (1U << c); if (l_o->has_arg != no_argument) on_off->optarg = va_arg(p, void **); c++; diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c index 4cdc2de76..fe06a8fe6 100644 --- a/libbb/pw_encrypt.c +++ b/libbb/pw_encrypt.c @@ -30,7 +30,7 @@ static int i64c(int i) int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */) { /* was: x += ... */ - int x = getpid() + monotonic_us(); + unsigned x = getpid() + monotonic_us(); do { /* x = (x*1664525 + 1013904223) % 2^32 generator is lame * (low-order bit is not "random", etc...), diff --git a/miscutils/rx.c b/miscutils/rx.c index 36fc20a72..1f6f2825c 100644 --- a/miscutils/rx.c +++ b/miscutils/rx.c @@ -94,7 +94,7 @@ static int receive(/*int read_fd, */int file_fd) int blockBegin; int blockNo, blockNoOnesCompl; int cksum_or_crc; - int expected; + unsigned expected; int i, j; blockBegin = read_byte(timeout); -- cgit v1.2.3-55-g6feb