changeset 910:89555751c489 asm

merge up to 2013.63, improve ASM makefile rules a bit
author Matt Johnston <matt@ucc.asn.au>
date Thu, 27 Feb 2014 21:35:58 +0800
parents e4b75744acab (current diff) 4a74c58e11fc (diff)
children 367205a2c1c4
files Makefile.in common-algo.c crypto_desc.c crypto_desc.h random.c random.h
diffstat 93 files changed, 4752 insertions(+), 1563 deletions(-) [+]
line wrap: on
line diff
--- a/.hgsigs	Sun Oct 06 22:32:03 2013 +0800
+++ b/.hgsigs	Thu Feb 27 21:35:58 2014 +0800
@@ -5,3 +5,8 @@
 095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC
 f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6QCePVovn/avKXUyNwNBYCcov6JLYqkAnRCPQdkXgv20N3t10r6PRMBBo1/S
 deb211f75ca194e2fcf0d2e5f71c60474e42ec95 0 iEYEABECAAYFAlJO01cACgkQjPn4sExkf7yDqACaA/P+Yl/K2Cv3OC5G0b7ck2Kb75EAoIeW7qpCyclzJLWwk95koED+4lxD
+025237c9f0a1a60a616f984d82fb2a9270d3b0ea 0 iEYEABECAAYFAlJeqDYACgkQjPn4sExkf7y5nQCfW6t+TJySBTTo+gCfDUBPRVxvNe8AoIn/15aWfqH/A2G9uikfoVtWK3pd
+a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVqACg6IP0fU29+Feh/TDeemDA+2XAzrIAoIdZfMDvVYlDoWotZD8ACFnf5H1P
+9ec083a21adfcb099f21eb03704b66d14a4ba800 0 iEYEABECAAYFAlKE4JoACgkQjPn4sExkf7wLDgCghkVGwMjI138bEv+ORVzN7zIH7cEAoLckaxZc1k1aXlmlSCRlP8cuKH3o
+3d1d7d151c0ce3a79da62e86463f5632fa2b144a 0 iEYEABECAAYFAlKd5AEACgkQjPn4sExkf7wzWgCfdvPEEIdlMPqcbOQMJ7b+eAyy164An2ip1lPh1eS5g26/gSfruvWBVym4
+277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
--- a/.hgtags	Sun Oct 06 22:32:03 2013 +0800
+++ b/.hgtags	Thu Feb 27 21:35:58 2014 +0800
@@ -39,3 +39,7 @@
 96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57
 e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58
 7b68e581985fd4ea50869f8608ab95cda5d17876 DROPBEAR_2013.59
+a50a1dc743317fad9b3737bc68fbca640659bb6d DROPBEAR_2013.60
+e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
+3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62
+2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
--- a/CHANGES	Sun Oct 06 22:32:03 2013 +0800
+++ b/CHANGES	Thu Feb 27 21:35:58 2014 +0800
@@ -1,3 +1,89 @@
+2014.63 - Wednesday 19 February 2014
+
+- Fix ~. to terminate a client interactive session after waking a laptop
+  from sleep.
+
+- Changed port separator syntax again, now using host^port. This is because
+  IPv6 link-local addresses use %. Reported by Gui Iribarren
+
+- Avoid constantly relinking dropbearmulti target, fix "make install"
+  for multi target, thanks to Mike Frysinger
+
+- Avoid getting stuck in a loop writing huge key files, reported by Bruno
+  Thomsen
+
+- Don't link dropbearkey or dropbearconvert to libz or libutil, 
+  thanks to Nicolas Boos
+
+- Fix linking -lcrypt on systems without /usr/lib, thanks to Nicolas Boos
+
+- Avoid crash on exit due to cleaned up keys before last packets are sent,
+  debugged by Ronald Wahl
+
+- Fix a race condition in rekeying where Dropbear would exit if it received a
+  still-in-flight packet after initiating rekeying. Reported by Oliver Metz.
+  This is a longstanding bug but is triggered more easily since 2013.57
+
+- Fix README for ecdsa keys, from Catalin Patulea
+
+- Ensure that generated RSA keys are always exactly the length
+  requested. Previously Dropbear always generated N+16 or N+15 bit keys.
+  Thanks to Unit 193
+
+- Fix DROPBEAR_CLI_IMMEDIATE_AUTH mode which saves a network round trip if the
+  first public key succeeds. Still not enabled by default, needs more
+  compatibility testing with other implementations.
+
+- Fix for port 0 forwarding in the client and port forwarding with Apache MINA SSHD. Thanks to 
+
+- Fix for bad system linux/pkt-sched.h header file with older Linux
+kernels, from Steve Dover
+
+- Fix signal handlers so that errno is saved, thanks to Erik Ahlén for a patch
+  and Mark Wickham for independently spotting the same problem.
+
+2013.62 - Tuesday 3 December 2013
+
+- Disable "interactive" QoS connection options when a connection doesn't
+  have a PTY (eg scp, rsync). Thanks to Catalin Patulea for the patch.
+
+- Log when a hostkey is generated with -R, fix some bugs in handling server
+  hostkey commandline options
+
+- Fix crash in Dropbearconvert and 521 bit key, reported by NiLuJe
+
+- Update config.guess and config.sub again
+
+2013.61test - Thursday 14 November 2013
+
+- ECC (elliptic curve) support. Supports ECDSA hostkeys (requires new keys to
+  be generated) and ECDH for setting up encryption keys (no intervention
+  required). This is significantly faster.
+
+- [email protected] support for setting up encryption keys. This is
+  another elliptic curve mode with less potential of NSA interference in
+  algorithm parameters. curve25519-donna code thanks to Adam Langley
+
+- -R option to automatically generate hostkeys. This is recommended for
+  embedded platforms since it allows the system random number device
+  /dev/urandom a longer startup time to generate a secure seed before the
+  hostkey is required.
+
+- Compile fixes for old vendor compilers like Tru64 from Daniel Richard G.
+
+- Make authorized_keys handling more robust, don't exit encountering
+  malformed lines. Thanks to Lorin Hochstein and Mark Stillwell 
+
+2013.60 - Wednesday 16 October 2013
+
+- Fix "make install" so that it doesn't always install to /bin and /sbin
+
+- Fix "make install MULTI=1", installing manpages failed
+
+- Fix "make install" when scp is included since it has no manpage
+
+- Make --disable-bundled-libtom work
+
 2013.59 - Friday 4 October 2013
 
 - Fix crash from -J command 
