aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services/dropbear
diff options
context:
space:
mode:
Diffstat (limited to 'package/network/services/dropbear')
-rw-r--r--package/network/services/dropbear/Config.in117
-rw-r--r--package/network/services/dropbear/Makefile120
-rwxr-xr-xpackage/network/services/dropbear/files/dropbear.failsafe57
-rwxr-xr-xpackage/network/services/dropbear/files/dropbear.init340
-rw-r--r--package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch104
-rw-r--r--package/network/services/dropbear/patches/002-fix-y2038-issues.patch198
-rw-r--r--package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch25
-rw-r--r--package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch24
-rw-r--r--package/network/services/dropbear/patches/005-const-parameter-mp_int.patch123
-rw-r--r--package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch21
-rw-r--r--package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch29
-rw-r--r--package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch94
-rw-r--r--package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch27
-rw-r--r--package/network/services/dropbear/patches/010-remove-SO_LINGER.patch39
-rw-r--r--package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch147
-rw-r--r--package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch50
-rw-r--r--package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch74
-rw-r--r--package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch60
-rw-r--r--package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch121
-rw-r--r--package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch35
-rw-r--r--package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch32
-rw-r--r--package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch33
-rw-r--r--package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch34
-rw-r--r--package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch33
-rw-r--r--package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch216
-rw-r--r--package/network/services/dropbear/patches/100-pubkey_path.patch116
-rw-r--r--package/network/services/dropbear/patches/110-change_user.patch2
-rw-r--r--package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch14
-rw-r--r--package/network/services/dropbear/patches/140-disable_assert.patch2
-rw-r--r--package/network/services/dropbear/patches/160-lto-jobserver.patch4
-rw-r--r--package/network/services/dropbear/patches/600-allow-blank-root-password.patch2
-rw-r--r--package/network/services/dropbear/patches/900-configure-hardening.patch35
-rw-r--r--package/network/services/dropbear/patches/901-bundled-libs-cflags.patch71
-rw-r--r--package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch16
34 files changed, 2150 insertions, 265 deletions
diff --git a/package/network/services/dropbear/Config.in b/package/network/services/dropbear/Config.in
index 15000eff53e..7ffe7684d4a 100644
--- a/package/network/services/dropbear/Config.in
+++ b/package/network/services/dropbear/Config.in
@@ -12,7 +12,6 @@ config DROPBEAR_CURVE25519
config DROPBEAR_ECC
bool "Elliptic curve cryptography (ECC)"
- default n
help
Enables basic support for elliptic curve cryptography (ECC)
in key exchange and public key authentication.
@@ -25,11 +24,10 @@ config DROPBEAR_ECC
Increases binary size by about 24 kB (MIPS).
- If full ECC support is required, also select DROPBEAR_ECC_FULL.
+ Note: select DROPBEAR_ECC_FULL if full ECC support is required.
config DROPBEAR_ECC_FULL
bool "Elliptic curve cryptography (ECC), full support"
- default n
depends on DROPBEAR_ECC
help
Enables full support for elliptic curve cryptography (ECC)
@@ -67,41 +65,62 @@ config DROPBEAR_CHACHA20POLY1305
Increases binary size by about 4 kB (MIPS).
+config DROPBEAR_U2F
+ bool "U2F/FIDO support"
+ default y
+ help
+ This option itself doesn't enable any support for U2F/FIDO
+ but subordinate options do:
+
+ - DROPBEAR_ECDSA_SK - ecdsa-sk keys support
+ depends on DROPBEAR_ECC ("Elliptic curve cryptography (ECC)")
+ - DROPBEAR_ED25519_SK - ed25519-sk keys support
+ depends on DROPBEAR_ED25519 ("Ed25519 support")
+
+config DROPBEAR_ECDSA_SK
+ bool "ECDSA-SK support"
+ default y
+ depends on DROPBEAR_U2F && DROPBEAR_ECC
+ help
+ This enables the following public key algorithm:
+ sk-ecdsa-sha2-nistp256@openssh.com
+
+config DROPBEAR_ED25519_SK
+ bool "Ed25519-SK support"
+ default y
+ depends on DROPBEAR_U2F && DROPBEAR_ED25519
+ help
+ This enables the following public key algorithm:
+ sk-ssh-ed25519@openssh.com
+
config DROPBEAR_ZLIB
bool "Enable compression"
- default n
help
Enables compression using shared zlib library.
- Increases binary size by about 0.1 kB (MIPS) and requires additional 62 kB (MIPS)
- for a shared zlib library.
+ Increases binary size by about 0.1 kB (MIPS) and requires
+ additional 62 kB (MIPS) for a shared zlib library.
config DROPBEAR_UTMP
bool "Utmp support"
- default n
depends on BUSYBOX_CONFIG_FEATURE_UTMP
help
- This enables dropbear utmp support, the file /var/run/utmp is used to
- track who is currently logged in.
+ This enables dropbear utmp support, the file /var/run/utmp is
+ used to track who is currently logged in.
config DROPBEAR_PUTUTLINE
bool "Pututline support"
- default n
depends on DROPBEAR_UTMP
help
- Dropbear will use pututline() to write the utmp structure into the utmp file.
+ Dropbear will use pututline() to write the utmp structure into
+ the utmp file.
config DROPBEAR_DBCLIENT
bool "Build dropbear with dbclient"
default y
-config DROPBEAR_SCP
- bool "Build dropbear with scp"
- default y
-
config DROPBEAR_ASKPASS
bool "Enable askpass helper support"
- default n
depends on DROPBEAR_DBCLIENT
help
This enables support for ssh-askpass helper in dropbear client
@@ -109,4 +128,70 @@ config DROPBEAR_ASKPASS
Increases binary size by about 0.1 kB (MIPS).
+config DROPBEAR_DBCLIENT_AGENTFORWARD
+ bool "Enable agent forwarding in dbclient [LEGACY/SECURITY]"
+ default y
+ depends on DROPBEAR_DBCLIENT
+ help
+ Increases binary size by about 0.1 kB (MIPS).
+
+ Security notes:
+
+ SSH agent forwarding might cause security issues (locally and
+ on the jump machine).
+
+ Hovewer, it's enabled by default for compatibility with
+ previous OpenWrt/dropbear releases.
+
+ Consider DISABLING this option if you're building own OpenWrt
+ image.
+
+ Also see DROPBEAR_AGENTFORWARD (agent forwarding in dropbear
+ server itself).
+
+config DROPBEAR_SCP
+ bool "Build dropbear with scp"
+ default y
+
+config DROPBEAR_AGENTFORWARD
+ bool "Enable agent forwarding [LEGACY/SECURITY]"
+ default y
+ help
+ Increases binary size by about 0.1 kB (MIPS).
+
+ Security notes:
+
+ SSH agent forwarding might cause security issues (locally and
+ on the jump machine).
+
+ Hovewer, it's enabled by default for compatibility with
+ previous OpenWrt/dropbear releases.
+
+ Consider DISABLING this option if you're building own OpenWrt
+ image.
+
+ Also see DROPBEAR_DBCLIENT_AGENTFORWARD (agent forwarding in
+ dropbear client) if DROPBEAR_DBCLIENT is selected.
+
+config DROPBEAR_MODERN_ONLY
+ bool "Use modern crypto only [BREAKS COMPATIBILITY]"
+ select DROPBEAR_ED25519
+ select DROPBEAR_CURVE25519
+ select DROPBEAR_CHACHA20POLY1305
+ help
+ This option enables:
+ - Chacha20-Poly1305
+ - Curve25519
+ - Ed25519
+ and disables:
+ - AES
+ - RSA
+ - SHA1
+
+ Reduces binary size by about 64 kB (MIPS) from default
+ configuration.
+
+ Consider enabling this option if you're building own OpenWrt
+ image and using modern SSH software everywhere.
+
endmenu
diff --git a/package/network/services/dropbear/Makefile b/package/network/services/dropbear/Makefile
index 77887f39db1..2d7ce75b8d0 100644
--- a/package/network/services/dropbear/Makefile
+++ b/package/network/services/dropbear/Makefile
@@ -8,14 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dropbear
-PKG_VERSION:=2020.81
-PKG_RELEASE:=2
+PKG_VERSION:=2022.83
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
- http://matt.ucc.asn.au/dropbear/releases/ \
+ https://matt.ucc.asn.au/dropbear/releases/ \
https://dropbear.nl/mirror/releases/
-PKG_HASH:=48235d10b37775dbda59341ac0c4b239b82ad6318c31568b985730c788aac53b
+PKG_HASH:=bc5a121ffbc94b5171ad5ebe01be42746d50aa797c9549a4639894a16749443b
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE libtomcrypt/LICENSE libtommath/LICENSE
@@ -23,7 +23,7 @@ PKG_CPE_ID:=cpe:/a:matt_johnston:dropbear_ssh_server
PKG_BUILD_PARALLEL:=1
PKG_ASLR_PIE_REGULAR:=1
-PKG_USE_MIPS16:=0
+PKG_BUILD_FLAGS:=no-mips16 gc-sections lto
PKG_FIXUP:=autoreconf
PKG_FLAGS:=nonshared
@@ -31,8 +31,11 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_TARGET_INIT_PATH CONFIG_DROPBEAR_ECC CONFIG_DROPBEAR_ECC_FULL \
CONFIG_DROPBEAR_CURVE25519 CONFIG_DROPBEAR_ZLIB \
CONFIG_DROPBEAR_ED25519 CONFIG_DROPBEAR_CHACHA20POLY1305 \
+ CONFIG_DROPBEAR_U2F CONFIG_DROPBEAR_ECDSA_SK CONFIG_DROPBEAR_ED25519_SK \
CONFIG_DROPBEAR_UTMP CONFIG_DROPBEAR_PUTUTLINE \
- CONFIG_DROPBEAR_DBCLIENT CONFIG_DROPBEAR_SCP CONFIG_DROPBEAR_ASKPASS
+ CONFIG_DROPBEAR_DBCLIENT CONFIG_DROPBEAR_SCP CONFIG_DROPBEAR_ASKPASS \
+ CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD CONFIG_DROPBEAR_AGENTFORWARD \
+ CONFIG_DROPBEAR_MODERN_ONLY
include $(INCLUDE_DIR)/package.mk
@@ -41,7 +44,7 @@ ifneq ($(DUMP),1)
endif
define Package/dropbear/Default
- URL:=http://matt.ucc.asn.au/dropbear/
+ URL:=https://matt.ucc.asn.au/dropbear/
endef
define Package/dropbear/config
@@ -67,10 +70,11 @@ define Package/dropbear/description
endef
define Package/dropbear/conffiles
-$(if $(CONFIG_DROPBEAR_ED25519),/etc/dropbear/dropbear_ed25519_host_key)
-$(if $(CONFIG_DROPBEAR_ECC),/etc/dropbear/dropbear_ecdsa_host_key)
-/etc/dropbear/dropbear_rsa_host_key
/etc/config/dropbear
+/etc/dropbear/authorized_keys
+/etc/dropbear/dropbear_ecdsa_host_key
+/etc/dropbear/dropbear_ed25519_host_key
+/etc/dropbear/dropbear_rsa_host_key
endef
define Package/dropbearconvert
@@ -98,78 +102,100 @@ CONFIGURE_ARGS += \
##############################################################################
#
-# option|value - add option to localoptions.h
-# !!option|value - replace option in sysoptions.h
+# option,value - add option to localoptions.h
+# !!option,value - replace option in sysoptions.h
#
##############################################################################
+# adjust allowed shell list (if getusershell(3) is missing):
+# - COMPAT_USER_SHELLS
# remove protocol idented software version number:
# - LOCAL_IDENT
# disable legacy/unsafe methods and unused functionality:
-# - INETD_MODE
# - DROPBEAR_CLI_NETCAT
# - DROPBEAR_DSS
# - DO_MOTD
+# - DROPBEAR_DH_GROUP14_SHA1
+# - DROPBEAR_SHA1_HMAC
DB_OPT_COMMON = \
- DEFAULT_PATH|"$(TARGET_INIT_PATH)" \
- !!LOCAL_IDENT|"SSH-2.0-dropbear" \
- INETD_MODE|0 \
- DROPBEAR_CLI_NETCAT|0 \
- DROPBEAR_DSS|0 \
- DO_MOTD|0 \
+ !!LOCAL_IDENT,"SSH-2.0-dropbear" \
+ COMPAT_USER_SHELLS,"/bin/ash","/bin/sh" \
+ DEFAULT_PATH,"$(TARGET_INIT_PATH)" \
+ DEFAULT_ROOT_PATH,"$(TARGET_INIT_PATH)" \
+ DROPBEAR_DSS,0 \
+ DROPBEAR_CLI_NETCAT,0 \
+ DO_MOTD,0 \
+ DROPBEAR_DH_GROUP14_SHA1,0 \
+ DROPBEAR_SHA1_HMAC,0 \
##############################################################################
#
-# option|config|enabled|disabled = add option to localoptions.h
-# !!option|config|enabled|disabled = replace option in sysoptions.h
+# option,config,enabled,disabled = add option to localoptions.h
+# !!option,config,enabled,disabled = replace option in sysoptions.h
#
# option := (config) ? enabled : disabled
#
##############################################################################
DB_OPT_CONFIG = \
- DROPBEAR_CURVE25519|CONFIG_DROPBEAR_CURVE25519|1|0 \
- DROPBEAR_ED25519|CONFIG_DROPBEAR_ED25519|1|0 \
- DROPBEAR_CHACHA20POLY1305|CONFIG_DROPBEAR_CHACHA20POLY1305|1|0 \
- DROPBEAR_ECDSA|CONFIG_DROPBEAR_ECC|1|0 \
- DROPBEAR_ECDH|CONFIG_DROPBEAR_ECC|1|0 \
- !!DROPBEAR_ECC_384|CONFIG_DROPBEAR_ECC_FULL|1|0 \
- !!DROPBEAR_ECC_521|CONFIG_DROPBEAR_ECC_FULL|1|0 \
- DROPBEAR_CLI_ASKPASS_HELPER|CONFIG_DROPBEAR_ASKPASS|1|0 \
-
-
-TARGET_CFLAGS += -DARGTYPE=3 -ffunction-sections -fdata-sections -flto
-TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver
+ !!DROPBEAR_ECC_384,CONFIG_DROPBEAR_ECC_FULL,1,0 \
+ !!DROPBEAR_ECC_521,CONFIG_DROPBEAR_ECC_FULL,1,0 \
+ DROPBEAR_CURVE25519,CONFIG_DROPBEAR_CURVE25519,1,0 \
+ DROPBEAR_CHACHA20POLY1305,CONFIG_DROPBEAR_CHACHA20POLY1305,1,0 \
+ DROPBEAR_ED25519,CONFIG_DROPBEAR_ED25519,1,0 \
+ DROPBEAR_ECDSA,CONFIG_DROPBEAR_ECC,1,0 \
+ DROPBEAR_ECDH,CONFIG_DROPBEAR_ECC,1,0 \
+ DROPBEAR_SK_KEYS,CONFIG_DROPBEAR_U2F,1,0 \
+ DROPBEAR_SK_ECDSA,CONFIG_DROPBEAR_ECDSA_SK,1,0 \
+ DROPBEAR_SK_ED25519,CONFIG_DROPBEAR_ED25519_SK,1,0 \
+ DROPBEAR_CLI_ASKPASS_HELPER,CONFIG_DROPBEAR_ASKPASS,1,0 \
+ DROPBEAR_CLI_AGENTFWD,CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD,1,0 \
+ DROPBEAR_SVR_AGENTFWD,CONFIG_DROPBEAR_AGENTFORWARD,1,0 \
+ DROPBEAR_AES128,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_AES256,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_ENABLE_CTR_MODE,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_RSA,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+ DROPBEAR_RSA_SHA1,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
+
+
+TARGET_CFLAGS += -DARGTYPE=3
+
+xsedx:=$(shell printf '\027')
db_opt_add =echo '\#define $(1) $(2)' >> $(PKG_BUILD_DIR)/localoptions.h
-db_opt_replace =$(ESED) 's,^(\#define $(1)) .*$$$$,\1 $(2),g' $(PKG_BUILD_DIR)/sysoptions.h
+db_opt_replace =$(ESED) '/^\#define $(1) .*$$$$/{h;:a;$$$$!n;/^\#.+$$$$/bb;/^$$$$/bb;H;ba;:b;x;s$(xsedx)^.+$$$$$(xsedx)\#define $(1) $(2)$(xsedx)p;x};p' -n $(PKG_BUILD_DIR)/sysoptions.h
define Build/Configure/dropbear_headers
$(strip $(foreach s,$(DB_OPT_COMMON), \
- $(if $(filter !!%,$(word 1,$(subst |, ,$(s)))), \
- $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst |, ,$(s)))),$(word 2,$(subst |, ,$(s)))), \
- $(call db_opt_add,$(word 1,$(subst |, ,$(s))),$(word 2,$(subst |, ,$(s)))) \
+ $(if $(filter !!%,$(word 1,$(subst $(comma),$(space),$(s)))), \
+ $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst $(comma),$(space),$(s)))),$(subst $(space),$(comma),$(wordlist 2,$(words $(subst $(comma),$(space),$(s))),$(subst $(comma),$(space),$(s))))), \
+ $(call db_opt_add,$(word 1,$(subst $(comma),$(space),$(s))),$(subst $(space),$(comma),$(wordlist 2,$(words $(subst $(comma),$(space),$(s))),$(subst $(comma),$(space),$(s))))) \
) ; \
))
$(strip $(foreach s,$(DB_OPT_CONFIG), \
- $(if $(filter !!%,$(word 1,$(subst |, ,$(s)))), \
- $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst |, ,$(s)))),$(if $($(word 2,$(subst |, ,$(s)))),$(word 3,$(subst |, ,$(s))),$(word 4,$(subst |, ,$(s))))), \
- $(call db_opt_add,$(word 1,$(subst |, ,$(s))),$(if $($(word 2,$(subst |, ,$(s)))),$(word 3,$(subst |, ,$(s))),$(word 4,$(subst |, ,$(s))))) \
+ $(if $(filter !!%,$(word 1,$(subst $(comma),$(space),$(s)))), \
+ $(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst $(comma),$(space),$(s)))),$(if $($(word 2,$(subst $(comma),$(space),$(s)))),$(word 3,$(subst $(comma),$(space),$(s))),$(word 4,$(subst $(comma),$(space),$(s))))), \
+ $(call db_opt_add,$(word 1,$(subst $(comma),$(space),$(s))),$(if $($(word 2,$(subst $(comma),$(space),$(s)))),$(word 3,$(subst $(comma),$(space),$(s))),$(word 4,$(subst $(comma),$(space),$(s))))) \
) ; \
))
endef
-define Build/Configure
- : > $(PKG_BUILD_DIR)/localoptions.h
+define Build/Configure/dropbear_objects
+ grep -ERZl -e '($(subst $(space),|,$(strip $(sort $(patsubst !!%,%,$(foreach s,$(DB_OPT_COMMON) $(DB_OPT_CONFIG),$(word 1,$(subst $(comma),$(space),$(s)))))))))' \
+ $(PKG_BUILD_DIR)/ | sed -zE 's/^(.+)\.[^.]+$$$$/\1.o/' | sort -uV | xargs -0 -r rm -fv || :
+endef
+define Build/Configure
+ rm -f $(PKG_BUILD_DIR)/localoptions.h
$(Build/Configure/Default)
+ : > $(PKG_BUILD_DIR)/localoptions.h
$(Build/Configure/dropbear_headers)
- # Enforce rebuild of svr-chansession.c
- rm -f $(PKG_BUILD_DIR)/svr-chansession.o
+ # Enforce rebuild of files depending on configured options
+ $(Build/Configure/dropbear_objects)
# Rebuild them on config change
+$(MAKE) -C $(PKG_BUILD_DIR)/libtomcrypt clean
@@ -179,10 +205,12 @@ endef
define Build/Compile
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
+ IGNORE_SPEED=1 \
PROGRAMS="dropbear $(if $(CONFIG_DROPBEAR_DBCLIENT),dbclient,) dropbearkey $(if $(CONFIG_DROPBEAR_SCP),scp,)" \
MULTI=1 SCPPROGRESS=1
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
+ IGNORE_SPEED=1 \
PROGRAMS="dropbearconvert"
endef
@@ -200,9 +228,7 @@ define Package/dropbear/install
$(INSTALL_DIR) $(1)/etc/dropbear
$(INSTALL_DIR) $(1)/lib/preinit
$(INSTALL_DATA) ./files/dropbear.failsafe $(1)/lib/preinit/99_10_failsafe_dropbear
- $(if $(CONFIG_DROPBEAR_ED25519),touch $(1)/etc/dropbear/dropbear_ed25519_host_key)
- $(if $(CONFIG_DROPBEAR_ECC),touch $(1)/etc/dropbear/dropbear_ecdsa_host_key)
- touch $(1)/etc/dropbear/dropbear_rsa_host_key
+ $(foreach f,$(filter /etc/dropbear/%,$(Package/dropbear/conffiles)),$(if $(wildcard $(TOPDIR)/files/$(f)),chmod 0600 $(TOPDIR)/files/$(f) || :; ))
endef
define Package/dropbearconvert/install
diff --git a/package/network/services/dropbear/files/dropbear.failsafe b/package/network/services/dropbear/files/dropbear.failsafe
index a98ede459ad..417265babed 100755
--- a/package/network/services/dropbear/files/dropbear.failsafe
+++ b/package/network/services/dropbear/files/dropbear.failsafe
@@ -1,8 +1,61 @@
#!/bin/sh
+_dropbear()
+{
+ /usr/sbin/dropbear "$@" </dev/null >/dev/null 2>&1
+}
+
+_dropbearkey()
+{
+ /usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
+}
+
+_ensurekey()
+{
+ _dropbearkey -y -f "$1" && return
+ rm -f "$1"
+ _dropbearkey -f "$@" || {
+ rm -f "$1"
+ return 1
+ }
+}
+
+ktype_all='ed25519 ecdsa rsa'
+
failsafe_dropbear () {
- dropbearkey -t rsa -s 1024 -f /tmp/dropbear_failsafe_host_key
- dropbear -r /tmp/dropbear_failsafe_host_key <> /dev/null 2>&1
+ local kargs kcount ktype tkey
+
+ kargs=
+ kcount=0
+ for ktype in ${ktype_all} ; do
+ tkey="/tmp/dropbear_failsafe_${ktype}_host_key"
+
+ case "${ktype}" in
+ ed25519) _ensurekey "${tkey}" -t ed25519 ;;
+ ecdsa) _ensurekey "${tkey}" -t ecdsa -s 256 ;;
+ rsa) _ensurekey "${tkey}" -t rsa -s 1024 ;;
+ *)
+ echo "unknown key type: ${ktype}" >&2
+ continue
+ ;;
+ esac
+
+ [ -s "${tkey}" ] || {
+ rm -f "${tkey}"
+ continue
+ }
+
+ chmod 0400 "${tkey}"
+ kargs="${kargs}${kargs:+ }-r ${tkey}"
+ kcount=$((kcount+1))
+ done
+
+ [ "${kcount}" != 0 ] || {
+ echo 'DROPBEAR IS BROKEN' >&2
+ return 1
+ }
+
+ _dropbear ${kargs}
}
boot_hook_add failsafe failsafe_dropbear
diff --git a/package/network/services/dropbear/files/dropbear.init b/package/network/services/dropbear/files/dropbear.init
index ea4cad2a8d5..21570987c43 100755
--- a/package/network/services/dropbear/files/dropbear.init
+++ b/package/network/services/dropbear/files/dropbear.init
@@ -12,28 +12,52 @@ PIDCOUNT=0
extra_command "killclients" "Kill ${NAME} processes except servers and yourself"
+# most of time real_stat() will be failing
+# due to missing "stat" binary (by default)
+real_stat() { env stat -L "$@" 2>/dev/null ; }
+dumb_stat() { ls -Ldln "$1" | tr -s '\t ' ' ' ; }
+stat_perm() { real_stat -c '%A' "$1" || dumb_stat "$1" | cut -d ' ' -f 1 ; }
+stat_owner() { real_stat -c '%u' "$1" || dumb_stat "$1" | cut -d ' ' -f 3 ; }
+
_dropbearkey()
{
- /usr/bin/dropbearkey "$@" 0<&- 1>&- 2>&-
+ /usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
}
-# $1 - host key file name
-hk_verify()
+# $1 - file name (host key or config)
+file_verify()
{
[ -f "$1" ] || return 1
- [ -s "$1" ] || return 2
- _dropbearkey -y -f "$1" || return 3
+ # checking file ownership
+ [ "$(stat_owner "$1")" = "0" ] || {
+ chown 0 "$1"
+ [ "$(stat_owner "$1")" = "0" ] || return 2
+ }
+ # checking file permissions
+ [ "$(stat_perm "$1")" = "-rw-------" ] || {
+ chmod 0600 "$1"
+ [ "$(stat_perm "$1")" = "-rw-------" ] || return 3
+ }
+ # file is host key or not?
+ # if $2 is empty string - file is "host key"
+ # if $2 is non-empty string - file is "config"
+ [ -z "$2" ] || return 0
+ # checking file contents (finally)
+ [ -s "$1" ] || return 4
+ _dropbearkey -y -f "$1" || return 5
return 0
}
-# $1 - hk_verify() return code
-hk_errmsg()
+# $1 - file_verify() return code
+file_errmsg()
{
case "$1" in
0) ;;
1) echo "file does not exist" ;;
- 2) echo "file has zero length" ;;
- 3) echo "file is not valid host key or not supported" ;;
+ 2) echo "file has wrong owner (must be owned by root)" ;;
+ 3) echo "file has wrong permissions (must not have group/other write bit)" ;;
+ 4) echo "file has zero length" ;;
+ 5) echo "file is not valid host key or not supported" ;;
*) echo "unknown error" ;;
esac
}
@@ -43,73 +67,97 @@ hk_errmsg()
hk_config()
{
local x m
- hk_verify "$2"; x=$?
- case "$x" in
- 0) procd_append_param command -r "$2"
- ;;
- *) m=$(hk_errmsg "$x")
- logger -t "${NAME}" -p daemon.warn \
- "option '$1', value '$2': $m, skipping"
- ;;
- esac
+ file_verify "$2" ; x=$?
+ if [ "$x" = 0 ] ; then
+ procd_append_param command -r "$2"
+ return
+ fi
+ m=$(file_errmsg "$x")
+ logger -s -t "${NAME}" -p daemon.warn \
+ "Option '$1', skipping '$2': $m"
}
# $1 - host key file name
-hk_config__keyfile()
-{
- hk_config 'keyfile' "$1"
-}
+hk_config__keyfile() { hk_config keyfile "$1" ; }
+
+ktype_all='ed25519 ecdsa rsa'
hk_generate_as_needed()
{
- local kdir kgen ktype tdir kcount tfile
- kdir='/etc/dropbear'
+ local hk_cfg_dir kgen ktype kfile hk_tmp_dir
+ hk_cfg_dir='/etc/dropbear'
+
+ [ -d "${hk_cfg_dir}" ] || mkdir -p "${hk_cfg_dir}"
+
+ kgen=
+ for ktype in ${ktype_all} ; do
+ kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
- kgen=''
- for ktype in ed25519 ecdsa rsa; do
- hk_verify "${kdir}/dropbear_${ktype}_host_key" && continue
+ if file_verify "${kfile}" ; then continue ; fi
- kgen="${kgen} ${ktype}"
+ kgen="${kgen}${kgen:+ }${ktype}"
done
- [ -z "${kgen}" ] && return
+ # all keys are sane?
+ [ -n "${kgen}" ] || return 0
- tdir=$(mktemp -d); chmod 0700 "${tdir}"
+ hk_tmp_dir=$(mktemp -d)
+ # system in bad state?
+ [ -n "${hk_tmp_dir}" ] || return 1
- kcount=0
- for ktype in ${kgen}; do
- tfile="${tdir}/dropbear_${ktype}_host_key"
+ chmod 0700 "${hk_tmp_dir}"
- if ! _dropbearkey -t ${ktype} -f "${tfile}"; then
+ for ktype in ${kgen} ; do
+ kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
+
+ if ! _dropbearkey -t ${ktype} -f "${kfile}" ; then
# unsupported key type
- rm -f "${tfile}"
+ rm -f "${kfile}"
continue
fi
- kcount=$((kcount+1))
+ chmod 0600 "${kfile}"
done
- if [ ${kcount} -ne 0 ]; then
- mkdir -p "${kdir}"; chmod 0700 "${kdir}"; chown root "${kdir}"
- mv -f "${tdir}/"* "${kdir}/"
+ kgen=
+ for ktype in ${ktype_all} ; do
+ kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
+
+ [ -s "${kfile}" ] || continue
+
+ kgen="${kgen}${kgen:+ }${ktype}"
+ done
+
+ if [ -n "${kgen}" ] ; then
+ for ktype in ${kgen} ; do
+ kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
+ [ -s "${kfile}" ] || continue
+ mv -f "${kfile}" "${hk_cfg_dir}/"
+ done
fi
- rm -rf "${tdir}"
+ rm -rf "${hk_tmp_dir}"
+
+ # cleanup empty files
+ for ktype in ${ktype_all} ; do
+ kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
+
+ [ -s "${kfile}" ] || rm -f "${kfile}"
+ done
}
-append_ports()
+# $1 - list with whitespace-separated elements
+normalize_list()
{
- local ipaddrs="$1"
- local port="$2"
-
- [ -z "$ipaddrs" ] && {
- procd_append_param command -p "$port"
- return
- }
+ printf '%s' "$1" | tr -s ' \r\n\t' ' ' | sed -E 's/^ //;s/ $//'
+}
- for addr in $ipaddrs; do
- procd_append_param command -p "$addr:$port"
- done
+warn_multiple_interfaces()
+{
+ logger -t "${NAME}" -p daemon.warn \
+ "Option '$1' should specify SINGLE interface but instead it lists interfaces: $2"
+ logger -t "${NAME}" -p daemon.warn \
+ "Consider creating per-interface instances instead!"
}
validate_section_dropbear()
@@ -117,8 +165,10 @@ validate_section_dropbear()
uci_load_validate dropbear dropbear "$1" "$2" \
'PasswordAuth:bool:1' \
'enable:bool:1' \
+ 'DirectInterface:string' \
'Interface:string' \
'GatewayPorts:bool:0' \
+ 'ForceCommand:string' \
'RootPasswordAuth:bool:1' \
'RootLogin:bool:1' \
'rsakeyfile:file' \
@@ -128,52 +178,181 @@ validate_section_dropbear()
'SSHKeepAlive:uinteger:300' \
'IdleTimeout:uinteger:0' \
'MaxAuthTries:uinteger:3' \
- 'RecvWindowSize:uinteger:0' \
+ 'RecvWindowSize:uinteger:262144' \
'mdns:bool:1'
}
dropbear_instance()
{
- local ipaddrs
-
[ "$2" = 0 ] || {
echo "validation failed"
return 1
}
- [ -n "${Interface}" ] && {
- [ -n "${BOOT}" ] && return 0
+ [ "${enable}" = "1" ] || return 1
- network_get_ipaddrs_all ipaddrs "${Interface}" || {
- echo "interface ${Interface} has no physdev or physdev has no suitable ip"
- return 1
- }
- }
+ local iface ndev ipaddrs
+
+ # 'DirectInterface' should specify single interface
+ # but end users may misinterpret this setting
+ DirectInterface=$(normalize_list "${DirectInterface}")
+
+ # 'Interface' should specify single interface
+ # but end users are often misinterpret this setting
+ Interface=$(normalize_list "${Interface}")
+
+ if [ -n "${Interface}" ] ; then
+ if [ -n "${DirectInterface}" ] ; then
+ logger -t "${NAME}" -p daemon.warn \
+ "Option 'DirectInterface' takes precedence over 'Interface'"
+ else
+ logger -t "${NAME}" -p daemon.info \
+ "Option 'Interface' binds to address(es) but not to interface"
+ logger -t "${NAME}" -p daemon.info \
+ "Consider using option 'DirectInterface' to bind directly to interface"
+ fi
+ fi
+
+ # handle 'DirectInterface'
+ iface=$(echo "${DirectInterface}" | awk '{print $1}')
+ case "${DirectInterface}" in
+ *\ *)
+ warn_multiple_interfaces DirectInterface "${DirectInterface}"
+ logger -t "${NAME}" -p daemon.warn \
+ "Using network interface '${iface}' for direct binding"
+ ;;
+ esac
+ while [ -n "${iface}" ] ; do
+ # if network is available (even during boot) - proceed
+ if network_is_up "${iface}" ; then break ; fi
+ # skip during boot
+ [ -z "${BOOT}" ] || return 0
+
+ logger -t "${NAME}" -p daemon.crit \
+ "Network interface '${iface}' is not available!"
+ return 1
+ done
+ while [ -n "${iface}" ] ; do
+ # ${iface} is logical (higher level) interface name
+ # ${ndev} is 'real' interface name
+ # e.g.: if ${iface} is 'lan' (default LAN interface) then ${ndev} is 'br-lan'
+ network_get_device ndev "${iface}"
+ [ -z "${ndev}" ] || break
+
+ logger -t "${NAME}" -p daemon.crit \
+ "Missing network device for network interface '${iface}'!"
+ return 1
+ done
+ if [ -n "${iface}" ] ; then
+ logger -t "${NAME}" -p daemon.info \
+ "Using network interface '${iface}' (network device '${ndev}') for direct binding"
+ fi
+ # handle 'Interface'
+ while [ -z "${iface}" ] ; do
+ [ -n "${Interface}" ] || break
+
+ # skip during boot
+ [ -z "${BOOT}" ] || return 0
+
+ case "${Interface}" in
+ *\ *)
+ warn_multiple_interfaces Interface "${Interface}"
+ ;;
+ esac
+
+ local c=0
+ # sysoptions.h
+ local DROPBEAR_MAX_PORTS=10
+
+ local a n if_ipaddrs
+ for n in ${Interface} ; do
+ [ -n "$n" ] || continue
+
+ if_ipaddrs=
+ network_get_ipaddrs_all if_ipaddrs "$n"
+ [ -n "${if_ipaddrs}" ] || {
+ logger -s -t "${NAME}" -p daemon.err \
+ "Network interface '$n' has no suitable IP address(es)!"
+ continue
+ }
+
+ [ $c -le ${DROPBEAR_MAX_PORTS} ] || {
+ logger -s -t "${NAME}" -p daemon.err \
+ "Network interface '$n' is NOT listened due to option limit exceed!"
+ continue
+ }
+
+ for a in ${if_ipaddrs} ; do
+ [ -n "$a" ] || continue
+
+ c=$((c+1))
+ if [ $c -le ${DROPBEAR_MAX_PORTS} ] ; then
+ ipaddrs="${ipaddrs} $a"
+ continue
+ fi
+
+ logger -t "${NAME}" -p daemon.err \
+ "Endpoint '$a:${Port}' on network interface '$n' is NOT listened due to option limit exceed!"
+ done
+ done
+ break
+ done
- [ "${enable}" = "0" ] && return 1
PIDCOUNT="$(( ${PIDCOUNT} + 1))"
local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid"
procd_open_instance
procd_set_param command "$PROG" -F -P "$pid_file"
+ if [ -n "${iface}" ] ; then
+ # if ${iface} is non-empty then ${ndev} is non-empty too
+ procd_append_param command -l "${ndev}" -p "${Port}"
+ else
+ if [ -z "${ipaddrs}" ] ; then
+ procd_append_param command -p "${Port}"
+ else
+ local a
+ for a in ${ipaddrs} ; do
+ [ -n "$a" ] || continue
+ procd_append_param command -p "$a:${Port}"
+ done
+ fi
+ fi
[ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s
[ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a
+ [ -n "${ForceCommand}" ] && procd_append_param command -c "${ForceCommand}"
[ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g
[ "${RootLogin}" -eq 0 ] && procd_append_param command -w
+ config_list_foreach "$1" 'keyfile' hk_config__keyfile
if [ -n "${rsakeyfile}" ]; then
- logger -t ${NAME} -p daemon.warn \
- "option 'rsakeyfile' is considered to be deprecated and" \
- "will be removed in future releases, use 'keyfile' instead"
+ logger -s -t "${NAME}" -p daemon.crit \
+ "Option 'rsakeyfile' is considered to be DEPRECATED and will be REMOVED in future releases, use 'keyfile' list instead"
+ sed -i.before-upgrade -E -e 's/option(\s+)rsakeyfile/list keyfile/' \
+ "/etc/config/${NAME}"
+ logger -s -t "${NAME}" -p daemon.crit \
+ "Auto-transition 'option rsakeyfile' => 'list keyfile' in /etc/config/${NAME} is done, please verify your configuration"
hk_config 'rsakeyfile' "${rsakeyfile}"
fi
- config_list_foreach "$1" "keyfile" hk_config__keyfile
[ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}"
- append_ports "${ipaddrs}" "${Port}"
[ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}"
[ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}"
[ "${MaxAuthTries}" -ne 0 ] && procd_append_param command -T "${MaxAuthTries}"
- [ "${RecvWindowSize}" -gt 0 -a "${RecvWindowSize}" -le 1048576 ] && \
+ [ "${RecvWindowSize}" -gt 0 ] && {
+ # NB: OpenWrt increases receive window size to increase throughput on high latency links
+ # ref: validate_section_dropbear()
+ # default receive window size is 24576 (DEFAULT_RECV_WINDOW in default_options.h)
+
+ # sysoptions.h
+ local MAX_RECV_WINDOW=10485760
+ if [ "${RecvWindowSize}" -gt ${MAX_RECV_WINDOW} ] ; then
+ # separate logging is required because syslog misses dropbear's message
+ # Bad recv window '${RecvWindowSize}', using ${MAX_RECV_WINDOW}
+ # it's probably dropbear issue but we should handle this and notify user
+ logger -s -t "${NAME}" -p daemon.warn \
+ "Option 'RecvWindowSize' is too high (${RecvWindowSize}), limiting to ${MAX_RECV_WINDOW}"
+ RecvWindowSize=${MAX_RECV_WINDOW}
+ fi
procd_append_param command -W "${RecvWindowSize}"
+ }
[ "${mdns}" -ne 0 ] && procd_add_mdns "ssh" "tcp" "$Port" "daemon=dropbear"
procd_set_param respawn
procd_close_instance
@@ -181,10 +360,21 @@ dropbear_instance()
load_interfaces()
{
- config_get interface "$1" Interface
+ local enable
config_get enable "$1" enable 1
-
- [ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}"
+ [ "${enable}" = "1" ] || return 0
+
+ local direct_iface iface
+ config_get direct_iface "$1" DirectInterface
+ direct_iface=$(normalize_list "${direct_iface}")
+ # 'DirectInterface' takes precedence over 'Interface'
+ if [ -n "${direct_iface}" ] ; then
+ iface=$(echo "${direct_iface}" | awk '{print $1}')
+ else
+ config_get iface "$1" Interface
+ iface=$(normalize_list "${iface}")
+ fi
+ interfaces="${interfaces} ${iface}"
}
boot()
@@ -196,6 +386,7 @@ boot()
start_service()
{
hk_generate_as_needed
+ file_verify /etc/dropbear/authorized_keys config
. /lib/functions.sh
. /lib/functions/network.sh
@@ -208,13 +399,14 @@ service_triggers()
{
local interfaces
- procd_add_config_trigger "config.change" "dropbear" /etc/init.d/dropbear reload
+ procd_add_config_trigger "config.change" "${NAME}" /etc/init.d/dropbear reload
config_load "${NAME}"
- config_foreach load_interfaces dropbear
+ config_foreach load_interfaces "${NAME}"
[ -n "${interfaces}" ] && {
- for n in $interfaces ; do
+ local n
+ for n in $(printf '%s\n' ${interfaces} | sort -u) ; do
procd_add_interface_trigger "interface.*" $n /etc/init.d/dropbear reload
done
}
diff --git a/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch b/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch
new file mode 100644
index 00000000000..ad1a20c520f
--- /dev/null
+++ b/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch
@@ -0,0 +1,104 @@
+From 36a03132634a17c667c0fac0a8e1519b3d1b71c6 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 28 Nov 2022 21:12:23 +0800
+Subject: Add #if DROPBEAR_RSA guards
+
+Fixes building with DROPBEAR_RSA disabled.
+Closes #197
+---
+ signkey.c | 8 +++++++-
+ signkey.h | 2 ++
+ sysoptions.h | 5 +----
+ 3 files changed, 10 insertions(+), 5 deletions(-)
+
+--- a/signkey.c
++++ b/signkey.c
+@@ -120,6 +120,7 @@ enum signkey_type signkey_type_from_name
+ /* Special case for rsa-sha2-256. This could be generalised if more
+ signature names are added that aren't 1-1 with public key names */
+ const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA256
+ if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
+ if (namelen) {
+@@ -136,11 +137,13 @@ const char* signature_name_from_type(enu
+ return SSH_SIGNKEY_RSA;
+ }
+ #endif
++#endif /* DROPBEAR_RSA */
+ return signkey_name_from_type((enum signkey_type)type, namelen);
+ }
+
+ /* Returns DROPBEAR_SIGNATURE_NONE if none match */
+ enum signature_type signature_type_from_name(const char* name, unsigned int namelen) {
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA256
+ if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256)
+ && memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) {
+@@ -153,10 +156,11 @@ enum signature_type signature_type_from_
+ return DROPBEAR_SIGNATURE_RSA_SHA1;
+ }
+ #endif
++#endif /* DROPBEAR_RSA */
+ return (enum signature_type)signkey_type_from_name(name, namelen);
+ }
+
+-/* Returns the signature type from a key type. Must not be called
++/* Returns the signature type from a key type. Must not be called
+ with RSA keytype */
+ enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
+ #if DROPBEAR_RSA
+@@ -167,6 +171,7 @@ enum signature_type signature_type_from_
+ }
+
+ enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA256
+ if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
+ return DROPBEAR_SIGNKEY_RSA;
+@@ -177,6 +182,7 @@ enum signkey_type signkey_type_from_sign
+ return DROPBEAR_SIGNKEY_RSA;
+ }
+ #endif
++#endif /* DROPBEAR_RSA */
+ assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED);
+ return (enum signkey_type)sigtype;
+ }
+--- a/signkey.h
++++ b/signkey.h
+@@ -79,12 +79,14 @@ enum signature_type {
+ DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
+ #endif
+ #endif
++#if DROPBEAR_RSA
+ #if DROPBEAR_RSA_SHA1
+ DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
+ #endif
+ #if DROPBEAR_RSA_SHA256
+ DROPBEAR_SIGNATURE_RSA_SHA256 = 101, /* rsa-sha2-256 signature. has a ssh-rsa key */
+ #endif
++#endif /* DROPBEAR_RSA */
+ DROPBEAR_SIGNATURE_NONE = DROPBEAR_SIGNKEY_NONE,
+ };
+
+--- a/sysoptions.h
++++ b/sysoptions.h
+@@ -137,7 +137,7 @@
+
+ /* Debian doesn't define this in system headers */
+ #if !defined(LTM_DESC) && (DROPBEAR_ECC)
+-#define LTM_DESC
++#define LTM_DESC
+ #endif
+
+ #define DROPBEAR_ECC_256 (DROPBEAR_ECC)
+@@ -151,9 +151,6 @@
+ * signing operations slightly slower. */
+ #define DROPBEAR_RSA_BLINDING 1
+
+-#ifndef DROPBEAR_RSA_SHA1
+-#define DROPBEAR_RSA_SHA1 DROPBEAR_RSA
+-#endif
+ #ifndef DROPBEAR_RSA_SHA256
+ #define DROPBEAR_RSA_SHA256 DROPBEAR_RSA
+ #endif
diff --git a/package/network/services/dropbear/patches/002-fix-y2038-issues.patch b/package/network/services/dropbear/patches/002-fix-y2038-issues.patch
new file mode 100644
index 00000000000..0654e3b98b5
--- /dev/null
+++ b/package/network/services/dropbear/patches/002-fix-y2038-issues.patch
@@ -0,0 +1,198 @@
+From ec2215726cffb976019d08ebf569edd2229e9dba Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Thu, 1 Dec 2022 11:34:43 +0800
+Subject: Fix y2038 issues with time_t conversion
+
+These changes were identified by building with and without
+-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
+on 32-bit arm, logging warnings to files.
+-Wconversion was added to CFLAGS in both builds.
+
+Then a "diff -I Wconversion log1 log2" shows new warnings that appear
+with the 64-bit time_t. There are a few false positives that have been
+fixed for quietness.
+
+struct logininfo and struct wtmp are still problematic, those will
+need to be handled by libc.
+---
+ common-session.c | 43 +++++++++++++++++++++++++++----------------
+ dbutil.c | 2 +-
+ loginrec.c | 2 ++
+ loginrec.h | 4 ++--
+ runopts.h | 4 ++--
+ svr-auth.c | 2 +-
+ 6 files changed, 35 insertions(+), 22 deletions(-)
+
+--- a/common-session.c
++++ b/common-session.c
+@@ -519,15 +519,24 @@ static void send_msg_keepalive() {
+ ses.last_packet_time_idle = old_time_idle;
+ }
+
++/* Returns the difference in seconds, clamped to LONG_MAX */
++static long elapsed(time_t now, time_t prev) {
++ time_t del = now - prev;
++ if (del > LONG_MAX) {
++ return LONG_MAX;
++ }
++ return (long)del;
++}
++
+ /* Check all timeouts which are required. Currently these are the time for
+ * user authentication, and the automatic rekeying. */
+ static void checktimeouts() {
+
+ time_t now;
+ now = monotonic_now();
+-
++
+ if (IS_DROPBEAR_SERVER && ses.connect_time != 0
+- && now - ses.connect_time >= AUTH_TIMEOUT) {
++ && elapsed(now, ses.connect_time) >= AUTH_TIMEOUT) {
+ dropbear_close("Timeout before auth");
+ }
+
+@@ -537,45 +546,47 @@ static void checktimeouts() {
+ }
+
+ if (!ses.kexstate.sentkexinit
+- && (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
++ && (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT
+ || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
+ TRACE(("rekeying after timeout or max data reached"))
+ send_msg_kexinit();
+ }
+-
++
+ if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
+ /* Avoid sending keepalives prior to auth - those are
+ not valid pre-auth packet types */
+
+ /* Send keepalives if we've been idle */
+- if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
++ if (elapsed(now, ses.last_packet_time_any_sent) >= opts.keepalive_secs) {
+ send_msg_keepalive();
+ }
+
+ /* Also send an explicit keepalive message to trigger a response
+ if the remote end hasn't sent us anything */
+- if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
+- && now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
++ if (elapsed(now, ses.last_packet_time_keepalive_recv) >= opts.keepalive_secs
++ && elapsed(now, ses.last_packet_time_keepalive_sent) >= opts.keepalive_secs) {
+ send_msg_keepalive();
+ }
+
+- if (now - ses.last_packet_time_keepalive_recv
++ if (elapsed(now, ses.last_packet_time_keepalive_recv)
+ >= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
+ dropbear_exit("Keepalive timeout");
+ }
+ }
+
+- if (opts.idle_timeout_secs > 0
+- && now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
++ if (opts.idle_timeout_secs > 0
++ && elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) {
+ dropbear_close("Idle timeout");
+ }
+ }
+
+-static void update_timeout(long limit, long now, long last_event, long * timeout) {
+- TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
+- limit, now, last_event, *timeout))
++static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) {
++ TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld",
++ limit,
++ (unsigned long long)now,
++ (unsigned long long)last_event, *timeout))
+ if (last_event > 0 && limit > 0) {
+- *timeout = MIN(*timeout, last_event+limit-now);
++ *timeout = MIN(*timeout, elapsed(now, last_event) + limit);
+ TRACE2(("new timeout %ld", *timeout))
+ }
+ }
+@@ -584,7 +595,7 @@ static long select_timeout() {
+ /* determine the minimum timeout that might be required, so
+ as to avoid waking when unneccessary */
+ long timeout = KEX_REKEY_TIMEOUT;
+- long now = monotonic_now();
++ time_t now = monotonic_now();
+
+ if (!ses.kexstate.sentkexinit) {
+ update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
+@@ -596,7 +607,7 @@ static long select_timeout() {
+ }
+
+ if (ses.authstate.authdone) {
+- update_timeout(opts.keepalive_secs, now,
++ update_timeout(opts.keepalive_secs, now,
+ MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
+ &timeout);
+ }
+--- a/dbutil.c
++++ b/dbutil.c
+@@ -724,7 +724,7 @@ void gettime_wrapper(struct timespec *no
+ /* Fallback for everything else - this will sometimes go backwards */
+ gettimeofday(&tv, NULL);
+ now->tv_sec = tv.tv_sec;
+- now->tv_nsec = 1000*tv.tv_usec;
++ now->tv_nsec = 1000*(long)tv.tv_usec;
+ }
+
+ /* second-resolution monotonic timestamp */
+--- a/loginrec.c
++++ b/loginrec.c
+@@ -459,6 +459,7 @@ line_abbrevname(char *dst, const char *s
+ void
+ set_utmp_time(struct logininfo *li, struct utmp *ut)
+ {
++ /* struct utmp in glibc isn't y2038 safe yet */
+ # ifdef HAVE_STRUCT_UTMP_UT_TV
+ ut->ut_tv.tv_sec = li->tv_sec;
+ ut->ut_tv.tv_usec = li->tv_usec;
+@@ -1272,6 +1273,7 @@ lastlog_construct(struct logininfo *li,
+ (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
+ strlcpy(last->ll_host, li->hostname,
+ MIN_SIZEOF(last->ll_host, li->hostname));
++ /* struct lastlog in glibc isn't y2038 safe yet */
+ last->ll_time = li->tv_sec;
+ }
+
+--- a/loginrec.h
++++ b/loginrec.h
+@@ -139,8 +139,8 @@ struct logininfo {
+ /* struct timeval (sys/time.h) isn't always available, if it isn't we'll
+ * use time_t's value as tv_sec and set tv_usec to 0
+ */
+- unsigned int tv_sec;
+- unsigned int tv_usec;
++ time_t tv_sec;
++ suseconds_t tv_usec;
+ union login_netinfo hostaddr; /* caller's host address(es) */
+ }; /* struct logininfo */
+
+--- a/runopts.h
++++ b/runopts.h
+@@ -39,8 +39,8 @@ typedef struct runopts {
+ int listen_fwd_all;
+ #endif
+ unsigned int recv_window;
+- time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
+- time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
++ long keepalive_secs; /* Time between sending keepalives. 0 is off */
++ long idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
+ int usingsyslog;
+
+ #ifndef DISABLE_ZLIB
+--- a/svr-auth.c
++++ b/svr-auth.c
+@@ -389,7 +389,7 @@ void send_msg_userauth_failure(int parti
+ Beware of integer overflow if increasing these values */
+ const unsigned int mindelay = 250000000;
+ const unsigned int vardelay = 100000000;
+- unsigned int rand_delay;
++ suseconds_t rand_delay;
+ struct timespec delay;
+
+ gettime_wrapper(&delay);
diff --git a/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch b/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch
new file mode 100644
index 00000000000..6789800e120
--- /dev/null
+++ b/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch
@@ -0,0 +1,25 @@
+From c043efb47c3173072fa636ca0da0d19875d4511f Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Tue, 6 Dec 2022 22:34:11 +0800
+Subject: Fix so DROPBEAR_DSS is only forced for fuzzing
+
+Regression from 787391ea3b5af2acf5e3c83372510f0c79477ad7,
+was missing fuzzing conditional
+---
+ sysoptions.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sysoptions.h
++++ b/sysoptions.h
+@@ -380,9 +380,11 @@
+ #endif
+
+ /* Fuzzing expects all key types to be enabled */
++#if DROPBEAR_FUZZ
+ #if defined(DROPBEAR_DSS)
+ #undef DROPBEAR_DSS
+ #endif
+ #define DROPBEAR_DSS 1
++#endif
+
+ /* no include guard for this file */
diff --git a/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch b/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch
new file mode 100644
index 00000000000..bcb43aed2ae
--- /dev/null
+++ b/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch
@@ -0,0 +1,24 @@
+From 860721558837441ab45019858e710a2625ffa46e Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Wed, 7 Dec 2022 13:04:10 +0800
+Subject: Allow users's own gid in pty permission check
+
+This allows non-root Dropbear to work even without devpts gid=5 mount
+option on Linux.
+---
+ sshpty.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/sshpty.c
++++ b/sshpty.c
+@@ -380,7 +380,9 @@ pty_setowner(struct passwd *pw, const ch
+ tty_name, strerror(errno));
+ }
+
+- if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
++ /* Allow either "tty" gid or user's own gid. On Linux with openpty()
++ * this varies depending on the devpts mount options */
++ if (st.st_uid != pw->pw_uid || !(st.st_gid == gid || st.st_gid == pw->pw_gid)) {
+ if (chown(tty_name, pw->pw_uid, gid) < 0) {
+ if (errno == EROFS &&
+ (st.st_uid == pw->pw_uid || st.st_uid == 0)) {
diff --git a/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch b/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch
new file mode 100644
index 00000000000..0d23c9c4161
--- /dev/null
+++ b/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch
@@ -0,0 +1,123 @@
+From 01415ef8269e594a647f67ea0729ca8b590679de Mon Sep 17 00:00:00 2001
+From: Francois Perrad <francois.perrad@gadz.org>
+Date: Thu, 22 Dec 2022 10:19:54 +0100
+Subject: const parameter mp_int
+
+---
+ bignum.c | 2 +-
+ bignum.h | 2 +-
+ buffer.c | 2 +-
+ buffer.h | 2 +-
+ dbrandom.c | 2 +-
+ dbrandom.h | 2 +-
+ dbutil.c | 2 +-
+ dbutil.h | 2 +-
+ genrsa.c | 4 ++--
+ 9 files changed, 10 insertions(+), 10 deletions(-)
+
+--- a/bignum.c
++++ b/bignum.c
+@@ -93,7 +93,7 @@ void bytes_to_mp(mp_int *mp, const unsig
+
+ /* hash the ssh representation of the mp_int mp */
+ void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
+- hash_state *hs, mp_int *mp) {
++ hash_state *hs, const mp_int *mp) {
+ buffer * buf;
+
+ buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
+--- a/bignum.h
++++ b/bignum.h
+@@ -33,6 +33,6 @@ void m_mp_alloc_init_multi(mp_int **mp,
+ void m_mp_free_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
+ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
+ void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
+- hash_state *hs, mp_int *mp);
++ hash_state *hs, const mp_int *mp);
+
+ #endif /* DROPBEAR_BIGNUM_H_ */
+--- a/buffer.c
++++ b/buffer.c
+@@ -299,7 +299,7 @@ void buf_putbytes(buffer *buf, const uns
+
+ /* for our purposes we only need positive (or 0) numbers, so will
+ * fail if we get negative numbers */
+-void buf_putmpint(buffer* buf, mp_int * mp) {
++void buf_putmpint(buffer* buf, const mp_int * mp) {
+ size_t written;
+ unsigned int len, pad = 0;
+ TRACE2(("enter buf_putmpint"))
+--- a/buffer.h
++++ b/buffer.h
+@@ -65,7 +65,7 @@ void buf_putint(buffer* buf, unsigned in
+ void buf_putstring(buffer* buf, const char* str, unsigned int len);
+ void buf_putbufstring(buffer *buf, const buffer* buf_str);
+ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
+-void buf_putmpint(buffer* buf, mp_int * mp);
++void buf_putmpint(buffer* buf, const mp_int * mp);
+ int buf_getmpint(buffer* buf, mp_int* mp);
+ unsigned int buf_getint(buffer* buf);
+
+--- a/dbrandom.c
++++ b/dbrandom.c
+@@ -347,7 +347,7 @@ void genrandom(unsigned char* buf, unsig
+ * rand must be an initialised *mp_int for the result.
+ * the result rand satisfies: 0 < rand < max
+ * */
+-void gen_random_mpint(mp_int *max, mp_int *rand) {
++void gen_random_mpint(const mp_int *max, mp_int *rand) {
+
+ unsigned char *randbuf = NULL;
+ unsigned int len = 0;
+--- a/dbrandom.h
++++ b/dbrandom.h
+@@ -30,6 +30,6 @@
+ void seedrandom(void);
+ void genrandom(unsigned char* buf, unsigned int len);
+ void addrandom(const unsigned char * buf, unsigned int len);
+-void gen_random_mpint(mp_int *max, mp_int *rand);
++void gen_random_mpint(const mp_int *max, mp_int *rand);
+
+ #endif /* DROPBEAR_RANDOM_H_ */
+--- a/dbutil.c
++++ b/dbutil.c
+@@ -442,7 +442,7 @@ void printhex(const char * label, const
+ }
+ }
+
+-void printmpint(const char *label, mp_int *mp) {
++void printmpint(const char *label, const mp_int *mp) {
+ buffer *buf = buf_new(1000);
+ buf_putmpint(buf, mp);
+ fprintf(stderr, "%d bits ", mp_count_bits(mp));
+--- a/dbutil.h
++++ b/dbutil.h
+@@ -53,7 +53,7 @@ void dropbear_trace3(const char* format,
+ void dropbear_trace4(const char* format, ...) ATTRIB_PRINTF(1,2);
+ void dropbear_trace5(const char* format, ...) ATTRIB_PRINTF(1,2);
+ void printhex(const char * label, const unsigned char * buf, int len);
+-void printmpint(const char *label, mp_int *mp);
++void printmpint(const char *label, const mp_int *mp);
+ void debug_start_net(void);
+ extern int debug_trace;
+ #endif
+--- a/genrsa.c
++++ b/genrsa.c
+@@ -34,7 +34,7 @@
+ #if DROPBEAR_RSA
+
+ static void getrsaprime(mp_int* prime, mp_int *primeminus,
+- mp_int* rsa_e, unsigned int size_bytes);
++ const mp_int* rsa_e, unsigned int size_bytes);
+
+ /* mostly taken from libtomcrypt's rsa key generation routine */
+ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
+@@ -89,7 +89,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsi
+
+ /* return a prime suitable for p or q */
+ static void getrsaprime(mp_int* prime, mp_int *primeminus,
+- mp_int* rsa_e, unsigned int size_bytes) {
++ const mp_int* rsa_e, unsigned int size_bytes) {
+
+ unsigned char *buf;
+ int trials;
diff --git a/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch b/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch
new file mode 100644
index 00000000000..c7011021c17
--- /dev/null
+++ b/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch
@@ -0,0 +1,21 @@
+From 39d955c49f31fc155e885447ee2be61c869d8c2d Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Tue, 3 Jan 2023 22:05:14 +0800
+Subject: Add missing break in switch
+
+Has no effect on execution, the fallthrough does nothing
+Closes #208
+---
+ dropbearkey.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/dropbearkey.c
++++ b/dropbearkey.c
+@@ -139,6 +139,7 @@ static void check_signkey_bits(enum sign
+ dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
+ exit(EXIT_FAILURE);
+ }
++ break;
+ #endif
+ default:
+ (void)0; /* quiet, compiler. ecdsa handles checks itself */
diff --git a/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch b/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch
new file mode 100644
index 00000000000..5fcfaad1809
--- /dev/null
+++ b/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch
@@ -0,0 +1,29 @@
+From 7a53c7f0f4b3eb23e002819553cb45558642c01d Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Wed, 4 Jan 2023 20:32:23 +0800
+Subject: Fix building only client or server
+
+Regressed when -Wundef was added
+
+Fixes #210
+---
+ sysoptions.h | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/sysoptions.h
++++ b/sysoptions.h
+@@ -10,6 +10,14 @@
+ #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
+ #define PROGNAME "dropbear"
+
++#ifndef DROPBEAR_CLIENT
++#define DROPBEAR_CLIENT 0
++#endif
++
++#ifndef DROPBEAR_SERVER
++#define DROPBEAR_SERVER 0
++#endif
++
+ /* Spec recommends after one hour or 1 gigabyte of data. One hour
+ * is a bit too verbose, so we try 8 hours */
+ #ifndef KEX_REKEY_TIMEOUT
diff --git a/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch b/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch
new file mode 100644
index 00000000000..4f675234ff9
--- /dev/null
+++ b/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch
@@ -0,0 +1,94 @@
+From a113381c12a2da3c9b7bd594f47a1b2657bdfdf2 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sun, 12 Feb 2023 22:44:32 +0800
+Subject: Disable rsa signatures when no rsa hostkey
+
+Otherwise Dropbear will offer RSA as a hostkey signature option, but the
+session will exit with an assertion or NULL pointer dereference once
+that algorithm is negotiated.
+
+This likely regressed in 2020.79 when signature vs key type enums were
+split, for rsa-sha256.
+
+Fixes #219 on github
+---
+ svr-runopts.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -505,11 +505,11 @@ static void addportandaddress(const char
+ svr_opts.portcount++;
+ }
+
+-static void disablekey(int type) {
++static void disablekey(enum signature_type type) {
+ int i;
+ TRACE(("Disabling key type %d", type))
+ for (i = 0; sigalgs[i].name != NULL; i++) {
+- if (sigalgs[i].val == type) {
++ if ((int)sigalgs[i].val == (int)type) {
+ sigalgs[i].usable = 0;
+ break;
+ }
+@@ -624,7 +624,8 @@ void load_all_hostkeys() {
+
+ #if DROPBEAR_RSA
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
+- disablekey(DROPBEAR_SIGNKEY_RSA);
++ disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
++ disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
+ } else {
+ any_keys = 1;
+ }
+@@ -632,7 +633,7 @@ void load_all_hostkeys() {
+
+ #if DROPBEAR_DSS
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
+- disablekey(DROPBEAR_SIGNKEY_DSS);
++ disablekey(DROPBEAR_SIGNATURE_DSS);
+ } else {
+ any_keys = 1;
+ }
+@@ -666,35 +667,35 @@ void load_all_hostkeys() {
+ #if DROPBEAR_ECC_256
+ if (!svr_opts.hostkey->ecckey256
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
+- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
+ }
+ #endif
+ #if DROPBEAR_ECC_384
+ if (!svr_opts.hostkey->ecckey384
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
+- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
+ }
+ #endif
+ #if DROPBEAR_ECC_521
+ if (!svr_opts.hostkey->ecckey521
+ && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
+- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
+ }
+ #endif
+ #endif /* DROPBEAR_ECDSA */
+
+ #if DROPBEAR_ED25519
+ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
+- disablekey(DROPBEAR_SIGNKEY_ED25519);
++ disablekey(DROPBEAR_SIGNATURE_ED25519);
+ } else {
+ any_keys = 1;
+ }
+ #endif
+ #if DROPBEAR_SK_ECDSA
+- disablekey(DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256);
++ disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
+ #endif
+ #if DROPBEAR_SK_ED25519
+- disablekey(DROPBEAR_SIGNKEY_SK_ED25519);
++ disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
+ #endif
+
+ if (!any_keys) {
diff --git a/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch b/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch
new file mode 100644
index 00000000000..e1538a4c1f7
--- /dev/null
+++ b/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch
@@ -0,0 +1,27 @@
+From 3292b8c6f1e5fcc405fa0f7a20e90a60f74037b2 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sun, 12 Feb 2023 23:00:00 +0800
+Subject: Use write() rather than fprintf() in segv handler
+
+fprintf isn't guaranteed safe (though hasn't had any problems reported).
+---
+ svr-main.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/svr-main.c
++++ b/svr-main.c
+@@ -420,8 +420,12 @@ static void sigchld_handler(int UNUSED(u
+
+ /* catch any segvs */
+ static void sigsegv_handler(int UNUSED(unused)) {
+- fprintf(stderr, "Aiee, segfault! You should probably report "
+- "this as a bug to the developer\n");
++ int i;
++ const char *msg = "Aiee, segfault! You should probably report "
++ "this as a bug to the developer\n";
++ i = write(STDERR_FILENO, msg, strlen(msg));
++ /* ignore short writes */
++ (void)i;
+ _exit(EXIT_FAILURE);
+ }
+
diff --git a/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch b/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch
new file mode 100644
index 00000000000..12b1843ee26
--- /dev/null
+++ b/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch
@@ -0,0 +1,39 @@
+From 5040f21cb4ee6ade966e60c6d5a3c270d03de1f1 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 1 May 2023 22:05:43 +0800
+Subject: Remove SO_LINGER
+
+It could cause channels to take up to 5 seconds to close(), which would block
+the entire process. On busy TCP forwarding sessions this would result in
+channels seeming stuck and new connections not being accepted.
+
+We don't need to monitor for flushing failures since we can't report errors, so
+SO_LINGER wasn't useful.
+
+Thanks to GektorUA for reporting and testing
+
+Fixes #230
+---
+ netio.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/netio.c
++++ b/netio.c
+@@ -472,7 +472,6 @@ int dropbear_listen(const char* address,
+ struct addrinfo hints, *res = NULL, *res0 = NULL;
+ int err;
+ unsigned int nsock;
+- struct linger linger;
+ int val;
+ int sock;
+ uint16_t *allocated_lport_p = NULL;
+@@ -551,9 +550,6 @@ int dropbear_listen(const char* address,
+ val = 1;
+ /* set to reuse, quick timeout */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+- linger.l_onoff = 1;
+- linger.l_linger = 5;
+- setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
+
+ #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
+ if (res->ai_family == AF_INET6) {
diff --git a/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch b/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch
new file mode 100644
index 00000000000..d1c1fa4cced
--- /dev/null
+++ b/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch
@@ -0,0 +1,147 @@
+From fb64db9eac3fdc6434f2dc7b5ea407fe5df76e6f Mon Sep 17 00:00:00 2001
+From: Diederik De Coninck <diederik.deconinck_ext@softathome.com>
+Date: Tue, 11 Apr 2023 15:38:04 +0200
+Subject: Add option to bind to interface
+
+---
+ netio.c | 13 +++++++++++--
+ netio.h | 2 +-
+ runopts.h | 1 +
+ svr-main.c | 2 +-
+ svr-runopts.c | 9 +++++++++
+ svr-tcpfwd.c | 1 +
+ tcp-accept.c | 2 +-
+ tcpfwd.h | 1 +
+ 8 files changed, 26 insertions(+), 5 deletions(-)
+
+--- a/netio.c
++++ b/netio.c
+@@ -467,7 +467,7 @@ int get_sock_port(int sock) {
+ * failure, if errstring wasn't NULL, it'll be a newly malloced error
+ * string.*/
+ int dropbear_listen(const char* address, const char* port,
+- int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
++ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface) {
+
+ struct addrinfo hints, *res = NULL, *res0 = NULL;
+ int err;
+@@ -497,7 +497,11 @@ int dropbear_listen(const char* address,
+ TRACE(("dropbear_listen: local loopback"))
+ } else {
+ if (address[0] == '\0') {
+- TRACE(("dropbear_listen: all interfaces"))
++ if (interface) {
++ TRACE(("dropbear_listen: %s", interface))
++ } else {
++ TRACE(("dropbear_listen: all interfaces"))
++ }
+ address = NULL;
+ }
+ hints.ai_flags = AI_PASSIVE;
+@@ -551,6 +555,11 @@ int dropbear_listen(const char* address,
+ /* set to reuse, quick timeout */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+
++ if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
++ dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
++ TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
++ }
++
+ #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
+ if (res->ai_family == AF_INET6) {
+ int on = 1;
+--- a/netio.h
++++ b/netio.h
+@@ -19,7 +19,7 @@ void get_socket_address(int fd, char **l
+ void getaddrstring(struct sockaddr_storage* addr,
+ char **ret_host, char **ret_port, int host_lookup);
+ int dropbear_listen(const char* address, const char* port,
+- int *socks, unsigned int sockcount, char **errstring, int *maxfd);
++ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface);
+
+ struct dropbear_progress_connection;
+
+--- a/runopts.h
++++ b/runopts.h
+@@ -128,6 +128,7 @@ typedef struct svr_runopts {
+ char * pidfile;
+
+ char * forced_command;
++ char* interface;
+
+ #if DROPBEAR_PLUGIN
+ /* malloced */
+--- a/svr-main.c
++++ b/svr-main.c
+@@ -488,7 +488,7 @@ static size_t listensockets(int *socks,
+
+ nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos],
+ sockcount - sockpos,
+- &errstring, maxfd);
++ &errstring, maxfd, svr_opts.interface);
+
+ if (nsock < 0) {
+ dropbear_log(LOG_WARNING, "Failed listening on '%s': %s",
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -98,6 +98,8 @@ static void printhelp(const char * progn
+ " (default port is %s if none specified)\n"
+ "-P PidFile Create pid file PidFile\n"
+ " (default %s)\n"
++ "-l <interface>\n"
++ " interface to bind on\n"
+ #if INETD_MODE
+ "-i Start for inetd\n"
+ #endif
+@@ -265,6 +267,9 @@ void svr_getopts(int argc, char ** argv)
+ case 'P':
+ next = &svr_opts.pidfile;
+ break;
++ case 'l':
++ next = &svr_opts.interface;
++ break;
+ #if DO_MOTD
+ /* motd is displayed by default, -m turns it off */
+ case 'm':
+@@ -438,6 +443,10 @@ void svr_getopts(int argc, char ** argv)
+ dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
+ }
+
++ if (svr_opts.interface) {
++ dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface);
++ }
++
+ if (reexec_fd_arg) {
+ if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
+ || svr_opts.reexec_childpipe < 0) {
+--- a/svr-tcpfwd.c
++++ b/svr-tcpfwd.c
+@@ -205,6 +205,7 @@ static int svr_remotetcpreq(int *allocat
+ tcpinfo->listenport = port;
+ tcpinfo->chantype = &svr_chan_tcpremote;
+ tcpinfo->tcp_type = forwarded;
++ tcpinfo->interface = svr_opts.interface;
+
+ tcpinfo->request_listenaddr = request_addr;
+ if (!opts.listen_fwd_all || (strcmp(request_addr, "localhost") == 0) ) {
+--- a/tcp-accept.c
++++ b/tcp-accept.c
+@@ -117,7 +117,7 @@ int listen_tcpfwd(struct TCPListener* tc
+ snprintf(portstring, sizeof(portstring), "%u", tcpinfo->listenport);
+
+ nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks,
+- DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
++ DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd, tcpinfo->interface);
+ if (nsocks < 0) {
+ dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
+ m_free(errstring);
+--- a/tcpfwd.h
++++ b/tcpfwd.h
+@@ -42,6 +42,7 @@ struct TCPListener {
+ unsigned int listenport;
+ /* The address that the remote host asked to listen on */
+ char *request_listenaddr;
++ char* interface;
+
+ const struct ChanType *chantype;
+ enum {direct, forwarded} tcp_type;
diff --git a/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch b/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch
new file mode 100644
index 00000000000..11f902bf907
--- /dev/null
+++ b/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch
@@ -0,0 +1,50 @@
+From 031d09b47912b2401f4934667c0b6f857ede61ee Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Tue, 18 Jul 2023 23:20:16 +0800
+Subject: Add ifdef guards for SO_BINDTODEVICE
+
+---
+ netio.c | 2 ++
+ svr-runopts.c | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+--- a/netio.c
++++ b/netio.c
+@@ -555,10 +555,12 @@ int dropbear_listen(const char* address,
+ /* set to reuse, quick timeout */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+
++#ifdef SO_BINDTODEVICE
+ if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
+ dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
+ TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
+ }
++#endif
+
+ #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
+ if (res->ai_family == AF_INET6) {
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -98,8 +98,10 @@ static void printhelp(const char * progn
+ " (default port is %s if none specified)\n"
+ "-P PidFile Create pid file PidFile\n"
+ " (default %s)\n"
++#ifdef SO_BINDTODEVICE
+ "-l <interface>\n"
+ " interface to bind on\n"
++#endif
+ #if INETD_MODE
+ "-i Start for inetd\n"
+ #endif
+@@ -267,9 +269,11 @@ void svr_getopts(int argc, char ** argv)
+ case 'P':
+ next = &svr_opts.pidfile;
+ break;
++#ifdef SO_BINDTODEVICE
+ case 'l':
+ next = &svr_opts.interface;
+ break;
++#endif
+ #if DO_MOTD
+ /* motd is displayed by default, -m turns it off */
+ case 'm':
diff --git a/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch b/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch
new file mode 100644
index 00000000000..531215c7576
--- /dev/null
+++ b/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch
@@ -0,0 +1,74 @@
+From 62a06cd95f58060a59359f8769c3f35cd680d4fd Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sun, 23 Jul 2023 21:01:48 +0800
+Subject: Make banner reading failure non-fatal
+
+---
+ svr-runopts.c | 45 ++++++++++++++++++++++++++++-----------------
+ 1 file changed, 28 insertions(+), 17 deletions(-)
+
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -38,6 +38,7 @@ static void printhelp(const char * progn
+ static void addportandaddress(const char* spec);
+ static void loadhostkey(const char *keyfile, int fatal_duplicate);
+ static void addhostkey(const char *keyfile);
++static void load_banner();
+
+ static void printhelp(const char * progname) {
+
+@@ -382,23 +383,7 @@ void svr_getopts(int argc, char ** argv)
+ }
+
+ if (svr_opts.bannerfile) {
+- struct stat buf;
+- if (stat(svr_opts.bannerfile, &buf) != 0) {
+- dropbear_exit("Error opening banner file '%s'",
+- svr_opts.bannerfile);
+- }
+-
+- if (buf.st_size > MAX_BANNER_SIZE) {
+- dropbear_exit("Banner file too large, max is %d bytes",
+- MAX_BANNER_SIZE);
+- }
+-
+- svr_opts.banner = buf_new(buf.st_size);
+- if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
+- dropbear_exit("Error reading banner file '%s'",
+- svr_opts.bannerfile);
+- }
+- buf_setpos(svr_opts.banner, 0);
++ load_banner();
+ }
+
+ #ifdef HAVE_GETGROUPLIST
+@@ -715,3 +700,29 @@ void load_all_hostkeys() {
+ dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
+ }
+ }
++
++static void load_banner() {
++ struct stat buf;
++ if (stat(svr_opts.bannerfile, &buf) != 0) {
++ dropbear_log(LOG_WARNING, "Error opening banner file '%s'",
++ svr_opts.bannerfile);
++ return;
++ }
++
++ if (buf.st_size > MAX_BANNER_SIZE) {
++ dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes",
++ MAX_BANNER_SIZE);
++ return;
++ }
++
++ svr_opts.banner = buf_new(buf.st_size);
++ if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) {
++ dropbear_log(LOG_WARNING, "Error reading banner file '%s'",
++ svr_opts.bannerfile);
++ buf_free(svr_opts.banner);
++ svr_opts.banner = NULL;
++ return;
++ }
++ buf_setpos(svr_opts.banner, 0);
++
++}
diff --git a/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch b/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch
new file mode 100644
index 00000000000..ff130f8be0a
--- /dev/null
+++ b/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch
@@ -0,0 +1,60 @@
+From ec26975d442163b66d1646a48e022bc8c2f1607a Mon Sep 17 00:00:00 2001
+From: Sergey Ponomarev <stokito@gmail.com>
+Date: Sun, 27 Aug 2023 00:07:05 +0300
+Subject: dropbearkey.c Ignore unsupported command line options
+
+To generate non interactively a key with OpenSSH the simplest command is:
+
+ssh-keygen -t ed25519 -q -N '' -f ~/.ssh/id_ed25519
+
+The command has two options -q quiet and -N passphrase which aren't supported by the dropbearkey.
+
+To improve interoperability add explicit ignoring of the -q and -N with empty passphrase.
+Also ignore the -v even if the DEBUG_TRACE is not set.
+
+Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
+---
+ dropbearkey.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+--- a/dropbearkey.c
++++ b/dropbearkey.c
+@@ -159,6 +159,7 @@ int main(int argc, char ** argv) {
+ enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
+ char * typetext = NULL;
+ char * sizetext = NULL;
++ char * passphrase = NULL;
+ unsigned int bits = 0, genbits;
+ int printpub = 0;
+
+@@ -194,11 +195,16 @@ int main(int argc, char ** argv) {
+ printhelp(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+-#if DEBUG_TRACE
+ case 'v':
++#if DEBUG_TRACE
+ debug_trace = DROPBEAR_VERBOSE_LEVEL;
+- break;
+ #endif
++ break;
++ case 'q':
++ break; /* quiet is default */
++ case 'N':
++ next = &passphrase;
++ break;
+ default:
+ fprintf(stderr, "Unknown argument %s\n", argv[i]);
+ printhelp(argv[0]);
+@@ -266,6 +272,11 @@ int main(int argc, char ** argv) {
+ check_signkey_bits(keytype, bits);;
+ }
+
++ if (passphrase && *passphrase != '\0') {
++ fprintf(stderr, "Only empty passphrase is supported\n");
++ exit(EXIT_FAILURE);
++ }
++
+ genbits = signkey_generate_get_bits(keytype, bits);
+ fprintf(stderr, "Generating %u bit %s key, this may take a while...\n", genbits, typetext);
+ if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)
diff --git a/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch b/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch
new file mode 100644
index 00000000000..f39417adb79
--- /dev/null
+++ b/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch
@@ -0,0 +1,121 @@
+From 3b576d95dcf791d7b945e75f639da8f89c1685a2 Mon Sep 17 00:00:00 2001
+From: czurnieden <czurnieden@gmx.de>
+Date: Tue, 9 May 2023 17:17:12 +0200
+Subject: Fix possible integer overflow
+
+---
+ libtommath/bn_mp_2expt.c | 4 ++++
+ libtommath/bn_mp_grow.c | 4 ++++
+ libtommath/bn_mp_init_size.c | 5 +++++
+ libtommath/bn_mp_mul_2d.c | 4 ++++
+ libtommath/bn_s_mp_mul_digs.c | 4 ++++
+ libtommath/bn_s_mp_mul_digs_fast.c | 4 ++++
+ libtommath/bn_s_mp_mul_high_digs.c | 4 ++++
+ libtommath/bn_s_mp_mul_high_digs_fast.c | 4 ++++
+ 8 files changed, 33 insertions(+)
+
+--- a/libtommath/bn_mp_2expt.c
++++ b/libtommath/bn_mp_2expt.c
+@@ -12,6 +12,10 @@ mp_err mp_2expt(mp_int *a, int b)
+ {
+ mp_err err;
+
++ if (b < 0) {
++ return MP_VAL;
++ }
++
+ /* zero a as per default */
+ mp_zero(a);
+
+--- a/libtommath/bn_mp_grow.c
++++ b/libtommath/bn_mp_grow.c
+@@ -9,6 +9,10 @@ mp_err mp_grow(mp_int *a, int size)
+ int i;
+ mp_digit *tmp;
+
++ if (size < 0) {
++ return MP_VAL;
++ }
++
+ /* if the alloc size is smaller alloc more ram */
+ if (a->alloc < size) {
+ /* reallocate the array a->dp
+--- a/libtommath/bn_mp_init_size.c
++++ b/libtommath/bn_mp_init_size.c
+@@ -6,6 +6,11 @@
+ /* init an mp_init for a given size */
+ mp_err mp_init_size(mp_int *a, int size)
+ {
++
++ if (size < 0) {
++ return MP_VAL;
++ }
++
+ size = MP_MAX(MP_MIN_PREC, size);
+
+ /* alloc mem */
+--- a/libtommath/bn_mp_mul_2d.c
++++ b/libtommath/bn_mp_mul_2d.c
+@@ -9,6 +9,10 @@ mp_err mp_mul_2d(const mp_int *a, int b,
+ mp_digit d;
+ mp_err err;
+
++ if (b < 0) {
++ return MP_VAL;
++ }
++
+ /* copy */
+ if (a != c) {
+ if ((err = mp_copy(a, c)) != MP_OKAY) {
+--- a/libtommath/bn_s_mp_mul_digs.c
++++ b/libtommath/bn_s_mp_mul_digs.c
+@@ -16,6 +16,10 @@ mp_err s_mp_mul_digs(const mp_int *a, co
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* can we use the fast multiplier? */
+ if ((digs < MP_WARRAY) &&
+ (MP_MIN(a->used, b->used) < MP_MAXFAST)) {
+--- a/libtommath/bn_s_mp_mul_digs_fast.c
++++ b/libtommath/bn_s_mp_mul_digs_fast.c
+@@ -26,6 +26,10 @@ mp_err s_mp_mul_digs_fast(const mp_int *
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* grow the destination as required */
+ if (c->alloc < digs) {
+ if ((err = mp_grow(c, digs)) != MP_OKAY) {
+--- a/libtommath/bn_s_mp_mul_high_digs.c
++++ b/libtommath/bn_s_mp_mul_high_digs.c
+@@ -15,6 +15,10 @@ mp_err s_mp_mul_high_digs(const mp_int *
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* can we use the fast multiplier? */
+ if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)
+ && ((a->used + b->used + 1) < MP_WARRAY)
+--- a/libtommath/bn_s_mp_mul_high_digs_fast.c
++++ b/libtommath/bn_s_mp_mul_high_digs_fast.c
+@@ -19,6 +19,10 @@ mp_err s_mp_mul_high_digs_fast(const mp_
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
++ if (digs < 0) {
++ return MP_VAL;
++ }
++
+ /* grow the destination as required */
+ pa = a->used + b->used;
+ if (c->alloc < pa) {
diff --git a/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch b/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch
new file mode 100644
index 00000000000..b6933120e6f
--- /dev/null
+++ b/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch
@@ -0,0 +1,35 @@
+From 3cf8344769eda55e26eee53c1898b2c66544f188 Mon Sep 17 00:00:00 2001
+From: Justin Chen <justin.chen@broadcom.com>
+Date: Fri, 8 Sep 2023 11:35:18 -0700
+Subject: src: svr-tcpfwd: Fix noremotetcp behavior
+
+If noremotetcp is set, we should still reply with
+send_msg_request_failed. This matches the behavior
+of !DROPBEAR_SVR_REMOTETCPFWD.
+
+We were seeing keepalive packets being ignored when
+the "-k" option was used.
+---
+ svr-tcpfwd.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/svr-tcpfwd.c
++++ b/svr-tcpfwd.c
+@@ -79,14 +79,14 @@ void recv_msg_global_request_remotetcp()
+
+ TRACE(("enter recv_msg_global_request_remotetcp"))
+
++ reqname = buf_getstring(ses.payload, &namelen);
++ wantreply = buf_getbool(ses.payload);
++
+ if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) {
+ TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
+ goto out;
+ }
+
+- reqname = buf_getstring(ses.payload, &namelen);
+- wantreply = buf_getbool(ses.payload);
+-
+ if (namelen > MAX_NAME_LEN) {
+ TRACE(("name len is wrong: %d", namelen))
+ goto out;
diff --git a/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch b/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch
new file mode 100644
index 00000000000..603c61d6fb1
--- /dev/null
+++ b/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch
@@ -0,0 +1,32 @@
+From e28ba1b9975eab48799aa3ed77d3cd91627d7b27 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Sat, 9 Dec 2023 23:10:41 +0800
+Subject: Don't try to shutdown() a pty
+
+shutdown() of a pty doesn't work (ENOTSOCK), so we should close
+it instead.
+
+This will ensure that PTY controlling terminals are closed when a
+session exits, including when multiple sessions run over a single SSH
+connection. In the normal case of a single session, the PTY controlling
+terminal would be closed when the Dropbear server process exits anyway.
+
+This possibly fixes #264 on github
+
+It is possible that there could be subtle changes to PTY flushing
+behaviour, though nothing caught by tests at present.
+---
+ svr-chansession.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/svr-chansession.c
++++ b/svr-chansession.c
+@@ -910,7 +910,7 @@ static int ptycommand(struct Channel *ch
+ channel->readfd = chansess->master;
+ /* don't need to set stderr here */
+ ses.maxfd = MAX(ses.maxfd, chansess->master);
+- channel->bidir_fd = 1;
++ channel->bidir_fd = 0;
+
+ setnonblocking(chansess->master);
+
diff --git a/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch b/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch
new file mode 100644
index 00000000000..9c70c3141c8
--- /dev/null
+++ b/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch
@@ -0,0 +1,33 @@
+From 806586b585806cbe32013bcd3af3847278972060 Mon Sep 17 00:00:00 2001
+From: Sergey Ponomarev <stokito@gmail.com>
+Date: Sun, 10 Dec 2023 10:31:56 +0200
+Subject: dropbearkey: add alias to ssh-keygen
+
+The dropbearkey is partially compatible with ssh-keygen and can be used as an alias.
+
+Closes: #263
+---
+ dbmulti.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/dbmulti.c
++++ b/dbmulti.c
+@@ -41,7 +41,8 @@ static int runprog(const char *multipath
+ }
+ #endif
+ #ifdef DBMULTI_dropbearkey
+- if (strcmp(progname, "dropbearkey") == 0) {
++ if (strcmp(progname, "dropbearkey") == 0
++ || strcmp(progname, "ssh-keygen") == 0) {
+ return dropbearkey_main(argc, argv);
+ }
+ #endif
+@@ -88,7 +89,7 @@ int main(int argc, char ** argv) {
+ "'dbclient' or 'ssh' - the Dropbear client\n"
+ #endif
+ #ifdef DBMULTI_dropbearkey
+- "'dropbearkey' - the key generator\n"
++ "'dropbearkey' or 'ssh-keygen' - the key generator\n"
+ #endif
+ #ifdef DBMULTI_dropbearconvert
+ "'dropbearconvert' - the key converter\n"
diff --git a/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch b/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch
new file mode 100644
index 00000000000..3544f2123c6
--- /dev/null
+++ b/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch
@@ -0,0 +1,34 @@
+From 383cc8c97a9420aad9cf93d88e77ec636b183a9d Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 11 Dec 2023 23:18:09 +0800
+Subject: Allow inetd with non-syslog
+
+An inetd-alike should be able to distinguish stdout and stderr, so
+it's a valid configuration.
+
+Fixes #218 on github
+---
+ svr-runopts.c | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -443,18 +443,6 @@ void svr_getopts(int argc, char ** argv)
+ }
+ }
+
+-#if INETD_MODE
+- if (svr_opts.inetdmode && (
+- opts.usingsyslog == 0
+-#if DEBUG_TRACE
+- || debug_trace
+-#endif
+- )) {
+- /* log output goes to stderr which would get sent over the inetd network socket */
+- dropbear_exit("Dropbear inetd mode is incompatible with debug -v or non-syslog");
+- }
+-#endif
+-
+ if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
+ dropbear_exit("-t and -s are incompatible");
+ }
diff --git a/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch b/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch
new file mode 100644
index 00000000000..8d016faa9c7
--- /dev/null
+++ b/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch
@@ -0,0 +1,33 @@
+From 9ac650401ffc2fb05c9328d26e76a5e7ae39152a Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 11 Dec 2023 23:31:22 +0800
+Subject: Fix test for multiuser kernels
+
+getuid() succeeds even on non-multiuser kernels. Instead
+getgroups() is a valid test.
+
+Fixes #214 on github
+---
+ common-session.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+--- a/common-session.c
++++ b/common-session.c
+@@ -71,10 +71,13 @@ void common_session_init(int sock_in, in
+ #if !DROPBEAR_SVR_MULTIUSER
+ /* A sanity check to prevent an accidental configuration option
+ leaving multiuser systems exposed */
+- errno = 0;
+- getuid();
+- if (errno != ENOSYS) {
+- dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
++ {
++ int ret;
++ errno = 0;
++ ret = getgroups(0, NULL);
++ if (!(ret == -1 && errno == ENOSYS)) {
++ dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
++ }
+ }
+ #endif
+
diff --git a/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch b/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch
new file mode 100644
index 00000000000..d490d9545a2
--- /dev/null
+++ b/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch
@@ -0,0 +1,216 @@
+From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001
+From: Matt Johnston <matt@ucc.asn.au>
+Date: Mon, 20 Nov 2023 14:02:47 +0800
+Subject: Implement Strict KEX mode
+
+As specified by OpenSSH with kex-strict-c-v00@openssh.com and
+kex-strict-s-v00@openssh.com.
+---
+ cli-session.c | 11 +++++++++++
+ common-algo.c | 6 ++++++
+ common-kex.c | 26 +++++++++++++++++++++++++-
+ kex.h | 3 +++
+ process-packet.c | 34 +++++++++++++++++++---------------
+ ssh.h | 4 ++++
+ svr-session.c | 3 +++
+ 7 files changed, 71 insertions(+), 16 deletions(-)
+
+--- a/cli-session.c
++++ b/cli-session.c
+@@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO
+ static void recv_msg_service_accept(void);
+ static void cli_session_cleanup(void);
+ static void recv_msg_global_request_cli(void);
++static void cli_algos_initialise(void);
+
+ struct clientsession cli_ses; /* GLOBAL */
+
+@@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
+ }
+
+ chaninitialise(cli_chantypes);
++ cli_algos_initialise();
+
+ /* Set up cli_ses vars */
+ cli_session_init(proxy_cmd_pid);
+@@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons
+ fflush(stderr);
+ }
+
++static void cli_algos_initialise(void) {
++ algo_type *algo;
++ for (algo = sshkex; algo->name; algo++) {
++ if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
++ algo->usable = 0;
++ }
++ }
++}
++
+--- a/common-algo.c
++++ b/common-algo.c
+@@ -308,6 +308,12 @@ algo_type sshkex[] = {
+ {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
+ #endif
+ #endif
++#if DROPBEAR_CLIENT
++ {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
++#endif
++#if DROPBEAR_SERVER
++ {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
++#endif
+ {NULL, 0, NULL, 0, NULL}
+ };
+
+--- a/common-kex.c
++++ b/common-kex.c
+@@ -183,6 +183,10 @@ void send_msg_newkeys() {
+ gen_new_keys();
+ switch_keys();
+
++ if (ses.kexstate.strict_kex) {
++ ses.transseq = 0;
++ }
++
+ TRACE(("leave send_msg_newkeys"))
+ }
+
+@@ -193,7 +197,11 @@ void recv_msg_newkeys() {
+
+ ses.kexstate.recvnewkeys = 1;
+ switch_keys();
+-
++
++ if (ses.kexstate.strict_kex) {
++ ses.recvseq = 0;
++ }
++
+ TRACE(("leave recv_msg_newkeys"))
+ }
+
+@@ -550,6 +558,10 @@ void recv_msg_kexinit() {
+
+ ses.kexstate.recvkexinit = 1;
+
++ if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
++ dropbear_exit("First packet wasn't kexinit");
++ }
++
+ TRACE(("leave recv_msg_kexinit"))
+ }
+
+@@ -859,6 +871,18 @@ static void read_kex_algos() {
+ }
+ #endif
+
++ if (!ses.kexstate.donefirstkex) {
++ const char* strict_name;
++ if (IS_DROPBEAR_CLIENT) {
++ strict_name = SSH_STRICT_KEX_S;
++ } else {
++ strict_name = SSH_STRICT_KEX_C;
++ }
++ if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
++ ses.kexstate.strict_kex = 1;
++ }
++ }
++
+ algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
+ allgood &= goodguess;
+ if (algo == NULL || algo->data == NULL) {
+--- a/kex.h
++++ b/kex.h
+@@ -83,6 +83,9 @@ struct KEXState {
+
+ unsigned our_first_follows_matches : 1;
+
++ /* Boolean indicating that strict kex mode is in use */
++ unsigned int strict_kex;
++
+ time_t lastkextime; /* time of the last kex */
+ unsigned int datatrans; /* data transmitted since last kex */
+ unsigned int datarecv; /* data received since last kex */
+--- a/process-packet.c
++++ b/process-packet.c
+@@ -44,6 +44,7 @@ void process_packet() {
+
+ unsigned char type;
+ unsigned int i;
++ unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
+ time_t now;
+
+ TRACE2(("enter process_packet"))
+@@ -54,22 +55,24 @@ void process_packet() {
+ now = monotonic_now();
+ ses.last_packet_time_keepalive_recv = now;
+
+- /* These packets we can receive at any time */
+- switch(type) {
+
+- case SSH_MSG_IGNORE:
+- goto out;
+- case SSH_MSG_DEBUG:
+- goto out;
+-
+- case SSH_MSG_UNIMPLEMENTED:
+- /* debugging XXX */
+- TRACE(("SSH_MSG_UNIMPLEMENTED"))
+- goto out;
+-
+- case SSH_MSG_DISCONNECT:
+- /* TODO cleanup? */
+- dropbear_close("Disconnect received");
++ if (type == SSH_MSG_DISCONNECT) {
++ /* Allowed at any time */
++ dropbear_close("Disconnect received");
++ }
++
++ /* These packets may be received at any time,
++ except during first kex with strict kex */
++ if (!first_strict_kex) {
++ switch(type) {
++ case SSH_MSG_IGNORE:
++ goto out;
++ case SSH_MSG_DEBUG:
++ goto out;
++ case SSH_MSG_UNIMPLEMENTED:
++ TRACE(("SSH_MSG_UNIMPLEMENTED"))
++ goto out;
++ }
+ }
+
+ /* Ignore these packet types so that keepalives don't interfere with
+@@ -98,7 +101,8 @@ void process_packet() {
+ if (type >= 1 && type <= 49
+ && type != SSH_MSG_SERVICE_REQUEST
+ && type != SSH_MSG_SERVICE_ACCEPT
+- && type != SSH_MSG_KEXINIT)
++ && type != SSH_MSG_KEXINIT
++ && !first_strict_kex)
+ {
+ TRACE(("unknown allowed packet during kexinit"))
+ recv_unimplemented();
+--- a/ssh.h
++++ b/ssh.h
+@@ -100,6 +100,10 @@
+ #define SSH_EXT_INFO_C "ext-info-c"
+ #define SSH_SERVER_SIG_ALGS "server-sig-algs"
+
++/* OpenSSH strict KEX feature */
++#define SSH_STRICT_KEX_S "kex-strict-s-v00@openssh.com"
++#define SSH_STRICT_KEX_C "kex-strict-c-v00@openssh.com"
++
+ /* service types */
+ #define SSH_SERVICE_USERAUTH "ssh-userauth"
+ #define SSH_SERVICE_USERAUTH_LEN 12
+--- a/svr-session.c
++++ b/svr-session.c
+@@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
+ algo->usable = 0;
+ }
+ #endif
++ if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {
++ algo->usable = 0;
++ }
+ }
+ }
+
diff --git a/package/network/services/dropbear/patches/100-pubkey_path.patch b/package/network/services/dropbear/patches/100-pubkey_path.patch
index af3fbb336bf..b1075f84642 100644
--- a/package/network/services/dropbear/patches/100-pubkey_path.patch
+++ b/package/network/services/dropbear/patches/100-pubkey_path.patch
@@ -1,34 +1,50 @@
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
-@@ -386,14 +386,19 @@ static int checkpubkey(const char* keyal
- goto out;
- }
+@@ -78,6 +78,13 @@ static void send_msg_userauth_pk_ok(cons
+ const unsigned char* keyblob, unsigned int keybloblen);
+ static int checkfileperm(char * filename);
-- /* we don't need to check pw and pw_dir for validity, since
-- * its been done in checkpubkeyperms. */
-- len = strlen(ses.authstate.pw_dir);
-- /* allocate max required pathname storage,
-- * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
-- filename = m_malloc(len + 22);
-- snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
-- ses.authstate.pw_dir);
-+ if (ses.authstate.pw_uid != 0) {
-+ /* we don't need to check pw and pw_dir for validity, since
-+ * its been done in checkpubkeyperms. */
-+ len = strlen(ses.authstate.pw_dir);
-+ /* allocate max required pathname storage,
-+ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
-+ filename = m_malloc(len + 22);
-+ snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
-+ ses.authstate.pw_dir);
-+ } else {
-+ filename = m_malloc(30);
-+ strncpy(filename, "/etc/dropbear/authorized_keys", 30);
-+ }
++static const char * const global_authkeys_dir = "/etc/dropbear";
++static const int n_global_authkeys_dir = 14; /* + 1 extra byte */
++static const char * const user_authkeys_dir = ".ssh";
++static const int n_user_authkeys_dir = 5; /* + 1 extra byte */
++static const char * const authkeys_file = "authorized_keys";
++static const int n_authkeys_file = 16; /* + 1 extra byte */
++
+ /* process a pubkey auth request, sending success or failure message as
+ * appropriate */
+ void svr_auth_pubkey(int valid_user) {
+@@ -462,14 +469,21 @@ static int checkpubkey(const char* keyal
+ if (checkpubkeyperms() == DROPBEAR_FAILURE) {
+ TRACE(("bad authorized_keys permissions, or file doesn't exist"))
+ } else {
+- /* we don't need to check pw and pw_dir for validity, since
+- * its been done in checkpubkeyperms. */
+- len = strlen(ses.authstate.pw_dir);
+- /* allocate max required pathname storage,
+- * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
+- filename = m_malloc(len + 22);
+- snprintf(filename, len + 22, "%s/.ssh/authorized_keys",
+- ses.authstate.pw_dir);
++ if (ses.authstate.pw_uid == 0) {
++ len = n_global_authkeys_dir + n_authkeys_file;
++ filename = m_malloc(len);
++ snprintf(filename, len, "%s/%s", global_authkeys_dir, authkeys_file);
++ } else {
++ /* we don't need to check pw and pw_dir for validity, since
++ * its been done in checkpubkeyperms. */
++ len = strlen(ses.authstate.pw_dir);
++ /* allocate max required pathname storage,
++ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
++ len += n_user_authkeys_dir + n_authkeys_file + 1;
++ filename = m_malloc(len);
++ snprintf(filename, len, "%s/%s/%s", ses.authstate.pw_dir,
++ user_authkeys_dir, authkeys_file);
++ }
- #if DROPBEAR_SVR_MULTIUSER
- /* open the file as the authenticating user. */
-@@ -474,27 +479,36 @@ static int checkpubkeyperms() {
+ authfile = fopen(filename, "r");
+ if (!authfile) {
+@@ -543,27 +557,41 @@ static int checkpubkeyperms() {
goto out;
}
@@ -37,47 +53,51 @@
- len += 22;
- filename = m_malloc(len);
- strlcpy(filename, ses.authstate.pw_dir, len);
--
++ if (ses.authstate.pw_uid == 0) {
++ if (checkfileperm(global_authkeys_dir) != DROPBEAR_SUCCESS) {
++ goto out;
++ }
+
- /* check ~ */
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
-+ if (ses.authstate.pw_uid == 0) {
-+ if (checkfileperm("/etc/dropbear") != DROPBEAR_SUCCESS) {
-+ goto out;
-+ }
-+ if (checkfileperm("/etc/dropbear/authorized_keys") != DROPBEAR_SUCCESS) {
-+ goto out;
-+ }
-+ } else {
-+ /* allocate max required pathname storage,
-+ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
-+ len += 22;
++ len = n_global_authkeys_dir + n_authkeys_file;
+ filename = m_malloc(len);
-+ strlcpy(filename, ses.authstate.pw_dir, len);
-+
-+ /* check ~ */
-+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
-+ goto out;
-+ }
- /* check ~/.ssh */
- strlcat(filename, "/.ssh", len);
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
- }
-+ /* check ~/.ssh */
-+ strlcat(filename, "/.ssh", len);
++ snprintf(filename, len, "%s/%s", global_authkeys_dir, authkeys_file);
+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+ goto out;
+ }
++ } else {
++ /* check ~ */
++ if (checkfileperm(ses.authstate.pw_dir) != DROPBEAR_SUCCESS) {
++ goto out;
++ }
- /* now check ~/.ssh/authorized_keys */
- strlcat(filename, "/authorized_keys", len);
- if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
- goto out;
++ /* allocate max required pathname storage,
++ * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */
++ len += n_user_authkeys_dir + n_authkeys_file + 1;
++ filename = m_malloc(len);
++
++ /* check ~/.ssh */
++ snprintf(filename, len, "%s/%s", ses.authstate.pw_dir, user_authkeys_dir);
++ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
++ goto out;
++ }
++
+ /* now check ~/.ssh/authorized_keys */
-+ strlcat(filename, "/authorized_keys", len);
++ snprintf(filename, len, "%s/%s/%s", ses.authstate.pw_dir,
++ user_authkeys_dir, authkeys_file);
+ if (checkfileperm(filename) != DROPBEAR_SUCCESS) {
+ goto out;
+ }
diff --git a/package/network/services/dropbear/patches/110-change_user.patch b/package/network/services/dropbear/patches/110-change_user.patch
index 1dd67948af6..04d1df3fdeb 100644
--- a/package/network/services/dropbear/patches/110-change_user.patch
+++ b/package/network/services/dropbear/patches/110-change_user.patch
@@ -1,6 +1,6 @@
--- a/svr-chansession.c
+++ b/svr-chansession.c
-@@ -954,12 +954,12 @@ static void execchild(const void *user_d
+@@ -985,12 +985,12 @@ static void execchild(const void *user_d
/* We can only change uid/gid as root ... */
if (getuid() == 0) {
diff --git a/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
index 5e736320cc7..a26f33dfbce 100644
--- a/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
+++ b/package/network/services/dropbear/patches/130-ssh_ignore_x_args.patch
@@ -1,11 +1,13 @@
--- a/cli-runopts.c
+++ b/cli-runopts.c
-@@ -299,6 +299,8 @@ void cli_getopts(int argc, char ** argv)
- debug_trace = 1;
+@@ -329,6 +329,10 @@ void cli_getopts(int argc, char ** argv)
+ case 'z':
+ opts.disable_ip_tos = 1;
break;
- #endif
+ case 'x':
++ /* compatibility with openssh cli
++ * ("-x" disables X11 forwarding) */
+ break;
- case 'F':
- case 'e':
- #if !DROPBEAR_USER_ALGO_LIST
+ default:
+ fprintf(stderr,
+ "WARNING: Ignoring unknown option -%c\n", c);
diff --git a/package/network/services/dropbear/patches/140-disable_assert.patch b/package/network/services/dropbear/patches/140-disable_assert.patch
index 8c3ae7f1192..af01573dee5 100644
--- a/package/network/services/dropbear/patches/140-disable_assert.patch
+++ b/package/network/services/dropbear/patches/140-disable_assert.patch
@@ -1,6 +1,6 @@
--- a/dbutil.h
+++ b/dbutil.h
-@@ -75,7 +75,11 @@ int m_str_to_uint(const char* str, unsig
+@@ -80,7 +80,11 @@ int m_snprintf(char *str, size_t size, c
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
/* Dropbear assertion */
diff --git a/package/network/services/dropbear/patches/160-lto-jobserver.patch b/package/network/services/dropbear/patches/160-lto-jobserver.patch
index 1ba7dd6f442..fd80b986ae2 100644
--- a/package/network/services/dropbear/patches/160-lto-jobserver.patch
+++ b/package/network/services/dropbear/patches/160-lto-jobserver.patch
@@ -1,6 +1,6 @@
--- a/Makefile.in
+++ b/Makefile.in
-@@ -198,17 +198,17 @@ dropbearkey: $(dropbearkeyobjs)
+@@ -200,17 +200,17 @@ dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
@@ -22,7 +22,7 @@
# multi-binary compilation.
-@@ -219,7 +219,7 @@ ifeq ($(MULTI),1)
+@@ -221,7 +221,7 @@ ifeq ($(MULTI),1)
endif
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
diff --git a/package/network/services/dropbear/patches/600-allow-blank-root-password.patch b/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
index b138862ca31..07ae0227631 100644
--- a/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
+++ b/package/network/services/dropbear/patches/600-allow-blank-root-password.patch
@@ -1,6 +1,6 @@
--- a/svr-auth.c
+++ b/svr-auth.c
-@@ -125,7 +125,7 @@ void recv_msg_userauth_request() {
+@@ -124,7 +124,7 @@ void recv_msg_userauth_request() {
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"))
if (valid_user
diff --git a/package/network/services/dropbear/patches/900-configure-hardening.patch b/package/network/services/dropbear/patches/900-configure-hardening.patch
index ab1361f6ae8..5dc84849bef 100644
--- a/package/network/services/dropbear/patches/900-configure-hardening.patch
+++ b/package/network/services/dropbear/patches/900-configure-hardening.patch
@@ -1,6 +1,6 @@
--- a/configure.ac
+++ b/configure.ac
-@@ -70,53 +70,6 @@ AC_ARG_ENABLE(harden,
+@@ -87,54 +87,6 @@ AC_ARG_ENABLE(harden,
if test "$hardenbuild" -eq 1; then
AC_MSG_NOTICE(Checking for available hardened build flags:)
@@ -11,15 +11,15 @@
-
- OLDLDFLAGS="$LDFLAGS"
- TESTFLAGS="-Wl,-pie"
-- LDFLAGS="$LDFLAGS $TESTFLAGS"
-- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- LDFLAGS="$TESTFLAGS $LDFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [
- LDFLAGS="$OLDLDFLAGS"
- TESTFLAGS="-pie"
-- LDFLAGS="$LDFLAGS $TESTFLAGS"
-- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- LDFLAGS="$TESTFLAGS $LDFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
- )
- ]
@@ -27,30 +27,31 @@
- # readonly elf relocation sections (relro)
- OLDLDFLAGS="$LDFLAGS"
- TESTFLAGS="-Wl,-z,now -Wl,-z,relro"
-- LDFLAGS="$LDFLAGS $TESTFLAGS"
-- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- LDFLAGS="$TESTFLAGS $LDFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
- )
- fi # non-static
- # stack protector. -strong is good but only in gcc 4.9 or later
- OLDCFLAGS="$CFLAGS"
- TESTFLAGS="-fstack-protector-strong"
-- CFLAGS="$CFLAGS $TESTFLAGS"
-- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- CFLAGS="$TESTFLAGS $CFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [
- CFLAGS="$OLDCFLAGS"
- TESTFLAGS="-fstack-protector --param=ssp-buffer-size=4"
-- CFLAGS="$CFLAGS $TESTFLAGS"
-- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
-- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
+- CFLAGS="$TESTFLAGS $CFLAGS"
+- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDCFLAGS" ]
- )
- ]
- )
- # FORTIFY_SOURCE
- DB_TRYADDCFLAGS([-D_FORTIFY_SOURCE=2])
-
+-
# Spectre v2 mitigations
DB_TRYADDCFLAGS([-mfunction-return=thunk])
+ DB_TRYADDCFLAGS([-mindirect-branch=thunk])
diff --git a/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch b/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch
index 2432b4ef72e..a9a441ce76e 100644
--- a/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch
+++ b/package/network/services/dropbear/patches/901-bundled-libs-cflags.patch
@@ -1,48 +1,29 @@
---- a/libtomcrypt/makefile_include.mk
-+++ b/libtomcrypt/makefile_include.mk
-@@ -94,6 +94,13 @@ endif
+--- a/configure.ac
++++ b/configure.ac
+@@ -45,11 +45,8 @@ fi
+ # LTM_CFLAGS is given to ./configure by the user,
+ # DROPBEAR_LTM_CFLAGS is substituted in the LTM Makefile.in
+ DROPBEAR_LTM_CFLAGS="$LTM_CFLAGS"
+-if test -z "$DROPBEAR_LTM_CFLAGS"; then
+- DROPBEAR_LTM_CFLAGS="-O3 -funroll-loops -fomit-frame-pointer"
+-fi
+-AC_MSG_NOTICE(Setting LTM_CFLAGS to $DROPBEAR_LTM_CFLAGS)
+-AC_ARG_VAR(LTM_CFLAGS, CFLAGS for bundled libtommath. Default -O3 -funroll-loops -fomit-frame-pointer)
++AC_MSG_NOTICE(Setting LTM_CFLAGS to '$DROPBEAR_LTM_CFLAGS')
++AC_ARG_VAR(LTM_CFLAGS, CFLAGS for bundled libtommath. Defaults to empty string)
+ AC_SUBST(DROPBEAR_LTM_CFLAGS)
- LTC_CFLAGS += -Wno-type-limits
+ AC_MSG_NOTICE([Checking if compiler '$CC' supports -Wno-pointer-sign])
+--- a/libtomcrypt/src/headers/tomcrypt_dropbear.h
++++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h
+@@ -7,8 +7,10 @@
-+ifdef OPENWRT_BUILD
-+ ifeq (-Os,$(filter -Os,$(CFLAGS)))
-+ LTC_CFLAGS += -DLTC_SMALL_CODE
-+ endif
-+else
-+ ### ! OPENWRT_BUILD
-+
- ifdef LTC_DEBUG
- $(info Debug build)
- # compile for DEBUGGING (required for ccmalloc checking!!!)
-@@ -121,6 +128,9 @@ endif
- endif # COMPILE_SMALL
- endif # COMPILE_DEBUG
+ /* Use small code where possible */
+ #if DROPBEAR_SMALL_CODE
++#ifndef LTC_SMALL_CODE
+ #define LTC_SMALL_CODE
+ #endif
++#endif
-+ ### ! OPENWRT_BUILD
-+endif
-+
-
- ifneq ($(findstring clang,$(CC)),)
- LTC_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header -Wno-missing-field-initializers
---- a/libtommath/makefile_include.mk
-+++ b/libtommath/makefile_include.mk
-@@ -70,6 +70,9 @@ else
- LTM_CFLAGS += -Wsystem-headers
- endif
-
-+ifndef OPENWRT_BUILD
-+ ### ! OPENWRT_BUILD
-+
- ifdef COMPILE_DEBUG
- #debug
- LTM_CFLAGS += -g3
-@@ -90,6 +93,9 @@ endif
-
- endif # COMPILE_SIZE
-
-+ ### ! OPENWRT_BUILD
-+endif
-+
- ifneq ($(findstring clang,$(CC)),)
- LTM_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header
- endif
+ /* Fewer entries needed */
+ #define TAB_SIZE 5
diff --git a/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch b/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch
index b774a38b1aa..059177a1c58 100644
--- a/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch
+++ b/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch
@@ -21,7 +21,7 @@ Signed-off-by: Petr Štetiar <ynezz@true.cz>
--- a/signkey.c
+++ b/signkey.c
-@@ -657,8 +657,12 @@ int buf_verify(buffer * buf, sign_key *k
+@@ -652,10 +652,18 @@ int buf_verify(buffer * buf, sign_key *k
sigtype = signature_type_from_name(type_name, type_name_len);
m_free(type_name);
@@ -29,10 +29,16 @@ Signed-off-by: Petr Štetiar <ynezz@true.cz>
- dropbear_exit("Non-matching signing type");
+ if (sigtype == DROPBEAR_SIGNATURE_NONE) {
+ dropbear_exit("No signature type");
-+ }
-+
-+ if ((expect_sigtype != DROPBEAR_SIGNATURE_RSA_SHA256) && (expect_sigtype != sigtype)) {
-+ dropbear_exit("Non-matching signing type");
}
++#if DROPBEAR_RSA
++#if DROPBEAR_RSA_SHA256
++ if ((expect_sigtype != DROPBEAR_SIGNATURE_RSA_SHA256) && (expect_sigtype != sigtype)) {
++ dropbear_exit("Non-matching signing type");
++ }
++#endif
++#endif
++
keytype = signkey_type_from_signature(sigtype);
+ #if DROPBEAR_DSS
+ if (keytype == DROPBEAR_SIGNKEY_DSS) {