From f166cf9ca07ceb023db356532cf4154ef433322a Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Mon, 13 Apr 2020 03:24:28 +0500 Subject: [PATCH 01/14] dropbear: add ed25519 and chacha20-poly1305 - add Ed25519 support (backport): * DROPBEAR_ED25519 option for ssh-ed25519, * disabled by default - add Chacha20-Poly1305 support (backport): * DROPBEAR_CHACHA20POLY1305 for chacha20-poly1305@openssh.com, * enabled by default - update feature costs in binary size Signed-off-by: Vladislav Grishenko --- package/network/services/dropbear/Config.in | 20 +- package/network/services/dropbear/Makefile | 11 +- .../services/dropbear/files/dropbear.init | 2 +- .../020-backport-ed25519-support.patch | 2890 +++++++++++++++++ ...1-backport-chacha20-poly1305-support.patch | 693 ++++ 5 files changed, 3613 insertions(+), 3 deletions(-) create mode 100644 package/network/services/dropbear/patches/020-backport-ed25519-support.patch create mode 100644 package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch 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 + From 258dc0d0fd3aae47add9b7dca40848a92d03a4ea Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 13 May 2020 20:22:12 +0200 Subject: [PATCH 02/14] tools: add zstd Signed-off-by: Matthias Schiffer --- tools/Makefile | 2 +- tools/zstd/Makefile | 20 ++++++ ...re-portable-header-prefix-usage-1987.patch | 61 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tools/zstd/Makefile create mode 100644 tools/zstd/patches/0001-build-issue-More-portable-header-prefix-usage-1987.patch diff --git a/tools/Makefile b/tools/Makefile index aaaef95046..9bae09ece6 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -33,7 +33,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/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 + From 4696112ea28299a805ef7de5aff32451adfb2fc3 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 17 May 2020 13:18:10 +0200 Subject: [PATCH 03/14] build: add zstd support to pack/unpack functions Signed-off-by: Matthias Schiffer --- include/download.mk | 1 + include/unpack.mk | 4 ++++ 2 files changed, 5 insertions(+) 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/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 From 4bd7990488b0ca7b5cae16f0a9147a4146759053 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 13 May 2020 20:33:46 +0200 Subject: [PATCH 04/14] build: compress kernel debuginfo using zstd zstd with its default settings (compression level -3) compresses better than bzip2 -9 (which is the default setting), and is an order of magnitude faster. I made the following measurements for the most common compression tools (all standard Debian Buster versions, default flags unless noted otherwise), using the debug information of a large x86-64 kernel with ALL_KMODS: * kernel-debug.tar: 376M * kernel-debug.tar.gz: 101M, compressed in ~12s * kernel-debug.tar.bz2: 91M, compressed in ~15s * kernel-debug.tar.xz: 57M, compressed in ~101s * kernel-debug.tar.zst: 86M, compressed in ~1s With zstd, there is still some room for improvement by increasing the compression, but the slight increase in compression ratio (22.83% -> 19.46%) does not justify the significant increase in compression time (about 5 times on my machine) in my opinion. Note that multithreaded compression (-T argument) does not affect reproducibility with zstd. Signed-off-by: Matthias Schiffer --- include/kernel-build.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 479f1f2c92f6b7e75f945cfdb2214b609a92b692 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 12 May 2020 19:44:41 +0200 Subject: [PATCH 05/14] mt76: update to the latest version (adds 7663e, 7663u, 7915 drivers) 7aabfd0c9282 mt7615: add CONFIG_MT76_LEDS to cflags 10a5b7630a37 mt76: mt7615: fix getting maximum tx power from eeprom 8688ed70c987 mt76: mt7615: use module parameter option for offload firmware preference 04798aab1257 net: mt7603: remove duplicate error message 9636177117d8 mt76: mt7615: fix ssid configuration in mt7615_mcu_hw_scan d4ba139d8b8b mt76: mt7615: introduce mt7615_check_offload_capability routine 2cc0d54b65a1 mt76: mt7615: do not mark sched_scan disabled in mt7615_scan_work 5b73be962388 mt76: mt7615: add passive mode for hw scan 96e429e18174 mt76: mt7615: free pci_vector if mt7615_pci_probe fails 8fddbf6390ac mt76: mt7615: introduce support for hardware beacon filter f2c760177bdd mt76: mt7615: introduce mt7615_mcu_set_hif_suspend mcu command db454605106f mt76: mt7615: add WoW support 20b87321c39f mt76: mt7663u: introduce suspend/resume to mt7663u 20db7e73c586 mt76: mt7615: introduce PM support 523716bba561 mt76: mt7615: add gtk rekey offload support 50d377a825cc mt76: mt7615: introduce beacon_loss mcu event 4ef1957cea35 mt76: mt7663: read tx streams from eeprom f25a43cc53e7 mt76: mt7615: check return value of mt7615_eeprom_get_power_index 0a9f71652927 mt76: mt7615: fix ibss mode for mt7663 83f2ba3101b4 mt76: mt7663: fix target power parsing 3e6968593b61 mt76: mt7615: fix delta tx power for mt7663 c1d3ad194ae4 mt76: mt7663: introduce WoW with net detect support 891136ab99da mt76: mt7663: add support to sched scan with randomise addr 82e4d3ebe967 mt76: mt7615: scan all channels if not specified 690b84821cd3 mt76: avoid rx reorder buffer overflow f0117d3107b4 mt76: add support for HE RX rate reporting cc68782bab1a mt76: add Rx stats support for radiotap 3ec47f2fba61 mt76: adjust wcid size to support new 802.11ax generation 0a9f4173dd07 mt76: add HE phy modes and hardware queue c6b002bcdfa6 mt76: add mac80211 driver for MT7915 PCIe-based chipsets b96af5039581 mt76: mt7915: enable Rx HE rate reporting 230054096155 mt76: mt7915: implement HE per-rate tx power support c8f4b6cf1add mt76: mt7915: register per-phy HE capabilities for each interface de1e8af96e19 mt76: mt7915: add HE bss_conf support for interfaces 135a5085932b mt76: mt7915: add HE capabilities support for peers 3b5d908dae2f mt76: mt7915: add Rx radiotap header support 158253e2c11e mt76: mt7915: add .sta_add_debugfs support 7f40e8c2b98d mt76: mt7915: add .sta_statistics support a5368e5cad11 mt76: mt7915: set peer Tx fixed rate through debugfs 4f79c516be5c mt76: mt7915: add tsf related callbacks 509fceb43235 mt76: mt7915: enable firmware module debug support 56405976fc7b mt76: set runtime stream caps by mt76_phy 6bbf1a35c0da linux-firmware: add rebb firmware for mt7663 d7a10094c4e5 mt7663: add client offload firmware 9200732e8534 mt76: mt7663u: copy key pointer in mt7663u_mac_write_txwi 3aa810bde810 mt76: mt7663u: add missing register definitions e236ea5be344 mt76: mt7615: usb: cancel ps work stopping the vif 1d0903de2131 mt76: mt7915: introduce mt7915_get_he_phy_cap 095c72c81c74 mt76: mt7915: add Tx beamformer support 5f9e7664cd26 mt76: mt7915: add Tx beamformee support ac505404c385 mt76: mt7915: add TxBF capabilities 6656bebd39cd mt76: mt7915: add debugfs to track TxBF status 9590db025475 mt76: mt7915: allocate proper size for tlv tags 26eb1ed65987 mt76: mt7915: fix possible deadlock in mt7915_stop f85c1f3fc189 firmware: add mt7915 firmware 9b07251b00b0 mt76: mt7615: fix typo defining ps work 060e375a9244 mt76: fix per-driver wcid range checks after wcid array size bump 7270b56389a9 mt76: mt7615: do not report scan_complete twice to mac80211 8c9e4847d01e mt76: mt7615: reduce hw scan timeout 8bd88a1b1880 mt76: enable p2p support 1ea444d0e8e5 mt76: mt7615: configure bss info adding the interface fa81da5bb4e9 mt76: mt7615: introduce remain_on_channel support 44f2262c0289 mt76: mt76x02: remove check in mt76x02_mcu_msg_send 7005aa891440 mt76: mt7915: add spatial reuse support 1e3dc5b76649 mt76: mt7915: fix some sparse warnings 01b784174cd5 mt76: mt7915: fix sparse warnings: incorrect type initializer 40b7b5354a16 mt76: mt7615: fix NULL pointer deref in mt7615_register_ext_phy 6d731d188d31 mt76: mt7915: fix decoded radiotap HE flags b74d5b1c14cf mt76: mt7915: fix some sparse warnings 6679d35be5cc mt76: mt7615: switch to per-vif power_save support 01e870b44769 mt76: mt7915: fix a handful of spelling mistakes 7b2d16655904 mt76: mt7663: fix the usage WoW with net detect support ed3a244fb647 mt76: mt7915: Fix build error 5396a61cec99 mt76: mt7615: fix hw_scan with ssid_type for specified SSID only 466a5b4d041d mt76: mt7915: fix possible NULL pointer dereference in mt7915_register_ext_phy 984a172609c0 mt76: fix wcid allocation issues 6e02acddcb1a mt76: mt7615: add support for MT7611N 4e6f4e432d0d mt76: only iterate over initialized rx queues 9ad940fee593 mt76: mt7615: Use kmemdup in mt7615_queue_key_update() 85c516081338 mt76: mt7915: remove set but not used variable 'msta' Signed-off-by: Felix Fietkau --- package/kernel/mt76/Makefile | 97 ++++++++++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 10 deletions(-) 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)) From 705fe43522c756962589b360141d4c398363ce1c Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Sun, 31 May 2020 12:46:26 +0200 Subject: [PATCH 06/14] ath79: fix LEDs for GL.inet GL-AR150 Since the wireless LED was used for boot and set up with a DT trigger, the WiFi indication hasn't worked on ath79 at all. In addition, a look into the manual revealed that the OEM configuration is as follows: LED 1 (green): power LED 2 (green): configurable LED 3 (red): wireless So, let's just keep the WiFi trigger and convert the rest to its "intended" use. Signed-off-by: Adrian Schmutzler --- .../linux/ath79/dts/ar9330_glinet_gl-ar150.dts | 18 ++++++++++-------- .../generic/base-files/etc/board.d/01_leds | 4 ---- 2 files changed, 10 insertions(+), 12 deletions(-) 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/generic/base-files/etc/board.d/01_leds b/target/linux/ath79/generic/base-files/etc/board.d/01_leds index 8e3b5e17af..d4fdb423ab 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" ;; From 0f910a8c4c03d92e399dd79dbc5d707eb03b22df Mon Sep 17 00:00:00 2001 From: Samantha Collard Date: Sun, 31 May 2020 09:49:51 +1000 Subject: [PATCH 07/14] ipq806x: EA8500 fix boot partition detection Remove extraneous code that disabled boot partition detection. Fixes: b3770eaca39f ("mtd: base-files: Unify dual-firmware devices (Linksys)") Signed-off-by: Samantha Collard --- target/linux/ipq806x/base-files/lib/upgrade/linksys.sh | 2 -- 1 file changed, 2 deletions(-) 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 From 95caa3436d98dac3709e550765f3f86d11a99782 Mon Sep 17 00:00:00 2001 From: Roger Pueyo Centelles Date: Thu, 28 May 2020 11:44:54 +0200 Subject: [PATCH 08/14] ath79: update WA/XC devices UBNT_VERSION to 8.5.3 Ubiquiti WA devices with newer hw version 2011K require UBNT_VERSION to be at least 8.5.3, otherwise the image is rejected: New ver: WA.ar934x.v8.5.0-42.OpenWrt-r10947-65030d81f3 Versions: New(525568) 8.5.0, Required(525571) 8.5.3 Invalid version 'WA.ar934x.v8.5.0-42.OpenWrt-r10947-65030d81f3' For consistency, also increase version number for XC devices. Tested-by: Pedro Signed-off-by: Roger Pueyo Centelles --- target/linux/ath79/image/generic-ubnt.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 From f841e706403b1a111cbb6dc5930b7886307bf633 Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Fri, 29 May 2020 21:56:18 +0200 Subject: [PATCH 09/14] ar71xx: fix reset key for TP-Link TL-WR802N V1/V2 During porting support for this router to ath79 target it was discovered that GPIO mapping was incorrect (GPIO11 active high). Correct mapping for both V1 and V2 is GPIO12 active low. Default configuration from GPL source for V2 explicitly states this, and this was confirmed experimentally on ath79 by looking on /sys/kernel/debug/gpio. Correctness of this was also validated for V1 by cross-flashing vendor firmware for V1 on V2 hardware, in which reset button also worked. Fix it. Signed-off-by: Lech Perczak [slightly adjust commit title] Signed-off-by: Adrian Schmutzler --- target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr802n.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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, } }; From 7e513136c63108bf55b38be4d2b65aa00b0d2b26 Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Fri, 29 May 2020 20:50:05 +0200 Subject: [PATCH 10/14] ath79: add support for TP-Link TL-WR802N V1 and V2 Specification: - SoC: Qualcomm Atheros QCA9533 (560 MHz, MIPS 24Kc) - RAM: 32 MiB - Storage: 4 MiB of Flash on board - Wireless: Built into QCA9533 (Honey Bee), PHY modes b/g/n - Ethernet: 1x100M (port0) Installation through OEM Web Interface: - Connect to TL-WR802N by Ethernet or Wi-Fi - Go to web interface: [V1] http://192.168.0.1 [V2] http://192.168.0.254 Default user is "admin" & password is "admin". On V2, there is no DHCP server running by default, so remember to set IP manually. - Go to "System Tools -> Firmware Upgrade" - Browse for firmware: [V1] "*.factory.bin" [V2] "*.factory-us.bin" or "*.factory-eu.bin" for eu model Web interface may complain if filename is too long. In such case, rename .bin to something shorter. - Click upgrade Installation through tftp: Note: T_OUT, T_IN and GND on the board must be connected to USB TTL Serial Configuration 115200 8n1 - Boot the TL-WR802N - When "Autobooting in 1 seconds" appears type "tpl" followed by enter - Connect to the board Ethernet port (IPADDR: 192.168.1.1, ServerIP: 192.168.1.10) - tftpboot 0x80000000 - Record the result of "printenv bootcmd" - Enter "erase +0x3c0000" (e.g erase 0x9f020000 +0x3c0000) - Enter "cp.b 0x80000000 0x3c0000" (e.g cp.b 0x80000000 0x9f020000 0x3c0000) - Enter "bootm " (e.g bootm 0x9f020000) Notes: When porting from ar71xx target to ath79, I found out that on V2, reset button is on GPIO12 and active low, instead of GPIO11 and active high. By cross-flashing V1 firmware to V2, I confirmed the same is true for V1. Also according to manual of V1, this one also has green LED instead of blue - both of those issues were fixed accordingly. The MAC address assignment has been checked with OEM firmware. Installation manual based on ar71xx support by Thomas Roberts Signed-off-by: Lech Perczak [slightly adjust commit message, add MAC address comment] Signed-off-by: Adrian Schmutzler --- .../ath79/dts/qca9533_tplink_tl-wr802n-v1.dts | 9 ++ .../ath79/dts/qca9533_tplink_tl-wr802n-v2.dts | 9 ++ .../ath79/dts/qca9533_tplink_tl-wr802n.dtsi | 99 +++++++++++++++++++ target/linux/ath79/image/tiny-tp-link.mk | 24 +++++ .../tiny/base-files/etc/board.d/02_network | 4 +- .../etc/uci-defaults/04_led_migration | 18 ++++ 6 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v1.dts create mode 100644 target/linux/ath79/dts/qca9533_tplink_tl-wr802n-v2.dts create mode 100644 target/linux/ath79/dts/qca9533_tplink_tl-wr802n.dtsi create mode 100644 target/linux/ath79/tiny/base-files/etc/uci-defaults/04_led_migration 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/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 From c764c512ac18ce9724b3fb0e476831150817c162 Mon Sep 17 00:00:00 2001 From: Andreas Wiese Date: Wed, 27 May 2020 15:31:30 +0200 Subject: [PATCH 11/14] ath79: add support for TP-Link RE450 v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TP-Link RE450 v3 is a dual band router/range-extender based on Qualcomm/Atheros QCA9563 + QCA9880. This device is nearly identical to RE450 v2 besides a modified flash layout (hence I think force-flashing a RE450v2 image will lead to at least loss of MAC address). Specification: - 775 MHz CPU - 64 MB of RAM (DDR2) - 8 MB of FLASH (SPI NOR) - 3T3R 2.4 GHz - 3T3R 5 GHz - 1x 10/100/1000 Mbps Ethernet (AR8033 PHY) - 7x LED, 4x button- - possible UART header on PCB¹ Flash instruction: Apply factory image in OEM firmware web-gui. ¹ Didn't check to connect as I didn't even manage to connect on RE450v2 (AFAIU it requires disconnecting some resistors, which I was too much of a coward to do). But given the similarities to v2 I think it's the same or very similar procedure (and most likely also the only way to debrick). Signed-off-by: Andreas Wiese [remove dts-v1 and compatible in DTSI] Signed-off-by: Adrian Schmutzler --- .../ath79/dts/qca9563_tplink_re450-v2.dts | 203 +++--------------- .../ath79/dts/qca9563_tplink_re450-v3.dts | 53 +++++ .../linux/ath79/dts/qca9563_tplink_re450.dtsi | 154 +++++++++++++ .../generic/base-files/etc/board.d/01_leds | 3 +- .../generic/base-files/etc/board.d/02_network | 1 + .../etc/hotplug.d/firmware/11-ath10k-caldata | 3 +- target/linux/ath79/image/generic-tp-link.mk | 12 ++ tools/firmware-utils/src/tplink-safeloader.c | 39 ++++ 8 files changed, 291 insertions(+), 177 deletions(-) create mode 100644 target/linux/ath79/dts/qca9563_tplink_re450-v3.dts create mode 100644 target/linux/ath79/dts/qca9563_tplink_re450.dtsi 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..4e1195b647 --- /dev/null +++ b/target/linux/ath79/dts/qca9563_tplink_re450.dtsi @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include +#include + +#include "qca956x.dtsi" + +/ { + chosen { + bootargs = "console=ttyS0,115200n8"; + }; + + aliases { + 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 d4fdb423ab..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 @@ -248,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/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} }, From 91b1a625f4a85ba94317351a0f7cca765a0d7935 Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Sun, 31 May 2020 13:41:55 +0200 Subject: [PATCH 12/14] ath79: add label MAC address for TP-Link RE450 v2/v3 Signed-off-by: Adrian Schmutzler --- target/linux/ath79/dts/qca9563_tplink_re450.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/ath79/dts/qca9563_tplink_re450.dtsi b/target/linux/ath79/dts/qca9563_tplink_re450.dtsi index 4e1195b647..6c894a314e 100644 --- a/target/linux/ath79/dts/qca9563_tplink_re450.dtsi +++ b/target/linux/ath79/dts/qca9563_tplink_re450.dtsi @@ -11,6 +11,7 @@ }; aliases { + label-mac-device = ð0; led-boot = &led_power; led-failsafe = &led_power; led-running = &led_power; From b017a016cc0cd26f84a7e6b8de3dc02dc101e888 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sat, 30 May 2020 16:24:03 +0200 Subject: [PATCH 13/14] ar71xx: correct button type for TL-MR3020 mode slider The TP-Link TL-MR3020 has a three-state mode slider which was previously integrated as a button (EV_KEY). This led to spurious activations of failsafe mode. Set the type for the button to switch (EV_SW), to avoid unintended activations of failsafe mode. Related: commit 27f3f493de06 ("gpio-button-hotplug: unify polled and interrupt code") Signed-off-by: David Bauer --- target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3020.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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, From 8d2c031f21d48505a58807bcafae13f2f6cf628f Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Sun, 31 May 2020 20:28:06 +0200 Subject: [PATCH 14/14] ppp: update to version 2.4.8.git-2020-05-25 ddd57c2 pppd: Add lcp-echo-adaptive option c319558 pppd: Handle SIGINT and SIGTERM during interrupted syscalls (#148) 0bc11fb Added missing options to manual pages. (#149) b1fcf16 Merge branch 'monotonic-time' of https://github.com/themiron/ppp c78e312 pppd: linux: use monotonic time if possible Remove patch 121-debian_adaptive_lcp_echo as patch is upstream accepted Remove patch 206-compensate_time_change.patch as timewrap issues are solved by a patch making use of monotonic time Signed-off-by: Hans Dedecker --- package/network/services/ppp/Makefile | 6 +- .../ppp/patches/100-debian_ip-ip_option.patch | 2 +- .../ppp/patches/105-debian_demand.patch | 2 +- .../ppp/patches/110-debian_defaultroute.patch | 6 +- .../120-debian_ipv6_updown_option.patch | 2 +- .../121-debian_adaptive_lcp_echo.patch | 56 ----------- .../patches/206-compensate_time_change.patch | 94 ------------------- .../ppp/patches/208-fix_status_code.patch | 2 +- .../ppp/patches/401-no_record_file.patch | 2 +- .../404-remove_obsolete_protocol_names.patch | 16 ++-- ...openssl-for-the-DES-instead-of-the-l.patch | 2 +- 11 files changed, 20 insertions(+), 170 deletions(-) delete mode 100644 package/network/services/ppp/patches/121-debian_adaptive_lcp_echo.patch delete mode 100644 package/network/services/ppp/patches/206-compensate_time_change.patch diff --git a/package/network/services/ppp/Makefile b/package/network/services/ppp/Makefile index 2f6bf40eef..bc1eccacb6 100644 --- a/package/network/services/ppp/Makefile +++ b/package/network/services/ppp/Makefile @@ -13,9 +13,9 @@ PKG_RELEASE:=2 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