@@ -14,10 +100,10 @@
 
 - Limit the size of decompressed payloads, avoids memory exhaustion denial
   of service 
-  Thanks to Logan Lamb for reporting and investigating it
+  Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
 
 - Avoid disclosing existence of valid users through inconsistent delays
-  Thanks to Logan Lamb for reporting
+  Thanks to Logan Lamb for reporting. CVE-2013-4434
 
 - Update config.guess and config.sub for newer architectures
 
@@ -318,7 +404,7 @@
 
 - Security: dbclient previously would prompt to confirm a 
   mismatching hostkey but wouldn't warn loudly. It will now
-  exit upon a mismatch.
+  exit upon a mismatch. CVE-2007-1099
 
 - Compile fixes, make sure that all variable definitions are at the start
   of a scope.
@@ -380,7 +466,7 @@
   (thanks to Tomas Vanek for helping track it down)
 
 - Implement per-IP pre-authentication connection limits 
-  (after some poking from Pablo Fernandez)
+  (after some poking from Pablo Fernandez) CVE-2006-1206
 
 - Exit gracefully if trying to connect to as SSH v1 server 
   (reported by Rushi Lala)
@@ -401,7 +487,7 @@
 - SECURITY: fix for buffer allocation error in server code, could potentially
   allow authenticated users to gain elevated privileges. All multi-user systems
   running the server should upgrade (or apply the patch available on the
-  Dropbear webpage).
+  Dropbear webpage). CVE-2005-4178
 
 - Fix channel handling code so that redirecting to /dev/null doesn't use
   100% CPU.
@@ -608,7 +694,7 @@
 - SECURITY: Don't try to free() uninitialised variables in DSS verification
   code. Thanks to Arne Bernin for pointing out this bug. This is possibly
   exploitable, all users with DSS and pubkey-auth compiled in are advised to
-  upgrade.
+  upgrade. CVE-2004-2486
 
 - Clean up agent forwarding socket files correctly, patch from Gerrit Pape.
 
--- a/LICENSE	Sun Oct 06 22:32:03 2013 +0800
+++ b/LICENSE	Thu Feb 27 21:35:58 2014 +0800
@@ -87,3 +87,55 @@
 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.
+
+=====
+
+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 <[email protected]>
+ *
+ * Derived from public domain C code by Daniel J. Bernstein <[email protected]>
+ *
+ * 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.
+ */
--- a/MULTI	Sun Oct 06 22:32:03 2013 +0800
+++ b/MULTI	Thu Feb 27 21:35:58 2014 +0800
@@ -20,7 +20,3 @@
 then execute as normal:
 
 ./dropbear <options here>
