diff --git a/include/download.mk b/include/download.mk index 14d68bf8f5..9c8ada052b 100644 --- a/include/download.mk +++ b/include/download.mk @@ -50,6 +50,7 @@ endef dl_pack/bz2=bzip2 -c > $(1) dl_pack/gz=gzip -nc > $(1) dl_pack/xz=xz -zc -7e > $(1) +dl_pack/zst=zstd -T0 --ultra -20 -c > $(1) dl_pack/unknown=$(error ERROR: Unknown pack format for file $(1)) define dl_pack $(if $(dl_pack/$(call ext,$(1))),$(dl_pack/$(call ext,$(1))),$(dl_pack/unknown)) diff --git a/include/kernel-build.mk b/include/kernel-build.mk index c371e78ab9..32c91a5b83 100644 --- a/include/kernel-build.mk +++ b/include/kernel-build.mk @@ -70,7 +70,7 @@ ifdef CONFIG_COLLECT_KERNEL_DEBUG $(FIND) $(KERNEL_BUILD_DIR)/debug -type f | $(XARGS) $(KERNEL_CROSS)strip --only-keep-debug $(TAR) c -C $(KERNEL_BUILD_DIR) debug \ $(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \ - | bzip2 -c -9 > $(BIN_DIR)/kernel-debug.tar.bz2 + | zstd -T0 -f -o $(BIN_DIR)/kernel-debug.tar.zst endef endif diff --git a/include/unpack.mk b/include/unpack.mk index 6141b1c722..5bb27d41c9 100644 --- a/include/unpack.mk +++ b/include/unpack.mk @@ -31,6 +31,10 @@ ifeq ($(strip $(UNPACK_CMD)),) EXT:=$(call ext,$(PKG_SOURCE:.$(EXT)=)) DECOMPRESS_CMD:=xzcat $(DL_DIR)/$(PKG_SOURCE) | endif + ifeq (zst,$(EXT)) + EXT:=$(call ext,$(PKG_SOURCE:.$(EXT)=)) + DECOMPRESS_CMD:=zstdcat $(DL_DIR)/$(PKG_SOURCE) | + endif ifeq ($(filter tgz tbz tbz2 txz,$(EXT1)),$(EXT1)) EXT:=tar endif diff --git a/package/kernel/mt76/Makefile b/package/kernel/mt76/Makefile index f4b37989c8..31a4a922db 100644 --- a/package/kernel/mt76/Makefile +++ b/package/kernel/mt76/Makefile @@ -8,9 +8,9 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2020-04-27 -PKG_SOURCE_VERSION:=5f3ccc7226272198c21ec934d9072a56b0953f47 -PKG_MIRROR_HASH:=6f1a7b7d7b9f4db79d72405baeafa318769eeab270fea4479756f91ac5a2494d +PKG_SOURCE_DATE:=2020-05-30 +PKG_SOURCE_VERSION:=85c516081338d3d1454fb53b5741321c2adefbef +PKG_MIRROR_HASH:=a3e110700843ecfee10eba274ab6fe63b9d78a00eb96ee1634b145e0a9ae9a69 PKG_MAINTAINER:=Felix Fietkau PKG_BUILD_PARALLEL:=1 @@ -138,16 +138,54 @@ define KernelPackage/mt7603 AUTOLOAD:=$(call AutoProbe,mt7603e) endef +define KernelPackage/mt7615-common + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615 wireless driver common code + HIDDEN:=1 + DEPENDS+=@PCI_SUPPORT +kmod-mt76-core + FILES:= $(PKG_BUILD_DIR)/mt7615/mt7615-common.ko +endef + +define KernelPackage/mt7615-firmware + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615e firmware + DEFAULT:=PACKAGE_kmod-mt7615e +endef + define KernelPackage/mt7615e $(KernelPackage/mt76-default) - TITLE:=MediaTek MT7615 wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76-core - FILES:=\ - $(PKG_BUILD_DIR)/mt7615/mt7615-common.ko \ - $(PKG_BUILD_DIR)/mt7615/mt7615e.ko + TITLE:=MediaTek MT7615e wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt7615-common + FILES:= $(PKG_BUILD_DIR)/mt7615/mt7615e.ko AUTOLOAD:=$(call AutoProbe,mt7615e) endef +define KernelPackage/mt7663-firmware-ap + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663e firmware (optimized for AP) +endef + +define KernelPackage/mt7663-firmware-sta + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663e firmware (client mode offload) +endef + +define KernelPackage/mt7663u + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7663u wireless driver + DEPENDS+=+kmod-mt76-usb +kmod-mt7615-common + FILES:= $(PKG_BUILD_DIR)/mt7615/mt7663u.ko + AUTOLOAD:=$(call AutoProbe,mt7663u) +endef + +define KernelPackage/mt7915e + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7915e wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt7615-common + FILES:= $(PKG_BUILD_DIR)/mt7915/mt7915e.ko + AUTOLOAD:=$(call AutoProbe,mt7915e) +endef + NOSTDINC_FLAGS = \ -I$(PKG_BUILD_DIR) \ -I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \ @@ -191,14 +229,22 @@ endif ifdef CONFIG_PACKAGE_kmod-mt7603 PKG_MAKE_FLAGS += CONFIG_MT7603E=m endif -ifdef CONFIG_PACKAGE_kmod-mt7615e +ifdef CONFIG_PACKAGE_kmod-mt7615-common PKG_MAKE_FLAGS += CONFIG_MT7615_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7615e PKG_MAKE_FLAGS += CONFIG_MT7615E=m ifdef CONFIG_TARGET_mediatek_mt7622 PKG_MAKE_FLAGS += CONFIG_MT7622_WMAC=y NOSTDINC_FLAGS += -DCONFIG_MT7622_WMAC endif endif +ifdef CONFIG_PACKAGE_kmod-mt7663u + PKG_MAKE_FLAGS += CONFIG_MT7663U=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7915e + PKG_MAKE_FLAGS += CONFIG_MT7915E=m +endif define Build/Compile +$(MAKE) $(PKG_JOBS) -C "$(LINUX_DIR)" \ @@ -251,7 +297,7 @@ define KernelPackage/mt7603/install $(1)/lib/firmware endef -define KernelPackage/mt7615e/install +define KernelPackage/mt7615-firmware/install $(INSTALL_DIR) $(1)/lib/firmware/mediatek cp \ $(PKG_BUILD_DIR)/firmware/mt7615_cr4.bin \ @@ -263,6 +309,31 @@ define KernelPackage/mt7615e/install $(1)/lib/firmware/mediatek endef +define KernelPackage/mt7663-firmware-ap/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7663_n9_rebb.bin \ + $(PKG_BUILD_DIR)/firmware/mt7663pr2h_rebb.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7663-firmware-sta/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7663_n9_v3.bin \ + $(PKG_BUILD_DIR)/firmware/mt7663pr2h.bin \ + $(1)/lib/firmware/mediatek +endef + +define KernelPackage/mt7915e/install + $(INSTALL_DIR) $(1)/lib/firmware/mediatek + cp \ + $(PKG_BUILD_DIR)/firmware/mt7915_wa.bin \ + $(PKG_BUILD_DIR)/firmware/mt7915_wm.bin \ + $(PKG_BUILD_DIR)/firmware/mt7915_rom_patch.bin \ + $(1)/lib/firmware/mediatek +endef + $(eval $(call KernelPackage,mt76-core)) $(eval $(call KernelPackage,mt76-usb)) $(eval $(call KernelPackage,mt76x02-usb)) @@ -274,5 +345,11 @@ $(eval $(call KernelPackage,mt76x2-common)) $(eval $(call KernelPackage,mt76x2u)) $(eval $(call KernelPackage,mt76x2)) $(eval $(call KernelPackage,mt7603)) +$(eval $(call KernelPackage,mt7615-common)) +$(eval $(call KernelPackage,mt7615-firmware)) $(eval $(call KernelPackage,mt7615e)) +$(eval $(call KernelPackage,mt7663-firmware-ap)) +$(eval $(call KernelPackage,mt7663-firmware-sta)) +$(eval $(call KernelPackage,mt7663u)) +$(eval $(call KernelPackage,mt7915e)) $(eval $(call KernelPackage,mt76)) diff --git a/package/network/services/dropbear/Config.in b/package/network/services/dropbear/Config.in index 61a04ec876..3de4189e08 100644 --- a/package/network/services/dropbear/Config.in +++ b/package/network/services/dropbear/Config.in @@ -8,7 +8,7 @@ config DROPBEAR_CURVE25519 This enables the following key exchange algorithm: curve25519-sha256@libssh.org - Increases binary size by about 8 kB uncompressed (MIPS). + Increases binary size by about 4 kB (MIPS). config DROPBEAR_ECC bool "Elliptic curve cryptography (ECC)" @@ -49,6 +49,24 @@ config DROPBEAR_ECC_FULL Increases binary size by about 4 kB (MIPS). +config DROPBEAR_ED25519 + bool "Ed25519 support" + default n + help + This enables the following public key algorithm: + ssh-ed25519 + + Increases binary size by about 12 kB (MIPS). + +config DROPBEAR_CHACHA20POLY1305 + bool "Chacha20-Poly1305 support" + default y + help + This enables the following authenticated encryption cipher: + chacha20-poly1305@openssh.com + + Increases binary size by about 4 kB (MIPS). + config DROPBEAR_ZLIB bool "Enable compression" default n diff --git a/package/network/services/dropbear/Makefile b/package/network/services/dropbear/Makefile index b30229300c..8de0739d56 100644 --- a/package/network/services/dropbear/Makefile +++ b/package/network/services/dropbear/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dropbear PKG_VERSION:=2019.78 -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:= \ @@ -29,6 +29,7 @@ PKG_FIXUP:=autoreconf 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_UTMP CONFIG_DROPBEAR_PUTUTLINE \ CONFIG_DROPBEAR_DBCLIENT @@ -63,6 +64,7 @@ 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 @@ -110,6 +112,12 @@ define Build/Configure $(PKG_BUILD_DIR)/localoptions.h; \ done + echo '#define DROPBEAR_ED25519 $(if $(CONFIG_DROPBEAR_ED25519),1,0)' >> \ + $(PKG_BUILD_DIR)/localoptions.h + + echo '#define DROPBEAR_CHACHA20POLY1305 $(if $(CONFIG_DROPBEAR_CHACHA20POLY1305),1,0)' >> \ + $(PKG_BUILD_DIR)/localoptions.h + # remove protocol idented software version number $(ESED) 's,^(#define LOCAL_IDENT) .*$$$$,\1 "SSH-2.0-dropbear",g' \ $(PKG_BUILD_DIR)/sysoptions.h @@ -160,6 +168,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 endef diff --git a/package/network/services/dropbear/files/dropbear.init b/package/network/services/dropbear/files/dropbear.init index 173ab09285..daf111fadb 100755 --- a/package/network/services/dropbear/files/dropbear.init +++ b/package/network/services/dropbear/files/dropbear.init @@ -66,7 +66,7 @@ hk_generate_as_needed() kdir='/etc/dropbear' kgen='' - for ktype in ecdsa rsa; do + for ktype in ed25519 ecdsa rsa; do hk_verify "${kdir}/dropbear_${ktype}_host_key" && continue kgen="${kgen} ${ktype}" diff --git a/package/network/services/dropbear/patches/020-backport-ed25519-support.patch b/package/network/services/dropbear/patches/020-backport-ed25519-support.patch new file mode 100644 index 0000000000..00a3bbbee1 --- /dev/null +++ b/package/network/services/dropbear/patches/020-backport-ed25519-support.patch @@ -0,0 +1,2890 @@ +From 3d12521735e7ef7e48be217af0f27d68e23050a7 Mon Sep 17 00:00:00 2001 +From: Vladislav Grishenko +Date: Wed, 11 Mar 2020 21:09:45 +0500 +Subject: [PATCH] Add Ed25519 support (#91) + +* Add support for Ed25519 as a public key type + +Ed25519 is a elliptic curve signature scheme that offers +better security than ECDSA and DSA and good performance. It may be +used for both user and host keys. + +OpenSSH key import and fuzzer are not supported yet. + +Initially inspired by Peter Szabo. + +* Add curve25519 and ed25519 fuzzers + +* Add import and export of Ed25519 keys +--- + .travis.yml | 1 + + FUZZER-NOTES.md | 3 + + LICENSE | 71 ++-- + Makefile.in | 12 +- + README | 1 + + cli-kex.c | 2 +- + common-algo.c | 3 + + common-kex.c | 14 +- + curve25519-donna.c | 860 ----------------------------------------- + curve25519.c | 502 ++++++++++++++++++++++++ + curve25519.h | 37 ++ + default_options.h | 7 +- + dropbear.8 | 6 +- + dropbearkey.c | 25 ++ + ed25519.c | 184 +++++++++ + ed25519.h | 54 +++ + filelist.txt | 4 + + fuzz-common.c | 8 + + fuzz-hostkeys.c | 10 + + fuzzer-kexcurve25519.c | 72 ++++ + gened25519.c | 47 +++ + gened25519.h | 36 ++ + gensignkey.c | 10 + + keyimport.c | 158 +++++++- + signkey.c | 60 ++- + signkey.h | 7 + + ssh.h | 2 + + svr-kex.c | 8 +- + svr-runopts.c | 24 ++ + sysoptions.h | 7 +- + 30 files changed, 1289 insertions(+), 946 deletions(-) + delete mode 100644 curve25519-donna.c + create mode 100644 curve25519.c + create mode 100644 curve25519.h + create mode 100644 ed25519.c + create mode 100644 ed25519.h + create mode 100644 fuzzer-kexcurve25519.c + create mode 100644 gened25519.c + create mode 100644 gened25519.h + +diff --git a/.travis.yml b/.travis.yml +index 9bcbce4..99499c8 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -57,6 +57,7 @@ script: + - ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256 + - ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384 + - ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521 ++ - ~/inst/bin/dropbearkey -t ed25519 -f tested25519 + - test -z $DO_FUZZ || ./fuzzers_test.sh + + branches: +diff --git a/FUZZER-NOTES.md b/FUZZER-NOTES.md +index 7b88238..4967eba 100644 +--- a/FUZZER-NOTES.md ++++ b/FUZZER-NOTES.md +@@ -72,3 +72,6 @@ Current fuzzers are + + - [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh. + This is testing libtommath ECC routines. ++ ++- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange ++ like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines. +diff --git a/LICENSE b/LICENSE +index c400d94..a4849ff 100644 +--- a/LICENSE ++++ b/LICENSE +@@ -90,52 +90,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + ===== + +-curve25519-donna: +- +-/* Copyright 2008, Google Inc. +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions are +- * met: +- * +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * * Redistributions in binary form must reproduce the above +- * copyright notice, this list of conditions and the following disclaimer +- * in the documentation and/or other materials provided with the +- * distribution. +- * * Neither the name of Google Inc. nor the names of its +- * contributors may be used to endorse or promote products derived from +- * this software without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- * +- * curve25519-donna: Curve25519 elliptic curve, public key function +- * +- * http://code.google.com/p/curve25519-donna/ +- * +- * Adam Langley +- * +- * Derived from public domain C code by Daniel J. Bernstein +- * +- * More information about curve25519 can be found here +- * http://cr.yp.to/ecdh.html +- * +- * djb's sample implementation of curve25519 is written in a special assembly +- * language called qhasm and uses the floating point registers. +- * +- * This is, almost, a clean room reimplementation from the curve25519 paper. It +- * uses many of the tricks described therein. Only the crecip function is taken +- * from the sample implementation. +- */ ++crypto25519.c: ++crypto26619.h: ++ ++Modified TweetNaCl version 20140427, a self-contained public-domain C library. ++https://tweetnacl.cr.yp.to/ ++ ++Contributors (alphabetical order) ++Daniel J. Bernstein, University of Illinois at Chicago and Technische ++Universiteit Eindhoven ++Bernard van Gastel, Radboud Universiteit Nijmegen ++Wesley Janssen, Radboud Universiteit Nijmegen ++Tanja Lange, Technische Universiteit Eindhoven ++Peter Schwabe, Radboud Universiteit Nijmegen ++Sjaak Smetsers, Radboud Universiteit Nijmegen ++ ++Acknowledgments ++This work was supported by the U.S. National Science Foundation under grant ++1018836. "Any opinions, findings, and conclusions or recommendations expressed ++in this material are those of the author(s) and do not necessarily reflect the ++views of the National Science Foundation." ++This work was supported by the Netherlands Organisation for Scientific ++Research (NWO) under grant 639.073.005 and Veni 2013 project 13114. +diff --git a/Makefile.in b/Makefile.in +index bc55b7d..aaf7b3b 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -36,8 +36,9 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \ + queue.o \ + atomicio.o compat.o fake-rfc2553.o \ + ltc_prng.o ecc.o ecdsa.o crypto_desc.o \ ++ curve25519.o ed25519.o \ + dbmalloc.o \ +- gensignkey.o gendss.o genrsa.o ++ gensignkey.o gendss.o genrsa.o gened25519.o + + SVROBJS=svr-kex.o svr-auth.o sshpty.o \ + svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \ +@@ -52,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ + CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ + common-channel.o common-chansession.o termcodes.o loginrec.o \ + tcp-accept.o listener.o process-packet.o dh_groups.o \ +- common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o ++ common-runopts.o circbuffer.o list.o netio.o + + KEYOBJS=dropbearkey.o + +@@ -264,7 +265,7 @@ tidy: + ## Fuzzing targets + + # list of fuzz targets +-FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh ++FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 + + FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS)) + +@@ -303,6 +304,9 @@ fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o + fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o + $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ + ++fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o ++ $(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@ ++ + fuzzer-%.options: Makefile + echo "[libfuzzer]" > $@ + echo "max_len = 50000" >> $@ +@@ -313,7 +317,9 @@ fuzz-hostkeys: + dropbearkey -t rsa -f keyr + dropbearkey -t dss -f keyd + dropbearkey -t ecdsa -size 256 -f keye ++ dropbearkey -t ed25519 -f keyed25519 + echo > hostkeys.c + /usr/bin/xxd -i -a keyr >> hostkeys.c + /usr/bin/xxd -i -a keye >> hostkeys.c + /usr/bin/xxd -i -a keyd >> hostkeys.c ++ /usr/bin/xxd -i -a keyed25519 >> hostkeys.c +diff --git a/README b/README +index b8a6fd2..d197ec7 100644 +--- a/README ++++ b/README +@@ -55,6 +55,7 @@ To run the server, you need to generate server keys, this is one-off: + ./dropbearkey -t rsa -f dropbear_rsa_host_key + ./dropbearkey -t dss -f dropbear_dss_host_key + ./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key ++./dropbearkey -t ed25519 -f dropbear_ed25519_host_key + + or alternatively convert OpenSSH keys to Dropbear: + ./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key +diff --git a/cli-kex.c b/cli-kex.c +index b02cfc7..7cefb5f 100644 +--- a/cli-kex.c ++++ b/cli-kex.c +@@ -81,7 +81,7 @@ void send_msg_kexdh_init() { + } + cli_ses.curve25519_param = gen_kexcurve25519_param(); + } +- buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN); ++ buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN); + break; + #endif + } +diff --git a/common-algo.c b/common-algo.c +index 2f896ab..558aad2 100644 +--- a/common-algo.c ++++ b/common-algo.c +@@ -222,6 +222,9 @@ algo_type ssh_nocompress[] = { + }; + + algo_type sshhostkey[] = { ++#if DROPBEAR_ED25519 ++ {"ssh-ed25519", DROPBEAR_SIGNKEY_ED25519, NULL, 1, NULL}, ++#endif + #if DROPBEAR_ECDSA + #if DROPBEAR_ECC_256 + {"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL}, +diff --git a/common-kex.c b/common-kex.c +index d4933dd..16b7e27 100644 +--- a/common-kex.c ++++ b/common-kex.c +@@ -36,6 +36,7 @@ + #include "dbrandom.h" + #include "runopts.h" + #include "ecc.h" ++#include "curve25519.h" + #include "crypto_desc.h" + + static void kexinitialise(void); +@@ -703,23 +704,18 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them, + #endif /* DROPBEAR_ECDH */ + + #if DROPBEAR_CURVE25519 +-struct kex_curve25519_param *gen_kexcurve25519_param () { ++struct kex_curve25519_param *gen_kexcurve25519_param() { + /* Per http://cr.yp.to/ecdh.html */ + struct kex_curve25519_param *param = m_malloc(sizeof(*param)); + const unsigned char basepoint[32] = {9}; + + genrandom(param->priv, CURVE25519_LEN); +- param->priv[0] &= 248; +- param->priv[31] &= 127; +- param->priv[31] |= 64; +- +- curve25519_donna(param->pub, param->priv, basepoint); ++ dropbear_curve25519_scalarmult(param->pub, param->priv, basepoint); + + return param; + } + +-void free_kexcurve25519_param(struct kex_curve25519_param *param) +-{ ++void free_kexcurve25519_param(struct kex_curve25519_param *param) { + m_burn(param->priv, CURVE25519_LEN); + m_free(param); + } +@@ -736,7 +732,7 @@ void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buff + dropbear_exit("Bad curve25519"); + } + +- curve25519_donna(out, param->priv, buf_pub_them->data); ++ dropbear_curve25519_scalarmult(out, param->priv, buf_pub_them->data); + + if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) { + dropbear_exit("Bad curve25519"); +diff --git a/curve25519-donna.c b/curve25519-donna.c +deleted file mode 100644 +index ef0b6d1..0000000 +--- a/curve25519-donna.c ++++ /dev/null +@@ -1,860 +0,0 @@ +-/* Copyright 2008, Google Inc. +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions are +- * met: +- * +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * * Redistributions in binary form must reproduce the above +- * copyright notice, this list of conditions and the following disclaimer +- * in the documentation and/or other materials provided with the +- * distribution. +- * * Neither the name of Google Inc. nor the names of its +- * contributors may be used to endorse or promote products derived from +- * this software without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- * +- * curve25519-donna: Curve25519 elliptic curve, public key function +- * +- * http://code.google.com/p/curve25519-donna/ +- * +- * Adam Langley +- * +- * Derived from public domain C code by Daniel J. Bernstein +- * +- * More information about curve25519 can be found here +- * http://cr.yp.to/ecdh.html +- * +- * djb's sample implementation of curve25519 is written in a special assembly +- * language called qhasm and uses the floating point registers. +- * +- * This is, almost, a clean room reimplementation from the curve25519 paper. It +- * uses many of the tricks described therein. Only the crecip function is taken +- * from the sample implementation. */ +- +-#include +-#include +- +-#ifdef _MSC_VER +-#define inline __inline +-#endif +- +-typedef uint8_t u8; +-typedef int32_t s32; +-typedef int64_t limb; +- +-/* Field element representation: +- * +- * Field elements are written as an array of signed, 64-bit limbs, least +- * significant first. The value of the field element is: +- * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... +- * +- * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */ +- +-/* Sum two numbers: output += in */ +-static void fsum(limb *output, const limb *in) { +- unsigned i; +- for (i = 0; i < 10; i += 2) { +- output[0+i] = output[0+i] + in[0+i]; +- output[1+i] = output[1+i] + in[1+i]; +- } +-} +- +-/* Find the difference of two numbers: output = in - output +- * (note the order of the arguments!). */ +-static void fdifference(limb *output, const limb *in) { +- unsigned i; +- for (i = 0; i < 10; ++i) { +- output[i] = in[i] - output[i]; +- } +-} +- +-/* Multiply a number by a scalar: output = in * scalar */ +-static void fscalar_product(limb *output, const limb *in, const limb scalar) { +- unsigned i; +- for (i = 0; i < 10; ++i) { +- output[i] = in[i] * scalar; +- } +-} +- +-/* Multiply two numbers: output = in2 * in +- * +- * output must be distinct to both inputs. The inputs are reduced coefficient +- * form, the output is not. +- * +- * output[x] <= 14 * the largest product of the input limbs. */ +-static void fproduct(limb *output, const limb *in2, const limb *in) { +- output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); +- output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + +- ((limb) ((s32) in2[1])) * ((s32) in[0]); +- output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + +- ((limb) ((s32) in2[0])) * ((s32) in[2]) + +- ((limb) ((s32) in2[2])) * ((s32) in[0]); +- output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + +- ((limb) ((s32) in2[2])) * ((s32) in[1]) + +- ((limb) ((s32) in2[0])) * ((s32) in[3]) + +- ((limb) ((s32) in2[3])) * ((s32) in[0]); +- output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + +- 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + +- ((limb) ((s32) in2[3])) * ((s32) in[1])) + +- ((limb) ((s32) in2[0])) * ((s32) in[4]) + +- ((limb) ((s32) in2[4])) * ((s32) in[0]); +- output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + +- ((limb) ((s32) in2[3])) * ((s32) in[2]) + +- ((limb) ((s32) in2[1])) * ((s32) in[4]) + +- ((limb) ((s32) in2[4])) * ((s32) in[1]) + +- ((limb) ((s32) in2[0])) * ((s32) in[5]) + +- ((limb) ((s32) in2[5])) * ((s32) in[0]); +- output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + +- ((limb) ((s32) in2[1])) * ((s32) in[5]) + +- ((limb) ((s32) in2[5])) * ((s32) in[1])) + +- ((limb) ((s32) in2[2])) * ((s32) in[4]) + +- ((limb) ((s32) in2[4])) * ((s32) in[2]) + +- ((limb) ((s32) in2[0])) * ((s32) in[6]) + +- ((limb) ((s32) in2[6])) * ((s32) in[0]); +- output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + +- ((limb) ((s32) in2[4])) * ((s32) in[3]) + +- ((limb) ((s32) in2[2])) * ((s32) in[5]) + +- ((limb) ((s32) in2[5])) * ((s32) in[2]) + +- ((limb) ((s32) in2[1])) * ((s32) in[6]) + +- ((limb) ((s32) in2[6])) * ((s32) in[1]) + +- ((limb) ((s32) in2[0])) * ((s32) in[7]) + +- ((limb) ((s32) in2[7])) * ((s32) in[0]); +- output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + +- 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + +- ((limb) ((s32) in2[5])) * ((s32) in[3]) + +- ((limb) ((s32) in2[1])) * ((s32) in[7]) + +- ((limb) ((s32) in2[7])) * ((s32) in[1])) + +- ((limb) ((s32) in2[2])) * ((s32) in[6]) + +- ((limb) ((s32) in2[6])) * ((s32) in[2]) + +- ((limb) ((s32) in2[0])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[0]); +- output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + +- ((limb) ((s32) in2[5])) * ((s32) in[4]) + +- ((limb) ((s32) in2[3])) * ((s32) in[6]) + +- ((limb) ((s32) in2[6])) * ((s32) in[3]) + +- ((limb) ((s32) in2[2])) * ((s32) in[7]) + +- ((limb) ((s32) in2[7])) * ((s32) in[2]) + +- ((limb) ((s32) in2[1])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[1]) + +- ((limb) ((s32) in2[0])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[0]); +- output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + +- ((limb) ((s32) in2[3])) * ((s32) in[7]) + +- ((limb) ((s32) in2[7])) * ((s32) in[3]) + +- ((limb) ((s32) in2[1])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[1])) + +- ((limb) ((s32) in2[4])) * ((s32) in[6]) + +- ((limb) ((s32) in2[6])) * ((s32) in[4]) + +- ((limb) ((s32) in2[2])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[2]); +- output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + +- ((limb) ((s32) in2[6])) * ((s32) in[5]) + +- ((limb) ((s32) in2[4])) * ((s32) in[7]) + +- ((limb) ((s32) in2[7])) * ((s32) in[4]) + +- ((limb) ((s32) in2[3])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[3]) + +- ((limb) ((s32) in2[2])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[2]); +- output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + +- 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + +- ((limb) ((s32) in2[7])) * ((s32) in[5]) + +- ((limb) ((s32) in2[3])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[3])) + +- ((limb) ((s32) in2[4])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[4]); +- output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + +- ((limb) ((s32) in2[7])) * ((s32) in[6]) + +- ((limb) ((s32) in2[5])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[5]) + +- ((limb) ((s32) in2[4])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[4]); +- output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + +- ((limb) ((s32) in2[5])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[5])) + +- ((limb) ((s32) in2[6])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[6]); +- output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + +- ((limb) ((s32) in2[8])) * ((s32) in[7]) + +- ((limb) ((s32) in2[6])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[6]); +- output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + +- 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[7])); +- output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + +- ((limb) ((s32) in2[9])) * ((s32) in[8]); +- output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); +-} +- +-/* Reduce a long form to a short form by taking the input mod 2^255 - 19. +- * +- * On entry: |output[i]| < 14*2^54 +- * On exit: |output[0..8]| < 280*2^54 */ +-static void freduce_degree(limb *output) { +- /* Each of these shifts and adds ends up multiplying the value by 19. +- * +- * For output[0..8], the absolute entry value is < 14*2^54 and we add, at +- * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */ +- output[8] += output[18] << 4; +- output[8] += output[18] << 1; +- output[8] += output[18]; +- output[7] += output[17] << 4; +- output[7] += output[17] << 1; +- output[7] += output[17]; +- output[6] += output[16] << 4; +- output[6] += output[16] << 1; +- output[6] += output[16]; +- output[5] += output[15] << 4; +- output[5] += output[15] << 1; +- output[5] += output[15]; +- output[4] += output[14] << 4; +- output[4] += output[14] << 1; +- output[4] += output[14]; +- output[3] += output[13] << 4; +- output[3] += output[13] << 1; +- output[3] += output[13]; +- output[2] += output[12] << 4; +- output[2] += output[12] << 1; +- output[2] += output[12]; +- output[1] += output[11] << 4; +- output[1] += output[11] << 1; +- output[1] += output[11]; +- output[0] += output[10] << 4; +- output[0] += output[10] << 1; +- output[0] += output[10]; +-} +- +-#if (-1 & 3) != 3 +-#error "This code only works on a two's complement system" +-#endif +- +-/* return v / 2^26, using only shifts and adds. +- * +- * On entry: v can take any value. */ +-static inline limb +-div_by_2_26(const limb v) +-{ +- /* High word of v; no shift needed. */ +- const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); +- /* Set to all 1s if v was negative; else set to 0s. */ +- const int32_t sign = ((int32_t) highword) >> 31; +- /* Set to 0x3ffffff if v was negative; else set to 0. */ +- const int32_t roundoff = ((uint32_t) sign) >> 6; +- /* Should return v / (1<<26) */ +- return (v + roundoff) >> 26; +-} +- +-/* return v / (2^25), using only shifts and adds. +- * +- * On entry: v can take any value. */ +-static inline limb +-div_by_2_25(const limb v) +-{ +- /* High word of v; no shift needed*/ +- const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); +- /* Set to all 1s if v was negative; else set to 0s. */ +- const int32_t sign = ((int32_t) highword) >> 31; +- /* Set to 0x1ffffff if v was negative; else set to 0. */ +- const int32_t roundoff = ((uint32_t) sign) >> 7; +- /* Should return v / (1<<25) */ +- return (v + roundoff) >> 25; +-} +- +-/* Reduce all coefficients of the short form input so that |x| < 2^26. +- * +- * On entry: |output[i]| < 280*2^54 */ +-static void freduce_coefficients(limb *output) { +- unsigned i; +- +- output[10] = 0; +- +- for (i = 0; i < 10; i += 2) { +- limb over = div_by_2_26(output[i]); +- /* The entry condition (that |output[i]| < 280*2^54) means that over is, at +- * most, 280*2^28 in the first iteration of this loop. This is added to the +- * next limb and we can approximate the resulting bound of that limb by +- * 281*2^54. */ +- output[i] -= over << 26; +- output[i+1] += over; +- +- /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < +- * 281*2^29. When this is added to the next limb, the resulting bound can +- * be approximated as 281*2^54. +- * +- * For subsequent iterations of the loop, 281*2^54 remains a conservative +- * bound and no overflow occurs. */ +- over = div_by_2_25(output[i+1]); +- output[i+1] -= over << 25; +- output[i+2] += over; +- } +- /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ +- output[0] += output[10] << 4; +- output[0] += output[10] << 1; +- output[0] += output[10]; +- +- output[10] = 0; +- +- /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 +- * So |over| will be no more than 2^16. */ +- { +- limb over = div_by_2_26(output[0]); +- output[0] -= over << 26; +- output[1] += over; +- } +- +- /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The +- * bound on |output[1]| is sufficient to meet our needs. */ +-} +- +-/* A helpful wrapper around fproduct: output = in * in2. +- * +- * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27. +- * +- * output must be distinct to both inputs. The output is reduced degree +- * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */ +-static void +-fmul(limb *output, const limb *in, const limb *in2) { +- limb t[19]; +- fproduct(t, in, in2); +- /* |t[i]| < 14*2^54 */ +- freduce_degree(t); +- freduce_coefficients(t); +- /* |t[i]| < 2^26 */ +- memcpy(output, t, sizeof(limb) * 10); +-} +- +-/* Square a number: output = in**2 +- * +- * output must be distinct from the input. The inputs are reduced coefficient +- * form, the output is not. +- * +- * output[x] <= 14 * the largest product of the input limbs. */ +-static void fsquare_inner(limb *output, const limb *in) { +- output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); +- output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); +- output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + +- ((limb) ((s32) in[0])) * ((s32) in[2])); +- output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + +- ((limb) ((s32) in[0])) * ((s32) in[3])); +- output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + +- 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + +- 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); +- output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + +- ((limb) ((s32) in[1])) * ((s32) in[4]) + +- ((limb) ((s32) in[0])) * ((s32) in[5])); +- output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + +- ((limb) ((s32) in[2])) * ((s32) in[4]) + +- ((limb) ((s32) in[0])) * ((s32) in[6]) + +- 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); +- output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + +- ((limb) ((s32) in[2])) * ((s32) in[5]) + +- ((limb) ((s32) in[1])) * ((s32) in[6]) + +- ((limb) ((s32) in[0])) * ((s32) in[7])); +- output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + +- 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + +- ((limb) ((s32) in[0])) * ((s32) in[8]) + +- 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + +- ((limb) ((s32) in[3])) * ((s32) in[5]))); +- output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + +- ((limb) ((s32) in[3])) * ((s32) in[6]) + +- ((limb) ((s32) in[2])) * ((s32) in[7]) + +- ((limb) ((s32) in[1])) * ((s32) in[8]) + +- ((limb) ((s32) in[0])) * ((s32) in[9])); +- output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + +- ((limb) ((s32) in[4])) * ((s32) in[6]) + +- ((limb) ((s32) in[2])) * ((s32) in[8]) + +- 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + +- ((limb) ((s32) in[1])) * ((s32) in[9]))); +- output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + +- ((limb) ((s32) in[4])) * ((s32) in[7]) + +- ((limb) ((s32) in[3])) * ((s32) in[8]) + +- ((limb) ((s32) in[2])) * ((s32) in[9])); +- output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + +- 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + +- 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + +- ((limb) ((s32) in[3])) * ((s32) in[9]))); +- output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + +- ((limb) ((s32) in[5])) * ((s32) in[8]) + +- ((limb) ((s32) in[4])) * ((s32) in[9])); +- output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + +- ((limb) ((s32) in[6])) * ((s32) in[8]) + +- 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); +- output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + +- ((limb) ((s32) in[6])) * ((s32) in[9])); +- output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + +- 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); +- output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); +- output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); +-} +- +-/* fsquare sets output = in^2. +- * +- * On entry: The |in| argument is in reduced coefficients form and |in[i]| < +- * 2^27. +- * +- * On exit: The |output| argument is in reduced coefficients form (indeed, one +- * need only provide storage for 10 limbs) and |out[i]| < 2^26. */ +-static void +-fsquare(limb *output, const limb *in) { +- limb t[19]; +- fsquare_inner(t, in); +- /* |t[i]| < 14*2^54 because the largest product of two limbs will be < +- * 2^(27+27) and fsquare_inner adds together, at most, 14 of those +- * products. */ +- freduce_degree(t); +- freduce_coefficients(t); +- /* |t[i]| < 2^26 */ +- memcpy(output, t, sizeof(limb) * 10); +-} +- +-/* Take a little-endian, 32-byte number and expand it into polynomial form */ +-static void +-fexpand(limb *output, const u8 *input) { +-#define F(n,start,shift,mask) \ +- output[n] = ((((limb) input[start + 0]) | \ +- ((limb) input[start + 1]) << 8 | \ +- ((limb) input[start + 2]) << 16 | \ +- ((limb) input[start + 3]) << 24) >> shift) & mask; +- F(0, 0, 0, 0x3ffffff); +- F(1, 3, 2, 0x1ffffff); +- F(2, 6, 3, 0x3ffffff); +- F(3, 9, 5, 0x1ffffff); +- F(4, 12, 6, 0x3ffffff); +- F(5, 16, 0, 0x1ffffff); +- F(6, 19, 1, 0x3ffffff); +- F(7, 22, 3, 0x1ffffff); +- F(8, 25, 4, 0x3ffffff); +- F(9, 28, 6, 0x1ffffff); +-#undef F +-} +- +-#if (-32 >> 1) != -16 +-#error "This code only works when >> does sign-extension on negative numbers" +-#endif +- +-/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */ +-static s32 s32_eq(s32 a, s32 b) { +- a = ~(a ^ b); +- a &= a << 16; +- a &= a << 8; +- a &= a << 4; +- a &= a << 2; +- a &= a << 1; +- return a >> 31; +-} +- +-/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are +- * both non-negative. */ +-static s32 s32_gte(s32 a, s32 b) { +- a -= b; +- /* a >= 0 iff a >= b. */ +- return ~(a >> 31); +-} +- +-/* Take a fully reduced polynomial form number and contract it into a +- * little-endian, 32-byte array. +- * +- * On entry: |input_limbs[i]| < 2^26 */ +-static void +-fcontract(u8 *output, limb *input_limbs) { +- int i; +- int j; +- s32 input[10]; +- s32 mask; +- +- /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ +- for (i = 0; i < 10; i++) { +- input[i] = input_limbs[i]; +- } +- +- for (j = 0; j < 2; ++j) { +- for (i = 0; i < 9; ++i) { +- if ((i & 1) == 1) { +- /* This calculation is a time-invariant way to make input[i] +- * non-negative by borrowing from the next-larger limb. */ +- const s32 mask = input[i] >> 31; +- const s32 carry = -((input[i] & mask) >> 25); +- input[i] = input[i] + (carry << 25); +- input[i+1] = input[i+1] - carry; +- } else { +- const s32 mask = input[i] >> 31; +- const s32 carry = -((input[i] & mask) >> 26); +- input[i] = input[i] + (carry << 26); +- input[i+1] = input[i+1] - carry; +- } +- } +- +- /* There's no greater limb for input[9] to borrow from, but we can multiply +- * by 19 and borrow from input[0], which is valid mod 2^255-19. */ +- { +- const s32 mask = input[9] >> 31; +- const s32 carry = -((input[9] & mask) >> 25); +- input[9] = input[9] + (carry << 25); +- input[0] = input[0] - (carry * 19); +- } +- +- /* After the first iteration, input[1..9] are non-negative and fit within +- * 25 or 26 bits, depending on position. However, input[0] may be +- * negative. */ +- } +- +- /* The first borrow-propagation pass above ended with every limb +- except (possibly) input[0] non-negative. +- +- If input[0] was negative after the first pass, then it was because of a +- carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, +- one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. +- +- In the second pass, each limb is decreased by at most one. Thus the second +- borrow-propagation pass could only have wrapped around to decrease +- input[0] again if the first pass left input[0] negative *and* input[1] +- through input[9] were all zero. In that case, input[1] is now 2^25 - 1, +- and this last borrow-propagation step will leave input[1] non-negative. */ +- { +- const s32 mask = input[0] >> 31; +- const s32 carry = -((input[0] & mask) >> 26); +- input[0] = input[0] + (carry << 26); +- input[1] = input[1] - carry; +- } +- +- /* All input[i] are now non-negative. However, there might be values between +- * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ +- for (j = 0; j < 2; j++) { +- for (i = 0; i < 9; i++) { +- if ((i & 1) == 1) { +- const s32 carry = input[i] >> 25; +- input[i] &= 0x1ffffff; +- input[i+1] += carry; +- } else { +- const s32 carry = input[i] >> 26; +- input[i] &= 0x3ffffff; +- input[i+1] += carry; +- } +- } +- +- { +- const s32 carry = input[9] >> 25; +- input[9] &= 0x1ffffff; +- input[0] += 19*carry; +- } +- } +- +- /* If the first carry-chain pass, just above, ended up with a carry from +- * input[9], and that caused input[0] to be out-of-bounds, then input[0] was +- * < 2^26 + 2*19, because the carry was, at most, two. +- * +- * If the second pass carried from input[9] again then input[0] is < 2*19 and +- * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ +- +- /* It still remains the case that input might be between 2^255-19 and 2^255. +- * In this case, input[1..9] must take their maximum value and input[0] must +- * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ +- mask = s32_gte(input[0], 0x3ffffed); +- for (i = 1; i < 10; i++) { +- if ((i & 1) == 1) { +- mask &= s32_eq(input[i], 0x1ffffff); +- } else { +- mask &= s32_eq(input[i], 0x3ffffff); +- } +- } +- +- /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus +- * this conditionally subtracts 2^255-19. */ +- input[0] -= mask & 0x3ffffed; +- +- for (i = 1; i < 10; i++) { +- if ((i & 1) == 1) { +- input[i] -= mask & 0x1ffffff; +- } else { +- input[i] -= mask & 0x3ffffff; +- } +- } +- +- input[1] <<= 2; +- input[2] <<= 3; +- input[3] <<= 5; +- input[4] <<= 6; +- input[6] <<= 1; +- input[7] <<= 3; +- input[8] <<= 4; +- input[9] <<= 6; +-#define F(i, s) \ +- output[s+0] |= input[i] & 0xff; \ +- output[s+1] = (input[i] >> 8) & 0xff; \ +- output[s+2] = (input[i] >> 16) & 0xff; \ +- output[s+3] = (input[i] >> 24) & 0xff; +- output[0] = 0; +- output[16] = 0; +- F(0,0); +- F(1,3); +- F(2,6); +- F(3,9); +- F(4,12); +- F(5,16); +- F(6,19); +- F(7,22); +- F(8,25); +- F(9,28); +-#undef F +-} +- +-/* Input: Q, Q', Q-Q' +- * Output: 2Q, Q+Q' +- * +- * x2 z3: long form +- * x3 z3: long form +- * x z: short form, destroyed +- * xprime zprime: short form, destroyed +- * qmqp: short form, preserved +- * +- * On entry and exit, the absolute value of the limbs of all inputs and outputs +- * are < 2^26. */ +-static void fmonty(limb *x2, limb *z2, /* output 2Q */ +- limb *x3, limb *z3, /* output Q + Q' */ +- limb *x, limb *z, /* input Q */ +- limb *xprime, limb *zprime, /* input Q' */ +- const limb *qmqp /* input Q - Q' */) { +- limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], +- zzprime[19], zzzprime[19], xxxprime[19]; +- +- memcpy(origx, x, 10 * sizeof(limb)); +- fsum(x, z); +- /* |x[i]| < 2^27 */ +- fdifference(z, origx); /* does x - z */ +- /* |z[i]| < 2^27 */ +- +- memcpy(origxprime, xprime, sizeof(limb) * 10); +- fsum(xprime, zprime); +- /* |xprime[i]| < 2^27 */ +- fdifference(zprime, origxprime); +- /* |zprime[i]| < 2^27 */ +- fproduct(xxprime, xprime, z); +- /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < +- * 2^(27+27) and fproduct adds together, at most, 14 of those products. +- * (Approximating that to 2^58 doesn't work out.) */ +- fproduct(zzprime, x, zprime); +- /* |zzprime[i]| < 14*2^54 */ +- freduce_degree(xxprime); +- freduce_coefficients(xxprime); +- /* |xxprime[i]| < 2^26 */ +- freduce_degree(zzprime); +- freduce_coefficients(zzprime); +- /* |zzprime[i]| < 2^26 */ +- memcpy(origxprime, xxprime, sizeof(limb) * 10); +- fsum(xxprime, zzprime); +- /* |xxprime[i]| < 2^27 */ +- fdifference(zzprime, origxprime); +- /* |zzprime[i]| < 2^27 */ +- fsquare(xxxprime, xxprime); +- /* |xxxprime[i]| < 2^26 */ +- fsquare(zzzprime, zzprime); +- /* |zzzprime[i]| < 2^26 */ +- fproduct(zzprime, zzzprime, qmqp); +- /* |zzprime[i]| < 14*2^52 */ +- freduce_degree(zzprime); +- freduce_coefficients(zzprime); +- /* |zzprime[i]| < 2^26 */ +- memcpy(x3, xxxprime, sizeof(limb) * 10); +- memcpy(z3, zzprime, sizeof(limb) * 10); +- +- fsquare(xx, x); +- /* |xx[i]| < 2^26 */ +- fsquare(zz, z); +- /* |zz[i]| < 2^26 */ +- fproduct(x2, xx, zz); +- /* |x2[i]| < 14*2^52 */ +- freduce_degree(x2); +- freduce_coefficients(x2); +- /* |x2[i]| < 2^26 */ +- fdifference(zz, xx); /* does zz = xx - zz */ +- /* |zz[i]| < 2^27 */ +- memset(zzz + 10, 0, sizeof(limb) * 9); +- fscalar_product(zzz, zz, 121665); +- /* |zzz[i]| < 2^(27+17) */ +- /* No need to call freduce_degree here: +- fscalar_product doesn't increase the degree of its input. */ +- freduce_coefficients(zzz); +- /* |zzz[i]| < 2^26 */ +- fsum(zzz, xx); +- /* |zzz[i]| < 2^27 */ +- fproduct(z2, zz, zzz); +- /* |z2[i]| < 14*2^(26+27) */ +- freduce_degree(z2); +- freduce_coefficients(z2); +- /* |z2|i| < 2^26 */ +-} +- +-/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave +- * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid +- * side-channel attacks. +- * +- * NOTE that this function requires that 'iswap' be 1 or 0; other values give +- * wrong results. Also, the two limb arrays must be in reduced-coefficient, +- * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, +- * and all all values in a[0..9],b[0..9] must have magnitude less than +- * INT32_MAX. */ +-static void +-swap_conditional(limb a[19], limb b[19], limb iswap) { +- unsigned i; +- const s32 swap = (s32) -iswap; +- +- for (i = 0; i < 10; ++i) { +- const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); +- a[i] = ((s32)a[i]) ^ x; +- b[i] = ((s32)b[i]) ^ x; +- } +-} +- +-/* Calculates nQ where Q is the x-coordinate of a point on the curve +- * +- * resultx/resultz: the x coordinate of the resulting curve point (short form) +- * n: a little endian, 32-byte number +- * q: a point of the curve (short form) */ +-static void +-cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { +- limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; +- limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; +- limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; +- limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; +- +- unsigned i, j; +- +- memcpy(nqpqx, q, sizeof(limb) * 10); +- +- for (i = 0; i < 32; ++i) { +- u8 byte = n[31 - i]; +- for (j = 0; j < 8; ++j) { +- const limb bit = byte >> 7; +- +- swap_conditional(nqx, nqpqx, bit); +- swap_conditional(nqz, nqpqz, bit); +- fmonty(nqx2, nqz2, +- nqpqx2, nqpqz2, +- nqx, nqz, +- nqpqx, nqpqz, +- q); +- swap_conditional(nqx2, nqpqx2, bit); +- swap_conditional(nqz2, nqpqz2, bit); +- +- t = nqx; +- nqx = nqx2; +- nqx2 = t; +- t = nqz; +- nqz = nqz2; +- nqz2 = t; +- t = nqpqx; +- nqpqx = nqpqx2; +- nqpqx2 = t; +- t = nqpqz; +- nqpqz = nqpqz2; +- nqpqz2 = t; +- +- byte <<= 1; +- } +- } +- +- memcpy(resultx, nqx, sizeof(limb) * 10); +- memcpy(resultz, nqz, sizeof(limb) * 10); +-} +- +-/* ----------------------------------------------------------------------------- +- * Shamelessly copied from djb's code +- * ----------------------------------------------------------------------------- */ +-static void +-crecip(limb *out, const limb *z) { +- limb z2[10]; +- limb z9[10]; +- limb z11[10]; +- limb z2_5_0[10]; +- limb z2_10_0[10]; +- limb z2_20_0[10]; +- limb z2_50_0[10]; +- limb z2_100_0[10]; +- limb t0[10]; +- limb t1[10]; +- int i; +- +- /* 2 */ fsquare(z2,z); +- /* 4 */ fsquare(t1,z2); +- /* 8 */ fsquare(t0,t1); +- /* 9 */ fmul(z9,t0,z); +- /* 11 */ fmul(z11,z9,z2); +- /* 22 */ fsquare(t0,z11); +- /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); +- +- /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); +- /* 2^7 - 2^2 */ fsquare(t1,t0); +- /* 2^8 - 2^3 */ fsquare(t0,t1); +- /* 2^9 - 2^4 */ fsquare(t1,t0); +- /* 2^10 - 2^5 */ fsquare(t0,t1); +- /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); +- +- /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); +- /* 2^12 - 2^2 */ fsquare(t1,t0); +- /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } +- /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); +- +- /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); +- /* 2^22 - 2^2 */ fsquare(t1,t0); +- /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } +- /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); +- +- /* 2^41 - 2^1 */ fsquare(t1,t0); +- /* 2^42 - 2^2 */ fsquare(t0,t1); +- /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } +- /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); +- +- /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); +- /* 2^52 - 2^2 */ fsquare(t1,t0); +- /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } +- /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); +- +- /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); +- /* 2^102 - 2^2 */ fsquare(t0,t1); +- /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } +- /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); +- +- /* 2^201 - 2^1 */ fsquare(t0,t1); +- /* 2^202 - 2^2 */ fsquare(t1,t0); +- /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } +- /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); +- +- /* 2^251 - 2^1 */ fsquare(t1,t0); +- /* 2^252 - 2^2 */ fsquare(t0,t1); +- /* 2^253 - 2^3 */ fsquare(t1,t0); +- /* 2^254 - 2^4 */ fsquare(t0,t1); +- /* 2^255 - 2^5 */ fsquare(t1,t0); +- /* 2^255 - 21 */ fmul(out,t1,z11); +-} +- +-int +-curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { +- limb bp[10], x[10], z[11], zmone[10]; +- uint8_t e[32]; +- int i; +- +- for (i = 0; i < 32; ++i) e[i] = secret[i]; +- e[0] &= 248; +- e[31] &= 127; +- e[31] |= 64; +- +- fexpand(bp, basepoint); +- cmult(x, z, e, bp); +- crecip(zmone, z); +- fmul(z, x, zmone); +- fcontract(mypublic, z); +- return 0; +-} +diff --git a/curve25519.c b/curve25519.c +new file mode 100644 +index 0000000..4b83776 +--- /dev/null ++++ b/curve25519.c +@@ -0,0 +1,502 @@ ++/* ++ * Dropbear - a SSH2 server ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++#include "includes.h" ++#include "dbrandom.h" ++#include "curve25519.h" ++ ++#if DROPBEAR_CURVE25519 || DROPBEAR_ED25519 ++ ++/* Modified TweetNaCl version 20140427, a self-contained public-domain C library. ++ * https://tweetnacl.cr.yp.to/ */ ++ ++#define FOR(i,n) for (i = 0;i < n;++i) ++#define sv static void ++ ++typedef unsigned char u8; ++typedef unsigned long u32; ++typedef unsigned long long u64; ++typedef long long i64; ++typedef i64 gf[16]; ++ ++#if DROPBEAR_CURVE25519 ++static const gf ++ _121665 = {0xDB41,1}; ++#endif /* DROPBEAR_CURVE25519 */ ++#if DROPBEAR_ED25519 ++static const gf ++ gf0, ++ gf1 = {1}, ++ D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406}, ++ X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169}, ++ Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666}; ++#if DROPBEAR_SIGNKEY_VERIFY ++static const gf ++ D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203}, ++ I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83}; ++#endif /* DROPBEAR_SIGNKEY_VERIFY */ ++#endif /* DROPBEAR_ED25519 */ ++ ++#if DROPBEAR_ED25519 ++#if DROPBEAR_SIGNKEY_VERIFY ++static int vn(const u8 *x,const u8 *y,u32 n) ++{ ++ u32 i,d = 0; ++ FOR(i,n) d |= x[i]^y[i]; ++ return (1 & ((d - 1) >> 8)) - 1; ++} ++ ++static int crypto_verify_32(const u8 *x,const u8 *y) ++{ ++ return vn(x,y,32); ++} ++#endif /* DROPBEAR_SIGNKEY_VERIFY */ ++ ++sv set25519(gf r, const gf a) ++{ ++ int i; ++ FOR(i,16) r[i]=a[i]; ++} ++#endif /* DROPBEAR_ED25519 */ ++ ++sv car25519(gf o) ++{ ++ int i; ++ i64 c; ++ FOR(i,16) { ++ o[i]+=(1LL<<16); ++ c=o[i]>>16; ++ o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15); ++ o[i]-=c<<16; ++ } ++} ++ ++sv sel25519(gf p,gf q,int b) ++{ ++ i64 t,i,c=~(b-1); ++ FOR(i,16) { ++ t= c&(p[i]^q[i]); ++ p[i]^=t; ++ q[i]^=t; ++ } ++} ++ ++sv pack25519(u8 *o,const gf n) ++{ ++ int i,j,b; ++ gf m,t; ++ FOR(i,16) t[i]=n[i]; ++ car25519(t); ++ car25519(t); ++ car25519(t); ++ FOR(j,2) { ++ m[0]=t[0]-0xffed; ++ for(i=1;i<15;i++) { ++ m[i]=t[i]-0xffff-((m[i-1]>>16)&1); ++ m[i-1]&=0xffff; ++ } ++ m[15]=t[15]-0x7fff-((m[14]>>16)&1); ++ b=(m[15]>>16)&1; ++ m[14]&=0xffff; ++ sel25519(t,m,1-b); ++ } ++ FOR(i,16) { ++ o[2*i]=t[i]&0xff; ++ o[2*i+1]=t[i]>>8; ++ } ++} ++ ++#if DROPBEAR_ED25519 ++#if DROPBEAR_SIGNKEY_VERIFY ++static int neq25519(const gf a, const gf b) ++{ ++ u8 c[32],d[32]; ++ pack25519(c,a); ++ pack25519(d,b); ++ return crypto_verify_32(c,d); ++} ++#endif /* DROPBEAR_SIGNKEY_VERIFY */ ++ ++static u8 par25519(const gf a) ++{ ++ u8 d[32]; ++ pack25519(d,a); ++ return d[0]&1; ++} ++#endif /* DROPBEAR_ED25519 */ ++ ++sv unpack25519(gf o, const u8 *n) ++{ ++ int i; ++ FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8); ++ o[15]&=0x7fff; ++} ++ ++sv A(gf o,const gf a,const gf b) ++{ ++ int i; ++ FOR(i,16) o[i]=a[i]+b[i]; ++} ++ ++sv Z(gf o,const gf a,const gf b) ++{ ++ int i; ++ FOR(i,16) o[i]=a[i]-b[i]; ++} ++ ++sv M(gf o,const gf a,const gf b) ++{ ++ i64 i,j,t[31]; ++ FOR(i,31) t[i]=0; ++ FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j]; ++ FOR(i,15) t[i]+=38*t[i+16]; ++ FOR(i,16) o[i]=t[i]; ++ car25519(o); ++ car25519(o); ++} ++ ++sv S(gf o,const gf a) ++{ ++ M(o,a,a); ++} ++ ++sv inv25519(gf o,const gf i) ++{ ++ gf c; ++ int a; ++ FOR(a,16) c[a]=i[a]; ++ for(a=253;a>=0;a--) { ++ S(c,c); ++ if(a!=2&&a!=4) M(c,c,i); ++ } ++ FOR(a,16) o[a]=c[a]; ++} ++ ++#if DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY ++sv pow2523(gf o,const gf i) ++{ ++ gf c; ++ int a; ++ FOR(a,16) c[a]=i[a]; ++ for(a=250;a>=0;a--) { ++ S(c,c); ++ if(a!=1) M(c,c,i); ++ } ++ FOR(a,16) o[a]=c[a]; ++} ++#endif /* DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY */ ++ ++#if DROPBEAR_CURVE25519 ++int dropbear_curve25519_scalarmult(u8 *q,const u8 *n,const u8 *p) ++{ ++ u8 z[32]; ++ i64 x[80],r,i; ++ gf a,b,c,d,e,f; ++ FOR(i,31) z[i]=n[i]; ++ z[31]=(n[31]&127)|64; ++ z[0]&=248; ++ unpack25519(x,p); ++ FOR(i,16) { ++ b[i]=x[i]; ++ d[i]=a[i]=c[i]=0; ++ } ++ a[0]=d[0]=1; ++ for(i=254;i>=0;--i) { ++ r=(z[i>>3]>>(i&7))&1; ++ sel25519(a,b,r); ++ sel25519(c,d,r); ++ A(e,a,c); ++ Z(a,a,c); ++ A(c,b,d); ++ Z(b,b,d); ++ S(d,e); ++ S(f,a); ++ M(a,c,a); ++ M(c,b,e); ++ A(e,a,c); ++ Z(a,a,c); ++ S(b,a); ++ Z(c,d,f); ++ M(a,c,_121665); ++ A(a,a,d); ++ M(c,c,a); ++ M(a,d,f); ++ M(d,b,x); ++ S(b,e); ++ sel25519(a,b,r); ++ sel25519(c,d,r); ++ } ++ FOR(i,16) { ++ x[i+16]=a[i]; ++ x[i+32]=c[i]; ++ x[i+48]=b[i]; ++ x[i+64]=d[i]; ++ } ++ inv25519(x+32,x+32); ++ M(x+16,x+16,x+32); ++ pack25519(q,x+16); ++ return 0; ++} ++#endif /* DROPBEAR_CURVE25519 */ ++ ++#if DROPBEAR_ED25519 ++static int crypto_hash(u8 *out,const u8 *m,u64 n) ++{ ++ hash_state hs; ++ ++ sha512_init(&hs); ++ sha512_process(&hs, m, n); ++ return sha512_done(&hs, out); ++} ++ ++sv add(gf p[4],gf q[4]) ++{ ++ gf a,b,c,d,t,e,f,g,h; ++ ++ Z(a, p[1], p[0]); ++ Z(t, q[1], q[0]); ++ M(a, a, t); ++ A(b, p[0], p[1]); ++ A(t, q[0], q[1]); ++ M(b, b, t); ++ M(c, p[3], q[3]); ++ M(c, c, D2); ++ M(d, p[2], q[2]); ++ A(d, d, d); ++ Z(e, b, a); ++ Z(f, d, c); ++ A(g, d, c); ++ A(h, b, a); ++ ++ M(p[0], e, f); ++ M(p[1], h, g); ++ M(p[2], g, f); ++ M(p[3], e, h); ++} ++ ++sv cswap(gf p[4],gf q[4],u8 b) ++{ ++ int i; ++ FOR(i,4) ++ sel25519(p[i],q[i],b); ++} ++ ++sv pack(u8 *r,gf p[4]) ++{ ++ gf tx, ty, zi; ++ inv25519(zi, p[2]); ++ M(tx, p[0], zi); ++ M(ty, p[1], zi); ++ pack25519(r, ty); ++ r[31] ^= par25519(tx) << 7; ++} ++ ++sv scalarmult(gf p[4],gf q[4],const u8 *s) ++{ ++ int i; ++ set25519(p[0],gf0); ++ set25519(p[1],gf1); ++ set25519(p[2],gf1); ++ set25519(p[3],gf0); ++ for (i = 255;i >= 0;--i) { ++ u8 b = (s[i/8]>>(i&7))&1; ++ cswap(p,q,b); ++ add(q,p); ++ add(p,p); ++ cswap(p,q,b); ++ } ++} ++ ++sv scalarbase(gf p[4],const u8 *s) ++{ ++ gf q[4]; ++ set25519(q[0],X); ++ set25519(q[1],Y); ++ set25519(q[2],gf1); ++ M(q[3],X,Y); ++ scalarmult(p,q,s); ++} ++ ++int dropbear_ed25519_make_key(u8 *pk,u8 *sk) ++{ ++ u8 d[64]; ++ gf p[4]; ++ ++ genrandom(sk, 32); ++ ++ crypto_hash(d, sk, 32); ++ d[0] &= 248; ++ d[31] &= 127; ++ d[31] |= 64; ++ ++ scalarbase(p,d); ++ pack(pk,p); ++ ++ return 0; ++} ++ ++static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; ++ ++sv modL(u8 *r,i64 x[64]) ++{ ++ i64 carry,i,j; ++ for (i = 63;i >= 32;--i) { ++ carry = 0; ++ for (j = i - 32;j < i - 12;++j) { ++ x[j] += carry - 16 * x[i] * L[j - (i - 32)]; ++ carry = (x[j] + 128) >> 8; ++ x[j] -= carry << 8; ++ } ++ x[j] += carry; ++ x[i] = 0; ++ } ++ carry = 0; ++ FOR(j,32) { ++ x[j] += carry - (x[31] >> 4) * L[j]; ++ carry = x[j] >> 8; ++ x[j] &= 255; ++ } ++ FOR(j,32) x[j] -= carry * L[j]; ++ FOR(i,32) { ++ x[i+1] += x[i] >> 8; ++ r[i] = x[i] & 255; ++ } ++} ++ ++sv reduce(u8 *r) ++{ ++ i64 x[64],i; ++ FOR(i,64) x[i] = (u64) r[i]; ++ FOR(i,64) r[i] = 0; ++ modL(r,x); ++} ++ ++int dropbear_ed25519_sign(const u8 *m,u32 mlen,u8 *s,u32 *slen,const u8 *sk, const u8 *pk) ++{ ++ hash_state hs; ++ u8 d[64],h[64],r[64]; ++ i64 x[64]; ++ gf p[4]; ++ u32 i,j; ++ ++ crypto_hash(d, sk, 32); ++ d[0] &= 248; ++ d[31] &= 127; ++ d[31] |= 64; ++ ++ *slen = 64; ++ ++ sha512_init(&hs); ++ sha512_process(&hs,d + 32,32); ++ sha512_process(&hs,m,mlen); ++ sha512_done(&hs,r); ++ reduce(r); ++ scalarbase(p,r); ++ pack(s,p); ++ ++ sha512_init(&hs); ++ sha512_process(&hs,s,32); ++ sha512_process(&hs,pk,32); ++ sha512_process(&hs,m,mlen); ++ sha512_done(&hs,h); ++ reduce(h); ++ ++ FOR(i,64) x[i] = 0; ++ FOR(i,32) x[i] = (u64) r[i]; ++ FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j]; ++ modL(s + 32,x); ++ ++ return 0; ++} ++ ++#if DROPBEAR_SIGNKEY_VERIFY ++static int unpackneg(gf r[4],const u8 p[32]) ++{ ++ gf t, chk, num, den, den2, den4, den6; ++ set25519(r[2],gf1); ++ unpack25519(r[1],p); ++ S(num,r[1]); ++ M(den,num,D); ++ Z(num,num,r[2]); ++ A(den,r[2],den); ++ ++ S(den2,den); ++ S(den4,den2); ++ M(den6,den4,den2); ++ M(t,den6,num); ++ M(t,t,den); ++ ++ pow2523(t,t); ++ M(t,t,num); ++ M(t,t,den); ++ M(t,t,den); ++ M(r[0],t,den); ++ ++ S(chk,r[0]); ++ M(chk,chk,den); ++ if (neq25519(chk, num)) M(r[0],r[0],I); ++ ++ S(chk,r[0]); ++ M(chk,chk,den); ++ if (neq25519(chk, num)) return -1; ++ ++ if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]); ++ ++ M(r[3],r[0],r[1]); ++ return 0; ++} ++ ++int dropbear_ed25519_verify(const u8 *m,u32 mlen,const u8 *s,u32 slen,const u8 *pk) ++{ ++ hash_state hs; ++ u8 t[32],h[64]; ++ gf p[4],q[4]; ++ ++ if (slen < 64) return -1; ++ ++ if (unpackneg(q,pk)) return -1; ++ ++ sha512_init(&hs); ++ sha512_process(&hs,s,32); ++ sha512_process(&hs,pk,32); ++ sha512_process(&hs,m,mlen); ++ sha512_done(&hs,h); ++ ++ reduce(h); ++ scalarmult(p,q,h); ++ ++ scalarbase(q,s + 32); ++ add(p,q); ++ pack(t,p); ++ ++ if (crypto_verify_32(s, t)) ++ return -1; ++ ++ return 0; ++} ++#endif /* DROPBEAR_SIGNKEY_VERIFY */ ++ ++#endif /* DROPBEAR_ED25519 */ ++ ++#endif /* DROPBEAR_CURVE25519 || DROPBEAR_ED25519 */ +diff --git a/curve25519.h b/curve25519.h +new file mode 100644 +index 0000000..7f75aed +--- /dev/null ++++ b/curve25519.h +@@ -0,0 +1,37 @@ ++/* ++ * Dropbear - a SSH2 server ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++#ifndef DROPBEAR_CURVE25519_H ++#define DROPBEAR_CURVE25519_H ++ ++int dropbear_curve25519_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p); ++int dropbear_ed25519_make_key(unsigned char *pk, unsigned char *sk); ++int dropbear_ed25519_sign(const unsigned char *m, unsigned long mlen, ++ unsigned char *s, unsigned long *slen, ++ const unsigned char *sk, const unsigned char *pk); ++int dropbear_ed25519_verify(const unsigned char *m, unsigned long mlen, ++ const unsigned char *s, unsigned long slen, ++ const unsigned char *pk); ++ ++#endif /* DROPBEAR_CURVE25519_H */ +diff --git a/default_options.h b/default_options.h +index 9000fcc..5b232dd 100644 +--- a/default_options.h ++++ b/default_options.h +@@ -22,6 +22,7 @@ IMPORTANT: Some options will require "make clean" after changes */ + #define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key" + #define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key" + #define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key" ++#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key" + + /* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens + * on chosen ports and keeps accepting connections. This is the default. +@@ -116,11 +117,15 @@ IMPORTANT: Some options will require "make clean" after changes */ + * code (either ECDSA or ECDH) increases binary size - around 30kB + * on x86-64 */ + #define DROPBEAR_ECDSA 1 ++/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases ++ binary size - around 7,5kB on x86-64 */ ++#define DROPBEAR_ED25519 1 + + /* RSA must be >=1024 */ + #define DROPBEAR_DEFAULT_RSA_SIZE 2048 + /* DSS is always 1024 */ + /* ECDSA defaults to largest size configured, usually 521 */ ++/* Ed25519 is always 256 */ + + /* Add runtime flag "-R" to generate hostkeys as-needed when the first + connection using that key type occurs. +@@ -143,7 +148,7 @@ IMPORTANT: Some options will require "make clean" after changes */ + * group14 is supported by most implementations. + * group16 provides a greater strength level but is slower and increases binary size + * curve25519 and ecdh algorithms are faster than non-elliptic curve methods +- * curve25519 increases binary size by ~8kB on x86-64 ++ * curve25519 increases binary size by ~2,5kB on x86-64 + * including either ECDH or ECDSA increases binary size by ~30kB on x86-64 + + * Small systems should generally include either curve25519 or ecdh for performance. +diff --git a/dropbear.8 b/dropbear.8 +index 71c955a..345954f 100644 +--- a/dropbear.8 ++++ b/dropbear.8 +@@ -107,7 +107,7 @@ Print the version + Authorized Keys + + ~/.ssh/authorized_keys can be set up to allow remote login with a RSA, +-ECDSA, or DSS ++ECDSA, Ed25519 or DSS + key. Each line is of the form + .TP + [restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment] +@@ -146,8 +146,8 @@ key authentication. + Host Key Files + + Host key files are read at startup from a standard location, by default +-/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and +-/etc/dropbear/dropbear_ecdsa_host_key ++/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, ++/etc/dropbear/dropbear_ecdsa_host_key and /etc/dropbear/dropbear_ed25519_host_key + + If the -r command line option is specified the default files are not loaded. + Host key files are of the form generated by dropbearkey. +diff --git a/dropbearkey.c b/dropbearkey.c +index dd0e697..f881855 100644 +--- a/dropbearkey.c ++++ b/dropbearkey.c +@@ -43,6 +43,10 @@ + * mp_int y + * mp_int x + * ++ * Ed25519: ++ * string "ssh-ed25519" ++ * string k (32 bytes) + A (32 bytes) ++ * + */ + #include "includes.h" + #include "signkey.h" +@@ -51,6 +55,7 @@ + + #include "genrsa.h" + #include "gendss.h" ++#include "gened25519.h" + #include "ecdsa.h" + #include "crypto_desc.h" + #include "dbrandom.h" +@@ -75,6 +80,9 @@ static void printhelp(char * progname) { + #endif + #if DROPBEAR_ECDSA + " ecdsa\n" ++#endif ++#if DROPBEAR_ED25519 ++ " ed25519\n" + #endif + "-f filename Use filename for the secret key.\n" + " ~/.ssh/id_dropbear is recommended for client keys.\n" +@@ -94,6 +102,9 @@ static void printhelp(char * progname) { + "521 " + #endif + "\n" ++#endif ++#if DROPBEAR_ED25519 ++ " Ed25519 has a fixed size of 256 bits\n" + #endif + "-y Just print the publickey and fingerprint for the\n private key in .\n" + #if DEBUG_TRACE +@@ -106,6 +117,14 @@ static void printhelp(char * progname) { + static void check_signkey_bits(enum signkey_type type, int bits) + { + switch (type) { ++#if DROPBEAR_ED25519 ++ case DROPBEAR_SIGNKEY_ED25519: ++ if (bits != 256) { ++ dropbear_exit("Ed25519 keys have a fixed size of 256 bits\n"); ++ exit(EXIT_FAILURE); ++ } ++ break; ++#endif + #if DROPBEAR_RSA + case DROPBEAR_SIGNKEY_RSA: + if (bits < 512 || bits > 4096 || (bits % 8 != 0)) { +@@ -224,6 +243,12 @@ int main(int argc, char ** argv) { + keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN; + } + #endif ++#if DROPBEAR_ED25519 ++ if (strcmp(typetext, "ed25519") == 0) ++ { ++ keytype = DROPBEAR_SIGNKEY_ED25519; ++ } ++#endif + + if (keytype == DROPBEAR_SIGNKEY_NONE) { + fprintf(stderr, "Unknown key type '%s'\n", typetext); +diff --git a/ed25519.c b/ed25519.c +new file mode 100644 +index 0000000..3fb544c +--- /dev/null ++++ b/ed25519.c +@@ -0,0 +1,184 @@ ++/* ++ * Dropbear - a SSH2 server ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++/* Perform Ed25519 operations on data, including reading keys, signing and ++ * verification. */ ++ ++#include "includes.h" ++#include "dbutil.h" ++#include "buffer.h" ++#include "ssh.h" ++#include "curve25519.h" ++#include "ed25519.h" ++ ++#if DROPBEAR_ED25519 ++ ++/* Load a public ed25519 key from a buffer, initialising the values. ++ * The key will have the same format as buf_put_ed25519_key. ++ * These should be freed with ed25519_key_free. ++ * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ ++int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) { ++ ++ unsigned int len; ++ ++ TRACE(("enter buf_get_ed25519_pub_key")) ++ dropbear_assert(key != NULL); ++ ++ buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */ ++ ++ len = buf_getint(buf); ++ if (len != CURVE25519_LEN || buf->len - buf->pos < len) { ++ TRACE(("leave buf_get_ed25519_pub_key: failure")) ++ return DROPBEAR_FAILURE; ++ } ++ ++ m_burn(key->priv, CURVE25519_LEN); ++ memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN); ++ buf_incrpos(buf, CURVE25519_LEN); ++ ++ TRACE(("leave buf_get_ed25519_pub_key: success")) ++ return DROPBEAR_SUCCESS; ++} ++ ++/* Same as buf_get_ed25519_pub_key, but reads private key at the end. ++ * Loads a public and private ed25519 key from a buffer ++ * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ ++int buf_get_ed25519_priv_key(buffer *buf, dropbear_ed25519_key *key) { ++ ++ unsigned int len; ++ ++ TRACE(("enter buf_get_ed25519_priv_key")) ++ dropbear_assert(key != NULL); ++ ++ buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */ ++ ++ len = buf_getint(buf); ++ if (len != CURVE25519_LEN*2 || buf->len - buf->pos < len) { ++ TRACE(("leave buf_get_ed25519_priv_key: failure")) ++ return DROPBEAR_FAILURE; ++ } ++ ++ memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN); ++ buf_incrpos(buf, CURVE25519_LEN); ++ memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN); ++ buf_incrpos(buf, CURVE25519_LEN); ++ ++ TRACE(("leave buf_get_ed25519_pub_key: success")) ++ return DROPBEAR_SUCCESS; ++} ++ ++/* Clear and free the memory used by a public or private key */ ++void ed25519_key_free(dropbear_ed25519_key *key) { ++ ++ TRACE2(("enter ed25519_key_free")) ++ ++ if (key == NULL) { ++ TRACE2(("leave ed25519_key_free: key == NULL")) ++ return; ++ } ++ m_burn(key->priv, CURVE25519_LEN); ++ m_free(key); ++ ++ TRACE2(("leave rsa_key_free")) ++} ++ ++/* Put the public ed25519 key into the buffer in the required format */ ++void buf_put_ed25519_pub_key(buffer *buf, const dropbear_ed25519_key *key) { ++ ++ TRACE(("enter buf_put_ed25519_pub_key")) ++ dropbear_assert(key != NULL); ++ ++ buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN); ++ buf_putstring(buf, key->pub, CURVE25519_LEN); ++ ++ TRACE(("leave buf_put_ed25519_pub_key")) ++} ++ ++/* Put the public and private ed25519 key into the buffer in the required format */ ++void buf_put_ed25519_priv_key(buffer *buf, const dropbear_ed25519_key *key) { ++ ++ TRACE(("enter buf_put_ed25519_priv_key")) ++ dropbear_assert(key != NULL); ++ ++ buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN); ++ buf_putint(buf, CURVE25519_LEN*2); ++ buf_putbytes(buf, key->priv, CURVE25519_LEN); ++ buf_putbytes(buf, key->pub, CURVE25519_LEN); ++ ++ TRACE(("leave buf_put_ed25519_priv_key")) ++} ++ ++/* Sign the data presented with key, writing the signature contents ++ * to the buffer */ ++void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf) { ++ ++ unsigned char s[64]; ++ unsigned long slen = sizeof(s); ++ ++ TRACE(("enter buf_put_ed25519_sign")) ++ dropbear_assert(key != NULL); ++ ++ if (dropbear_ed25519_sign(data_buf->data, data_buf->len, ++ s, &slen, key->priv, key->pub) == 0) { ++ buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN); ++ buf_putstring(buf, s, slen); ++ } ++ ++ TRACE(("leave buf_put_ed25519_sign")) ++} ++ ++#if DROPBEAR_SIGNKEY_VERIFY ++/* Verify a signature in buf, made on data by the key given. ++ * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ ++int buf_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf) { ++ ++ int ret = DROPBEAR_FAILURE; ++ unsigned char *s; ++ unsigned long slen; ++ ++ TRACE(("enter buf_ed25519_verify")) ++ dropbear_assert(key != NULL); ++ ++ slen = buf_getint(buf); ++ if (slen != 64 || buf->len - buf->pos < slen) { ++ TRACE(("bad size")) ++ goto out; ++ } ++ s = buf_getptr(buf, slen); ++ ++ if (dropbear_ed25519_verify(data_buf->data, data_buf->len, ++ s, slen, key->pub) == 0) { ++ /* signature is valid */ ++ TRACE(("success!")) ++ ret = DROPBEAR_SUCCESS; ++ } ++ ++out: ++ TRACE(("leave buf_ed25519_verify: ret %d", ret)) ++ return ret; ++} ++ ++#endif /* DROPBEAR_SIGNKEY_VERIFY */ ++ ++#endif /* DROPBEAR_ED25519 */ +diff --git a/ed25519.h b/ed25519.h +new file mode 100644 +index 0000000..16c0d7b +--- /dev/null ++++ b/ed25519.h +@@ -0,0 +1,54 @@ ++/* ++ * Dropbear - a SSH2 server ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++#ifndef DROPBEAR_ED25519_H_ ++#define DROPBEAR_ED25519_H_ ++ ++#include "includes.h" ++#include "buffer.h" ++ ++#if DROPBEAR_ED25519 ++ ++#define CURVE25519_LEN 32 ++ ++typedef struct { ++ ++ unsigned char priv[CURVE25519_LEN]; ++ unsigned char pub[CURVE25519_LEN]; ++ ++} dropbear_ed25519_key; ++ ++void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf); ++#if DROPBEAR_SIGNKEY_VERIFY ++int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf); ++#endif ++int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key); ++int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key); ++void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key); ++void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key); ++void ed25519_key_free(dropbear_ed25519_key *key); ++ ++#endif /* DROPBEAR_ED25519 */ ++ ++#endif /* DROPBEAR_ED25519_H_ */ +diff --git a/filelist.txt b/filelist.txt +index 8281c14..3b9bb67 100644 +--- a/filelist.txt ++++ b/filelist.txt +@@ -99,6 +99,10 @@ rsa.c RSA asymmetric crypto routines + + dss.c DSS asymmetric crypto routines + ++ed25519.c Ed25519 asymmetric crypto routines ++ ++gened25519.c Ed25519 key generation ++ + gendss.c DSS key generation + + genrsa.c RSA key generation +diff --git a/fuzz-common.c b/fuzz-common.c +index 5c90c45..b1b00f6 100644 +--- a/fuzz-common.c ++++ b/fuzz-common.c +@@ -112,6 +112,14 @@ static void load_fixed_hostkeys(void) { + dropbear_exit("failed fixed ecdsa hostkey"); + } + ++ buf_setlen(b, 0); ++ buf_putbytes(b, keyed25519, keyed25519_len); ++ buf_setpos(b, 0); ++ type = DROPBEAR_SIGNKEY_ED25519; ++ if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) { ++ dropbear_exit("failed fixed ed25519 hostkey"); ++ } ++ + buf_free(b); + } + +diff --git a/fuzz-hostkeys.c b/fuzz-hostkeys.c +index dc1615d..3fff5cb 100644 +--- a/fuzz-hostkeys.c ++++ b/fuzz-hostkeys.c +@@ -127,3 +127,13 @@ unsigned char keyd[] = { + 0xf9, 0x39 + }; + unsigned int keyd_len = 458; ++unsigned char keyed25519[] = { ++ 0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35, ++ 0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5, ++ 0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66, ++ 0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2, ++ 0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19, ++ 0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69, ++ 0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9 ++}; ++unsigned int keyed25519_len = 83; +diff --git a/fuzzer-kexcurve25519.c b/fuzzer-kexcurve25519.c +new file mode 100644 +index 0000000..f2eab14 +--- /dev/null ++++ b/fuzzer-kexcurve25519.c +@@ -0,0 +1,72 @@ ++#include "fuzz.h" ++#include "session.h" ++#include "fuzz-wrapfd.h" ++#include "debug.h" ++#include "runopts.h" ++#include "algo.h" ++#include "bignum.h" ++ ++int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { ++ static int once = 0; ++ static struct key_context* keep_newkeys = NULL; ++ /* number of generated parameters is limited by the timeout for the first run. ++ TODO move this to the libfuzzer initialiser function instead if the timeout ++ doesn't apply there */ ++ #define NUM_PARAMS 20 ++ static struct kex_curve25519_param *curve25519_params[NUM_PARAMS]; ++ ++ if (!once) { ++ fuzz_common_setup(); ++ fuzz_svr_setup(); ++ ++ keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); ++ keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256"); ++ keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519; ++ ses.newkeys = keep_newkeys; ++ ++ /* Pre-generate parameters */ ++ int i; ++ for (i = 0; i < NUM_PARAMS; i++) { ++ curve25519_params[i] = gen_kexcurve25519_param(); ++ } ++ ++ once = 1; ++ } ++ ++ if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) { ++ return 0; ++ } ++ ++ m_malloc_set_epoch(1); ++ ++ if (setjmp(fuzz.jmp) == 0) { ++ /* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply() ++ with DROPBEAR_KEX_CURVE25519 */ ++ ses.newkeys = keep_newkeys; ++ ++ /* Choose from the collection of curve25519 params */ ++ unsigned int e = buf_getint(fuzz.input); ++ struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS]; ++ ++ buffer * ecdh_qs = buf_getstringbuf(fuzz.input); ++ ++ ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS); ++ kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey); ++ ++ mp_clear(ses.dh_K); ++ m_free(ses.dh_K); ++ buf_free(ecdh_qs); ++ ++ buf_free(ses.hash); ++ buf_free(ses.session_id); ++ /* kexhashbuf is freed in kexdh_comb_key */ ++ ++ m_malloc_free_epoch(1, 0); ++ } else { ++ m_malloc_free_epoch(1, 1); ++ TRACE(("dropbear_exit longjmped")) ++ /* dropbear_exit jumped here */ ++ } ++ ++ return 0; ++} +diff --git a/gened25519.c b/gened25519.c +new file mode 100644 +index 0000000..a027914 +--- /dev/null ++++ b/gened25519.c +@@ -0,0 +1,47 @@ ++/* ++ * Dropbear - a SSH2 server ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++#include "includes.h" ++#include "dbutil.h" ++#include "dbrandom.h" ++#include "curve25519.h" ++#include "gened25519.h" ++ ++#if DROPBEAR_ED25519 ++ ++dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size) { ++ ++ dropbear_ed25519_key *key; ++ ++ if (size != 256) { ++ dropbear_exit("Ed25519 keys have a fixed size of 256 bits"); ++ } ++ ++ key = m_malloc(sizeof(*key)); ++ dropbear_ed25519_make_key(key->pub, key->priv); ++ ++ return key; ++} ++ ++#endif /* DROPBEAR_ED25519 */ +diff --git a/gened25519.h b/gened25519.h +new file mode 100644 +index 0000000..8058310 +--- /dev/null ++++ b/gened25519.h +@@ -0,0 +1,36 @@ ++/* ++ * Dropbear - a SSH2 server ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++#ifndef DROPBEAR_GENED25519_H_ ++#define DROPBEAR_GENED25519_H_ ++ ++#include "ed25519.h" ++ ++#if DROPBEAR_ED25519 ++ ++dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size); ++ ++#endif /* DROPBEAR_ED25519 */ ++ ++#endif /* DROPBEAR_GENED25519_H_ */ +diff --git a/gensignkey.c b/gensignkey.c +index 34b6f5a..674d81f 100644 +--- a/gensignkey.c ++++ b/gensignkey.c +@@ -4,6 +4,7 @@ + #include "ecdsa.h" + #include "genrsa.h" + #include "gendss.h" ++#include "gened25519.h" + #include "signkey.h" + #include "dbrandom.h" + +@@ -68,6 +69,10 @@ static int get_default_bits(enum signkey_type keytype) + return 384; + case DROPBEAR_SIGNKEY_ECDSA_NISTP256: + return 256; ++#endif ++#if DROPBEAR_ED25519 ++ case DROPBEAR_SIGNKEY_ED25519: ++ return 256; + #endif + default: + return 0; +@@ -118,6 +123,11 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename, + *signkey_key_ptr(key, keytype) = ecckey; + } + break; ++#endif ++#if DROPBEAR_ED25519 ++ case DROPBEAR_SIGNKEY_ED25519: ++ key->ed25519key = gen_ed25519_priv_key(bits); ++ break; + #endif + default: + dropbear_exit("Internal error"); +diff --git a/keyimport.c b/keyimport.c +index 7304e58..ad0c530 100644 +--- a/keyimport.c ++++ b/keyimport.c +@@ -35,6 +35,15 @@ + #include "buffer.h" + #include "dbutil.h" + #include "ecc.h" ++#include "ssh.h" ++ ++static const unsigned char OSSH_PKEY_BLOB[] = ++ "openssh-key-v1\0" /* AUTH_MAGIC */ ++ "\0\0\0\4none" /* cipher name*/ ++ "\0\0\0\4none" /* kdf name */ ++ "\0\0\0\0" /* kdf */ ++ "\0\0\0\1"; /* key num */ ++#define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1) + + #if DROPBEAR_ECDSA + static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; +@@ -352,7 +361,7 @@ struct mpint_pos { void *start; int bytes; }; + * Code to read and write OpenSSH private keys. + */ + +-enum { OSSH_DSA, OSSH_RSA, OSSH_EC }; ++enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY }; + struct openssh_key { + int type; + int encrypted; +@@ -364,11 +373,12 @@ struct openssh_key { + static struct openssh_key *load_openssh_key(const char *filename) + { + struct openssh_key *ret; ++ buffer *buf = NULL; + FILE *fp = NULL; + char buffer[256]; + char *errmsg = NULL, *p = NULL; + int headers_done; +- unsigned long len, outlen; ++ unsigned long len; + + ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); + ret->keyblob = NULL; +@@ -397,12 +407,15 @@ static struct openssh_key *load_openssh_key(const char *filename) + ret->type = OSSH_DSA; + else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) + ret->type = OSSH_EC; ++ else if (!strcmp(buffer, "-----BEGIN OPENSSH PRIVATE KEY-----\n")) ++ ret->type = OSSH_PKEY; + else { + errmsg = "Unrecognised key type"; + goto error; + } + + headers_done = 0; ++ buf = buf_new(0); + while (1) { + if (!fgets(buffer, sizeof(buffer), fp)) { + errmsg = "Unexpected end of file"; +@@ -448,20 +461,31 @@ static struct openssh_key *load_openssh_key(const char *filename) + } else { + headers_done = 1; + len = strlen(buffer); +- outlen = len*4/3; +- if (ret->keyblob_len + outlen > ret->keyblob_size) { +- ret->keyblob_size = ret->keyblob_len + outlen + 256; +- ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, +- ret->keyblob_size); +- } +- outlen = ret->keyblob_size - ret->keyblob_len; +- if (base64_decode((const unsigned char *)buffer, len, +- ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){ +- errmsg = "Error decoding base64"; +- goto error; +- } +- ret->keyblob_len += outlen; ++ buf = buf_resize(buf, buf->size + len); ++ buf_putbytes(buf, buffer, len); ++ } ++ } ++ ++ if (buf && buf->len) { ++ ret->keyblob_size = ret->keyblob_len + buf->len*4/3 + 256; ++ ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, ret->keyblob_size); ++ len = ret->keyblob_size; ++ if (base64_decode((const unsigned char *)buf->data, buf->len, ++ ret->keyblob, &len) != CRYPT_OK){ ++ errmsg = "Error decoding base64"; ++ goto error; ++ } ++ ret->keyblob_len = len; ++ } ++ ++ if (ret->type == OSSH_PKEY) { ++ if (ret->keyblob_len < OSSH_PKEY_BLOBLEN || ++ memcmp(ret->keyblob, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN)) { ++ errmsg = "Error decoding OpenSSH key"; ++ goto error; + } ++ ret->keyblob_len -= OSSH_PKEY_BLOBLEN; ++ memmove(ret->keyblob, ret->keyblob + OSSH_PKEY_BLOBLEN, ret->keyblob_len); + } + + if (ret->keyblob_len == 0 || !ret->keyblob) { +@@ -474,10 +498,18 @@ static struct openssh_key *load_openssh_key(const char *filename) + goto error; + } + ++ if (buf) { ++ buf_burn(buf); ++ buf_free(buf); ++ } + m_burn(buffer, sizeof(buffer)); + return ret; + + error: ++ if (buf) { ++ buf_burn(buf); ++ buf_free(buf); ++ } + m_burn(buffer, sizeof(buffer)); + if (ret) { + if (ret->keyblob) { +@@ -569,6 +601,57 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra + #endif + } + ++ /* ++ * Now we have a decrypted key blob, which contains OpenSSH ++ * encoded private key. We must now untangle the OpenSSH format. ++ */ ++ if (key->type == OSSH_PKEY) { ++ blobbuf = buf_new(key->keyblob_len); ++ buf_putbytes(blobbuf, key->keyblob, key->keyblob_len); ++ buf_setpos(blobbuf, 0); ++ ++ /* limit length of private key blob */ ++ len = buf_getint(blobbuf); ++ buf_setlen(blobbuf, blobbuf->pos + len); ++ ++ type = DROPBEAR_SIGNKEY_ANY; ++ if (buf_get_pub_key(blobbuf, retkey, &type) ++ != DROPBEAR_SUCCESS) { ++ errmsg = "Error parsing OpenSSH key"; ++ goto ossh_error; ++ } ++ ++ /* restore full length */ ++ buf_setlen(blobbuf, key->keyblob_len); ++ ++ if (type != DROPBEAR_SIGNKEY_NONE) { ++ retkey->type = type; ++ /* limit length of private key blob */ ++ len = buf_getint(blobbuf); ++ buf_setlen(blobbuf, blobbuf->pos + len); ++#if DROPBEAR_ED25519 ++ if (type == DROPBEAR_SIGNKEY_ED25519) { ++ buf_incrpos(blobbuf, 8); ++ buf_eatstring(blobbuf); ++ buf_eatstring(blobbuf); ++ buf_incrpos(blobbuf, -SSH_SIGNKEY_ED25519_LEN-4); ++ if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key) ++ == DROPBEAR_SUCCESS) { ++ errmsg = NULL; ++ retval = retkey; ++ goto error; ++ } ++ } ++#endif ++ } ++ ++ errmsg = "Unsupported OpenSSH key type"; ++ ossh_error: ++ sign_key_free(retkey); ++ retkey = NULL; ++ goto error; ++ } ++ + /* + * Now we have a decrypted key blob, which contains an ASN.1 + * encoded private key. We must now untangle the ASN.1. +@@ -1129,6 +1212,51 @@ static int openssh_write(const char *filename, sign_key *key, + } + #endif + ++#if DROPBEAR_ED25519 ++ if (key->type == DROPBEAR_SIGNKEY_ED25519) { ++ buffer *buf = buf_new(300); ++ keyblob = buf_new(100); ++ extrablob = buf_new(200); ++ ++ /* private key blob w/o header */ ++ buf_put_priv_key(keyblob, key, key->type); ++ buf_setpos(keyblob, 0); ++ buf_incrpos(keyblob, buf_getint(keyblob)); ++ len = buf_getint(keyblob); ++ ++ /* header */ ++ buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN); ++ ++ /* public key */ ++ buf_put_pub_key(buf, key, key->type); ++ ++ /* private key */ ++ buf_incrwritepos(extrablob, 4); ++ buf_put_pub_key(extrablob, key, key->type); ++ buf_putstring(extrablob, buf_getptr(keyblob, len), len); ++ /* comment */ ++ buf_putstring(extrablob, "", 0); ++ /* padding to cipher block length */ ++ len = (extrablob->len+8) & ~7; ++ for (i = 1; len - extrablob->len > 0; i++) ++ buf_putbyte(extrablob, i); ++ buf_setpos(extrablob, 0); ++ buf_putbytes(extrablob, "\0\0\0\0\0\0\0\0", 8); ++ buf_putbufstring(buf, extrablob); ++ ++ outlen = len = pos = buf->len; ++ outblob = (unsigned char*)m_malloc(outlen); ++ memcpy(outblob, buf->data, buf->len); ++ ++ buf_burn(buf); ++ buf_free(buf); ++ buf = NULL; ++ ++ header = "-----BEGIN OPENSSH PRIVATE KEY-----\n"; ++ footer = "-----END OPENSSH PRIVATE KEY-----\n"; ++ } ++#endif ++ + /* + * Padding on OpenSSH keys is deterministic. The number of + * padding bytes is always more than zero, and always at most +diff --git a/signkey.c b/signkey.c +index 88f06c7..a0af44a 100644 +--- a/signkey.c ++++ b/signkey.c +@@ -39,8 +39,11 @@ static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = { + #if DROPBEAR_ECDSA + "ecdsa-sha2-nistp256", + "ecdsa-sha2-nistp384", +- "ecdsa-sha2-nistp521" ++ "ecdsa-sha2-nistp521", + #endif /* DROPBEAR_ECDSA */ ++#if DROPBEAR_ED25519 ++ "ssh-ed25519", ++#endif /* DROPBEAR_ED25519 */ + }; + + /* malloc a new sign_key and set the dss and rsa keys to NULL */ +@@ -107,6 +110,10 @@ Be sure to check both (ret != NULL) and (*ret != NULL) */ + void ** + signkey_key_ptr(sign_key *key, enum signkey_type type) { + switch (type) { ++#if DROPBEAR_ED25519 ++ case DROPBEAR_SIGNKEY_ED25519: ++ return (void**)&key->ed25519key; ++#endif + #if DROPBEAR_ECDSA + #if DROPBEAR_ECC_256 + case DROPBEAR_SIGNKEY_ECDSA_NISTP256: +@@ -200,6 +207,17 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) { + } + } + #endif ++#if DROPBEAR_ED25519 ++ if (keytype == DROPBEAR_SIGNKEY_ED25519) { ++ ed25519_key_free(key->ed25519key); ++ key->ed25519key = m_malloc(sizeof(*key->ed25519key)); ++ ret = buf_get_ed25519_pub_key(buf, key->ed25519key); ++ if (ret == DROPBEAR_FAILURE) { ++ m_free(key->ed25519key); ++ key->ed25519key = NULL; ++ } ++ } ++#endif + + TRACE2(("leave buf_get_pub_key")) + +@@ -270,6 +288,17 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) { + } + } + #endif ++#if DROPBEAR_ED25519 ++ if (keytype == DROPBEAR_SIGNKEY_ED25519) { ++ ed25519_key_free(key->ed25519key); ++ key->ed25519key = m_malloc(sizeof(*key->ed25519key)); ++ ret = buf_get_ed25519_priv_key(buf, key->ed25519key); ++ if (ret == DROPBEAR_FAILURE) { ++ m_free(key->ed25519key); ++ key->ed25519key = NULL; ++ } ++ } ++#endif + + TRACE2(("leave buf_get_priv_key")) + +@@ -302,6 +331,11 @@ void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) { + buf_put_ecdsa_pub_key(pubkeys, *eck); + } + } ++#endif ++#if DROPBEAR_ED25519 ++ if (type == DROPBEAR_SIGNKEY_ED25519) { ++ buf_put_ed25519_pub_key(pubkeys, key->ed25519key); ++ } + #endif + if (pubkeys->len == 0) { + dropbear_exit("Bad key types in buf_put_pub_key"); +@@ -341,6 +375,13 @@ void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) { + return; + } + } ++#endif ++#if DROPBEAR_ED25519 ++ if (type == DROPBEAR_SIGNKEY_ED25519) { ++ buf_put_ed25519_priv_key(buf, key->ed25519key); ++ TRACE(("leave buf_put_priv_key: ed25519 done")) ++ return; ++ } + #endif + dropbear_exit("Bad key types in put pub key"); + } +@@ -379,6 +420,10 @@ void sign_key_free(sign_key *key) { + key->ecckey521 = NULL; + } + #endif ++#endif ++#if DROPBEAR_ED25519 ++ ed25519_key_free(key->ed25519key); ++ key->ed25519key = NULL; + #endif + + m_free(key->filename); +@@ -503,6 +548,11 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type, + buf_put_ecdsa_sign(sigblob, *eck, data_buf); + } + } ++#endif ++#if DROPBEAR_ED25519 ++ if (type == DROPBEAR_SIGNKEY_ED25519) { ++ buf_put_ed25519_sign(sigblob, key->ed25519key, data_buf); ++ } + #endif + if (sigblob->len == 0) { + dropbear_exit("Non-matching signing type"); +@@ -555,6 +605,14 @@ int buf_verify(buffer * buf, sign_key *key, const buffer *data_buf) { + } + } + #endif ++#if DROPBEAR_ED25519 ++ if (type == DROPBEAR_SIGNKEY_ED25519) { ++ if (key->ed25519key == NULL) { ++ dropbear_exit("No Ed25519 key to verify signature"); ++ } ++ return buf_ed25519_verify(buf, key->ed25519key, data_buf); ++ } ++#endif + + dropbear_exit("Non-matching signing type"); + return DROPBEAR_FAILURE; +diff --git a/signkey.h b/signkey.h +index 59df3ee..fa39a02 100644 +--- a/signkey.h ++++ b/signkey.h +@@ -28,6 +28,7 @@ + #include "buffer.h" + #include "dss.h" + #include "rsa.h" ++#include "ed25519.h" + + enum signkey_type { + #if DROPBEAR_RSA +@@ -41,6 +42,9 @@ enum signkey_type { + DROPBEAR_SIGNKEY_ECDSA_NISTP384, + DROPBEAR_SIGNKEY_ECDSA_NISTP521, + #endif /* DROPBEAR_ECDSA */ ++#if DROPBEAR_ED25519 ++ DROPBEAR_SIGNKEY_ED25519, ++#endif + DROPBEAR_SIGNKEY_NUM_NAMED, + DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */ + DROPBEAR_SIGNKEY_ANY = 80, +@@ -78,6 +82,9 @@ struct SIGN_key { + ecc_key * ecckey521; + #endif + #endif ++#if DROPBEAR_ED25519 ++ dropbear_ed25519_key * ed25519key; ++#endif + }; + + typedef struct SIGN_key sign_key; +diff --git a/ssh.h b/ssh.h +index f40b65a..db723b8 100644 +--- a/ssh.h ++++ b/ssh.h +@@ -105,6 +105,8 @@ + #define SSH_SIGNKEY_DSS_LEN 7 + #define SSH_SIGNKEY_RSA "ssh-rsa" + #define SSH_SIGNKEY_RSA_LEN 7 ++#define SSH_SIGNKEY_ED25519 "ssh-ed25519" ++#define SSH_SIGNKEY_ED25519_LEN 11 + + /* Agent commands. These aren't part of the spec, and are defined + * only on the openssh implementation. */ +diff --git a/svr-kex.c b/svr-kex.c +index 406ad97..af16d2f 100644 +--- a/svr-kex.c ++++ b/svr-kex.c +@@ -122,6 +122,11 @@ static void svr_ensure_hostkey() { + case DROPBEAR_SIGNKEY_ECDSA_NISTP521: + fn = ECDSA_PRIV_FILENAME; + break; ++#endif ++#if DROPBEAR_ED25519 ++ case DROPBEAR_SIGNKEY_ED25519: ++ fn = ED25519_PRIV_FILENAME; ++ break; + #endif + default: + dropbear_assert(0); +@@ -219,7 +224,8 @@ static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) { + { + struct kex_curve25519_param *param = gen_kexcurve25519_param(); + kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey); +- buf_putstring(ses.writepayload, (const char*)param->pub, CURVE25519_LEN); ++ ++ buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN); + free_kexcurve25519_param(param); + } + break; +diff --git a/svr-runopts.c b/svr-runopts.c +index d7a0d5a..d430825 100644 +--- a/svr-runopts.c ++++ b/svr-runopts.c +@@ -57,6 +57,9 @@ static void printhelp(const char * progname) { + #if DROPBEAR_ECDSA + " ecdsa %s\n" + #endif ++#if DROPBEAR_ED25519 ++ " ed25519 %s\n" ++#endif + #if DROPBEAR_DELAY_HOSTKEY + "-R Create hostkeys as required\n" + #endif +@@ -116,6 +119,9 @@ static void printhelp(const char * progname) { + #endif + #if DROPBEAR_ECDSA + ECDSA_PRIV_FILENAME, ++#endif ++#if DROPBEAR_ED25519 ++ ED25519_PRIV_FILENAME, + #endif + MAX_AUTH_TRIES, + DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE, +@@ -538,6 +544,13 @@ static void loadhostkey(const char *keyfile, int fatal_duplicate) { + } + #endif + #endif /* DROPBEAR_ECDSA */ ++ ++#if DROPBEAR_ED25519 ++ if (type == DROPBEAR_SIGNKEY_ED25519) { ++ loadhostkey_helper("ed25519", (void**)&read_key->ed25519key, (void**)&svr_opts.hostkey->ed25519key, fatal_duplicate); ++ } ++#endif ++ + sign_key_free(read_key); + TRACE(("leave loadhostkey")) + } +@@ -578,6 +591,9 @@ void load_all_hostkeys() { + + #if DROPBEAR_ECDSA + loadhostkey(ECDSA_PRIV_FILENAME, 0); ++#endif ++#if DROPBEAR_ED25519 ++ loadhostkey(ED25519_PRIV_FILENAME, 0); + #endif + } + +@@ -642,6 +658,14 @@ void load_all_hostkeys() { + #endif + #endif /* DROPBEAR_ECDSA */ + ++#if DROPBEAR_ED25519 ++ if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) { ++ disablekey(DROPBEAR_SIGNKEY_ED25519); ++ } else { ++ any_keys = 1; ++ } ++#endif ++ + if (!any_keys) { + dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey."); + } +diff --git a/sysoptions.h b/sysoptions.h +index cfd5469..2c27caf 100644 +--- a/sysoptions.h ++++ b/sysoptions.h +@@ -145,7 +145,8 @@ If you test it please contact the Dropbear author */ + #define DROPBEAR_SHA384 (DROPBEAR_ECC_384) + /* LTC SHA384 depends on SHA512 */ + #define DROPBEAR_SHA512 ((DROPBEAR_SHA2_512_HMAC) || (DROPBEAR_ECC_521) \ +- || (DROPBEAR_SHA384) || (DROPBEAR_DH_GROUP16)) ++ || (DROPBEAR_SHA384) || (DROPBEAR_DH_GROUP16) \ ++ || (DROPBEAR_ED25519)) + #define DROPBEAR_MD5 (DROPBEAR_MD5_HMAC) + + #define DROPBEAR_DH_GROUP14 ((DROPBEAR_DH_GROUP14_SHA256) || (DROPBEAR_DH_GROUP14_SHA1)) +@@ -186,7 +187,7 @@ If you test it please contact the Dropbear author */ + /* For a 4096 bit DSS key, empirically determined */ + #define MAX_PRIVKEY_SIZE 1700 + +-#define MAX_HOSTKEYS 3 ++#define MAX_HOSTKEYS 4 + + /* The maximum size of the bignum portion of the kexhash buffer */ + /* Sect. 8 of the transport rfc 4253, K_S + e + f + K */ +@@ -252,7 +253,7 @@ If you test it please contact the Dropbear author */ + #error "At least one encryption algorithm must be enabled. AES128 is recommended." + #endif + +-#if !(DROPBEAR_RSA || DROPBEAR_DSS || DROPBEAR_ECDSA) ++#if !(DROPBEAR_RSA || DROPBEAR_DSS || DROPBEAR_ECDSA || DROPBEAR_ED25519) + #error "At least one hostkey or public-key algorithm must be enabled; RSA is recommended." + #endif + +-- +2.17.1 + diff --git a/package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch b/package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch new file mode 100644 index 0000000000..2120b4593e --- /dev/null +++ b/package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch @@ -0,0 +1,693 @@ +From 3cdf9ec918b37c17e12b33e4c244944d1ee836ca Mon Sep 17 00:00:00 2001 +From: Vladislav Grishenko +Date: Mon, 6 Apr 2020 23:28:09 +0500 +Subject: [PATCH] Add Chacha20-Poly1305 authenticated encryption + +* Add general AEAD approach. +* Add chacha20-poly1305@openssh.com algo using LibTomCrypt chacha and + poly1305 routines. + +Chacha20-Poly1305 is generally faster than AES256 on CPU w/o dedicated +AES instructions, having the same key size. +Compiling in will add ~5,5kB to binary size on x86-64. +--- + Makefile.in | 2 +- + algo.h | 8 ++ + chachapoly.c | 148 ++++++++++++++++++++ + chachapoly.h | 44 ++++++ + common-algo.c | 11 +- + common-kex.c | 44 ++++-- + default_options.h | 6 + + libtomcrypt/src/headers/tomcrypt_dropbear.h | 4 + + packet.c | 145 +++++++++++++------ + session.h | 4 + + sysoptions.h | 8 +- + 11 files changed, 368 insertions(+), 56 deletions(-) + create mode 100644 chachapoly.c + create mode 100644 chachapoly.h + +diff --git a/Makefile.in b/Makefile.in +index aaf7b3b..3437cb2 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -53,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ + CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \ + common-channel.o common-chansession.o termcodes.o loginrec.o \ + tcp-accept.o listener.o process-packet.o dh_groups.o \ +- common-runopts.o circbuffer.o list.o netio.o ++ common-runopts.o circbuffer.o list.o netio.o chachapoly.o + + KEYOBJS=dropbearkey.o + +diff --git a/algo.h b/algo.h +index b12fb94..efd0d73 100644 +--- a/algo.h ++++ b/algo.h +@@ -72,6 +72,14 @@ struct dropbear_cipher_mode { + unsigned long len, void *cipher_state); + int (*decrypt)(const unsigned char *ct, unsigned char *pt, + unsigned long len, void *cipher_state); ++ int (*aead_crypt)(unsigned int seq, ++ const unsigned char *in, unsigned char *out, ++ unsigned long len, unsigned long taglen, ++ void *cipher_state, int direction); ++ int (*aead_getlength)(unsigned int seq, ++ const unsigned char *in, unsigned int *outlen, ++ unsigned long len, void *cipher_state); ++ const struct dropbear_hash *aead_mac; + }; + + struct dropbear_hash { +diff --git a/chachapoly.c b/chachapoly.c +new file mode 100644 +index 0000000..8fb06c5 +--- /dev/null ++++ b/chachapoly.c +@@ -0,0 +1,148 @@ ++/* ++ * Dropbear SSH ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * Copyright (c) 2020 by Vladislav Grishenko ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++#include "includes.h" ++#include "algo.h" ++#include "dbutil.h" ++#include "chachapoly.h" ++ ++#if DROPBEAR_CHACHA20POLY1305 ++ ++#define CHACHA20_KEY_LEN 32 ++#define CHACHA20_BLOCKSIZE 8 ++#define POLY1305_KEY_LEN 32 ++#define POLY1305_TAG_LEN 16 ++ ++static const struct ltc_cipher_descriptor dummy = {.name = NULL}; ++ ++static const struct dropbear_hash dropbear_chachapoly_mac = ++ {NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN}; ++ ++const struct dropbear_cipher dropbear_chachapoly = ++ {&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE}; ++ ++static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV), ++ const unsigned char *key, int keylen, ++ int UNUSED(num_rounds), dropbear_chachapoly_state *state) { ++ int err; ++ ++ TRACE2(("enter dropbear_chachapoly_start")) ++ ++ if (keylen != CHACHA20_KEY_LEN*2) { ++ return CRYPT_ERROR; ++ } ++ ++ if ((err = chacha_setup(&state->chacha, key, ++ CHACHA20_KEY_LEN, 20)) != CRYPT_OK) { ++ return err; ++ } ++ ++ if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN, ++ CHACHA20_KEY_LEN, 20) != CRYPT_OK)) { ++ return err; ++ } ++ ++ TRACE2(("leave dropbear_chachapoly_start")) ++ return CRYPT_OK; ++} ++ ++static int dropbear_chachapoly_crypt(unsigned int seq, ++ const unsigned char *in, unsigned char *out, ++ unsigned long len, unsigned long taglen, ++ dropbear_chachapoly_state *state, int direction) { ++ poly1305_state poly; ++ unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN]; ++ int err; ++ ++ TRACE2(("enter dropbear_chachapoly_crypt")) ++ ++ if (len < 4 || taglen != POLY1305_TAG_LEN) { ++ return CRYPT_ERROR; ++ } ++ ++ STORE64H((uint64_t)seq, seqbuf); ++ chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0); ++ if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) { ++ return err; ++ } ++ ++ poly1305_init(&poly, key, sizeof(key)); ++ if (direction == LTC_DECRYPT) { ++ poly1305_process(&poly, in, len); ++ poly1305_done(&poly, tag, &taglen); ++ if (constant_time_memcmp(in + len, tag, taglen) != 0) { ++ return CRYPT_ERROR; ++ } ++ } ++ ++ chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0); ++ if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) { ++ return err; ++ } ++ ++ chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1); ++ if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) { ++ return err; ++ } ++ ++ if (direction == LTC_ENCRYPT) { ++ poly1305_process(&poly, out, len); ++ poly1305_done(&poly, out + len, &taglen); ++ } ++ ++ TRACE2(("leave dropbear_chachapoly_crypt")) ++ return CRYPT_OK; ++} ++ ++static int dropbear_chachapoly_getlength(unsigned int seq, ++ const unsigned char *in, unsigned int *outlen, ++ unsigned long len, dropbear_chachapoly_state *state) { ++ unsigned char seqbuf[8], buf[4]; ++ int err; ++ ++ TRACE2(("enter dropbear_chachapoly_getlength")) ++ ++ if (len < sizeof(buf)) { ++ return CRYPT_ERROR; ++ } ++ ++ STORE64H((uint64_t)seq, seqbuf); ++ chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0); ++ if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) { ++ return err; ++ } ++ ++ LOAD32H(*outlen, buf); ++ ++ TRACE2(("leave dropbear_chachapoly_getlength")) ++ return CRYPT_OK; ++} ++ ++const struct dropbear_cipher_mode dropbear_mode_chachapoly = ++ {(void *)dropbear_chachapoly_start, NULL, NULL, ++ (void *)dropbear_chachapoly_crypt, ++ (void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac}; ++ ++#endif /* DROPBEAR_CHACHA20POLY1305 */ +diff --git a/chachapoly.h b/chachapoly.h +new file mode 100644 +index 0000000..5a7c5b2 +--- /dev/null ++++ b/chachapoly.h +@@ -0,0 +1,44 @@ ++/* ++ * Dropbear SSH ++ * ++ * Copyright (c) 2002,2003 Matt Johnston ++ * Copyright (c) 2020 by Vladislav Grishenko ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. */ ++ ++#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_ ++#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_ ++ ++#include "includes.h" ++#include "algo.h" ++ ++#if DROPBEAR_CHACHA20POLY1305 ++ ++typedef struct { ++ chacha_state chacha; ++ chacha_state header; ++} dropbear_chachapoly_state; ++ ++extern const struct dropbear_cipher dropbear_chachapoly; ++extern const struct dropbear_cipher_mode dropbear_mode_chachapoly; ++ ++#endif /* DROPBEAR_CHACHA20POLY1305 */ ++ ++#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */ +diff --git a/common-algo.c b/common-algo.c +index 558aad2..1436456 100644 +--- a/common-algo.c ++++ b/common-algo.c +@@ -30,6 +30,7 @@ + #include "dh_groups.h" + #include "ltc_prng.h" + #include "ecc.h" ++#include "chachapoly.h" + + /* This file (algo.c) organises the ciphers which can be used, and is used to + * decide which ciphers/hashes/compression/signing to use during key exchange*/ +@@ -86,11 +87,11 @@ const struct dropbear_cipher dropbear_nocipher = + * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */ + #if DROPBEAR_ENABLE_CBC_MODE + const struct dropbear_cipher_mode dropbear_mode_cbc = +- {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt}; ++ {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL}; + #endif /* DROPBEAR_ENABLE_CBC_MODE */ + + const struct dropbear_cipher_mode dropbear_mode_none = +- {void_start, void_cipher, void_cipher}; ++ {void_start, void_cipher, void_cipher, NULL, NULL, NULL}; + + #if DROPBEAR_ENABLE_CTR_MODE + /* a wrapper to make ctr_start and cbc_start look the same */ +@@ -101,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher, + return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr); + } + const struct dropbear_cipher_mode dropbear_mode_ctr = +- {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt}; ++ {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL}; + #endif /* DROPBEAR_ENABLE_CTR_MODE */ + + /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc. +@@ -137,6 +138,10 @@ const struct dropbear_hash dropbear_nohash = + * that is also supported by the server will get used. */ + + algo_type sshciphers[] = { ++#if DROPBEAR_CHACHA20POLY1305 ++ {"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly}, ++#endif ++ + #if DROPBEAR_ENABLE_CTR_MODE + #if DROPBEAR_AES128 + {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr}, +diff --git a/common-kex.c b/common-kex.c +index 16b7e27..5e2923f 100644 +--- a/common-kex.c ++++ b/common-kex.c +@@ -329,9 +329,12 @@ static void gen_new_keys() { + hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D'); + + if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) { +- int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name); +- if (recv_cipher < 0) +- dropbear_exit("Crypto error"); ++ int recv_cipher = -1; ++ if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) { ++ recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name); ++ if (recv_cipher < 0) ++ dropbear_exit("Crypto error"); ++ } + if (ses.newkeys->recv.crypt_mode->start(recv_cipher, + recv_IV, recv_key, + ses.newkeys->recv.algo_crypt->keysize, 0, +@@ -341,9 +344,12 @@ static void gen_new_keys() { + } + + if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) { +- int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name); +- if (trans_cipher < 0) +- dropbear_exit("Crypto error"); ++ int trans_cipher = -1; ++ if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) { ++ trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name); ++ if (trans_cipher < 0) ++ dropbear_exit("Crypto error"); ++ } + if (ses.newkeys->trans.crypt_mode->start(trans_cipher, + trans_IV, trans_key, + ses.newkeys->trans.algo_crypt->keysize, 0, +@@ -868,19 +874,29 @@ static void read_kex_algos() { + + /* mac_algorithms_client_to_server */ + c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); ++#if DROPBEAR_AEAD_MODE ++ if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) { ++ c2s_hash_algo = NULL; ++ } else ++#endif + if (c2s_hash_algo == NULL) { + erralgo = "mac c->s"; + goto error; + } +- TRACE(("hash c2s is %s", c2s_hash_algo->name)) ++ TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "")) + + /* mac_algorithms_server_to_client */ + s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL); ++#if DROPBEAR_AEAD_MODE ++ if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) { ++ s2c_hash_algo = NULL; ++ } else ++#endif + if (s2c_hash_algo == NULL) { + erralgo = "mac s->c"; + goto error; + } +- TRACE(("hash s2c is %s", s2c_hash_algo->name)) ++ TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "")) + + /* compression_algorithms_client_to_server */ + c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL); +@@ -925,8 +941,14 @@ static void read_kex_algos() { + ses.newkeys->trans.crypt_mode = + (struct dropbear_cipher_mode*)c2s_cipher_algo->mode; + ses.newkeys->recv.algo_mac = ++#if DROPBEAR_AEAD_MODE ++ s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : ++#endif + (struct dropbear_hash*)s2c_hash_algo->data; + ses.newkeys->trans.algo_mac = ++#if DROPBEAR_AEAD_MODE ++ c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : ++#endif + (struct dropbear_hash*)c2s_hash_algo->data; + ses.newkeys->recv.algo_comp = s2c_comp_algo->val; + ses.newkeys->trans.algo_comp = c2s_comp_algo->val; +@@ -941,8 +963,14 @@ static void read_kex_algos() { + ses.newkeys->trans.crypt_mode = + (struct dropbear_cipher_mode*)s2c_cipher_algo->mode; + ses.newkeys->recv.algo_mac = ++#if DROPBEAR_AEAD_MODE ++ c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac : ++#endif + (struct dropbear_hash*)c2s_hash_algo->data; + ses.newkeys->trans.algo_mac = ++#if DROPBEAR_AEAD_MODE ++ s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac : ++#endif + (struct dropbear_hash*)s2c_hash_algo->data; + ses.newkeys->recv.algo_comp = c2s_comp_algo->val; + ses.newkeys->trans.algo_comp = s2c_comp_algo->val; +diff --git a/default_options.h b/default_options.h +index bafbb07..1a2ab10 100644 +--- a/default_options.h ++++ b/default_options.h +@@ -99,6 +99,12 @@ IMPORTANT: Some options will require "make clean" after changes */ + * and forwards compatibility */ + #define DROPBEAR_ENABLE_CTR_MODE 1 + ++/* Enable Chacha20-Poly1305 authenticated encryption mode. This is ++ * generally faster than AES256 on CPU w/o dedicated AES instructions, ++ * having the same key size. ++ * Compiling in will add ~5,5kB to binary size on x86-64 */ ++#define DROPBEAR_CHACHA20POLY1305 1 ++ + /* Message integrity. sha2-256 is recommended as a default, + sha1 for compatibility */ + #define DROPBEAR_SHA1_HMAC 1 +diff --git a/libtomcrypt/src/headers/tomcrypt_dropbear.h b/libtomcrypt/src/headers/tomcrypt_dropbear.h +index b0ce45b..59960e5 100644 +--- a/libtomcrypt/src/headers/tomcrypt_dropbear.h ++++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h +@@ -35,6 +35,10 @@ + #define LTC_CTR_MODE + #endif + ++#if DROPBEAR_CHACHA20POLY1305 ++#define LTC_CHACHA ++#define LTC_POLY1305 ++#endif + + #if DROPBEAR_SHA512 + #define LTC_SHA512 +diff --git a/packet.c b/packet.c +index 9fda0d6..0454726 100644 +--- a/packet.c ++++ b/packet.c +@@ -215,7 +215,7 @@ static int read_packet_init() { + + unsigned int maxlen; + int slen; +- unsigned int len; ++ unsigned int len, plen; + unsigned int blocksize; + unsigned int macsize; + +@@ -254,21 +254,35 @@ static int read_packet_init() { + /* now we have the first block, need to get packet length, so we decrypt + * the first block (only need first 4 bytes) */ + buf_setpos(ses.readbuf, 0); +- if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), +- buf_getwriteptr(ses.readbuf, blocksize), +- blocksize, +- &ses.keys->recv.cipher_state) != CRYPT_OK) { +- dropbear_exit("Error decrypting"); ++#if DROPBEAR_AEAD_MODE ++ if (ses.keys->recv.crypt_mode->aead_crypt) { ++ if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq, ++ buf_getptr(ses.readbuf, blocksize), &plen, ++ blocksize, ++ &ses.keys->recv.cipher_state) != CRYPT_OK) { ++ dropbear_exit("Error decrypting"); ++ } ++ len = plen + 4 + macsize; ++ } else ++#endif ++ { ++ if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize), ++ buf_getwriteptr(ses.readbuf, blocksize), ++ blocksize, ++ &ses.keys->recv.cipher_state) != CRYPT_OK) { ++ dropbear_exit("Error decrypting"); ++ } ++ plen = buf_getint(ses.readbuf) + 4; ++ len = plen + macsize; + } +- len = buf_getint(ses.readbuf) + 4 + macsize; + + TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize)) + + + /* check packet length */ + if ((len > RECV_MAX_PACKET_LEN) || +- (len < MIN_PACKET_LEN + macsize) || +- ((len - macsize) % blocksize != 0)) { ++ (plen < blocksize) || ++ (plen % blocksize != 0)) { + dropbear_exit("Integrity error (bad packet size %u)", len); + } + +@@ -294,23 +308,42 @@ void decrypt_packet() { + + ses.kexstate.datarecv += ses.readbuf->len; + +- /* we've already decrypted the first blocksize in read_packet_init */ +- buf_setpos(ses.readbuf, blocksize); +- +- /* decrypt it in-place */ +- len = ses.readbuf->len - macsize - ses.readbuf->pos; +- if (ses.keys->recv.crypt_mode->decrypt( +- buf_getptr(ses.readbuf, len), +- buf_getwriteptr(ses.readbuf, len), +- len, +- &ses.keys->recv.cipher_state) != CRYPT_OK) { +- dropbear_exit("Error decrypting"); +- } +- buf_incrpos(ses.readbuf, len); ++#if DROPBEAR_AEAD_MODE ++ if (ses.keys->recv.crypt_mode->aead_crypt) { ++ /* first blocksize is not decrypted yet */ ++ buf_setpos(ses.readbuf, 0); ++ ++ /* decrypt it in-place */ ++ len = ses.readbuf->len - macsize - ses.readbuf->pos; ++ if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq, ++ buf_getptr(ses.readbuf, len + macsize), ++ buf_getwriteptr(ses.readbuf, len), ++ len, macsize, ++ &ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) { ++ dropbear_exit("Error decrypting"); ++ } ++ buf_incrpos(ses.readbuf, len); ++ } else ++#endif ++ { ++ /* we've already decrypted the first blocksize in read_packet_init */ ++ buf_setpos(ses.readbuf, blocksize); ++ ++ /* decrypt it in-place */ ++ len = ses.readbuf->len - macsize - ses.readbuf->pos; ++ if (ses.keys->recv.crypt_mode->decrypt( ++ buf_getptr(ses.readbuf, len), ++ buf_getwriteptr(ses.readbuf, len), ++ len, ++ &ses.keys->recv.cipher_state) != CRYPT_OK) { ++ dropbear_exit("Error decrypting"); ++ } ++ buf_incrpos(ses.readbuf, len); + +- /* check the hmac */ +- if (checkmac() != DROPBEAR_SUCCESS) { +- dropbear_exit("Integrity error"); ++ /* check the hmac */ ++ if (checkmac() != DROPBEAR_SUCCESS) { ++ dropbear_exit("Integrity error"); ++ } + } + + /* get padding length */ +@@ -557,9 +590,16 @@ void encrypt_packet() { + buf_setpos(ses.writepayload, 0); + buf_setlen(ses.writepayload, 0); + +- /* length of padding - packet length must be a multiple of blocksize, +- * with a minimum of 4 bytes of padding */ +- padlen = blocksize - (writebuf->len) % blocksize; ++ /* length of padding - packet length excluding the packetlength uint32 ++ * field in aead mode must be a multiple of blocksize, with a minimum of ++ * 4 bytes of padding */ ++ len = writebuf->len; ++#if DROPBEAR_AEAD_MODE ++ if (ses.keys->trans.crypt_mode->aead_crypt) { ++ len -= 4; ++ } ++#endif ++ padlen = blocksize - len % blocksize; + if (padlen < 4) { + padlen += blocksize; + } +@@ -579,23 +619,42 @@ void encrypt_packet() { + buf_incrlen(writebuf, padlen); + genrandom(buf_getptr(writebuf, padlen), padlen); + +- make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes); ++#if DROPBEAR_AEAD_MODE ++ if (ses.keys->trans.crypt_mode->aead_crypt) { ++ /* do the actual encryption, in-place */ ++ buf_setpos(writebuf, 0); ++ /* encrypt it in-place*/ ++ len = writebuf->len; ++ buf_incrlen(writebuf, mac_size); ++ if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq, ++ buf_getptr(writebuf, len), ++ buf_getwriteptr(writebuf, len + mac_size), ++ len, mac_size, ++ &ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) { ++ dropbear_exit("Error encrypting"); ++ } ++ buf_incrpos(writebuf, len + mac_size); ++ } else ++#endif ++ { ++ make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes); ++ ++ /* do the actual encryption, in-place */ ++ buf_setpos(writebuf, 0); ++ /* encrypt it in-place*/ ++ len = writebuf->len; ++ if (ses.keys->trans.crypt_mode->encrypt( ++ buf_getptr(writebuf, len), ++ buf_getwriteptr(writebuf, len), ++ len, ++ &ses.keys->trans.cipher_state) != CRYPT_OK) { ++ dropbear_exit("Error encrypting"); ++ } ++ buf_incrpos(writebuf, len); + +- /* do the actual encryption, in-place */ +- buf_setpos(writebuf, 0); +- /* encrypt it in-place*/ +- len = writebuf->len; +- if (ses.keys->trans.crypt_mode->encrypt( +- buf_getptr(writebuf, len), +- buf_getwriteptr(writebuf, len), +- len, +- &ses.keys->trans.cipher_state) != CRYPT_OK) { +- dropbear_exit("Error encrypting"); ++ /* stick the MAC on it */ ++ buf_putbytes(writebuf, mac_bytes, mac_size); + } +- buf_incrpos(writebuf, len); +- +- /* stick the MAC on it */ +- buf_putbytes(writebuf, mac_bytes, mac_size); + + /* Update counts */ + ses.kexstate.datatrans += writebuf->len; +diff --git a/session.h b/session.h +index e436882..a8f8914 100644 +--- a/session.h ++++ b/session.h +@@ -41,6 +41,7 @@ + #include "chansession.h" + #include "dbutil.h" + #include "netio.h" ++#include "chachapoly.h" + + void common_session_init(int sock_in, int sock_out); + void session_loop(void(*loophandler)(void)) ATTRIB_NORETURN; +@@ -80,6 +81,9 @@ struct key_context_directional { + symmetric_CBC cbc; + #if DROPBEAR_ENABLE_CTR_MODE + symmetric_CTR ctr; ++#endif ++#if DROPBEAR_CHACHA20POLY1305 ++ dropbear_chachapoly_state chachapoly; + #endif + } cipher_state; + unsigned char mackey[MAX_MAC_LEN]; +diff --git a/sysoptions.h b/sysoptions.h +index 2c27caf..2432779 100644 +--- a/sysoptions.h ++++ b/sysoptions.h +@@ -92,7 +92,11 @@ + #define MD5_HASH_SIZE 16 + #define MAX_HASH_SIZE 64 /* sha512 */ + ++#if DROPBEAR_CHACHA20POLY1305 ++#define MAX_KEY_LEN 64 /* 2 x 256 bits for chacha20 */ ++#else + #define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */ ++#endif + #define MAX_IV_LEN 20 /* must be same as max blocksize, */ + + #if DROPBEAR_SHA2_512_HMAC +@@ -207,6 +211,8 @@ If you test it please contact the Dropbear author */ + + #define DROPBEAR_TWOFISH ((DROPBEAR_TWOFISH256) || (DROPBEAR_TWOFISH128)) + ++#define DROPBEAR_AEAD_MODE ((DROPBEAR_CHACHA20POLY1305)) ++ + #define DROPBEAR_CLI_ANYTCPFWD ((DROPBEAR_CLI_REMOTETCPFWD) || (DROPBEAR_CLI_LOCALTCPFWD)) + + #define DROPBEAR_TCP_ACCEPT ((DROPBEAR_CLI_LOCALTCPFWD) || (DROPBEAR_SVR_REMOTETCPFWD)) +@@ -249,7 +255,7 @@ If you test it please contact the Dropbear author */ + #endif + + #if !(DROPBEAR_AES128 || DROPBEAR_3DES || DROPBEAR_AES256 || DROPBEAR_BLOWFISH \ +- || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128) ++ || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128 || DROPBEAR_CHACHA20POLY1305) + #error "At least one encryption algorithm must be enabled. AES128 is recommended." + #endif + +-- +2.17.1 + diff --git a/package/network/services/ppp/Makefile b/package/network/services/ppp/Makefile index babc7a90bf..8cd2cbc1d9 100644 --- a/package/network/services/ppp/Makefile +++ b/package/network/services/ppp/Makefile @@ -13,9 +13,9 @@ PKG_RELEASE:=5 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/paulusmack/ppp -PKG_SOURCE_DATE:=2020-03-21 -PKG_SOURCE_VERSION:=41a73232c16e9a063cfe3fad461c94af3f450f6c -PKG_MIRROR_HASH:=7b966003b7c1bec95156159119b52583778405f0229dc7590911fa93f031552b +PKG_SOURCE_DATE:=2020-05-25 +PKG_SOURCE_VERSION:=ddd57c279f467e18c4fb3a661f21a069a5a37a1f +PKG_MIRROR_HASH:=aac65e65dd25eaf8978a7a0b3258c863d90e29e247dd33d95276c0c189bcd424 PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=BSD-4-Clause PKG_CPE_ID:=cpe:/a:samba:ppp diff --git a/package/network/services/ppp/patches/100-debian_ip-ip_option.patch b/package/network/services/ppp/patches/100-debian_ip-ip_option.patch index 335ce72b0a..a996622922 100644 --- a/package/network/services/ppp/patches/100-debian_ip-ip_option.patch +++ b/package/network/services/ppp/patches/100-debian_ip-ip_option.patch @@ -85,7 +85,7 @@ Signed-off-by: Jo-Philipp Wich "Enable multilink operation", OPT_PRIO | 1 }, --- a/pppd/pppd.h +++ b/pppd/pppd.h -@@ -334,6 +334,8 @@ extern int connect_delay; /* Time to del +@@ -335,6 +335,8 @@ extern int connect_delay; /* Time to del extern int max_data_rate; /* max bytes/sec through charshunt */ extern int req_unit; /* interface unit number to use */ extern char req_ifname[MAXIFNAMELEN]; /* interface name to use */ diff --git a/package/network/services/ppp/patches/105-debian_demand.patch b/package/network/services/ppp/patches/105-debian_demand.patch index c68bafa8df..fb6f39f4b9 100644 --- a/package/network/services/ppp/patches/105-debian_demand.patch +++ b/package/network/services/ppp/patches/105-debian_demand.patch @@ -161,7 +161,7 @@ } else { --- a/pppd/pppd.h +++ b/pppd/pppd.h -@@ -601,7 +601,7 @@ void demand_conf __P((void)); /* config +@@ -602,7 +602,7 @@ void demand_conf __P((void)); /* config void demand_block __P((void)); /* set all NPs to queue up packets */ void demand_unblock __P((void)); /* set all NPs to pass packets */ void demand_discard __P((void)); /* set all NPs to discard packets */ diff --git a/package/network/services/ppp/patches/110-debian_defaultroute.patch b/package/network/services/ppp/patches/110-debian_defaultroute.patch index 38739a5243..e474571767 100644 --- a/package/network/services/ppp/patches/110-debian_defaultroute.patch +++ b/package/network/services/ppp/patches/110-debian_defaultroute.patch @@ -137,7 +137,7 @@ Signed-off-by: Jo-Philipp Wich .B disconnect \fIscript Execute the command specified by \fIscript\fR, by passing it to a shell, after -@@ -746,7 +751,12 @@ disable both forms of hardware flow cont +@@ -751,7 +756,12 @@ disable both forms of hardware flow cont .TP .B nodefaultroute Disable the \fIdefaultroute\fR option. The system administrator who @@ -153,7 +153,7 @@ Signed-off-by: Jo-Philipp Wich .B nodefaultroute6 --- a/pppd/pppd.h +++ b/pppd/pppd.h -@@ -683,7 +683,7 @@ int sif6addr __P((int, eui64_t, eui64_t +@@ -684,7 +684,7 @@ int sif6addr __P((int, eui64_t, eui64_t int cif6addr __P((int, eui64_t, eui64_t)); /* Remove an IPv6 address from i/f */ #endif @@ -292,7 +292,7 @@ Signed-off-by: Jo-Philipp Wich } --- a/pppd/sys-solaris.c +++ b/pppd/sys-solaris.c -@@ -2119,12 +2119,18 @@ cifaddr(u, o, h) +@@ -2120,12 +2120,18 @@ cifaddr(u, o, h) * sifdefaultroute - assign a default route through the address given. */ int diff --git a/package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch b/package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch index 4a9ca7d5e7..5ef09b3f3e 100644 --- a/package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch +++ b/package/network/services/ppp/patches/120-debian_ipv6_updown_option.patch @@ -84,7 +84,7 @@ Signed-off-by: Jo-Philipp Wich } --- a/pppd/pppd.h +++ b/pppd/pppd.h -@@ -336,6 +336,8 @@ extern int req_unit; /* interface unit n +@@ -337,6 +337,8 @@ extern int req_unit; /* interface unit n extern char req_ifname[MAXIFNAMELEN]; /* interface name to use */ extern char path_ipup[MAXPATHLEN]; /* pathname of ip-up script */ extern char path_ipdown[MAXPATHLEN]; /* pathname of ip-down script */ diff --git a/package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch b/package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch deleted file mode 100644 index 510c96ba97..0000000000 --- a/package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch +++ /dev/null @@ -1,56 +0,0 @@ ---- a/pppd/lcp.c -+++ b/pppd/lcp.c -@@ -72,6 +72,7 @@ static void lcp_delayed_up __P((void *)) - */ - int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ - int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ -+bool lcp_echo_adaptive = 0; /* request echo only if the link was idle */ - bool lax_recv = 0; /* accept control chars in asyncmap */ - bool noendpoint = 0; /* don't send/accept endpoint discriminator */ - -@@ -150,6 +151,8 @@ static option_t lcp_option_list[] = { - OPT_PRIO }, - { "lcp-echo-interval", o_int, &lcp_echo_interval, - "Set time in seconds between LCP echo requests", OPT_PRIO }, -+ { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive, -+ "Suppress LCP echo requests if traffic was received", 1 }, - { "lcp-restart", o_int, &lcp_fsm[0].timeouttime, - "Set time in seconds between LCP retransmissions", OPT_PRIO }, - { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits, -@@ -2330,6 +2333,22 @@ LcpSendEchoRequest (f) - } - } - -+ /* -+ * If adaptive echos have been enabled, only send the echo request if -+ * no traffic was received since the last one. -+ */ -+ if (lcp_echo_adaptive) { -+ static unsigned int last_pkts_in = 0; -+ -+ update_link_stats(f->unit); -+ link_stats_valid = 0; -+ -+ if (link_stats.pkts_in != last_pkts_in) { -+ last_pkts_in = link_stats.pkts_in; -+ return; -+ } -+ } -+ - /* - * Make and send the echo request frame. - */ ---- a/pppd/pppd.8 -+++ b/pppd/pppd.8 -@@ -575,6 +575,11 @@ to 1) if the \fIproxyarp\fR option is us - dynamic IP address option (i.e. set /proc/sys/net/ipv4/ip_dynaddr to - 1) in demand mode if the local address changes. - .TP -+.B lcp\-echo\-adaptive -+If this option is used with the \fIlcp\-echo\-failure\fR option then -+pppd will send LCP echo\-request frames only if no traffic was received -+from the peer since the last echo\-request was sent. -+.TP - .B lcp\-echo\-failure \fIn - If this option is given, pppd will presume the peer to be dead - if \fIn\fR LCP echo\-requests are sent without receiving a valid LCP diff --git a/package/network/services/ppp/patches/206-compensate_time_change.patch b/package/network/services/ppp/patches/206-compensate_time_change.patch deleted file mode 100644 index a1eb6a716c..0000000000 --- a/package/network/services/ppp/patches/206-compensate_time_change.patch +++ /dev/null @@ -1,94 +0,0 @@ -pppd: Watch out for time warps - -On many embedded systems there is no battery backed RTC and a proper system -time only becomes available through NTP after establishing a connection. - -When the clock suddenly jumps forward, the internal accounting (connect time) -is confused resulting in unreliable data. - -This patch implements periodic clock checking to look for time warps, if one -is detected, the internal counters are adjusted accordingly. - -Signed-off-by: Jo-Philipp Wich - ---- a/pppd/main.c -+++ b/pppd/main.c -@@ -89,6 +89,7 @@ - #include - #include - #include -+#include - - #include "pppd.h" - #include "magic.h" -@@ -226,6 +227,7 @@ static struct subprocess *children; - - /* Prototypes for procedures local to this file. */ - -+static void check_time(void); - static void setup_signals __P((void)); - static void create_pidfile __P((int pid)); - static void create_linkpidfile __P((int pid)); -@@ -525,6 +527,7 @@ main(argc, argv) - info("Starting link"); - } - -+ check_time(); - gettimeofday(&start_time, NULL); - script_unsetenv("CONNECT_TIME"); - script_unsetenv("BYTES_SENT"); -@@ -1274,6 +1277,36 @@ struct callout { - - static struct callout *callout = NULL; /* Callout list */ - static struct timeval timenow; /* Current time */ -+static long uptime_diff = 0; -+static int uptime_diff_set = 0; -+ -+static void check_time(void) -+{ -+ long new_diff; -+ struct timeval t; -+ struct sysinfo i; -+ struct callout *p; -+ -+ gettimeofday(&t, NULL); -+ sysinfo(&i); -+ new_diff = t.tv_sec - i.uptime; -+ -+ if (!uptime_diff_set) { -+ uptime_diff = new_diff; -+ uptime_diff_set = 1; -+ return; -+ } -+ -+ if ((new_diff - 5 > uptime_diff) || (new_diff + 5 < uptime_diff)) { -+ /* system time has changed, update counters and timeouts */ -+ info("System time change detected."); -+ start_time.tv_sec += new_diff - uptime_diff; -+ -+ for (p = callout; p != NULL; p = p->c_next) -+ p->c_time.tv_sec += new_diff - uptime_diff; -+ } -+ uptime_diff = new_diff; -+} - - /* - * timeout - Schedule a timeout. -@@ -1344,6 +1377,8 @@ calltimeout() - { - struct callout *p; - -+ check_time(); -+ - while (callout != NULL) { - p = callout; - -@@ -1371,6 +1406,8 @@ timeleft(tvp) - { - if (callout == NULL) - return NULL; -+ -+ check_time(); - - gettimeofday(&timenow, NULL); - tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec; diff --git a/package/network/services/ppp/patches/208-fix_status_code.patch b/package/network/services/ppp/patches/208-fix_status_code.patch index 31460148a4..f1a12006a5 100644 --- a/package/network/services/ppp/patches/208-fix_status_code.patch +++ b/package/network/services/ppp/patches/208-fix_status_code.patch @@ -12,7 +12,7 @@ Signed-off-by: Jo-Philipp Wich --- a/pppd/main.c +++ b/pppd/main.c -@@ -1055,7 +1055,8 @@ get_input() +@@ -1052,7 +1052,8 @@ get_input() } notice("Modem hangup"); hungup = 1; diff --git a/package/network/services/ppp/patches/401-no_record_file.patch b/package/network/services/ppp/patches/401-no_record_file.patch index 56a9f02eb8..f707fda8ab 100644 --- a/package/network/services/ppp/patches/401-no_record_file.patch +++ b/package/network/services/ppp/patches/401-no_record_file.patch @@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich --- a/pppd/pppd.h +++ b/pppd/pppd.h -@@ -325,7 +325,6 @@ extern int holdoff; /* Dead time before +@@ -326,7 +326,6 @@ extern int holdoff; /* Dead time before extern bool holdoff_specified; /* true if user gave a holdoff value */ extern bool notty; /* Stdin/out is not a tty */ extern char *pty_socket; /* Socket to connect to pty */ diff --git a/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch b/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch index 1d94873f35..d37fc03539 100644 --- a/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch +++ b/package/network/services/ppp/patches/404-remove_obsolete_protocol_names.patch @@ -7,7 +7,7 @@ Signed-off-by: Jo-Philipp Wich --- a/pppd/main.c +++ b/pppd/main.c -@@ -886,14 +886,17 @@ struct protocol_list { +@@ -883,14 +883,17 @@ struct protocol_list { const char *name; } protocol_list[] = { { 0x21, "IP" }, @@ -25,7 +25,7 @@ Signed-off-by: Jo-Philipp Wich { 0x33, "Stream Protocol ST-II" }, { 0x35, "Banyan Vines" }, { 0x39, "AppleTalk EDDP" }, -@@ -907,8 +910,11 @@ struct protocol_list { +@@ -904,8 +907,11 @@ struct protocol_list { { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, { 0x4b, "SNA over 802.2" }, { 0x4d, "SNA" }, @@ -37,7 +37,7 @@ Signed-off-by: Jo-Philipp Wich { 0x53, "Encryption" }, { 0x55, "Individual Link Encryption" }, { 0x57, "IPv6" }, -@@ -919,12 +925,15 @@ struct protocol_list { +@@ -916,12 +922,15 @@ struct protocol_list { { 0x65, "RTP IPHC Compressed non-TCP" }, { 0x67, "RTP IPHC Compressed UDP 8" }, { 0x69, "RTP IPHC Compressed RTP 8" }, @@ -53,7 +53,7 @@ Signed-off-by: Jo-Philipp Wich { 0x0203, "IBM Source Routing BPDU" }, { 0x0205, "DEC LANBridge100 Spanning Tree" }, { 0x0207, "Cisco Discovery Protocol" }, -@@ -936,15 +945,19 @@ struct protocol_list { +@@ -933,15 +942,19 @@ struct protocol_list { { 0x0231, "Luxcom" }, { 0x0233, "Sigma Network Systems" }, { 0x0235, "Apple Client Server Protocol" }, @@ -73,7 +73,7 @@ Signed-off-by: Jo-Philipp Wich { 0x4001, "Cray Communications Control Protocol" }, { 0x4003, "CDPD Mobile Network Registration Protocol" }, { 0x4005, "Expand accelerator protocol" }, -@@ -955,8 +968,10 @@ struct protocol_list { +@@ -952,8 +965,10 @@ struct protocol_list { { 0x4023, "RefTek Protocol" }, { 0x4025, "Fibre Channel" }, { 0x4027, "EMIT Protocols" }, @@ -84,7 +84,7 @@ Signed-off-by: Jo-Philipp Wich { 0x8023, "OSI Network Layer Control Protocol" }, { 0x8025, "Xerox NS IDP Control Protocol" }, { 0x8027, "DECnet Phase IV Control Protocol" }, -@@ -965,7 +980,9 @@ struct protocol_list { +@@ -962,7 +977,9 @@ struct protocol_list { { 0x8031, "Bridging NCP" }, { 0x8033, "Stream Protocol Control Protocol" }, { 0x8035, "Banyan Vines Control Protocol" }, @@ -94,7 +94,7 @@ Signed-off-by: Jo-Philipp Wich { 0x803f, "NETBIOS Framing Control Protocol" }, { 0x8041, "Cisco Systems Control Protocol" }, { 0x8043, "Ascom Timeplex" }, -@@ -974,18 +991,24 @@ struct protocol_list { +@@ -971,18 +988,24 @@ struct protocol_list { { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" }, { 0x804b, "SNA over 802.2 Control Protocol" }, { 0x804d, "SNA Control Protocol" }, @@ -119,7 +119,7 @@ Signed-off-by: Jo-Philipp Wich { 0x8207, "Cisco Discovery Protocol Control" }, { 0x8209, "Netcs Twin Routing" }, { 0x820b, "STP - Control Protocol" }, -@@ -994,24 +1017,29 @@ struct protocol_list { +@@ -991,24 +1014,29 @@ struct protocol_list { { 0x8281, "MPLSCP" }, { 0x8285, "IEEE p1284.4 standard - Protocol Control" }, { 0x8287, "ETSI TETRA TNP1 Control Protocol" }, diff --git a/package/network/services/ppp/patches/600-Revert-pppd-Use-openssl-for-the-DES-instead-of-the-l.patch b/package/network/services/ppp/patches/600-Revert-pppd-Use-openssl-for-the-DES-instead-of-the-l.patch index 331ec09ed2..5802d6158c 100644 --- a/package/network/services/ppp/patches/600-Revert-pppd-Use-openssl-for-the-DES-instead-of-the-l.patch +++ b/package/network/services/ppp/patches/600-Revert-pppd-Use-openssl-for-the-DES-instead-of-the-l.patch @@ -17,7 +17,7 @@ This reverts commit 3c7b86229f7bd2600d74db14b1fe5b3896be3875. +++ b/pppd/Makefile.linux @@ -35,10 +35,10 @@ endif COPTS = -O2 -pipe -Wall -g - LIBS = + LIBS = -lrt -# Uncomment the next line to include support for Microsoft's +# Uncomment the next 2 lines to include support for Microsoft's diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c index 0a9dfbc8a0..e3b4087eff 100644 --- a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c +++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c @@ -79,7 +79,7 @@ static struct gpio_keys_button tl_mr3020_gpio_keys[] __initdata = { }, { .desc = "sw1", - .type = EV_KEY, + .type = EV_SW, .code = BTN_0, .debounce_interval = TL_MR3020_KEYS_DEBOUNCE_INTERVAL, .gpio = TL_MR3020_GPIO_BTN_SW1, @@ -87,7 +87,7 @@ static struct gpio_keys_button tl_mr3020_gpio_keys[] __initdata = { }, { .desc = "sw2", - .type = EV_KEY, + .type = EV_SW, .code = BTN_1, .debounce_interval = TL_MR3020_KEYS_DEBOUNCE_INTERVAL, .gpio = TL_MR3020_GPIO_BTN_SW2, diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c index ece38f900f..514529ca18 100644 --- a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c +++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c @@ -24,7 +24,7 @@ #include "machtypes.h" #define TL_WR802N_GPIO_LED_SYSTEM 13 -#define TL_WR802N_GPIO_BTN_RESET 11 +#define TL_WR802N_GPIO_BTN_RESET 12 #define TL_WR802N_KEYS_POLL_INTERVAL 20 /* msecs */ #define TL_WR802N_KEYS_DEBOUNCE_INTERVAL (3 * TL_WR802N_KEYS_POLL_INTERVAL) @@ -61,7 +61,7 @@ static struct gpio_keys_button tl_wr802n_gpio_keys[] __initdata = { .code = KEY_RESTART, .debounce_interval = TL_WR802N_KEYS_DEBOUNCE_INTERVAL, .gpio = TL_WR802N_GPIO_BTN_RESET, - .active_low = 0, + .active_low = 1, } }; diff --git a/target/linux/ath79/dts/ar9330_glinet_gl-ar150.dts b/target/linux/ath79/dts/ar9330_glinet_gl-ar150.dts index 68e1995c76..d81d477227 100644 --- a/target/linux/ath79/dts/ar9330_glinet_gl-ar150.dts +++ b/target/linux/ath79/dts/ar9330_glinet_gl-ar150.dts @@ -12,29 +12,31 @@ aliases { serial0 = &uart; - led-boot = &led_wlan; - led-failsafe = &led_wlan; - led-upgrade = &led_wlan; + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; label-mac-device = ð0; }; leds { compatible = "gpio-leds"; - led_wlan: wlan { + wlan { label = "gl-ar150:orange:wlan"; gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; linux,default-trigger = "phy0tpt"; }; - lan { - label = "gl-ar150:green:lan"; + configurable { + label = "gl-ar150:green:configurable"; gpios = <&gpio 13 GPIO_ACTIVE_HIGH>; }; - wan { - label = "gl-ar150:green:wan"; + led_power: power { + label = "gl-ar150:green:power"; gpios = <&gpio 15 GPIO_ACTIVE_HIGH>; + default-state = "on"; }; }; diff --git a/target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v1.dts b/target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v1.dts new file mode 100644 index 0000000000..229c5fa7bd --- /dev/null +++ b/target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v1.dts @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/dts-v1/; + +#include "qca9533_tplink_tl-wr802n.dtsi" + +/ { + model = "TP-Link TL-WR802N v1"; + compatible = "tplink,tl-wr802n-v1", "qca,qca9533"; +}; diff --git a/target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v2.dts b/target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v2.dts new file mode 100644 index 0000000000..cbfd275d2b --- /dev/null +++ b/target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v2.dts @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/dts-v1/; + +#include "qca9533_tplink_tl-wr802n.dtsi" + +/ { + model = "TP-Link TL-WR802N v2"; + compatible = "tplink,tl-wr802n-v2", "qca,qca9533"; +}; diff --git a/target/linux/ath79/dts/qca9533_tplink_tl-wr802n.dtsi b/target/linux/ath79/dts/qca9533_tplink_tl-wr802n.dtsi new file mode 100644 index 0000000000..f89d020672 --- /dev/null +++ b/target/linux/ath79/dts/qca9533_tplink_tl-wr802n.dtsi @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include +#include + +#include "qca953x.dtsi" + +/ { + chosen { + bootargs = "console=ttyS0,115200n8"; + }; + + aliases { + led-boot = &led_system; + led-failsafe = &led_system; + led-running = &led_system; + led-upgrade = &led_system; + label-mac-device = &wmac; + }; + + leds { + compatible = "gpio-leds"; + + led_system: system { + label = "tp-link:green:system"; + gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "Reset button"; + linux,code = ; + gpios = <&gpio 12 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&uart { + status = "okay"; +}; + +&spi { + status = "okay"; + + num-cs = <1>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + uboot: partition@0 { + label = "u-boot"; + reg = <0x000000 0x020000>; + read-only; + }; + + partition@20000 { + label = "firmware"; + reg = <0x020000 0x3d0000>; + compatible = "tplink,firmware"; + }; + + art: partition@3f0000 { + label = "art"; + reg = <0x3f0000 0x010000>; + read-only; + }; + }; + }; +}; + +&wmac { + status = "okay"; + + mtd-cal-data = <&art 0x1000>; + mtd-mac-address = <&uboot 0x1fc00>; +}; + +ð0 { + status = "okay"; + + phy-handle = <&swphy4>; + + mtd-mac-address = <&uboot 0x1fc00>; + mtd-mac-address-increment = <1>; +}; + +ð1 { + compatible = "syscon", "simple-mfd"; +}; diff --git a/target/linux/ath79/dts/qca9563_tplink_re450-v2.dts b/target/linux/ath79/dts/qca9563_tplink_re450-v2.dts index 16bc26c978..4446163a50 100644 --- a/target/linux/ath79/dts/qca9563_tplink_re450-v2.dts +++ b/target/linux/ath79/dts/qca9563_tplink_re450-v2.dts @@ -1,194 +1,47 @@ // SPDX-License-Identifier: GPL-2.0-or-later OR MIT /dts-v1/; -#include -#include - -#include "qca956x.dtsi" +#include "qca9563_tplink_re450.dtsi" / { compatible = "tplink,re450-v2", "qca,qca9563"; model = "TP-Link RE450 v2"; +}; - chosen { - bootargs = "console=ttyS0,115200n8"; +&partitions { + partition@0 { + label = "u-boot"; + reg = <0x000000 0x020000>; + read-only; }; - aliases { - led-boot = &led_power; - led-failsafe = &led_power; - led-running = &led_power; - led-upgrade = &led_power; - mdio-gpio0 = &mdio2; + partition@20000 { + compatible = "tplink,firmware"; + label = "firmware"; + reg = <0x020000 0x5e0000>; }; - leds { - compatible = "gpio-leds"; - - led_power: power { - label = "tp-link:blue:power"; - gpios = <&gpio 1 GPIO_ACTIVE_LOW>; - }; - - wlan2g { - label = "tp-link:blue:wlan2g"; - gpios = <&gpio 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "phy1tpt"; - }; - - wlan5g { - label = "tp-link:blue:wlan5g"; - gpios = <&gpio 5 GPIO_ACTIVE_LOW>; - linux,default-trigger = "phy0tpt"; - }; - - lan_link { - label = "tp-link:green:lan_link"; - gpios = <&gpio 8 GPIO_ACTIVE_LOW>; - }; - - lan_data { - label = "tp-link:green:lan_data"; - gpios = <&gpio 9 GPIO_ACTIVE_LOW>; - }; - - wps_blue { - label = "tp-link:blue:wps"; - gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; - }; - - wps_red { - label = "tp-link:red:wps"; - gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; - }; + partition@600000 { + label = "partition-table"; + reg = <0x600000 0x010000>; + read-only; }; - keys { - compatible = "gpio-keys"; - - reset { - label = "Reset button"; - linux,code = ; - gpios = <&gpio 6 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - }; - - power { - label = "Power button"; - linux,code = ; - gpios = <&gpio 2 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - }; - - leds { - label = "LED control button"; - linux,code = ; - gpios = <&gpio 7 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - }; - - wps { - label = "WPS button"; - linux,code = ; - gpios = <&gpio 19 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - }; + info: partition@610000 { + label = "info"; + reg = <0x610000 0x020000>; + read-only; }; - mdio2: mdio { - compatible = "virtual,mdio-gpio"; + partition@630000 { + label = "config"; + reg = <0x630000 0x020000>; + read-only; + }; - gpios = <&gpio 3 GPIO_ACTIVE_HIGH>, /* MDC */ - <&gpio 4 GPIO_ACTIVE_HIGH>; /* MDIO */ - #address-cells = <1>; - #size-cells = <0>; - - phy4: ethernet-phy@4 { - reg = <4>; - device_type = "ethernet-phy"; - reset-gpios = <&gpio 11 GPIO_ACTIVE_LOW>; - }; + art: partition@7f0000 { + label = "art"; + reg = <0x7f0000 0x010000>; + read-only; }; }; - -&pcie { - status = "okay"; -}; - -&uart { - status = "okay"; -}; - -&gpio { - status = "okay"; -}; - -&spi { - status = "okay"; - - num-cs = <1>; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <25000000>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "u-boot"; - reg = <0x000000 0x020000>; - read-only; - }; - - partition@20000 { - compatible = "tplink,firmware"; - label = "firmware"; - reg = <0x020000 0x5e0000>; - }; - - partition@600000 { - label = "partition-table"; - reg = <0x600000 0x010000>; - read-only; - }; - - info: partition@610000 { - label = "info"; - reg = <0x610000 0x020000>; - read-only; - }; - - partition@630000 { - label = "config"; - reg = <0x630000 0x020000>; - read-only; - }; - - art: partition@7f0000 { - label = "art"; - reg = <0x7f0000 0x010000>; - read-only; - }; - }; - }; -}; - -ð0 { - status = "okay"; - - phy-mode = "sgmii"; - phy-handle = <&phy4>; - - mtd-mac-address = <&info 0x8>; -}; - -&wmac { - status = "okay"; - - mtd-cal-data = <&art 0x1000>; - mtd-mac-address = <&info 0x8>; -}; diff --git a/target/linux/ath79/dts/qca9563_tplink_re450-v3.dts b/target/linux/ath79/dts/qca9563_tplink_re450-v3.dts new file mode 100644 index 0000000000..f85f02428b --- /dev/null +++ b/target/linux/ath79/dts/qca9563_tplink_re450-v3.dts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/dts-v1/; + +#include "qca9563_tplink_re450.dtsi" + +/ { + compatible = "tplink,re450-v3", "qca,qca9563"; + model = "TP-Link RE450 v3"; +}; + +&partitions { + partition@0 { + label = "u-boot"; + reg = <0x000000 0x020000>; + read-only; + }; + + info: partition@20000 { + label = "info"; + reg = <0x020000 0x002000>; + read-only; + }; + + partition@22000 { + label = "partition-table"; + reg = <0x022000 0x002000>; + read-only; + }; + + partition@24000 { + label = "info2"; + reg = <0x024000 0x00a000>; + read-only; + }; + + partition@2e000 { + label = "config"; + reg = <0x02e000 0x022000>; + read-only; + }; + + partition@50000 { + compatible = "tplink,firmware"; + label = "firmware"; + reg = <0x050000 0x7a0000>; + }; + + art: partition@7f0000 { + label = "art"; + reg = <0x7f0000 0x010000>; + read-only; + }; +}; diff --git a/target/linux/ath79/dts/qca9563_tplink_re450.dtsi b/target/linux/ath79/dts/qca9563_tplink_re450.dtsi new file mode 100644 index 0000000000..6c894a314e --- /dev/null +++ b/target/linux/ath79/dts/qca9563_tplink_re450.dtsi @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include +#include + +#include "qca956x.dtsi" + +/ { + chosen { + bootargs = "console=ttyS0,115200n8"; + }; + + aliases { + label-mac-device = ð0; + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + mdio-gpio0 = &mdio2; + }; + + leds { + compatible = "gpio-leds"; + + led_power: power { + label = "tp-link:blue:power"; + gpios = <&gpio 1 GPIO_ACTIVE_LOW>; + }; + + wlan2g { + label = "tp-link:blue:wlan2g"; + gpios = <&gpio 14 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy1tpt"; + }; + + wlan5g { + label = "tp-link:blue:wlan5g"; + gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy0tpt"; + }; + + lan_link { + label = "tp-link:green:lan_link"; + gpios = <&gpio 8 GPIO_ACTIVE_LOW>; + }; + + lan_data { + label = "tp-link:green:lan_data"; + gpios = <&gpio 9 GPIO_ACTIVE_LOW>; + }; + + wps_blue { + label = "tp-link:blue:wps"; + gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + }; + + wps_red { + label = "tp-link:red:wps"; + gpios = <&gpio 20 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "Reset button"; + linux,code = ; + gpios = <&gpio 6 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + + power { + label = "Power button"; + linux,code = ; + gpios = <&gpio 2 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + + leds { + label = "LED control button"; + linux,code = ; + gpios = <&gpio 7 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + + wps { + label = "WPS button"; + linux,code = ; + gpios = <&gpio 19 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + }; + + mdio2: mdio { + compatible = "virtual,mdio-gpio"; + + gpios = <&gpio 3 GPIO_ACTIVE_HIGH>, /* MDC */ + <&gpio 4 GPIO_ACTIVE_HIGH>; /* MDIO */ + #address-cells = <1>; + #size-cells = <0>; + + phy4: ethernet-phy@4 { + reg = <4>; + device_type = "ethernet-phy"; + reset-gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&uart { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&spi { + status = "okay"; + + num-cs = <1>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <25000000>; + + partitions: partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + }; + }; +}; + +ð0 { + status = "okay"; + + phy-mode = "sgmii"; + phy-handle = <&phy4>; + + mtd-mac-address = <&info 0x8>; +}; + +&wmac { + status = "okay"; + + mtd-cal-data = <&art 0x1000>; + mtd-mac-address = <&info 0x8>; +}; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/01_leds b/target/linux/ath79/generic/base-files/etc/board.d/01_leds index 8e3b5e17af..5521379cea 100755 --- a/target/linux/ath79/generic/base-files/etc/board.d/01_leds +++ b/target/linux/ath79/generic/base-files/etc/board.d/01_leds @@ -125,10 +125,6 @@ glinet,6408|\ glinet,6416) ucidef_set_led_netdev "lan" "LAN" "gl-inet:green:lan" "eth0" ;; -glinet,gl-ar150) - ucidef_set_led_netdev "wan" "WAN" "$boardname:green:wan" "eth1" - ucidef_set_led_switch "lan" "LAN" "$boardname:green:lan" "switch0" "0x02" - ;; glinet,gl-ar300m-lite) ucidef_set_led_netdev "lan" "LAN" "gl-ar300m-lite:green:lan" "eth0" ;; @@ -252,7 +248,8 @@ tplink,tl-wr902ac-v1) ;; tplink,re355-v1|\ tplink,re450-v1|\ -tplink,re450-v2) +tplink,re450-v2|\ +tplink,re450-v3) ucidef_set_led_netdev "lan_data" "LAN Data" "tp-link:green:lan_data" "eth0" "tx rx" ucidef_set_led_netdev "lan_link" "LAN Link" "tp-link:green:lan_link" "eth0" "link" ;; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index 6fe76817ff..1672f093a7 100755 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -43,6 +43,7 @@ ath79_setup_interfaces() tplink,re355-v1|\ tplink,re450-v1|\ tplink,re450-v2|\ + tplink,re450-v3|\ tplink,tl-wr902ac-v1|\ ubnt,bullet-m-ar7240|\ ubnt,bullet-m-ar7241|\ diff --git a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index 3ce95905b8..29815a1ada 100644 --- a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -118,7 +118,8 @@ case "$FIRMWARE" in caldata_extract "art" 0x5000 0x844 ath10k_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -2) ;; - tplink,re450-v2) + tplink,re450-v2|\ + tplink,re450-v3) caldata_extract "art" 0x5000 0x844 ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary info 0x8) +1) ;; diff --git a/target/linux/ath79/image/generic-tp-link.mk b/target/linux/ath79/image/generic-tp-link.mk index 3eedce4f8e..5fb36ca621 100644 --- a/target/linux/ath79/image/generic-tp-link.mk +++ b/target/linux/ath79/image/generic-tp-link.mk @@ -400,6 +400,18 @@ define Device/tplink_re450-v2 endef TARGET_DEVICES += tplink_re450-v2 +define Device/tplink_re450-v3 + $(Device/tplink-safeloader) + SOC := qca9563 + IMAGE_SIZE := 7808k + DEVICE_MODEL := RE450 + DEVICE_VARIANT := v3 + DEVICE_PACKAGES := kmod-ath10k-ct-smallbuffers ath10k-firmware-qca988x-ct + TPLINK_BOARD_ID := RE450-V3 + LOADER_TYPE := elf +endef +TARGET_DEVICES += tplink_re450-v3 + define Device/tplink_tl-mr6400-v1 $(Device/tplink-8mlzma) SOC := qca9531 diff --git a/target/linux/ath79/image/generic-ubnt.mk b/target/linux/ath79/image/generic-ubnt.mk index 577ae98624..480b3a5e68 100644 --- a/target/linux/ath79/image/generic-ubnt.mk +++ b/target/linux/ath79/image/generic-ubnt.mk @@ -28,7 +28,7 @@ endef # UBNT_BOARD e.g. one of (XS2, XS5, RS, XM) # UBNT_TYPE e.g. one of (BZ, XM, XW) # UBNT_CHIP e.g. one of (ar7240, ar933x, ar934x) -# UBNT_VERSION e.g. one of (6.0.0, 8.5.0) +# UBNT_VERSION e.g. one of (6.0.0, 8.5.3) define Device/ubnt DEVICE_VENDOR := Ubiquiti DEVICE_PACKAGES := kmod-usb2 @@ -66,7 +66,7 @@ define Device/ubnt-wa UBNT_BOARD := WA UBNT_CHIP := ar934x UBNT_TYPE := WA - UBNT_VERSION := 8.5.0 + UBNT_VERSION := 8.5.3 endef define Device/ubnt-xc @@ -75,7 +75,7 @@ define Device/ubnt-xc UBNT_BOARD := XC UBNT_CHIP := qca955x UBNT_TYPE := XC - UBNT_VERSION := 8.5.0 + UBNT_VERSION := 8.5.3 endef define Device/ubnt-xm diff --git a/target/linux/ath79/image/tiny-tp-link.mk b/target/linux/ath79/image/tiny-tp-link.mk index a5a76edd05..6e07d290f9 100644 --- a/target/linux/ath79/image/tiny-tp-link.mk +++ b/target/linux/ath79/image/tiny-tp-link.mk @@ -272,6 +272,30 @@ define Device/tplink_tl-wr743nd-v1 endef TARGET_DEVICES += tplink_tl-wr743nd-v1 +define Device/tplink_tl-wr802n-v1 + $(Device/tplink-4mlzma) + SOC := qca9533 + DEVICE_MODEL := TL-WR802N + DEVICE_VARIANT := v1 + TPLINK_HWID := 0x08020001 + SUPPORTED_DEVICES += tl-wr802n-v1 +endef +TARGET_DEVICES += tplink_tl-wr802n-v1 + +define Device/tplink_tl-wr802n-v2 + $(Device/tplink-4mlzma) + SOC := qca9533 + DEVICE_MODEL := TL-WR802N + DEVICE_VARIANT := v2 + TPLINK_HWID := 0x08020002 + TPLINK_HWREV := 2 + SUPPORTED_DEVICES += tl-wr802n-v2 + IMAGES += factory-us.bin factory-eu.bin + IMAGE/factory-us.bin := tplink-v1-image factory -C US + IMAGE/factory-eu.bin := tplink-v1-image factory -C EU +endef +TARGET_DEVICES += tplink_tl-wr802n-v2 + define Device/tplink_tl-wr841-v5 $(Device/tplink-4m) SOC := ar7240 diff --git a/target/linux/ath79/tiny/base-files/etc/board.d/02_network b/target/linux/ath79/tiny/base-files/etc/board.d/02_network index 5e559363b2..bff17bcce8 100755 --- a/target/linux/ath79/tiny/base-files/etc/board.d/02_network +++ b/target/linux/ath79/tiny/base-files/etc/board.d/02_network @@ -43,7 +43,9 @@ ath79_setup_interfaces() tplink,tl-wa901nd-v2|\ tplink,tl-wa901nd-v4|\ tplink,tl-wa901nd-v5|\ - tplink,tl-wr703n) + tplink,tl-wr703n|\ + tplink,tl-wr802n-v1|\ + tplink,tl-wr802n-v2) ucidef_set_interface_lan "eth0" ;; tplink,tl-mr3220-v1|\ diff --git a/target/linux/ath79/tiny/base-files/etc/uci-defaults/04_led_migration b/target/linux/ath79/tiny/base-files/etc/uci-defaults/04_led_migration new file mode 100644 index 0000000000..377135f530 --- /dev/null +++ b/target/linux/ath79/tiny/base-files/etc/uci-defaults/04_led_migration @@ -0,0 +1,18 @@ +. /lib/functions.sh +. /lib/functions/migrations.sh + +board=$(board_name) +boardonly="${board##*,}" + +case "$board" in +tplink,tl-wr802n-v1) + migrate_leds ":blue:=:green:" + ;; +tplink,tl-wr802n-v2) + migrate_leds "^$boardonly:=tp-link:" + ;; +esac + +migrations_apply system + +exit 0 diff --git a/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh b/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh index a957bf1149..22771278ce 100644 --- a/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh +++ b/target/linux/ipq806x/base-files/lib/upgrade/linksys.sh @@ -21,8 +21,6 @@ linksys_get_target_firmware() { "${cur_boot_part}" "${mtd_ubi0}" fi - cur_boot_part=$(/usr/sbin/fw_printenv -n boot_part) - case $cur_boot_part in 1) fw_setenv -s - <<-EOF diff --git a/tools/Makefile b/tools/Makefile index a3d27b5f5b..cddec94b7f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -34,7 +34,7 @@ tools-$(CONFIG_TARGET_mxs) += elftosb sdimage tools-$(CONFIG_TARGET_ar71xx) += lzma-old tools-$(CONFIG_TARGET_ar71xx)$(CONFIG_TARGET_ath79) += squashfs tools-$(CONFIG_USES_MINOR) += kernel2minor -tools-y += lzma squashfskit4 zip +tools-y += lzma squashfskit4 zip zstd tools-$(BUILD_B43_TOOLS) += b43-tools tools-$(BUILD_ISL) += isl tools-$(CONFIG_USE_SPARSE) += sparse diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c index 10178dc714..f0e777124c 100644 --- a/tools/firmware-utils/src/tplink-safeloader.c +++ b/tools/firmware-utils/src/tplink-safeloader.c @@ -1728,7 +1728,46 @@ static struct device_info boards[] = { {"user-config", 0x630000, 0x10000}, {"default-config", 0x640000, 0x10000}, {"radio", 0x7f0000, 0x10000}, + {NULL, 0, 0} + }, + .first_sysupgrade_partition = "os-image", + .last_sysupgrade_partition = "file-system" + }, + + /** Firmware layout for the RE450 v3 */ + { + .id = "RE450-V3", + .vendor = "", + .support_list = + "SupportList:\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:00000000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:55530000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:45550000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:4A500000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:43410000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:41550000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:41530000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:4B520000}\r\n" + "{product_name:RE450,product_ver:3.0.0,special_id:42520000}\r\n", + .support_trail = '\x00', + .soft_ver = NULL, + + /* We're using a dynamic kernel/rootfs split here */ + .partitions = { + {"fs-uboot", 0x00000, 0x20000}, + {"default-mac", 0x20000, 0x00020}, + {"pin", 0x20020, 0x00020}, + {"product-info", 0x21000, 0x01000}, + {"partition-table", 0x22000, 0x02000}, + {"soft-version", 0x24000, 0x01000}, + {"support-list", 0x25000, 0x01000}, + {"profile", 0x26000, 0x08000}, + {"user-config", 0x2e000, 0x10000}, + {"default-config", 0x3e000, 0x10000}, + {"config-info", 0x4e000, 0x00400}, + {"firmware", 0x50000, 0x7a0000}, + {"radio", 0x7f0000, 0x10000}, {NULL, 0, 0} }, diff --git a/tools/zstd/Makefile b/tools/zstd/Makefile new file mode 100644 index 0000000000..7459725e8e --- /dev/null +++ b/tools/zstd/Makefile @@ -0,0 +1,20 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=zstd +PKG_VERSION:=1.4.4 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=@GITHUB/facebook/zstd/releases/download/v$(PKG_VERSION) +PKG_HASH:=a364f5162c7d1a455cc915e8e3cf5f4bd8b75d09bc0f53965b0c9ca1383c52c8 + +PKG_LICENSE:=BSD-3-Clause +PKG_LICENSE_FILES:=LICENSE +PKG_CPE_ID:=cpe:/a:facebook:zstandard + +HOST_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/host-build.mk + +HOST_MAKE_FLAGS = PREFIX=$(HOST_BUILD_PREFIX) HAVE_ZLIB=0 HAVE_LZMA=0 HAVE_LZ4=0 + +$(eval $(call HostBuild)) diff --git a/tools/zstd/patches/0001-build-issue-More-portable-header-prefix-usage-1987.patch b/tools/zstd/patches/0001-build-issue-More-portable-header-prefix-usage-1987.patch new file mode 100644 index 0000000000..6d743aa385 --- /dev/null +++ b/tools/zstd/patches/0001-build-issue-More-portable-header-prefix-usage-1987.patch @@ -0,0 +1,61 @@ +From 06a57cf57e3c4e887cadcf688e3081154f3f6db4 Mon Sep 17 00:00:00 2001 +Message-Id: <06a57cf57e3c4e887cadcf688e3081154f3f6db4.1589392463.git.mschiffer@universe-factory.net> +From: Bimba Shrestha +Date: Thu, 6 Feb 2020 14:10:51 -0800 +Subject: [PATCH] [build-issue] More portable header prefix usage (#) (#1987) + +* make 4.3 build issue fix + +* Changing header name and adding comment +--- + programs/Makefile | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/programs/Makefile b/programs/Makefile +index b75314a83f43..a9ee3cb5311b 100644 +--- a/programs/Makefile ++++ b/programs/Makefile +@@ -94,9 +94,12 @@ endif + + VOID = /dev/null + ++# Make 4.3 doesn't support '\#' anymore (https://lwn.net/Articles/810071/) ++NUM_SYMBOL := \# ++ + # thread detection + NO_THREAD_MSG := ==> no threads, building without multithreading support +-HAVE_PTHREAD := $(shell printf '\#include \nint main(void) { return 0; }' > have_pthread.c && $(CC) $(FLAGS) -o have_pthread$(EXT) have_pthread.c -pthread 2> $(VOID) && rm have_pthread$(EXT) && echo 1 || echo 0; rm have_pthread.c) ++HAVE_PTHREAD := $(shell printf '$(NUM_SYMBOL)include \nint main(void) { return 0; }' > have_pthread.c && $(CC) $(FLAGS) -o have_pthread$(EXT) have_pthread.c -pthread 2> $(VOID) && rm have_pthread$(EXT) && echo 1 || echo 0; rm have_pthread.c) + HAVE_THREAD := $(shell [ "$(HAVE_PTHREAD)" -eq "1" -o -n "$(filter Windows%,$(OS))" ] && echo 1 || echo 0) + ifeq ($(HAVE_THREAD), 1) + THREAD_MSG := ==> building with threading support +@@ -108,7 +111,7 @@ endif + + # zlib detection + NO_ZLIB_MSG := ==> no zlib, building zstd without .gz support +-HAVE_ZLIB := $(shell printf '\#include \nint main(void) { return 0; }' > have_zlib.c && $(CC) $(FLAGS) -o have_zlib$(EXT) have_zlib.c -lz 2> $(VOID) && rm have_zlib$(EXT) && echo 1 || echo 0; rm have_zlib.c) ++HAVE_ZLIB := $(shell printf '$(NUM_SYMBOL)include \nint main(void) { return 0; }' > have_zlib.c && $(CC) $(FLAGS) -o have_zlib$(EXT) have_zlib.c -lz 2> $(VOID) && rm have_zlib$(EXT) && echo 1 || echo 0; rm have_zlib.c) + ifeq ($(HAVE_ZLIB), 1) + ZLIB_MSG := ==> building zstd with .gz compression support + ZLIBCPP = -DZSTD_GZCOMPRESS -DZSTD_GZDECOMPRESS +@@ -119,7 +122,7 @@ endif + + # lzma detection + NO_LZMA_MSG := ==> no liblzma, building zstd without .xz/.lzma support +-HAVE_LZMA := $(shell printf '\#include \nint main(void) { return 0; }' > have_lzma.c && $(CC) $(FLAGS) -o have_lzma$(EXT) have_lzma.c -llzma 2> $(VOID) && rm have_lzma$(EXT) && echo 1 || echo 0; rm have_lzma.c) ++HAVE_LZMA := $(shell printf '$(NUM_SYMBOL)include \nint main(void) { return 0; }' > have_lzma.c && $(CC) $(FLAGS) -o have_lzma$(EXT) have_lzma.c -llzma 2> $(VOID) && rm have_lzma$(EXT) && echo 1 || echo 0; rm have_lzma.c) + ifeq ($(HAVE_LZMA), 1) + LZMA_MSG := ==> building zstd with .xz/.lzma compression support + LZMACPP = -DZSTD_LZMACOMPRESS -DZSTD_LZMADECOMPRESS +@@ -130,7 +133,7 @@ endif + + # lz4 detection + NO_LZ4_MSG := ==> no liblz4, building zstd without .lz4 support +-HAVE_LZ4 := $(shell printf '\#include \n\#include \nint main(void) { return 0; }' > have_lz4.c && $(CC) $(FLAGS) -o have_lz4$(EXT) have_lz4.c -llz4 2> $(VOID) && rm have_lz4$(EXT) && echo 1 || echo 0; rm have_lz4.c) ++HAVE_LZ4 := $(shell printf '$(NUM_SYMBOL)include \n\#include \nint main(void) { return 0; }' > have_lz4.c && $(CC) $(FLAGS) -o have_lz4$(EXT) have_lz4.c -llz4 2> $(VOID) && rm have_lz4$(EXT) && echo 1 || echo 0; rm have_lz4.c) + ifeq ($(HAVE_LZ4), 1) + LZ4_MSG := ==> building zstd with .lz4 compression support + LZ4CPP = -DZSTD_LZ4COMPRESS -DZSTD_LZ4DECOMPRESS +-- +2.26.2 +