diff options
author | Ron Yorston <rmy@pobox.com> | 2018-11-28 10:28:18 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-11-28 10:28:18 +0000 |
commit | 2a69a2200a141c1504b662eca64b802cdab71b12 (patch) | |
tree | eab0cc01852db237a26052a83c8f582ed92b7cd9 | |
parent | 97ca1f4b955f486cd26461cb09185335483d2921 (diff) | |
parent | 572dfb8e78323b9837f7c5e3369ee233a440b8f2 (diff) | |
download | busybox-w32-2a69a2200a141c1504b662eca64b802cdab71b12.tar.gz busybox-w32-2a69a2200a141c1504b662eca64b802cdab71b12.tar.bz2 busybox-w32-2a69a2200a141c1504b662eca64b802cdab71b12.zip |
Merge branch 'busybox' into merge
69 files changed, 2946 insertions, 641 deletions
diff --git a/.gitignore b/.gitignore index 517e750c1..cc485189e 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -58,3 +58,8 @@ cscope.po.out | |||
58 | # | 58 | # |
59 | tags | 59 | tags |
60 | TAGS | 60 | TAGS |
61 | |||
62 | # | ||
63 | # user-supplied scripts | ||
64 | # | ||
65 | /embed | ||
@@ -192,6 +192,11 @@ config BUSYBOX | |||
192 | 192 | ||
193 | Running "busybox APPLET [ARGS...]" will still work, of course. | 193 | Running "busybox APPLET [ARGS...]" will still work, of course. |
194 | 194 | ||
195 | config FEATURE_SHOW_SCRIPT | ||
196 | bool "Support --show SCRIPT" | ||
197 | default y | ||
198 | depends on BUSYBOX | ||
199 | |||
195 | config FEATURE_INSTALLER | 200 | config FEATURE_INSTALLER |
196 | bool "Support --install [-s] to install applet links at runtime" | 201 | bool "Support --install [-s] to install applet links at runtime" |
197 | default y | 202 | default y |
@@ -363,7 +363,7 @@ scripts/basic/%: scripts_basic ; | |||
363 | 363 | ||
364 | # This target generates Kbuild's and Config.in's from *.c files | 364 | # This target generates Kbuild's and Config.in's from *.c files |
365 | PHONY += gen_build_files | 365 | PHONY += gen_build_files |
366 | gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) | 366 | gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) $(wildcard $(srctree)/embed/*) |
367 | $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) | 367 | $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) |
368 | 368 | ||
369 | # bbox: we have helpers in applets/ | 369 | # bbox: we have helpers in applets/ |
@@ -854,11 +854,14 @@ quiet_cmd_gen_common_bufsiz = GEN include/common_bufsiz.h | |||
854 | cmd_gen_common_bufsiz = $(srctree)/scripts/generate_BUFSIZ.sh include/common_bufsiz.h | 854 | cmd_gen_common_bufsiz = $(srctree)/scripts/generate_BUFSIZ.sh include/common_bufsiz.h |
855 | quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/* | 855 | quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/* |
856 | cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config | 856 | cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config |
857 | quiet_cmd_gen_embedded_scripts = GEN include/embedded_scripts.h | ||
858 | cmd_gen_embedded_scripts = $(srctree)/scripts/embedded_scripts include/embedded_scripts.h $(srctree)/embed $(srctree)/applets_sh | ||
857 | #bbox# piggybacked generation of few .h files | 859 | #bbox# piggybacked generation of few .h files |
858 | include/config/MARKER: scripts/basic/split-include include/autoconf.h | 860 | include/config/MARKER: scripts/basic/split-include include/autoconf.h $(wildcard $(srctree)/embed/*) $(wildcard $(srctree)/applets_sh/*) $(srctree)/scripts/embedded_scripts |
859 | $(call cmd,split_autoconf) | 861 | $(call cmd,split_autoconf) |
860 | $(call cmd,gen_bbconfigopts) | 862 | $(call cmd,gen_bbconfigopts) |
861 | $(call cmd,gen_common_bufsiz) | 863 | $(call cmd,gen_common_bufsiz) |
864 | $(call cmd,gen_embedded_scripts) | ||
862 | @touch $@ | 865 | @touch $@ |
863 | 866 | ||
864 | # Generate some files | 867 | # Generate some files |
@@ -978,6 +981,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \ | |||
978 | include/autoconf.h \ | 981 | include/autoconf.h \ |
979 | include/bbconfigopts.h \ | 982 | include/bbconfigopts.h \ |
980 | include/bbconfigopts_bz2.h \ | 983 | include/bbconfigopts_bz2.h \ |
984 | include/embedded_scripts.h \ | ||
981 | include/usage_compressed.h \ | 985 | include/usage_compressed.h \ |
982 | include/applet_tables.h \ | 986 | include/applet_tables.h \ |
983 | include/applets.h \ | 987 | include/applets.h \ |
diff --git a/applets/applet_tables.c b/applets/applet_tables.c index b997194ad..6a20c8b38 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c | |||
@@ -85,7 +85,15 @@ int main(int argc, char **argv) | |||
85 | 85 | ||
86 | qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name); | 86 | qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name); |
87 | 87 | ||
88 | if (!argv[1]) | 88 | for (i = j = 0; i < NUM_APPLETS-1; ++i) { |
89 | if (cmp_name(applets+i, applets+i+1) == 0) { | ||
90 | fprintf(stderr, "%s: duplicate applet name '%s'\n", argv[0], | ||
91 | applets[i].name); | ||
92 | j = 1; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | if (j != 0 || !argv[1]) | ||
89 | return 1; | 97 | return 1; |
90 | snprintf(tmp1, PATH_MAX, "%s.%u.new", argv[1], (int) getpid()); | 98 | snprintf(tmp1, PATH_MAX, "%s.%u.new", argv[1], (int) getpid()); |
91 | i = open(tmp1, O_WRONLY | O_TRUNC | O_CREAT, 0666); | 99 | i = open(tmp1, O_WRONLY | O_TRUNC | O_CREAT, 0666); |
diff --git a/applets/busybox.mkscripts b/applets/busybox.mkscripts new file mode 100755 index 000000000..935685cba --- /dev/null +++ b/applets/busybox.mkscripts | |||
@@ -0,0 +1,16 @@ | |||
1 | #!/bin/sh | ||
2 | # Make busybox scripted applet list file. | ||
3 | |||
4 | # input $1: full path to Config.h | ||
5 | # input $2: full path to applets.h | ||
6 | # output (stdout): list of pathnames that should be linked to busybox | ||
7 | |||
8 | export LC_ALL=POSIX | ||
9 | export LC_CTYPE=POSIX | ||
10 | |||
11 | CONFIG_H=${1:-include/autoconf.h} | ||
12 | APPLETS_H=${2:-include/applets.h} | ||
13 | $HOSTCC -E -DMAKE_SCRIPTS -include $CONFIG_H $APPLETS_H | | ||
14 | awk '/^[ \t]*SCRIPT/{ | ||
15 | print $2 | ||
16 | }' | ||
diff --git a/applets_sh/README b/applets_sh/README deleted file mode 100644 index 9dcd38ae3..000000000 --- a/applets_sh/README +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | This directory contains examples of applets implemented as shell scripts. | ||
2 | |||
3 | So far these scripts are not hooked to the build system and are not | ||
4 | installed by "make install". If you want to use them, | ||
5 | you need to install them by hand. | ||
diff --git a/applets_sh/dos2unix b/applets_sh/dos2unix deleted file mode 100755 index 0fd5206f6..000000000 --- a/applets_sh/dos2unix +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | # TODO: use getopt to avoid parsing options as filenames, | ||
3 | # and to support -- and --help | ||
4 | [ $# -ne 0 ] && DASH_I=-i | ||
5 | sed $DASH_I -e 's/\r$//' "$@" | ||
diff --git a/applets_sh/nologin b/applets_sh/nologin index 3768eaaa7..4ed5f6ca3 100755 --- a/applets_sh/nologin +++ b/applets_sh/nologin | |||
@@ -1,4 +1,3 @@ | |||
1 | #!/bin/sh | 1 | cat /etc/nologin.txt 2>/dev/null || echo This account is not available |
2 | cat /etc/nologin.txt 2>/dev/null || echo "This account is not available" | ||
3 | sleep 5 | 2 | sleep 5 |
4 | exit 1 | 3 | exit 1 |
diff --git a/applets_sh/tac b/applets_sh/tac deleted file mode 100755 index c5a8e39c1..000000000 --- a/applets_sh/tac +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | # TODO: use getopt to avoid parsing options as filenames, | ||
3 | # and to support -- and --help | ||
4 | for i in "$@" | ||
5 | do | ||
6 | sed -e '1!G;h;$!d' "$i" | ||
7 | done | ||
diff --git a/applets_sh/unix2dos b/applets_sh/unix2dos deleted file mode 100755 index 70e042906..000000000 --- a/applets_sh/unix2dos +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | # TODO: use getopt to avoid parsing options as filenames, | ||
3 | # and to support -- and --help | ||
4 | [ $# -ne 0 ] && DASH_I=-i | ||
5 | sed $DASH_I -e 's/$/\r/' "$@" | ||
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src index e1a8a7529..d2f284b08 100644 --- a/archival/libarchive/Kbuild.src +++ b/archival/libarchive/Kbuild.src | |||
@@ -91,6 +91,7 @@ lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma. | |||
91 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o | 91 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o |
92 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o | 92 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o |
93 | lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o | 93 | lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o |
94 | lib-$(CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS) += open_transformer.o decompress_bunzip2.o | ||
94 | 95 | ||
95 | ifneq ($(lib-y),) | 96 | ifneq ($(lib-y),) |
96 | lib-y += $(COMMON_FILES) | 97 | lib-y += $(COMMON_FILES) |
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c index 7ef4e035f..78366f26a 100644 --- a/archival/libarchive/decompress_bunzip2.c +++ b/archival/libarchive/decompress_bunzip2.c | |||
@@ -107,7 +107,7 @@ struct bunzip_data { | |||
107 | uint8_t selectors[32768]; /* nSelectors=15 bits */ | 107 | uint8_t selectors[32768]; /* nSelectors=15 bits */ |
108 | struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ | 108 | struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ |
109 | }; | 109 | }; |
110 | /* typedef struct bunzip_data bunzip_data; -- done in .h file */ | 110 | typedef struct bunzip_data bunzip_data; |
111 | 111 | ||
112 | 112 | ||
113 | /* Return the next nnn bits of input. All reads from the compressed input | 113 | /* Return the next nnn bits of input. All reads from the compressed input |
@@ -575,7 +575,7 @@ static int get_next_block(bunzip_data *bd) | |||
575 | in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0. | 575 | in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0. |
576 | (Why? This allows to get rid of one local variable) | 576 | (Why? This allows to get rid of one local variable) |
577 | */ | 577 | */ |
578 | int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) | 578 | static int read_bunzip(bunzip_data *bd, char *outbuf, int len) |
579 | { | 579 | { |
580 | const uint32_t *dbuf; | 580 | const uint32_t *dbuf; |
581 | int pos, current, previous; | 581 | int pos, current, previous; |
@@ -699,7 +699,7 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) | |||
699 | /* Because bunzip2 is used for help text unpacking, and because bb_show_usage() | 699 | /* Because bunzip2 is used for help text unpacking, and because bb_show_usage() |
700 | should work for NOFORK applets too, we must be extremely careful to not leak | 700 | should work for NOFORK applets too, we must be extremely careful to not leak |
701 | any allocations! */ | 701 | any allocations! */ |
702 | int FAST_FUNC start_bunzip( | 702 | static int FAST_FUNC start_bunzip( |
703 | void *jmpbuf, | 703 | void *jmpbuf, |
704 | bunzip_data **bdp, | 704 | bunzip_data **bdp, |
705 | int in_fd, | 705 | int in_fd, |
@@ -759,7 +759,7 @@ int FAST_FUNC start_bunzip( | |||
759 | return RETVAL_OK; | 759 | return RETVAL_OK; |
760 | } | 760 | } |
761 | 761 | ||
762 | void FAST_FUNC dealloc_bunzip(bunzip_data *bd) | 762 | static void FAST_FUNC dealloc_bunzip(bunzip_data *bd) |
763 | { | 763 | { |
764 | free(bd->dbuf); | 764 | free(bd->dbuf); |
765 | free(bd); | 765 | free(bd); |
@@ -809,7 +809,7 @@ unpack_bz2_stream(transformer_state_t *xstate) | |||
809 | /* Observed case when i == RETVAL_OK: | 809 | /* Observed case when i == RETVAL_OK: |
810 | * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file | 810 | * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file |
811 | * (to be exact, z.bz2 is exactly these 14 bytes: | 811 | * (to be exact, z.bz2 is exactly these 14 bytes: |
812 | * 42 5a 68 39 17 72 45 38 50 90 00 00 00 00). | 812 | * 42 5a 68 39 17 72 45 38 50 90 00 00 00 00). |
813 | */ | 813 | */ |
814 | && i != RETVAL_OK | 814 | && i != RETVAL_OK |
815 | ) { | 815 | ) { |
@@ -847,6 +847,36 @@ unpack_bz2_stream(transformer_state_t *xstate) | |||
847 | return i ? i : IF_DESKTOP(total_written) + 0; | 847 | return i ? i : IF_DESKTOP(total_written) + 0; |
848 | } | 848 | } |
849 | 849 | ||
850 | char* FAST_FUNC | ||
851 | unpack_bz2_data(const char *packed, int packed_len, int unpacked_len) | ||
852 | { | ||
853 | char *outbuf = NULL; | ||
854 | bunzip_data *bd; | ||
855 | int i; | ||
856 | jmp_buf jmpbuf; | ||
857 | |||
858 | /* Setup for I/O error handling via longjmp */ | ||
859 | i = setjmp(jmpbuf); | ||
860 | if (i == 0) { | ||
861 | i = start_bunzip(&jmpbuf, | ||
862 | &bd, | ||
863 | /* src_fd: */ -1, | ||
864 | /* inbuf: */ packed, | ||
865 | /* len: */ packed_len | ||
866 | ); | ||
867 | } | ||
868 | /* read_bunzip can longjmp and end up here with i != 0 | ||
869 | * on read data errors! Not trivial */ | ||
870 | if (i == 0) { | ||
871 | /* Cannot use xmalloc: will leak bd in NOFORK case! */ | ||
872 | outbuf = malloc_or_warn(unpacked_len); | ||
873 | if (outbuf) | ||
874 | read_bunzip(bd, outbuf, unpacked_len); | ||
875 | } | ||
876 | dealloc_bunzip(bd); | ||
877 | return outbuf; | ||
878 | } | ||
879 | |||
850 | #ifdef TESTING | 880 | #ifdef TESTING |
851 | 881 | ||
852 | static char *const bunzip_errors[] = { | 882 | static char *const bunzip_errors[] = { |
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c index 6886239d0..668b01618 100644 --- a/archival/libarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c | |||
@@ -353,8 +353,10 @@ unpack_lzma_stream(transformer_state_t *xstate) | |||
353 | if ((int32_t)pos < 0) { | 353 | if ((int32_t)pos < 0) { |
354 | pos += header.dict_size; | 354 | pos += header.dict_size; |
355 | /* see unzip_bad_lzma_2.zip: */ | 355 | /* see unzip_bad_lzma_2.zip: */ |
356 | if (pos >= buffer_size) | 356 | if (pos >= buffer_size) { |
357 | dbg("%d pos:%d buffer_size:%d", __LINE__, pos, buffer_size); | ||
357 | goto bad; | 358 | goto bad; |
359 | } | ||
358 | } | 360 | } |
359 | previous_byte = buffer[pos]; | 361 | previous_byte = buffer[pos]; |
360 | goto one_byte1; | 362 | goto one_byte1; |
@@ -430,10 +432,9 @@ unpack_lzma_stream(transformer_state_t *xstate) | |||
430 | for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--) | 432 | for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--) |
431 | rep0 = (rep0 << 1) | rc_direct_bit(rc); | 433 | rep0 = (rep0 << 1) | rc_direct_bit(rc); |
432 | rep0 <<= LZMA_NUM_ALIGN_BITS; | 434 | rep0 <<= LZMA_NUM_ALIGN_BITS; |
433 | if ((int32_t)rep0 < 0) { | 435 | // Note: (int32_t)rep0 may be < 0 here |
434 | dbg("%d rep0:%d", __LINE__, rep0); | 436 | // (I have linux-3.3.4.tar.lzma which has it). |
435 | goto bad; | 437 | // I moved the check after "++rep0 == 0" check below. |
436 | } | ||
437 | prob3 = p + LZMA_ALIGN; | 438 | prob3 = p + LZMA_ALIGN; |
438 | } | 439 | } |
439 | i2 = 1; | 440 | i2 = 1; |
@@ -444,8 +445,13 @@ unpack_lzma_stream(transformer_state_t *xstate) | |||
444 | i2 <<= 1; | 445 | i2 <<= 1; |
445 | } | 446 | } |
446 | } | 447 | } |
447 | if (++rep0 == 0) | 448 | rep0++; |
448 | break; | 449 | if ((int32_t)rep0 <= 0) { |
450 | if (rep0 == 0) | ||
451 | break; | ||
452 | dbg("%d rep0:%d", __LINE__, rep0); | ||
453 | goto bad; | ||
454 | } | ||
449 | } | 455 | } |
450 | 456 | ||
451 | len += LZMA_MATCH_MIN_LEN; | 457 | len += LZMA_MATCH_MIN_LEN; |
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index 5c495e14e..52fa4554a 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c | |||
@@ -414,7 +414,8 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | |||
414 | // case 'D': /* GNU dump dir */ | 414 | // case 'D': /* GNU dump dir */ |
415 | // case 'M': /* Continuation of multi volume archive */ | 415 | // case 'M': /* Continuation of multi volume archive */ |
416 | // case 'N': /* Old GNU for names > 100 characters */ | 416 | // case 'N': /* Old GNU for names > 100 characters */ |
417 | // case 'V': /* Volume header */ | 417 | case 'V': /* Volume header */ |
418 | ; /* Fall through to skip it */ | ||
418 | #endif | 419 | #endif |
419 | } | 420 | } |
420 | skip_ext_hdr: | 421 | skip_ext_hdr: |
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 0160a64fe..399ee03a7 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c | |||
@@ -304,8 +304,7 @@ static transformer_state_t *open_transformer(const char *fname, int fail_if_not_ | |||
304 | 304 | ||
305 | if (ENABLE_FEATURE_SEAMLESS_LZMA) { | 305 | if (ENABLE_FEATURE_SEAMLESS_LZMA) { |
306 | /* .lzma has no header/signature, can only detect it by extension */ | 306 | /* .lzma has no header/signature, can only detect it by extension */ |
307 | char *sfx = strrchr(fname, '.'); | 307 | if (is_suffixed_with(fname, ".lzma")) { |
308 | if (sfx && strcmp(sfx+1, "lzma") == 0) { | ||
309 | xstate = xzalloc(sizeof(*xstate)); | 308 | xstate = xzalloc(sizeof(*xstate)); |
310 | xstate->src_fd = fd; | 309 | xstate->src_fd = fd; |
311 | xstate->xformer = unpack_lzma_stream; | 310 | xstate->xformer = unpack_lzma_stream; |
diff --git a/archival/tar.c b/archival/tar.c index 9a171ceea..22ad0e0f2 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1197,8 +1197,16 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1197 | tar_handle->seek = seek_by_read; | 1197 | tar_handle->seek = seek_by_read; |
1198 | } else | 1198 | } else |
1199 | if (ENABLE_FEATURE_TAR_AUTODETECT | 1199 | if (ENABLE_FEATURE_TAR_AUTODETECT |
1200 | && ENABLE_FEATURE_SEAMLESS_LZMA | ||
1200 | && flags == O_RDONLY | 1201 | && flags == O_RDONLY |
1201 | && !(opt & OPT_ANY_COMPRESS) | 1202 | && !(opt & OPT_ANY_COMPRESS) |
1203 | && is_suffixed_with(tar_filename, ".lzma") | ||
1204 | /* We do this only for .lzma files, they have no signature. | ||
1205 | * All other compression formats are recognized in | ||
1206 | * get_header_tar() when first tar block has invalid format. | ||
1207 | * Doing it here for all filenames would falsely trigger | ||
1208 | * on e.g. tarball with 1st file named "BZh5". | ||
1209 | */ | ||
1202 | ) { | 1210 | ) { |
1203 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); | 1211 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); |
1204 | if (tar_handle->src_fd < 0) | 1212 | if (tar_handle->src_fd < 0) |
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index 18005618e..5a49bc4a8 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.30.0.git | 3 | # Busybox version: 1.30.0.git |
4 | # Mon Sep 10 15:03:06 2018 | 4 | # Wed Nov 28 10:24:41 2018 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -26,6 +26,7 @@ CONFIG_LFS=y | |||
26 | # CONFIG_FEATURE_PIDFILE is not set | 26 | # CONFIG_FEATURE_PIDFILE is not set |
27 | CONFIG_PID_FILE_PATH="" | 27 | CONFIG_PID_FILE_PATH="" |
28 | CONFIG_BUSYBOX=y | 28 | CONFIG_BUSYBOX=y |
29 | CONFIG_FEATURE_SHOW_SCRIPT=y | ||
29 | CONFIG_FEATURE_INSTALLER=y | 30 | CONFIG_FEATURE_INSTALLER=y |
30 | # CONFIG_INSTALL_NO_USR is not set | 31 | # CONFIG_INSTALL_NO_USR is not set |
31 | # CONFIG_FEATURE_SUID is not set | 32 | # CONFIG_FEATURE_SUID is not set |
@@ -96,6 +97,7 @@ CONFIG_NO_DEBUG_LIB=y | |||
96 | # CONFIG_FEATURE_USE_BSS_TAIL is not set | 97 | # CONFIG_FEATURE_USE_BSS_TAIL is not set |
97 | CONFIG_FLOAT_DURATION=y | 98 | CONFIG_FLOAT_DURATION=y |
98 | CONFIG_FEATURE_RTMINMAX=y | 99 | CONFIG_FEATURE_RTMINMAX=y |
100 | CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS=y | ||
99 | CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | 101 | CONFIG_FEATURE_BUFFERS_USE_MALLOC=y |
100 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 102 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
101 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 103 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
@@ -668,6 +670,8 @@ CONFIG_XXD=y | |||
668 | # CONFIG_FEATURE_MOUNT_FSTAB is not set | 670 | # CONFIG_FEATURE_MOUNT_FSTAB is not set |
669 | # CONFIG_FEATURE_MOUNT_OTHERTAB is not set | 671 | # CONFIG_FEATURE_MOUNT_OTHERTAB is not set |
670 | # CONFIG_MOUNTPOINT is not set | 672 | # CONFIG_MOUNTPOINT is not set |
673 | # CONFIG_NOLOGIN is not set | ||
674 | # CONFIG_NOLOGIN_DEPENDENCIES is not set | ||
671 | # CONFIG_NSENTER is not set | 675 | # CONFIG_NSENTER is not set |
672 | # CONFIG_PIVOT_ROOT is not set | 676 | # CONFIG_PIVOT_ROOT is not set |
673 | # CONFIG_RDATE is not set | 677 | # CONFIG_RDATE is not set |
@@ -916,6 +920,7 @@ CONFIG_NC_SERVER=y | |||
916 | # CONFIG_NTPD is not set | 920 | # CONFIG_NTPD is not set |
917 | # CONFIG_FEATURE_NTPD_SERVER is not set | 921 | # CONFIG_FEATURE_NTPD_SERVER is not set |
918 | # CONFIG_FEATURE_NTPD_CONF is not set | 922 | # CONFIG_FEATURE_NTPD_CONF is not set |
923 | # CONFIG_FEATURE_NTP_AUTH is not set | ||
919 | # CONFIG_PING is not set | 924 | # CONFIG_PING is not set |
920 | # CONFIG_PING6 is not set | 925 | # CONFIG_PING6 is not set |
921 | # CONFIG_FEATURE_FANCY_PING is not set | 926 | # CONFIG_FEATURE_FANCY_PING is not set |
@@ -1147,6 +1152,7 @@ CONFIG_FEATURE_SH_STANDALONE=y | |||
1147 | CONFIG_FEATURE_SH_NOFORK=y | 1152 | CONFIG_FEATURE_SH_NOFORK=y |
1148 | # CONFIG_FEATURE_SH_READ_FRAC is not set | 1153 | # CONFIG_FEATURE_SH_READ_FRAC is not set |
1149 | CONFIG_FEATURE_SH_HISTFILESIZE=y | 1154 | CONFIG_FEATURE_SH_HISTFILESIZE=y |
1155 | CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y | ||
1150 | 1156 | ||
1151 | # | 1157 | # |
1152 | # System Logging Utilities | 1158 | # System Logging Utilities |
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index 6389867f2..9d6e32104 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Busybox version: 1.30.0.git | 3 | # Busybox version: 1.30.0.git |
4 | # Mon Sep 10 15:03:06 2018 | 4 | # Wed Nov 28 10:26:29 2018 |
5 | # | 5 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_HAVE_DOT_CONFIG=y |
7 | # CONFIG_PLATFORM_POSIX is not set | 7 | # CONFIG_PLATFORM_POSIX is not set |
@@ -26,6 +26,7 @@ CONFIG_LFS=y | |||
26 | # CONFIG_FEATURE_PIDFILE is not set | 26 | # CONFIG_FEATURE_PIDFILE is not set |
27 | CONFIG_PID_FILE_PATH="" | 27 | CONFIG_PID_FILE_PATH="" |
28 | CONFIG_BUSYBOX=y | 28 | CONFIG_BUSYBOX=y |
29 | CONFIG_FEATURE_SHOW_SCRIPT=y | ||
29 | CONFIG_FEATURE_INSTALLER=y | 30 | CONFIG_FEATURE_INSTALLER=y |
30 | # CONFIG_INSTALL_NO_USR is not set | 31 | # CONFIG_INSTALL_NO_USR is not set |
31 | # CONFIG_FEATURE_SUID is not set | 32 | # CONFIG_FEATURE_SUID is not set |
@@ -96,6 +97,7 @@ CONFIG_NO_DEBUG_LIB=y | |||
96 | # CONFIG_FEATURE_USE_BSS_TAIL is not set | 97 | # CONFIG_FEATURE_USE_BSS_TAIL is not set |
97 | CONFIG_FLOAT_DURATION=y | 98 | CONFIG_FLOAT_DURATION=y |
98 | CONFIG_FEATURE_RTMINMAX=y | 99 | CONFIG_FEATURE_RTMINMAX=y |
100 | CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS=y | ||
99 | CONFIG_FEATURE_BUFFERS_USE_MALLOC=y | 101 | CONFIG_FEATURE_BUFFERS_USE_MALLOC=y |
100 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set | 102 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set |
101 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set | 103 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set |
@@ -668,6 +670,8 @@ CONFIG_XXD=y | |||
668 | # CONFIG_FEATURE_MOUNT_FSTAB is not set | 670 | # CONFIG_FEATURE_MOUNT_FSTAB is not set |
669 | # CONFIG_FEATURE_MOUNT_OTHERTAB is not set | 671 | # CONFIG_FEATURE_MOUNT_OTHERTAB is not set |
670 | # CONFIG_MOUNTPOINT is not set | 672 | # CONFIG_MOUNTPOINT is not set |
673 | # CONFIG_NOLOGIN is not set | ||
674 | # CONFIG_NOLOGIN_DEPENDENCIES is not set | ||
671 | # CONFIG_NSENTER is not set | 675 | # CONFIG_NSENTER is not set |
672 | # CONFIG_PIVOT_ROOT is not set | 676 | # CONFIG_PIVOT_ROOT is not set |
673 | # CONFIG_RDATE is not set | 677 | # CONFIG_RDATE is not set |
@@ -916,6 +920,7 @@ CONFIG_NC_SERVER=y | |||
916 | # CONFIG_NTPD is not set | 920 | # CONFIG_NTPD is not set |
917 | # CONFIG_FEATURE_NTPD_SERVER is not set | 921 | # CONFIG_FEATURE_NTPD_SERVER is not set |
918 | # CONFIG_FEATURE_NTPD_CONF is not set | 922 | # CONFIG_FEATURE_NTPD_CONF is not set |
923 | # CONFIG_FEATURE_NTP_AUTH is not set | ||
919 | # CONFIG_PING is not set | 924 | # CONFIG_PING is not set |
920 | # CONFIG_PING6 is not set | 925 | # CONFIG_PING6 is not set |
921 | # CONFIG_FEATURE_FANCY_PING is not set | 926 | # CONFIG_FEATURE_FANCY_PING is not set |
@@ -1147,6 +1152,7 @@ CONFIG_FEATURE_SH_STANDALONE=y | |||
1147 | CONFIG_FEATURE_SH_NOFORK=y | 1152 | CONFIG_FEATURE_SH_NOFORK=y |
1148 | # CONFIG_FEATURE_SH_READ_FRAC is not set | 1153 | # CONFIG_FEATURE_SH_READ_FRAC is not set |
1149 | CONFIG_FEATURE_SH_HISTFILESIZE=y | 1154 | CONFIG_FEATURE_SH_HISTFILESIZE=y |
1155 | CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y | ||
1150 | 1156 | ||
1151 | # | 1157 | # |
1152 | # System Logging Utilities | 1158 | # System Logging Utilities |
diff --git a/coreutils/dd.c b/coreutils/dd.c index d29357dae..d73f6224b 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c | |||
@@ -37,7 +37,7 @@ | |||
37 | //config: elapsed time and speed. | 37 | //config: elapsed time and speed. |
38 | //config: | 38 | //config: |
39 | //config:config FEATURE_DD_IBS_OBS | 39 | //config:config FEATURE_DD_IBS_OBS |
40 | //config: bool "Enable ibs, obs, iflag and conv options" | 40 | //config: bool "Enable ibs, obs, iflag, oflag and conv options" |
41 | //config: default y | 41 | //config: default y |
42 | //config: depends on DD | 42 | //config: depends on DD |
43 | //config: help | 43 | //config: help |
@@ -56,8 +56,11 @@ | |||
56 | //kbuild:lib-$(CONFIG_DD) += dd.o | 56 | //kbuild:lib-$(CONFIG_DD) += dd.o |
57 | 57 | ||
58 | //usage:#define dd_trivial_usage | 58 | //usage:#define dd_trivial_usage |
59 | //usage: "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" | 59 | //usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n" |
60 | //usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync] [iflag=skip_bytes|fullblock]") | 60 | //usage: IF_FEATURE_DD_IBS_OBS( |
61 | //usage: " [conv=notrunc|noerror|sync|fsync]\n" | ||
62 | //usage: " [iflag=skip_bytes|fullblock] [oflag=seek_bytes]" | ||
63 | //usage: ) | ||
61 | //usage:#define dd_full_usage "\n\n" | 64 | //usage:#define dd_full_usage "\n\n" |
62 | //usage: "Copy a file with converting and formatting\n" | 65 | //usage: "Copy a file with converting and formatting\n" |
63 | //usage: "\n if=FILE Read from FILE instead of stdin" | 66 | //usage: "\n if=FILE Read from FILE instead of stdin" |
@@ -80,6 +83,7 @@ | |||
80 | //usage: "\n conv=swab Swap every pair of bytes" | 83 | //usage: "\n conv=swab Swap every pair of bytes" |
81 | //usage: "\n iflag=skip_bytes skip=N is in bytes" | 84 | //usage: "\n iflag=skip_bytes skip=N is in bytes" |
82 | //usage: "\n iflag=fullblock Read full blocks" | 85 | //usage: "\n iflag=fullblock Read full blocks" |
86 | //usage: "\n oflag=seek_bytes seek=N is in bytes" | ||
83 | //usage: ) | 87 | //usage: ) |
84 | //usage: IF_FEATURE_DD_STATUS( | 88 | //usage: IF_FEATURE_DD_STATUS( |
85 | //usage: "\n status=noxfer Suppress rate output" | 89 | //usage: "\n status=noxfer Suppress rate output" |
@@ -136,10 +140,14 @@ enum { | |||
136 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, | 140 | FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, |
137 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, | 141 | FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, |
138 | /* end of input flags */ | 142 | /* end of input flags */ |
139 | FLAG_TWOBUFS = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, | 143 | /* start of output flags */ |
140 | FLAG_COUNT = 1 << 8, | 144 | FLAG_OFLAG_SHIFT = 7, |
141 | FLAG_STATUS_NONE = 1 << 9, | 145 | FLAG_SEEK_BYTES = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, |
142 | FLAG_STATUS_NOXFER = 1 << 10, | 146 | /* end of output flags */ |
147 | FLAG_TWOBUFS = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, | ||
148 | FLAG_COUNT = 1 << 9, | ||
149 | FLAG_STATUS_NONE = 1 << 10, | ||
150 | FLAG_STATUS_NOXFER = 1 << 11, | ||
143 | }; | 151 | }; |
144 | 152 | ||
145 | static void dd_output_status(int UNUSED_PARAM cur_signal) | 153 | static void dd_output_status(int UNUSED_PARAM cur_signal) |
@@ -253,7 +261,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
253 | static const char keywords[] ALIGN1 = | 261 | static const char keywords[] ALIGN1 = |
254 | "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0") | 262 | "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0") |
255 | #if ENABLE_FEATURE_DD_IBS_OBS | 263 | #if ENABLE_FEATURE_DD_IBS_OBS |
256 | "ibs\0""obs\0""conv\0""iflag\0" | 264 | "ibs\0""obs\0""conv\0""iflag\0""oflag\0" |
257 | #endif | 265 | #endif |
258 | ; | 266 | ; |
259 | #if ENABLE_FEATURE_DD_IBS_OBS | 267 | #if ENABLE_FEATURE_DD_IBS_OBS |
@@ -261,6 +269,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
261 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; | 269 | "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; |
262 | static const char iflag_words[] ALIGN1 = | 270 | static const char iflag_words[] ALIGN1 = |
263 | "skip_bytes\0""fullblock\0"; | 271 | "skip_bytes\0""fullblock\0"; |
272 | static const char oflag_words[] ALIGN1 = | ||
273 | "seek_bytes\0"; | ||
264 | #endif | 274 | #endif |
265 | #if ENABLE_FEATURE_DD_STATUS | 275 | #if ENABLE_FEATURE_DD_STATUS |
266 | static const char status_words[] ALIGN1 = | 276 | static const char status_words[] ALIGN1 = |
@@ -279,6 +289,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
279 | OP_obs, | 289 | OP_obs, |
280 | OP_conv, | 290 | OP_conv, |
281 | OP_iflag, | 291 | OP_iflag, |
292 | OP_oflag, | ||
282 | /* Must be in the same order as FLAG_XXX! */ | 293 | /* Must be in the same order as FLAG_XXX! */ |
283 | OP_conv_notrunc = 0, | 294 | OP_conv_notrunc = 0, |
284 | OP_conv_sync, | 295 | OP_conv_sync, |
@@ -300,6 +311,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
300 | //swab swap every pair of input bytes: will abort on non-even reads | 311 | //swab swap every pair of input bytes: will abort on non-even reads |
301 | OP_iflag_skip_bytes, | 312 | OP_iflag_skip_bytes, |
302 | OP_iflag_fullblock, | 313 | OP_iflag_fullblock, |
314 | OP_oflag_seek_bytes, | ||
303 | #endif | 315 | #endif |
304 | }; | 316 | }; |
305 | smallint exitcode = EXIT_FAILURE; | 317 | smallint exitcode = EXIT_FAILURE; |
@@ -315,13 +327,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
315 | #endif | 327 | #endif |
316 | /* These are all zeroed at once! */ | 328 | /* These are all zeroed at once! */ |
317 | struct { | 329 | struct { |
318 | size_t oc; | 330 | IF_FEATURE_DD_IBS_OBS(size_t ocount;) |
319 | ssize_t prev_read_size; /* for detecting swab failure */ | 331 | ssize_t prev_read_size; /* for detecting swab failure */ |
320 | off_t count; | 332 | off_t count; |
321 | off_t seek, skip; | 333 | off_t seek, skip; |
322 | const char *infile, *outfile; | 334 | const char *infile, *outfile; |
323 | } Z; | 335 | } Z; |
324 | #define oc (Z.oc ) | 336 | #define ocount (Z.ocount ) |
325 | #define prev_read_size (Z.prev_read_size) | 337 | #define prev_read_size (Z.prev_read_size) |
326 | #define count (Z.count ) | 338 | #define count (Z.count ) |
327 | #define seek (Z.seek ) | 339 | #define seek (Z.seek ) |
@@ -371,6 +383,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
371 | G.flags |= parse_comma_flags(val, iflag_words, "iflag") << FLAG_IFLAG_SHIFT; | 383 | G.flags |= parse_comma_flags(val, iflag_words, "iflag") << FLAG_IFLAG_SHIFT; |
372 | /*continue;*/ | 384 | /*continue;*/ |
373 | } | 385 | } |
386 | if (what == OP_oflag) { | ||
387 | G.flags |= parse_comma_flags(val, oflag_words, "oflag") << FLAG_OFLAG_SHIFT; | ||
388 | /*continue;*/ | ||
389 | } | ||
374 | #endif | 390 | #endif |
375 | if (what == OP_bs) { | 391 | if (what == OP_bs) { |
376 | ibs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes); | 392 | ibs = xatoul_range_sfx(val, 1, ULONG_MAX/2, cwbkMG_suffixes); |
@@ -447,7 +463,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
447 | xmove_fd(xopen(outfile, oflag), ofd); | 463 | xmove_fd(xopen(outfile, oflag), ofd); |
448 | 464 | ||
449 | if (seek && !(G.flags & FLAG_NOTRUNC)) { | 465 | if (seek && !(G.flags & FLAG_NOTRUNC)) { |
450 | if (ftruncate(ofd, seek * obs) < 0) { | 466 | size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; |
467 | if (ftruncate(ofd, seek * blocksz) < 0) { | ||
451 | struct stat st; | 468 | struct stat st; |
452 | 469 | ||
453 | if (fstat(ofd, &st) < 0 | 470 | if (fstat(ofd, &st) < 0 |
@@ -480,7 +497,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
480 | } | 497 | } |
481 | } | 498 | } |
482 | if (seek) { | 499 | if (seek) { |
483 | if (lseek(ofd, seek * obs, SEEK_CUR) < 0) | 500 | size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; |
501 | if (lseek(ofd, seek * blocksz, SEEK_CUR) < 0) | ||
484 | goto die_outfile; | 502 | goto die_outfile; |
485 | } | 503 | } |
486 | 504 | ||
@@ -536,24 +554,26 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
536 | n = ibs; | 554 | n = ibs; |
537 | } | 555 | } |
538 | } | 556 | } |
557 | #if ENABLE_FEATURE_DD_IBS_OBS | ||
539 | if (G.flags & FLAG_TWOBUFS) { | 558 | if (G.flags & FLAG_TWOBUFS) { |
540 | char *tmp = ibuf; | 559 | char *tmp = ibuf; |
541 | while (n) { | 560 | while (n) { |
542 | size_t d = obs - oc; | 561 | size_t d = obs - ocount; |
543 | |||
544 | if (d > (size_t)n) | 562 | if (d > (size_t)n) |
545 | d = n; | 563 | d = n; |
546 | memcpy(obuf + oc, tmp, d); | 564 | memcpy(obuf + ocount, tmp, d); |
547 | n -= d; | 565 | n -= d; |
548 | tmp += d; | 566 | tmp += d; |
549 | oc += d; | 567 | ocount += d; |
550 | if (oc == obs) { | 568 | if (ocount == obs) { |
551 | if (write_and_stats(obuf, obs, obs, outfile)) | 569 | if (write_and_stats(obuf, obs, obs, outfile)) |
552 | goto out_status; | 570 | goto out_status; |
553 | oc = 0; | 571 | ocount = 0; |
554 | } | 572 | } |
555 | } | 573 | } |
556 | } else { | 574 | } else |
575 | #endif | ||
576 | { | ||
557 | if (write_and_stats(ibuf, n, obs, outfile)) | 577 | if (write_and_stats(ibuf, n, obs, outfile)) |
558 | goto out_status; | 578 | goto out_status; |
559 | } | 579 | } |
@@ -564,11 +584,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) | |||
564 | goto die_outfile; | 584 | goto die_outfile; |
565 | } | 585 | } |
566 | 586 | ||
567 | if (ENABLE_FEATURE_DD_IBS_OBS && oc) { | 587 | #if ENABLE_FEATURE_DD_IBS_OBS |
568 | if (write_and_stats(obuf, oc, obs, outfile)) | 588 | if (ocount != 0) { |
589 | if (write_and_stats(obuf, ocount, obs, outfile)) | ||
569 | goto out_status; | 590 | goto out_status; |
570 | } | 591 | } |
571 | 592 | #endif | |
572 | if (close(ifd) < 0) { | 593 | if (close(ifd) < 0) { |
573 | die_infile: | 594 | die_infile: |
574 | bb_simple_perror_msg_and_die(infile); | 595 | bb_simple_perror_msg_and_die(infile); |
diff --git a/coreutils/printf.c b/coreutils/printf.c index a666ff7ac..67d3b2eda 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c | |||
@@ -95,6 +95,12 @@ static int multiconvert(const char *arg, void *result, converter convert) | |||
95 | 95 | ||
96 | static void FAST_FUNC conv_strtoull(const char *arg, void *result) | 96 | static void FAST_FUNC conv_strtoull(const char *arg, void *result) |
97 | { | 97 | { |
98 | /* Allow leading '+' - bb_strtoull() by itself does not allow it, | ||
99 | * and probably shouldn't (other callers might require purely numeric | ||
100 | * inputs to be allowed. | ||
101 | */ | ||
102 | if (arg[0] == '+') | ||
103 | arg++; | ||
98 | *(unsigned long long*)result = bb_strtoull(arg, NULL, 0); | 104 | *(unsigned long long*)result = bb_strtoull(arg, NULL, 0); |
99 | /* both coreutils 6.10 and bash 3.2: | 105 | /* both coreutils 6.10 and bash 3.2: |
100 | * $ printf '%x\n' -2 | 106 | * $ printf '%x\n' -2 |
@@ -107,6 +113,8 @@ static void FAST_FUNC conv_strtoull(const char *arg, void *result) | |||
107 | } | 113 | } |
108 | static void FAST_FUNC conv_strtoll(const char *arg, void *result) | 114 | static void FAST_FUNC conv_strtoll(const char *arg, void *result) |
109 | { | 115 | { |
116 | if (arg[0] == '+') | ||
117 | arg++; | ||
110 | *(long long*)result = bb_strtoll(arg, NULL, 0); | 118 | *(long long*)result = bb_strtoll(arg, NULL, 0); |
111 | } | 119 | } |
112 | static void FAST_FUNC conv_strtod(const char *arg, void *result) | 120 | static void FAST_FUNC conv_strtod(const char *arg, void *result) |
@@ -191,6 +199,7 @@ static void print_direc(char *format, unsigned fmt_length, | |||
191 | if (have_width - 1 == have_prec) | 199 | if (have_width - 1 == have_prec) |
192 | have_width = NULL; | 200 | have_width = NULL; |
193 | 201 | ||
202 | /* multiconvert sets errno = 0, but %s needs it cleared */ | ||
194 | errno = 0; | 203 | errno = 0; |
195 | 204 | ||
196 | switch (format[fmt_length - 1]) { | 205 | switch (format[fmt_length - 1]) { |
@@ -199,7 +208,7 @@ static void print_direc(char *format, unsigned fmt_length, | |||
199 | break; | 208 | break; |
200 | case 'd': | 209 | case 'd': |
201 | case 'i': | 210 | case 'i': |
202 | llv = my_xstrtoll(argument); | 211 | llv = my_xstrtoll(skip_whitespace(argument)); |
203 | print_long: | 212 | print_long: |
204 | if (!have_width) { | 213 | if (!have_width) { |
205 | if (!have_prec) | 214 | if (!have_prec) |
@@ -217,7 +226,7 @@ static void print_direc(char *format, unsigned fmt_length, | |||
217 | case 'u': | 226 | case 'u': |
218 | case 'x': | 227 | case 'x': |
219 | case 'X': | 228 | case 'X': |
220 | llv = my_xstrtoull(argument); | 229 | llv = my_xstrtoull(skip_whitespace(argument)); |
221 | /* cheat: unsigned long and long have same width, so... */ | 230 | /* cheat: unsigned long and long have same width, so... */ |
222 | goto print_long; | 231 | goto print_long; |
223 | case 's': | 232 | case 's': |
diff --git a/docs/embedded-scripts.txt b/docs/embedded-scripts.txt new file mode 100644 index 000000000..7a273d698 --- /dev/null +++ b/docs/embedded-scripts.txt | |||
@@ -0,0 +1,111 @@ | |||
1 | Embedded Shell Scripts in BusyBox | ||
2 | ================================= | ||
3 | |||
4 | BusyBox allows applets to be implemented as shell scripts. Since | ||
5 | this obviously requires a shell to interpret the scripts the feature | ||
6 | depends on having a shell built into the binary. Either ash or hush | ||
7 | will do. If both are present ash will be used. Support for embedded | ||
8 | scripts also has to be enabled. | ||
9 | |||
10 | It's unlikely that your applet will be implemented as a pure shell | ||
11 | script: it will probably need some external commands. If these are | ||
12 | to be provided by BusyBox you'll need to ensure they're enabled too. | ||
13 | |||
14 | There are two ways to include scripts in BusyBox: the quick-and-dirty | ||
15 | custom script and the full-featured scripted applet. | ||
16 | |||
17 | Custom Scripts | ||
18 | -------------- | ||
19 | |||
20 | When embedded script support is enabled the BusyBox build process | ||
21 | assumes that any files in the directory 'embed' at the top level of | ||
22 | the source tree are scripts to be embedded. | ||
23 | |||
24 | The embed directory isn't present in the BusyBox source tree and | ||
25 | BusyBox itself will never put anything there: it's entirely for the | ||
26 | use of third parties. | ||
27 | |||
28 | Adding a custom script is as simple as running the following sequence | ||
29 | of commands in the BusyBox source directory: | ||
30 | |||
31 | mkdir embed | ||
32 | echo 'echo foo' >embed/foo | ||
33 | make defconfig | ||
34 | make | ||
35 | |||
36 | The resulting binary includes the new applet foo! | ||
37 | |||
38 | Custom scripts have limited opportunities for configuration: the only | ||
39 | control developers have is to put them in the embed directory, or not. | ||
40 | Everything else takes default values. For more control you need the | ||
41 | additional features provided by scripted applets. | ||
42 | |||
43 | Scripted Applets | ||
44 | ---------------- | ||
45 | |||
46 | Suppose we want to make a shell script version of the sample applet | ||
47 | from the New Applet HOWTO. First we'd have to write a script (vaguely) | ||
48 | equivalent to the C code: | ||
49 | |||
50 | return $(($RANDOM%256)) | ||
51 | |||
52 | This should be placed in the file applets_sh/mu in the source tree. | ||
53 | |||
54 | Next we need the configuration data. This is very similar to the example | ||
55 | code for the native applet: | ||
56 | |||
57 | //config:config MU | ||
58 | //config: bool "MU" | ||
59 | //config: default y | ||
60 | //config: help | ||
61 | //config: Returns an indeterminate value. | ||
62 | |||
63 | //applet:IF_MU(APPLET_SCRIPTED(mu, scripted, BB_DIR_USR_BIN, BB_SUID_DROP, mu)) | ||
64 | |||
65 | //usage:#define mu_trivial_usage | ||
66 | //usage: "[-abcde] FILE..." | ||
67 | //usage:#define mu_full_usage | ||
68 | //usage: "Returns an indeterminate value\n" | ||
69 | //usage: "\n -a First function" | ||
70 | //usage: "\n -b Second function" | ||
71 | |||
72 | The only difference is that the applet is specified as being of type | ||
73 | APPLET_SCRIPTED. It would also be useful to include details of any | ||
74 | dependencies the script has. No external commands are used by our mu | ||
75 | script, but it does depend on optional shell features. We can ensure | ||
76 | these are selected by adding this to the configuration: | ||
77 | |||
78 | //config:config MU_DEPENDENCIES | ||
79 | //config: bool "Enable dependencies for mu" | ||
80 | //config: default y | ||
81 | //config: depends on MU | ||
82 | //config: select ASH_RANDOM_SUPPORT | ||
83 | //config: select FEATURE_SH_MATH | ||
84 | //config: help | ||
85 | //config: mu is implemented as a shell script. It requires support | ||
86 | //config: for $RANDOM and arithmetic. | ||
87 | |||
88 | The configuration data should be placed in a C file in an appropriate | ||
89 | subdirectory. There isn't any C code, though! In this case the file | ||
90 | could be miscutils/mu.c. | ||
91 | |||
92 | Scripted applets are just as configurable as applets written in C. | ||
93 | They can be enabled or disabled using the configuration menu; their | ||
94 | install directory can be specified and their usage messages are stored | ||
95 | along with those of all other applets. | ||
96 | |||
97 | Additional Notes | ||
98 | ---------------- | ||
99 | |||
100 | The source for embedded scripts can be displayed by running: | ||
101 | |||
102 | busybox --show SCRIPT | ||
103 | |||
104 | This can be disabled by turning off FEATURE_SHOW_SCRIPT in the | ||
105 | configuration, though it won't prevent a determined user from | ||
106 | extracting the source code. | ||
107 | |||
108 | It can be argued that embedded scripts are linked into the BusyBox | ||
109 | binary and are therefore not subject to the 'mere aggregation' | ||
110 | exception in the GPL. If this is the case embedded scripts should | ||
111 | have a licence compatible with BusyBox's GPL v2-only licence. | ||
diff --git a/docs/posix_conformance.txt b/docs/posix_conformance.txt index cdf89b744..0e6f4a317 100644 --- a/docs/posix_conformance.txt +++ b/docs/posix_conformance.txt | |||
@@ -182,6 +182,7 @@ dd compatibility options: | |||
182 | conv=fsync | yes | | | 182 | conv=fsync | yes | | |
183 | iflag=skip_bytes| yes | | | 183 | iflag=skip_bytes| yes | | |
184 | iflag=fullblock | yes | | | 184 | iflag=fullblock | yes | | |
185 | oflag=seek_bytes| yes | | | ||
185 | 186 | ||
186 | df POSIX options | 187 | df POSIX options |
187 | option | exists | compliant | remarks | 188 | option | exists | compliant | remarks |
diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index e4c1f2d76..44aa46ece 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script | |||
@@ -6,19 +6,31 @@ RESOLV_CONF="/etc/resolv.conf" | |||
6 | [ -n "$1" ] || { echo "Error: should be called from udhcpc"; exit 1; } | 6 | [ -n "$1" ] || { echo "Error: should be called from udhcpc"; exit 1; } |
7 | 7 | ||
8 | NETMASK="" | 8 | NETMASK="" |
9 | [ -n "$subnet" ] && NETMASK="netmask $subnet" | 9 | if command -v ip >/dev/null; then |
10 | [ -n "$subnet" ] && NETMASK="/$subnet" | ||
11 | else | ||
12 | [ -n "$subnet" ] && NETMASK="netmask $subnet" | ||
13 | fi | ||
10 | BROADCAST="broadcast +" | 14 | BROADCAST="broadcast +" |
11 | [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" | 15 | [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" |
12 | 16 | ||
13 | case "$1" in | 17 | case "$1" in |
14 | deconfig) | 18 | deconfig) |
15 | echo "Setting IP address 0.0.0.0 on $interface" | 19 | echo "Setting IP address 0.0.0.0 on $interface" |
16 | ifconfig $interface 0.0.0.0 | 20 | if command -v ip >/dev/null; then |
21 | ip addr flush dev $interface | ||
22 | else | ||
23 | ifconfig $interface 0.0.0.0 | ||
24 | fi | ||
17 | ;; | 25 | ;; |
18 | 26 | ||
19 | renew|bound) | 27 | renew|bound) |
20 | echo "Setting IP address $ip on $interface" | 28 | echo "Setting IP address $ip on $interface" |
21 | ifconfig $interface $ip $NETMASK $BROADCAST | 29 | if command -v ip >/dev/null; then |
30 | ip addr add $ip$NETMASK $BROADCAST dev $interface | ||
31 | else | ||
32 | ifconfig $interface $ip $NETMASK $BROADCAST | ||
33 | fi | ||
22 | 34 | ||
23 | if [ -n "$router" ] ; then | 35 | if [ -n "$router" ] ; then |
24 | echo "Deleting routers" | 36 | echo "Deleting routers" |
diff --git a/findutils/xargs.c b/findutils/xargs.c index 4399783ea..2ce5634ca 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -277,14 +277,15 @@ static int xargs_exec(void) | |||
277 | status = (errno == ENOENT) ? 127 : 126; | 277 | status = (errno == ENOENT) ? 127 : 126; |
278 | } | 278 | } |
279 | else if (status >= 0x180) { | 279 | else if (status >= 0x180) { |
280 | bb_error_msg("'%s' terminated by signal %d", | 280 | bb_error_msg("'%s' terminated by signal %u", |
281 | G.args[0], status - 0x180); | 281 | G.args[0], status - 0x180); |
282 | status = 125; | 282 | status = 125; |
283 | } | 283 | } |
284 | else if (status != 0) { | 284 | else if (status != 0) { |
285 | if (status == 255) { | 285 | if (status == 255) { |
286 | bb_error_msg("%s: exited with status 255; aborting", G.args[0]); | 286 | bb_error_msg("%s: exited with status 255; aborting", G.args[0]); |
287 | return 124; | 287 | status = 124; |
288 | goto ret; | ||
288 | } | 289 | } |
289 | /* "123 if any invocation of the command exited with status 1-125" | 290 | /* "123 if any invocation of the command exited with status 1-125" |
290 | * This implies that nonzero exit code is remembered, | 291 | * This implies that nonzero exit code is remembered, |
@@ -293,7 +294,7 @@ static int xargs_exec(void) | |||
293 | G.xargs_exitcode = 123; | 294 | G.xargs_exitcode = 123; |
294 | status = 0; | 295 | status = 0; |
295 | } | 296 | } |
296 | 297 | ret: | |
297 | if (status != 0) | 298 | if (status != 0) |
298 | G.xargs_exitcode = status; | 299 | G.xargs_exitcode = status; |
299 | return status; | 300 | return status; |
diff --git a/include/.gitignore b/include/.gitignore index 75afff9ca..13a96e018 100644 --- a/include/.gitignore +++ b/include/.gitignore | |||
@@ -5,6 +5,7 @@ | |||
5 | /autoconf.h | 5 | /autoconf.h |
6 | /bbconfigopts_bz2.h | 6 | /bbconfigopts_bz2.h |
7 | /bbconfigopts.h | 7 | /bbconfigopts.h |
8 | /embedded_scripts.h | ||
8 | /NUM_APPLETS.h | 9 | /NUM_APPLETS.h |
9 | /usage_compressed.h | 10 | /usage_compressed.h |
10 | /usage.h | 11 | /usage.h |
diff --git a/include/applets.src.h b/include/applets.src.h index 2ddf120ad..60968cec7 100644 --- a/include/applets.src.h +++ b/include/applets.src.h | |||
@@ -27,36 +27,49 @@ s - suid type: | |||
27 | # define APPLET_ODDNAME(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 27 | # define APPLET_ODDNAME(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
28 | # define APPLET_NOEXEC(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 28 | # define APPLET_NOEXEC(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
29 | # define APPLET_NOFORK(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 29 | # define APPLET_NOFORK(name,main,l,s,help) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
30 | # define APPLET_SCRIPTED(name,main,l,s,help) | ||
30 | 31 | ||
31 | #elif defined(NAME_MAIN) | 32 | #elif defined(NAME_MAIN) |
32 | # define APPLET(name,l,s) name name##_main | 33 | # define APPLET(name,l,s) name name##_main |
33 | # define APPLET_ODDNAME(name,main,l,s,help) name main##_main | 34 | # define APPLET_ODDNAME(name,main,l,s,help) name main##_main |
34 | # define APPLET_NOEXEC(name,main,l,s,help) name main##_main | 35 | # define APPLET_NOEXEC(name,main,l,s,help) name main##_main |
35 | # define APPLET_NOFORK(name,main,l,s,help) name main##_main | 36 | # define APPLET_NOFORK(name,main,l,s,help) name main##_main |
37 | # define APPLET_SCRIPTED(name,main,l,s,help) name scripted_main | ||
36 | 38 | ||
37 | #elif defined(MAKE_USAGE) && ENABLE_FEATURE_VERBOSE_USAGE | 39 | #elif defined(MAKE_USAGE) && ENABLE_FEATURE_VERBOSE_USAGE |
38 | # define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage name##_full_usage) | 40 | # define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage name##_full_usage) |
39 | # define APPLET_ODDNAME(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage) | 41 | # define APPLET_ODDNAME(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage) |
40 | # define APPLET_NOEXEC(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage) | 42 | # define APPLET_NOEXEC(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage) |
41 | # define APPLET_NOFORK(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage) | 43 | # define APPLET_NOFORK(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage) |
44 | # define APPLET_SCRIPTED(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage help##_full_usage) | ||
42 | 45 | ||
43 | #elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE | 46 | #elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE |
44 | # define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage) | 47 | # define APPLET(name,l,s) MAKE_USAGE(#name, name##_trivial_usage) |
45 | # define APPLET_ODDNAME(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage) | 48 | # define APPLET_ODDNAME(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage) |
46 | # define APPLET_NOEXEC(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage) | 49 | # define APPLET_NOEXEC(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage) |
47 | # define APPLET_NOFORK(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage) | 50 | # define APPLET_NOFORK(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage) |
51 | # define APPLET_SCRIPTED(name,main,l,s,help) MAKE_USAGE(#name, help##_trivial_usage) | ||
48 | 52 | ||
49 | #elif defined(MAKE_LINKS) | 53 | #elif defined(MAKE_LINKS) |
50 | # define APPLET(name,l,c) LINK l name | 54 | # define APPLET(name,l,c) LINK l name |
51 | # define APPLET_ODDNAME(name,main,l,s,help) LINK l name | 55 | # define APPLET_ODDNAME(name,main,l,s,help) LINK l name |
52 | # define APPLET_NOEXEC(name,main,l,s,help) LINK l name | 56 | # define APPLET_NOEXEC(name,main,l,s,help) LINK l name |
53 | # define APPLET_NOFORK(name,main,l,s,help) LINK l name | 57 | # define APPLET_NOFORK(name,main,l,s,help) LINK l name |
58 | # define APPLET_SCRIPTED(name,main,l,s,help) LINK l name | ||
54 | 59 | ||
55 | #elif defined(MAKE_SUID) | 60 | #elif defined(MAKE_SUID) |
56 | # define APPLET(name,l,s) SUID s l name | 61 | # define APPLET(name,l,s) SUID s l name |
57 | # define APPLET_ODDNAME(name,main,l,s,help) SUID s l name | 62 | # define APPLET_ODDNAME(name,main,l,s,help) SUID s l name |
58 | # define APPLET_NOEXEC(name,main,l,s,help) SUID s l name | 63 | # define APPLET_NOEXEC(name,main,l,s,help) SUID s l name |
59 | # define APPLET_NOFORK(name,main,l,s,help) SUID s l name | 64 | # define APPLET_NOFORK(name,main,l,s,help) SUID s l name |
65 | # define APPLET_SCRIPTED(name,main,l,s,help) SUID s l name | ||
66 | |||
67 | #elif defined(MAKE_SCRIPTS) | ||
68 | # define APPLET(name,l,s) | ||
69 | # define APPLET_ODDNAME(name,main,l,s,help) | ||
70 | # define APPLET_NOEXEC(name,main,l,s,help) | ||
71 | # define APPLET_NOFORK(name,main,l,s,help) | ||
72 | # define APPLET_SCRIPTED(name,main,l,s,help) SCRIPT name | ||
60 | 73 | ||
61 | #else | 74 | #else |
62 | static struct bb_applet applets[] = { /* name, main, location, need_suid */ | 75 | static struct bb_applet applets[] = { /* name, main, location, need_suid */ |
@@ -64,6 +77,7 @@ s - suid type: | |||
64 | # define APPLET_ODDNAME(name,main,l,s,help) { #name, #main, l, s }, | 77 | # define APPLET_ODDNAME(name,main,l,s,help) { #name, #main, l, s }, |
65 | # define APPLET_NOEXEC(name,main,l,s,help) { #name, #main, l, s, 1 }, | 78 | # define APPLET_NOEXEC(name,main,l,s,help) { #name, #main, l, s, 1 }, |
66 | # define APPLET_NOFORK(name,main,l,s,help) { #name, #main, l, s, 1, 1 }, | 79 | # define APPLET_NOFORK(name,main,l,s,help) { #name, #main, l, s, 1, 1 }, |
80 | # define APPLET_SCRIPTED(name,main,l,s,help) { #name, #main, l, s }, | ||
67 | #endif | 81 | #endif |
68 | 82 | ||
69 | #if ENABLE_INSTALL_NO_USR | 83 | #if ENABLE_INSTALL_NO_USR |
@@ -84,3 +98,4 @@ INSERT | |||
84 | #undef APPLET_ODDNAME | 98 | #undef APPLET_ODDNAME |
85 | #undef APPLET_NOEXEC | 99 | #undef APPLET_NOEXEC |
86 | #undef APPLET_NOFORK | 100 | #undef APPLET_NOFORK |
101 | #undef APPLET_SCRIPTED | ||
diff --git a/include/bb_archive.h b/include/bb_archive.h index ace9c8e23..5abcdcb44 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h | |||
@@ -228,12 +228,7 @@ const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_F | |||
228 | const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_FUNC; | 228 | const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_FUNC; |
229 | 229 | ||
230 | /* A bit of bunzip2 internals are exposed for compressed help support: */ | 230 | /* A bit of bunzip2 internals are exposed for compressed help support: */ |
231 | typedef struct bunzip_data bunzip_data; | 231 | char *unpack_bz2_data(const char *packed, int packed_len, int unpacked_len) FAST_FUNC; |
232 | int start_bunzip(void *, bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC; | ||
233 | /* NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes | ||
234 | * in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0: */ | ||
235 | int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; | ||
236 | void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; | ||
237 | 232 | ||
238 | /* Meaning and direction (input/output) of the fields are transformer-specific */ | 233 | /* Meaning and direction (input/output) of the fields are transformer-specific */ |
239 | typedef struct transformer_state_t { | 234 | typedef struct transformer_state_t { |
diff --git a/include/libbb.h b/include/libbb.h index 90fdd1178..405c929a2 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -777,18 +777,25 @@ struct hostent *xgethostbyname(const char *name) FAST_FUNC; | |||
777 | // + inet_common.c has additional IPv4-only stuff | 777 | // + inet_common.c has additional IPv4-only stuff |
778 | 778 | ||
779 | 779 | ||
780 | struct tls_aes { | ||
781 | uint32_t key[60]; | ||
782 | unsigned rounds; | ||
783 | }; | ||
780 | #define TLS_MAX_MAC_SIZE 32 | 784 | #define TLS_MAX_MAC_SIZE 32 |
781 | #define TLS_MAX_KEY_SIZE 32 | 785 | #define TLS_MAX_KEY_SIZE 32 |
786 | #define TLS_MAX_IV_SIZE 4 | ||
782 | struct tls_handshake_data; /* opaque */ | 787 | struct tls_handshake_data; /* opaque */ |
783 | typedef struct tls_state { | 788 | typedef struct tls_state { |
789 | unsigned flags; | ||
790 | |||
784 | int ofd; | 791 | int ofd; |
785 | int ifd; | 792 | int ifd; |
786 | 793 | ||
787 | unsigned min_encrypted_len_on_read; | 794 | unsigned min_encrypted_len_on_read; |
788 | uint16_t cipher_id; | 795 | uint16_t cipher_id; |
789 | uint8_t encrypt_on_write; | ||
790 | unsigned MAC_size; | 796 | unsigned MAC_size; |
791 | unsigned key_size; | 797 | unsigned key_size; |
798 | unsigned IV_size; | ||
792 | 799 | ||
793 | uint8_t *outbuf; | 800 | uint8_t *outbuf; |
794 | int outbuf_size; | 801 | int outbuf_size; |
@@ -810,12 +817,21 @@ typedef struct tls_state { | |||
810 | /*uint64_t read_seq64_be;*/ | 817 | /*uint64_t read_seq64_be;*/ |
811 | uint64_t write_seq64_be; | 818 | uint64_t write_seq64_be; |
812 | 819 | ||
820 | /*uint8_t *server_write_MAC_key;*/ | ||
813 | uint8_t *client_write_key; | 821 | uint8_t *client_write_key; |
814 | uint8_t *server_write_key; | 822 | uint8_t *server_write_key; |
823 | uint8_t *client_write_IV; | ||
824 | uint8_t *server_write_IV; | ||
815 | uint8_t client_write_MAC_key[TLS_MAX_MAC_SIZE]; | 825 | uint8_t client_write_MAC_key[TLS_MAX_MAC_SIZE]; |
816 | uint8_t server_write_MAC_k__[TLS_MAX_MAC_SIZE]; | 826 | uint8_t server_write_MAC_k__[TLS_MAX_MAC_SIZE]; |
817 | uint8_t client_write_k__[TLS_MAX_KEY_SIZE]; | 827 | uint8_t client_write_k__[TLS_MAX_KEY_SIZE]; |
818 | uint8_t server_write_k__[TLS_MAX_KEY_SIZE]; | 828 | uint8_t server_write_k__[TLS_MAX_KEY_SIZE]; |
829 | uint8_t client_write_I_[TLS_MAX_IV_SIZE]; | ||
830 | uint8_t server_write_I_[TLS_MAX_IV_SIZE]; | ||
831 | |||
832 | struct tls_aes aes_encrypt; | ||
833 | struct tls_aes aes_decrypt; | ||
834 | uint8_t H[16]; //used by AES_GCM | ||
819 | } tls_state_t; | 835 | } tls_state_t; |
820 | 836 | ||
821 | static inline tls_state_t *new_tls_state(void) | 837 | static inline tls_state_t *new_tls_state(void) |
@@ -1366,9 +1382,22 @@ void bb_logenv_override(void) FAST_FUNC; | |||
1366 | #define MAIN_EXTERNALLY_VISIBLE | 1382 | #define MAIN_EXTERNALLY_VISIBLE |
1367 | #endif | 1383 | #endif |
1368 | 1384 | ||
1385 | /* Embedded script support */ | ||
1386 | char *get_script_content(unsigned n) FAST_FUNC; | ||
1387 | int scripted_main(int argc, char** argv); | ||
1369 | 1388 | ||
1370 | /* Applets which are useful from another applets */ | 1389 | /* Applets which are useful from another applets */ |
1371 | int bb_cat(char** argv) FAST_FUNC; | 1390 | int bb_cat(char** argv) FAST_FUNC; |
1391 | int ash_main(int argc, char** argv) | ||
1392 | #if ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH | ||
1393 | MAIN_EXTERNALLY_VISIBLE | ||
1394 | #endif | ||
1395 | ; | ||
1396 | int hush_main(int argc, char** argv) | ||
1397 | #if ENABLE_HUSH || ENABLE_SH_IS_HUSH || ENABLE_BASH_IS_HUSH | ||
1398 | MAIN_EXTERNALLY_VISIBLE | ||
1399 | #endif | ||
1400 | ; | ||
1372 | /* If shell needs them, they exist even if not enabled as applets */ | 1401 | /* If shell needs them, they exist even if not enabled as applets */ |
1373 | int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE); | 1402 | int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE); |
1374 | int printf_main(int argc, char **argv) IF_PRINTF(MAIN_EXTERNALLY_VISIBLE); | 1403 | int printf_main(int argc, char **argv) IF_PRINTF(MAIN_EXTERNALLY_VISIBLE); |
@@ -2041,7 +2070,7 @@ typedef struct bb_progress_t { | |||
2041 | (p)->curfile = NULL; \ | 2070 | (p)->curfile = NULL; \ |
2042 | } while (0) | 2071 | } while (0) |
2043 | void bb_progress_init(bb_progress_t *p, const char *curfile) FAST_FUNC; | 2072 | void bb_progress_init(bb_progress_t *p, const char *curfile) FAST_FUNC; |
2044 | void bb_progress_update(bb_progress_t *p, | 2073 | int bb_progress_update(bb_progress_t *p, |
2045 | uoff_t beg_range, | 2074 | uoff_t beg_range, |
2046 | uoff_t transferred, | 2075 | uoff_t transferred, |
2047 | uoff_t totalsize) FAST_FUNC; | 2076 | uoff_t totalsize) FAST_FUNC; |
diff --git a/include/platform.h b/include/platform.h index 0d17062da..afd8cf292 100644 --- a/include/platform.h +++ b/include/platform.h | |||
@@ -252,6 +252,7 @@ typedef uint64_t bb__aliased_uint64_t FIX_ALIASING; | |||
252 | # define move_from_unaligned32(v, u32p) ((v) = *(bb__aliased_uint32_t*)(u32p)) | 252 | # define move_from_unaligned32(v, u32p) ((v) = *(bb__aliased_uint32_t*)(u32p)) |
253 | # define move_to_unaligned16(u16p, v) (*(bb__aliased_uint16_t*)(u16p) = (v)) | 253 | # define move_to_unaligned16(u16p, v) (*(bb__aliased_uint16_t*)(u16p) = (v)) |
254 | # define move_to_unaligned32(u32p, v) (*(bb__aliased_uint32_t*)(u32p) = (v)) | 254 | # define move_to_unaligned32(u32p, v) (*(bb__aliased_uint32_t*)(u32p) = (v)) |
255 | # define move_to_unaligned64(u64p, v) (*(bb__aliased_uint64_t*)(u64p) = (v)) | ||
255 | /* #elif ... - add your favorite arch today! */ | 256 | /* #elif ... - add your favorite arch today! */ |
256 | #else | 257 | #else |
257 | # define BB_UNALIGNED_MEMACCESS_OK 0 | 258 | # define BB_UNALIGNED_MEMACCESS_OK 0 |
@@ -268,6 +269,10 @@ typedef uint64_t bb__aliased_uint64_t FIX_ALIASING; | |||
268 | uint32_t __t = (v); \ | 269 | uint32_t __t = (v); \ |
269 | memcpy((u32p), &__t, 4); \ | 270 | memcpy((u32p), &__t, 4); \ |
270 | } while (0) | 271 | } while (0) |
272 | # define move_to_unaligned64(u64p, v) do { \ | ||
273 | uint64_t __t = (v); \ | ||
274 | memcpy((u64p), &__t, 8); \ | ||
275 | } while (0) | ||
271 | #endif | 276 | #endif |
272 | 277 | ||
273 | /* Unaligned, fixed-endian accessors */ | 278 | /* Unaligned, fixed-endian accessors */ |
diff --git a/include/usage.src.h b/include/usage.src.h index 00369dfb3..d22efd3ba 100644 --- a/include/usage.src.h +++ b/include/usage.src.h | |||
@@ -14,6 +14,9 @@ | |||
14 | 14 | ||
15 | #define NOUSAGE_STR "\b" | 15 | #define NOUSAGE_STR "\b" |
16 | 16 | ||
17 | #define scripted_trivial_usage NOUSAGE_STR | ||
18 | #define scripted_full_usage "" | ||
19 | |||
17 | #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA | 20 | #if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA |
18 | # define CRYPT_METHODS_HELP_STR "des,md5,sha256/512" \ | 21 | # define CRYPT_METHODS_HELP_STR "des,md5,sha256/512" \ |
19 | " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" | 22 | " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index add609b78..3cbb5699c 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -59,6 +59,17 @@ | |||
59 | 59 | ||
60 | #include "usage_compressed.h" | 60 | #include "usage_compressed.h" |
61 | 61 | ||
62 | #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS | ||
63 | # define DEFINE_SCRIPT_DATA 1 | ||
64 | # include "embedded_scripts.h" | ||
65 | #else | ||
66 | # define NUM_SCRIPTS 0 | ||
67 | #endif | ||
68 | #if NUM_SCRIPTS > 0 | ||
69 | # define BB_ARCHIVE_PUBLIC | ||
70 | # include "bb_archive.h" | ||
71 | static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS }; | ||
72 | #endif | ||
62 | 73 | ||
63 | /* "Do not compress usage text if uncompressed text is small | 74 | /* "Do not compress usage text if uncompressed text is small |
64 | * and we don't include bunzip2 code for other reasons" | 75 | * and we don't include bunzip2 code for other reasons" |
@@ -105,36 +116,10 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; | |||
105 | #if ENABLE_FEATURE_COMPRESS_USAGE | 116 | #if ENABLE_FEATURE_COMPRESS_USAGE |
106 | 117 | ||
107 | static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; | 118 | static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; |
108 | #define BB_ARCHIVE_PUBLIC | 119 | # define BB_ARCHIVE_PUBLIC |
109 | # include "bb_archive.h" | 120 | # include "bb_archive.h" |
110 | static const char *unpack_usage_messages(void) | 121 | # define unpack_usage_messages() \ |
111 | { | 122 | unpack_bz2_data(packed_usage, sizeof(packed_usage), sizeof(UNPACKED_USAGE)) |
112 | char *outbuf = NULL; | ||
113 | bunzip_data *bd; | ||
114 | int i; | ||
115 | jmp_buf jmpbuf; | ||
116 | |||
117 | /* Setup for I/O error handling via longjmp */ | ||
118 | i = setjmp(jmpbuf); | ||
119 | if (i == 0) { | ||
120 | i = start_bunzip(&jmpbuf, | ||
121 | &bd, | ||
122 | /* src_fd: */ -1, | ||
123 | /* inbuf: */ packed_usage, | ||
124 | /* len: */ sizeof(packed_usage) | ||
125 | ); | ||
126 | } | ||
127 | /* read_bunzip can longjmp and end up here with i != 0 | ||
128 | * on read data errors! Not trivial */ | ||
129 | if (i == 0) { | ||
130 | /* Cannot use xmalloc: will leak bd in NOFORK case! */ | ||
131 | outbuf = malloc_or_warn(sizeof(UNPACKED_USAGE)); | ||
132 | if (outbuf) | ||
133 | read_bunzip(bd, outbuf, sizeof(UNPACKED_USAGE)); | ||
134 | } | ||
135 | dealloc_bunzip(bd); | ||
136 | return outbuf; | ||
137 | } | ||
138 | # define dealloc_usage_messages(s) free(s) | 123 | # define dealloc_usage_messages(s) free(s) |
139 | 124 | ||
140 | #else | 125 | #else |
@@ -152,21 +137,23 @@ void FAST_FUNC bb_show_usage(void) | |||
152 | /* Imagine that this applet is "true". Dont suck in printf! */ | 137 | /* Imagine that this applet is "true". Dont suck in printf! */ |
153 | const char *usage_string = unpack_usage_messages(); | 138 | const char *usage_string = unpack_usage_messages(); |
154 | 139 | ||
155 | if (*usage_string == '\b') { | 140 | if (usage_string) { |
156 | full_write2_str("No help available.\n\n"); | 141 | if (*usage_string == '\b') { |
157 | } else { | 142 | full_write2_str("No help available.\n\n"); |
158 | full_write2_str("Usage: "SINGLE_APPLET_STR" "); | 143 | } else { |
159 | full_write2_str(usage_string); | 144 | full_write2_str("Usage: "SINGLE_APPLET_STR" "); |
160 | full_write2_str("\n\n"); | 145 | full_write2_str(usage_string); |
146 | full_write2_str("\n\n"); | ||
147 | } | ||
148 | if (ENABLE_FEATURE_CLEAN_UP) | ||
149 | dealloc_usage_messages((char*)usage_string); | ||
161 | } | 150 | } |
162 | if (ENABLE_FEATURE_CLEAN_UP) | ||
163 | dealloc_usage_messages((char*)usage_string); | ||
164 | #else | 151 | #else |
165 | const char *p; | 152 | const char *p; |
166 | const char *usage_string = p = unpack_usage_messages(); | 153 | const char *usage_string = p = unpack_usage_messages(); |
167 | int ap = find_applet_by_name(applet_name); | 154 | int ap = find_applet_by_name(applet_name); |
168 | 155 | ||
169 | if (ap < 0) /* never happens, paranoia */ | 156 | if (ap < 0 || usage_string == NULL) |
170 | xfunc_die(); | 157 | xfunc_die(); |
171 | while (ap) { | 158 | while (ap) { |
172 | while (*p++) continue; | 159 | while (*p++) continue; |
@@ -808,6 +795,50 @@ static void install_links(const char *busybox UNUSED_PARAM, | |||
808 | 795 | ||
809 | static void run_applet_and_exit(const char *name, char **argv) NORETURN; | 796 | static void run_applet_and_exit(const char *name, char **argv) NORETURN; |
810 | 797 | ||
798 | # if NUM_SCRIPTS > 0 | ||
799 | static int find_script_by_name(const char *name) | ||
800 | { | ||
801 | int i; | ||
802 | int applet = find_applet_by_name(name); | ||
803 | |||
804 | if (applet >= 0) { | ||
805 | for (i = 0; i < NUM_SCRIPTS; ++i) | ||
806 | if (applet_numbers[i] == applet) | ||
807 | return i; | ||
808 | } | ||
809 | return -1; | ||
810 | } | ||
811 | |||
812 | int scripted_main(int argc UNUSED_PARAM, char **argv) | ||
813 | { | ||
814 | int script = find_script_by_name(applet_name); | ||
815 | if (script >= 0) | ||
816 | #if ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH | ||
817 | exit(ash_main(-script - 1, argv)); | ||
818 | #elif ENABLE_HUSH || ENABLE_SH_IS_HUSH || ENABLE_BASH_IS_HUSH | ||
819 | exit(hush_main(-script - 1, argv)); | ||
820 | #else | ||
821 | return 1; | ||
822 | #endif | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | char* FAST_FUNC | ||
827 | get_script_content(unsigned n) | ||
828 | { | ||
829 | char *t = unpack_bz2_data(packed_scripts, sizeof(packed_scripts), | ||
830 | UNPACKED_SCRIPTS_LENGTH); | ||
831 | if (t) { | ||
832 | while (n != 0) { | ||
833 | while (*t++ != '\0') | ||
834 | continue; | ||
835 | n--; | ||
836 | } | ||
837 | } | ||
838 | return t; | ||
839 | } | ||
840 | # endif /* NUM_SCRIPTS > 0 */ | ||
841 | |||
811 | # if ENABLE_BUSYBOX | 842 | # if ENABLE_BUSYBOX |
812 | # if ENABLE_FEATURE_SH_STANDALONE && ENABLE_FEATURE_TAB_COMPLETION | 843 | # if ENABLE_FEATURE_SH_STANDALONE && ENABLE_FEATURE_TAB_COMPLETION |
813 | /* | 844 | /* |
@@ -850,6 +881,9 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) | |||
850 | "\n" | 881 | "\n" |
851 | "Usage: busybox [function [arguments]...]\n" | 882 | "Usage: busybox [function [arguments]...]\n" |
852 | " or: busybox --list"IF_FULL_LIST_OPTION("[-full]")"\n" | 883 | " or: busybox --list"IF_FULL_LIST_OPTION("[-full]")"\n" |
884 | # if ENABLE_FEATURE_SHOW_SCRIPT && NUM_SCRIPTS > 0 | ||
885 | " or: busybox --show SCRIPT\n" | ||
886 | # endif | ||
853 | IF_FEATURE_INSTALLER( | 887 | IF_FEATURE_INSTALLER( |
854 | " or: busybox --install "IF_NOT_PLATFORM_MINGW32("[-s] ")"[DIR]\n" | 888 | " or: busybox --install "IF_NOT_PLATFORM_MINGW32("[-s] ")"[DIR]\n" |
855 | ) | 889 | ) |
@@ -877,9 +911,9 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) | |||
877 | "Currently defined functions:\n" | 911 | "Currently defined functions:\n" |
878 | ); | 912 | ); |
879 | col = 0; | 913 | col = 0; |
880 | a = applet_names; | ||
881 | /* prevent last comma to be in the very last pos */ | 914 | /* prevent last comma to be in the very last pos */ |
882 | output_width--; | 915 | output_width--; |
916 | a = applet_names; | ||
883 | while (*a) { | 917 | while (*a) { |
884 | int len2 = strlen(a) + 2; | 918 | int len2 = strlen(a) + 2; |
885 | if (col >= (int)output_width - len2) { | 919 | if (col >= (int)output_width - len2) { |
@@ -900,6 +934,19 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) | |||
900 | return 0; | 934 | return 0; |
901 | } | 935 | } |
902 | 936 | ||
937 | # if ENABLE_FEATURE_SHOW_SCRIPT && NUM_SCRIPTS > 0 | ||
938 | if (strcmp(argv[1], "--show") == 0) { | ||
939 | int n; | ||
940 | if (!argv[2]) | ||
941 | bb_error_msg_and_die(bb_msg_requires_arg, "--show"); | ||
942 | n = find_script_by_name(argv[2]); | ||
943 | if (n < 0) | ||
944 | bb_error_msg_and_die("script '%s' not found", argv[2]); | ||
945 | full_write1_str(get_script_content(n)); | ||
946 | return 0; | ||
947 | } | ||
948 | # endif | ||
949 | |||
903 | if (is_prefixed_with(argv[1], "--list")) { | 950 | if (is_prefixed_with(argv[1], "--list")) { |
904 | unsigned i = 0; | 951 | unsigned i = 0; |
905 | const char *a = applet_names; | 952 | const char *a = applet_names; |
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index a53a382ce..9db79ea8b 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
@@ -794,6 +794,11 @@ static const uint32_t init512_lo[] = { | |||
794 | }; | 794 | }; |
795 | #endif /* NEED_SHA512 */ | 795 | #endif /* NEED_SHA512 */ |
796 | 796 | ||
797 | // Note: SHA-384 is identical to SHA-512, except that initial hash values are | ||
798 | // 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, | ||
799 | // 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, | ||
800 | // and the output is constructed by omitting last two 64-bit words of it. | ||
801 | |||
797 | /* Initialize structure containing state of computation. | 802 | /* Initialize structure containing state of computation. |
798 | (FIPS 180-2:5.3.2) */ | 803 | (FIPS 180-2:5.3.2) */ |
799 | void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | 804 | void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) |
diff --git a/libbb/progress.c b/libbb/progress.c index 23e974ce7..d071ce705 100644 --- a/libbb/progress.c +++ b/libbb/progress.c | |||
@@ -69,7 +69,7 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile) | |||
69 | * will be "totalsize" bytes. | 69 | * will be "totalsize" bytes. |
70 | * If totalsize == 0, then it is unknown. | 70 | * If totalsize == 0, then it is unknown. |
71 | */ | 71 | */ |
72 | void FAST_FUNC bb_progress_update(bb_progress_t *p, | 72 | int FAST_FUNC bb_progress_update(bb_progress_t *p, |
73 | uoff_t beg_size, | 73 | uoff_t beg_size, |
74 | uoff_t transferred, | 74 | uoff_t transferred, |
75 | uoff_t totalsize) | 75 | uoff_t totalsize) |
@@ -94,7 +94,7 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, | |||
94 | * Do not update on every call | 94 | * Do not update on every call |
95 | * (we can be called on every network read!) | 95 | * (we can be called on every network read!) |
96 | */ | 96 | */ |
97 | return; | 97 | return -1; |
98 | } | 98 | } |
99 | 99 | ||
100 | /* Before we lose real, unscaled sizes, produce human-readable size string */ | 100 | /* Before we lose real, unscaled sizes, produce human-readable size string */ |
@@ -211,4 +211,5 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, | |||
211 | } | 211 | } |
212 | if (notty) | 212 | if (notty) |
213 | fputc('\n', stderr); | 213 | fputc('\n', stderr); |
214 | return notty; | ||
214 | } | 215 | } |
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c index b3038e32d..f7d598c7a 100644 --- a/libbb/u_signal_names.c +++ b/libbb/u_signal_names.c | |||
@@ -12,6 +12,18 @@ | |||
12 | //config: help | 12 | //config: help |
13 | //config: Support RTMIN[+n] and RTMAX[-n] signal names | 13 | //config: Support RTMIN[+n] and RTMAX[-n] signal names |
14 | //config: in kill, killall etc. This costs ~250 bytes. | 14 | //config: in kill, killall etc. This costs ~250 bytes. |
15 | //config: | ||
16 | //config:config FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS | ||
17 | //config: bool "Use the definitions of SIGRTMIN/SIGRTMAX provided by libc" | ||
18 | //config: default y | ||
19 | //config: depends on FEATURE_RTMINMAX | ||
20 | //config: help | ||
21 | //config: Some C libraries reserve a few real-time signals for internal | ||
22 | //config: use, and adjust the values of SIGRTMIN/SIGRTMAX seen by | ||
23 | //config: applications accordingly. Saying yes here means that a signal | ||
24 | //config: name RTMIN+n will be interpreted according to the libc definition | ||
25 | //config: of SIGRTMIN, and not the raw definition provided by the kernel. | ||
26 | //config: This behavior matches "kill -l RTMIN+n" from bash. | ||
15 | 27 | ||
16 | #include "libbb.h" | 28 | #include "libbb.h" |
17 | 29 | ||
@@ -123,7 +135,7 @@ static const char signals[][7] ALIGN1 = { | |||
123 | #ifdef SIGSYS | 135 | #ifdef SIGSYS |
124 | [SIGSYS ] = "SYS", | 136 | [SIGSYS ] = "SYS", |
125 | #endif | 137 | #endif |
126 | #if ENABLE_FEATURE_RTMINMAX | 138 | #if ENABLE_FEATURE_RTMINMAX && !ENABLE_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS |
127 | # ifdef __SIGRTMIN | 139 | # ifdef __SIGRTMIN |
128 | [__SIGRTMIN] = "RTMIN", | 140 | [__SIGRTMIN] = "RTMIN", |
129 | # endif | 141 | # endif |
@@ -141,8 +153,12 @@ int FAST_FUNC get_signum(const char *name) | |||
141 | { | 153 | { |
142 | unsigned i; | 154 | unsigned i; |
143 | 155 | ||
156 | /* bb_strtou returns UINT_MAX on error. NSIG is smaller | ||
157 | * than UINT_MAX on any sane Unix. Hence no need | ||
158 | * to check errno after bb_strtou(). | ||
159 | */ | ||
144 | i = bb_strtou(name, NULL, 10); | 160 | i = bb_strtou(name, NULL, 10); |
145 | if (!errno && i < NSIG) /* for shells, we allow 0 too */ | 161 | if (i < NSIG) /* for shells, we allow 0 too */ |
146 | return i; | 162 | return i; |
147 | if (strncasecmp(name, "SIG", 3) == 0) | 163 | if (strncasecmp(name, "SIG", 3) == 0) |
148 | name += 3; | 164 | name += 3; |
@@ -168,36 +184,46 @@ int FAST_FUNC get_signum(const char *name) | |||
168 | # endif | 184 | # endif |
169 | #endif | 185 | #endif |
170 | 186 | ||
171 | #if ENABLE_FEATURE_RTMINMAX | 187 | #if ENABLE_FEATURE_RTMINMAX && defined(SIGRTMIN) && defined(SIGRTMAX) |
172 | # if defined(SIGRTMIN) && defined(SIGRTMAX) | 188 | { |
173 | /* libc may use some rt sigs for pthreads and therefore "remap" SIGRTMIN/MAX, | 189 | # if ENABLE_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS |
174 | * but we want to use "raw" SIGRTMIN/MAX. Underscored names, if exist, provide | 190 | /* Use the libc provided values. */ |
175 | * them. If they don't exist, fall back to non-underscored ones: */ | 191 | unsigned sigrtmin = SIGRTMIN; |
192 | unsigned sigrtmax = SIGRTMAX; | ||
193 | # else | ||
194 | /* Use the "raw" SIGRTMIN/MAX. Underscored names, if exist, provide | ||
195 | * them. If they don't exist, fall back to non-underscored ones: */ | ||
176 | # if !defined(__SIGRTMIN) | 196 | # if !defined(__SIGRTMIN) |
177 | # define __SIGRTMIN SIGRTMIN | 197 | # define __SIGRTMIN SIGRTMIN |
178 | # endif | 198 | # endif |
179 | # if !defined(__SIGRTMAX) | 199 | # if !defined(__SIGRTMAX) |
180 | # define __SIGRTMAX SIGRTMAX | 200 | # define __SIGRTMAX SIGRTMAX |
181 | # endif | 201 | # endif |
182 | if (strncasecmp(name, "RTMIN", 5) == 0) { | 202 | |
183 | if (!name[5]) | 203 | # define sigrtmin __SIGRTMIN |
184 | return __SIGRTMIN; | 204 | # define sigrtmax __SIGRTMAX |
185 | if (name[5] == '+') { | 205 | # endif |
186 | i = bb_strtou(name + 6, NULL, 10); | 206 | if (strncasecmp(name, "RTMIN", 5) == 0) { |
187 | if (!errno && i <= __SIGRTMAX - __SIGRTMIN) | 207 | if (!name[5]) |
188 | return __SIGRTMIN + i; | 208 | return sigrtmin; |
209 | if (name[5] == '+') { | ||
210 | i = bb_strtou(name + 6, NULL, 10); | ||
211 | if (i <= sigrtmax - sigrtmin) | ||
212 | return sigrtmin + i; | ||
213 | } | ||
189 | } | 214 | } |
190 | } | 215 | else if (strncasecmp(name, "RTMAX", 5) == 0) { |
191 | else if (strncasecmp(name, "RTMAX", 5) == 0) { | 216 | if (!name[5]) |
192 | if (!name[5]) | 217 | return sigrtmax; |
193 | return __SIGRTMAX; | 218 | if (name[5] == '-') { |
194 | if (name[5] == '-') { | 219 | i = bb_strtou(name + 6, NULL, 10); |
195 | i = bb_strtou(name + 6, NULL, 10); | 220 | if (i <= sigrtmax - sigrtmin) |
196 | if (!errno && i <= __SIGRTMAX - __SIGRTMIN) | 221 | return sigrtmax - i; |
197 | return __SIGRTMAX - i; | 222 | } |
198 | } | 223 | } |
224 | # undef sigrtmin | ||
225 | # undef sigrtmax | ||
199 | } | 226 | } |
200 | # endif | ||
201 | #endif | 227 | #endif |
202 | 228 | ||
203 | return -1; | 229 | return -1; |
@@ -228,8 +254,16 @@ void FAST_FUNC print_signames(void) | |||
228 | printf("%2u) %s\n", signo, name); | 254 | printf("%2u) %s\n", signo, name); |
229 | } | 255 | } |
230 | #if ENABLE_FEATURE_RTMINMAX | 256 | #if ENABLE_FEATURE_RTMINMAX |
231 | # ifdef __SIGRTMAX | 257 | # if ENABLE_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS |
258 | # if defined(SIGRTMIN) && defined(SIGRTMAX) | ||
259 | printf("%2u) %s\n", SIGRTMIN, "RTMIN"); | ||
260 | printf("%2u) %s\n", SIGRTMAX, "RTMAX"); | ||
261 | # endif | ||
262 | # else | ||
263 | // __SIGRTMIN is included in signals[] array. | ||
264 | # ifdef __SIGRTMAX | ||
232 | printf("%2u) %s\n", __SIGRTMAX, "RTMAX"); | 265 | printf("%2u) %s\n", __SIGRTMAX, "RTMAX"); |
266 | # endif | ||
233 | # endif | 267 | # endif |
234 | #endif | 268 | #endif |
235 | } | 269 | } |
diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c index aa42de648..077e03c5d 100644 --- a/miscutils/bbconfig.c +++ b/miscutils/bbconfig.c | |||
@@ -44,29 +44,10 @@ int bbconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
44 | int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 44 | int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
45 | { | 45 | { |
46 | #if ENABLE_FEATURE_COMPRESS_BBCONFIG | 46 | #if ENABLE_FEATURE_COMPRESS_BBCONFIG |
47 | bunzip_data *bd; | 47 | const char *outbuf = unpack_bz2_data(bbconfig_config_bz2, |
48 | int i; | 48 | sizeof(bbconfig_config_bz2), sizeof(bbconfig_config)); |
49 | jmp_buf jmpbuf; | 49 | if (outbuf) { |
50 | 50 | full_write1_str(outbuf); | |
51 | /* Setup for I/O error handling via longjmp */ | ||
52 | i = setjmp(jmpbuf); | ||
53 | if (i == 0) { | ||
54 | i = start_bunzip(&jmpbuf, | ||
55 | &bd, | ||
56 | /* src_fd: */ -1, | ||
57 | /* inbuf: */ bbconfig_config_bz2, | ||
58 | /* len: */ sizeof(bbconfig_config_bz2) | ||
59 | ); | ||
60 | } | ||
61 | /* read_bunzip can longjmp and end up here with i != 0 | ||
62 | * on read data errors! Not trivial */ | ||
63 | if (i == 0) { | ||
64 | /* Cannot use xmalloc: will leak bd in NOFORK case! */ | ||
65 | char *outbuf = malloc_or_warn(sizeof(bbconfig_config)); | ||
66 | if (outbuf) { | ||
67 | read_bunzip(bd, outbuf, sizeof(bbconfig_config)); | ||
68 | full_write1_str(outbuf); | ||
69 | } | ||
70 | } | 51 | } |
71 | #else | 52 | #else |
72 | full_write1_str(bbconfig_config); | 53 | full_write1_str(bbconfig_config); |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 59f6d54f3..291e4cb90 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -245,7 +245,7 @@ static int FAST_FUNC config_file_action(const char *filename, | |||
245 | parser_t *p; | 245 | parser_t *p; |
246 | struct module_entry *m; | 246 | struct module_entry *m; |
247 | int rc = TRUE; | 247 | int rc = TRUE; |
248 | const char *base, *ext; | 248 | const char *base; |
249 | 249 | ||
250 | /* Skip files that begin with a "." */ | 250 | /* Skip files that begin with a "." */ |
251 | base = bb_basename(filename); | 251 | base = bb_basename(filename); |
@@ -266,8 +266,7 @@ static int FAST_FUNC config_file_action(const char *filename, | |||
266 | * "include FILE_NOT_ENDING_IN_CONF" must work too. | 266 | * "include FILE_NOT_ENDING_IN_CONF" must work too. |
267 | */ | 267 | */ |
268 | if (depth != 0) { | 268 | if (depth != 0) { |
269 | ext = strrchr(base, '.'); | 269 | if (!is_suffixed_with(base, ".conf")) |
270 | if (ext == NULL || strcmp(ext + 1, "conf")) | ||
271 | goto error; | 270 | goto error; |
272 | } | 271 | } |
273 | 272 | ||
diff --git a/networking/brctl.c b/networking/brctl.c index 5d5f0af30..ba4a714f8 100644 --- a/networking/brctl.c +++ b/networking/brctl.c | |||
@@ -241,7 +241,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
241 | 241 | ||
242 | #if ENABLE_FEATURE_BRCTL_SHOW | 242 | #if ENABLE_FEATURE_BRCTL_SHOW |
243 | if (key == ARG_show) { /* show */ | 243 | if (key == ARG_show) { /* show */ |
244 | char brname[IFNAMSIZ]; | 244 | char buf[IFNAMSIZ]; |
245 | int bridx[MAX_PORTS]; | 245 | int bridx[MAX_PORTS]; |
246 | int i, num; | 246 | int i, num; |
247 | arm_ioctl(args, BRCTL_GET_BRIDGES, | 247 | arm_ioctl(args, BRCTL_GET_BRIDGES, |
@@ -249,19 +249,18 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
249 | num = xioctl(fd, SIOCGIFBR, args); | 249 | num = xioctl(fd, SIOCGIFBR, args); |
250 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); | 250 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); |
251 | for (i = 0; i < num; i++) { | 251 | for (i = 0; i < num; i++) { |
252 | char ifname[IFNAMSIZ]; | ||
253 | int j, tabs; | 252 | int j, tabs; |
254 | struct __bridge_info bi; | 253 | struct __bridge_info bi; |
255 | unsigned char *x; | 254 | unsigned char *x; |
256 | 255 | ||
257 | if (!if_indextoname(bridx[i], brname)) | 256 | if (!if_indextoname(bridx[i], buf)) |
258 | bb_perror_msg_and_die("can't get bridge name for index %d", i); | 257 | bb_perror_msg_and_die("can't get bridge name for index %d", i); |
259 | strncpy_IFNAMSIZ(ifr.ifr_name, brname); | 258 | strncpy_IFNAMSIZ(ifr.ifr_name, buf); |
260 | 259 | ||
261 | arm_ioctl(args, BRCTL_GET_BRIDGE_INFO, | 260 | arm_ioctl(args, BRCTL_GET_BRIDGE_INFO, |
262 | (unsigned long) &bi, 0); | 261 | (unsigned long) &bi, 0); |
263 | xioctl(fd, SIOCDEVPRIVATE, &ifr); | 262 | xioctl(fd, SIOCDEVPRIVATE, &ifr); |
264 | printf("%s\t\t", brname); | 263 | printf("%s\t\t", buf); |
265 | 264 | ||
266 | /* print bridge id */ | 265 | /* print bridge id */ |
267 | x = (unsigned char *) &bi.bridge_id; | 266 | x = (unsigned char *) &bi.bridge_id; |
@@ -280,13 +279,13 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
280 | for (j = 0; j < MAX_PORTS; j++) { | 279 | for (j = 0; j < MAX_PORTS; j++) { |
281 | if (!ifidx[j]) | 280 | if (!ifidx[j]) |
282 | continue; | 281 | continue; |
283 | if (!if_indextoname(ifidx[j], ifname)) | 282 | if (!if_indextoname(ifidx[j], buf)) |
284 | bb_perror_msg_and_die("can't get interface name for index %d", j); | 283 | bb_perror_msg_and_die("can't get interface name for index %d", j); |
285 | if (tabs) | 284 | if (tabs) |
286 | printf("\t\t\t\t\t"); | 285 | printf("\t\t\t\t\t"); |
287 | else | 286 | else |
288 | tabs = 1; | 287 | tabs = 1; |
289 | printf("\t\t%s\n", ifname); | 288 | printf("\t\t%s\n", buf); |
290 | } | 289 | } |
291 | if (!tabs) /* bridge has no interfaces */ | 290 | if (!tabs) /* bridge has no interfaces */ |
292 | bb_putchar('\n'); | 291 | bb_putchar('\n'); |
diff --git a/networking/nbd-client.c b/networking/nbd-client.c index bedb01a1c..103756b59 100644 --- a/networking/nbd-client.c +++ b/networking/nbd-client.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "libbb.h" | 16 | #include "libbb.h" |
17 | #include <netinet/tcp.h> | 17 | #include <netinet/tcp.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <getopt.h> | ||
19 | 20 | ||
20 | #define NBD_SET_SOCK _IO(0xab, 0) | 21 | #define NBD_SET_SOCK _IO(0xab, 0) |
21 | #define NBD_SET_BLKSIZE _IO(0xab, 1) | 22 | #define NBD_SET_BLKSIZE _IO(0xab, 1) |
@@ -27,57 +28,144 @@ | |||
27 | #define NBD_SET_SIZE_BLOCKS _IO(0xab, 7) | 28 | #define NBD_SET_SIZE_BLOCKS _IO(0xab, 7) |
28 | #define NBD_DISCONNECT _IO(0xab, 8) | 29 | #define NBD_DISCONNECT _IO(0xab, 8) |
29 | #define NBD_SET_TIMEOUT _IO(0xab, 9) | 30 | #define NBD_SET_TIMEOUT _IO(0xab, 9) |
31 | #define NBD_SET_FLAGS _IO(0xab, 10) | ||
30 | 32 | ||
31 | //usage:#define nbdclient_trivial_usage | 33 | //usage:#define nbdclient_trivial_usage |
32 | //usage: "HOST PORT BLOCKDEV" | 34 | //usage: "{ [-b BLKSIZE] [-N NAME] [-t SEC] [-p] HOST [PORT] | -d } BLOCKDEV" |
33 | //usage:#define nbdclient_full_usage "\n\n" | 35 | //usage:#define nbdclient_full_usage "\n\n" |
34 | //usage: "Connect to HOST and provide a network block device on BLOCKDEV" | 36 | //usage: "Connect to HOST and provide network block device on BLOCKDEV" |
35 | 37 | ||
36 | //TODO: more compat with nbd-client version 2.9.13 - | 38 | //TODO: more compat with nbd-client version 3.17 - |
37 | //Usage: nbd-client [bs=blocksize] [timeout=sec] host port nbd_device [-swap] [-persist] [-nofork] | 39 | //nbd-client host [ port ] nbd-device [ -connections num ] [ -sdp ] [ -swap ] |
38 | //Or : nbd-client -d nbd_device | 40 | // [ -persist ] [ -nofork ] [ -nonetlink ] [ -systemd-mark ] |
39 | //Or : nbd-client -c nbd_device | 41 | // [ -block-size block size ] [ -timeout seconds ] [ -name name ] |
40 | //Default value for blocksize is 1024 (recommended for ethernet) | 42 | // [ -certfile certfile ] [ -keyfile keyfile ] [ -cacertfile cacertfile ] |
43 | // [ -tlshostname hostname ] | ||
44 | //nbd-client -unix path nbd-device [ -connections num ] [ -sdp ] [ -swap ] | ||
45 | // [ -persist ] [ -nofork ] [ -nonetlink ] [ -systemd-mark ] | ||
46 | // [ -block-size block size ] [ -timeout seconds ] [ -name name ] | ||
47 | //nbd-client nbd-device | ||
48 | //nbd-client -d nbd-device | ||
49 | //nbd-client -c nbd-device | ||
50 | //nbd-client -l host [ port ] | ||
51 | //nbd-client [ -netlink ] -l host | ||
52 | // | ||
53 | //Default value for blocksize is 4096 | ||
41 | //Allowed values for blocksize are 512,1024,2048,4096 | 54 | //Allowed values for blocksize are 512,1024,2048,4096 |
42 | //Note, that kernel 2.4.2 and older ones do not work correctly with | ||
43 | //blocksizes other than 1024 without patches | ||
44 | 55 | ||
45 | int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 56 | int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
46 | int nbdclient_main(int argc UNUSED_PARAM, char **argv) | 57 | int nbdclient_main(int argc, char **argv) |
47 | { | 58 | { |
48 | unsigned long timeout = 0; | ||
49 | #if BB_MMU | 59 | #if BB_MMU |
50 | int nofork = 0; | 60 | bool nofork; |
51 | #endif | 61 | #endif |
52 | char *host, *port, *device; | 62 | bool opt_d; |
63 | bool opt_p; | ||
64 | const char *host, *port, *device; | ||
65 | const char *name; | ||
66 | unsigned blksize, size_blocks; | ||
67 | unsigned timeout; | ||
68 | int ch; | ||
53 | struct nbd_header_t { | 69 | struct nbd_header_t { |
54 | uint64_t magic1; // "NBDMAGIC" | 70 | uint64_t magic1; // "NBDMAGIC" |
55 | uint64_t magic2; // 0x420281861253 big endian | 71 | uint64_t magic2; // old style: 0x420281861253 big endian |
72 | // // new style: 0x49484156454F5054 (IHAVEOPT) | ||
73 | } nbd_header; | ||
74 | struct old_nbd_header_t { | ||
56 | uint64_t devsize; | 75 | uint64_t devsize; |
57 | uint32_t flags; | 76 | uint32_t flags; |
58 | char data[124]; | 77 | char data[124]; |
59 | } nbd_header; | 78 | } old_nbd_header; |
79 | struct new_nbd_header_t { | ||
80 | uint64_t devsize; | ||
81 | uint16_t transmission_flags; | ||
82 | char data[124]; | ||
83 | } new_nbd_header; | ||
84 | struct nbd_opt_t { | ||
85 | uint64_t magic; | ||
86 | uint32_t opt; | ||
87 | uint32_t len; | ||
88 | } nbd_opts; | ||
60 | 89 | ||
61 | BUILD_BUG_ON(offsetof(struct nbd_header_t, data) != 8+8+8+4); | 90 | static const struct option long_options[] = { |
91 | { "block-size", required_argument, NULL, 'b' }, | ||
92 | { "timeout" , required_argument, NULL, 't' }, | ||
93 | { "name" , required_argument, NULL, 'n' }, | ||
94 | { "persist" , no_argument , NULL, 'p' }, | ||
95 | { NULL } | ||
96 | }; | ||
62 | 97 | ||
63 | // Parse command line stuff (just a stub now) | 98 | BUILD_BUG_ON(offsetof(struct old_nbd_header_t, data) != 8 + 4); |
64 | if (!argv[1] || !argv[2] || !argv[3] || argv[4]) | 99 | BUILD_BUG_ON(offsetof(struct new_nbd_header_t, data) != 8 + 2); |
65 | bb_show_usage(); | ||
66 | 100 | ||
67 | #if !BB_MMU | 101 | #if !BB_MMU |
68 | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); | 102 | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); |
69 | #endif | 103 | #endif |
70 | 104 | ||
71 | host = argv[1]; | 105 | // Parse args. nbd-client uses stupid "one-dash long options" style :( |
72 | port = argv[2]; | 106 | // Even though short forms (-b,-t,-N,-p) exist for all long opts, |
73 | device = argv[3]; | 107 | // older manpages only contained long forms, which probably resulted |
108 | // in many scripts using them. | ||
109 | blksize = 4096; | ||
110 | timeout = 0; | ||
111 | name = ""; // use of "" instead of NULL simplifies strlen() later | ||
112 | opt_d = opt_p = 0; | ||
113 | while ((ch = getopt_long_only(argc, argv, "dN:", long_options, NULL)) != -1) { | ||
114 | switch (ch) { | ||
115 | case 'p': // -persist | ||
116 | opt_p = 1; | ||
117 | break; | ||
118 | case 'd': // -d | ||
119 | opt_d = 1; | ||
120 | break; | ||
121 | case 'b': // -block-size | ||
122 | blksize = xatou(optarg); | ||
123 | break; | ||
124 | case 't': // -timeout | ||
125 | timeout = xatou(optarg); | ||
126 | break; | ||
127 | case 'N': // -N | ||
128 | case 'n': // -name | ||
129 | name = optarg; | ||
130 | break; | ||
131 | default: | ||
132 | bb_show_usage(); | ||
133 | } | ||
134 | } | ||
135 | argv += optind; | ||
136 | |||
137 | if (opt_d) { // -d | ||
138 | if (argv[0] && !argv[1]) { | ||
139 | int nbd = xopen(argv[0], O_RDWR); | ||
140 | ioctl(nbd, NBD_DISCONNECT); | ||
141 | ioctl(nbd, NBD_CLEAR_SOCK); | ||
142 | if (ENABLE_FEATURE_CLEAN_UP) | ||
143 | close(nbd); | ||
144 | return 0; | ||
145 | } | ||
146 | bb_show_usage(); | ||
147 | } | ||
148 | |||
149 | // Allow only argv[] of: HOST [PORT] BLOCKDEV | ||
150 | if (!argv[0] || !argv[1] || (argv[2] && argv[3])) { | ||
151 | bb_show_usage(); | ||
152 | } | ||
74 | 153 | ||
75 | // Repeat until spanked (-persist behavior) | 154 | host = argv[0]; |
76 | for (;;) { | 155 | port = argv[2] ? argv[1] : "10809"; |
156 | device = argv[2] ? argv[2] : argv[1]; | ||
157 | |||
158 | // Repeat until spanked if -persist | ||
159 | #if BB_MMU | ||
160 | nofork = 0; | ||
161 | #endif | ||
162 | do { | ||
77 | int sock, nbd; | 163 | int sock, nbd; |
78 | int ro; | 164 | int ro; |
165 | int proto_new; // 0 for old, 1 for new | ||
166 | char *data; | ||
79 | 167 | ||
80 | // Make sure the /dev/nbd exists | 168 | // Make sure BLOCKDEV exists |
81 | nbd = xopen(device, O_RDWR); | 169 | nbd = xopen(device, O_RDWR); |
82 | 170 | ||
83 | // Find and connect to server | 171 | // Find and connect to server |
@@ -85,40 +173,95 @@ int nbdclient_main(int argc UNUSED_PARAM, char **argv) | |||
85 | setsockopt_1(sock, IPPROTO_TCP, TCP_NODELAY); | 173 | setsockopt_1(sock, IPPROTO_TCP, TCP_NODELAY); |
86 | 174 | ||
87 | // Log on to the server | 175 | // Log on to the server |
88 | xread(sock, &nbd_header, 8+8+8+4 + 124); | 176 | xread(sock, &nbd_header, 8 + 8); |
89 | if (memcmp(&nbd_header.magic1, "NBDMAGIC""\x00\x00\x42\x02\x81\x86\x12\x53", 16) != 0) | 177 | if (memcmp(&nbd_header.magic1, "NBDMAGIC", |
178 | sizeof(nbd_header.magic1)) != 0 | ||
179 | ) { | ||
180 | bb_error_msg_and_die("login failed"); | ||
181 | } | ||
182 | if (memcmp(&nbd_header.magic2, | ||
183 | "\x00\x00\x42\x02\x81\x86\x12\x53", | ||
184 | sizeof(nbd_header.magic2)) == 0 | ||
185 | ) { | ||
186 | proto_new = 0; | ||
187 | } else if (memcmp(&nbd_header.magic2, "IHAVEOPT", 8) == 0) { | ||
188 | proto_new = 1; | ||
189 | } else { | ||
90 | bb_error_msg_and_die("login failed"); | 190 | bb_error_msg_and_die("login failed"); |
191 | } | ||
192 | |||
193 | if (!proto_new) { | ||
194 | xread(sock, &old_nbd_header, | ||
195 | sizeof(old_nbd_header.devsize) + | ||
196 | sizeof(old_nbd_header.flags) + | ||
197 | sizeof(old_nbd_header.data)); | ||
198 | size_blocks = SWAP_BE64(old_nbd_header.devsize) / blksize; | ||
199 | ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long) blksize); | ||
200 | ioctl(nbd, NBD_SET_SIZE_BLOCKS, size_blocks); | ||
201 | ioctl(nbd, NBD_CLEAR_SOCK); | ||
202 | ro = !!(old_nbd_header.flags & htons(2)); | ||
203 | data = old_nbd_header.data; | ||
204 | } else { | ||
205 | unsigned namelen; | ||
206 | uint16_t handshake_flags; | ||
207 | |||
208 | xread(sock, &handshake_flags, sizeof(handshake_flags)); | ||
209 | xwrite(sock, &const_int_0, sizeof(const_int_0)); // client_flags | ||
210 | |||
211 | memcpy(&nbd_opts.magic, "IHAVEOPT", | ||
212 | sizeof(nbd_opts.magic)); | ||
213 | nbd_opts.opt = htonl(1); // NBD_OPT_EXPORT_NAME | ||
214 | namelen = strlen(name); | ||
215 | nbd_opts.len = htonl(namelen); | ||
216 | xwrite(sock, &nbd_opts, | ||
217 | sizeof(nbd_opts.magic) + | ||
218 | sizeof(nbd_opts.opt) + | ||
219 | sizeof(nbd_opts.len)); | ||
220 | xwrite(sock, name, namelen); | ||
91 | 221 | ||
92 | // Set 4k block size. Everything uses that these days | 222 | xread(sock, &new_nbd_header, |
93 | ioctl(nbd, NBD_SET_BLKSIZE, 4096); | 223 | sizeof(new_nbd_header.devsize) + |
94 | ioctl(nbd, NBD_SET_SIZE_BLOCKS, SWAP_BE64(nbd_header.devsize) / 4096); | 224 | sizeof(new_nbd_header.transmission_flags) + |
95 | ioctl(nbd, NBD_CLEAR_SOCK); | 225 | sizeof(new_nbd_header.data)); |
226 | size_blocks = SWAP_BE64(new_nbd_header.devsize) / blksize; | ||
227 | ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long) blksize); | ||
228 | ioctl(nbd, NBD_SET_SIZE_BLOCKS, size_blocks); | ||
229 | ioctl(nbd, NBD_CLEAR_SOCK); | ||
230 | ioctl(nbd, NBD_SET_FLAGS, | ||
231 | ntohs(new_nbd_header.transmission_flags)); | ||
232 | ro = !!(new_nbd_header.transmission_flags & htons(2)); | ||
233 | data = new_nbd_header.data; | ||
234 | } | ||
96 | 235 | ||
97 | // If the sucker was exported read only, respect that locally | 236 | if (ioctl(nbd, BLKROSET, &ro) < 0) { |
98 | ro = (nbd_header.flags & SWAP_BE32(2)) / SWAP_BE32(2); | ||
99 | if (ioctl(nbd, BLKROSET, &ro) < 0) | ||
100 | bb_perror_msg_and_die("BLKROSET"); | 237 | bb_perror_msg_and_die("BLKROSET"); |
238 | } | ||
101 | 239 | ||
102 | if (timeout) | 240 | if (timeout) { |
103 | if (ioctl(nbd, NBD_SET_TIMEOUT, timeout)) | 241 | if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long) timeout)) { |
104 | bb_perror_msg_and_die("NBD_SET_TIMEOUT"); | 242 | bb_perror_msg_and_die("NBD_SET_TIMEOUT"); |
105 | if (ioctl(nbd, NBD_SET_SOCK, sock)) | 243 | } |
106 | bb_perror_msg_and_die("NBD_SET_SOCK"); | 244 | } |
107 | 245 | ||
108 | // if (swap) mlockall(MCL_CURRENT|MCL_FUTURE); | 246 | if (ioctl(nbd, NBD_SET_SOCK, sock)) { |
247 | bb_perror_msg_and_die("NBD_SET_SOCK"); | ||
248 | } | ||
109 | 249 | ||
250 | //if (swap) mlockall(MCL_CURRENT|MCL_FUTURE); | ||
110 | #if BB_MMU | 251 | #if BB_MMU |
111 | // Open the device to force reread of the partition table. | 252 | // Open the device to force reread of the partition table. |
112 | // Need to do it in a separate process, since open(device) | 253 | // Need to do it in a separate process, since open(device) |
113 | // needs some other process to sit in ioctl(nbd, NBD_DO_IT). | 254 | // needs some other process to sit in ioctl(nbd, NBD_DO_IT). |
114 | if (fork() == 0) { | 255 | if (fork() == 0) { |
256 | /* child */ | ||
115 | char *s = strrchr(device, '/'); | 257 | char *s = strrchr(device, '/'); |
116 | sprintf(nbd_header.data, "/sys/block/%.32s/pid", s ? s + 1 : device); | 258 | sprintf(data, "/sys/block/%.32s/pid", s ? s + 1 : device); |
117 | // Is it up yet? | 259 | // Is it up yet? |
118 | for (;;) { | 260 | for (;;) { |
119 | int fd = open(nbd_header.data, O_RDONLY); | 261 | int fd = open(data, O_RDONLY); |
120 | if (fd >= 0) { | 262 | if (fd >= 0) { |
121 | //close(fd); | 263 | if (ENABLE_FEATURE_CLEAN_UP) |
264 | close(fd); | ||
122 | break; | 265 | break; |
123 | } | 266 | } |
124 | sleep(1); | 267 | sleep(1); |
@@ -133,7 +276,6 @@ int nbdclient_main(int argc UNUSED_PARAM, char **argv) | |||
133 | nofork = 1; | 276 | nofork = 1; |
134 | } | 277 | } |
135 | #endif | 278 | #endif |
136 | |||
137 | // This turns us (the process that calls this ioctl) | 279 | // This turns us (the process that calls this ioctl) |
138 | // into a dedicated NBD request handler. | 280 | // into a dedicated NBD request handler. |
139 | // We block here for a long time. | 281 | // We block here for a long time. |
@@ -148,7 +290,7 @@ int nbdclient_main(int argc UNUSED_PARAM, char **argv) | |||
148 | 290 | ||
149 | close(sock); | 291 | close(sock); |
150 | close(nbd); | 292 | close(nbd); |
151 | } | 293 | } while (opt_p); |
152 | 294 | ||
153 | return 0; | 295 | return 0; |
154 | } | 296 | } |
diff --git a/networking/ntpd.c b/networking/ntpd.c index 1ebdc34c3..041cac762 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -62,13 +62,20 @@ | |||
62 | //config: help | 62 | //config: help |
63 | //config: Make ntpd look in /etc/ntp.conf for peers. Only "server address" | 63 | //config: Make ntpd look in /etc/ntp.conf for peers. Only "server address" |
64 | //config: is supported. | 64 | //config: is supported. |
65 | //config: | ||
66 | //config:config FEATURE_NTP_AUTH | ||
67 | //config: bool "Support md5/sha1 message authentication codes" | ||
68 | //config: default y | ||
69 | //config: depends on NTPD | ||
65 | 70 | ||
66 | //applet:IF_NTPD(APPLET(ntpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 71 | //applet:IF_NTPD(APPLET(ntpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
67 | 72 | ||
68 | //kbuild:lib-$(CONFIG_NTPD) += ntpd.o | 73 | //kbuild:lib-$(CONFIG_NTPD) += ntpd.o |
69 | 74 | ||
70 | //usage:#define ntpd_trivial_usage | 75 | //usage:#define ntpd_trivial_usage |
71 | //usage: "[-dnqNw"IF_FEATURE_NTPD_SERVER("l -I IFACE")"] [-S PROG] [-p PEER]..." | 76 | //usage: "[-dnqNw"IF_FEATURE_NTPD_SERVER("l] [-I IFACE")"] [-S PROG]" |
77 | //usage: IF_NOT_FEATURE_NTP_AUTH(" [-p PEER]...") | ||
78 | //usage: IF_FEATURE_NTP_AUTH(" [-k KEYFILE] [-p [keyno:N:]PEER]...") | ||
72 | //usage:#define ntpd_full_usage "\n\n" | 79 | //usage:#define ntpd_full_usage "\n\n" |
73 | //usage: "NTP client/server\n" | 80 | //usage: "NTP client/server\n" |
74 | //usage: "\n -d Verbose (may be repeated)" | 81 | //usage: "\n -d Verbose (may be repeated)" |
@@ -76,8 +83,16 @@ | |||
76 | //usage: "\n -q Quit after clock is set" | 83 | //usage: "\n -q Quit after clock is set" |
77 | //usage: "\n -N Run at high priority" | 84 | //usage: "\n -N Run at high priority" |
78 | //usage: "\n -w Do not set time (only query peers), implies -n" | 85 | //usage: "\n -w Do not set time (only query peers), implies -n" |
79 | //usage: "\n -S PROG Run PROG after stepping time, stratum change, and every 11 mins" | 86 | //usage: "\n -S PROG Run PROG after stepping time, stratum change, and every 11 min" |
87 | //usage: IF_NOT_FEATURE_NTP_AUTH( | ||
80 | //usage: "\n -p PEER Obtain time from PEER (may be repeated)" | 88 | //usage: "\n -p PEER Obtain time from PEER (may be repeated)" |
89 | //usage: ) | ||
90 | //usage: IF_FEATURE_NTP_AUTH( | ||
91 | //usage: "\n -k FILE Key file (ntp.keys compatible)" | ||
92 | //usage: "\n -p [keyno:NUM:]PEER" | ||
93 | //usage: "\n Obtain time from PEER (may be repeated)" | ||
94 | //usage: "\n Use key NUM for authentication" | ||
95 | //usage: ) | ||
81 | //usage: IF_FEATURE_NTPD_CONF( | 96 | //usage: IF_FEATURE_NTPD_CONF( |
82 | //usage: "\n If -p is not given, 'server HOST' lines" | 97 | //usage: "\n If -p is not given, 'server HOST' lines" |
83 | //usage: "\n from /etc/ntp.conf are used" | 98 | //usage: "\n from /etc/ntp.conf are used" |
@@ -228,14 +243,18 @@ | |||
228 | /* Parameter averaging constant */ | 243 | /* Parameter averaging constant */ |
229 | #define AVG 4 | 244 | #define AVG 4 |
230 | 245 | ||
246 | #define MAX_KEY_NUMBER 65535 | ||
247 | #define KEYID_SIZE sizeof(uint32_t) | ||
231 | 248 | ||
232 | enum { | 249 | enum { |
233 | NTP_VERSION = 4, | 250 | NTP_VERSION = 4, |
234 | NTP_MAXSTRATUM = 15, | 251 | NTP_MAXSTRATUM = 15, |
235 | 252 | ||
236 | NTP_DIGESTSIZE = 16, | 253 | NTP_MD5_DIGESTSIZE = 16, |
237 | NTP_MSGSIZE_NOAUTH = 48, | 254 | NTP_MSGSIZE_NOAUTH = 48, |
238 | NTP_MSGSIZE = (NTP_MSGSIZE_NOAUTH + 4 + NTP_DIGESTSIZE), | 255 | NTP_MSGSIZE_MD5_AUTH = NTP_MSGSIZE_NOAUTH + KEYID_SIZE + NTP_MD5_DIGESTSIZE, |
256 | NTP_SHA1_DIGESTSIZE = 20, | ||
257 | NTP_MSGSIZE_SHA1_AUTH = NTP_MSGSIZE_NOAUTH + KEYID_SIZE + NTP_SHA1_DIGESTSIZE, | ||
239 | 258 | ||
240 | /* Status Masks */ | 259 | /* Status Masks */ |
241 | MODE_MASK = (7 << 0), | 260 | MODE_MASK = (7 << 0), |
@@ -288,7 +307,7 @@ typedef struct { | |||
288 | l_fixedpt_t m_rectime; | 307 | l_fixedpt_t m_rectime; |
289 | l_fixedpt_t m_xmttime; | 308 | l_fixedpt_t m_xmttime; |
290 | uint32_t m_keyid; | 309 | uint32_t m_keyid; |
291 | uint8_t m_digest[NTP_DIGESTSIZE]; | 310 | uint8_t m_digest[ENABLE_FEATURE_NTP_AUTH ? NTP_SHA1_DIGESTSIZE : NTP_MD5_DIGESTSIZE]; |
292 | } msg_t; | 311 | } msg_t; |
293 | 312 | ||
294 | typedef struct { | 313 | typedef struct { |
@@ -297,9 +316,26 @@ typedef struct { | |||
297 | double d_dispersion; | 316 | double d_dispersion; |
298 | } datapoint_t; | 317 | } datapoint_t; |
299 | 318 | ||
319 | #if ENABLE_FEATURE_NTP_AUTH | ||
320 | enum { | ||
321 | HASH_MD5, | ||
322 | HASH_SHA1, | ||
323 | }; | ||
324 | typedef struct { | ||
325 | unsigned id; //try uint16_t? | ||
326 | smalluint type; | ||
327 | smalluint msg_size; | ||
328 | smalluint key_length; | ||
329 | char key[0]; | ||
330 | } key_entry_t; | ||
331 | #endif | ||
332 | |||
300 | typedef struct { | 333 | typedef struct { |
301 | len_and_sockaddr *p_lsa; | 334 | len_and_sockaddr *p_lsa; |
302 | char *p_dotted; | 335 | char *p_dotted; |
336 | #if ENABLE_FEATURE_NTP_AUTH | ||
337 | key_entry_t *key_entry; | ||
338 | #endif | ||
303 | int p_fd; | 339 | int p_fd; |
304 | int datapoint_idx; | 340 | int datapoint_idx; |
305 | uint32_t lastpkt_refid; | 341 | uint32_t lastpkt_refid; |
@@ -337,13 +373,14 @@ enum { | |||
337 | OPT_q = (1 << 1), | 373 | OPT_q = (1 << 1), |
338 | OPT_N = (1 << 2), | 374 | OPT_N = (1 << 2), |
339 | OPT_x = (1 << 3), | 375 | OPT_x = (1 << 3), |
376 | OPT_k = (1 << 4) * ENABLE_FEATURE_NTP_AUTH, | ||
340 | /* Insert new options above this line. */ | 377 | /* Insert new options above this line. */ |
341 | /* Non-compat options: */ | 378 | /* Non-compat options: */ |
342 | OPT_w = (1 << 4), | 379 | OPT_w = (1 << (4+ENABLE_FEATURE_NTP_AUTH)), |
343 | OPT_p = (1 << 5), | 380 | OPT_p = (1 << (5+ENABLE_FEATURE_NTP_AUTH)), |
344 | OPT_S = (1 << 6), | 381 | OPT_S = (1 << (6+ENABLE_FEATURE_NTP_AUTH)), |
345 | OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER, | 382 | OPT_l = (1 << (7+ENABLE_FEATURE_NTP_AUTH)) * ENABLE_FEATURE_NTPD_SERVER, |
346 | OPT_I = (1 << 8) * ENABLE_FEATURE_NTPD_SERVER, | 383 | OPT_I = (1 << (8+ENABLE_FEATURE_NTP_AUTH)) * ENABLE_FEATURE_NTPD_SERVER, |
347 | /* We hijack some bits for other purposes */ | 384 | /* We hijack some bits for other purposes */ |
348 | OPT_qq = (1 << 31), | 385 | OPT_qq = (1 << 31), |
349 | }; | 386 | }; |
@@ -816,8 +853,12 @@ resolve_peer_hostname(peer_t *p) | |||
816 | return lsa; | 853 | return lsa; |
817 | } | 854 | } |
818 | 855 | ||
856 | #if !ENABLE_FEATURE_NTP_AUTH | ||
857 | #define add_peers(s, key_entry) \ | ||
858 | add_peers(s) | ||
859 | #endif | ||
819 | static void | 860 | static void |
820 | add_peers(const char *s) | 861 | add_peers(const char *s, key_entry_t *key_entry) |
821 | { | 862 | { |
822 | llist_t *item; | 863 | llist_t *item; |
823 | peer_t *p; | 864 | peer_t *p; |
@@ -846,6 +887,7 @@ add_peers(const char *s) | |||
846 | } | 887 | } |
847 | } | 888 | } |
848 | 889 | ||
890 | IF_FEATURE_NTP_AUTH(p->key_entry = key_entry;) | ||
849 | llist_add_to(&G.ntp_peers, p); | 891 | llist_add_to(&G.ntp_peers, p); |
850 | G.peer_cnt++; | 892 | G.peer_cnt++; |
851 | } | 893 | } |
@@ -870,6 +912,48 @@ do_sendto(int fd, | |||
870 | return 0; | 912 | return 0; |
871 | } | 913 | } |
872 | 914 | ||
915 | #if ENABLE_FEATURE_NTP_AUTH | ||
916 | static void | ||
917 | hash(key_entry_t *key_entry, const msg_t *msg, uint8_t *output) | ||
918 | { | ||
919 | union { | ||
920 | md5_ctx_t m; | ||
921 | sha1_ctx_t s; | ||
922 | } ctx; | ||
923 | unsigned hash_size = sizeof(*msg) - sizeof(msg->m_keyid) - sizeof(msg->m_digest); | ||
924 | |||
925 | switch (key_entry->type) { | ||
926 | case HASH_MD5: | ||
927 | md5_begin(&ctx.m); | ||
928 | md5_hash(&ctx.m, key_entry->key, key_entry->key_length); | ||
929 | md5_hash(&ctx.m, msg, hash_size); | ||
930 | md5_end(&ctx.m, output); | ||
931 | break; | ||
932 | default: /* it's HASH_SHA1 */ | ||
933 | sha1_begin(&ctx.s); | ||
934 | sha1_hash(&ctx.s, key_entry->key, key_entry->key_length); | ||
935 | sha1_hash(&ctx.s, msg, hash_size); | ||
936 | sha1_end(&ctx.s, output); | ||
937 | break; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | static void | ||
942 | hash_peer(peer_t *p) | ||
943 | { | ||
944 | p->p_xmt_msg.m_keyid = htonl(p->key_entry->id); | ||
945 | hash(p->key_entry, &p->p_xmt_msg, p->p_xmt_msg.m_digest); | ||
946 | } | ||
947 | |||
948 | static int | ||
949 | hashes_differ(peer_t *p, const msg_t *msg) | ||
950 | { | ||
951 | uint8_t digest[NTP_SHA1_DIGESTSIZE]; | ||
952 | hash(p->key_entry, msg, digest); | ||
953 | return memcmp(digest, msg->m_digest, p->key_entry->msg_size - NTP_MSGSIZE_NOAUTH - KEYID_SIZE); | ||
954 | } | ||
955 | #endif | ||
956 | |||
873 | static void | 957 | static void |
874 | send_query_to_peer(peer_t *p) | 958 | send_query_to_peer(peer_t *p) |
875 | { | 959 | { |
@@ -946,9 +1030,18 @@ send_query_to_peer(peer_t *p) | |||
946 | */ | 1030 | */ |
947 | p->reachable_bits <<= 1; | 1031 | p->reachable_bits <<= 1; |
948 | 1032 | ||
1033 | #if ENABLE_FEATURE_NTP_AUTH | ||
1034 | if (p->key_entry) | ||
1035 | hash_peer(p); | ||
949 | if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len, | 1036 | if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len, |
950 | &p->p_xmt_msg, NTP_MSGSIZE_NOAUTH) == -1 | 1037 | &p->p_xmt_msg, !p->key_entry ? NTP_MSGSIZE_NOAUTH : p->key_entry->msg_size) == -1 |
951 | ) { | 1038 | ) |
1039 | #else | ||
1040 | if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len, | ||
1041 | &p->p_xmt_msg, NTP_MSGSIZE_NOAUTH) == -1 | ||
1042 | ) | ||
1043 | #endif | ||
1044 | { | ||
952 | close(p->p_fd); | 1045 | close(p->p_fd); |
953 | p->p_fd = -1; | 1046 | p->p_fd = -1; |
954 | /* | 1047 | /* |
@@ -1924,10 +2017,21 @@ recv_and_process_peer_pkt(peer_t *p) | |||
1924 | bb_perror_msg_and_die("recv(%s) error", p->p_dotted); | 2017 | bb_perror_msg_and_die("recv(%s) error", p->p_dotted); |
1925 | } | 2018 | } |
1926 | 2019 | ||
1927 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { | 2020 | #if ENABLE_FEATURE_NTP_AUTH |
2021 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH && size != NTP_MSGSIZE_SHA1_AUTH) { | ||
2022 | bb_error_msg("malformed packet received from %s", p->p_dotted); | ||
2023 | return; | ||
2024 | } | ||
2025 | if (p->key_entry && hashes_differ(p, &msg)) { | ||
2026 | bb_error_msg("invalid cryptographic hash received from %s", p->p_dotted); | ||
2027 | return; | ||
2028 | } | ||
2029 | #else | ||
2030 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH) { | ||
1928 | bb_error_msg("malformed packet received from %s", p->p_dotted); | 2031 | bb_error_msg("malformed packet received from %s", p->p_dotted); |
1929 | return; | 2032 | return; |
1930 | } | 2033 | } |
2034 | #endif | ||
1931 | 2035 | ||
1932 | if (msg.m_orgtime.int_partl != p->p_xmt_msg.m_xmttime.int_partl | 2036 | if (msg.m_orgtime.int_partl != p->p_xmt_msg.m_xmttime.int_partl |
1933 | || msg.m_orgtime.fractionl != p->p_xmt_msg.m_xmttime.fractionl | 2037 | || msg.m_orgtime.fractionl != p->p_xmt_msg.m_xmttime.fractionl |
@@ -2135,7 +2239,12 @@ recv_and_process_client_pkt(void /*int fd*/) | |||
2135 | from = xzalloc(to->len); | 2239 | from = xzalloc(to->len); |
2136 | 2240 | ||
2137 | size = recv_from_to(G_listen_fd, &msg, sizeof(msg), MSG_DONTWAIT, from, &to->u.sa, to->len); | 2241 | size = recv_from_to(G_listen_fd, &msg, sizeof(msg), MSG_DONTWAIT, from, &to->u.sa, to->len); |
2138 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { | 2242 | #if ENABLE_FEATURE_NTP_AUTH |
2243 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH && size != NTP_MSGSIZE_SHA1_AUTH) | ||
2244 | #else | ||
2245 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE_MD5_AUTH) | ||
2246 | #endif | ||
2247 | { | ||
2139 | char *addr; | 2248 | char *addr; |
2140 | if (size < 0) { | 2249 | if (size < 0) { |
2141 | if (errno == EAGAIN) | 2250 | if (errno == EAGAIN) |
@@ -2278,6 +2387,19 @@ recv_and_process_client_pkt(void /*int fd*/) | |||
2278 | * with the -g and -q options. See the tinker command for other options. | 2387 | * with the -g and -q options. See the tinker command for other options. |
2279 | * Note: The kernel time discipline is disabled with this option. | 2388 | * Note: The kernel time discipline is disabled with this option. |
2280 | */ | 2389 | */ |
2390 | #if ENABLE_FEATURE_NTP_AUTH | ||
2391 | static key_entry_t * | ||
2392 | find_key_entry(llist_t *key_entries, unsigned id) | ||
2393 | { | ||
2394 | while (key_entries) { | ||
2395 | key_entry_t *cur = (key_entry_t*) key_entries->data; | ||
2396 | if (cur->id == id) | ||
2397 | return cur; | ||
2398 | key_entries = key_entries->link; | ||
2399 | } | ||
2400 | bb_error_msg_and_die("key %u is not defined", id); | ||
2401 | } | ||
2402 | #endif | ||
2281 | 2403 | ||
2282 | /* By doing init in a separate function we decrease stack usage | 2404 | /* By doing init in a separate function we decrease stack usage |
2283 | * in main loop. | 2405 | * in main loop. |
@@ -2286,6 +2408,10 @@ static NOINLINE void ntp_init(char **argv) | |||
2286 | { | 2408 | { |
2287 | unsigned opts; | 2409 | unsigned opts; |
2288 | llist_t *peers; | 2410 | llist_t *peers; |
2411 | #if ENABLE_FEATURE_NTP_AUTH | ||
2412 | llist_t *key_entries; | ||
2413 | char *key_file_path; | ||
2414 | #endif | ||
2289 | 2415 | ||
2290 | srand(getpid()); | 2416 | srand(getpid()); |
2291 | 2417 | ||
@@ -2302,8 +2428,10 @@ static NOINLINE void ntp_init(char **argv) | |||
2302 | 2428 | ||
2303 | /* Parse options */ | 2429 | /* Parse options */ |
2304 | peers = NULL; | 2430 | peers = NULL; |
2431 | IF_FEATURE_NTP_AUTH(key_entries = NULL;) | ||
2305 | opts = getopt32(argv, "^" | 2432 | opts = getopt32(argv, "^" |
2306 | "nqNx" /* compat */ | 2433 | "nqNx" /* compat */ |
2434 | IF_FEATURE_NTP_AUTH("k:") /* compat */ | ||
2307 | "wp:*S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */ | 2435 | "wp:*S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */ |
2308 | IF_FEATURE_NTPD_SERVER("I:") /* compat */ | 2436 | IF_FEATURE_NTPD_SERVER("I:") /* compat */ |
2309 | "d" /* compat */ | 2437 | "d" /* compat */ |
@@ -2311,11 +2439,11 @@ static NOINLINE void ntp_init(char **argv) | |||
2311 | "\0" | 2439 | "\0" |
2312 | "dd:wn" /* -d: counter; -p: list; -w implies -n */ | 2440 | "dd:wn" /* -d: counter; -p: list; -w implies -n */ |
2313 | IF_FEATURE_NTPD_SERVER(":Il") /* -I implies -l */ | 2441 | IF_FEATURE_NTPD_SERVER(":Il") /* -I implies -l */ |
2314 | , &peers, &G.script_name, | 2442 | IF_FEATURE_NTP_AUTH(, &key_file_path) |
2315 | #if ENABLE_FEATURE_NTPD_SERVER | 2443 | , &peers, &G.script_name |
2316 | &G.if_name, | 2444 | IF_FEATURE_NTPD_SERVER(, &G.if_name) |
2317 | #endif | 2445 | , &G.verbose |
2318 | &G.verbose); | 2446 | ); |
2319 | 2447 | ||
2320 | // if (opts & OPT_x) /* disable stepping, only slew is allowed */ | 2448 | // if (opts & OPT_x) /* disable stepping, only slew is allowed */ |
2321 | // G.time_was_stepped = 1; | 2449 | // G.time_was_stepped = 1; |
@@ -2341,19 +2469,108 @@ static NOINLINE void ntp_init(char **argv) | |||
2341 | logmode = LOGMODE_NONE; | 2469 | logmode = LOGMODE_NONE; |
2342 | } | 2470 | } |
2343 | 2471 | ||
2472 | #if ENABLE_FEATURE_NTP_AUTH | ||
2473 | if (opts & OPT_k) { | ||
2474 | char *tokens[4]; | ||
2475 | parser_t *parser; | ||
2476 | |||
2477 | parser = config_open(key_file_path); | ||
2478 | while (config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL | PARSE_MIN_DIE) == 3) { | ||
2479 | key_entry_t *key_entry; | ||
2480 | char buffer[40]; | ||
2481 | smalluint hash_type; | ||
2482 | smalluint msg_size; | ||
2483 | smalluint key_length; | ||
2484 | char *key; | ||
2485 | |||
2486 | if ((tokens[1][0] | 0x20) == 'm') | ||
2487 | /* supports 'M' and 'md5' formats */ | ||
2488 | hash_type = HASH_MD5; | ||
2489 | else | ||
2490 | if (strncasecmp(tokens[1], "sha", 3) == 0) | ||
2491 | /* supports 'sha' and 'sha1' formats */ | ||
2492 | hash_type = HASH_SHA1; | ||
2493 | else | ||
2494 | bb_error_msg_and_die("only MD5 and SHA1 keys supported"); | ||
2495 | /* man ntp.keys: | ||
2496 | * MD5 The key is 1 to 16 printable characters terminated by an EOL, | ||
2497 | * whitespace, or a # (which is the "start of comment" character). | ||
2498 | * SHA | ||
2499 | * SHA1 | ||
2500 | * RMD160 The key is a hex-encoded ASCII string of 40 characters, which | ||
2501 | * is truncated as necessary. | ||
2502 | */ | ||
2503 | key_length = strnlen(tokens[2], sizeof(buffer)+1); | ||
2504 | if (key_length >= sizeof(buffer)+1) { | ||
2505 | err: | ||
2506 | bb_error_msg_and_die("malformed key at line %u", parser->lineno); | ||
2507 | } | ||
2508 | if (hash_type == HASH_MD5) { | ||
2509 | key = tokens[2]; | ||
2510 | msg_size = NTP_MSGSIZE_MD5_AUTH; | ||
2511 | } else /* it's hash_type == HASH_SHA1 */ | ||
2512 | if (!(key_length & 1)) { | ||
2513 | key_length >>= 1; | ||
2514 | if (!hex2bin(buffer, tokens[2], key_length)) | ||
2515 | goto err; | ||
2516 | key = buffer; | ||
2517 | msg_size = NTP_MSGSIZE_SHA1_AUTH; | ||
2518 | } else { | ||
2519 | goto err; | ||
2520 | } | ||
2521 | key_entry = xzalloc(sizeof(*key_entry) + key_length); | ||
2522 | key_entry->type = hash_type; | ||
2523 | key_entry->msg_size = msg_size; | ||
2524 | key_entry->key_length = key_length; | ||
2525 | memcpy(key_entry->key, key, key_length); | ||
2526 | key_entry->id = xatou_range(tokens[0], 1, MAX_KEY_NUMBER); | ||
2527 | llist_add_to(&key_entries, key_entry); | ||
2528 | } | ||
2529 | config_close(parser); | ||
2530 | } | ||
2531 | #endif | ||
2344 | if (peers) { | 2532 | if (peers) { |
2533 | #if ENABLE_FEATURE_NTP_AUTH | ||
2534 | while (peers) { | ||
2535 | char *peer = llist_pop(&peers); | ||
2536 | key_entry_t *key_entry = NULL; | ||
2537 | if (strncmp(peer, "keyno:", 6) == 0) { | ||
2538 | char *end; | ||
2539 | int key_id; | ||
2540 | peer += 6; | ||
2541 | end = strchr(peer, ':'); | ||
2542 | if (!end) bb_show_usage(); | ||
2543 | *end = '\0'; | ||
2544 | key_id = xatou_range(peer, 1, MAX_KEY_NUMBER); | ||
2545 | *end = ':'; | ||
2546 | key_entry = find_key_entry(key_entries, key_id); | ||
2547 | peer = end + 1; | ||
2548 | } | ||
2549 | add_peers(peer, key_entry); | ||
2550 | } | ||
2551 | #else | ||
2345 | while (peers) | 2552 | while (peers) |
2346 | add_peers(llist_pop(&peers)); | 2553 | add_peers(llist_pop(&peers), NULL); |
2554 | #endif | ||
2347 | } | 2555 | } |
2348 | #if ENABLE_FEATURE_NTPD_CONF | 2556 | #if ENABLE_FEATURE_NTPD_CONF |
2349 | else { | 2557 | else { |
2350 | parser_t *parser; | 2558 | parser_t *parser; |
2351 | char *token[3]; | 2559 | char *token[3 + 2*ENABLE_FEATURE_NTP_AUTH]; |
2352 | 2560 | ||
2353 | parser = config_open("/etc/ntp.conf"); | 2561 | parser = config_open("/etc/ntp.conf"); |
2354 | while (config_read(parser, token, 3, 1, "# \t", PARSE_NORMAL)) { | 2562 | while (config_read(parser, token, 3 + 2*ENABLE_FEATURE_NTP_AUTH, 1, "# \t", PARSE_NORMAL)) { |
2355 | if (strcmp(token[0], "server") == 0 && token[1]) { | 2563 | if (strcmp(token[0], "server") == 0 && token[1]) { |
2356 | add_peers(token[1]); | 2564 | # if ENABLE_FEATURE_NTP_AUTH |
2565 | key_entry_t *key_entry = NULL; | ||
2566 | if (token[2] && token[3] && strcmp(token[2], "key") == 0) { | ||
2567 | unsigned key_id = xatou_range(token[3], 1, MAX_KEY_NUMBER); | ||
2568 | key_entry = find_key_entry(key_entries, key_id); | ||
2569 | } | ||
2570 | add_peers(token[1], key_entry); | ||
2571 | # else | ||
2572 | add_peers(token[1], NULL); | ||
2573 | # endif | ||
2357 | continue; | 2574 | continue; |
2358 | } | 2575 | } |
2359 | bb_error_msg("skipping %s:%u: unimplemented command '%s'", | 2576 | bb_error_msg("skipping %s:%u: unimplemented command '%s'", |
@@ -2394,6 +2611,7 @@ static NOINLINE void ntp_init(char **argv) | |||
2394 | | (1 << SIGCHLD) | 2611 | | (1 << SIGCHLD) |
2395 | , SIG_IGN | 2612 | , SIG_IGN |
2396 | ); | 2613 | ); |
2614 | //TODO: free unused elements of key_entries? | ||
2397 | } | 2615 | } |
2398 | 2616 | ||
2399 | int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; | 2617 | int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; |
diff --git a/networking/tls.c b/networking/tls.c index fce1d0ea6..38eb79798 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
@@ -12,16 +12,18 @@ | |||
12 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o | 12 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o |
13 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o | 13 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o |
14 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o | 14 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o |
15 | //kbuild:lib-$(CONFIG_TLS) += tls_rsa.o | ||
16 | //kbuild:lib-$(CONFIG_TLS) += tls_aes.o | 15 | //kbuild:lib-$(CONFIG_TLS) += tls_aes.o |
17 | ////kbuild:lib-$(CONFIG_TLS) += tls_aes_gcm.o | 16 | //kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o |
17 | //kbuild:lib-$(CONFIG_TLS) += tls_rsa.o | ||
18 | //kbuild:lib-$(CONFIG_TLS) += tls_fe.o | ||
18 | 19 | ||
19 | #include "tls.h" | 20 | #include "tls.h" |
20 | 21 | ||
22 | // works against "openssl s_server -cipher NULL" | ||
23 | // and against wolfssl-3.9.10-stable/examples/server/server.c: | ||
24 | #define ALLOW_RSA_NULL_SHA256 0 // for testing (does everything except encrypting) | ||
25 | |||
21 | //Tested against kernel.org: | 26 | //Tested against kernel.org: |
22 | //TLS 1.2 | ||
23 | #define TLS_MAJ 3 | ||
24 | #define TLS_MIN 3 | ||
25 | //#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box | 27 | //#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box |
26 | //#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE | 28 | //#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE |
27 | //#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE | 29 | //#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE |
@@ -35,26 +37,28 @@ | |||
35 | //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 | 37 | //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 |
36 | //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE | 38 | //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE |
37 | //#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE | 39 | //#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE |
38 | //#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this? | 40 | //#define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE |
39 | |||
40 | // works against "openssl s_server -cipher NULL" | ||
41 | // and against wolfssl-3.9.10-stable/examples/server/server.c: | ||
42 | //#define CIPHER_ID1 TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting) | ||
43 | 41 | ||
44 | // works against wolfssl-3.9.10-stable/examples/server/server.c | 42 | // works against wolfssl-3.9.10-stable/examples/server/server.c |
45 | // works for kernel.org | 43 | // works for kernel.org |
46 | // does not work for cdn.kernel.org (e.g. downloading an actual tarball, not a web page) | 44 | // does not work for cdn.kernel.org (e.g. downloading an actual tarball, not a web page) |
47 | // getting alert 40 "handshake failure" at once | 45 | // getting alert 40 "handshake failure" at once |
48 | // with GNU Wget 1.18, they agree on TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) cipher | 46 | // with GNU Wget 1.18, they agree on TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F) cipher |
49 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-SHA256 | 47 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -cipher AES256-SHA256 |
50 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES256-GCM-SHA384 | 48 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -cipher AES256-GCM-SHA384 |
51 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA256 | 49 | // fail: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -cipher AES128-SHA256 |
52 | // ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-GCM-SHA256 | 50 | // ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -cipher AES128-GCM-SHA256 |
53 | // ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher AES128-SHA | 51 | // ok: openssl s_client -connect cdn.kernel.org:443 -debug -tls1_2 -cipher AES128-SHA |
54 | // (TLS_RSA_WITH_AES_128_CBC_SHA - in TLS 1.2 it's mandated to be always supported) | 52 | // (TLS_RSA_WITH_AES_128_CBC_SHA - in TLS 1.2 it's mandated to be always supported) |
55 | #define CIPHER_ID1 TLS_RSA_WITH_AES_256_CBC_SHA256 // no SERVER_KEY_EXCHANGE from peer | 53 | //#define CIPHER_ID1 TLS_RSA_WITH_AES_256_CBC_SHA256 //0x003D |
56 | // Works with "wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.9.5.tar.xz" | 54 | // Works with "wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.9.5.tar.xz" |
57 | #define CIPHER_ID2 TLS_RSA_WITH_AES_128_CBC_SHA | 55 | //#define CIPHER_ID2 TLS_RSA_WITH_AES_128_CBC_SHA //0x002F |
56 | |||
57 | // bug #11456: | ||
58 | // ftp.openbsd.org only supports ECDHE-RSA-AESnnn-GCM-SHAnnn or ECDHE-RSA-CHACHA20-POLY1305 | ||
59 | //#define CIPHER_ID3 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 //0xC02F | ||
60 | // host is.gd accepts only ECDHE-ECDSA-foo (the simplest which works: ECDHE-ECDSA-AES128-SHA 0xC009) | ||
61 | //#define CIPHER_ID4 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA //0xC009 | ||
58 | 62 | ||
59 | 63 | ||
60 | #define TLS_DEBUG 0 | 64 | #define TLS_DEBUG 0 |
@@ -84,6 +88,11 @@ | |||
84 | # define dbg_der(...) ((void)0) | 88 | # define dbg_der(...) ((void)0) |
85 | #endif | 89 | #endif |
86 | 90 | ||
91 | |||
92 | //TLS 1.2 | ||
93 | #define TLS_MAJ 3 | ||
94 | #define TLS_MIN 3 | ||
95 | |||
87 | #define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 /* 0x14 */ | 96 | #define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 /* 0x14 */ |
88 | #define RECORD_TYPE_ALERT 21 /* 0x15 */ | 97 | #define RECORD_TYPE_ALERT 21 /* 0x15 */ |
89 | #define RECORD_TYPE_HANDSHAKE 22 /* 0x16 */ | 98 | #define RECORD_TYPE_HANDSHAKE 22 /* 0x16 */ |
@@ -102,66 +111,98 @@ | |||
102 | #define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 /* 0x10 */ | 111 | #define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 /* 0x10 */ |
103 | #define HANDSHAKE_FINISHED 20 /* 0x14 */ | 112 | #define HANDSHAKE_FINISHED 20 /* 0x14 */ |
104 | 113 | ||
114 | #define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF /* not a real cipher id... */ | ||
115 | |||
105 | #define SSL_NULL_WITH_NULL_NULL 0x0000 | 116 | #define SSL_NULL_WITH_NULL_NULL 0x0000 |
106 | #define SSL_RSA_WITH_NULL_MD5 0x0001 | 117 | #define SSL_RSA_WITH_NULL_MD5 0x0001 |
107 | #define SSL_RSA_WITH_NULL_SHA 0x0002 | 118 | #define SSL_RSA_WITH_NULL_SHA 0x0002 |
108 | #define SSL_RSA_WITH_RC4_128_MD5 0x0004 | 119 | #define SSL_RSA_WITH_RC4_128_MD5 0x0004 |
109 | #define SSL_RSA_WITH_RC4_128_SHA 0x0005 | 120 | #define SSL_RSA_WITH_RC4_128_SHA 0x0005 |
121 | #define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* 7 */ | ||
110 | #define SSL_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* 10 */ | 122 | #define SSL_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* 10 */ |
111 | #define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /* 47 */ | ||
112 | #define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* 53 */ | ||
113 | #define TLS_RSA_WITH_NULL_SHA256 0x003B /* 59 */ | ||
114 | |||
115 | #define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF | ||
116 | 123 | ||
117 | #define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* 7 */ | ||
118 | #define SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* 22 */ | 124 | #define SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* 22 */ |
119 | #define SSL_DH_anon_WITH_RC4_128_MD5 0x0018 /* 24 */ | 125 | #define SSL_DH_anon_WITH_RC4_128_MD5 0x0018 /* 24 */ |
120 | #define SSL_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* 27 */ | 126 | #define SSL_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* 27 */ |
127 | #define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /*SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 */ | ||
121 | #define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* 51 */ | 128 | #define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* 51 */ |
122 | #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* 57 */ | ||
123 | #define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 /* 103 */ | ||
124 | #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B /* 107 */ | ||
125 | #define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* 52 */ | 129 | #define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* 52 */ |
130 | #define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* 53 */ | ||
131 | #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* 57 */ | ||
126 | #define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* 58 */ | 132 | #define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* 58 */ |
133 | #define TLS_RSA_WITH_NULL_SHA256 0x003B /* 59 */ | ||
127 | #define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C /* 60 */ | 134 | #define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C /* 60 */ |
128 | #define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D /* 61 */ | 135 | #define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D /* 61 */ |
129 | #define TLS_RSA_WITH_SEED_CBC_SHA 0x0096 /* 150 */ | 136 | #define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 /* 103 */ |
137 | #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B /* 107 */ | ||
130 | #define TLS_PSK_WITH_AES_128_CBC_SHA 0x008C /* 140 */ | 138 | #define TLS_PSK_WITH_AES_128_CBC_SHA 0x008C /* 140 */ |
131 | #define TLS_PSK_WITH_AES_128_CBC_SHA256 0x00AE /* 174 */ | ||
132 | #define TLS_PSK_WITH_AES_256_CBC_SHA384 0x00AF /* 175 */ | ||
133 | #define TLS_PSK_WITH_AES_256_CBC_SHA 0x008D /* 141 */ | 139 | #define TLS_PSK_WITH_AES_256_CBC_SHA 0x008D /* 141 */ |
134 | #define TLS_DHE_PSK_WITH_AES_128_CBC_SHA 0x0090 /* 144 */ | 140 | #define TLS_DHE_PSK_WITH_AES_128_CBC_SHA 0x0090 /* 144 */ |
135 | #define TLS_DHE_PSK_WITH_AES_256_CBC_SHA 0x0091 /* 145 */ | 141 | #define TLS_DHE_PSK_WITH_AES_256_CBC_SHA 0x0091 /* 145 */ |
142 | #define TLS_RSA_WITH_SEED_CBC_SHA 0x0096 /* 150 */ | ||
143 | #define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C /*TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD */ | ||
144 | #define TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D /*TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD */ | ||
145 | #define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E /*TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD */ | ||
146 | #define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F /*TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD */ | ||
147 | #define TLS_DH_anon_WITH_AES_128_GCM_SHA256 0x00A6 /* RFC 5288 */ | ||
148 | #define TLS_DH_anon_WITH_AES_256_GCM_SHA384 0x00A7 /* RFC 5288 */ | ||
149 | #define TLS_PSK_WITH_AES_128_CBC_SHA256 0x00AE /* 174 */ | ||
150 | #define TLS_PSK_WITH_AES_256_CBC_SHA384 0x00AF /* 175 */ | ||
136 | #define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 /* 49156 */ | 151 | #define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 /* 49156 */ |
137 | #define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 /* 49157 */ | 152 | #define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 /* 49157 */ |
138 | #define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 /* 49161 */ | 153 | #define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 /*TLSv1 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 */ |
139 | #define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A /* 49162 */ | 154 | #define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A /*TLSv1 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 */ |
140 | #define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 /* 49170 */ | ||
141 | #define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 /* 49171 */ | ||
142 | #define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 /* 49172 */ | ||
143 | #define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E /* 49166 */ | 155 | #define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E /* 49166 */ |
144 | #define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F /* 49167 */ | 156 | #define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F /* 49167 */ |
145 | #define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 /* 49187 */ | 157 | #define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 /* 49170 */ |
146 | #define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024 /* 49188 */ | 158 | #define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 /*TLSv1 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 */ |
159 | #define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 /*TLSv1 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 */ | ||
160 | #define TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018 /* RFC 4492 */ | ||
161 | #define TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019 /* RFC 4492 */ | ||
162 | #define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 */ | ||
163 | #define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024 /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 */ | ||
147 | #define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025 /* 49189 */ | 164 | #define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025 /* 49189 */ |
148 | #define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026 /* 49190 */ | 165 | #define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026 /* 49190 */ |
149 | #define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 /* 49191 */ | 166 | #define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 /*TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 */ |
150 | #define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028 /* 49192 */ | 167 | #define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028 /*TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 */ |
151 | #define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029 /* 49193 */ | 168 | #define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029 /* 49193 */ |
152 | #define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A /* 49194 */ | 169 | #define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A /* 49194 */ |
153 | |||
154 | /* RFC 5288 "AES Galois Counter Mode (GCM) Cipher Suites for TLS" */ | 170 | /* RFC 5288 "AES Galois Counter Mode (GCM) Cipher Suites for TLS" */ |
155 | #define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C /* 156 */ | 171 | #define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD */ |
156 | #define TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D /* 157 */ | 172 | #define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD */ |
157 | #define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B /* 49195 */ | ||
158 | #define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C /* 49196 */ | ||
159 | #define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D /* 49197 */ | 173 | #define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D /* 49197 */ |
160 | #define TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E /* 49198 */ | 174 | #define TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E /* 49198 */ |
161 | #define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F /* 49199 */ | 175 | #define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F /*TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD */ |
162 | #define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030 /* 49200 */ | 176 | #define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030 /*TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD */ |
163 | #define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 /* 49201 */ | 177 | #define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 /* 49201 */ |
164 | #define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 /* 49202 */ | 178 | #define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 /* 49202 */ |
179 | #define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA 0xC035 | ||
180 | #define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA 0xC036 | ||
181 | #define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 0xC037 | ||
182 | #define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 0xC038 | ||
183 | |||
184 | /* From http://wiki.mozilla.org/Security/Server_Side_TLS */ | ||
185 | /* and 'openssl ciphers -V -stdname' */ | ||
186 | #define TLS_RSA_WITH_AES_128_CCM 0xC09C /*TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM(128) Mac=AEAD */ | ||
187 | #define TLS_RSA_WITH_AES_256_CCM 0xC09D /*TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM(256) Mac=AEAD */ | ||
188 | #define TLS_DHE_RSA_WITH_AES_128_CCM 0xC09E /*TLSv1.2 Kx=DH Au=RSA Enc=AESCCM(128) Mac=AEAD */ | ||
189 | #define TLS_DHE_RSA_WITH_AES_256_CCM 0xC09F /*TLSv1.2 Kx=DH Au=RSA Enc=AESCCM(256) Mac=AEAD */ | ||
190 | #define TLS_RSA_WITH_AES_128_CCM_8 0xC0A0 /*TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM8(128) Mac=AEAD */ | ||
191 | #define TLS_RSA_WITH_AES_256_CCM_8 0xC0A1 /*TLSv1.2 Kx=RSA Au=RSA Enc=AESCCM8(256) Mac=AEAD */ | ||
192 | #define TLS_DHE_RSA_WITH_AES_128_CCM_8 0xC0A2 /*TLSv1.2 Kx=DH Au=RSA Enc=AESCCM8(128) Mac=AEAD */ | ||
193 | #define TLS_DHE_RSA_WITH_AES_256_CCM_8 0xC0A3 /*TLSv1.2 Kx=DH Au=RSA Enc=AESCCM8(256) Mac=AEAD */ | ||
194 | #define TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESCCM(128) Mac=AEAD */ | ||
195 | #define TLS_ECDHE_ECDSA_WITH_AES_256_CCM 0xC0AD /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESCCM(256) Mac=AEAD */ | ||
196 | #define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESCCM8(128) Mac=AEAD */ | ||
197 | #define TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESCCM8(256) Mac=AEAD */ | ||
198 | #define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8 /*TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD */ | ||
199 | #define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9 /*TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD */ | ||
200 | #define TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA /*TLSv1.2 Kx=DH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD */ | ||
201 | |||
202 | #define TLS_AES_128_GCM_SHA256 0x1301 /*TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD */ | ||
203 | #define TLS_AES_256_GCM_SHA384 0x1302 /*TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD */ | ||
204 | #define TLS_CHACHA20_POLY1305_SHA256 0x1303 /*TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD */ | ||
205 | #define TLS_AES_128_CCM_SHA256 0x1304 /*TLSv1.3 Kx=any Au=any Enc=AESCCM(128) Mac=AEAD */ | ||
165 | 206 | ||
166 | /* Might go to libbb.h */ | 207 | /* Might go to libbb.h */ |
167 | #define TLS_MAX_CRYPTBLOCK_SIZE 16 | 208 | #define TLS_MAX_CRYPTBLOCK_SIZE 16 |
@@ -172,7 +213,6 @@ enum { | |||
172 | SHA1_OUTSIZE = 20, | 213 | SHA1_OUTSIZE = 20, |
173 | SHA256_OUTSIZE = 32, | 214 | SHA256_OUTSIZE = 32, |
174 | 215 | ||
175 | AES_BLOCKSIZE = 16, | ||
176 | AES128_KEYSIZE = 16, | 216 | AES128_KEYSIZE = 16, |
177 | AES256_KEYSIZE = 32, | 217 | AES256_KEYSIZE = 32, |
178 | 218 | ||
@@ -181,10 +221,10 @@ enum { | |||
181 | RECHDR_LEN = 5, | 221 | RECHDR_LEN = 5, |
182 | 222 | ||
183 | /* 8 = 3+5. 3 extra bytes result in record data being 32-bit aligned */ | 223 | /* 8 = 3+5. 3 extra bytes result in record data being 32-bit aligned */ |
184 | OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */ | 224 | OUTBUF_PFX = 8 + AES_BLOCK_SIZE, /* header + IV */ |
185 | OUTBUF_SFX = TLS_MAX_MAC_SIZE + TLS_MAX_CRYPTBLOCK_SIZE, /* MAC + padding */ | 225 | OUTBUF_SFX = TLS_MAX_MAC_SIZE + TLS_MAX_CRYPTBLOCK_SIZE, /* MAC + padding */ |
186 | 226 | ||
187 | // RFC 5246 | 227 | // RFC 5246: |
188 | // | 6.2.1. Fragmentation | 228 | // | 6.2.1. Fragmentation |
189 | // | The record layer fragments information blocks into TLSPlaintext | 229 | // | The record layer fragments information blocks into TLSPlaintext |
190 | // | records carrying data in chunks of 2^14 bytes or less. Client | 230 | // | records carrying data in chunks of 2^14 bytes or less. Client |
@@ -219,6 +259,14 @@ enum { | |||
219 | // | The length (in bytes) of the following TLSCiphertext.fragment. | 259 | // | The length (in bytes) of the following TLSCiphertext.fragment. |
220 | // | The length MUST NOT exceed 2^14 + 2048. | 260 | // | The length MUST NOT exceed 2^14 + 2048. |
221 | MAX_INBUF = RECHDR_LEN + (1 << 14) + 2048, | 261 | MAX_INBUF = RECHDR_LEN + (1 << 14) + 2048, |
262 | |||
263 | /* Bits for tls->flags */ | ||
264 | NEED_EC_KEY = 1 << 0, | ||
265 | GOT_CERT_RSA_KEY_ALG = 1 << 1, | ||
266 | GOT_CERT_ECDSA_KEY_ALG = 1 << 2, // so far unused | ||
267 | GOT_EC_KEY = 1 << 3, | ||
268 | ENCRYPTION_AESGCM = 1 << 4, // else AES-SHA (or NULL-SHA if ALLOW_RSA_NULL_SHA256=1) | ||
269 | ENCRYPT_ON_WRITE = 1 << 5, | ||
222 | }; | 270 | }; |
223 | 271 | ||
224 | struct record_hdr { | 272 | struct record_hdr { |
@@ -233,12 +281,15 @@ struct tls_handshake_data { | |||
233 | 281 | ||
234 | uint8_t client_and_server_rand32[2 * 32]; | 282 | uint8_t client_and_server_rand32[2 * 32]; |
235 | uint8_t master_secret[48]; | 283 | uint8_t master_secret[48]; |
284 | |||
236 | //TODO: store just the DER key here, parse/use/delete it when sending client key | 285 | //TODO: store just the DER key here, parse/use/delete it when sending client key |
237 | //this way it will stay key type agnostic here. | 286 | //this way it will stay key type agnostic here. |
238 | psRsaKey_t server_rsa_pub_key; | 287 | psRsaKey_t server_rsa_pub_key; |
288 | uint8_t ecc_pub_key32[32]; | ||
239 | 289 | ||
240 | unsigned saved_client_hello_size; | 290 | /* HANDSHAKE HASH: */ |
241 | uint8_t saved_client_hello[1]; | 291 | //unsigned saved_client_hello_size; |
292 | //uint8_t saved_client_hello[1]; | ||
242 | }; | 293 | }; |
243 | 294 | ||
244 | 295 | ||
@@ -248,6 +299,15 @@ static unsigned get24be(const uint8_t *p) | |||
248 | } | 299 | } |
249 | 300 | ||
250 | #if TLS_DEBUG | 301 | #if TLS_DEBUG |
302 | /* Nondestructively see the current hash value */ | ||
303 | # if TLS_DEBUG_HASH | ||
304 | static unsigned sha_peek(md5sha_ctx_t *ctx, void *buffer) | ||
305 | { | ||
306 | md5sha_ctx_t ctx_copy = *ctx; /* struct copy */ | ||
307 | return sha_end(&ctx_copy, buffer); | ||
308 | } | ||
309 | # endif | ||
310 | |||
251 | static void dump_hex(const char *fmt, const void *vp, int len) | 311 | static void dump_hex(const char *fmt, const void *vp, int len) |
252 | { | 312 | { |
253 | char hexbuf[32 * 1024 + 4]; | 313 | char hexbuf[32 * 1024 + 4]; |
@@ -287,7 +347,7 @@ static void dump_tls_record(const void *vp, int len) | |||
287 | # define dump_tls_record(...) ((void)0) | 347 | # define dump_tls_record(...) ((void)0) |
288 | #endif | 348 | #endif |
289 | 349 | ||
290 | void tls_get_random(void *buf, unsigned len) | 350 | void FAST_FUNC tls_get_random(void *buf, unsigned len) |
291 | { | 351 | { |
292 | #if !ENABLE_PLATFORM_MINGW32 | 352 | #if !ENABLE_PLATFORM_MINGW32 |
293 | if (len != open_read_close("/dev/urandom", buf, len)) | 353 | if (len != open_read_close("/dev/urandom", buf, len)) |
@@ -299,16 +359,32 @@ void tls_get_random(void *buf, unsigned len) | |||
299 | #endif | 359 | #endif |
300 | } | 360 | } |
301 | 361 | ||
302 | /* Nondestructively see the current hash value */ | 362 | static void xorbuf3(void *dst, const void *src1, const void *src2, unsigned count) |
303 | static unsigned sha_peek(md5sha_ctx_t *ctx, void *buffer) | ||
304 | { | 363 | { |
305 | md5sha_ctx_t ctx_copy = *ctx; /* struct copy */ | 364 | uint8_t *d = dst; |
306 | return sha_end(&ctx_copy, buffer); | 365 | const uint8_t *s1 = src1; |
366 | const uint8_t* s2 = src2; | ||
367 | while (count--) | ||
368 | *d++ = *s1++ ^ *s2++; | ||
307 | } | 369 | } |
308 | 370 | ||
309 | static ALWAYS_INLINE unsigned get_handshake_hash(tls_state_t *tls, void *buffer) | 371 | void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count) |
310 | { | 372 | { |
311 | return sha_peek(&tls->hsd->handshake_hash_ctx, buffer); | 373 | xorbuf3(dst, dst, src, count); |
374 | } | ||
375 | |||
376 | void FAST_FUNC xorbuf_aligned_AES_BLOCK_SIZE(void *dst, const void *src) | ||
377 | { | ||
378 | unsigned long *d = dst; | ||
379 | const unsigned long *s = src; | ||
380 | d[0] ^= s[0]; | ||
381 | #if ULONG_MAX <= 0xffffffffffffffff | ||
382 | d[1] ^= s[1]; | ||
383 | #if ULONG_MAX == 0xffffffff | ||
384 | d[2] ^= s[2]; | ||
385 | d[3] ^= s[3]; | ||
386 | #endif | ||
387 | #endif | ||
312 | } | 388 | } |
313 | 389 | ||
314 | #if !TLS_DEBUG_HASH | 390 | #if !TLS_DEBUG_HASH |
@@ -335,7 +411,7 @@ static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer | |||
335 | #endif | 411 | #endif |
336 | } | 412 | } |
337 | 413 | ||
338 | // RFC 2104 | 414 | // RFC 2104: |
339 | // HMAC(key, text) based on a hash H (say, sha256) is: | 415 | // HMAC(key, text) based on a hash H (say, sha256) is: |
340 | // ipad = [0x36 x INSIZE] | 416 | // ipad = [0x36 x INSIZE] |
341 | // opad = [0x5c x INSIZE] | 417 | // opad = [0x5c x INSIZE] |
@@ -350,35 +426,12 @@ typedef struct hmac_precomputed { | |||
350 | md5sha_ctx_t hashed_key_xor_opad; | 426 | md5sha_ctx_t hashed_key_xor_opad; |
351 | } hmac_precomputed_t; | 427 | } hmac_precomputed_t; |
352 | 428 | ||
353 | static unsigned hmac_sha_precomputed_v( | ||
354 | hmac_precomputed_t *pre, | ||
355 | uint8_t *out, | ||
356 | va_list va) | ||
357 | { | ||
358 | uint8_t *text; | ||
359 | unsigned len; | ||
360 | |||
361 | /* pre->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
362 | /* pre->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
363 | |||
364 | /* calculate out = H((key XOR ipad) + text) */ | ||
365 | while ((text = va_arg(va, uint8_t*)) != NULL) { | ||
366 | unsigned text_size = va_arg(va, unsigned); | ||
367 | md5sha_hash(&pre->hashed_key_xor_ipad, text, text_size); | ||
368 | } | ||
369 | len = sha_end(&pre->hashed_key_xor_ipad, out); | ||
370 | |||
371 | /* out = H((key XOR opad) + out) */ | ||
372 | md5sha_hash(&pre->hashed_key_xor_opad, out, len); | ||
373 | return sha_end(&pre->hashed_key_xor_opad, out); | ||
374 | } | ||
375 | |||
376 | typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC; | 429 | typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC; |
377 | static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, md5sha_begin_func *begin) | 430 | static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, md5sha_begin_func *begin) |
378 | { | 431 | { |
379 | uint8_t key_xor_ipad[SHA_INSIZE]; | 432 | uint8_t key_xor_ipad[SHA_INSIZE]; |
380 | uint8_t key_xor_opad[SHA_INSIZE]; | 433 | uint8_t key_xor_opad[SHA_INSIZE]; |
381 | uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE]; | 434 | // uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE]; |
382 | unsigned i; | 435 | unsigned i; |
383 | 436 | ||
384 | // "The authentication key can be of any length up to INSIZE, the | 437 | // "The authentication key can be of any length up to INSIZE, the |
@@ -386,10 +439,18 @@ static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, | |||
386 | // than INSIZE bytes will first hash the key using H and then use the | 439 | // than INSIZE bytes will first hash the key using H and then use the |
387 | // resultant OUTSIZE byte string as the actual key to HMAC." | 440 | // resultant OUTSIZE byte string as the actual key to HMAC." |
388 | if (key_size > SHA_INSIZE) { | 441 | if (key_size > SHA_INSIZE) { |
389 | md5sha_ctx_t ctx; | 442 | bb_error_msg_and_die("HMAC key>64"); //does not happen (yet?) |
390 | begin(&ctx); | 443 | // md5sha_ctx_t ctx; |
391 | md5sha_hash(&ctx, key, key_size); | 444 | // begin(&ctx); |
392 | key_size = sha_end(&ctx, tempkey); | 445 | // md5sha_hash(&ctx, key, key_size); |
446 | // key_size = sha_end(&ctx, tempkey); | ||
447 | // //key = tempkey; - right? RIGHT? why does it work without this? | ||
448 | // // because SHA_INSIZE is 64, but hmac() is always called with | ||
449 | // // key_size = tls->MAC_size = SHA1/256_OUTSIZE (20 or 32), | ||
450 | // // and prf_hmac_sha256() -> hmac_sha256() key sizes are: | ||
451 | // // - RSA_PREMASTER_SIZE is 48 | ||
452 | // // - CURVE25519_KEYSIZE is 32 | ||
453 | // // - master_secret[] is 48 | ||
393 | } | 454 | } |
394 | 455 | ||
395 | for (i = 0; i < key_size; i++) { | 456 | for (i = 0; i < key_size; i++) { |
@@ -407,26 +468,43 @@ static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, | |||
407 | md5sha_hash(&pre->hashed_key_xor_opad, key_xor_opad, SHA_INSIZE); | 468 | md5sha_hash(&pre->hashed_key_xor_opad, key_xor_opad, SHA_INSIZE); |
408 | } | 469 | } |
409 | 470 | ||
410 | static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) | 471 | static unsigned hmac_sha_precomputed_v( |
472 | hmac_precomputed_t *pre, | ||
473 | uint8_t *out, | ||
474 | va_list va) | ||
475 | { | ||
476 | uint8_t *text; | ||
477 | unsigned len; | ||
478 | |||
479 | /* pre->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */ | ||
480 | /* pre->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */ | ||
481 | |||
482 | /* calculate out = H((key XOR ipad) + text) */ | ||
483 | while ((text = va_arg(va, uint8_t*)) != NULL) { | ||
484 | unsigned text_size = va_arg(va, unsigned); | ||
485 | md5sha_hash(&pre->hashed_key_xor_ipad, text, text_size); | ||
486 | } | ||
487 | len = sha_end(&pre->hashed_key_xor_ipad, out); | ||
488 | |||
489 | /* out = H((key XOR opad) + out) */ | ||
490 | md5sha_hash(&pre->hashed_key_xor_opad, out, len); | ||
491 | return sha_end(&pre->hashed_key_xor_opad, out); | ||
492 | } | ||
493 | |||
494 | static unsigned hmac_sha_precomputed(hmac_precomputed_t *pre_init, uint8_t *out, ...) | ||
411 | { | 495 | { |
412 | hmac_precomputed_t pre; | 496 | hmac_precomputed_t pre; |
413 | va_list va; | 497 | va_list va; |
414 | unsigned len; | 498 | unsigned len; |
415 | 499 | ||
416 | va_start(va, key_size); | 500 | va_start(va, out); |
417 | 501 | pre = *pre_init; /* struct copy */ | |
418 | hmac_begin(&pre, key, key_size, | ||
419 | (tls->MAC_size == SHA256_OUTSIZE) | ||
420 | ? sha256_begin | ||
421 | : sha1_begin | ||
422 | ); | ||
423 | len = hmac_sha_precomputed_v(&pre, out, va); | 502 | len = hmac_sha_precomputed_v(&pre, out, va); |
424 | |||
425 | va_end(va); | 503 | va_end(va); |
426 | return len; | 504 | return len; |
427 | } | 505 | } |
428 | 506 | ||
429 | static unsigned hmac_sha256(/*tls_state_t *tls,*/ uint8_t *out, uint8_t *key, unsigned key_size, ...) | 507 | static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...) |
430 | { | 508 | { |
431 | hmac_precomputed_t pre; | 509 | hmac_precomputed_t pre; |
432 | va_list va; | 510 | va_list va; |
@@ -434,7 +512,11 @@ static unsigned hmac_sha256(/*tls_state_t *tls,*/ uint8_t *out, uint8_t *key, un | |||
434 | 512 | ||
435 | va_start(va, key_size); | 513 | va_start(va, key_size); |
436 | 514 | ||
437 | hmac_begin(&pre, key, key_size, sha256_begin); | 515 | hmac_begin(&pre, key, key_size, |
516 | (tls->MAC_size == SHA256_OUTSIZE) | ||
517 | ? sha256_begin | ||
518 | : sha1_begin | ||
519 | ); | ||
438 | len = hmac_sha_precomputed_v(&pre, out, va); | 520 | len = hmac_sha_precomputed_v(&pre, out, va); |
439 | 521 | ||
440 | va_end(va); | 522 | va_end(va); |
@@ -449,8 +531,9 @@ static unsigned hmac_sha256(/*tls_state_t *tls,*/ uint8_t *out, uint8_t *key, un | |||
449 | // document and in TLS documents published prior to this document when | 531 | // document and in TLS documents published prior to this document when |
450 | // TLS 1.2 is negotiated. | 532 | // TLS 1.2 is negotiated. |
451 | // ^^^^^^^^^^^^^ IMPORTANT! | 533 | // ^^^^^^^^^^^^^ IMPORTANT! |
452 | // PRF uses sha256 regardless of cipher (at least for all ciphers | 534 | // PRF uses sha256 regardless of cipher for all ciphers |
453 | // defined by RFC5246). It's not sha1 for AES_128_CBC_SHA! | 535 | // defined by RFC 5246. It's not sha1 for AES_128_CBC_SHA! |
536 | // However, for _SHA384 ciphers, it's sha384. See RFC 5288,5289. | ||
454 | //... | 537 | //... |
455 | // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + | 538 | // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + |
456 | // HMAC_hash(secret, A(2) + seed) + | 539 | // HMAC_hash(secret, A(2) + seed) + |
@@ -472,12 +555,19 @@ static unsigned hmac_sha256(/*tls_state_t *tls,*/ uint8_t *out, uint8_t *key, un | |||
472 | // PRF(secret, label, seed) = P_<hash>(secret, label + seed) | 555 | // PRF(secret, label, seed) = P_<hash>(secret, label + seed) |
473 | // | 556 | // |
474 | // The label is an ASCII string. | 557 | // The label is an ASCII string. |
558 | // | ||
559 | // RFC 5288: | ||
560 | // For cipher suites ending with _SHA256, the PRF is the TLS PRF | ||
561 | // with SHA-256 as the hash function. | ||
562 | // For cipher suites ending with _SHA384, the PRF is the TLS PRF | ||
563 | // with SHA-384 as the hash function. | ||
475 | static void prf_hmac_sha256(/*tls_state_t *tls,*/ | 564 | static void prf_hmac_sha256(/*tls_state_t *tls,*/ |
476 | uint8_t *outbuf, unsigned outbuf_size, | 565 | uint8_t *outbuf, unsigned outbuf_size, |
477 | uint8_t *secret, unsigned secret_size, | 566 | uint8_t *secret, unsigned secret_size, |
478 | const char *label, | 567 | const char *label, |
479 | uint8_t *seed, unsigned seed_size) | 568 | uint8_t *seed, unsigned seed_size) |
480 | { | 569 | { |
570 | hmac_precomputed_t pre; | ||
481 | uint8_t a[TLS_MAX_MAC_SIZE]; | 571 | uint8_t a[TLS_MAX_MAC_SIZE]; |
482 | uint8_t *out_p = outbuf; | 572 | uint8_t *out_p = outbuf; |
483 | unsigned label_size = strlen(label); | 573 | unsigned label_size = strlen(label); |
@@ -485,28 +575,28 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
485 | 575 | ||
486 | /* In P_hash() calculation, "seed" is "label + seed": */ | 576 | /* In P_hash() calculation, "seed" is "label + seed": */ |
487 | #define SEED label, label_size, seed, seed_size | 577 | #define SEED label, label_size, seed, seed_size |
488 | #define SECRET secret, secret_size | ||
489 | #define A a, MAC_size | 578 | #define A a, MAC_size |
490 | 579 | ||
580 | hmac_begin(&pre, secret, secret_size, sha256_begin); | ||
581 | |||
491 | /* A(1) = HMAC_hash(secret, seed) */ | 582 | /* A(1) = HMAC_hash(secret, seed) */ |
492 | hmac_sha256(/*tls,*/ a, SECRET, SEED, NULL); | 583 | hmac_sha_precomputed(&pre, a, SEED, NULL); |
493 | //TODO: convert hmac to precomputed | ||
494 | 584 | ||
495 | for (;;) { | 585 | for (;;) { |
496 | /* HMAC_hash(secret, A(1) + seed) */ | 586 | /* HMAC_hash(secret, A(1) + seed) */ |
497 | if (outbuf_size <= MAC_size) { | 587 | if (outbuf_size <= MAC_size) { |
498 | /* Last, possibly incomplete, block */ | 588 | /* Last, possibly incomplete, block */ |
499 | /* (use a[] as temp buffer) */ | 589 | /* (use a[] as temp buffer) */ |
500 | hmac_sha256(/*tls,*/ a, SECRET, A, SEED, NULL); | 590 | hmac_sha_precomputed(&pre, a, A, SEED, NULL); |
501 | memcpy(out_p, a, outbuf_size); | 591 | memcpy(out_p, a, outbuf_size); |
502 | return; | 592 | return; |
503 | } | 593 | } |
504 | /* Not last block. Store directly to result buffer */ | 594 | /* Not last block. Store directly to result buffer */ |
505 | hmac_sha256(/*tls,*/ out_p, SECRET, A, SEED, NULL); | 595 | hmac_sha_precomputed(&pre, out_p, A, SEED, NULL); |
506 | out_p += MAC_size; | 596 | out_p += MAC_size; |
507 | outbuf_size -= MAC_size; | 597 | outbuf_size -= MAC_size; |
508 | /* A(2) = HMAC_hash(secret, A(1)) */ | 598 | /* A(2) = HMAC_hash(secret, A(1)) */ |
509 | hmac_sha256(/*tls,*/ a, SECRET, A, NULL); | 599 | hmac_sha_precomputed(&pre, a, A, NULL); |
510 | } | 600 | } |
511 | #undef A | 601 | #undef A |
512 | #undef SECRET | 602 | #undef SECRET |
@@ -566,17 +656,24 @@ static void *tls_get_outbuf(tls_state_t *tls, int len) | |||
566 | return tls->outbuf + OUTBUF_PFX; | 656 | return tls->outbuf + OUTBUF_PFX; |
567 | } | 657 | } |
568 | 658 | ||
569 | static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) | 659 | static void *tls_get_zeroed_outbuf(tls_state_t *tls, int len) |
660 | { | ||
661 | void *record = tls_get_outbuf(tls, len); | ||
662 | memset(record, 0, len); | ||
663 | return record; | ||
664 | } | ||
665 | |||
666 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) | ||
570 | { | 667 | { |
571 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; | 668 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; |
572 | struct record_hdr *xhdr; | 669 | struct record_hdr *xhdr; |
573 | uint8_t padding_length; | 670 | uint8_t padding_length; |
574 | 671 | ||
575 | xhdr = (void*)(buf - RECHDR_LEN); | 672 | xhdr = (void*)(buf - RECHDR_LEN); |
576 | if (CIPHER_ID1 != TLS_RSA_WITH_NULL_SHA256 /* if "no encryption" can't be selected */ | 673 | if (!ALLOW_RSA_NULL_SHA256 /* if "no encryption" can't be selected */ |
577 | || tls->cipher_id != TLS_RSA_WITH_NULL_SHA256 /* or if it wasn't selected */ | 674 | || tls->cipher_id != TLS_RSA_WITH_NULL_SHA256 /* or if it wasn't selected */ |
578 | ) { | 675 | ) { |
579 | xhdr = (void*)(buf - RECHDR_LEN - AES_BLOCKSIZE); /* place for IV */ | 676 | xhdr = (void*)(buf - RECHDR_LEN - AES_BLOCK_SIZE); /* place for IV */ |
580 | } | 677 | } |
581 | 678 | ||
582 | xhdr->type = type; | 679 | xhdr->type = type; |
@@ -598,7 +695,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) | |||
598 | 695 | ||
599 | size += tls->MAC_size; | 696 | size += tls->MAC_size; |
600 | 697 | ||
601 | // RFC 5246 | 698 | // RFC 5246: |
602 | // 6.2.3.1. Null or Standard Stream Cipher | 699 | // 6.2.3.1. Null or Standard Stream Cipher |
603 | // | 700 | // |
604 | // Stream ciphers (including BulkCipherAlgorithm.null; see Appendix A.6) | 701 | // Stream ciphers (including BulkCipherAlgorithm.null; see Appendix A.6) |
@@ -631,7 +728,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) | |||
631 | // -------- ----------- ---------- -------------- | 728 | // -------- ----------- ---------- -------------- |
632 | // SHA HMAC-SHA1 20 20 | 729 | // SHA HMAC-SHA1 20 20 |
633 | // SHA256 HMAC-SHA256 32 32 | 730 | // SHA256 HMAC-SHA256 32 32 |
634 | if (CIPHER_ID1 == TLS_RSA_WITH_NULL_SHA256 | 731 | if (ALLOW_RSA_NULL_SHA256 |
635 | && tls->cipher_id == TLS_RSA_WITH_NULL_SHA256 | 732 | && tls->cipher_id == TLS_RSA_WITH_NULL_SHA256 |
636 | ) { | 733 | ) { |
637 | /* No encryption, only signing */ | 734 | /* No encryption, only signing */ |
@@ -679,7 +776,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) | |||
679 | // AES_128_CBC Block 16 16 16 | 776 | // AES_128_CBC Block 16 16 16 |
680 | // AES_256_CBC Block 32 16 16 | 777 | // AES_256_CBC Block 32 16 16 |
681 | 778 | ||
682 | tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */ | 779 | tls_get_random(buf - AES_BLOCK_SIZE, AES_BLOCK_SIZE); /* IV */ |
683 | dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", | 780 | dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", |
684 | size - tls->MAC_size, tls->MAC_size); | 781 | size - tls->MAC_size, tls->MAC_size); |
685 | 782 | ||
@@ -699,23 +796,23 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) | |||
699 | // If you need no bytes to reach BLOCKSIZE, you have to pad a full | 796 | // If you need no bytes to reach BLOCKSIZE, you have to pad a full |
700 | // BLOCKSIZE with bytes of value (BLOCKSIZE-1). | 797 | // BLOCKSIZE with bytes of value (BLOCKSIZE-1). |
701 | // It's ok to have more than minimum padding, but we do minimum. | 798 | // It's ok to have more than minimum padding, but we do minimum. |
702 | padding_length = (~size) & (AES_BLOCKSIZE - 1); | 799 | padding_length = (~size) & (AES_BLOCK_SIZE - 1); |
703 | do { | 800 | do { |
704 | buf[size++] = padding_length; /* padding */ | 801 | buf[size++] = padding_length; /* padding */ |
705 | } while ((size & (AES_BLOCKSIZE - 1)) != 0); | 802 | } while ((size & (AES_BLOCK_SIZE - 1)) != 0); |
706 | 803 | ||
707 | /* Encrypt content+MAC+padding in place */ | 804 | /* Encrypt content+MAC+padding in place */ |
708 | aes_cbc_encrypt( | 805 | aes_cbc_encrypt( |
709 | tls->client_write_key, tls->key_size, /* selects 128/256 */ | 806 | &tls->aes_encrypt, /* selects 128/256 */ |
710 | buf - AES_BLOCKSIZE, /* IV */ | 807 | buf - AES_BLOCK_SIZE, /* IV */ |
711 | buf, size, /* plaintext */ | 808 | buf, size, /* plaintext */ |
712 | buf /* ciphertext */ | 809 | buf /* ciphertext */ |
713 | ); | 810 | ); |
714 | 811 | ||
715 | /* Write out */ | 812 | /* Write out */ |
716 | dbg("writing 5 + %u IV + %u encrypted bytes, padding_length:0x%02x\n", | 813 | dbg("writing 5 + %u IV + %u encrypted bytes, padding_length:0x%02x\n", |
717 | AES_BLOCKSIZE, size, padding_length); | 814 | AES_BLOCK_SIZE, size, padding_length); |
718 | size += AES_BLOCKSIZE; /* + IV */ | 815 | size += AES_BLOCK_SIZE; /* + IV */ |
719 | xhdr->len16_hi = size >> 8; | 816 | xhdr->len16_hi = size >> 8; |
720 | xhdr->len16_lo = size & 0xff; | 817 | xhdr->len16_lo = size & 0xff; |
721 | dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size); | 818 | dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size); |
@@ -723,28 +820,114 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) | |||
723 | dbg("wrote %u bytes\n", (int)RECHDR_LEN + size); | 820 | dbg("wrote %u bytes\n", (int)RECHDR_LEN + size); |
724 | } | 821 | } |
725 | 822 | ||
823 | /* Example how GCM encryption combines nonce, aad, input and generates | ||
824 | * "header | exp_nonce | encrypted output | tag": | ||
825 | * nonce:0d 6a 26 31 00 00 00 00 00 00 00 01 (implicit 4 bytes (derived from master secret), then explicit 8 bytes) | ||
826 | * aad: 00 00 00 00 00 00 00 01 17 03 03 00 1c | ||
827 | * in: 47 45 54 20 2f 69 6e 64 65 78 2e 68 74 6d 6c 20 48 54 54 50 2f 31 2e 30 0d 0a 0d 0a "GET /index.html HTTP/1.0\r\n\r\n" (0x1c bytes) | ||
828 | * out: f7 8a b2 8f 78 0e f6 d5 76 17 2e b5 6d 46 59 56 8b 46 9f 0b d9 2c 35 28 13 66 19 be | ||
829 | * tag: c2 86 ce 4a 50 4a d0 aa 50 b3 76 5c 49 2a 3f 33 | ||
830 | * sent: 17 03 03 00 34|00 00 00 00 00 00 00 01|f7 8a b2 8f 78 0e f6 d5 76 17 2e b5 6d 46 59 56 8b 46 9f 0b d9 2c 35 28 13 66 19 be|c2 86 ce 4a 50 4a d0 aa 50 b3 76 5c 49 2a 3f 33 | ||
831 | * .............................................^^ buf points here | ||
832 | */ | ||
833 | static void xwrite_encrypted_aesgcm(tls_state_t *tls, unsigned size, unsigned type) | ||
834 | { | ||
835 | #define COUNTER(v) (*(uint32_t*)(v + 12)) | ||
836 | |||
837 | uint8_t aad[13 + 3] ALIGNED_long; /* +3 creates [16] buffer, simplifying GHASH() */ | ||
838 | uint8_t nonce[12 + 4] ALIGNED_long; /* +4 creates space for AES block counter */ | ||
839 | uint8_t scratch[AES_BLOCK_SIZE] ALIGNED_long; //[16] | ||
840 | uint8_t authtag[AES_BLOCK_SIZE] ALIGNED_long; //[16] | ||
841 | uint8_t *buf; | ||
842 | struct record_hdr *xhdr; | ||
843 | unsigned remaining; | ||
844 | unsigned cnt; | ||
845 | uint64_t t64; | ||
846 | |||
847 | buf = tls->outbuf + OUTBUF_PFX; /* see above for the byte it points to */ | ||
848 | dump_hex("xwrite_encrypted_aesgcm plaintext:%s\n", buf, size); | ||
849 | |||
850 | xhdr = (void*)(buf - 8 - RECHDR_LEN); | ||
851 | xhdr->type = type; /* do it here so that "type" param no longer used */ | ||
852 | |||
853 | aad[8] = type; | ||
854 | aad[9] = TLS_MAJ; | ||
855 | aad[10] = TLS_MIN; | ||
856 | aad[11] = size >> 8; | ||
857 | /* set aad[12], and clear aad[13..15] */ | ||
858 | COUNTER(aad) = SWAP_LE32(size & 0xff); | ||
859 | |||
860 | memcpy(nonce, tls->client_write_IV, 4); | ||
861 | t64 = tls->write_seq64_be; | ||
862 | move_to_unaligned64(nonce + 4, t64); | ||
863 | move_to_unaligned64(aad, t64); | ||
864 | move_to_unaligned64(buf - 8, t64); | ||
865 | /* seq64 is not used later in this func, can increment here */ | ||
866 | tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(t64)); | ||
867 | |||
868 | cnt = 1; | ||
869 | remaining = size; | ||
870 | while (remaining != 0) { | ||
871 | unsigned n; | ||
872 | |||
873 | cnt++; | ||
874 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ | ||
875 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); | ||
876 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | ||
877 | xorbuf(buf, scratch, n); | ||
878 | buf += n; | ||
879 | remaining -= n; | ||
880 | } | ||
881 | |||
882 | aesgcm_GHASH(tls->H, aad, /*sizeof(aad),*/ tls->outbuf + OUTBUF_PFX, size, authtag /*, sizeof(authtag)*/); | ||
883 | COUNTER(nonce) = htonl(1); | ||
884 | aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); | ||
885 | xorbuf_aligned_AES_BLOCK_SIZE(authtag, scratch); | ||
886 | |||
887 | memcpy(buf, authtag, sizeof(authtag)); | ||
888 | |||
889 | /* Write out */ | ||
890 | xhdr = (void*)(tls->outbuf + OUTBUF_PFX - 8 - RECHDR_LEN); | ||
891 | size += 8 + sizeof(authtag); | ||
892 | /*xhdr->type = type; - already is */ | ||
893 | xhdr->proto_maj = TLS_MAJ; | ||
894 | xhdr->proto_min = TLS_MIN; | ||
895 | xhdr->len16_hi = size >> 8; | ||
896 | xhdr->len16_lo = size & 0xff; | ||
897 | size += RECHDR_LEN; | ||
898 | dump_raw_out(">> %s\n", xhdr, size); | ||
899 | xwrite(tls->ofd, xhdr, size); | ||
900 | dbg("wrote %u bytes\n", size); | ||
901 | #undef COUNTER | ||
902 | } | ||
903 | |||
904 | static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type) | ||
905 | { | ||
906 | if (!(tls->flags & ENCRYPTION_AESGCM)) { | ||
907 | xwrite_encrypted_and_hmac_signed(tls, size, type); | ||
908 | return; | ||
909 | } | ||
910 | xwrite_encrypted_aesgcm(tls, size, type); | ||
911 | } | ||
912 | |||
726 | static void xwrite_handshake_record(tls_state_t *tls, unsigned size) | 913 | static void xwrite_handshake_record(tls_state_t *tls, unsigned size) |
727 | { | 914 | { |
728 | //if (!tls->encrypt_on_write) { | 915 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; |
729 | uint8_t *buf = tls->outbuf + OUTBUF_PFX; | 916 | struct record_hdr *xhdr = (void*)(buf - RECHDR_LEN); |
730 | struct record_hdr *xhdr = (void*)(buf - RECHDR_LEN); | ||
731 | 917 | ||
732 | xhdr->type = RECORD_TYPE_HANDSHAKE; | 918 | xhdr->type = RECORD_TYPE_HANDSHAKE; |
733 | xhdr->proto_maj = TLS_MAJ; | 919 | xhdr->proto_maj = TLS_MAJ; |
734 | xhdr->proto_min = TLS_MIN; | 920 | xhdr->proto_min = TLS_MIN; |
735 | xhdr->len16_hi = size >> 8; | 921 | xhdr->len16_hi = size >> 8; |
736 | xhdr->len16_lo = size & 0xff; | 922 | xhdr->len16_lo = size & 0xff; |
737 | dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size); | 923 | dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size); |
738 | xwrite(tls->ofd, xhdr, RECHDR_LEN + size); | 924 | xwrite(tls->ofd, xhdr, RECHDR_LEN + size); |
739 | dbg("wrote %u bytes\n", (int)RECHDR_LEN + size); | 925 | dbg("wrote %u bytes\n", (int)RECHDR_LEN + size); |
740 | // return; | ||
741 | //} | ||
742 | //xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE); | ||
743 | } | 926 | } |
744 | 927 | ||
745 | static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size) | 928 | static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size) |
746 | { | 929 | { |
747 | if (!tls->encrypt_on_write) { | 930 | if (!(tls->flags & ENCRYPT_ON_WRITE)) { |
748 | uint8_t *buf; | 931 | uint8_t *buf; |
749 | 932 | ||
750 | xwrite_handshake_record(tls, size); | 933 | xwrite_handshake_record(tls, size); |
@@ -783,6 +966,51 @@ static const char *alert_text(int code) | |||
783 | return itoa(code); | 966 | return itoa(code); |
784 | } | 967 | } |
785 | 968 | ||
969 | static void tls_aesgcm_decrypt(tls_state_t *tls, uint8_t *buf, int size) | ||
970 | { | ||
971 | #define COUNTER(v) (*(uint32_t*)(v + 12)) | ||
972 | |||
973 | //uint8_t aad[13 + 3] ALIGNED_long; /* +3 creates [16] buffer, simplifying GHASH() */ | ||
974 | uint8_t nonce[12 + 4] ALIGNED_long; /* +4 creates space for AES block counter */ | ||
975 | uint8_t scratch[AES_BLOCK_SIZE] ALIGNED_long; //[16] | ||
976 | //uint8_t authtag[AES_BLOCK_SIZE] ALIGNED_long; //[16] | ||
977 | unsigned remaining; | ||
978 | unsigned cnt; | ||
979 | |||
980 | //memcpy(aad, buf, 8); | ||
981 | //aad[8] = type; | ||
982 | //aad[9] = TLS_MAJ; | ||
983 | //aad[10] = TLS_MIN; | ||
984 | //aad[11] = size >> 8; | ||
985 | ///* set aad[12], and clear aad[13..15] */ | ||
986 | //COUNTER(aad) = SWAP_LE32(size & 0xff); | ||
987 | |||
988 | memcpy(nonce, tls->server_write_IV, 4); | ||
989 | memcpy(nonce + 4, buf, 8); | ||
990 | |||
991 | cnt = 1; | ||
992 | remaining = size; | ||
993 | while (remaining != 0) { | ||
994 | unsigned n; | ||
995 | |||
996 | cnt++; | ||
997 | COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ | ||
998 | aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); | ||
999 | n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; | ||
1000 | xorbuf3(buf, scratch, buf + 8, n); | ||
1001 | buf += n; | ||
1002 | remaining -= n; | ||
1003 | } | ||
1004 | |||
1005 | //aesgcm_GHASH(tls->H, aad, tls->inbuf + RECHDR_LEN, size, authtag); | ||
1006 | //COUNTER(nonce) = htonl(1); | ||
1007 | //aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); | ||
1008 | //xorbuf_aligned_AES_BLOCK_SIZE(authtag, scratch); | ||
1009 | |||
1010 | //memcmp(buf, authtag, sizeof(authtag)) || DIE("HASH DOES NOT MATCH!"); | ||
1011 | #undef COUNTER | ||
1012 | } | ||
1013 | |||
786 | static int tls_xread_record(tls_state_t *tls, const char *expected) | 1014 | static int tls_xread_record(tls_state_t *tls, const char *expected) |
787 | { | 1015 | { |
788 | struct record_hdr *xhdr; | 1016 | struct record_hdr *xhdr; |
@@ -853,34 +1081,43 @@ static int tls_xread_record(tls_state_t *tls, const char *expected) | |||
853 | sz = target - RECHDR_LEN; | 1081 | sz = target - RECHDR_LEN; |
854 | 1082 | ||
855 | /* Needs to be decrypted? */ | 1083 | /* Needs to be decrypted? */ |
856 | if (tls->min_encrypted_len_on_read > tls->MAC_size) { | 1084 | if (tls->min_encrypted_len_on_read != 0) { |
857 | uint8_t *p = tls->inbuf + RECHDR_LEN; | 1085 | if (sz < (int)tls->min_encrypted_len_on_read) |
858 | int padding_len; | 1086 | bb_error_msg_and_die("bad encrypted len:%u", sz); |
859 | 1087 | ||
860 | if (sz & (AES_BLOCKSIZE-1) | 1088 | if (tls->flags & ENCRYPTION_AESGCM) { |
861 | || sz < (int)tls->min_encrypted_len_on_read | 1089 | /* AESGCM */ |
862 | ) { | 1090 | uint8_t *p = tls->inbuf + RECHDR_LEN; |
863 | bb_error_msg_and_die("bad encrypted len:%u < %u", | 1091 | |
864 | sz, tls->min_encrypted_len_on_read); | 1092 | sz -= 8 + AES_BLOCK_SIZE; /* we will overwrite nonce, drop hash */ |
1093 | tls_aesgcm_decrypt(tls, p, sz); | ||
1094 | dbg("encrypted size:%u\n", sz); | ||
1095 | } else | ||
1096 | if (tls->min_encrypted_len_on_read > tls->MAC_size) { | ||
1097 | /* AES+SHA */ | ||
1098 | uint8_t *p = tls->inbuf + RECHDR_LEN; | ||
1099 | int padding_len; | ||
1100 | |||
1101 | if (sz & (AES_BLOCK_SIZE-1)) | ||
1102 | bb_error_msg_and_die("bad encrypted len:%u", sz); | ||
1103 | |||
1104 | /* Decrypt content+MAC+padding, moving it over IV in the process */ | ||
1105 | sz -= AES_BLOCK_SIZE; /* we will overwrite IV now */ | ||
1106 | aes_cbc_decrypt( | ||
1107 | &tls->aes_decrypt, /* selects 128/256 */ | ||
1108 | p, /* IV */ | ||
1109 | p + AES_BLOCK_SIZE, sz, /* ciphertext */ | ||
1110 | p /* plaintext */ | ||
1111 | ); | ||
1112 | padding_len = p[sz - 1]; | ||
1113 | dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[0], padding_len); | ||
1114 | padding_len++; | ||
1115 | sz -= tls->MAC_size + padding_len; /* drop MAC and padding */ | ||
1116 | } else { | ||
1117 | /* if nonzero, then it's TLS_RSA_WITH_NULL_SHA256: drop MAC */ | ||
1118 | /* else: no encryption yet on input, subtract zero = NOP */ | ||
1119 | sz -= tls->min_encrypted_len_on_read; | ||
865 | } | 1120 | } |
866 | /* Decrypt content+MAC+padding, moving it over IV in the process */ | ||
867 | sz -= AES_BLOCKSIZE; /* we will overwrite IV now */ | ||
868 | aes_cbc_decrypt( | ||
869 | tls->server_write_key, tls->key_size, /* selects 128/256 */ | ||
870 | p, /* IV */ | ||
871 | p + AES_BLOCKSIZE, sz, /* ciphertext */ | ||
872 | p /* plaintext */ | ||
873 | ); | ||
874 | padding_len = p[sz - 1]; | ||
875 | dbg("encrypted size:%u type:0x%02x padding_length:0x%02x\n", sz, p[0], padding_len); | ||
876 | padding_len++; | ||
877 | sz -= tls->MAC_size + padding_len; /* drop MAC and padding */ | ||
878 | //if (sz < 0) | ||
879 | // bb_error_msg_and_die("bad padding size:%u", padding_len); | ||
880 | } else { | ||
881 | /* if nonzero, then it's TLS_RSA_WITH_NULL_SHA256: drop MAC */ | ||
882 | /* else: no encryption yet on input, subtract zero = NOP */ | ||
883 | sz -= tls->min_encrypted_len_on_read; | ||
884 | } | 1121 | } |
885 | if (sz < 0) | 1122 | if (sz < 0) |
886 | bb_error_msg_and_die("encrypted data too short"); | 1123 | bb_error_msg_and_die("encrypted data too short"); |
@@ -921,7 +1158,8 @@ static int tls_xread_record(tls_state_t *tls, const char *expected) | |||
921 | * in our FINISHED record must include data of incoming packets too! | 1158 | * in our FINISHED record must include data of incoming packets too! |
922 | */ | 1159 | */ |
923 | if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE | 1160 | if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE |
924 | && tls->MAC_size != 0 /* do we know which hash to use? (server_hello() does not!) */ | 1161 | /* HANDSHAKE HASH: */ |
1162 | // && do_we_know_which_hash_to_use /* server_hello() might not know it in the future! */ | ||
925 | ) { | 1163 | ) { |
926 | hash_handshake(tls, "<< hash:%s", tls->inbuf + RECHDR_LEN, sz); | 1164 | hash_handshake(tls, "<< hash:%s", tls->inbuf + RECHDR_LEN, sz); |
927 | } | 1165 | } |
@@ -930,6 +1168,13 @@ static int tls_xread_record(tls_state_t *tls, const char *expected) | |||
930 | return sz; | 1168 | return sz; |
931 | } | 1169 | } |
932 | 1170 | ||
1171 | static void binary_to_pstm(pstm_int *pstm_n, uint8_t *bin_ptr, unsigned len) | ||
1172 | { | ||
1173 | pstm_init_for_read_unsigned_bin(/*pool:*/ NULL, pstm_n, len); | ||
1174 | pstm_read_unsigned_bin(pstm_n, bin_ptr, len); | ||
1175 | //return bin_ptr + len; | ||
1176 | } | ||
1177 | |||
933 | /* | 1178 | /* |
934 | * DER parsing routines | 1179 | * DER parsing routines |
935 | */ | 1180 | */ |
@@ -1001,9 +1246,7 @@ static void der_binary_to_pstm(pstm_int *pstm_n, uint8_t *der, uint8_t *end) | |||
1001 | unsigned len = get_der_len(&bin_ptr, der, end); | 1246 | unsigned len = get_der_len(&bin_ptr, der, end); |
1002 | 1247 | ||
1003 | dbg_der("binary bytes:%u, first:0x%02x\n", len, bin_ptr[0]); | 1248 | dbg_der("binary bytes:%u, first:0x%02x\n", len, bin_ptr[0]); |
1004 | pstm_init_for_read_unsigned_bin(/*pool:*/ NULL, pstm_n, len); | 1249 | binary_to_pstm(pstm_n, bin_ptr, len); |
1005 | pstm_read_unsigned_bin(pstm_n, bin_ptr, len); | ||
1006 | //return bin + len; | ||
1007 | } | 1250 | } |
1008 | 1251 | ||
1009 | static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) | 1252 | static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) |
@@ -1086,10 +1329,20 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) | |||
1086 | * publicKey (BIT STRING) | 1329 | * publicKey (BIT STRING) |
1087 | * | 1330 | * |
1088 | * We need Certificate.tbsCertificate.subjectPublicKeyInfo.publicKey | 1331 | * We need Certificate.tbsCertificate.subjectPublicKeyInfo.publicKey |
1332 | * | ||
1333 | * Example of an ECDSA key: | ||
1334 | * SEQ 0x59 bytes (subjectPublicKeyInfo): 3059 | ||
1335 | * SEQ 0x13 bytes (algorithm): 3013 | ||
1336 | * OID 7 bytes: 0607 2a8648ce3d0201 (OID_ECDSA_KEY_ALG 42.134.72.206.61.2.1) | ||
1337 | * OID 8 bytes: 0608 2a8648ce3d030107 (OID_EC_prime256v1 42.134.72.206.61.3.1.7) | ||
1338 | * BITSTRING 0x42 bytes (publicKey): 0342 | ||
1339 | * 0004 53af f65e 50cc 7959 7e29 0171 c75c | ||
1340 | * 7335 e07d f45b 9750 b797 3a38 aebb 2ac6 | ||
1341 | * 8329 2748 e77e 41cb d482 2ce6 05ec a058 | ||
1342 | * f3ab d561 2f4c d845 9ad3 7252 e3de bd3b | ||
1343 | * 9012 | ||
1089 | */ | 1344 | */ |
1090 | uint8_t *end = der + len; | 1345 | uint8_t *end = der + len; |
1091 | uint8_t tag_class, pc, tag_number; | ||
1092 | int version_present; | ||
1093 | 1346 | ||
1094 | /* enter "Certificate" item: [der, end) will be only Cert */ | 1347 | /* enter "Certificate" item: [der, end) will be only Cert */ |
1095 | der = enter_der_item(der, &end); | 1348 | der = enter_der_item(der, &end); |
@@ -1106,13 +1359,11 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) | |||
1106 | * (constructed), and a tag number of 0 (see ITU-T X.690 sections 8.1.2 | 1359 | * (constructed), and a tag number of 0 (see ITU-T X.690 sections 8.1.2 |
1107 | * and 8.14). | 1360 | * and 8.14). |
1108 | */ | 1361 | */ |
1109 | tag_class = der[0] >> 6; /* bits 8-7 */ | 1362 | /* bits 7-6: 10 */ |
1110 | pc = (der[0] & 32) >> 5; /* bit 6 */ | 1363 | /* bit 5: 1 */ |
1111 | tag_number = der[0] & 31; /* bits 5-1 */ | 1364 | /* bits 4-0: 00000 */ |
1112 | version_present = tag_class == 2 && pc == 1 && tag_number == 0; | 1365 | if (der[0] == 0xa0) |
1113 | if (version_present) { | ||
1114 | der = skip_der_item(der, end); /* version */ | 1366 | der = skip_der_item(der, end); /* version */ |
1115 | } | ||
1116 | 1367 | ||
1117 | /* skip up to subjectPublicKeyInfo */ | 1368 | /* skip up to subjectPublicKeyInfo */ |
1118 | der = skip_der_item(der, end); /* serialNumber */ | 1369 | der = skip_der_item(der, end); /* serialNumber */ |
@@ -1124,40 +1375,67 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) | |||
1124 | /* enter subjectPublicKeyInfo */ | 1375 | /* enter subjectPublicKeyInfo */ |
1125 | der = enter_der_item(der, &end); | 1376 | der = enter_der_item(der, &end); |
1126 | { /* check subjectPublicKeyInfo.algorithm */ | 1377 | { /* check subjectPublicKeyInfo.algorithm */ |
1127 | static const uint8_t expected[] = { | 1378 | static const uint8_t OID_RSA_KEY_ALG[] = { |
1128 | 0x30,0x0d, // SEQ 13 bytes | 1379 | 0x30,0x0d, // SEQ 13 bytes |
1129 | 0x06,0x09, 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, // OID RSA_KEY_ALG 42.134.72.134.247.13.1.1.1 | 1380 | 0x06,0x09, 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, //OID_RSA_KEY_ALG 42.134.72.134.247.13.1.1.1 |
1130 | //0x05,0x00, // NULL | 1381 | //0x05,0x00, // NULL |
1131 | }; | 1382 | }; |
1132 | if (memcmp(der, expected, sizeof(expected)) != 0) | 1383 | static const uint8_t OID_ECDSA_KEY_ALG[] = { |
1133 | bb_error_msg_and_die("not RSA key"); | 1384 | 0x30,0x13, // SEQ 0x13 bytes |
1385 | 0x06,0x07, 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01, //OID_ECDSA_KEY_ALG 42.134.72.206.61.2.1 | ||
1386 | //allow any curve code for now... | ||
1387 | // 0x06,0x08, 0x2a,0x86,0x48,0xce,0x3d,0x03,0x01,0x07, //OID_EC_prime256v1 42.134.72.206.61.3.1.7 | ||
1388 | //RFC 3279: | ||
1389 | //42.134.72.206.61.3 is ellipticCurve | ||
1390 | //42.134.72.206.61.3.0 is c-TwoCurve | ||
1391 | //42.134.72.206.61.3.1 is primeCurve | ||
1392 | //42.134.72.206.61.3.1.7 is curve_secp256r1 | ||
1393 | }; | ||
1394 | if (memcmp(der, OID_RSA_KEY_ALG, sizeof(OID_RSA_KEY_ALG)) == 0) { | ||
1395 | dbg("RSA key\n"); | ||
1396 | tls->flags |= GOT_CERT_RSA_KEY_ALG; | ||
1397 | } else | ||
1398 | if (memcmp(der, OID_ECDSA_KEY_ALG, sizeof(OID_ECDSA_KEY_ALG)) == 0) { | ||
1399 | dbg("ECDSA key\n"); | ||
1400 | //UNUSED: tls->flags |= GOT_CERT_ECDSA_KEY_ALG; | ||
1401 | } else | ||
1402 | bb_error_msg_and_die("not RSA or ECDSA cert"); | ||
1134 | } | 1403 | } |
1135 | /* skip subjectPublicKeyInfo.algorithm */ | ||
1136 | der = skip_der_item(der, end); | ||
1137 | /* enter subjectPublicKeyInfo.publicKey */ | ||
1138 | // die_if_not_this_der_type(der, end, 0x03); /* must be BITSTRING */ | ||
1139 | der = enter_der_item(der, &end); | ||
1140 | 1404 | ||
1141 | /* parse RSA key: */ | 1405 | if (tls->flags & GOT_CERT_RSA_KEY_ALG) { |
1142 | //based on getAsnRsaPubKey(), pkcs1ParsePrivBin() is also of note | 1406 | /* parse RSA key: */ |
1143 | dbg("key bytes:%u, first:0x%02x\n", (int)(end - der), der[0]); | 1407 | //based on getAsnRsaPubKey(), pkcs1ParsePrivBin() is also of note |
1144 | if (end - der < 14) xfunc_die(); | 1408 | /* skip subjectPublicKeyInfo.algorithm */ |
1145 | /* example format: | 1409 | der = skip_der_item(der, end); |
1146 | * ignore bits: 00 | 1410 | /* enter subjectPublicKeyInfo.publicKey */ |
1147 | * SEQ 0x018a/394 bytes: 3082018a | 1411 | //die_if_not_this_der_type(der, end, 0x03); /* must be BITSTRING */ |
1148 | * INTEGER 0x0181/385 bytes (modulus): 02820181 XX...XXX | 1412 | der = enter_der_item(der, &end); |
1149 | * INTEGER 3 bytes (exponent): 0203 010001 | 1413 | |
1414 | dbg("key bytes:%u, first:0x%02x\n", (int)(end - der), der[0]); | ||
1415 | if (end - der < 14) | ||
1416 | xfunc_die(); | ||
1417 | /* example format: | ||
1418 | * ignore bits: 00 | ||
1419 | * SEQ 0x018a/394 bytes: 3082018a | ||
1420 | * INTEGER 0x0181/385 bytes (modulus): 02820181 XX...XXX | ||
1421 | * INTEGER 3 bytes (exponent): 0203 010001 | ||
1422 | */ | ||
1423 | if (*der != 0) /* "ignore bits", should be 0 */ | ||
1424 | xfunc_die(); | ||
1425 | der++; | ||
1426 | der = enter_der_item(der, &end); /* enter SEQ */ | ||
1427 | /* memset(tls->hsd->server_rsa_pub_key, 0, sizeof(tls->hsd->server_rsa_pub_key)); - already is */ | ||
1428 | der_binary_to_pstm(&tls->hsd->server_rsa_pub_key.N, der, end); /* modulus */ | ||
1429 | der = skip_der_item(der, end); | ||
1430 | der_binary_to_pstm(&tls->hsd->server_rsa_pub_key.e, der, end); /* exponent */ | ||
1431 | tls->hsd->server_rsa_pub_key.size = pstm_unsigned_bin_size(&tls->hsd->server_rsa_pub_key.N); | ||
1432 | dbg("server_rsa_pub_key.size:%d\n", tls->hsd->server_rsa_pub_key.size); | ||
1433 | } | ||
1434 | /* else: ECDSA key. It is not used for generating encryption keys, | ||
1435 | * it is used only to sign the EC public key (which comes in ServerKey message). | ||
1436 | * Since we do not verify cert validity, verifying signature on EC public key | ||
1437 | * wouldn't add any security. Thus, we do nothing here. | ||
1150 | */ | 1438 | */ |
1151 | if (*der != 0) /* "ignore bits", should be 0 */ | ||
1152 | xfunc_die(); | ||
1153 | der++; | ||
1154 | der = enter_der_item(der, &end); /* enter SEQ */ | ||
1155 | /* memset(tls->hsd->server_rsa_pub_key, 0, sizeof(tls->hsd->server_rsa_pub_key)); - already is */ | ||
1156 | der_binary_to_pstm(&tls->hsd->server_rsa_pub_key.N, der, end); /* modulus */ | ||
1157 | der = skip_der_item(der, end); | ||
1158 | der_binary_to_pstm(&tls->hsd->server_rsa_pub_key.e, der, end); /* exponent */ | ||
1159 | tls->hsd->server_rsa_pub_key.size = pstm_unsigned_bin_size(&tls->hsd->server_rsa_pub_key.N); | ||
1160 | dbg("server_rsa_pub_key.size:%d\n", tls->hsd->server_rsa_pub_key.size); | ||
1161 | } | 1439 | } |
1162 | 1440 | ||
1163 | /* | 1441 | /* |
@@ -1194,6 +1472,56 @@ static ALWAYS_INLINE void fill_handshake_record_hdr(void *buf, unsigned type, un | |||
1194 | 1472 | ||
1195 | static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) | 1473 | static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) |
1196 | { | 1474 | { |
1475 | #define NUM_CIPHERS (13 + ALLOW_RSA_NULL_SHA256) | ||
1476 | static const uint8_t ciphers[] = { | ||
1477 | 0x00,(1 + NUM_CIPHERS) * 2, //len16_be | ||
1478 | 0x00,0xFF, //not a cipher - TLS_EMPTY_RENEGOTIATION_INFO_SCSV | ||
1479 | /* ^^^^^^ RFC 5746 Renegotiation Indication Extension - some servers will refuse to work with us otherwise */ | ||
1480 | 0xC0,0x09, // 1 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - ok: wget https://is.gd/ | ||
1481 | 0xC0,0x0A, // 2 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - ok: wget https://is.gd/ | ||
1482 | 0xC0,0x13, // 3 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA | ||
1483 | 0xC0,0x14, // 4 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES256-SHA (might fail with older openssl) | ||
1484 | 0xC0,0x23, // 5 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - ok: wget https://is.gd/ | ||
1485 | // 0xC0,0x24, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet | ||
1486 | 0xC0,0x27, // 6 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA256 | ||
1487 | // 0xC0,0x28, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet | ||
1488 | 0xC0,0x2B, // 7 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - ok: wget https://is.gd/ | ||
1489 | // 0xC0,0x2C, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - wget https://is.gd/: "TLS error from peer (alert code 20): bad MAC" | ||
1490 | //TODO: GCM_SHA384 ciphers can be supported, only need sha384-based PRF? | ||
1491 | 0xC0,0x2F, // 8 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-GCM-SHA256 | ||
1492 | // 0xC0,0x30, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher ECDHE-RSA-AES256-GCM-SHA384: "decryption failed or bad record mac" | ||
1493 | //possibly these too: | ||
1494 | // 0xC0,0x35, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA | ||
1495 | // 0xC0,0x36, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA | ||
1496 | // 0xC0,0x37, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 | ||
1497 | // 0xC0,0x38, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet | ||
1498 | 0x00,0x2F, // 9 TLS_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher AES128-SHA | ||
1499 | 0x00,0x35, //10 TLS_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher AES256-SHA | ||
1500 | 0x00,0x3C, //11 TLS_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher AES128-SHA256 | ||
1501 | 0x00,0x3D, //12 TLS_RSA_WITH_AES_256_CBC_SHA256 - ok: openssl s_server ... -cipher AES256-SHA256 | ||
1502 | 0x00,0x9C, //13 TLS_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher AES128-GCM-SHA256 | ||
1503 | // 0x00,0x9D, // TLS_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher AES256-GCM-SHA384: "decryption failed or bad record mac" | ||
1504 | #if ALLOW_RSA_NULL_SHA256 | ||
1505 | 0x00,0x3B, // TLS_RSA_WITH_NULL_SHA256 | ||
1506 | #endif | ||
1507 | 0x01,0x00, //not a cipher - comprtypes_len, comprtype | ||
1508 | }; | ||
1509 | static const uint8_t supported_groups[] = { | ||
1510 | 0x00,0x0a, //extension_type: "supported_groups" | ||
1511 | 0x00,0x04, //ext len | ||
1512 | 0x00,0x02, //list len | ||
1513 | 0x00,0x1d, //curve_x25519 (RFC 7748) | ||
1514 | //0x00,0x17, //curve_secp256r1 | ||
1515 | //0x00,0x18, //curve_secp384r1 | ||
1516 | //0x00,0x19, //curve_secp521r1 | ||
1517 | }; | ||
1518 | //static const uint8_t signature_algorithms[] = { | ||
1519 | // 000d | ||
1520 | // 0020 | ||
1521 | // 001e | ||
1522 | // 0601 0602 0603 0501 0502 0503 0401 0402 0403 0301 0302 0303 0201 0202 0203 | ||
1523 | //}; | ||
1524 | |||
1197 | struct client_hello { | 1525 | struct client_hello { |
1198 | uint8_t type; | 1526 | uint8_t type; |
1199 | uint8_t len24_hi, len24_mid, len24_lo; | 1527 | uint8_t len24_hi, len24_mid, len24_lo; |
@@ -1202,7 +1530,7 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) | |||
1202 | uint8_t session_id_len; | 1530 | uint8_t session_id_len; |
1203 | /* uint8_t session_id[]; */ | 1531 | /* uint8_t session_id[]; */ |
1204 | uint8_t cipherid_len16_hi, cipherid_len16_lo; | 1532 | uint8_t cipherid_len16_hi, cipherid_len16_lo; |
1205 | uint8_t cipherid[2 * (2 + !!CIPHER_ID2)]; /* actually variable */ | 1533 | uint8_t cipherid[(1 + NUM_CIPHERS) * 2]; /* actually variable */ |
1206 | uint8_t comprtypes_len; | 1534 | uint8_t comprtypes_len; |
1207 | uint8_t comprtypes[1]; /* actually variable */ | 1535 | uint8_t comprtypes[1]; /* actually variable */ |
1208 | /* Extensions (SNI shown): | 1536 | /* Extensions (SNI shown): |
@@ -1227,14 +1555,20 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) | |||
1227 | // 0017 0000 - extended master secret | 1555 | // 0017 0000 - extended master secret |
1228 | }; | 1556 | }; |
1229 | struct client_hello *record; | 1557 | struct client_hello *record; |
1558 | uint8_t *ptr; | ||
1230 | int len; | 1559 | int len; |
1231 | int sni_len = sni ? strnlen(sni, 127 - 9) : 0; | 1560 | int ext_len; |
1561 | int sni_len = sni ? strnlen(sni, 127 - 5) : 0; | ||
1232 | 1562 | ||
1233 | len = sizeof(*record); | 1563 | ext_len = 0; |
1564 | /* is.gd responds with "handshake failure" to our hello if there's no supported_groups element */ | ||
1565 | ext_len += sizeof(supported_groups); | ||
1234 | if (sni_len) | 1566 | if (sni_len) |
1235 | len += 11 + sni_len; | 1567 | ext_len += 9 + sni_len; |
1236 | record = tls_get_outbuf(tls, len); | 1568 | |
1237 | memset(record, 0, len); | 1569 | /* +2 is for "len of all extensions" 2-byte field */ |
1570 | len = sizeof(*record) + 2 + ext_len; | ||
1571 | record = tls_get_zeroed_outbuf(tls, len); | ||
1238 | 1572 | ||
1239 | fill_handshake_record_hdr(record, HANDSHAKE_CLIENT_HELLO, len); | 1573 | fill_handshake_record_hdr(record, HANDSHAKE_CLIENT_HELLO, len); |
1240 | record->proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */ | 1574 | record->proto_maj = TLS_MAJ; /* the "requested" version of the protocol, */ |
@@ -1244,46 +1578,43 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni) | |||
1244 | memset(record->rand32, 0x11, sizeof(record->rand32)); | 1578 | memset(record->rand32, 0x11, sizeof(record->rand32)); |
1245 | /* record->session_id_len = 0; - already is */ | 1579 | /* record->session_id_len = 0; - already is */ |
1246 | 1580 | ||
1247 | /* record->cipherid_len16_hi = 0; */ | 1581 | BUILD_BUG_ON(sizeof(ciphers) != 2 + (1 + NUM_CIPHERS) * 2 + 2); |
1248 | record->cipherid_len16_lo = sizeof(record->cipherid); | 1582 | memcpy(&record->cipherid_len16_hi, ciphers, sizeof(ciphers)); |
1249 | /* RFC 5746 Renegotiation Indication Extension - some servers will refuse to work with us otherwise */ | ||
1250 | /*record->cipherid[0] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV >> 8; - zero */ | ||
1251 | record->cipherid[1] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV & 0xff; | ||
1252 | if ((CIPHER_ID1 >> 8) != 0) record->cipherid[2] = CIPHER_ID1 >> 8; | ||
1253 | /*************************/ record->cipherid[3] = CIPHER_ID1 & 0xff; | ||
1254 | #if CIPHER_ID2 | ||
1255 | if ((CIPHER_ID2 >> 8) != 0) record->cipherid[4] = CIPHER_ID2 >> 8; | ||
1256 | /*************************/ record->cipherid[5] = CIPHER_ID2 & 0xff; | ||
1257 | #endif | ||
1258 | |||
1259 | record->comprtypes_len = 1; | ||
1260 | /* record->comprtypes[0] = 0; */ | ||
1261 | 1583 | ||
1584 | ptr = (void*)(record + 1); | ||
1585 | *ptr++ = ext_len >> 8; | ||
1586 | *ptr++ = ext_len; | ||
1262 | if (sni_len) { | 1587 | if (sni_len) { |
1263 | uint8_t *p = (void*)(record + 1); | 1588 | //ptr[0] = 0; // |
1264 | //p[0] = 0; // | 1589 | //ptr[1] = 0; //extension_type |
1265 | p[1] = sni_len + 9; //ext_len | 1590 | //ptr[2] = 0; // |
1266 | //p[2] = 0; // | 1591 | ptr[3] = sni_len + 5; //list len |
1267 | //p[3] = 0; //extension_type | 1592 | //ptr[4] = 0; // |
1268 | //p[4] = 0; // | 1593 | ptr[5] = sni_len + 3; //len of 1st SNI |
1269 | p[5] = sni_len + 5; //list len | 1594 | //ptr[6] = 0; //name type |
1270 | //p[6] = 0; // | 1595 | //ptr[7] = 0; // |
1271 | p[7] = sni_len + 3; //len of 1st SNI | 1596 | ptr[8] = sni_len; //name len |
1272 | //p[8] = 0; //name type | 1597 | ptr = mempcpy(&ptr[9], sni, sni_len); |
1273 | //p[9] = 0; // | ||
1274 | p[10] = sni_len; //name len | ||
1275 | memcpy(&p[11], sni, sni_len); | ||
1276 | } | 1598 | } |
1599 | memcpy(ptr, supported_groups, sizeof(supported_groups)); | ||
1277 | 1600 | ||
1278 | dbg(">> CLIENT_HELLO\n"); | 1601 | tls->hsd = xzalloc(sizeof(*tls->hsd)); |
1279 | /* Can hash it only when we know which MAC hash to use */ | 1602 | /* HANDSHAKE HASH: ^^^ + len if need to save saved_client_hello */ |
1280 | /*xwrite_and_update_handshake_hash(tls, len); - WRONG! */ | 1603 | memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32)); |
1281 | xwrite_handshake_record(tls, len); | 1604 | /* HANDSHAKE HASH: |
1282 | |||
1283 | tls->hsd = xzalloc(sizeof(*tls->hsd) + len); | ||
1284 | tls->hsd->saved_client_hello_size = len; | 1605 | tls->hsd->saved_client_hello_size = len; |
1285 | memcpy(tls->hsd->saved_client_hello, record, len); | 1606 | memcpy(tls->hsd->saved_client_hello, record, len); |
1286 | memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32)); | 1607 | */ |
1608 | dbg(">> CLIENT_HELLO\n"); | ||
1609 | /* Can hash immediately only if we know which MAC hash to use. | ||
1610 | * So far we do know: it's sha256: | ||
1611 | */ | ||
1612 | sha256_begin(&tls->hsd->handshake_hash_ctx); | ||
1613 | xwrite_and_update_handshake_hash(tls, len); | ||
1614 | /* if this would become infeasible: save tls->hsd->saved_client_hello, | ||
1615 | * use "xwrite_handshake_record(tls, len)" here, | ||
1616 | * and hash saved_client_hello later. | ||
1617 | */ | ||
1287 | } | 1618 | } |
1288 | 1619 | ||
1289 | static void get_server_hello(tls_state_t *tls) | 1620 | static void get_server_hello(tls_state_t *tls) |
@@ -1303,7 +1634,7 @@ static void get_server_hello(tls_state_t *tls) | |||
1303 | 1634 | ||
1304 | struct server_hello *hp; | 1635 | struct server_hello *hp; |
1305 | uint8_t *cipherid; | 1636 | uint8_t *cipherid; |
1306 | unsigned cipher; | 1637 | uint8_t cipherid1; |
1307 | int len, len24; | 1638 | int len, len24; |
1308 | 1639 | ||
1309 | len = tls_xread_handshake_block(tls, 74 - 32); | 1640 | len = tls_xread_handshake_block(tls, 74 - 32); |
@@ -1336,33 +1667,87 @@ static void get_server_hello(tls_state_t *tls) | |||
1336 | len24 += 32; /* what len would be if session id would be present */ | 1667 | len24 += 32; /* what len would be if session id would be present */ |
1337 | } | 1668 | } |
1338 | 1669 | ||
1339 | if (len24 < 70 | 1670 | if (len24 < 70) |
1340 | // || cipherid[0] != (CIPHER_ID >> 8) | ||
1341 | // || cipherid[1] != (CIPHER_ID & 0xff) | ||
1342 | // || cipherid[2] != 0 /* comprtype */ | ||
1343 | ) { | ||
1344 | bad_record_die(tls, "'server hello'", len); | 1671 | bad_record_die(tls, "'server hello'", len); |
1345 | } | ||
1346 | dbg("<< SERVER_HELLO\n"); | 1672 | dbg("<< SERVER_HELLO\n"); |
1347 | 1673 | ||
1348 | memcpy(tls->hsd->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32)); | 1674 | memcpy(tls->hsd->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32)); |
1349 | 1675 | ||
1350 | tls->cipher_id = cipher = 0x100 * cipherid[0] + cipherid[1]; | 1676 | /* Set up encryption params based on selected cipher */ |
1351 | dbg("server chose cipher %04x\n", cipher); | 1677 | #if 0 |
1352 | 1678 | 0xC0,0x09, // 1 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - ok: wget https://is.gd/ | |
1353 | if (cipher == TLS_RSA_WITH_AES_128_CBC_SHA) { | 1679 | 0xC0,0x0A, // 2 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - ok: wget https://is.gd/ |
1354 | tls->key_size = AES128_KEYSIZE; | 1680 | 0xC0,0x13, // 3 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA |
1355 | tls->MAC_size = SHA1_OUTSIZE; | 1681 | 0xC0,0x14, // 4 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher ECDHE-RSA-AES256-SHA (might fail with older openssl) |
1356 | } | 1682 | 0xC0,0x23, // 5 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - ok: wget https://is.gd/ |
1357 | else { /* TLS_RSA_WITH_AES_256_CBC_SHA256 */ | 1683 | // 0xC0,0x24, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet |
1358 | tls->key_size = AES256_KEYSIZE; | 1684 | 0xC0,0x27, // 6 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-SHA256 |
1359 | tls->MAC_size = SHA256_OUTSIZE; | 1685 | // 0xC0,0x28, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet |
1686 | 0xC0,0x2B, // 7 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - ok: wget https://is.gd/ | ||
1687 | // 0xC0,0x2C, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - wget https://is.gd/: "TLS error from peer (alert code 20): bad MAC" | ||
1688 | 0xC0,0x2F, // 8 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher ECDHE-RSA-AES128-GCM-SHA256 | ||
1689 | // 0xC0,0x30, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher ECDHE-RSA-AES256-GCM-SHA384: "decryption failed or bad record mac" | ||
1690 | //possibly these too: | ||
1691 | // 0xC0,0x35, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA | ||
1692 | // 0xC0,0x36, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA | ||
1693 | // 0xC0,0x37, // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 | ||
1694 | // 0xC0,0x38, // TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 - can't do SHA384 yet | ||
1695 | 0x00,0x2F, // 9 TLS_RSA_WITH_AES_128_CBC_SHA - ok: openssl s_server ... -cipher AES128-SHA | ||
1696 | 0x00,0x35, //10 TLS_RSA_WITH_AES_256_CBC_SHA - ok: openssl s_server ... -cipher AES256-SHA | ||
1697 | 0x00,0x3C, //11 TLS_RSA_WITH_AES_128_CBC_SHA256 - ok: openssl s_server ... -cipher AES128-SHA256 | ||
1698 | 0x00,0x3D, //12 TLS_RSA_WITH_AES_256_CBC_SHA256 - ok: openssl s_server ... -cipher AES256-SHA256 | ||
1699 | 0x00,0x9C, //13 TLS_RSA_WITH_AES_128_GCM_SHA256 - ok: openssl s_server ... -cipher AES128-GCM-SHA256 | ||
1700 | // 0x00,0x9D, // TLS_RSA_WITH_AES_256_GCM_SHA384 - openssl s_server ... -cipher AES256-GCM-SHA384: "decryption failed or bad record mac" | ||
1701 | 0x00,0x3B, // TLS_RSA_WITH_NULL_SHA256 | ||
1702 | #endif | ||
1703 | cipherid1 = cipherid[1]; | ||
1704 | tls->cipher_id = 0x100 * cipherid[0] + cipherid1; | ||
1705 | tls->key_size = AES256_KEYSIZE; | ||
1706 | tls->MAC_size = SHA256_OUTSIZE; | ||
1707 | /*tls->IV_size = 0; - already is */ | ||
1708 | if (cipherid[0] == 0xC0) { | ||
1709 | /* All C0xx are ECDHE */ | ||
1710 | tls->flags |= NEED_EC_KEY; | ||
1711 | if (cipherid1 & 1) { | ||
1712 | /* Odd numbered C0xx use AES128 (even ones use AES256) */ | ||
1713 | tls->key_size = AES128_KEYSIZE; | ||
1714 | } | ||
1715 | if (cipherid1 <= 0x14) { | ||
1716 | tls->MAC_size = SHA1_OUTSIZE; | ||
1717 | } else | ||
1718 | if (cipherid1 >= 0x2B && cipherid1 <= 0x30) { | ||
1719 | /* C02B,2C,2F,30 are AES-GCM */ | ||
1720 | tls->flags |= ENCRYPTION_AESGCM; | ||
1721 | tls->MAC_size = 0; | ||
1722 | tls->IV_size = 4; | ||
1723 | } | ||
1724 | } else { | ||
1725 | /* All 00xx are RSA */ | ||
1726 | if (cipherid1 == 0x2F | ||
1727 | || cipherid1 == 0x3C | ||
1728 | || cipherid1 == 0x9C | ||
1729 | ) { | ||
1730 | tls->key_size = AES128_KEYSIZE; | ||
1731 | } | ||
1732 | if (cipherid1 <= 0x35) { | ||
1733 | tls->MAC_size = SHA1_OUTSIZE; | ||
1734 | } else | ||
1735 | if (cipherid1 == 0x9C /*|| cipherid1 == 0x9D*/) { | ||
1736 | /* 009C,9D are AES-GCM */ | ||
1737 | tls->flags |= ENCRYPTION_AESGCM; | ||
1738 | tls->MAC_size = 0; | ||
1739 | tls->IV_size = 4; | ||
1740 | } | ||
1360 | } | 1741 | } |
1742 | dbg("server chose cipher %04x\n", tls->cipher_id); | ||
1743 | dbg("key_size:%u MAC_size:%u IV_size:%u\n", tls->key_size, tls->MAC_size, tls->IV_size); | ||
1744 | |||
1361 | /* Handshake hash eventually destined to FINISHED record | 1745 | /* Handshake hash eventually destined to FINISHED record |
1362 | * is sha256 regardless of cipher | 1746 | * is sha256 regardless of cipher |
1363 | * (at least for all ciphers defined by RFC5246). | 1747 | * (at least for all ciphers defined by RFC5246). |
1364 | * It's not sha1 for AES_128_CBC_SHA - only MAC is sha1, not this hash. | 1748 | * It's not sha1 for AES_128_CBC_SHA - only MAC is sha1, not this hash. |
1365 | */ | 1749 | */ |
1750 | /* HANDSHAKE HASH: | ||
1366 | sha256_begin(&tls->hsd->handshake_hash_ctx); | 1751 | sha256_begin(&tls->hsd->handshake_hash_ctx); |
1367 | hash_handshake(tls, ">> client hello hash:%s", | 1752 | hash_handshake(tls, ">> client hello hash:%s", |
1368 | tls->hsd->saved_client_hello, tls->hsd->saved_client_hello_size | 1753 | tls->hsd->saved_client_hello, tls->hsd->saved_client_hello_size |
@@ -1370,6 +1755,7 @@ static void get_server_hello(tls_state_t *tls) | |||
1370 | hash_handshake(tls, "<< server hello hash:%s", | 1755 | hash_handshake(tls, "<< server hello hash:%s", |
1371 | tls->inbuf + RECHDR_LEN, len | 1756 | tls->inbuf + RECHDR_LEN, len |
1372 | ); | 1757 | ); |
1758 | */ | ||
1373 | } | 1759 | } |
1374 | 1760 | ||
1375 | static void get_server_cert(tls_state_t *tls) | 1761 | static void get_server_cert(tls_state_t *tls) |
@@ -1402,6 +1788,68 @@ static void get_server_cert(tls_state_t *tls) | |||
1402 | find_key_in_der_cert(tls, certbuf + 10, len); | 1788 | find_key_in_der_cert(tls, certbuf + 10, len); |
1403 | } | 1789 | } |
1404 | 1790 | ||
1791 | /* On input, len is known to be >= 4. | ||
1792 | * The record is known to be SERVER_KEY_EXCHANGE. | ||
1793 | */ | ||
1794 | static void process_server_key(tls_state_t *tls, int len) | ||
1795 | { | ||
1796 | struct record_hdr *xhdr; | ||
1797 | uint8_t *keybuf; | ||
1798 | int len1; | ||
1799 | uint32_t t32; | ||
1800 | |||
1801 | xhdr = (void*)tls->inbuf; | ||
1802 | keybuf = (void*)(xhdr + 1); | ||
1803 | //seen from is.gd: it selects curve_x25519: | ||
1804 | // 0c 00006e //SERVER_KEY_EXCHANGE, len | ||
1805 | // 03 //curve_type: named curve | ||
1806 | // 001d //curve_x25519 | ||
1807 | //server-chosen EC point, and then signed_params | ||
1808 | // (RFC 8422: "A hash of the params, with the signature | ||
1809 | // appropriate to that hash applied. The private key corresponding | ||
1810 | // to the certified public key in the server's Certificate message is | ||
1811 | // used for signing.") | ||
1812 | //follow. Format unclear/guessed: | ||
1813 | // 20 //eccPubKeyLen | ||
1814 | // 25511923d73b70dd2f60e66ba2f3fda31a9c25170963c7a3a972e481dbb2835d //eccPubKey (32bytes) | ||
1815 | // 0203 //hashSigAlg: 2:SHA1 (4:SHA256 5:SHA384 6:SHA512), 3:ECDSA (1:RSA) | ||
1816 | // 0046 //len (16bit) | ||
1817 | // 30 44 //SEQ, len | ||
1818 | // 02 20 //INTEGER, len | ||
1819 | // 2e18e7c2a9badd0a70cd3059a6ab114539b9f5163568911147386cd77ed7c412 //32bytes | ||
1820 | //this item ^^^^^ is sometimes 33 bytes (with all container sizes also +1) | ||
1821 | // 02 20 //INTEGER, len | ||
1822 | // 64523d6216cb94c43c9b20e377d8c52c55be6703fd6730a155930c705eaf3af6 //32bytes | ||
1823 | //same about this item ^^^^^ | ||
1824 | |||
1825 | //seen from ftp.openbsd.org | ||
1826 | //(which only accepts ECDHE-RSA-AESnnn-GCM-SHAnnn and ECDHE-RSA-CHACHA20-POLY1305 ciphers): | ||
1827 | // 0c 000228 //SERVER_KEY_EXCHANGE, len | ||
1828 | // 03 //curve_type: named curve | ||
1829 | // 001d //curve_x25519 | ||
1830 | // 20 //eccPubKeyLen | ||
1831 | // eef7a15c43b71a4c7eaa48a39369399cc4332e569ec90a83274cc92596705c1a //eccPubKey | ||
1832 | // 0401 //hashSigAlg: 4:SHA256, 1:RSA | ||
1833 | // 0200 //len | ||
1834 | // //0x200 bytes follow | ||
1835 | |||
1836 | /* Get and verify length */ | ||
1837 | len1 = get24be(keybuf + 1); | ||
1838 | if (len1 > len - 4) tls_error_die(tls); | ||
1839 | len = len1; | ||
1840 | if (len < (1+2+1+32)) tls_error_die(tls); | ||
1841 | keybuf += 4; | ||
1842 | |||
1843 | /* So far we only support curve_x25519 */ | ||
1844 | move_from_unaligned32(t32, keybuf); | ||
1845 | if (t32 != htonl(0x03001d20)) | ||
1846 | bb_error_msg_and_die("elliptic curve is not x25519"); | ||
1847 | |||
1848 | memcpy(tls->hsd->ecc_pub_key32, keybuf + 4, 32); | ||
1849 | tls->flags |= GOT_EC_KEY; | ||
1850 | dbg("got eccPubKey\n"); | ||
1851 | } | ||
1852 | |||
1405 | static void send_empty_client_cert(tls_state_t *tls) | 1853 | static void send_empty_client_cert(tls_state_t *tls) |
1406 | { | 1854 | { |
1407 | struct client_empty_cert { | 1855 | struct client_empty_cert { |
@@ -1411,12 +1859,14 @@ static void send_empty_client_cert(tls_state_t *tls) | |||
1411 | }; | 1859 | }; |
1412 | struct client_empty_cert *record; | 1860 | struct client_empty_cert *record; |
1413 | 1861 | ||
1414 | record = tls_get_outbuf(tls, sizeof(*record)); | 1862 | record = tls_get_zeroed_outbuf(tls, sizeof(*record)); |
1415 | //FIXME: can just memcpy a ready-made one. | 1863 | //fill_handshake_record_hdr(record, HANDSHAKE_CERTIFICATE, sizeof(*record)); |
1416 | fill_handshake_record_hdr(record, HANDSHAKE_CERTIFICATE, sizeof(*record)); | 1864 | //record->cert_chain_len24_hi = 0; |
1417 | record->cert_chain_len24_hi = 0; | 1865 | //record->cert_chain_len24_mid = 0; |
1418 | record->cert_chain_len24_mid = 0; | 1866 | //record->cert_chain_len24_lo = 0; |
1419 | record->cert_chain_len24_lo = 0; | 1867 | // same as above: |
1868 | record->type = HANDSHAKE_CERTIFICATE; | ||
1869 | record->len24_lo = 3; | ||
1420 | 1870 | ||
1421 | dbg(">> CERTIFICATE\n"); | 1871 | dbg(">> CERTIFICATE\n"); |
1422 | xwrite_and_update_handshake_hash(tls, sizeof(*record)); | 1872 | xwrite_and_update_handshake_hash(tls, sizeof(*record)); |
@@ -1427,36 +1877,72 @@ static void send_client_key_exchange(tls_state_t *tls) | |||
1427 | struct client_key_exchange { | 1877 | struct client_key_exchange { |
1428 | uint8_t type; | 1878 | uint8_t type; |
1429 | uint8_t len24_hi, len24_mid, len24_lo; | 1879 | uint8_t len24_hi, len24_mid, len24_lo; |
1430 | /* keylen16 exists for RSA (in TLS, not in SSL), but not for some other key types */ | 1880 | uint8_t key[2 + 4 * 1024]; // size?? |
1431 | uint8_t keylen16_hi, keylen16_lo; | ||
1432 | uint8_t key[4 * 1024]; // size?? | ||
1433 | }; | 1881 | }; |
1434 | //FIXME: better size estimate | 1882 | //FIXME: better size estimate |
1435 | struct client_key_exchange *record = tls_get_outbuf(tls, sizeof(*record)); | 1883 | struct client_key_exchange *record = tls_get_zeroed_outbuf(tls, sizeof(*record)); |
1436 | uint8_t rsa_premaster[RSA_PREMASTER_SIZE]; | 1884 | uint8_t rsa_premaster[RSA_PREMASTER_SIZE]; |
1885 | uint8_t x25519_premaster[CURVE25519_KEYSIZE]; | ||
1886 | uint8_t *premaster; | ||
1887 | int premaster_size; | ||
1437 | int len; | 1888 | int len; |
1438 | 1889 | ||
1439 | tls_get_random(rsa_premaster, sizeof(rsa_premaster)); | 1890 | if (!(tls->flags & NEED_EC_KEY)) { |
1440 | if (TLS_DEBUG_FIXED_SECRETS) | 1891 | /* RSA */ |
1441 | memset(rsa_premaster, 0x44, sizeof(rsa_premaster)); | 1892 | if (!(tls->flags & GOT_CERT_RSA_KEY_ALG)) |
1442 | // RFC 5246 | 1893 | bb_error_msg("server cert is not RSA"); |
1443 | // "Note: The version number in the PreMasterSecret is the version | 1894 | |
1444 | // offered by the client in the ClientHello.client_version, not the | 1895 | tls_get_random(rsa_premaster, sizeof(rsa_premaster)); |
1445 | // version negotiated for the connection." | 1896 | if (TLS_DEBUG_FIXED_SECRETS) |
1446 | rsa_premaster[0] = TLS_MAJ; | 1897 | memset(rsa_premaster, 0x44, sizeof(rsa_premaster)); |
1447 | rsa_premaster[1] = TLS_MIN; | 1898 | // RFC 5246 |
1448 | dump_hex("premaster:%s\n", rsa_premaster, sizeof(rsa_premaster)); | 1899 | // "Note: The version number in the PreMasterSecret is the version |
1449 | len = psRsaEncryptPub(/*pool:*/ NULL, | 1900 | // offered by the client in the ClientHello.client_version, not the |
1450 | /* psRsaKey_t* */ &tls->hsd->server_rsa_pub_key, | 1901 | // version negotiated for the connection." |
1451 | rsa_premaster, /*inlen:*/ sizeof(rsa_premaster), | 1902 | rsa_premaster[0] = TLS_MAJ; |
1452 | record->key, sizeof(record->key), | 1903 | rsa_premaster[1] = TLS_MIN; |
1453 | data_param_ignored | 1904 | dump_hex("premaster:%s\n", rsa_premaster, sizeof(rsa_premaster)); |
1454 | ); | 1905 | len = psRsaEncryptPub(/*pool:*/ NULL, |
1455 | record->keylen16_hi = len >> 8; | 1906 | /* psRsaKey_t* */ &tls->hsd->server_rsa_pub_key, |
1456 | record->keylen16_lo = len & 0xff; | 1907 | rsa_premaster, /*inlen:*/ sizeof(rsa_premaster), |
1457 | len += 2; | 1908 | record->key + 2, sizeof(record->key) - 2, |
1909 | data_param_ignored | ||
1910 | ); | ||
1911 | /* keylen16 exists for RSA (in TLS, not in SSL), but not for some other key types */ | ||
1912 | record->key[0] = len >> 8; | ||
1913 | record->key[1] = len & 0xff; | ||
1914 | len += 2; | ||
1915 | premaster = rsa_premaster; | ||
1916 | premaster_size = sizeof(rsa_premaster); | ||
1917 | } else { | ||
1918 | /* ECDHE */ | ||
1919 | static const uint8_t basepoint9[CURVE25519_KEYSIZE] = {9}; | ||
1920 | uint8_t privkey[CURVE25519_KEYSIZE]; //[32] | ||
1921 | |||
1922 | if (!(tls->flags & GOT_EC_KEY)) | ||
1923 | bb_error_msg("server did not provide EC key"); | ||
1924 | |||
1925 | /* Generate random private key, see RFC 7748 */ | ||
1926 | tls_get_random(privkey, sizeof(privkey)); | ||
1927 | privkey[0] &= 0xf8; | ||
1928 | privkey[CURVE25519_KEYSIZE-1] = ((privkey[CURVE25519_KEYSIZE-1] & 0x7f) | 0x40); | ||
1929 | |||
1930 | /* Compute public key */ | ||
1931 | curve25519(record->key + 1, privkey, basepoint9); | ||
1932 | |||
1933 | /* Compute premaster using peer's public key */ | ||
1934 | dbg("computing x25519_premaster\n"); | ||
1935 | curve25519(x25519_premaster, privkey, tls->hsd->ecc_pub_key32); | ||
1936 | |||
1937 | len = CURVE25519_KEYSIZE; | ||
1938 | record->key[0] = len; | ||
1939 | len++; | ||
1940 | premaster = x25519_premaster; | ||
1941 | premaster_size = sizeof(x25519_premaster); | ||
1942 | } | ||
1943 | |||
1458 | record->type = HANDSHAKE_CLIENT_KEY_EXCHANGE; | 1944 | record->type = HANDSHAKE_CLIENT_KEY_EXCHANGE; |
1459 | record->len24_hi = 0; | 1945 | /* record->len24_hi = 0; - already is */ |
1460 | record->len24_mid = len >> 8; | 1946 | record->len24_mid = len >> 8; |
1461 | record->len24_lo = len & 0xff; | 1947 | record->len24_lo = len & 0xff; |
1462 | len += 4; | 1948 | len += 4; |
@@ -1476,7 +1962,7 @@ static void send_client_key_exchange(tls_state_t *tls) | |||
1476 | // of the premaster secret will vary depending on key exchange method. | 1962 | // of the premaster secret will vary depending on key exchange method. |
1477 | prf_hmac_sha256(/*tls,*/ | 1963 | prf_hmac_sha256(/*tls,*/ |
1478 | tls->hsd->master_secret, sizeof(tls->hsd->master_secret), | 1964 | tls->hsd->master_secret, sizeof(tls->hsd->master_secret), |
1479 | rsa_premaster, sizeof(rsa_premaster), | 1965 | premaster, premaster_size, |
1480 | "master secret", | 1966 | "master secret", |
1481 | tls->hsd->client_and_server_rand32, sizeof(tls->hsd->client_and_server_rand32) | 1967 | tls->hsd->client_and_server_rand32, sizeof(tls->hsd->client_and_server_rand32) |
1482 | ); | 1968 | ); |
@@ -1523,23 +2009,38 @@ static void send_client_key_exchange(tls_state_t *tls) | |||
1523 | memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32); | 2009 | memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32); |
1524 | 2010 | ||
1525 | prf_hmac_sha256(/*tls,*/ | 2011 | prf_hmac_sha256(/*tls,*/ |
1526 | tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size), | 2012 | tls->client_write_MAC_key, 2 * (tls->MAC_size + tls->key_size + tls->IV_size), |
1527 | // also fills: | 2013 | // also fills: |
1528 | // server_write_MAC_key[] | 2014 | // server_write_MAC_key[] |
1529 | // client_write_key[] | 2015 | // client_write_key[] |
1530 | // server_write_key[] | 2016 | // server_write_key[] |
2017 | // client_write_IV[] | ||
2018 | // server_write_IV[] | ||
1531 | tls->hsd->master_secret, sizeof(tls->hsd->master_secret), | 2019 | tls->hsd->master_secret, sizeof(tls->hsd->master_secret), |
1532 | "key expansion", | 2020 | "key expansion", |
1533 | tmp64, 64 | 2021 | tmp64, 64 |
1534 | ); | 2022 | ); |
1535 | tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size); | 2023 | tls->client_write_key = tls->client_write_MAC_key + (2 * tls->MAC_size); |
1536 | tls->server_write_key = tls->client_write_key + tls->key_size; | 2024 | tls->server_write_key = tls->client_write_key + tls->key_size; |
2025 | tls->client_write_IV = tls->server_write_key + tls->key_size; | ||
2026 | tls->server_write_IV = tls->client_write_IV + tls->IV_size; | ||
1537 | dump_hex("client_write_MAC_key:%s\n", | 2027 | dump_hex("client_write_MAC_key:%s\n", |
1538 | tls->client_write_MAC_key, tls->MAC_size | 2028 | tls->client_write_MAC_key, tls->MAC_size |
1539 | ); | 2029 | ); |
1540 | dump_hex("client_write_key:%s\n", | 2030 | dump_hex("client_write_key:%s\n", |
1541 | tls->client_write_key, tls->key_size | 2031 | tls->client_write_key, tls->key_size |
1542 | ); | 2032 | ); |
2033 | dump_hex("client_write_IV:%s\n", | ||
2034 | tls->client_write_IV, tls->IV_size | ||
2035 | ); | ||
2036 | |||
2037 | aes_setkey(&tls->aes_decrypt, tls->server_write_key, tls->key_size); | ||
2038 | aes_setkey(&tls->aes_encrypt, tls->client_write_key, tls->key_size); | ||
2039 | { | ||
2040 | uint8_t iv[AES_BLOCK_SIZE]; | ||
2041 | memset(iv, 0, AES_BLOCK_SIZE); | ||
2042 | aes_encrypt_one_block(&tls->aes_encrypt, iv, tls->H); | ||
2043 | } | ||
1543 | } | 2044 | } |
1544 | } | 2045 | } |
1545 | 2046 | ||
@@ -1604,7 +2105,8 @@ static void send_client_finished(tls_state_t *tls) | |||
1604 | 2105 | ||
1605 | fill_handshake_record_hdr(record, HANDSHAKE_FINISHED, sizeof(*record)); | 2106 | fill_handshake_record_hdr(record, HANDSHAKE_FINISHED, sizeof(*record)); |
1606 | 2107 | ||
1607 | len = get_handshake_hash(tls, handshake_hash); | 2108 | len = sha_end(&tls->hsd->handshake_hash_ctx, handshake_hash); |
2109 | |||
1608 | prf_hmac_sha256(/*tls,*/ | 2110 | prf_hmac_sha256(/*tls,*/ |
1609 | record->prf_result, sizeof(record->prf_result), | 2111 | record->prf_result, sizeof(record->prf_result), |
1610 | tls->hsd->master_secret, sizeof(tls->hsd->master_secret), | 2112 | tls->hsd->master_secret, sizeof(tls->hsd->master_secret), |
@@ -1663,8 +2165,19 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni) | |||
1663 | //SvKey len=455^ | 2165 | //SvKey len=455^ |
1664 | // with TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: 461 bytes: | 2166 | // with TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: 461 bytes: |
1665 | // 0c 00|01|c9 03|00|17|41|04|cd|9b|b4|29|1f|f6|b0|c2|84|82|7f|29|6a|47|4e|ec|87|0b|c1|9c|69|e1|f8|c6|d0|53|e9|27|90|a5|c8|02|15|75... | 2167 | // 0c 00|01|c9 03|00|17|41|04|cd|9b|b4|29|1f|f6|b0|c2|84|82|7f|29|6a|47|4e|ec|87|0b|c1|9c|69|e1|f8|c6|d0|53|e9|27|90|a5|c8|02|15|75... |
2168 | // | ||
2169 | // RFC 8422 5.4. Server Key Exchange | ||
2170 | // This message is sent when using the ECDHE_ECDSA, ECDHE_RSA, and | ||
2171 | // ECDH_anon key exchange algorithms. | ||
2172 | // This message is used to convey the server's ephemeral ECDH public key | ||
2173 | // (and the corresponding elliptic curve domain parameters) to the | ||
2174 | // client. | ||
1666 | dbg("<< SERVER_KEY_EXCHANGE len:%u\n", len); | 2175 | dbg("<< SERVER_KEY_EXCHANGE len:%u\n", len); |
1667 | //probably need to save it | 2176 | dump_raw_in("<< %s\n", tls->inbuf, RECHDR_LEN + len); |
2177 | if (tls->flags & NEED_EC_KEY) | ||
2178 | process_server_key(tls, len); | ||
2179 | |||
2180 | // read next handshake block | ||
1668 | len = tls_xread_handshake_block(tls, 4); | 2181 | len = tls_xread_handshake_block(tls, 4); |
1669 | } | 2182 | } |
1670 | 2183 | ||
@@ -1698,7 +2211,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni) | |||
1698 | send_change_cipher_spec(tls); | 2211 | send_change_cipher_spec(tls); |
1699 | /* from now on we should send encrypted */ | 2212 | /* from now on we should send encrypted */ |
1700 | /* tls->write_seq64_be = 0; - already is */ | 2213 | /* tls->write_seq64_be = 0; - already is */ |
1701 | tls->encrypt_on_write = 1; | 2214 | tls->flags |= ENCRYPT_ON_WRITE; |
1702 | 2215 | ||
1703 | send_client_finished(tls); | 2216 | send_client_finished(tls); |
1704 | 2217 | ||
@@ -1707,18 +2220,22 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni) | |||
1707 | if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) | 2220 | if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) |
1708 | bad_record_die(tls, "switch to encrypted traffic", len); | 2221 | bad_record_die(tls, "switch to encrypted traffic", len); |
1709 | dbg("<< CHANGE_CIPHER_SPEC\n"); | 2222 | dbg("<< CHANGE_CIPHER_SPEC\n"); |
1710 | if (CIPHER_ID1 == TLS_RSA_WITH_NULL_SHA256 | 2223 | |
2224 | if (ALLOW_RSA_NULL_SHA256 | ||
1711 | && tls->cipher_id == TLS_RSA_WITH_NULL_SHA256 | 2225 | && tls->cipher_id == TLS_RSA_WITH_NULL_SHA256 |
1712 | ) { | 2226 | ) { |
1713 | tls->min_encrypted_len_on_read = tls->MAC_size; | 2227 | tls->min_encrypted_len_on_read = tls->MAC_size; |
1714 | } else { | 2228 | } else |
1715 | unsigned mac_blocks = (unsigned)(tls->MAC_size + AES_BLOCKSIZE-1) / AES_BLOCKSIZE; | 2229 | if (!(tls->flags & ENCRYPTION_AESGCM)) { |
2230 | unsigned mac_blocks = (unsigned)(tls->MAC_size + AES_BLOCK_SIZE-1) / AES_BLOCK_SIZE; | ||
1716 | /* all incoming packets now should be encrypted and have | 2231 | /* all incoming packets now should be encrypted and have |
1717 | * at least IV + (MAC padded to blocksize): | 2232 | * at least IV + (MAC padded to blocksize): |
1718 | */ | 2233 | */ |
1719 | tls->min_encrypted_len_on_read = AES_BLOCKSIZE + (mac_blocks * AES_BLOCKSIZE); | 2234 | tls->min_encrypted_len_on_read = AES_BLOCK_SIZE + (mac_blocks * AES_BLOCK_SIZE); |
1720 | dbg("min_encrypted_len_on_read: %u", tls->min_encrypted_len_on_read); | 2235 | } else { |
2236 | tls->min_encrypted_len_on_read = 8 + AES_BLOCK_SIZE; | ||
1721 | } | 2237 | } |
2238 | dbg("min_encrypted_len_on_read: %u\n", tls->min_encrypted_len_on_read); | ||
1722 | 2239 | ||
1723 | /* Get (encrypted) FINISHED from the server */ | 2240 | /* Get (encrypted) FINISHED from the server */ |
1724 | len = tls_xread_record(tls, "'server finished'"); | 2241 | len = tls_xread_record(tls, "'server finished'"); |
@@ -1728,6 +2245,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni) | |||
1728 | /* application data can be sent/received */ | 2245 | /* application data can be sent/received */ |
1729 | 2246 | ||
1730 | /* free handshake data */ | 2247 | /* free handshake data */ |
2248 | psRsaKey_clear(&tls->hsd->server_rsa_pub_key); | ||
1731 | // if (PARANOIA) | 2249 | // if (PARANOIA) |
1732 | // memset(tls->hsd, 0, tls->hsd->hsd_size); | 2250 | // memset(tls->hsd, 0, tls->hsd->hsd_size); |
1733 | free(tls->hsd); | 2251 | free(tls->hsd); |
@@ -1742,12 +2260,12 @@ static void tls_xwrite(tls_state_t *tls, int len) | |||
1742 | 2260 | ||
1743 | // To run a test server using openssl: | 2261 | // To run a test server using openssl: |
1744 | // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' | 2262 | // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' |
1745 | // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 | 2263 | // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 |
1746 | // | 2264 | // |
1747 | // Unencryped SHA256 example: | 2265 | // Unencryped SHA256 example: |
1748 | // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' | 2266 | // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost' |
1749 | // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL | 2267 | // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -cipher NULL |
1750 | // openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256 | 2268 | // openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -cipher NULL-SHA256 |
1751 | 2269 | ||
1752 | void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags) | 2270 | void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags) |
1753 | { | 2271 | { |
diff --git a/networking/tls.h b/networking/tls.h index d487f3810..494ed78c4 100644 --- a/networking/tls.h +++ b/networking/tls.h | |||
@@ -78,7 +78,14 @@ typedef int16_t int16; | |||
78 | #define PUBKEY_TYPE 0x01 | 78 | #define PUBKEY_TYPE 0x01 |
79 | #define PRIVKEY_TYPE 0x02 | 79 | #define PRIVKEY_TYPE 0x02 |
80 | 80 | ||
81 | void tls_get_random(void *buf, unsigned len); | 81 | #define AES_BLOCK_SIZE 16 |
82 | |||
83 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; | ||
84 | |||
85 | void xorbuf(void* buf, const void* mask, unsigned count) FAST_FUNC; | ||
86 | |||
87 | #define ALIGNED_long ALIGNED(sizeof(long)) | ||
88 | void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; | ||
82 | 89 | ||
83 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) | 90 | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) |
84 | 91 | ||
@@ -94,6 +101,8 @@ void tls_get_random(void *buf, unsigned len); | |||
94 | 101 | ||
95 | 102 | ||
96 | #include "tls_pstm.h" | 103 | #include "tls_pstm.h" |
97 | #include "tls_rsa.h" | ||
98 | #include "tls_symmetric.h" | 104 | #include "tls_symmetric.h" |
99 | #include "tls_aes.h" | 105 | #include "tls_aes.h" |
106 | #include "tls_aesgcm.h" | ||
107 | #include "tls_rsa.h" | ||
108 | #include "tls_fe.h" | ||
diff --git a/networking/tls_aes.c b/networking/tls_aes.c index c137442e9..cf6b5fe3d 100644 --- a/networking/tls_aes.c +++ b/networking/tls_aes.c | |||
@@ -326,8 +326,11 @@ static void InvMixColumns(unsigned astate[16]) | |||
326 | } | 326 | } |
327 | } | 327 | } |
328 | 328 | ||
329 | static void aes_encrypt_1(unsigned astate[16], unsigned rounds, const uint32_t *RoundKey) | 329 | static void aes_encrypt_1(struct tls_aes *aes, unsigned astate[16]) |
330 | { | 330 | { |
331 | unsigned rounds = aes->rounds; | ||
332 | const uint32_t *RoundKey = aes->key; | ||
333 | |||
331 | for (;;) { | 334 | for (;;) { |
332 | AddRoundKey(astate, RoundKey); | 335 | AddRoundKey(astate, RoundKey); |
333 | RoundKey += 4; | 336 | RoundKey += 4; |
@@ -340,8 +343,12 @@ static void aes_encrypt_1(unsigned astate[16], unsigned rounds, const uint32_t * | |||
340 | AddRoundKey(astate, RoundKey); | 343 | AddRoundKey(astate, RoundKey); |
341 | } | 344 | } |
342 | 345 | ||
343 | #if 0 // UNUSED | 346 | void FAST_FUNC aes_setkey(struct tls_aes *aes, const void *key, unsigned key_len) |
344 | static void aes_encrypt_one_block(unsigned rounds, const uint32_t *RoundKey, const void *data, void *dst) | 347 | { |
348 | aes->rounds = KeyExpansion(aes->key, key, key_len); | ||
349 | } | ||
350 | |||
351 | void FAST_FUNC aes_encrypt_one_block(struct tls_aes *aes, const void *data, void *dst) | ||
345 | { | 352 | { |
346 | unsigned astate[16]; | 353 | unsigned astate[16]; |
347 | unsigned i; | 354 | unsigned i; |
@@ -351,23 +358,19 @@ static void aes_encrypt_one_block(unsigned rounds, const uint32_t *RoundKey, con | |||
351 | 358 | ||
352 | for (i = 0; i < 16; i++) | 359 | for (i = 0; i < 16; i++) |
353 | astate[i] = pt[i]; | 360 | astate[i] = pt[i]; |
354 | aes_encrypt_1(astate, rounds, RoundKey); | 361 | aes_encrypt_1(aes, astate); |
355 | for (i = 0; i < 16; i++) | 362 | for (i = 0; i < 16; i++) |
356 | ct[i] = astate[i]; | 363 | ct[i] = astate[i]; |
357 | } | 364 | } |
358 | #endif | ||
359 | 365 | ||
360 | void aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst) | 366 | void FAST_FUNC aes_cbc_encrypt(struct tls_aes *aes, void *iv, const void *data, size_t len, void *dst) |
361 | { | 367 | { |
362 | uint32_t RoundKey[60]; | ||
363 | uint8_t iv2[16]; | 368 | uint8_t iv2[16]; |
364 | unsigned rounds; | ||
365 | 369 | ||
366 | const uint8_t *pt = data; | 370 | const uint8_t *pt = data; |
367 | uint8_t *ct = dst; | 371 | uint8_t *ct = dst; |
368 | 372 | ||
369 | memcpy(iv2, iv, 16); | 373 | memcpy(iv2, iv, 16); |
370 | rounds = KeyExpansion(RoundKey, key, klen); | ||
371 | while (len > 0) { | 374 | while (len > 0) { |
372 | { | 375 | { |
373 | /* almost aes_encrypt_one_block(rounds, RoundKey, pt, ct); | 376 | /* almost aes_encrypt_one_block(rounds, RoundKey, pt, ct); |
@@ -378,7 +381,7 @@ void aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size | |||
378 | unsigned astate[16]; | 381 | unsigned astate[16]; |
379 | for (i = 0; i < 16; i++) | 382 | for (i = 0; i < 16; i++) |
380 | astate[i] = pt[i] ^ iv2[i]; | 383 | astate[i] = pt[i] ^ iv2[i]; |
381 | aes_encrypt_1(astate, rounds, RoundKey); | 384 | aes_encrypt_1(aes, astate); |
382 | for (i = 0; i < 16; i++) | 385 | for (i = 0; i < 16; i++) |
383 | iv2[i] = ct[i] = astate[i]; | 386 | iv2[i] = ct[i] = astate[i]; |
384 | } | 387 | } |
@@ -388,8 +391,11 @@ void aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size | |||
388 | } | 391 | } |
389 | } | 392 | } |
390 | 393 | ||
391 | static void aes_decrypt_1(unsigned astate[16], unsigned rounds, const uint32_t *RoundKey) | 394 | static void aes_decrypt_1(struct tls_aes *aes, unsigned astate[16]) |
392 | { | 395 | { |
396 | unsigned rounds = aes->rounds; | ||
397 | const uint32_t *RoundKey = aes->key; | ||
398 | |||
393 | RoundKey += rounds * 4; | 399 | RoundKey += rounds * 4; |
394 | AddRoundKey(astate, RoundKey); | 400 | AddRoundKey(astate, RoundKey); |
395 | for (;;) { | 401 | for (;;) { |
@@ -404,8 +410,10 @@ static void aes_decrypt_1(unsigned astate[16], unsigned rounds, const uint32_t * | |||
404 | } | 410 | } |
405 | 411 | ||
406 | #if 0 //UNUSED | 412 | #if 0 //UNUSED |
407 | static void aes_decrypt_one_block(unsigned rounds, const uint32_t *RoundKey, const void *data, void *dst) | 413 | static void aes_decrypt_one_block(struct tls_aes *aes, const void *data, void *dst) |
408 | { | 414 | { |
415 | unsigned rounds = aes->rounds; | ||
416 | const uint32_t *RoundKey = aes->key; | ||
409 | unsigned astate[16]; | 417 | unsigned astate[16]; |
410 | unsigned i; | 418 | unsigned i; |
411 | 419 | ||
@@ -414,25 +422,22 @@ static void aes_decrypt_one_block(unsigned rounds, const uint32_t *RoundKey, con | |||
414 | 422 | ||
415 | for (i = 0; i < 16; i++) | 423 | for (i = 0; i < 16; i++) |
416 | astate[i] = ct[i]; | 424 | astate[i] = ct[i]; |
417 | aes_decrypt_1(astate, rounds, RoundKey); | 425 | aes_decrypt_1(aes, astate); |
418 | for (i = 0; i < 16; i++) | 426 | for (i = 0; i < 16; i++) |
419 | pt[i] = astate[i]; | 427 | pt[i] = astate[i]; |
420 | } | 428 | } |
421 | #endif | 429 | #endif |
422 | 430 | ||
423 | void aes_cbc_decrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst) | 431 | void FAST_FUNC aes_cbc_decrypt(struct tls_aes *aes, void *iv, const void *data, size_t len, void *dst) |
424 | { | 432 | { |
425 | uint32_t RoundKey[60]; | ||
426 | uint8_t iv2[16]; | 433 | uint8_t iv2[16]; |
427 | uint8_t iv3[16]; | 434 | uint8_t iv3[16]; |
428 | unsigned rounds; | ||
429 | uint8_t *ivbuf; | 435 | uint8_t *ivbuf; |
430 | uint8_t *ivnext; | 436 | uint8_t *ivnext; |
431 | 437 | ||
432 | const uint8_t *ct = data; | 438 | const uint8_t *ct = data; |
433 | uint8_t *pt = dst; | 439 | uint8_t *pt = dst; |
434 | 440 | ||
435 | rounds = KeyExpansion(RoundKey, key, klen); | ||
436 | ivbuf = memcpy(iv2, iv, 16); | 441 | ivbuf = memcpy(iv2, iv, 16); |
437 | while (len) { | 442 | while (len) { |
438 | ivnext = (ivbuf==iv2) ? iv3 : iv2; | 443 | ivnext = (ivbuf==iv2) ? iv3 : iv2; |
@@ -444,7 +449,7 @@ void aes_cbc_decrypt(const void *key, int klen, void *iv, const void *data, size | |||
444 | unsigned astate[16]; | 449 | unsigned astate[16]; |
445 | for (i = 0; i < 16; i++) | 450 | for (i = 0; i < 16; i++) |
446 | ivnext[i] = astate[i] = ct[i]; | 451 | ivnext[i] = astate[i] = ct[i]; |
447 | aes_decrypt_1(astate, rounds, RoundKey); | 452 | aes_decrypt_1(aes, astate); |
448 | for (i = 0; i < 16; i++) | 453 | for (i = 0; i < 16; i++) |
449 | pt[i] = astate[i] ^ ivbuf[i]; | 454 | pt[i] = astate[i] ^ ivbuf[i]; |
450 | } | 455 | } |
diff --git a/networking/tls_aes.h b/networking/tls_aes.h index c6791866a..e9e3721f1 100644 --- a/networking/tls_aes.h +++ b/networking/tls_aes.h | |||
@@ -6,5 +6,9 @@ | |||
6 | * Selected few declarations for AES. | 6 | * Selected few declarations for AES. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | void aes_cbc_encrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst); | 9 | void aes_setkey(struct tls_aes *aes, const void *key, unsigned key_len) FAST_FUNC; |
10 | void aes_cbc_decrypt(const void *key, int klen, void *iv, const void *data, size_t len, void *dst); | 10 | |
11 | void aes_encrypt_one_block(struct tls_aes *aes, const void *data, void *dst) FAST_FUNC; | ||
12 | |||
13 | void aes_cbc_encrypt(struct tls_aes *aes, void *iv, const void *data, size_t len, void *dst) FAST_FUNC; | ||
14 | void aes_cbc_decrypt(struct tls_aes *aes, void *iv, const void *data, size_t len, void *dst) FAST_FUNC; | ||
diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c new file mode 100644 index 000000000..688df85fb --- /dev/null +++ b/networking/tls_aesgcm.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | |||
7 | #include "tls.h" | ||
8 | |||
9 | typedef uint8_t byte; | ||
10 | typedef uint32_t word32; | ||
11 | #define XMEMSET memset | ||
12 | #define XMEMCPY memcpy | ||
13 | |||
14 | /* from wolfssl-3.15.3/wolfcrypt/src/aes.c */ | ||
15 | |||
16 | static ALWAYS_INLINE void FlattenSzInBits(byte* buf, word32 sz) | ||
17 | { | ||
18 | /* Multiply the sz by 8 */ | ||
19 | //bbox: these sizes are never even close to 2^32/8 | ||
20 | // word32 szHi = (sz >> (8*sizeof(sz) - 3)); | ||
21 | sz <<= 3; | ||
22 | |||
23 | /* copy over the words of the sz into the destination buffer */ | ||
24 | // buf[0] = (szHi >> 24) & 0xff; | ||
25 | // buf[1] = (szHi >> 16) & 0xff; | ||
26 | // buf[2] = (szHi >> 8) & 0xff; | ||
27 | // buf[3] = szHi & 0xff; | ||
28 | *(uint32_t*)(buf + 0) = 0; | ||
29 | // buf[4] = (sz >> 24) & 0xff; | ||
30 | // buf[5] = (sz >> 16) & 0xff; | ||
31 | // buf[6] = (sz >> 8) & 0xff; | ||
32 | // buf[7] = sz & 0xff; | ||
33 | *(uint32_t*)(buf + 4) = SWAP_BE32(sz); | ||
34 | } | ||
35 | |||
36 | static void RIGHTSHIFTX(byte* x) | ||
37 | { | ||
38 | int i; | ||
39 | int carryOut = 0; | ||
40 | int carryIn = 0; | ||
41 | int borrow = x[15] & 0x01; | ||
42 | |||
43 | for (i = 0; i < AES_BLOCK_SIZE; i++) { | ||
44 | carryOut = x[i] & 0x01; | ||
45 | x[i] = (x[i] >> 1) | (carryIn ? 0x80 : 0); | ||
46 | carryIn = carryOut; | ||
47 | } | ||
48 | if (borrow) x[0] ^= 0xE1; | ||
49 | } | ||
50 | |||
51 | static void GMULT(byte* X, byte* Y) | ||
52 | { | ||
53 | byte Z[AES_BLOCK_SIZE] ALIGNED_long; | ||
54 | byte V[AES_BLOCK_SIZE] ALIGNED_long; | ||
55 | int i, j; | ||
56 | |||
57 | XMEMSET(Z, 0, AES_BLOCK_SIZE); | ||
58 | XMEMCPY(V, X, AES_BLOCK_SIZE); | ||
59 | for (i = 0; i < AES_BLOCK_SIZE; i++) | ||
60 | { | ||
61 | byte y = Y[i]; | ||
62 | for (j = 0; j < 8; j++) | ||
63 | { | ||
64 | if (y & 0x80) { | ||
65 | xorbuf_aligned_AES_BLOCK_SIZE(Z, V); | ||
66 | } | ||
67 | |||
68 | RIGHTSHIFTX(V); | ||
69 | y = y << 1; | ||
70 | } | ||
71 | } | ||
72 | XMEMCPY(X, Z, AES_BLOCK_SIZE); | ||
73 | } | ||
74 | |||
75 | //bbox: | ||
76 | // for TLS AES-GCM, a (which is AAD) is always 13 bytes long, and bbox code provides | ||
77 | // extra 3 zeroed bytes, making it a[16], or a[AES_BLOCK_SIZE]. | ||
78 | // Resulting auth tag in s[] is also always AES_BLOCK_SIZE bytes. | ||
79 | // | ||
80 | // This allows some simplifications. | ||
81 | #define aSz 13 | ||
82 | #define sSz AES_BLOCK_SIZE | ||
83 | void FAST_FUNC aesgcm_GHASH(byte* h, | ||
84 | const byte* a, //unsigned aSz, | ||
85 | const byte* c, unsigned cSz, | ||
86 | byte* s //, unsigned sSz | ||
87 | ) | ||
88 | { | ||
89 | byte x[AES_BLOCK_SIZE] ALIGNED_long; | ||
90 | // byte scratch[AES_BLOCK_SIZE] ALIGNED_long; | ||
91 | unsigned blocks, partial; | ||
92 | //was: byte* h = aes->H; | ||
93 | |||
94 | //XMEMSET(x, 0, AES_BLOCK_SIZE); | ||
95 | |||
96 | /* Hash in A, the Additional Authentication Data */ | ||
97 | // if (aSz != 0 && a != NULL) { | ||
98 | // blocks = aSz / AES_BLOCK_SIZE; | ||
99 | // partial = aSz % AES_BLOCK_SIZE; | ||
100 | // while (blocks--) { | ||
101 | //xorbuf(x, a, AES_BLOCK_SIZE); | ||
102 | XMEMCPY(x, a, AES_BLOCK_SIZE);// memcpy(x,a) = memset(x,0)+xorbuf(x,a) | ||
103 | GMULT(x, h); | ||
104 | // a += AES_BLOCK_SIZE; | ||
105 | // } | ||
106 | // if (partial != 0) { | ||
107 | // XMEMSET(scratch, 0, AES_BLOCK_SIZE); | ||
108 | // XMEMCPY(scratch, a, partial); | ||
109 | // xorbuf(x, scratch, AES_BLOCK_SIZE); | ||
110 | // GMULT(x, h); | ||
111 | // } | ||
112 | // } | ||
113 | |||
114 | /* Hash in C, the Ciphertext */ | ||
115 | if (cSz != 0 /*&& c != NULL*/) { | ||
116 | blocks = cSz / AES_BLOCK_SIZE; | ||
117 | partial = cSz % AES_BLOCK_SIZE; | ||
118 | while (blocks--) { | ||
119 | if (BB_UNALIGNED_MEMACCESS_OK) // c is not guaranteed to be aligned | ||
120 | xorbuf_aligned_AES_BLOCK_SIZE(x, c); | ||
121 | else | ||
122 | xorbuf(x, c, AES_BLOCK_SIZE); | ||
123 | GMULT(x, h); | ||
124 | c += AES_BLOCK_SIZE; | ||
125 | } | ||
126 | if (partial != 0) { | ||
127 | //XMEMSET(scratch, 0, AES_BLOCK_SIZE); | ||
128 | //XMEMCPY(scratch, c, partial); | ||
129 | //xorbuf(x, scratch, AES_BLOCK_SIZE); | ||
130 | xorbuf(x, c, partial);//same result as above | ||
131 | GMULT(x, h); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | /* Hash in the lengths of A and C in bits */ | ||
136 | //FlattenSzInBits(&scratch[0], aSz); | ||
137 | //FlattenSzInBits(&scratch[8], cSz); | ||
138 | //xorbuf_aligned_AES_BLOCK_SIZE(x, scratch); | ||
139 | // simpler: | ||
140 | #define P32(v) ((uint32_t*)v) | ||
141 | //P32(x)[0] ^= 0; | ||
142 | P32(x)[1] ^= SWAP_BE32(aSz * 8); | ||
143 | //P32(x)[2] ^= 0; | ||
144 | P32(x)[3] ^= SWAP_BE32(cSz * 8); | ||
145 | #undef P32 | ||
146 | |||
147 | GMULT(x, h); | ||
148 | |||
149 | /* Copy the result into s. */ | ||
150 | XMEMCPY(s, x, sSz); | ||
151 | } | ||
diff --git a/networking/tls_aesgcm.h b/networking/tls_aesgcm.h new file mode 100644 index 000000000..d7e672e6e --- /dev/null +++ b/networking/tls_aesgcm.h | |||
@@ -0,0 +1,11 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | |||
7 | void aesgcm_GHASH(uint8_t* h, | ||
8 | const uint8_t* a, //unsigned aSz, | ||
9 | const uint8_t* c, unsigned cSz, | ||
10 | uint8_t* s //, unsigned sSz | ||
11 | ) FAST_FUNC; | ||
diff --git a/networking/tls_fe.c b/networking/tls_fe.c new file mode 100644 index 000000000..f235082f5 --- /dev/null +++ b/networking/tls_fe.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | #include "tls.h" | ||
7 | |||
8 | typedef uint8_t byte; | ||
9 | typedef uint16_t word16; | ||
10 | typedef uint32_t word32; | ||
11 | #define XMEMSET memset | ||
12 | |||
13 | #define F25519_SIZE CURVE25519_KEYSIZE | ||
14 | |||
15 | /* The code below is taken from wolfssl-3.15.3/wolfcrypt/src/fe_low_mem.c | ||
16 | * Header comment is kept intact: | ||
17 | */ | ||
18 | |||
19 | /* fe_low_mem.c | ||
20 | * | ||
21 | * Copyright (C) 2006-2017 wolfSSL Inc. | ||
22 | * | ||
23 | * This file is part of wolfSSL. | ||
24 | * | ||
25 | * wolfSSL is free software; you can redistribute it and/or modify | ||
26 | * it under the terms of the GNU General Public License as published by | ||
27 | * the Free Software Foundation; either version 2 of the License, or | ||
28 | * (at your option) any later version. | ||
29 | * | ||
30 | * wolfSSL is distributed in the hope that it will be useful, | ||
31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
33 | * GNU General Public License for more details. | ||
34 | * | ||
35 | * You should have received a copy of the GNU General Public License | ||
36 | * along with this program; if not, write to the Free Software | ||
37 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA | ||
38 | */ | ||
39 | |||
40 | |||
41 | /* Based from Daniel Beer's public domain work. */ | ||
42 | |||
43 | #if 0 //UNUSED | ||
44 | static void fprime_copy(byte *x, const byte *a) | ||
45 | { | ||
46 | int i; | ||
47 | for (i = 0; i < F25519_SIZE; i++) | ||
48 | x[i] = a[i]; | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | static void lm_copy(byte* x, const byte* a) | ||
53 | { | ||
54 | int i; | ||
55 | for (i = 0; i < F25519_SIZE; i++) | ||
56 | x[i] = a[i]; | ||
57 | } | ||
58 | |||
59 | #if 0 //UNUSED | ||
60 | static void fprime_select(byte *dst, const byte *zero, const byte *one, byte condition) | ||
61 | { | ||
62 | const byte mask = -condition; | ||
63 | int i; | ||
64 | |||
65 | for (i = 0; i < F25519_SIZE; i++) | ||
66 | dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i])); | ||
67 | } | ||
68 | #endif | ||
69 | |||
70 | static void fe_select(byte *dst, | ||
71 | const byte *zero, const byte *one, | ||
72 | byte condition) | ||
73 | { | ||
74 | const byte mask = -condition; | ||
75 | int i; | ||
76 | |||
77 | for (i = 0; i < F25519_SIZE; i++) | ||
78 | dst[i] = zero[i] ^ (mask & (one[i] ^ zero[i])); | ||
79 | } | ||
80 | |||
81 | #if 0 //UNUSED | ||
82 | static void raw_add(byte *x, const byte *p) | ||
83 | { | ||
84 | word16 c = 0; | ||
85 | int i; | ||
86 | |||
87 | for (i = 0; i < F25519_SIZE; i++) { | ||
88 | c += ((word16)x[i]) + ((word16)p[i]); | ||
89 | x[i] = (byte)c; | ||
90 | c >>= 8; | ||
91 | } | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | #if 0 //UNUSED | ||
96 | static void raw_try_sub(byte *x, const byte *p) | ||
97 | { | ||
98 | byte minusp[F25519_SIZE]; | ||
99 | word16 c = 0; | ||
100 | int i; | ||
101 | |||
102 | for (i = 0; i < F25519_SIZE; i++) { | ||
103 | c = ((word16)x[i]) - ((word16)p[i]) - c; | ||
104 | minusp[i] = (byte)c; | ||
105 | c = (c >> 8) & 1; | ||
106 | } | ||
107 | |||
108 | fprime_select(x, minusp, x, (byte)c); | ||
109 | } | ||
110 | #endif | ||
111 | |||
112 | #if 0 //UNUSED | ||
113 | static int prime_msb(const byte *p) | ||
114 | { | ||
115 | int i; | ||
116 | byte x; | ||
117 | int shift = 1; | ||
118 | int z = F25519_SIZE - 1; | ||
119 | |||
120 | /* | ||
121 | Test for any hot bits. | ||
122 | As soon as one instance is encountered set shift to 0. | ||
123 | */ | ||
124 | for (i = F25519_SIZE - 1; i >= 0; i--) { | ||
125 | shift &= ((shift ^ ((-p[i] | p[i]) >> 7)) & 1); | ||
126 | z -= shift; | ||
127 | } | ||
128 | x = p[z]; | ||
129 | z <<= 3; | ||
130 | shift = 1; | ||
131 | for (i = 0; i < 8; i++) { | ||
132 | shift &= ((-(x >> i) | (x >> i)) >> (7 - i) & 1); | ||
133 | z += shift; | ||
134 | } | ||
135 | |||
136 | return z - 1; | ||
137 | } | ||
138 | #endif | ||
139 | |||
140 | #if 0 //UNUSED | ||
141 | static void fprime_add(byte *r, const byte *a, const byte *modulus) | ||
142 | { | ||
143 | raw_add(r, a); | ||
144 | raw_try_sub(r, modulus); | ||
145 | } | ||
146 | #endif | ||
147 | |||
148 | #if 0 //UNUSED | ||
149 | static void fprime_sub(byte *r, const byte *a, const byte *modulus) | ||
150 | { | ||
151 | raw_add(r, modulus); | ||
152 | raw_try_sub(r, a); | ||
153 | raw_try_sub(r, modulus); | ||
154 | } | ||
155 | #endif | ||
156 | |||
157 | #if 0 //UNUSED | ||
158 | static void fprime_mul(byte *r, const byte *a, const byte *b, | ||
159 | const byte *modulus) | ||
160 | { | ||
161 | word16 c = 0; | ||
162 | int i,j; | ||
163 | |||
164 | XMEMSET(r, 0, F25519_SIZE); | ||
165 | |||
166 | for (i = prime_msb(modulus); i >= 0; i--) { | ||
167 | const byte bit = (b[i >> 3] >> (i & 7)) & 1; | ||
168 | byte plusa[F25519_SIZE]; | ||
169 | |||
170 | for (j = 0; j < F25519_SIZE; j++) { | ||
171 | c |= ((word16)r[j]) << 1; | ||
172 | r[j] = (byte)c; | ||
173 | c >>= 8; | ||
174 | } | ||
175 | raw_try_sub(r, modulus); | ||
176 | |||
177 | fprime_copy(plusa, r); | ||
178 | fprime_add(plusa, a, modulus); | ||
179 | |||
180 | fprime_select(r, r, plusa, bit); | ||
181 | } | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | #if 0 //UNUSED | ||
186 | static void fe_load(byte *x, word32 c) | ||
187 | { | ||
188 | word32 i; | ||
189 | |||
190 | for (i = 0; i < sizeof(c); i++) { | ||
191 | x[i] = c; | ||
192 | c >>= 8; | ||
193 | } | ||
194 | |||
195 | for (; i < F25519_SIZE; i++) | ||
196 | x[i] = 0; | ||
197 | } | ||
198 | #endif | ||
199 | |||
200 | static void fe_normalize(byte *x) | ||
201 | { | ||
202 | byte minusp[F25519_SIZE]; | ||
203 | word16 c; | ||
204 | int i; | ||
205 | |||
206 | /* Reduce using 2^255 = 19 mod p */ | ||
207 | c = (x[31] >> 7) * 19; | ||
208 | x[31] &= 127; | ||
209 | |||
210 | for (i = 0; i < F25519_SIZE; i++) { | ||
211 | c += x[i]; | ||
212 | x[i] = (byte)c; | ||
213 | c >>= 8; | ||
214 | } | ||
215 | |||
216 | /* The number is now less than 2^255 + 18, and therefore less than | ||
217 | * 2p. Try subtracting p, and conditionally load the subtracted | ||
218 | * value if underflow did not occur. | ||
219 | */ | ||
220 | c = 19; | ||
221 | |||
222 | for (i = 0; i + 1 < F25519_SIZE; i++) { | ||
223 | c += x[i]; | ||
224 | minusp[i] = (byte)c; | ||
225 | c >>= 8; | ||
226 | } | ||
227 | |||
228 | c += ((word16)x[i]) - 128; | ||
229 | minusp[31] = (byte)c; | ||
230 | |||
231 | /* Load x-p if no underflow */ | ||
232 | fe_select(x, minusp, x, (c >> 15) & 1); | ||
233 | } | ||
234 | |||
235 | static void lm_add(byte* r, const byte* a, const byte* b) | ||
236 | { | ||
237 | word16 c = 0; | ||
238 | int i; | ||
239 | |||
240 | /* Add */ | ||
241 | for (i = 0; i < F25519_SIZE; i++) { | ||
242 | c >>= 8; | ||
243 | c += ((word16)a[i]) + ((word16)b[i]); | ||
244 | r[i] = (byte)c; | ||
245 | } | ||
246 | |||
247 | /* Reduce with 2^255 = 19 mod p */ | ||
248 | r[31] &= 127; | ||
249 | c = (c >> 7) * 19; | ||
250 | |||
251 | for (i = 0; i < F25519_SIZE; i++) { | ||
252 | c += r[i]; | ||
253 | r[i] = (byte)c; | ||
254 | c >>= 8; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static void lm_sub(byte* r, const byte* a, const byte* b) | ||
259 | { | ||
260 | word32 c = 0; | ||
261 | int i; | ||
262 | |||
263 | /* Calculate a + 2p - b, to avoid underflow */ | ||
264 | c = 218; | ||
265 | for (i = 0; i + 1 < F25519_SIZE; i++) { | ||
266 | c += 65280 + ((word32)a[i]) - ((word32)b[i]); | ||
267 | r[i] = c; | ||
268 | c >>= 8; | ||
269 | } | ||
270 | |||
271 | c += ((word32)a[31]) - ((word32)b[31]); | ||
272 | r[31] = c & 127; | ||
273 | c = (c >> 7) * 19; | ||
274 | |||
275 | for (i = 0; i < F25519_SIZE; i++) { | ||
276 | c += r[i]; | ||
277 | r[i] = c; | ||
278 | c >>= 8; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | #if 0 //UNUSED | ||
283 | static void lm_neg(byte* r, const byte* a) | ||
284 | { | ||
285 | word32 c = 0; | ||
286 | int i; | ||
287 | |||
288 | /* Calculate 2p - a, to avoid underflow */ | ||
289 | c = 218; | ||
290 | for (i = 0; i + 1 < F25519_SIZE; i++) { | ||
291 | c += 65280 - ((word32)a[i]); | ||
292 | r[i] = c; | ||
293 | c >>= 8; | ||
294 | } | ||
295 | |||
296 | c -= ((word32)a[31]); | ||
297 | r[31] = c & 127; | ||
298 | c = (c >> 7) * 19; | ||
299 | |||
300 | for (i = 0; i < F25519_SIZE; i++) { | ||
301 | c += r[i]; | ||
302 | r[i] = c; | ||
303 | c >>= 8; | ||
304 | } | ||
305 | } | ||
306 | #endif | ||
307 | |||
308 | static void fe_mul__distinct(byte *r, const byte *a, const byte *b) | ||
309 | { | ||
310 | word32 c = 0; | ||
311 | int i; | ||
312 | |||
313 | for (i = 0; i < F25519_SIZE; i++) { | ||
314 | int j; | ||
315 | |||
316 | c >>= 8; | ||
317 | for (j = 0; j <= i; j++) | ||
318 | c += ((word32)a[j]) * ((word32)b[i - j]); | ||
319 | |||
320 | for (; j < F25519_SIZE; j++) | ||
321 | c += ((word32)a[j]) * | ||
322 | ((word32)b[i + F25519_SIZE - j]) * 38; | ||
323 | |||
324 | r[i] = c; | ||
325 | } | ||
326 | |||
327 | r[31] &= 127; | ||
328 | c = (c >> 7) * 19; | ||
329 | |||
330 | for (i = 0; i < F25519_SIZE; i++) { | ||
331 | c += r[i]; | ||
332 | r[i] = c; | ||
333 | c >>= 8; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | #if 0 //UNUSED | ||
338 | static void lm_mul(byte *r, const byte* a, const byte *b) | ||
339 | { | ||
340 | byte tmp[F25519_SIZE]; | ||
341 | |||
342 | fe_mul__distinct(tmp, a, b); | ||
343 | lm_copy(r, tmp); | ||
344 | } | ||
345 | #endif | ||
346 | |||
347 | static void fe_mul_c(byte *r, const byte *a, word32 b) | ||
348 | { | ||
349 | word32 c = 0; | ||
350 | int i; | ||
351 | |||
352 | for (i = 0; i < F25519_SIZE; i++) { | ||
353 | c >>= 8; | ||
354 | c += b * ((word32)a[i]); | ||
355 | r[i] = c; | ||
356 | } | ||
357 | |||
358 | r[31] &= 127; | ||
359 | c >>= 7; | ||
360 | c *= 19; | ||
361 | |||
362 | for (i = 0; i < F25519_SIZE; i++) { | ||
363 | c += r[i]; | ||
364 | r[i] = c; | ||
365 | c >>= 8; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | static void fe_inv__distinct(byte *r, const byte *x) | ||
370 | { | ||
371 | byte s[F25519_SIZE]; | ||
372 | int i; | ||
373 | |||
374 | /* This is a prime field, so by Fermat's little theorem: | ||
375 | * | ||
376 | * x^(p-1) = 1 mod p | ||
377 | * | ||
378 | * Therefore, raise to (p-2) = 2^255-21 to get a multiplicative | ||
379 | * inverse. | ||
380 | * | ||
381 | * This is a 255-bit binary number with the digits: | ||
382 | * | ||
383 | * 11111111... 01011 | ||
384 | * | ||
385 | * We compute the result by the usual binary chain, but | ||
386 | * alternate between keeping the accumulator in r and s, so as | ||
387 | * to avoid copying temporaries. | ||
388 | */ | ||
389 | |||
390 | /* 1 1 */ | ||
391 | fe_mul__distinct(s, x, x); | ||
392 | fe_mul__distinct(r, s, x); | ||
393 | |||
394 | /* 1 x 248 */ | ||
395 | for (i = 0; i < 248; i++) { | ||
396 | fe_mul__distinct(s, r, r); | ||
397 | fe_mul__distinct(r, s, x); | ||
398 | } | ||
399 | |||
400 | /* 0 */ | ||
401 | fe_mul__distinct(s, r, r); | ||
402 | |||
403 | /* 1 */ | ||
404 | fe_mul__distinct(r, s, s); | ||
405 | fe_mul__distinct(s, r, x); | ||
406 | |||
407 | /* 0 */ | ||
408 | fe_mul__distinct(r, s, s); | ||
409 | |||
410 | /* 1 */ | ||
411 | fe_mul__distinct(s, r, r); | ||
412 | fe_mul__distinct(r, s, x); | ||
413 | |||
414 | /* 1 */ | ||
415 | fe_mul__distinct(s, r, r); | ||
416 | fe_mul__distinct(r, s, x); | ||
417 | } | ||
418 | |||
419 | #if 0 //UNUSED | ||
420 | static void lm_invert(byte *r, const byte *x) | ||
421 | { | ||
422 | byte tmp[F25519_SIZE]; | ||
423 | |||
424 | fe_inv__distinct(tmp, x); | ||
425 | lm_copy(r, tmp); | ||
426 | } | ||
427 | #endif | ||
428 | |||
429 | #if 0 //UNUSED | ||
430 | /* Raise x to the power of (p-5)/8 = 2^252-3, using s for temporary | ||
431 | * storage. | ||
432 | */ | ||
433 | static void exp2523(byte *r, const byte *x, byte *s) | ||
434 | { | ||
435 | int i; | ||
436 | |||
437 | /* This number is a 252-bit number with the binary expansion: | ||
438 | * | ||
439 | * 111111... 01 | ||
440 | */ | ||
441 | |||
442 | /* 1 1 */ | ||
443 | fe_mul__distinct(r, x, x); | ||
444 | fe_mul__distinct(s, r, x); | ||
445 | |||
446 | /* 1 x 248 */ | ||
447 | for (i = 0; i < 248; i++) { | ||
448 | fe_mul__distinct(r, s, s); | ||
449 | fe_mul__distinct(s, r, x); | ||
450 | } | ||
451 | |||
452 | /* 0 */ | ||
453 | fe_mul__distinct(r, s, s); | ||
454 | |||
455 | /* 1 */ | ||
456 | fe_mul__distinct(s, r, r); | ||
457 | fe_mul__distinct(r, s, x); | ||
458 | } | ||
459 | #endif | ||
460 | |||
461 | #if 0 //UNUSED | ||
462 | static void fe_sqrt(byte *r, const byte *a) | ||
463 | { | ||
464 | byte v[F25519_SIZE]; | ||
465 | byte i[F25519_SIZE]; | ||
466 | byte x[F25519_SIZE]; | ||
467 | byte y[F25519_SIZE]; | ||
468 | |||
469 | /* v = (2a)^((p-5)/8) [x = 2a] */ | ||
470 | fe_mul_c(x, a, 2); | ||
471 | exp2523(v, x, y); | ||
472 | |||
473 | /* i = 2av^2 - 1 */ | ||
474 | fe_mul__distinct(y, v, v); | ||
475 | fe_mul__distinct(i, x, y); | ||
476 | fe_load(y, 1); | ||
477 | lm_sub(i, i, y); | ||
478 | |||
479 | /* r = avi */ | ||
480 | fe_mul__distinct(x, v, a); | ||
481 | fe_mul__distinct(r, x, i); | ||
482 | } | ||
483 | #endif | ||
484 | |||
485 | /* Differential addition */ | ||
486 | static void xc_diffadd(byte *x5, byte *z5, | ||
487 | const byte *x1, const byte *z1, | ||
488 | const byte *x2, const byte *z2, | ||
489 | const byte *x3, const byte *z3) | ||
490 | { | ||
491 | /* Explicit formulas database: dbl-1987-m3 | ||
492 | * | ||
493 | * source 1987 Montgomery "Speeding the Pollard and elliptic curve | ||
494 | * methods of factorization", page 261, fifth display, plus | ||
495 | * common-subexpression elimination | ||
496 | * compute A = X2+Z2 | ||
497 | * compute B = X2-Z2 | ||
498 | * compute C = X3+Z3 | ||
499 | * compute D = X3-Z3 | ||
500 | * compute DA = D A | ||
501 | * compute CB = C B | ||
502 | * compute X5 = Z1(DA+CB)^2 | ||
503 | * compute Z5 = X1(DA-CB)^2 | ||
504 | */ | ||
505 | byte da[F25519_SIZE]; | ||
506 | byte cb[F25519_SIZE]; | ||
507 | byte a[F25519_SIZE]; | ||
508 | byte b[F25519_SIZE]; | ||
509 | |||
510 | lm_add(a, x2, z2); | ||
511 | lm_sub(b, x3, z3); /* D */ | ||
512 | fe_mul__distinct(da, a, b); | ||
513 | |||
514 | lm_sub(b, x2, z2); | ||
515 | lm_add(a, x3, z3); /* C */ | ||
516 | fe_mul__distinct(cb, a, b); | ||
517 | |||
518 | lm_add(a, da, cb); | ||
519 | fe_mul__distinct(b, a, a); | ||
520 | fe_mul__distinct(x5, z1, b); | ||
521 | |||
522 | lm_sub(a, da, cb); | ||
523 | fe_mul__distinct(b, a, a); | ||
524 | fe_mul__distinct(z5, x1, b); | ||
525 | } | ||
526 | |||
527 | /* Double an X-coordinate */ | ||
528 | static void xc_double(byte *x3, byte *z3, | ||
529 | const byte *x1, const byte *z1) | ||
530 | { | ||
531 | /* Explicit formulas database: dbl-1987-m | ||
532 | * | ||
533 | * source 1987 Montgomery "Speeding the Pollard and elliptic | ||
534 | * curve methods of factorization", page 261, fourth display | ||
535 | * compute X3 = (X1^2-Z1^2)^2 | ||
536 | * compute Z3 = 4 X1 Z1 (X1^2 + a X1 Z1 + Z1^2) | ||
537 | */ | ||
538 | byte x1sq[F25519_SIZE]; | ||
539 | byte z1sq[F25519_SIZE]; | ||
540 | byte x1z1[F25519_SIZE]; | ||
541 | byte a[F25519_SIZE]; | ||
542 | |||
543 | fe_mul__distinct(x1sq, x1, x1); | ||
544 | fe_mul__distinct(z1sq, z1, z1); | ||
545 | fe_mul__distinct(x1z1, x1, z1); | ||
546 | |||
547 | lm_sub(a, x1sq, z1sq); | ||
548 | fe_mul__distinct(x3, a, a); | ||
549 | |||
550 | fe_mul_c(a, x1z1, 486662); | ||
551 | lm_add(a, x1sq, a); | ||
552 | lm_add(a, z1sq, a); | ||
553 | fe_mul__distinct(x1sq, x1z1, a); | ||
554 | fe_mul_c(z3, x1sq, 4); | ||
555 | } | ||
556 | |||
557 | void FAST_FUNC curve25519(byte *result, const byte *e, const byte *q) | ||
558 | { | ||
559 | int i; | ||
560 | |||
561 | struct { | ||
562 | /* from wolfssl-3.15.3/wolfssl/wolfcrypt/fe_operations.h */ | ||
563 | /*static const*/ byte f25519_one[F25519_SIZE]; // = {1}; | ||
564 | |||
565 | /* Current point: P_m */ | ||
566 | byte xm[F25519_SIZE]; | ||
567 | byte zm[F25519_SIZE]; // = {1}; | ||
568 | /* Predecessor: P_(m-1) */ | ||
569 | byte xm1[F25519_SIZE]; // = {1}; | ||
570 | byte zm1[F25519_SIZE]; // = {0}; | ||
571 | } z; | ||
572 | #define f25519_one z.f25519_one | ||
573 | #define xm z.xm | ||
574 | #define zm z.zm | ||
575 | #define xm1 z.xm1 | ||
576 | #define zm1 z.zm1 | ||
577 | memset(&z, 0, sizeof(z)); | ||
578 | f25519_one[0] = 1; | ||
579 | zm[0] = 1; | ||
580 | xm1[0] = 1; | ||
581 | |||
582 | /* Note: bit 254 is assumed to be 1 */ | ||
583 | lm_copy(xm, q); | ||
584 | |||
585 | for (i = 253; i >= 0; i--) { | ||
586 | const int bit = (e[i >> 3] >> (i & 7)) & 1; | ||
587 | byte xms[F25519_SIZE]; | ||
588 | byte zms[F25519_SIZE]; | ||
589 | |||
590 | /* From P_m and P_(m-1), compute P_(2m) and P_(2m-1) */ | ||
591 | xc_diffadd(xm1, zm1, q, f25519_one, xm, zm, xm1, zm1); | ||
592 | xc_double(xm, zm, xm, zm); | ||
593 | |||
594 | /* Compute P_(2m+1) */ | ||
595 | xc_diffadd(xms, zms, xm1, zm1, xm, zm, q, f25519_one); | ||
596 | |||
597 | /* Select: | ||
598 | * bit = 1 --> (P_(2m+1), P_(2m)) | ||
599 | * bit = 0 --> (P_(2m), P_(2m-1)) | ||
600 | */ | ||
601 | fe_select(xm1, xm1, xm, bit); | ||
602 | fe_select(zm1, zm1, zm, bit); | ||
603 | fe_select(xm, xm, xms, bit); | ||
604 | fe_select(zm, zm, zms, bit); | ||
605 | } | ||
606 | |||
607 | /* Freeze out of projective coordinates */ | ||
608 | fe_inv__distinct(zm1, zm); | ||
609 | fe_mul__distinct(result, zm1, xm); | ||
610 | fe_normalize(result); | ||
611 | } | ||
diff --git a/networking/tls_fe.h b/networking/tls_fe.h new file mode 100644 index 000000000..fe8cff228 --- /dev/null +++ b/networking/tls_fe.h | |||
@@ -0,0 +1,7 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2018 Denys Vlasenko | ||
3 | * | ||
4 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
5 | */ | ||
6 | #define CURVE25519_KEYSIZE 32 | ||
7 | void curve25519(uint8_t *result, const uint8_t *e, const uint8_t *q) FAST_FUNC; | ||
diff --git a/networking/tls_rsa.c b/networking/tls_rsa.c index 60c54248e..631397e4d 100644 --- a/networking/tls_rsa.c +++ b/networking/tls_rsa.c | |||
@@ -179,7 +179,7 @@ done: | |||
179 | return res; | 179 | return res; |
180 | } | 180 | } |
181 | 181 | ||
182 | int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key, | 182 | int32 FAST_FUNC psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key, |
183 | unsigned char *in, uint32 inlen, | 183 | unsigned char *in, uint32 inlen, |
184 | unsigned char *out, uint32 outlen, void *data) | 184 | unsigned char *out, uint32 outlen, void *data) |
185 | { | 185 | { |
diff --git a/networking/tls_rsa.h b/networking/tls_rsa.h index c464ed552..82bea2a67 100644 --- a/networking/tls_rsa.h +++ b/networking/tls_rsa.h | |||
@@ -13,8 +13,20 @@ typedef struct { | |||
13 | //bbox psPool_t *pool; | 13 | //bbox psPool_t *pool; |
14 | } psRsaKey_t; | 14 | } psRsaKey_t; |
15 | 15 | ||
16 | static ALWAYS_INLINE void psRsaKey_clear(psRsaKey_t *key) | ||
17 | { | ||
18 | pstm_clear(&key->N); | ||
19 | pstm_clear(&key->e); | ||
20 | pstm_clear(&key->d); | ||
21 | pstm_clear(&key->p); | ||
22 | pstm_clear(&key->q); | ||
23 | pstm_clear(&key->dP); | ||
24 | pstm_clear(&key->dQ); | ||
25 | pstm_clear(&key->qP); | ||
26 | } | ||
27 | |||
16 | #define psRsaEncryptPub(pool, key, in, inlen, out, outlen, data) \ | 28 | #define psRsaEncryptPub(pool, key, in, inlen, out, outlen, data) \ |
17 | psRsaEncryptPub( key, in, inlen, out, outlen) | 29 | psRsaEncryptPub( key, in, inlen, out, outlen) |
18 | int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key, | 30 | int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key, |
19 | unsigned char *in, uint32 inlen, | 31 | unsigned char *in, uint32 inlen, |
20 | unsigned char *out, uint32 outlen, void *data); | 32 | unsigned char *out, uint32 outlen, void *data) FAST_FUNC; |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 66e4b6c6a..3c6129249 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -814,7 +814,9 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st | |||
814 | } | 814 | } |
815 | 815 | ||
816 | /* Unicast a DHCP release message */ | 816 | /* Unicast a DHCP release message */ |
817 | static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) | 817 | static |
818 | ALWAYS_INLINE /* one caller, help compiler to use this fact */ | ||
819 | int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) | ||
818 | { | 820 | { |
819 | struct d6_packet packet; | 821 | struct d6_packet packet; |
820 | uint8_t *opt_ptr; | 822 | uint8_t *opt_ptr; |
@@ -1738,8 +1740,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1738 | /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ | 1740 | /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ |
1739 | timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; | 1741 | timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; |
1740 | /* paranoia: must not be too small */ | 1742 | /* paranoia: must not be too small */ |
1741 | if (timeout < 0x10) | 1743 | /* timeout > 60 - ensures at least one unicast renew attempt */ |
1742 | timeout = 0x10; | 1744 | if (timeout < 61) |
1745 | timeout = 61; | ||
1743 | /* enter bound state */ | 1746 | /* enter bound state */ |
1744 | d6_run_script(packet.d6_options, packet_end, | 1747 | d6_run_script(packet.d6_options, packet_end, |
1745 | (state == REQUESTING ? "bound" : "renew")); | 1748 | (state == REQUESTING ? "bound" : "renew")); |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index ab3e5a463..4b23e4d39 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -850,7 +850,9 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req | |||
850 | #endif | 850 | #endif |
851 | 851 | ||
852 | /* Unicast a DHCP release message */ | 852 | /* Unicast a DHCP release message */ |
853 | static int send_release(uint32_t server, uint32_t ciaddr) | 853 | static |
854 | ALWAYS_INLINE /* one caller, help compiler to use this fact */ | ||
855 | int send_release(uint32_t server, uint32_t ciaddr) | ||
854 | { | 856 | { |
855 | struct dhcp_packet packet; | 857 | struct dhcp_packet packet; |
856 | 858 | ||
@@ -1725,8 +1727,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1725 | move_from_unaligned32(lease_seconds, temp); | 1727 | move_from_unaligned32(lease_seconds, temp); |
1726 | lease_seconds = ntohl(lease_seconds); | 1728 | lease_seconds = ntohl(lease_seconds); |
1727 | /* paranoia: must not be too small and not prone to overflows */ | 1729 | /* paranoia: must not be too small and not prone to overflows */ |
1728 | if (lease_seconds < 0x10) | 1730 | /* timeout > 60 - ensures at least one unicast renew attempt */ |
1729 | lease_seconds = 0x10; | 1731 | if (lease_seconds < 2 * 61) |
1732 | lease_seconds = 2 * 61; | ||
1730 | //if (lease_seconds > 0x7fffffff) | 1733 | //if (lease_seconds > 0x7fffffff) |
1731 | // lease_seconds = 0x7fffffff; | 1734 | // lease_seconds = 0x7fffffff; |
1732 | //^^^not necessary since "timeout = lease_seconds / 2" | 1735 | //^^^not necessary since "timeout = lease_seconds / 2" |
diff --git a/networking/wget.c b/networking/wget.c index bd2f4edcf..ae5c945d0 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -233,20 +233,19 @@ struct globals { | |||
233 | char *fname_out; /* where to direct output (-O) */ | 233 | char *fname_out; /* where to direct output (-O) */ |
234 | const char *proxy_flag; /* Use proxies if env vars are set */ | 234 | const char *proxy_flag; /* Use proxies if env vars are set */ |
235 | const char *user_agent; /* "User-Agent" header field */ | 235 | const char *user_agent; /* "User-Agent" header field */ |
236 | int output_fd; | ||
237 | int o_flags; | ||
236 | #if ENABLE_FEATURE_WGET_TIMEOUT | 238 | #if ENABLE_FEATURE_WGET_TIMEOUT |
237 | unsigned timeout_seconds; | 239 | unsigned timeout_seconds; |
238 | bool die_if_timed_out; | 240 | smallint die_if_timed_out; |
239 | #endif | 241 | #endif |
240 | int output_fd; | ||
241 | int o_flags; | ||
242 | smallint chunked; /* chunked transfer encoding */ | 242 | smallint chunked; /* chunked transfer encoding */ |
243 | smallint got_clen; /* got content-length: from server */ | 243 | smallint got_clen; /* got content-length: from server */ |
244 | /* Local downloads do benefit from big buffer. | 244 | /* Local downloads do benefit from big buffer. |
245 | * With 512 byte buffer, it was measured to be | 245 | * With 512 byte buffer, it was measured to be |
246 | * an order of magnitude slower than with big one. | 246 | * an order of magnitude slower than with big one. |
247 | */ | 247 | */ |
248 | uint64_t just_to_align_next_member; | 248 | char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024] ALIGNED(sizeof(long)); |
249 | char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024]; | ||
250 | } FIX_ALIASING; | 249 | } FIX_ALIASING; |
251 | #define G (*ptr_to_globals) | 250 | #define G (*ptr_to_globals) |
252 | #define INIT_G() do { \ | 251 | #define INIT_G() do { \ |
@@ -283,13 +282,15 @@ enum { | |||
283 | #if ENABLE_FEATURE_WGET_STATUSBAR | 282 | #if ENABLE_FEATURE_WGET_STATUSBAR |
284 | static void progress_meter(int flag) | 283 | static void progress_meter(int flag) |
285 | { | 284 | { |
285 | int notty; | ||
286 | |||
286 | if (option_mask32 & WGET_OPT_QUIET) | 287 | if (option_mask32 & WGET_OPT_QUIET) |
287 | return; | 288 | return; |
288 | 289 | ||
289 | if (flag == PROGRESS_START) | 290 | if (flag == PROGRESS_START) |
290 | bb_progress_init(&G.pmt, G.curfile); | 291 | bb_progress_init(&G.pmt, G.curfile); |
291 | 292 | ||
292 | bb_progress_update(&G.pmt, | 293 | notty = bb_progress_update(&G.pmt, |
293 | G.beg_range, | 294 | G.beg_range, |
294 | G.transferred, | 295 | G.transferred, |
295 | (G.chunked || !G.got_clen) ? 0 : G.beg_range + G.transferred + G.content_len | 296 | (G.chunked || !G.got_clen) ? 0 : G.beg_range + G.transferred + G.content_len |
@@ -297,7 +298,8 @@ static void progress_meter(int flag) | |||
297 | 298 | ||
298 | if (flag == PROGRESS_END) { | 299 | if (flag == PROGRESS_END) { |
299 | bb_progress_free(&G.pmt); | 300 | bb_progress_free(&G.pmt); |
300 | bb_putchar_stderr('\n'); | 301 | if (notty == 0) |
302 | bb_putchar_stderr('\n'); /* it's tty */ | ||
301 | G.transferred = 0; | 303 | G.transferred = 0; |
302 | } | 304 | } |
303 | } | 305 | } |
@@ -346,9 +348,8 @@ static void strip_ipv6_scope_id(char *host) | |||
346 | /* Base64-encode character string. */ | 348 | /* Base64-encode character string. */ |
347 | static char *base64enc(const char *str) | 349 | static char *base64enc(const char *str) |
348 | { | 350 | { |
349 | unsigned len = strlen(str); | 351 | /* paranoia */ |
350 | if (len > sizeof(G.wget_buf)/4*3 - 10) /* paranoia */ | 352 | unsigned len = strnlen(str, sizeof(G.wget_buf)/4*3 - 10); |
351 | len = sizeof(G.wget_buf)/4*3 - 10; | ||
352 | bb_uuencode(G.wget_buf, str, len, bb_uuenc_tbl_base64); | 353 | bb_uuencode(G.wget_buf, str, len, bb_uuenc_tbl_base64); |
353 | return G.wget_buf; | 354 | return G.wget_buf; |
354 | } | 355 | } |
@@ -723,8 +724,10 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags) | |||
723 | int pid; | 724 | int pid; |
724 | char *servername, *p; | 725 | char *servername, *p; |
725 | 726 | ||
726 | if (!(option_mask32 & WGET_OPT_NO_CHECK_CERT)) | 727 | if (!(option_mask32 & WGET_OPT_NO_CHECK_CERT)) { |
728 | option_mask32 |= WGET_OPT_NO_CHECK_CERT; | ||
727 | bb_error_msg("note: TLS certificate validation not implemented"); | 729 | bb_error_msg("note: TLS certificate validation not implemented"); |
730 | } | ||
728 | 731 | ||
729 | servername = xstrdup(host); | 732 | servername = xstrdup(host); |
730 | p = strrchr(servername, ':'); | 733 | p = strrchr(servername, ':'); |
diff --git a/procps/free.c b/procps/free.c index 48139c4a3..ee0cd981a 100644 --- a/procps/free.c +++ b/procps/free.c | |||
@@ -53,21 +53,27 @@ static unsigned long long scale(struct globals *g, unsigned long d) | |||
53 | } | 53 | } |
54 | 54 | ||
55 | /* NOINLINE reduces main() stack usage, which makes code smaller (on x86 at least) */ | 55 | /* NOINLINE reduces main() stack usage, which makes code smaller (on x86 at least) */ |
56 | static NOINLINE unsigned long parse_cached_kb(void) | 56 | static NOINLINE unsigned int parse_meminfo(unsigned long *cached_kb, unsigned long *available_kb) |
57 | { | 57 | { |
58 | char buf[60]; /* actual lines we expect are ~30 chars or less */ | 58 | char buf[60]; /* actual lines we expect are ~30 chars or less */ |
59 | FILE *fp; | 59 | FILE *fp; |
60 | unsigned long cached = 0; | 60 | int seen_cached_and_available; |
61 | 61 | ||
62 | fp = xfopen_for_read("/proc/meminfo"); | 62 | fp = xfopen_for_read("/proc/meminfo"); |
63 | while (fgets(buf, sizeof(buf), fp) != NULL) { | 63 | *cached_kb = *available_kb = 0; |
64 | if (sscanf(buf, "Cached: %lu %*s\n", &cached) == 1) | 64 | seen_cached_and_available = 2; |
65 | break; | 65 | while (fgets(buf, sizeof(buf), fp)) { |
66 | if (sscanf(buf, "Cached: %lu %*s\n", cached_kb) == 1) | ||
67 | if (--seen_cached_and_available == 0) | ||
68 | break; | ||
69 | if (sscanf(buf, "MemAvailable: %lu %*s\n", available_kb) == 1) | ||
70 | if (--seen_cached_and_available == 0) | ||
71 | break; | ||
66 | } | 72 | } |
67 | /* Have to close because of NOFORK */ | 73 | /* Have to close because of NOFORK */ |
68 | fclose(fp); | 74 | fclose(fp); |
69 | 75 | ||
70 | return cached; | 76 | return seen_cached_and_available == 0; |
71 | } | 77 | } |
72 | 78 | ||
73 | int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 79 | int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -75,7 +81,9 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) | |||
75 | { | 81 | { |
76 | struct globals G; | 82 | struct globals G; |
77 | struct sysinfo info; | 83 | struct sysinfo info; |
78 | unsigned long long cached; | 84 | unsigned long long cached, cached_plus_free, available; |
85 | unsigned long cached_kb, available_kb; | ||
86 | int seen_available; | ||
79 | 87 | ||
80 | #if ENABLE_DESKTOP | 88 | #if ENABLE_DESKTOP |
81 | G.unit_steps = 10; | 89 | G.unit_steps = 10; |
@@ -98,41 +106,46 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) | |||
98 | } | 106 | } |
99 | } | 107 | } |
100 | #endif | 108 | #endif |
101 | printf(" %11s%11s%11s%11s%11s%11s\n" | 109 | printf(" %12s%12s%12s%12s%12s%12s\n" |
102 | "Mem: ", | 110 | "Mem: ", |
103 | "total", | 111 | "total", |
104 | "used", | 112 | "used", |
105 | "free", | 113 | "free", |
106 | "shared", "buffers", "cached" /* swap and total don't have these columns */ | 114 | "shared", "buff/cache", "available" /* swap and total don't have these columns */ |
107 | ); | 115 | ); |
108 | 116 | ||
109 | sysinfo(&info); | 117 | sysinfo(&info); |
110 | /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ | 118 | /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ |
111 | G.mem_unit = (info.mem_unit ? info.mem_unit : 1); | 119 | G.mem_unit = (info.mem_unit ? info.mem_unit : 1); |
112 | /* Extract cached from /proc/meminfo and convert to mem_units */ | 120 | /* Extract cached and memavailable from /proc/meminfo and convert to mem_units */ |
113 | cached = ((unsigned long long) parse_cached_kb() * 1024) / G.mem_unit; | 121 | seen_available = parse_meminfo(&cached_kb, &available_kb); |
122 | available = ((unsigned long long) available_kb * 1024) / G.mem_unit; | ||
123 | cached = ((unsigned long long) cached_kb * 1024) / G.mem_unit; | ||
124 | cached += info.bufferram; | ||
125 | cached_plus_free = cached + info.freeram; | ||
114 | 126 | ||
115 | #define FIELDS_6 "%11llu%11llu%11llu%11llu%11llu%11llu\n" | 127 | #define FIELDS_6 "%12llu %11llu %11llu %11llu %11llu %11llu\n" |
116 | #define FIELDS_3 (FIELDS_6 + 3*6) | 128 | #define FIELDS_3 (FIELDS_6 + 6 + 7 + 7) |
117 | #define FIELDS_2 (FIELDS_6 + 4*6) | 129 | #define FIELDS_2 (FIELDS_6 + 6 + 7 + 7 + 7) |
118 | 130 | ||
119 | printf(FIELDS_6, | 131 | printf(FIELDS_6, |
120 | scale(&G, info.totalram), //total | 132 | scale(&G, info.totalram), //total |
121 | scale(&G, info.totalram - info.freeram), //used | 133 | scale(&G, info.totalram - cached_plus_free), //used |
122 | scale(&G, info.freeram), //free | 134 | scale(&G, info.freeram), //free |
123 | scale(&G, info.sharedram), //shared | 135 | scale(&G, info.sharedram), //shared |
124 | scale(&G, info.bufferram), //buffers | 136 | scale(&G, cached), //buff/cache |
125 | scale(&G, cached) //cached | 137 | scale(&G, available) //available |
126 | ); | 138 | ); |
127 | /* Show alternate, more meaningful busy/free numbers by counting | 139 | /* On kernels < 3.14, MemAvailable is not provided. |
140 | * Show alternate, more meaningful busy/free numbers by counting | ||
128 | * buffer cache as free memory. */ | 141 | * buffer cache as free memory. */ |
129 | printf("-/+ buffers/cache:"); | 142 | if (!seen_available) { |
130 | cached += info.freeram; | 143 | printf("-/+ buffers/cache: "); |
131 | cached += info.bufferram; | 144 | printf(FIELDS_2, |
132 | printf(FIELDS_2, | 145 | scale(&G, info.totalram - cached_plus_free), //used |
133 | scale(&G, info.totalram - cached), //used | 146 | scale(&G, cached_plus_free) //free |
134 | scale(&G, cached) //free | 147 | ); |
135 | ); | 148 | } |
136 | #if BB_MMU | 149 | #if BB_MMU |
137 | printf("Swap: "); | 150 | printf("Swap: "); |
138 | printf(FIELDS_3, | 151 | printf(FIELDS_3, |
diff --git a/runit/svlogd.c b/runit/svlogd.c index 13de2570f..b0690d794 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c | |||
@@ -1010,7 +1010,7 @@ static void sig_hangup_handler(int sig_no UNUSED_PARAM) | |||
1010 | reopenasap = 1; | 1010 | reopenasap = 1; |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | static void logmatch(struct logdir *ld) | 1013 | static void logmatch(struct logdir *ld, char* lineptr, int lineptr_len) |
1014 | { | 1014 | { |
1015 | char *s; | 1015 | char *s; |
1016 | 1016 | ||
@@ -1021,12 +1021,12 @@ static void logmatch(struct logdir *ld) | |||
1021 | switch (s[0]) { | 1021 | switch (s[0]) { |
1022 | case '+': | 1022 | case '+': |
1023 | case '-': | 1023 | case '-': |
1024 | if (pmatch(s+1, line, linelen)) | 1024 | if (pmatch(s+1, lineptr, lineptr_len)) |
1025 | ld->match = s[0]; | 1025 | ld->match = s[0]; |
1026 | break; | 1026 | break; |
1027 | case 'e': | 1027 | case 'e': |
1028 | case 'E': | 1028 | case 'E': |
1029 | if (pmatch(s+1, line, linelen)) | 1029 | if (pmatch(s+1, lineptr, lineptr_len)) |
1030 | ld->matcherr = s[0]; | 1030 | ld->matcherr = s[0]; |
1031 | break; | 1031 | break; |
1032 | } | 1032 | } |
@@ -1182,7 +1182,7 @@ int svlogd_main(int argc, char **argv) | |||
1182 | if (ld->fddir == -1) | 1182 | if (ld->fddir == -1) |
1183 | continue; | 1183 | continue; |
1184 | if (ld->inst) | 1184 | if (ld->inst) |
1185 | logmatch(ld); | 1185 | logmatch(ld, lineptr, linelen); |
1186 | if (ld->matcherr == 'e') { | 1186 | if (ld->matcherr == 'e') { |
1187 | /* runit-1.8.0 compat: if timestamping, do it on stderr too */ | 1187 | /* runit-1.8.0 compat: if timestamping, do it on stderr too */ |
1188 | ////full_write(STDERR_FILENO, printptr, printlen); | 1188 | ////full_write(STDERR_FILENO, printptr, printlen); |
diff --git a/scripts/embedded_scripts b/scripts/embedded_scripts new file mode 100755 index 000000000..aa7bf3e8a --- /dev/null +++ b/scripts/embedded_scripts | |||
@@ -0,0 +1,125 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | . ./.config || exit 1 | ||
4 | |||
5 | target="$1" | ||
6 | custom_loc="$2" | ||
7 | applet_loc="$3" | ||
8 | |||
9 | test "$target" || exit 1 | ||
10 | test "$SED" || SED=sed | ||
11 | test "$DD" || DD=dd | ||
12 | |||
13 | if [ x"$CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS" != x"y" ] | ||
14 | then | ||
15 | printf '#define NUM_SCRIPTS 0\n' >"$target" | ||
16 | exit 0 | ||
17 | fi | ||
18 | |||
19 | # Some people were bitten by their system lacking a (proper) od | ||
20 | od -v -b </dev/null >/dev/null | ||
21 | if test $? != 0; then | ||
22 | echo 'od tool is not installed or cannot accept "-v -b" options' | ||
23 | exit 1 | ||
24 | fi | ||
25 | |||
26 | custom_scripts="" | ||
27 | if [ -d "$custom_loc" ] | ||
28 | then | ||
29 | custom_scripts=$(cd $custom_loc; ls * 2>/dev/null) | ||
30 | fi | ||
31 | all_scripts=$($srctree/applets/busybox.mkscripts) | ||
32 | |||
33 | # all_scripts includes applet scripts and custom scripts, sort them out | ||
34 | applet_scripts="" | ||
35 | for i in $all_scripts | ||
36 | do | ||
37 | found=0 | ||
38 | for j in $custom_scripts | ||
39 | do | ||
40 | if [ "$i" = "$j" ] | ||
41 | then | ||
42 | found=1 | ||
43 | break; | ||
44 | fi | ||
45 | done | ||
46 | if [ $found -eq 0 ] | ||
47 | then | ||
48 | # anything that isn't a custom script is an applet script | ||
49 | applet_scripts="$applet_scripts $i" | ||
50 | fi | ||
51 | done | ||
52 | |||
53 | # we know the custom scripts are present but applet scripts might have | ||
54 | # become detached from their configuration | ||
55 | for i in $applet_scripts | ||
56 | do | ||
57 | #if [ ! -f "$applet_loc/$i" -a ! -f "$custom_loc/$i" ] | ||
58 | if [ ! -f "$applet_loc/$i" ] | ||
59 | then | ||
60 | echo "missing applet script $i" | ||
61 | exit 1 | ||
62 | fi | ||
63 | done | ||
64 | |||
65 | n=$(echo $custom_scripts $applet_scripts | wc -w) | ||
66 | nall=$(echo $all_scripts | wc -w) | ||
67 | |||
68 | if [ $n -ne $nall ] | ||
69 | then | ||
70 | echo "script mismatch $n != $nall" | ||
71 | exit 1 | ||
72 | fi | ||
73 | |||
74 | concatenate_scripts() { | ||
75 | for i in $custom_scripts | ||
76 | do | ||
77 | cat $custom_loc/$i | ||
78 | printf '\000' | ||
79 | done | ||
80 | for i in $applet_scripts | ||
81 | do | ||
82 | cat $applet_loc/$i | ||
83 | printf '\000' | ||
84 | done | ||
85 | } | ||
86 | |||
87 | exec >"$target.$$" | ||
88 | |||
89 | if [ $n -ne 0 ] | ||
90 | then | ||
91 | printf '#ifdef DEFINE_SCRIPT_DATA\n' | ||
92 | printf 'const uint16_t applet_numbers[] = {\n' | ||
93 | for i in $custom_scripts $applet_scripts | ||
94 | do | ||
95 | # TODO support applets with names including invalid characters | ||
96 | printf '\tAPPLET_NO_%s,\n' $i | ||
97 | done | ||
98 | printf '};\n' | ||
99 | printf '#else\n' | ||
100 | printf 'extern const uint16_t applet_numbers[];\n' | ||
101 | printf '#endif\n' | ||
102 | fi | ||
103 | |||
104 | printf "\n" | ||
105 | printf '#define NUM_SCRIPTS %d\n' $n | ||
106 | printf "\n" | ||
107 | |||
108 | if [ $n -ne 0 ] | ||
109 | then | ||
110 | printf '#define UNPACKED_SCRIPTS_LENGTH ' | ||
111 | concatenate_scripts | wc -c | ||
112 | |||
113 | printf '#define PACKED_SCRIPTS \\\n' | ||
114 | concatenate_scripts | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | \ | ||
115 | od -v -b \ | ||
116 | | grep -v '^ ' \ | ||
117 | | $SED -e 's/^[^ ]*//' \ | ||
118 | -e 's/ //g' \ | ||
119 | -e '/^$/d' \ | ||
120 | -e 's/\(...\)/0\1,/g' \ | ||
121 | -e 's/$/ \\/' | ||
122 | printf '\n' | ||
123 | fi | ||
124 | |||
125 | mv -- "$target.$$" "$target" | ||
diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index f79fa2f83..92de681ac 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh | |||
@@ -17,12 +17,26 @@ status() { printf ' %-8s%s\n' "$1" "$2"; } | |||
17 | gen() { status "GEN" "$@"; } | 17 | gen() { status "GEN" "$@"; } |
18 | chk() { status "CHK" "$@"; } | 18 | chk() { status "CHK" "$@"; } |
19 | 19 | ||
20 | # scripts in the 'embed' directory are treated as fake applets | ||
21 | custom_scripts() | ||
22 | { | ||
23 | custom_loc="$1" | ||
24 | if [ -d "$custom_loc" ] | ||
25 | then | ||
26 | for i in $(cd "$custom_loc"; ls * 2>/dev/null) | ||
27 | do | ||
28 | printf "IF_FEATURE_SH_EMBEDDED_SCRIPTS(APPLET_SCRIPTED(%s, scripted, BB_DIR_USR_BIN, BB_SUID_DROP, scripted))\n" $i; | ||
29 | done | ||
30 | fi | ||
31 | } | ||
32 | |||
20 | generate() | 33 | generate() |
21 | { | 34 | { |
22 | # NB: data to be inserted at INSERT line is coming on stdin | 35 | # NB: data to be inserted at INSERT line is coming on stdin |
23 | src="$1" | 36 | src="$1" |
24 | dst="$2" | 37 | dst="$2" |
25 | header="$3" | 38 | header="$3" |
39 | loc="$4" | ||
26 | #chk "${dst}" | 40 | #chk "${dst}" |
27 | { | 41 | { |
28 | # Need to use printf: different shells have inconsistent | 42 | # Need to use printf: different shells have inconsistent |
@@ -32,6 +46,10 @@ generate() | |||
32 | sed -n '/^INSERT$/ q; p' "${src}" | 46 | sed -n '/^INSERT$/ q; p' "${src}" |
33 | # copy stdin to stdout | 47 | # copy stdin to stdout |
34 | cat | 48 | cat |
49 | if [ -n "$loc" ] | ||
50 | then | ||
51 | custom_scripts "$loc" | ||
52 | fi | ||
35 | # print everything after INSERT line | 53 | # print everything after INSERT line |
36 | sed -n '/^INSERT$/ { | 54 | sed -n '/^INSERT$/ { |
37 | :l | 55 | :l |
@@ -53,7 +71,8 @@ sed -n 's@^//applet:@@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \ | |||
53 | | generate \ | 71 | | generate \ |
54 | "$srctree/include/applets.src.h" \ | 72 | "$srctree/include/applets.src.h" \ |
55 | "include/applets.h" \ | 73 | "include/applets.h" \ |
56 | "/* DO NOT EDIT. This file is generated from applets.src.h */" | 74 | "/* DO NOT EDIT. This file is generated from applets.src.h */" \ |
75 | "$srctree/embed" | ||
57 | 76 | ||
58 | # (Re)generate include/usage.h | 77 | # (Re)generate include/usage.h |
59 | # We add line continuation backslash after each line, | 78 | # We add line continuation backslash after each line, |
diff --git a/scripts/trylink b/scripts/trylink index ba2d265bc..bb6b2de2f 100755 --- a/scripts/trylink +++ b/scripts/trylink | |||
@@ -149,8 +149,8 @@ try $CC $CFLAGS $LDFLAGS \ | |||
149 | # Stop when no lib can be removed. | 149 | # Stop when no lib can be removed. |
150 | while test "$LDLIBS"; do | 150 | while test "$LDLIBS"; do |
151 | $debug && echo "Trying libraries: $LDLIBS" | 151 | $debug && echo "Trying libraries: $LDLIBS" |
152 | all_needed=true | 152 | dropped_non_first_lib=false |
153 | last_needed=false | 153 | first_lib=true |
154 | for one in $LDLIBS; do | 154 | for one in $LDLIBS; do |
155 | without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs` | 155 | without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs` |
156 | # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" | 156 | # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" |
@@ -167,20 +167,17 @@ while test "$LDLIBS"; do | |||
167 | if test $? = 0; then | 167 | if test $? = 0; then |
168 | echo " Library $one is not needed, excluding it" | 168 | echo " Library $one is not needed, excluding it" |
169 | LDLIBS="$without_one" | 169 | LDLIBS="$without_one" |
170 | all_needed=false | 170 | $first_lib || dropped_non_first_lib=true |
171 | last_needed=false | ||
172 | else | 171 | else |
173 | echo " Library $one is needed, can't exclude it (yet)" | 172 | echo " Library $one is needed, can't exclude it (yet)" |
174 | last_needed=true | 173 | first_lib=false |
175 | fi | 174 | fi |
176 | done | 175 | done |
177 | # All libs were needed, can't remove any | 176 | # We can stop trying to drop libs if either all libs were needed, |
178 | $all_needed && break | 177 | # or we excluded only the _first_ few. |
179 | # Optimization: was the last tried lib needed? | 178 | # (else: we dropped some intermediate lib(s), maybe now we can succeed |
180 | if $last_needed; then | 179 | # in dropping some of the preceding ones) |
181 | # Was it the only one lib left? Don't test again then. | 180 | $dropped_non_first_lib || break |
182 | { echo "$LDLIBS" | grep -q ' '; } || break | ||
183 | fi | ||
184 | done | 181 | done |
185 | 182 | ||
186 | # Make the binary with final, minimal list of libs | 183 | # Make the binary with final, minimal list of libs |
diff --git a/shell/Config.src b/shell/Config.src index 959d3cb42..bc7218fe5 100644 --- a/shell/Config.src +++ b/shell/Config.src | |||
@@ -161,6 +161,20 @@ config FEATURE_SH_HISTFILESIZE | |||
161 | to set shell history size. Note that its max value is capped | 161 | to set shell history size. Note that its max value is capped |
162 | by "History size" setting in library tuning section. | 162 | by "History size" setting in library tuning section. |
163 | 163 | ||
164 | config FEATURE_SH_EMBEDDED_SCRIPTS | ||
165 | bool "Embed scripts in the binary" | ||
166 | default y | ||
167 | depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH | ||
168 | help | ||
169 | Allow scripts to be compressed and embedded in the busybox | ||
170 | binary. The scripts should be placed in the 'embed' directory | ||
171 | at build time. Like applets, scripts can be run as | ||
172 | 'busybox SCRIPT ...' or by linking their name to the binary. | ||
173 | |||
174 | This also allows applets to be implemented as scripts: place | ||
175 | the script in 'applets_sh' and a stub C file containing | ||
176 | configuration in the appropriate subsystem directory. | ||
177 | |||
164 | endif # Options common to all shells | 178 | endif # Options common to all shells |
165 | 179 | ||
166 | endmenu | 180 | endmenu |
diff --git a/shell/ash.c b/shell/ash.c index 7131609e4..1b40e3407 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -208,6 +208,11 @@ | |||
208 | #include <sys/times.h> | 208 | #include <sys/times.h> |
209 | #include <sys/utsname.h> /* for setting $HOSTNAME */ | 209 | #include <sys/utsname.h> /* for setting $HOSTNAME */ |
210 | #include "busybox.h" /* for applet_names */ | 210 | #include "busybox.h" /* for applet_names */ |
211 | #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS | ||
212 | # include "embedded_scripts.h" | ||
213 | #else | ||
214 | # define NUM_SCRIPTS 0 | ||
215 | #endif | ||
211 | 216 | ||
212 | /* So far, all bash compat is controlled by one config option */ | 217 | /* So far, all bash compat is controlled by one config option */ |
213 | /* Separate defines document which part of code implements what */ | 218 | /* Separate defines document which part of code implements what */ |
@@ -2503,13 +2508,12 @@ setvar(const char *name, const char *val, int flags) | |||
2503 | } | 2508 | } |
2504 | 2509 | ||
2505 | INT_OFF; | 2510 | INT_OFF; |
2506 | nameeq = ckmalloc(namelen + vallen + 2); | 2511 | nameeq = ckzalloc(namelen + vallen + 2); |
2507 | p = mempcpy(nameeq, name, namelen); | 2512 | p = mempcpy(nameeq, name, namelen); |
2508 | if (val) { | 2513 | if (val) { |
2509 | *p++ = '='; | 2514 | *p++ = '='; |
2510 | p = mempcpy(p, val, vallen); | 2515 | memcpy(p, val, vallen); |
2511 | } | 2516 | } |
2512 | *p = '\0'; | ||
2513 | vp = setvareq(nameeq, flags | VNOSAVE); | 2517 | vp = setvareq(nameeq, flags | VNOSAVE); |
2514 | INT_ON; | 2518 | INT_ON; |
2515 | 2519 | ||
@@ -8420,6 +8424,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8420 | #else | 8424 | #else |
8421 | execve(cmd, argv, envp); | 8425 | execve(cmd, argv, envp); |
8422 | #endif | 8426 | #endif |
8427 | |||
8423 | if (cmd != bb_busybox_exec_path && errno == ENOEXEC) { | 8428 | if (cmd != bb_busybox_exec_path && errno == ENOEXEC) { |
8424 | /* Run "cmd" as a shell script: | 8429 | /* Run "cmd" as a shell script: |
8425 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html | 8430 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html |
@@ -13459,6 +13464,7 @@ parseheredoc(void) | |||
13459 | heredoclist = NULL; | 13464 | heredoclist = NULL; |
13460 | 13465 | ||
13461 | while (here) { | 13466 | while (here) { |
13467 | tokpushback = 0; | ||
13462 | setprompt_if(needprompt, 2); | 13468 | setprompt_if(needprompt, 2); |
13463 | readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, | 13469 | readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, |
13464 | here->eofmark, here->striptabs); | 13470 | here->eofmark, here->striptabs); |
@@ -14662,12 +14668,16 @@ procargs(char **argv) | |||
14662 | 14668 | ||
14663 | xargv = argv; | 14669 | xargv = argv; |
14664 | login_sh = xargv[0] && xargv[0][0] == '-'; | 14670 | login_sh = xargv[0] && xargv[0][0] == '-'; |
14671 | #if NUM_SCRIPTS > 0 | ||
14672 | if (minusc) | ||
14673 | goto setarg0; | ||
14674 | #endif | ||
14665 | arg0 = xargv[0]; | 14675 | arg0 = xargv[0]; |
14666 | /* if (xargv[0]) - mmm, this is always true! */ | 14676 | /* if (xargv[0]) - mmm, this is always true! */ |
14667 | xargv++; | 14677 | xargv++; |
14678 | argptr = xargv; | ||
14668 | for (i = 0; i < NOPTS; i++) | 14679 | for (i = 0; i < NOPTS; i++) |
14669 | optlist[i] = 2; | 14680 | optlist[i] = 2; |
14670 | argptr = xargv; | ||
14671 | if (options(/*cmdline:*/ 1, &login_sh)) { | 14681 | if (options(/*cmdline:*/ 1, &login_sh)) { |
14672 | /* it already printed err message */ | 14682 | /* it already printed err message */ |
14673 | raise_exception(EXERROR); | 14683 | raise_exception(EXERROR); |
@@ -14772,7 +14782,12 @@ extern int etext(); | |||
14772 | * is used to figure out how far we had gotten. | 14782 | * is used to figure out how far we had gotten. |
14773 | */ | 14783 | */ |
14774 | int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 14784 | int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
14785 | #if NUM_SCRIPTS > 0 | ||
14786 | int ash_main(int argc, char **argv) | ||
14787 | #else | ||
14775 | int ash_main(int argc UNUSED_PARAM, char **argv) | 14788 | int ash_main(int argc UNUSED_PARAM, char **argv) |
14789 | #endif | ||
14790 | /* note: 'argc' is used only if embedded scripts are enabled */ | ||
14776 | { | 14791 | { |
14777 | volatile smallint state; | 14792 | volatile smallint state; |
14778 | struct jmploc jmploc; | 14793 | struct jmploc jmploc; |
@@ -14839,6 +14854,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
14839 | bb_error_msg_and_die("forkshell failed"); | 14854 | bb_error_msg_and_die("forkshell failed"); |
14840 | } | 14855 | } |
14841 | #endif | 14856 | #endif |
14857 | |||
14858 | #if NUM_SCRIPTS > 0 | ||
14859 | if (argc < 0) | ||
14860 | /* Non-NULL minusc tells procargs that an embedded script is being run */ | ||
14861 | minusc = get_script_content(-argc - 1); | ||
14862 | #endif | ||
14842 | login_sh = procargs(argv); | 14863 | login_sh = procargs(argv); |
14843 | #if DEBUG | 14864 | #if DEBUG |
14844 | TRACE(("Shell args: ")); | 14865 | TRACE(("Shell args: ")); |
diff --git a/shell/hush.c b/shell/hush.c index 881331c5b..90191408d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -157,7 +157,7 @@ | |||
157 | //config: but no separate process group is formed. | 157 | //config: but no separate process group is formed. |
158 | //config: | 158 | //config: |
159 | //config:config HUSH_TICK | 159 | //config:config HUSH_TICK |
160 | //config: bool "Support process substitution" | 160 | //config: bool "Support command substitution" |
161 | //config: default y | 161 | //config: default y |
162 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH | 162 | //config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH |
163 | //config: help | 163 | //config: help |
@@ -367,6 +367,11 @@ | |||
367 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ | 367 | # define PIPE_BUF 4096 /* amount of buffering in a pipe */ |
368 | #endif | 368 | #endif |
369 | 369 | ||
370 | #if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS && !(ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH) | ||
371 | # include "embedded_scripts.h" | ||
372 | #else | ||
373 | # define NUM_SCRIPTS 0 | ||
374 | #endif | ||
370 | 375 | ||
371 | /* So far, all bash compat is controlled by one config option */ | 376 | /* So far, all bash compat is controlled by one config option */ |
372 | /* Separate defines document which part of code implements what */ | 377 | /* Separate defines document which part of code implements what */ |
@@ -9951,6 +9956,14 @@ int hush_main(int argc, char **argv) | |||
9951 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 9956 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
9952 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; | 9957 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; |
9953 | builtin_argc = 0; | 9958 | builtin_argc = 0; |
9959 | #if NUM_SCRIPTS > 0 | ||
9960 | if (argc < 0) { | ||
9961 | optarg = get_script_content(-argc - 1); | ||
9962 | optind = 0; | ||
9963 | argc = string_array_len(argv); | ||
9964 | goto run_script; | ||
9965 | } | ||
9966 | #endif | ||
9954 | while (1) { | 9967 | while (1) { |
9955 | int opt = getopt(argc, argv, "+c:exinsl" | 9968 | int opt = getopt(argc, argv, "+c:exinsl" |
9956 | #if !BB_MMU | 9969 | #if !BB_MMU |
@@ -9974,6 +9987,9 @@ int hush_main(int argc, char **argv) | |||
9974 | * Note: the form without ARG0 never happens: | 9987 | * Note: the form without ARG0 never happens: |
9975 | * sh ... -c 'builtin' BARGV... "" | 9988 | * sh ... -c 'builtin' BARGV... "" |
9976 | */ | 9989 | */ |
9990 | #if NUM_SCRIPTS > 0 | ||
9991 | run_script: | ||
9992 | #endif | ||
9977 | if (!G.root_pid) { | 9993 | if (!G.root_pid) { |
9978 | G.root_pid = getpid(); | 9994 | G.root_pid = getpid(); |
9979 | G.root_ppid = getppid(); | 9995 | G.root_ppid = getppid(); |
diff --git a/testsuite/echo/echo-prints-dash b/testsuite/echo/echo-prints-dash index ddcdbadf7..f1f31a034 100644 --- a/testsuite/echo/echo-prints-dash +++ b/testsuite/echo/echo-prints-dash | |||
@@ -1 +1,2 @@ | |||
1 | # FEATURE: CONFIG_DESKTOP | ||
1 | test "`busybox echo - | od -t x1 | head -n 1`" = "0000000 2d 0a" | 2 | test "`busybox echo - | od -t x1 | head -n 1`" = "0000000 2d 0a" |
diff --git a/testsuite/echo/echo-prints-non-opts b/testsuite/echo/echo-prints-non-opts index c7d1e201a..4e642a143 100644 --- a/testsuite/echo/echo-prints-non-opts +++ b/testsuite/echo/echo-prints-non-opts | |||
@@ -1 +1,2 @@ | |||
1 | # FEATURE: CONFIG_DESKTOP | ||
1 | test "`busybox echo -neEZ | od -t x1 | head -n 1`" = "0000000 2d 6e 65 45 5a 0a" | 2 | test "`busybox echo -neEZ | od -t x1 | head -n 1`" = "0000000 2d 6e 65 45 5a 0a" |
diff --git a/testsuite/echo/echo-prints-slash-zero b/testsuite/echo/echo-prints-slash-zero index d97ed8e66..948f899da 100644 --- a/testsuite/echo/echo-prints-slash-zero +++ b/testsuite/echo/echo-prints-slash-zero | |||
@@ -1,3 +1,3 @@ | |||
1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO | 1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO CONFIG_DESKTOP |
2 | 2 | ||
3 | test "`busybox echo -e -n 'msg\n\0' | od -t x1 | head -n 1`" = "0000000 6d 73 67 0a 00" | 3 | test "`busybox echo -e -n 'msg\n\0' | od -t x1 | head -n 1`" = "0000000 6d 73 67 0a 00" |
diff --git a/testsuite/echo/echo-prints-slash_00041 b/testsuite/echo/echo-prints-slash_00041 index 9cffabde0..7ea217bc5 100644 --- a/testsuite/echo/echo-prints-slash_00041 +++ b/testsuite/echo/echo-prints-slash_00041 | |||
@@ -1,3 +1,3 @@ | |||
1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO | 1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO CONFIG_DESKTOP |
2 | 2 | ||
3 | test "`busybox echo -ne '\00041z' | od -t x1 | head -n 1`" = "0000000 04 31 7a" | 3 | test "`busybox echo -ne '\00041z' | od -t x1 | head -n 1`" = "0000000 04 31 7a" |
diff --git a/testsuite/echo/echo-prints-slash_0041 b/testsuite/echo/echo-prints-slash_0041 index b07429dfd..941faca08 100644 --- a/testsuite/echo/echo-prints-slash_0041 +++ b/testsuite/echo/echo-prints-slash_0041 | |||
@@ -1,3 +1,3 @@ | |||
1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO | 1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO CONFIG_DESKTOP |
2 | 2 | ||
3 | test "`busybox echo -ne '\0041z' | od -t x1 | head -n 1`" = "0000000 21 7a" | 3 | test "`busybox echo -ne '\0041z' | od -t x1 | head -n 1`" = "0000000 21 7a" |
diff --git a/testsuite/echo/echo-prints-slash_041 b/testsuite/echo/echo-prints-slash_041 index 1d70cec92..60cbfca3d 100644 --- a/testsuite/echo/echo-prints-slash_041 +++ b/testsuite/echo/echo-prints-slash_041 | |||
@@ -1,3 +1,3 @@ | |||
1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO | 1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO CONFIG_DESKTOP |
2 | 2 | ||
3 | test "`busybox echo -ne '\041z' | od -t x1 | head -n 1`" = "0000000 21 7a" | 3 | test "`busybox echo -ne '\041z' | od -t x1 | head -n 1`" = "0000000 21 7a" |
diff --git a/testsuite/echo/echo-prints-slash_41 b/testsuite/echo/echo-prints-slash_41 index 6d8999b4e..afd7c36d1 100644 --- a/testsuite/echo/echo-prints-slash_41 +++ b/testsuite/echo/echo-prints-slash_41 | |||
@@ -1,3 +1,3 @@ | |||
1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO | 1 | # FEATURE: CONFIG_FEATURE_FANCY_ECHO CONFIG_DESKTOP |
2 | 2 | ||
3 | test "`busybox echo -ne '\41z' | od -t x1 | head -n 1`" = "0000000 21 7a" | 3 | test "`busybox echo -ne '\41z' | od -t x1 | head -n 1`" = "0000000 21 7a" |
diff --git a/testsuite/printf.tests b/testsuite/printf.tests index 963ded94b..34a65926e 100755 --- a/testsuite/printf.tests +++ b/testsuite/printf.tests | |||
@@ -79,6 +79,39 @@ testing "printf understands %Ld" \ | |||
79 | "-5\n""0\n" \ | 79 | "-5\n""0\n" \ |
80 | "" "" | 80 | "" "" |
81 | 81 | ||
82 | testing "printf handles positive numbers for %d" \ | ||
83 | "${bb}printf '%d\n' 3 +3 ' 3' ' +3' 2>&1; echo \$?" \ | ||
84 | "3\n"\ | ||
85 | "3\n"\ | ||
86 | "3\n"\ | ||
87 | "3\n""0\n" \ | ||
88 | "" "" | ||
89 | |||
90 | testing "printf handles positive numbers for %i" \ | ||
91 | "${bb}printf '%i\n' 3 +3 ' 3' ' +3' 2>&1; echo \$?" \ | ||
92 | "3\n"\ | ||
93 | "3\n"\ | ||
94 | "3\n"\ | ||
95 | "3\n""0\n" \ | ||
96 | "" "" | ||
97 | |||
98 | testing "printf handles positive numbers for %x" \ | ||
99 | "${bb}printf '%x\n' 42 +42 ' 42' ' +42' 2>&1; echo \$?" \ | ||
100 | "2a\n"\ | ||
101 | "2a\n"\ | ||
102 | "2a\n"\ | ||
103 | "2a\n""0\n" \ | ||
104 | "" "" | ||
105 | |||
106 | testing "printf handles positive numbers for %f" \ | ||
107 | "${bb}printf '%0.3f\n' .42 +.42 ' .42' ' +.42' 2>&1; echo \$?" \ | ||
108 | "0.420\n"\ | ||
109 | "0.420\n"\ | ||
110 | "0.420\n"\ | ||
111 | "0.420\n""0\n" \ | ||
112 | "" "" | ||
113 | |||
114 | |||
82 | # "FIXED" now to act compatibly | 115 | # "FIXED" now to act compatibly |
83 | ## We are "more correct" here than bash/coreutils: they happily print -2 | 116 | ## We are "more correct" here than bash/coreutils: they happily print -2 |
84 | ## as if it is a huge unsigned number | 117 | ## as if it is a huge unsigned number |
diff --git a/util-linux/nologin.c b/util-linux/nologin.c new file mode 100644 index 000000000..e4b192508 --- /dev/null +++ b/util-linux/nologin.c | |||
@@ -0,0 +1,27 @@ | |||
1 | //config:config NOLOGIN | ||
2 | //config: bool "nologin" | ||
3 | //config: default n | ||
4 | //config: depends on FEATURE_SH_EMBEDDED_SCRIPTS | ||
5 | //config: help | ||
6 | //config: Politely refuse a login | ||
7 | //config: | ||
8 | //config:config NOLOGIN_DEPENDENCIES | ||
9 | //config: bool "Enable dependencies for nologin" | ||
10 | //config: default y | ||
11 | //config: depends on NOLOGIN | ||
12 | //config: select CAT | ||
13 | //config: select ECHO | ||
14 | //config: select SLEEP | ||
15 | //config: help | ||
16 | //config: nologin is implemented as a shell script. It requires the | ||
17 | //config: following in the runtime environment: | ||
18 | //config: cat echo sleep | ||
19 | //config: If you know these will be available externally you can | ||
20 | //config: disable this option. | ||
21 | |||
22 | //applet:IF_NOLOGIN(APPLET_SCRIPTED(nologin, scripted, BB_DIR_USR_SBIN, BB_SUID_DROP, nologin)) | ||
23 | |||
24 | //usage:#define nologin_trivial_usage | ||
25 | //usage: "" | ||
26 | //usage:#define nologin_full_usage "\n\n" | ||
27 | //usage: "Politely refuse a login" | ||