-
-"make install" doesn't currently work for multi-binary configuration, though
-in most situations where it is being used, the target and build systems will
-differ.
--- a/Makefile.in	Sun Oct 06 22:32:03 2013 +0800
+++ b/Makefile.in	Thu Feb 27 21:35:58 2014 +0800
@@ -13,20 +13,32 @@
 	PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
 endif
 
-LTC=libtomcrypt/libtomcrypt.a
-LTM=libtommath/libtommath.a
+STATIC_LTC=libtomcrypt/libtomcrypt.a
+STATIC_LTM=libtommath/libtommath.a
+
+LIBTOM_LIBS=@LIBTOM_LIBS@
 
 ifeq (@BUNDLED_LIBTOM@, 1)
-LIBTOM_DEPS=$(LTC) $(LTM)
-CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/ 
-LIBS+=$(LTC) $(LTM)
+LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM) 
+LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM) 
+CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
+endif
+
+ifeq (@ASM_ARCH@, arm)
+ASM_OBJS=aes-arm.o sha1-arm.o aes-asm-ltc.o sha1-asm-ltc.o
+LIBTOM_DEPS += $(ASM_OBJS)
+LIBTOM_LIBS += $(ASM_OBJS)
+CFLAGS+=-DDROPBEAR_SHA1_ASM
+CFLAGS+=-DDROPBEAR_AES_ASM
 endif
 
 COMMONOBJS=dbutil.o buffer.o \
 		dss.o bignum.o \
-		signkey.o rsa.o random.o \
+		signkey.o rsa.o dbrandom.o \
 		queue.o \
-		atomicio.o compat.o  fake-rfc2553.o 
+		atomicio.o compat.o fake-rfc2553.o \
+		ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
+		gensignkey.o gendss.o genrsa.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 \
@@ -41,22 +53,22 @@
 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 \
-			common-runopts.o circbuffer.o aes-arm.o
+			common-runopts.o circbuffer.o curve25519-donna.o
 
-KEYOBJS=dropbearkey.o gendss.o genrsa.o
+KEYOBJS=dropbearkey.o
 
 CONVERTOBJS=dropbearconvert.o keyimport.o
 
 SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
 
 HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
-		dss.h bignum.h signkey.h rsa.h random.h service.h auth.h \
+		dss.h bignum.h signkey.h rsa.h dbrandom.h service.h auth.h \
 		debug.h channel.h chansession.h config.h queue.h sshpty.h \
 		termcodes.h gendss.h genrsa.h runopts.h includes.h \
 		loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
-		listener.h fake-rfc2553.h
+		listener.h fake-rfc2553.h ecc.h ecdsa.h
 
-dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@ 
+dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
 dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
 dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
 dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
@@ -66,6 +78,7 @@
 srcdir=@srcdir@
 
 prefix=@prefix@
+exec_prefix=@exec_prefix@
 datarootdir = @datarootdir@
 bindir=@bindir@
 sbindir=@sbindir@
@@ -121,34 +134,34 @@
 
 install: $(addprefix inst_, $(TARGETS))
 
-installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS)) 
-
-insdbmulti: dropbearmulti
-	$(INSTALL) -d $(DESTDIR)$(bindir)
-	$(INSTALL) dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)
-
 insmultidropbear: dropbearmulti
 	$(INSTALL) -d $(DESTDIR)$(sbindir)
 	-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
 	-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT) 
+	$(INSTALL) -d $(DESTDIR)$(mandir)/man8
+	$(INSTALL) -m 644 dropbear.8  $(DESTDIR)$(mandir)/man8/dropbear.8
 
 insmulti%: dropbearmulti
 	$(INSTALL) -d $(DESTDIR)$(bindir)
 	-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT) 
 	-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT) 
+	$(INSTALL) -d $(DESTDIR)$(mandir)/man1
+	if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
 
 # dropbear should go in sbin, so it needs a seperate rule
 inst_dropbear: dropbear
 	$(INSTALL) -d $(DESTDIR)$(sbindir)
 	$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
 	$(INSTALL) -d $(DESTDIR)$(mandir)/man8
-	$(INSTALL) -m 644 dropbear.8  $(DESTDIR)$(mandir)/man8/dropbear.8
+	$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
 
 inst_%: $*
 	$(INSTALL) -d $(DESTDIR)$(bindir)
 	$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
 	$(INSTALL) -d $(DESTDIR)$(mandir)/man1
-	$(INSTALL) -m 644 $*.1  $(DESTDIR)$(mandir)/man1/$*.1
+	if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
+
+inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS)) 
 
 
 # for some reason the rule further down doesn't like $($@objs) as a prereq.
@@ -157,8 +170,14 @@
 dropbearkey: $(dropbearkeyobjs)
 dropbearconvert: $(dropbearconvertobjs)
 
-dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
-	$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
+dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
+	$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
+
+dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
+	$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
+
+dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
+	$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS)
 
 # scp doesn't use the libs so is special.
 scp: $(SCPOBJS)  $(HEADERS) Makefile
@@ -168,14 +187,14 @@
 # multi-binary compilation.
 MULTIOBJS=
 ifeq ($(MULTI),1)
-	MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@ 
+	MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
 	CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
 endif
 
-dropbearmulti: multilink 
+dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
+	$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
 
-multibinary: $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
-	$(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
+multibinary: dropbearmulti$(EXEEXT)
 
 multilink: multibinary $(addprefix link, $(PROGRAMS))
 
@@ -183,10 +202,10 @@
 	-rm -f $*$(EXEEXT)
 	-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
 
-$(LTC): options.h
-	cd libtomcrypt && $(MAKE) clean && $(MAKE)
+$(STATIC_LTC): options.h
+	cd libtomcrypt && $(MAKE)
 
-$(LTM): options.h
+$(STATIC_LTM): options.h
 	cd libtommath && $(MAKE)
 
 .PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
--- a/README	Sun Oct 06 22:32:03 2013 +0800
+++ b/README	Thu Feb 27 21:35:58 2014 +0800
@@ -42,8 +42,7 @@
 dropbearconvert openssh dropbear ~/.ssh/id_rsa  ~/.ssh/id_rsa.db
 dbclient -i ~/.ssh/id_rsa.db <hostname>
 
-Currently encrypted keys aren't supported, neither is agent forwarding. At some
-stage both hopefully will be.
+Dropbear does not support encrypted hostkeys though can connect to ssh-agent.
 
 ============================================================================
 
@@ -52,13 +51,18 @@
 
 ============================================================================
 
-To run the server, you need to generate server keys, this is one-off:
+To run the server, you need to 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
 
 or alternatively convert OpenSSH keys to Dropbear:
 ./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
 
+You can also get Dropbear to create keys when the first connection is made -
+this is preferable to generating keys when the system boots. Make sure 
+/etc/dropbear/ exists and then pass '-R' to the dropbear server.
+
 ============================================================================
 
 If the server is run as non-root, you most likely won't be able to allocate a
--- a/agentfwd.h	Sun Oct 06 22:32:03 2013 +0800
+++ b/agentfwd.h	Thu Feb 27 21:35:58 2014 +0800
@@ -40,7 +40,7 @@
 /* client functions */
 void cli_load_agent_keys(m_list * ret_list);
 void agent_buf_sign(buffer *sigblob, sign_key *key, 
-    const unsigned char *data, unsigned int len);
+	buffer *data_buf);
 void cli_setup_agent(struct Channel *channel);
 
 #ifdef __hpux
--- a/algo.h	Sun Oct 06 22:32:03 2013 +0800
+++ b/algo.h	Thu Feb 27 21:35:58 2014 +0800
@@ -35,7 +35,7 @@
 
 struct Algo_Type {
 
-	unsigned char *name; /* identifying name */
+	const unsigned char *name; /* identifying name */
 	char val; /* a value for this cipher, or -1 for invalid */
 	const void *data; /* algorithm specific data */
 	char usable; /* whether we can use this algorithm */
@@ -59,8 +59,8 @@
 
 struct dropbear_cipher {
 	const struct ltc_cipher_descriptor *cipherdesc;
-	unsigned long keysize;
-	unsigned char blocksize;
+	const unsigned long keysize;
+	const unsigned char blocksize;
 };
 
 struct dropbear_cipher_mode {
@@ -74,12 +74,37 @@
 };
 
 struct dropbear_hash {
-	const struct ltc_hash_descriptor *hashdesc;
-	unsigned long keysize;
-	unsigned char hashsize;
+	const struct ltc_hash_descriptor *hash_desc;
+	const unsigned long keysize;
+	/* hashsize may be truncated from the size returned by hash_desc,
+	   eg sha1-96 */
+	const unsigned char hashsize;
+};
+
+enum dropbear_kex_mode {
+	DROPBEAR_KEX_NORMAL_DH,
+	DROPBEAR_KEX_ECDH,
+	DROPBEAR_KEX_CURVE25519,
 };
 
-void crypto_init();
+struct dropbear_kex {
+	enum dropbear_kex_mode mode;
+	
+	/* "normal" DH KEX */
+	const unsigned char *dh_p_bytes;
+	const int dh_p_len;
+
+	/* elliptic curve DH KEX */
+#ifdef DROPBEAR_ECDH
+	const struct dropbear_ecc_curve *ecc_curve;
+#else
+	const void* dummy;
+#endif
+
+	/* both */
+	const struct ltc_hash_descriptor *hash_desc;
+};
+
 int have_algo(char* algo, size_t algolen, algo_type algos[]);
 void buf_put_algolist(buffer * buf, algo_type localalgos[]);
 
@@ -102,5 +127,10 @@
 char * algolist_string(algo_type algos[]);
 #endif
 
+enum {
+	DROPBEAR_COMP_NONE,
+	DROPBEAR_COMP_ZLIB,
+	DROPBEAR_COMP_ZLIB_DELAY,
+};
 
 #endif /* _ALGO_H_ */
--- a/bignum.c	Sun Oct 06 22:32:03 2013 +0800
+++ b/bignum.c	Thu Feb 27 21:35:58 2014 +0800
@@ -52,6 +52,22 @@
     va_end(args);
 }
 
+void m_mp_alloc_init_multi(mp_int **mp, ...) 
+{
+    mp_int** cur_arg = mp;
+    va_list args;
+
+    va_start(args, mp);        /* init args to next argument from caller */
+    while (cur_arg != NULL) {
+    	*cur_arg = m_malloc(sizeof(mp_int));
+        if (mp_init(*cur_arg) != MP_OKAY) {
+			dropbear_exit("Mem alloc error");
+        }
+        cur_arg = va_arg(args, mp_int**);
+    }
+    va_end(args);
+}
+
 void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
 
 	if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
@@ -60,16 +76,13 @@
 }
 
 /* hash the ssh representation of the mp_int mp */
-void sha1_process_mp(hash_state *hs, mp_int *mp) {
-
-	int i;
+void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, 
+				hash_state *hs, mp_int *mp) {
 	buffer * buf;
 
 	buf = buf_new(512 + 20); /* max buffer is a 4096 bit key, 
 								plus header + some leeway*/
 	buf_putmpint(buf, mp);
-	i = buf->pos;
-	buf_setpos(buf, 0);
-	sha1_process(hs, buf_getptr(buf, i), i);
+	hash_desc->process(hs, buf->data, buf->len);
 	buf_free(buf);
 }
--- a/bignum.h	Sun Oct 06 22:32:03 2013 +0800
+++ b/bignum.h	Thu Feb 27 21:35:58 2014 +0800
@@ -30,7 +30,9 @@
 
 void m_mp_init(mp_int *mp);
 void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
+void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
 void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
-void sha1_process_mp(hash_state *hs, mp_int *mp);
+void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, 
+				hash_state *hs, mp_int *mp);
 
 #endif /* _BIGNUM_H_ */
--- a/buffer.c	Sun Oct 06 22:32:03 2013 +0800
+++ b/buffer.c	Thu Feb 27 21:35:58 2014 +0800
@@ -269,6 +269,11 @@
 
 }
 
+/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
+void buf_putbufstring(buffer *buf, const buffer* buf_str) {
+	buf_putstring(buf, buf_str->data, buf_str->len);
+}
+
 /* put the set of len bytes into the buffer, incrementing the pos, increasing
  * len if required */
 void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
--- a/buffer.h	Sun Oct 06 22:32:03 2013 +0800
+++ b/buffer.h	Thu Feb 27 21:35:58 2014 +0800
@@ -59,6 +59,7 @@
 void buf_eatstring(buffer *buf);
 void buf_putint(buffer* buf, unsigned int val);
 void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
+void buf_putbufstring(buffer *buf, const buffer* buf_str);
 void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
 void buf_putmpint(buffer* buf, mp_int * mp);
 int buf_getmpint(buffer* buf, mp_int* mp);
--- a/cli-agentfwd.c	Sun Oct 06 22:32:03 2013 +0800
+++ b/cli-agentfwd.c	Thu Feb 27 21:35:58 2014 +0800
@@ -34,7 +34,7 @@
 #include "channel.h"
 #include "packet.h"
 #include "buffer.h"
-#include "random.h"
+#include "dbrandom.h"
 #include "listener.h"
 #include "runopts.h"
 #include "atomicio.h"
@@ -73,8 +73,8 @@
 	return fd;
 }
 
-// handle a request for a connection to the locally running ssh-agent
-// or forward.
+/* handle a request for a connection to the locally running ssh-agent
+   or forward. */
 static int new_agent_chan(struct Channel * channel) {
 
 	int fd = -1;
@@ -94,7 +94,6 @@
 	channel->readfd = fd;
 	channel->writefd = fd;
 
-	// success
 	return 0;
 }
 
@@ -202,7 +201,7 @@
 	num = buf_getint(inbuf);
 	for (i = 0; i < num; i++) {
 		sign_key * pubkey = NULL;
-		int key_type = DROPBEAR_SIGNKEY_ANY;
+		enum signkey_type key_type = DROPBEAR_SIGNKEY_ANY;
 		buffer * key_buf;
 
 		/* each public key is encoded as a string */
@@ -254,7 +253,7 @@
 }
 
 void agent_buf_sign(buffer *sigblob, sign_key *key, 
-		const unsigned char *data, unsigned int len) {
+		buffer *data_buf) {
 	buffer *request_data = NULL;
 	buffer *response = NULL;
 	unsigned int siglen;
@@ -266,10 +265,10 @@
 	string			data
 	uint32			flags
 	*/
-	request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
+	request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
 	buf_put_pub_key(request_data, key, key->type);
 	
-	buf_putstring(request_data, data, len);
+	buf_putbufstring(request_data, data_buf);
 	buf_putint(request_data, 0);
 	
 	response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
--- a/cli-auth.c	Sun Oct 06 22:32:03 2013 +0800
+++ b/cli-auth.c	Thu Feb 27 21:35:58 2014 +0800
@@ -41,16 +41,6 @@
 /* Send a "none" auth request to get available methods */
 void cli_auth_getmethods() {
 	TRACE(("enter cli_auth_getmethods"))
-#ifdef CLI_IMMEDIATE_AUTH
-	ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
-    if (getenv(DROPBEAR_PASSWORD_ENV)) {
-		ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
-	}
-	if (cli_auth_try() == DROPBEAR_SUCCESS) {
-		TRACE(("skipped initial none auth query"))
-		return;
-	}
-#endif
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
 	buf_putstring(ses.writepayload, cli_opts.username, 
@@ -60,6 +50,26 @@
 	buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
 
 	encrypt_packet();
+
+#ifdef DROPBEAR_CLI_IMMEDIATE_AUTH
+	/* We can't haven't two auth requests in-flight with delayed zlib mode
+	since if the first one succeeds then the remote side will 
+	expect the second one to be compressed. 
+	Race described at
+	http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/zlib-openssh.html
+	*/
+	if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) {
+		ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
+		if (getenv(DROPBEAR_PASSWORD_ENV)) {
+			ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
+		}
+		if (cli_auth_try() == DROPBEAR_SUCCESS) {
+			TRACE(("skipped initial none auth query"))
+			/* Note that there will be two auth responses in-flight */
+			cli_ses.ignore_next_auth_response = 1;
+		}
+	}
+#endif
 	TRACE(("leave cli_auth_getmethods"))
 }
 
@@ -150,31 +160,46 @@
 	TRACE(("<- MSG_USERAUTH_FAILURE"))
 	TRACE(("enter recv_msg_userauth_failure"))
 
+	if (ses.authstate.authdone) {
+		TRACE(("leave recv_msg_userauth_failure, already authdone."))
+		return;
+	}
+
 	if (cli_ses.state != USERAUTH_REQ_SENT) {
 		/* Perhaps we should be more fatal? */
 		dropbear_exit("Unexpected userauth failure");
 	}
 
+	/* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for 
+	the "none" auth request, and then a response to the immediate auth request. 
+	We need to be careful handling them. */
+	if (cli_ses.ignore_next_auth_response) {
+		TRACE(("ignore next response, state set to USERAUTH_REQ_SENT"))
+		cli_ses.state = USERAUTH_REQ_SENT;
+	} else  {
+		cli_ses.state = USERAUTH_FAIL_RCVD;
+		cli_ses.lastauthtype = AUTH_TYPE_NONE;
 #ifdef ENABLE_CLI_PUBKEY_AUTH
-	/* If it was a pubkey auth request, we should cross that key 
-	 * off the list. */
-	if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
-		cli_pubkeyfail();
-	}
+		/* If it was a pubkey auth request, we should cross that key 
+		 * off the list. */
+		if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
+			cli_pubkeyfail();
+		}
 #endif
 
 #ifdef ENABLE_CLI_INTERACT_AUTH
-	/* If we get a failure message for keyboard interactive without
-	 * receiving any request info packet, then we don't bother trying
-	 * keyboard interactive again */
-	if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
-			&& !cli_ses.interact_request_received) {
-		TRACE(("setting auth_interact_failed = 1"))
-		cli_ses.auth_interact_failed = 1;
+		/* If we get a failure message for keyboard interactive without
+		 * receiving any request info packet, then we don't bother trying
+		 * keyboard interactive again */
+		if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
+				&& !cli_ses.interact_request_received) {
+			TRACE(("setting auth_interact_failed = 1"))
+			cli_ses.auth_interact_failed = 1;
+		}
+#endif
 	}
-#endif
 
-	cli_ses.lastauthtype = AUTH_TYPE_NONE;
+	cli_ses.ignore_next_auth_response = 0;
 
 	methods = buf_getstring(ses.payload, &methlen);
 
@@ -227,13 +252,14 @@
 	}
 
 	m_free(methods);
-
-	cli_ses.state = USERAUTH_FAIL_RCVD;
 		
 	TRACE(("leave recv_msg_userauth_failure"))
 }
 
 void recv_msg_userauth_success() {
+	/* This function can validly get called multiple times
+	if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
+
 	TRACE(("received msg_userauth_success"))
 	/* Note: in delayed-zlib mode, setting authdone here 
 	 * will enable compression in the transport layer */
--- a/cli-authpubkey.c	Sun Oct 06 22:32:03 2013 +0800
+++ b/cli-authpubkey.c	Thu Feb 27 21:35:58 2014 +0800
@@ -121,23 +121,19 @@
 }
 
 void cli_buf_put_sign(buffer* buf, sign_key *key, int type, 
-			const unsigned char *data, unsigned int len)
-{
+			buffer *data_buf) {
 #ifdef ENABLE_CLI_AGENTFWD
 	if (key->source == SIGNKEY_SOURCE_AGENT) {
 		/* Format the agent signature ourselves, as buf_put_sign would. */
 		buffer *sigblob;
 		sigblob = buf_new(MAX_PUBKEY_SIZE);
-		agent_buf_sign(sigblob, key, data, len);
-		buf_setpos(sigblob, 0);
-		buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
-				sigblob->len);
-
+		agent_buf_sign(sigblob, key, data_buf);
+		buf_putbufstring(buf, sigblob);
 		buf_free(sigblob);
 	} else 
 #endif /* ENABLE_CLI_AGENTFWD */
 	{
-		buf_put_sign(buf, key, type, data, len);
+		buf_put_sign(buf, key, type, data_buf);
 	}
 }
 
@@ -173,10 +169,10 @@
 		TRACE(("realsign"))
 		/* We put the signature as well - this contains string(session id), then
 		 * the contents of the write payload to this point */
-		sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
-		buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
+		sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
+		buf_putbufstring(sigbuf, ses.session_id);
 		buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
-		cli_buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
+		cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
 		buf_free(sigbuf); /* Nothing confidential in the buffer */
 	}
 
--- a/cli-chansession.c	Sun Oct 06 22:32:03 2013 +0800
+++ b/cli-chansession.c	Thu Feb 27 21:35:58 2014 +0800
@@ -369,6 +369,8 @@
 
 	if (cli_opts.wantpty) {
 		send_chansess_pty_req(channel);
+	} else {
+		set_sock_priority(ses.sock_out, DROPBEAR_PRIO_BULK);
 	}
 
 	send_chansess_shell_req(channel);
@@ -398,6 +400,7 @@
 	const unsigned char* source_host = "127.0.0.1";
 	const int source_port = 22;
 
+	TRACE(("enter cli_send_netcat_request"))
 	cli_opts.wantpty = 0;
 
 	if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat) 
@@ -414,7 +417,7 @@
 	buf_putint(ses.writepayload, source_port);
 
 	encrypt_packet();
-	TRACE(("leave cli_send_chansess_request"))
+	TRACE(("leave cli_send_netcat_request"))
 }
 #endif
 
@@ -433,7 +436,7 @@
 
 }
 
-// returns 1 if the character should be consumed, 0 to pass through
+/* returns 1 if the character should be consumed, 0 to pass through */
 static int
 do_escape(unsigned char c) {
 	switch (c) {
@@ -442,10 +445,10 @@
 			return 1;
 			break;
 		case 0x1a:
-			// ctrl-z
+			/* ctrl-z */
 			cli_tty_cleanup();
 			kill(getpid(), SIGTSTP);
-			// after continuation
+			/* after continuation */
 			cli_tty_setup();
 			cli_ses.winchange = 1;
 			return 1;
@@ -455,12 +458,12 @@
 }
 
 static
-void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len) {
+void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) {
 	char c;
 	int skip_char = 0;
 
-	// only handle escape characters if they are read one at a time. simplifies
-	// the code and avoids nasty people putting ~. at the start of a line to paste 
+	/* only handle escape characters if they are read one at a time. simplifies 
+	   the code and avoids nasty people putting ~. at the start of a line to paste  */
 	if (*len != 1) {
 		cli_ses.last_char = 0x0;
 		return;
--- a/cli-kex.c	Sun Oct 06 22:32:03 2013 +0800
+++ b/cli-kex.c	Thu Feb 27 21:35:58 2014 +0800
@@ -33,9 +33,10 @@
 #include "ssh.h"
 #include "packet.h"
 #include "bignum.h"
-#include "random.h"
+#include "dbrandom.h"
 #include "runopts.h"
 #include "signkey.h"
+#include "ecc.h"
 
 
 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
@@ -43,43 +44,62 @@
 
 void send_msg_kexdh_init() {
 	TRACE(("send_msg_kexdh_init()"))	
-	if ((cli_ses.dh_e && cli_ses.dh_x 
-				&& cli_ses.dh_val_algo == ses.newkeys->algo_kex)) {
-		TRACE(("reusing existing dh_e from first_kex_packet_follows"))
-	} else {
-		if (!cli_ses.dh_e || !cli_ses.dh_e) {
-			cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
-			cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
-			m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
-		}
-
-		gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
-		cli_ses.dh_val_algo = ses.newkeys->algo_kex;
-	}
 
 	CHECKCLEARTOWRITE();
 	buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
-	buf_putmpint(ses.writepayload, cli_ses.dh_e);
+	switch (ses.newkeys->algo_kex->mode) {
+		case DROPBEAR_KEX_NORMAL_DH:
+			if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
+				|| !cli_ses.dh_param) {
+				if (cli_ses.dh_param) {
+					free_kexdh_param(cli_ses.dh_param);
+				}
+				cli_ses.dh_param = gen_kexdh_param();
+			}
+			buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
+			break;
+		case DROPBEAR_KEX_ECDH:
+#ifdef DROPBEAR_ECDH
+			if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
+				|| !cli_ses.ecdh_param) {
+				if (cli_ses.ecdh_param) {
+					free_kexecdh_param(cli_ses.ecdh_param);
+				}
+				cli_ses.ecdh_param = gen_kexecdh_param();
+			}
+			buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
+#endif
+			break;
+#ifdef DROPBEAR_CURVE25519
+		case DROPBEAR_KEX_CURVE25519:
+			if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
+				|| !cli_ses.curve25519_param) {
+				if (cli_ses.curve25519_param) {
+					free_kexcurve25519_param(cli_ses.curve25519_param);
+				}
+				cli_ses.curve25519_param = gen_kexcurve25519_param();
+			}
+			buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
+#endif
+			break;
+	}
+
+	cli_ses.param_kex_algo = ses.newkeys->algo_kex;
 	encrypt_packet();
-	ses.requirenext[0] = SSH_MSG_KEXDH_REPLY;
-	ses.requirenext[1] = SSH_MSG_KEXINIT;
 }
 
 /* Handle a diffie-hellman key exchange reply. */
 void recv_msg_kexdh_reply() {
 
-	DEF_MP_INT(dh_f);
 	sign_key *hostkey = NULL;
 	unsigned int type, keybloblen;
 	unsigned char* keyblob = NULL;
 
-
 	TRACE(("enter recv_msg_kexdh_reply"))
 
 	if (cli_ses.kex_state != KEXDH_INIT_SENT) {
 		dropbear_exit("Received out-of-order kexdhreply");
 	}
-	m_mp_init(&dh_f);
 	type = ses.newkeys->algo_hostkey;
 	TRACE(("type is %d", type))
 
@@ -97,20 +117,59 @@
 		dropbear_exit("Bad KEX packet");
 	}
 
-	if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
-		TRACE(("failed getting mpint"))
-		dropbear_exit("Bad KEX packet");
+	switch (ses.newkeys->algo_kex->mode) {
+		case DROPBEAR_KEX_NORMAL_DH:
+			{
+			DEF_MP_INT(dh_f);
+			m_mp_init(&dh_f);
+			if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
+				TRACE(("failed getting mpint"))
+				dropbear_exit("Bad KEX packet");
+			}
+
+			kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
+			mp_clear(&dh_f);
+			}
+			break;
+		case DROPBEAR_KEX_ECDH:
+#ifdef DROPBEAR_ECDH
+			{
+			buffer *ecdh_qs = buf_getstringbuf(ses.payload);
+			kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
+			buf_free(ecdh_qs);
+			}
+#endif
+			break;
+#ifdef DROPBEAR_CURVE25519
+		case DROPBEAR_KEX_CURVE25519:
+			{
+			buffer *ecdh_qs = buf_getstringbuf(ses.payload);
+			kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);