changeset 1733:d529a52b2f7c coverity coverity

merge coverity from main
author Matt Johnston <matt@ucc.asn.au>
date Fri, 26 Jun 2020 21:07:34 +0800
parents b59623a64678 (current diff) 2f5d797d9811 (diff)
children
files .travis.yml Makefile.in default_options.h
diffstat 422 files changed, 17327 insertions(+), 48883 deletions(-) [+]
line wrap: on
line diff
--- a/.gitignore	Thu Mar 21 23:28:59 2019 +0800
+++ b/.gitignore	Fri Jun 26 21:07:34 2020 +0800
@@ -5,6 +5,7 @@
 *.bb
 *.bbg
 *.prof
+.*.swp
 /autom4te.cache
 /config.log
 /config.status
@@ -13,6 +14,9 @@
 /dropbearconvert
 /dropbearkey
 /dropbearmulti
+/fuzzcorpus
+/fuzzer-*
+/fuzzer-*.options
 /scp
 /scp-progress
 Makefile
@@ -20,3 +24,4 @@
 config.h.in
 configure
 default_options_guard.h
+tags
--- a/.hgsigs	Thu Mar 21 23:28:59 2019 +0800
+++ b/.hgsigs	Fri Jun 26 21:07:34 2020 +0800
@@ -24,3 +24,6 @@
 9030ffdbe5625e35ed7189ab84a41dfc8d413e9c 0 iQIcBAABCgAGBQJXkOg0AAoJEESTFJTynGdzc1kP/3vSKCnhOOvjCjnpTQadYcCUq8vTNnfLHYVu0R4ItPa/jT6RmxoaYP+lZnLnnBx9+aX7kzwHsa9BUX3MbMEyLrOzX2I+bDJbNPhQyupyCuPYlf5Q9KVcO9YlpbsC4q5XBzCn3j2+pT8kSfi9uD8fgY3TgE4w9meINrfQAealfjwMLT8S/I49/ni0r+usSfk/dnSShJYDUO7Ja0VWbJea/GkkZTu30bCnMUZPjRApipU3hPP63WFjkSMT1rp2mAXbWqyr9lf8z32yxzM9nMSjq4ViRFzFlkGtE3EVRJ4PwkO7JuiWAMPJpiQcEr+r52cCsmWhiGyHuINo01MwoMO9/n6uL1WVa3mJcE9se3xBOvfgDu2FRFGCAdm1tef+AGVo9EG1uJXi0sX2yUc6DMeuYaRWrXMMlZh7zp9cuNU9Y/lLui9RFmq66yeXG3Z2B72doju3Ig5QGrNNw2AOsSzeHdAtOp6ychqPcl9QfIeJQG18KyPSefZKM3G8YRKBRIwXFEH6iZJe5ZIP4iXrHDMn2JqtTRtDqKR8VNDAgb9z4Ffx8QRxFyj5JzTTMM1GddHb9udLvTQlO0ULYG7hCSMRNzvUBE2aTw8frjLRyfyyg3QpDu/hz8op8s1ecE8rTCD8RuX9DiiylNozypPtGNS+UDbAmkc1PCWaRpPVl+9K6787
 5c9207ceedaea794f958224c19214d66af6e2d56 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlkdtooACgkQRJMUlPKcZ3P6ZxAAmLy/buZB/d96DJF/pViRWt/fWdjQFC4MqWfeSLW02OZ8Qkm1vPL3ln6WPHC2thy3xZWVg2uan3pLk/XXnsIFu8Q7r1EAfFFpvlMUmdl7asE8V6ilaeqmiI7bIvGMFbf4cZkQliLjiFkJX56tFHRCNi+rb7WgRuru3/GzPXUq2AvXZvFpFJgik0B72TxVlmCKeBRZq1FvP0UhAH48RJWYJksdEyzh2paMfjX9ZO5Q2SFFrmPw6k2ArdJFC1AYcgceZC84y06RKJ0WiSntUPlEUXgQbQVVWbtQDhjfJXMr/beuroNdT/vsRraLVkAzvhaDXNnHlAJNLQxci+AcLpnzZhxMW+ax7RRtrpXGxRN4cs0lBGUcSkaDybFqMYXwEjXAE8w6fdJRWCIlxctkAW/iNEO4kAG97hI2Qwcw5oU2Ymnv09zyGR+XJE35pJqPulJHExdwanJHvmjH0QF7TNFS82yxS5dKnP954cj3Lu9SWGYWjxQJRmLtOwb+lqqol4VTxG7Ois4uef9/Tpp9skeMZXVeNlpn2wrp6iFcX3uiiVDg9VKkl3ig6UqCiqQSuiIN87RXwUOeHXlCnW3adz3Xei0ziBrwLSql7lBIHGEAlUUNmJ3CrR8IwQtcynGEMKfNIeZ/XK+uNlm9cJIqZf1fzqc8KexlyS9AS0i/kiYZTr4=
 2f0c3f3361d3ea4eb9129ed8810699fda7e7a8ee 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlqVb+IACgkQRJMUlPKcZ3OENA//R9HsOUJQB2QZjRgAvqgLn2AMLUvmWb2etTZEc3Nps957Fw1F4kjh6VGfIpWuytfsDx1W8qRx09ikTdb3YteMWCuX8/aFreSPrioYmzrAEcxkZdA7B/jciqU0iXuHiJ9saKk5TR70aNp+iRy0hjAgiYEsVMF9YKHzULOJcHr70x9XVKquubQkwNqJA+/b2JbK2j46wM5nVK/alGSI2kMmEzXmAHQxsvf1OLMvgH8ou/l0xsg/CuFEK299XKfZAbsFEXrjuoWZ1aSa6rTeOWsWli5T+czyyJHI4Eu0Sz/gaR8+MPhJSYes8YjvzEdv32rRMDVOdBq4e+HoTgFt/THYABP6/R1H5fX3Lm4K8u9F9SwJbb/YKRAIrfWDob8ApnGFHk2dyYO20Fskbbg6b1pC7ulDWsufu8lYkQyMlTc3dR6P4eTB6mKO4x+gMG6tIYZ60fiULoEnMJCgegPtevmz+TG1rzdjh3ljiw9Dxz5lNtL+W7sBKKHwhyG0u+bavgmvBMKNL/rdHEM+0yCIz1U6Lb8sVaST1E4zbdm7cWHbSozBij3G0GBSkLFEq7ZLlh8wco9rELRh0Y9fFsWY9j6H/PTOu0GfHrYluFb9WGywHAquQY8j2croRx+MrvTbR1wZrbevPNm9gqk3vgOiDWu7KwxLLqcj+dEQ7tccptVYtbM=
+07b0d56d186d7eeef4106137a3eba554959ba0e3 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlyWOo8ACgkQRJMUlPKcZ3O+MQ//c5oeDUvZuFiI4FHZqfIK/59YAciTP+9TQmoWDVSuOdkd9ZYJA7b7DCusqP2TWFEIl9M7i5hTLTMD21xuEQQtfOSP6EXpUw6JNdh/lsJs7EDlFANtwkdEozAQozFKnXbJEV3y9WldEWUlmPFjt4fJQIuG10SU7MTJHcSaQddJCh3I1//F4EvgRe+OqyrFwKekGiFdvfjcIFN3lQmk6K1Sc0MgyIO/VVZm/AQpBi0Dlg0yOl+EDcxxlmeSInbvLceWSP6op35I4dE5YWH1UetjzIsr5AIM15/k3viAKDDefY1EMAzK9b7YAF4BLw0a6XoQu0apvcWaALE/bJzWNSg/QbCm2JAZzk21WLLvR+AELzPfKXrHX3o0h51lpQ4rs7EWKUm43dJPoWkcFNOU+BDsNzffcJgChbRs48ut89DYLiGmSxhRxE77VPbA+klgTGdctOTLd8psseRlGYCuGe8zeota80bV9fUZ9WJZHwNgEWGowKUoTjy6l5k9OH3iQuQX3OXoy78ufRgWDulE7noVTMhXurQ8a0Jf2k/MW9dcnqGVkWitCFKPEvZwVmWyW2AWsdMcBJnFFGzDsNSxWTtCF9XcxieDO1IB8vGwYcb1TwEVuVzvR/wwvc3PgVikF+4Qv2NqdoQc1yn2PkocY2hwXyIZUAwz7erNumlTbeC/JK8=
+ebcdb893992d286d363e60f5353d6e1401e7084b 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlybhXAACgkQRJMUlPKcZ3O7pQ//QuNJfBVa7ROaOJOR2H/xr6PRn1Fnc6rr/GCF9cqWrbGP6wNo24dRjcu5LxviqPvzfwRXIMXwVz8L/y61/sm6XcA7VFP4+MBoltfeUOdMbfBdtwEUo3WMBdP1w2q5GgYj8ZY6MawiLEqFba5aua7dokTNBOQM3Yebj+9I16MiWEaRSnuwYPoieHW2Fo6oftcIgs/GCXwT2xYzc0n3FpYAbK7u6sEkpL16EstV0Y/G70+X1/4Mg3GM96S5fl9Zbun47W7/+gT4AQVQjE+UnPNDudObAe+2BaOZLFvEbd7iJBBcqtjpBktuP58IEAb3A3srUCy49LNLWk43lj+PtoslK/U6TShKQ2vAgfd//bbn6ieXFJY8N+wYPpJo1m7zpTiEtS7J7wu6vkGGZlqUAj6MHXZj223CgazhSAlg/XFPs9oz3Y96c33Tnd4jB9iEXNNt5jzCAMImx2huSGgnP0JFAbcniq/ug5tl1VWaracvSuJl7fmf17DbmehsLbvtZBoMlePY7Ssfb5IokfVvptt4zRpRZnjtWfHCjtC6zYhtvXTmXH/bqWwx9MMjOf5WPfZoCMvXfMqdVI15FVbxU15WnqjvdvKUCkdz1aMFzxqc4MXgyvjtB9CvO/8WwBOJ2m2nDdiZfh8/H8SawYqEHgB61FX5xA5aXecgXcjQnqWDDxw=
+4877afd51e041eca7749cc46b57fd80aa23815b4 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAl7nmREACgkQRJMUlPKcZ3PG1BAAnUl0/nTnQ3CMM3S72DT1JQ1eDxZa14r6r1xEPngU83hNNzmPcnfiMDts+Vz1M3PLxNNOXVVt/MTw04+V9joPhhSWEe8O1pd3lAqTPswL7hhIEbVwZwyFCuAV4iAm+tHKzKLjtjgZfMgij6XylOmw18VBw5R+suoOMclJqeHlJ5m0Mq2wRLDE+RdVCAkulTqhGYjJNQUXMMNPx/cxUo3NHsto9pWL3d1285vBByP6BQSaeYlO012InvJRlQuEkK3lnIyzq6voIc6+tMli0q9iyBz+2GIloBQNAnb6EGaXxqAOBW5NRc+/Oauiu8Yf/6JoFlkAIcPXmGRtxiAiynJImhiTaCFdgdxaXLFzjBvq+tcwVXvvNM52fOZ4Z3QgMDu6EgNWfma0lsg4T3ar2ml2/evuWeLVut5ZmYFHarTFX+/pTVy9nAZK/F5ROJM1prTNYI18PZV4qvULta8spGV2Be0rCkQQubp9RWdKHNGZE70lrX5OnNIwE/D3g2QE04243i0IGBwhlDEpYjqujLyHk8W6XE1CORx0hQ0fUjzKZsRvOB7XyMAFpQUVOhoMFcnk5XHDW6B/U7NAxzqNqO+gbHO/UIeuy/KOVlMNJCmtRL/HYNGZ6SCZbRpyX3d8Ow0sasNfJkZrT6a0Tf6lZktWOxtPkoEDLfuCzudzn4JxGQM=
--- a/.hgtags	Thu Mar 21 23:28:59 2019 +0800
+++ b/.hgtags	Fri Jun 26 21:07:34 2020 +0800
@@ -56,3 +56,6 @@
 0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
 c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
 1c66ca4f3791c82501c88e7637312182c7294978 DROPBEAR_2018.76
+6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77
+009d52ae26d35f3381c801e02318fa9be34be93c DROPBEAR_2019.78
+e2e4929d057b09422f2ea4556fb64209aff58161 DROPBEAR_2020.79
--- a/.travis.yml	Thu Mar 21 23:28:59 2019 +0800
+++ b/.travis.yml	Fri Jun 26 21:07:34 2020 +0800
@@ -1,13 +1,8 @@
 language: c
 
-os:
-  - linux
+git:
+  depth: 3
 
-compiler:
-  - gcc
-
-# container-based builds
-sudo: false
 addons:
   apt:
     packages:
--- a/CHANGES	Thu Mar 21 23:28:59 2019 +0800
+++ b/CHANGES	Fri Jun 26 21:07:34 2020 +0800
@@ -1,3 +1,117 @@
+2020.80 - 26 June 2020
+
+- Don't block authorized_keys logins with no-X11-forwarding or no-agent-forwarding 
+  restrictions when X11 or agent forwarding are disabled at compile time.
+  This is more of a problem now X11 is disabled by default, reported by Guilhem Moulin
+
+- Reduce binary size by 4kB (x64) when using bundled libtommath
+
+- Define GNU_SOURCE for getrandom() on uclibc, reported by Laurent Bercot and
+  Fabrice Fontaine
+
+- Improve checking libtomcrypt version compatibility
+
+- Add some style notes to DEVELOPING.md
+
+2020.79 - 15 June 2020
+
+- Support ed25519 hostkeys and authorized_keys, many thanks to Vladislav Grishenko.
+  This also replaces curve25519 with a TweetNaCl implementation that reduces code size.
+
+- Add chacha20-poly1305 authenticated cipher. This will perform faster than AES
+  on many platforms. Thanks to Vladislav Grishenko
+
+- Support using rsa-sha2 signatures. No changes are needed to hostkeys/authorized_keys
+  entries, existing RSA keys can be used with the new signature format (signatures
+  are ephemeral within a session). Old ssh-rsa signatures will no longer
+  be supported by OpenSSH in future so upgrading is recommended.
+
+- Use getrandom() call on Linux to ensure sufficient entropy has been gathered at startup.
+  Dropbear now avoids reading from the random source at startup, instead waiting until
+  the first connection. It is possible that some platforms were running without enough 
+  entropy previously, those could potentially block at first boot generating host keys.
+  The dropbear "-R" option is one way to avoid that.
+
+- Upgrade libtomcrypt to 1.18.2 and libtommath to 1.2.0, many thanks to Steffen Jaeckel for
+  updating Dropbear to use the current API. Dropbear's configure script will check 
+  for sufficient system library versions, otherwise using the bundled versions.
+
+- CBC ciphers, 3DES, hmac-sha1-96, and x11 forwarding are now disabled by default.
+  They can be set in localoptions.h if required.
+  Blowfish has been removed.
+
+- Support AES GCM, patch from Vladislav Grishenko. This is disabled by default,
+  Dropbear doesn't currently use hardware accelerated AES.
+
+- Added an API for specifying user public keys as an authorized_keys replacement.
+  See pubkeyapi.h for details, thanks to Fabrizio Bertocci
+
+- Fix idle detection clashing with keepalives, thanks to jcmathews
+
+- Include IP addresses in more early exit messages making it easier for fail2ban
+  processing. Patch from Kevin Darbyshire-Bryant
+
+- scp fix for CVE-2018-20685 where a server could modify name of output files
+
+- SSH_ORIGINAL_COMMAND is set for "dropbear -c" forced command too
+
+- Fix writing key files on systems without hard links, from Matt Robinson
+
+- Compatibility fixes for IRIX from Kazuo Kuroi
+
+- Re-enable printing MOTD by default, was lost moving from options.h. Thanks to zciendor
+
+- Call fsync() is called on parent directory when writing key files to ensure they are flushed
+
+- Fix "make install" for manpages in out-of-tree builds, from Gabor Z. Papp
+
+- Some notes are added in DEVELOPING.md
+
+2019.78 - 27 March 2019
+
+- Fix dbclient regression in 2019.77. After exiting the terminal would be left
+  in a bad state. Reported by Ryan Woodsmall
+  
+2019.77 - 23 March 2019
+
+- Fix server -R option with ECDSA - only advertise one key size which will be accepted.
+  Reported by Peter Krefting, 2018.76 regression.
+
+- Fix server regression in 2018.76 where multiple client -R forwards were all forwarded 
+  to the first destination. Reported by Iddo Samet.
+
+- Make failure delay more consistent to avoid revealing valid usernames, set server password 
+  limit of 100 characters. Problem reported by usd responsible disclosure team
+
+- Change handling of failed authentication to avoid disclosing valid usernames,
+  CVE-2018-15599. 
+
+- Fix dbclient to reliably return the exit code from the remote server.
+  Reported by W. Mike Petullo
+
+- Fix export of 521-bit ECDSA keys, from Christian Hohnstädt
+
+- Add -o Port=xxx option to work with sshfs, from xcko
+
+- Merged fuzzing code, see FUZZER-NOTES.md
+
+- Add a DROPBEAR_SVR_MULTIUSER=0 compile option to run on 
+  single-user Linux kernels (CONFIG_MULTIUSER disabled). From Patrick Stewart
+
+- Increase allowed username to 100 characters, reported by W. Mike Petullo
+
+- Update config.sub and config.guess, should now work with RISC-V
+
+- Cygwin compile fix from karel-m
+
+- Don't require GNU sed (accidentally in 2018.76), reported by Samuel Hsu
+
+- Fix for IRIX and writev(), reported by Kazuo Kuroi
+
+- Other fixes and cleanups from François Perrad, Andre McCurdy, Konstantin Demin,
+  Michael Jones, Pawel Rapkiewicz
+
+
 2018.76 - 27 February 2018
 
 > > > Configuration/compatibility changes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DEVELOPING.md	Fri Jun 26 21:07:34 2020 +0800
@@ -0,0 +1,75 @@
+# Developer Notes
+
+## Building
+
+See [INSTALL](INSTALL) for build instructions. 
+[SMALL](SMALL) has hints for building smaller binaries, also see comments
+in default_options.h.
+
+## Debug printing
+
+Set `#define DEBUG_TRACE 1` in localoptions.h to enable a `-v` option
+for dropbear and dbclient. That prints various details of the session. For
+development running `dropbear -F -E` is useful to run in the foreground. You
+can set `#define DEBUG_NOFORK 1` to make dropbear a one-shot server, easy to 
+run under a debugger.
+
+## Random sources
+
+Most cryptography requires a good random entropy source, both to generate secret
+keys and in the course of a session. Dropbear uses the Linux kernel's
+`getrandom()` syscall to ensure that the system RNG has been initialised before
+using it. On some systems there is insufficient entropy gathered during early
+boot - generating hostkeys then will block for some amount of time. 
+Dropbear has a `-R` option to generate hostkeys upon the first connection 
+as required - that will allow the system more time to gather entropy.
+
+## Algorithms
+
+Default algorithm lists are specified in [common-algo.c](common-algo.c).
+They are in priority order, the client's first matching choice is used
+(see rfc4253). 
+Dropbear client has `-c` and `-m` arguments to choose which are enabled at
+runtime (doesn't work for server as of June 2020).
+
+Enabling/disabling algorithms is done in [localoptions.h](localoptions.h),
+see [default_options.h](default_options.h).
+
+## Style
+
+Source code is indented with tabs, width set to 4 (though width shouldn't
+matter much). Braces are on the same line as functions/loops/if - try
+to keep consistency with existing code.
+
+All `if` statements should have braces, no exceptions.
+
+Avoid using pointer arithmetic, instead the functions in
+[buffer.h](buffer.h) should be used.
+
+Some Dropbear platforms have old compilers.
+Variable declarations must be at the top of a scope and
+comments must be `/* */` rather than `//`.
+
+Pointer variables should be initialised to NULL - it can reduce the
+severity of bugs.
+
+## Third party code
+
+Libtomcrypt and libtommath are periodically synced from upstream, so
+avoid making changes to that code which will need to be maintained.
+Improvements can be sent upstream to the libtom project.
+
+## Non-root user
+
+Dropbear server will run fine as a non-root user, allowing logins only for 
+that user. Password authentication probably won't work (can't read shadow 
+passwords). You will need to create hostkeys that are readable.
+
+## Connection setup 
+
+Dropbear implements first_kex_packet_follows to reduce 
+handshake latency (rfc 4253 7.1). Some less common implementations don't 
+handle that, it can be a cause of problems connecting. Note also that
+Dropbear may send several ssh packets within a single TCP packet - it's just a 
+stream.
+
--- a/FUZZER-NOTES.md	Thu Mar 21 23:28:59 2019 +0800
+++ b/FUZZER-NOTES.md	Fri Jun 26 21:07:34 2020 +0800
@@ -72,3 +72,6 @@
 
 - [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.
--- a/INSTALL	Thu Mar 21 23:28:59 2019 +0800
+++ b/INSTALL	Fri Jun 26 21:07:34 2020 +0800
@@ -28,6 +28,8 @@
 recompile after changing the PROGRAMS list, you *MUST* "make clean" before
 recompiling - bad things will happen otherwise)
 
+DEVELOPING.md has some notes on other developer topics, including debugging.
+
 See MULTI for instructions on making all-in-one binaries.
 
 If you want to compile statically use ./configure --enable-static
@@ -56,7 +58,7 @@
 uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
 You can use "make STATIC=1" to make statically linked binaries, and it is
 advisable to strip the binaries too. If you're looking to make a small binary,
-you should remove unneeded ciphers and MD5, by editing options.h
+you should remove unneeded ciphers and MD5, by editing localoptions.h
 
 It is possible to compile zlib in, by copying zlib.h and zconf.h into a
 subdirectory (ie zlibincludes), and 
--- a/LICENSE	Thu Mar 21 23:28:59 2019 +0800
+++ b/LICENSE	Fri Jun 26 21:07:34 2020 +0800
@@ -8,7 +8,7 @@
 Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
 same license:
 
-Copyright (c) 2002-2015 Matt Johnston
+Copyright (c) 2002-2020 Matt Johnston
 Portions copyright (c) 2004 Mihnea Stoenescu
 All rights reserved.
 
@@ -32,7 +32,8 @@
 
 =====
 
-LibTomCrypt and LibTomMath are written by Tom St Denis, and are Public Domain.
+LibTomCrypt and LibTomMath are written by Tom St Denis and others, see
+libtomcrypt/LICENSE and libtommath/LICENSE.
 
 =====
 
@@ -90,52 +91,24 @@
 
 =====
 
-curve25519-donna:
+curve25519.c:
+
+Modified TweetNaCl version 20140427, a self-contained public-domain C library.
+https://tweetnacl.cr.yp.to/
 
-/* 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.
- */
+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.
--- a/Makefile.in	Thu Mar 21 23:28:59 2019 +0800
+++ b/Makefile.in	Fri Jun 26 21:07:34 2020 +0800
@@ -36,8 +36,9 @@
 		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 @@
 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 chachapoly.o gcm.o
 
 KEYOBJS=dropbearkey.o
 
@@ -80,6 +81,15 @@
 	scpobjs=$(SCPOBJS)
 endif
 
+ifeq (@[email protected], 1)
+    # rdynamic makes all the global symbols of dropbear available to all the loaded shared libraries
+    # this allow a plugin to reuse existing crypto/utilities like base64_decode/base64_encode without
+    # the need to rewrite them.
+    PLUGIN_LIBS=-ldl -rdynamic
+else
+    PLUGIN_LIBS=
+endif
+
 [email protected]@
 [email protected]@
 
@@ -165,7 +175,7 @@
 	-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
+	if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
 
 # dropbear should go in sbin, so it needs a separate rule
 inst_dropbear: dropbear
@@ -178,7 +188,7 @@
 	$(INSTALL) -d $(DESTDIR)$(bindir)
 	$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
 	$(INSTALL) -d $(DESTDIR)$(mandir)/man1
-	if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
+	if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
 
 inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS)) 
 
@@ -189,7 +199,7 @@
 dropbearconvert: $(dropbearconvertobjs)
 
 dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
-	$(CC) $(LDFLAGS) -o [email protected]$(EXEEXT) $([email protected]) $(LIBTOM_LIBS) $(LIBS) @[email protected]
+	$(CC) $(LDFLAGS) -o [email protected]$(EXEEXT) $([email protected]) $(LIBTOM_LIBS) $(LIBS) @[email protected] $(PLUGIN_LIBS)
 
 dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
 	$(CC) $(LDFLAGS) -o [email protected]$(EXEEXT) $([email protected]) $(LIBTOM_LIBS) $(LIBS)
@@ -226,7 +236,7 @@
 $(STATIC_LTM): $(OPTION_HEADERS)
 	$(MAKE) -C libtommath
 
-.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
+.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint
 
 ltc-clean:
 	$(MAKE) -C libtomcrypt clean
@@ -252,10 +262,13 @@
 tidy:
 	-rm -f *~ *.gcov */*~
 
+lint:
+	cd $(srcdir); ./dropbear_lint.sh
+
 ## 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))
 
@@ -269,27 +282,32 @@
 # exclude svr-main.o to avoid duplicate main
 svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
 
+fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
+
 # build all the fuzzers. This will require fail to link unless built with
 # make fuzz-targets FUZZLIB=-lFuzzer.a 
 # or similar - the library provides main().
 fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
 
-fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o
 	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
 
-fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
+	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
+
+fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
 	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
 
-fuzzer-pubkey: fuzzer-pubkey.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+fuzzer-verify: fuzzer-verify.o fuzz-harness.o
 	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
 
-fuzzer-verify: fuzzer-verify.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
 	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
 
-fuzzer-kexdh: fuzzer-kexdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
 	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
 
-fuzzer-kexecdh: fuzzer-kexecdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
+fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
 	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
 
 fuzzer-%.options: Makefile
@@ -302,11 +320,14 @@
 	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
 
 # to make coverity happy?
 test:
 	true
+
--- a/README	Thu Mar 21 23:28:59 2019 +0800
+++ b/README	Fri Jun 26 21:07:34 2020 +0800
@@ -55,6 +55,7 @@
 ./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
--- a/agentfwd.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/agentfwd.h	Fri Jun 26 21:07:34 2020 +0800
@@ -32,6 +32,9 @@
 
 #if DROPBEAR_CLI_AGENTFWD
 
+/* From OpenSSH authfd.h */
+#define SSH_AGENT_RSA_SHA2_256          0x02
+
 /* An agent reply can be reasonably large, as it can
  * contain a list of all public keys held by the agent.
  * 10000 is arbitrary */
@@ -40,7 +43,7 @@
 /* client functions */
 void cli_load_agent_keys(m_list * ret_list);
 void agent_buf_sign(buffer *sigblob, sign_key *key, 
-	const buffer *data_buf);
+		const buffer *data_buf, enum signature_type type);
 void cli_setup_agent(const struct Channel *channel);
 
 #ifdef __hpux
--- a/algo.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/algo.h	Fri Jun 26 21:07:34 2020 +0800
@@ -47,7 +47,7 @@
 
 /* lists mapping ssh types of algorithms to internal values */
 extern algo_type sshkex[];
-extern algo_type sshhostkey[];
+extern algo_type sigalgs[];
 extern algo_type sshciphers[];
 extern algo_type sshhashes[];
 extern algo_type ssh_compress[];
@@ -72,6 +72,14 @@
 			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 {
@@ -112,21 +120,17 @@
 	const struct ltc_hash_descriptor *hash_desc;
 };
 
-int have_algo(const char* algo, size_t algolen, const algo_type algos[]);
+/* Includes all algorithms is useall is set */
+void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall);
+/* Includes "usable" algorithms */
 void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
 
-enum kexguess2_used {
-	KEXGUESS2_LOOK,
-	KEXGUESS2_NO,
-	KEXGUESS2_YES,
-};
+#define KEXGUESS2_ALGO_NAME "[email protected]"
 
-#define KEXGUESS2_ALGO_NAME "[email protected]"
-#define KEXGUESS2_ALGO_ID 99
-
-
+int buf_has_algo(buffer *buf, const char *algo);
+algo_type * first_usable_algo(algo_type algos[]);
 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
-		enum kexguess2_used *kexguess2, int *goodguess);
+		int kexguess2, int *goodguess);
 
 #if DROPBEAR_USER_ALGO_LIST
 int check_user_algos(const char* user_algo_list, algo_type * algos, 
--- a/bignum.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/bignum.c	Fri Jun 26 21:07:34 2020 +0800
@@ -86,7 +86,7 @@
 
 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) {
+	if (mp_from_ubin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
 		dropbear_exit("Mem alloc error");
 	}
 }
--- a/buffer.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/buffer.c	Fri Jun 26 21:07:34 2020 +0800
@@ -228,19 +228,37 @@
 }
 
 /* Return a string as a newly allocated buffer */
-buffer * buf_getstringbuf(buffer *buf) {
+static buffer * buf_getstringbuf_int(buffer *buf, int incllen) {
 	buffer *ret = NULL;
 	unsigned int len = buf_getint(buf);
+	int extra = 0;
 	if (len > MAX_STRING_LEN) {
 		dropbear_exit("String too long");
 	}
-	ret = buf_new(len);
+	if (incllen) {
+		extra = 4;
+	}
+	ret = buf_new(len+extra);
+	if (incllen) {
+		buf_putint(ret, len);
+	}
 	memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
 	buf_incrpos(buf, len);
 	buf_incrlen(ret, len);
+	buf_setpos(ret, 0);
 	return ret;
 }
 
+/* Return a string as a newly allocated buffer */
+buffer * buf_getstringbuf(buffer *buf) {
+	return buf_getstringbuf_int(buf, 0);
+}
+
+/* Returns a string in a new buffer, including the length */
+buffer * buf_getbuf(buffer *buf) {
+	return buf_getstringbuf_int(buf, 1);
+}
+
 /* Just increment the buffer position the same as if we'd used buf_getstring,
  * but don't bother copying/malloc()ing for it */
 void buf_eatstring(buffer *buf) {
@@ -289,18 +307,18 @@
 /* for our purposes we only need positive (or 0) numbers, so will
  * fail if we get negative numbers */
 void buf_putmpint(buffer* buf, mp_int * mp) {
-
+	size_t written;
 	unsigned int len, pad = 0;
 	TRACE2(("enter buf_putmpint"))
 
 	dropbear_assert(mp != NULL);
 
-	if (SIGN(mp) == MP_NEG) {
+	if (mp_isneg(mp)) {
 		dropbear_exit("negative bignum");
 	}
 
 	/* zero check */
-	if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
+	if (mp_iszero(mp)) {
 		len = 0;
 	} else {
 		/* SSH spec requires padding for mpints with the MSB set, this code
@@ -321,10 +339,10 @@
 		if (pad) {
 			buf_putbyte(buf, 0x00);
 		}
-		if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
+		if (mp_to_ubin(mp, buf_getwriteptr(buf, len-pad), len-pad, &written) != MP_OKAY) {
 			dropbear_exit("mpint error");
 		}
-		buf_incrwritepos(buf, len-pad);
+		buf_incrwritepos(buf, written);
 	}
 
 	TRACE2(("leave buf_putmpint"))
@@ -352,7 +370,7 @@
 		return DROPBEAR_FAILURE;
 	}
 
-	if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
+	if (mp_from_ubin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
 		return DROPBEAR_FAILURE;
 	}
 
--- a/buffer.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/buffer.h	Fri Jun 26 21:07:34 2020 +0800
@@ -58,6 +58,7 @@
 unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len);
 char* buf_getstring(buffer* buf, unsigned int *retlen);
 buffer * buf_getstringbuf(buffer *buf);
+buffer * buf_getbuf(buffer *buf);
 void buf_eatstring(buffer *buf);
 void buf_putint(buffer* buf, unsigned int val);
 void buf_putstring(buffer* buf, const char* str, unsigned int len);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chachapoly.c	Fri Jun 26 21:07:34 2020 +0800
@@ -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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chachapoly.h	Fri Jun 26 21:07:34 2020 +0800
@@ -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_ */
--- a/chansession.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/chansession.h	Fri Jun 26 21:07:34 2020 +0800
@@ -41,6 +41,9 @@
 
 	char * cmd; /* command to exec */
 	pid_t pid; /* child process pid */
+	/* command that was sent by the client, if authorized_keys command= or
+	dropbear -c was used */
+	char *original_command;
 
 	/* pty details */
 	int master; /* the master terminal fd*/
@@ -72,10 +75,6 @@
 	char * agentfile;
 	char * agentdir;
 #endif
-
-#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
-	char *original_command;
-#endif
 };
 
 struct ChildPid {
--- a/cli-agentfwd.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/cli-agentfwd.c	Fri Jun 26 21:07:34 2020 +0800
@@ -255,11 +255,12 @@
 }
 
 void agent_buf_sign(buffer *sigblob, sign_key *key, 
-		const buffer *data_buf) {
+		const buffer *data_buf, enum signature_type sigtype) {
 	buffer *request_data = NULL;
 	buffer *response = NULL;
 	unsigned int siglen;
 	int packet_type;
+	int flags = 0;
 	
 	/* Request format
 	byte			SSH2_AGENTC_SIGN_REQUEST
@@ -271,7 +272,12 @@
 	buf_put_pub_key(request_data, key, key->type);
 	
 	buf_putbufstring(request_data, data_buf);
-	buf_putint(request_data, 0);
+#if DROPBEAR_RSA_SHA256
+	if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
+		flags |= SSH_AGENT_RSA_SHA2_256;
+	}
+#endif
+	buf_putint(request_data, flags);
 	
 	response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
 	
--- a/cli-authpubkey.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/cli-authpubkey.c	Fri Jun 26 21:07:34 2020 +0800
@@ -33,7 +33,7 @@
 #include "agentfwd.h"
 
 #if DROPBEAR_CLI_PUBKEY_AUTH
-static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
+static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign);
 
 /* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
  * We use it to remove the key we tried from the list */
@@ -59,13 +59,15 @@
 	char* algotype = NULL;
 	unsigned int algolen;
 	enum signkey_type keytype;
+	enum signature_type sigtype;
 	unsigned int remotelen;
 
 	TRACE(("enter recv_msg_userauth_pk_ok"))
 
 	algotype = buf_getstring(ses.payload, &algolen);
-	keytype = signkey_type_from_name(algotype, algolen);
-	TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
+	sigtype = signature_type_from_name(algotype, algolen);
+	keytype = signkey_type_from_signature(sigtype);
+	TRACE(("recv_msg_userauth_pk_ok: type %d", sigtype))
 	m_free(algotype);
 
 	keybuf = buf_new(MAX_PUBKEY_SIZE);
@@ -112,7 +114,7 @@
 		TRACE(("matching key"))
 		/* XXX TODO: if it's an encrypted key, here we ask for their
 		 * password */
-		send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
+		send_msg_userauth_pubkey((sign_key*)iter->item, sigtype, 1);
 	} else {
 		TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
 	}
@@ -120,31 +122,32 @@
 	TRACE(("leave recv_msg_userauth_pk_ok"))
 }
 
-void cli_buf_put_sign(buffer* buf, sign_key *key, int type, 
+static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
 			const buffer *data_buf) {
 #if DROPBEAR_CLI_AGENTFWD
+	// TODO: rsa-sha256 agent
 	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_buf);
+		agent_buf_sign(sigblob, key, data_buf, sigtype);
 		buf_putbufstring(buf, sigblob);
 		buf_free(sigblob);
 	} else 
 #endif /* DROPBEAR_CLI_AGENTFWD */
 	{
-		buf_put_sign(buf, key, type, data_buf);
+		buf_put_sign(buf, key, sigtype, data_buf);
 	}
 }
 
-/* TODO: make it take an agent reference to use as well */
-static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
+static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign) {
 
 	const char *algoname = NULL;
 	unsigned int algolen;
 	buffer* sigbuf = NULL;
+	enum signkey_type keytype = signkey_type_from_signature(sigtype);
 
-	TRACE(("enter send_msg_userauth_pubkey"))
+	TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype))
 	CHECKCLEARTOWRITE();
 
 	buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
@@ -160,10 +163,9 @@
 
 	buf_putbyte(ses.writepayload, realsign);
 
-	algoname = signkey_name_from_type(type, &algolen);
-
+	algoname = signature_name_from_type(sigtype, &algolen);
 	buf_putstring(ses.writepayload, algoname, algolen);
-	buf_put_pub_key(ses.writepayload, key, type);
+	buf_put_pub_key(ses.writepayload, key, keytype);
 
 	if (realsign) {
 		TRACE(("realsign"))
@@ -172,7 +174,7 @@
 		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);
+		cli_buf_put_sign(ses.writepayload, key, sigtype, sigbuf);
 		buf_free(sigbuf); /* Nothing confidential in the buffer */
 	}
 
@@ -182,7 +184,7 @@
 
 /* Returns 1 if a key was tried */
 int cli_auth_pubkey() {
-
+	enum signature_type sigtype = DROPBEAR_SIGNATURE_NONE;
 	TRACE(("enter cli_auth_pubkey"))
 
 #if DROPBEAR_CLI_AGENTFWD
@@ -190,13 +192,79 @@
 		/* get the list of available keys from the agent */
 		cli_load_agent_keys(cli_opts.privkeys);
 		cli_opts.agent_keys_loaded = 1;
+		TRACE(("cli_auth_pubkey: agent keys loaded"))
 	}
 #endif
 
+	/* iterate through privkeys to remove ones not allowed in server-sig-algs */
+ 	while (cli_opts.privkeys->first) {
+		sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
+		if (cli_ses.server_sig_algs) {
+#if DROPBEAR_RSA
+			if (key->type == DROPBEAR_SIGNKEY_RSA) {
+#if DROPBEAR_RSA_SHA256
+				if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256) 
+						== DROPBEAR_SUCCESS) {
+					sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
+					TRACE(("server-sig-algs allows rsa sha256"))
+					break;
+				}
+#endif /* DROPBEAR_RSA_SHA256 */
+#if DROPBEAR_RSA_SHA1
+				if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNKEY_RSA)
+						== DROPBEAR_SUCCESS) {
+					sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
+					TRACE(("server-sig-algs allows rsa sha1"))
+					break;
+				}
+#endif /* DROPBEAR_RSA_SHA256 */
+			} else
+#endif /* DROPBEAR_RSA */
+			{
+				/* Not RSA */
+				const char *name = NULL;
+				sigtype = signature_type_from_signkey(key->type);
+				name = signature_name_from_type(sigtype, NULL);
+				if (buf_has_algo(cli_ses.server_sig_algs, name)
+						== DROPBEAR_SUCCESS) {
+					TRACE(("server-sig-algs allows %s", name))
+					break;
+				}
+			}
+
+			/* No match, skip this key */
+			TRACE(("server-sig-algs no match keytype %d, skipping", key->type))
+			key = list_remove(cli_opts.privkeys->first);
+			sign_key_free(key); 
+			continue;
+		} else {
+			/* Server didn't provide a server-sig-algs list, we'll 
+			   assume all except rsa-sha256 are OK. */
+#if DROPBEAR_RSA
+			if (key->type == DROPBEAR_SIGNKEY_RSA) {
+#if DROPBEAR_RSA_SHA1
+				sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
+				TRACE(("no server-sig-algs, using rsa sha1"))
+				break;
+#else
+				/* only support rsa-sha256, skip this key */
+				TRACE(("no server-sig-algs, skipping rsa sha256"))
+				key = list_remove(cli_opts.privkeys->first);
+				sign_key_free(key); 
+				continue;
+#endif
+			} /* key->type == DROPBEAR_SIGNKEY_RSA */
+#endif /* DROPBEAR_RSA */
+			sigtype = signature_type_from_signkey(key->type);
+			TRACE(("no server-sig-algs, using key"))
+			break;
+		}
+	}
+
 	if (cli_opts.privkeys->first) {
 		sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
 		/* Send a trial request */
-		send_msg_userauth_pubkey(key, key->type, 0);
+		send_msg_userauth_pubkey(key, sigtype, 0);
 		cli_ses.lastprivkey = key;
 		TRACE(("leave cli_auth_pubkey-success"))
 		return 1;
--- a/cli-chansession.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/cli-chansession.c	Fri Jun 26 21:07:34 2020 +0800
@@ -35,7 +35,7 @@
 #include "chansession.h"
 #include "agentfwd.h"
 
-static void cli_cleanupchansess(const struct Channel *channel);
+static void cli_closechansess(const struct Channel *channel);
 static int cli_initchansess(struct Channel *channel);
 static void cli_chansessreq(struct Channel *channel);
 static void send_chansess_pty_req(const struct Channel *channel);
@@ -51,8 +51,8 @@
 	cli_initchansess, /* inithandler */
 	NULL, /* checkclosehandler */
 	cli_chansessreq, /* reqhandler */
-	NULL, /* closehandler */
-	cli_cleanupchansess, /* cleanup */
+	cli_closechansess, /* closehandler */
+	NULL, /* cleanup */
 };
 
 static void cli_chansessreq(struct Channel *channel) {
@@ -84,7 +84,7 @@
 	
 
 /* If the main session goes, we close it up */
-static void cli_cleanupchansess(const struct Channel *UNUSED(channel)) {
+static void cli_closechansess(const struct Channel *UNUSED(channel)) {
 	cli_tty_cleanup(); /* Restore tty modes etc */
 
 	/* This channel hasn't gone yet, so we have > 1 */
@@ -388,8 +388,8 @@
 	cli_init_netcat, /* inithandler */
 	NULL,
 	NULL,
+	cli_closechansess,
 	NULL,
-	cli_cleanupchansess
 };
 
 void cli_send_netcat_request() {
--- a/cli-kex.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/cli-kex.c	Fri Jun 26 21:07:34 2020 +0800
@@ -81,7 +81,7 @@
 				}
 				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
 	}
@@ -94,7 +94,7 @@
 void recv_msg_kexdh_reply() {
 
 	sign_key *hostkey = NULL;
-	unsigned int type, keybloblen;
+	unsigned int keytype, keybloblen;
 	unsigned char* keyblob = NULL;
 
 	TRACE(("enter recv_msg_kexdh_reply"))
@@ -102,8 +102,8 @@
 	if (cli_ses.kex_state != KEXDH_INIT_SENT) {
 		dropbear_exit("Received out-of-order kexdhreply");
 	}
-	type = ses.newkeys->algo_hostkey;
-	TRACE(("type is %d", type))
+	keytype = ses.newkeys->algo_hostkey;
+	TRACE(("keytype is %d", keytype))
 
 	hostkey = new_sign_key();
 	keybloblen = buf_getint(ses.payload);
@@ -114,7 +114,7 @@
 		checkhostkey(keyblob, keybloblen);
 	}
 
-	if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
+	if (buf_get_pub_key(ses.payload, hostkey, &keytype) != DROPBEAR_SUCCESS) {
 		TRACE(("failed getting pubkey"))
 		dropbear_exit("Bad KEX packet");
 	}
@@ -155,10 +155,12 @@
 #endif
 	}
 
+#if DROPBEAR_NORMAL_DH
 	if (cli_ses.dh_param) {
 		free_kexdh_param(cli_ses.dh_param);
 		cli_ses.dh_param = NULL;
 	}
+#endif
 #if DROPBEAR_ECDH
 	if (cli_ses.ecdh_param) {
 		free_kexecdh_param(cli_ses.ecdh_param);
@@ -173,7 +175,8 @@
 #endif
 
 	cli_ses.param_kex_algo = NULL;
-	if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
+	if (buf_verify(ses.payload, hostkey, ses.newkeys->algo_signature, 
+			ses.hash) != DROPBEAR_SUCCESS) {
 		dropbear_exit("Bad hostkey signature");
 	}
 
@@ -410,3 +413,38 @@
 	}
 	m_free(fingerprint);
 }
+
+void recv_msg_ext_info(void) {
+	/* This message is not client-specific in the protocol but Dropbear only handles
+	a server-sent message at present. */
+	unsigned int num_ext;
+	unsigned int i;
+
+	TRACE(("enter recv_msg_ext_info"))
+
+	/* Must be after the first SSH_MSG_NEWKEYS */
+	TRACE(("last %d, donefirst %d, donescond %d", ses.lastpacket, ses.kexstate.donefirstkex, ses.kexstate.donesecondkex))
+	if (!(ses.lastpacket == SSH_MSG_NEWKEYS && !ses.kexstate.donesecondkex)) {
+		TRACE(("leave recv_msg_ext_info: ignoring packet received at the wrong time"))
+		return;
+	}
+
+	num_ext = buf_getint(ses.payload);
+	TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext))
+
+	for (i = 0; i < num_ext; i++) {
+		unsigned int name_len;
+		char *ext_name = buf_getstring(ses.payload, &name_len);
+		TRACE(("extension %d name '%s'", i, ext_name))
+		if (cli_ses.server_sig_algs == NULL
+				&& name_len == strlen(SSH_SERVER_SIG_ALGS)
+				&& strcmp(ext_name, SSH_SERVER_SIG_ALGS) == 0) {
+			cli_ses.server_sig_algs = buf_getbuf(ses.payload);
+		} else {
+			/* valid extension values could be >MAX_STRING_LEN */
+			buf_eatstring(ses.payload);
+		}
+		m_free(ext_name);
+	}
+	TRACE(("leave recv_msg_ext_info"))
+}
--- a/cli-main.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/cli-main.c	Fri Jun 26 21:07:34 2020 +0800
@@ -106,6 +106,7 @@
 
 	/* Render the formatted exit message */
 	vsnprintf(exitmsg, sizeof(exitmsg), format, param);
+	TRACE(("Exited, cleaning up: %s", exitmsg))
 
 	/* Add the prefix depending on session/auth state */
 	if (!ses.init_done) {
@@ -130,6 +131,12 @@
 		const char* format, va_list param) {
 
 	char printbuf[1024];
+	const char *name;
+
+	name = cli_opts.progname;
+	if (!name) {
+		name = "dbclient";
+	}
 
 	vsnprintf(printbuf, sizeof(printbuf), format, param);
 
@@ -139,7 +146,7 @@
 	}
 #endif
 
-	fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
+	fprintf(stderr, "%s: %s\n", name, printbuf);
 	fflush(stderr);
 }
 
--- a/cli-runopts.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/cli-runopts.c	Fri Jun 26 21:07:34 2020 +0800
@@ -214,7 +214,7 @@
 					cli_opts.always_accept_key = 1;
 					break;
 				case 'p': /* remoteport */
-					next = &cli_opts.remoteport;
+					next = (char**)&cli_opts.remoteport;
 					break;
 #if DROPBEAR_CLI_PUBKEY_AUTH
 				case 'i': /* an identityfile */
@@ -378,6 +378,11 @@
 		}
 	}
 
+#if DROPBEAR_USER_ALGO_LIST
+	/* -c help doesn't need a hostname */
+	parse_ciphers_macs();
+#endif
+
 	/* Done with options/flags; now handle the hostname (which may not
 	 * start with a hyphen) and optional command */
 
@@ -408,10 +413,6 @@
 
 	/* And now a few sanity checks and setup */
 
-#if DROPBEAR_USER_ALGO_LIST
-	parse_ciphers_macs();
-#endif
-
 #if DROPBEAR_CLI_PROXYCMD                                                                                                                                   
 	if (cli_opts.proxycmd) {
 		/* To match the common path of m_freeing it */
--- a/cli-session.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/cli-session.c	Fri Jun 26 21:07:34 2020 +0800
@@ -81,6 +81,7 @@
 	{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
 	{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
 #endif
+	{SSH_MSG_EXT_INFO, recv_msg_ext_info},
 	{0, NULL} /* End */
 };
 
@@ -352,11 +353,13 @@
 	(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
 
 	cli_tty_cleanup();
-
+	if (cli_ses.server_sig_algs) {
+		buf_free(cli_ses.server_sig_algs);
+	}
 }
 
 static void cli_finished() {
-	TRACE(("cli_finised()"))
+	TRACE(("cli_finished()"))
 
 	session_cleanup();
 	fprintf(stderr, "Connection to %[email protected]%s:%s closed.\n", cli_opts.username,
--- a/common-algo.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/common-algo.c	Fri Jun 26 21:07:34 2020 +0800
@@ -30,6 +30,9 @@
 #include "dh_groups.h"
 #include "ltc_prng.h"
 #include "ecc.h"
+#include "gcm.h"
+#include "chachapoly.h"
+#include "ssh.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*/
@@ -61,10 +64,6 @@
 static const struct dropbear_cipher dropbear_aes128 = 
 	{&aes_desc, 16, 16};
 #endif
-#if DROPBEAR_BLOWFISH
-static const struct dropbear_cipher dropbear_blowfish = 
-	{&blowfish_desc, 16, 8};
-#endif
 #if DROPBEAR_TWOFISH256
 static const struct dropbear_cipher dropbear_twofish256 = 
 	{&twofish_desc, 32, 16};
@@ -86,11 +85,11 @@
  * 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 +100,7 @@
 	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 +136,19 @@
  * that is also supported by the server will get used. */
 
 algo_type sshciphers[] = {
+#if DROPBEAR_CHACHA20POLY1305
+	{"[email protected]", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
+#endif
+
+#if DROPBEAR_ENABLE_GCM_MODE
+#if DROPBEAR_AES128
+	{"[email protected]", 0, &dropbear_aes128, 1, &dropbear_mode_gcm},
+#endif
+#if DROPBEAR_AES256
+	{"[email protected]", 0, &dropbear_aes256, 1, &dropbear_mode_gcm},
+#endif
+#endif /* DROPBEAR_ENABLE_GCM_MODE */
+
 #if DROPBEAR_ENABLE_CTR_MODE
 #if DROPBEAR_AES128
 	{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
@@ -169,15 +181,18 @@
 #if DROPBEAR_TWOFISH128
 	{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
 #endif
+#endif /* DROPBEAR_ENABLE_CBC_MODE */
+
 #if DROPBEAR_3DES
+#if DROPBEAR_ENABLE_CTR_MODE
 	{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
 #endif
-#if DROPBEAR_3DES
+#if DROPBEAR_ENABLE_CBC_MODE
 	{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
 #endif
-#if DROPBEAR_BLOWFISH
-	{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
-#endif
+#endif /* DROPBEAR_3DES */
+
+#if DROPBEAR_ENABLE_CBC_MODE
 #endif /* DROPBEAR_ENABLE_CBC_MODE */
 	{NULL, 0, NULL, 0, NULL}
 };
@@ -221,23 +236,31 @@
 	{NULL, 0, NULL, 0, NULL}
 };
 
-algo_type sshhostkey[] = {
+algo_type sigalgs[] = {
+#if DROPBEAR_ED25519
+	{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
+#endif
 #if DROPBEAR_ECDSA
 #if DROPBEAR_ECC_256
-	{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
+	{"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL},
 #endif
 #if DROPBEAR_ECC_384
-	{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
+	{"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL},
 #endif
 #if DROPBEAR_ECC_521
-	{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
+	{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
 #endif
 #endif
 #if DROPBEAR_RSA
-	{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
+#if DROPBEAR_RSA_SHA256
+	{"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL},
+#endif
+#if DROPBEAR_RSA_SHA1
+	{"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL},
+#endif
 #endif
 #if DROPBEAR_DSS
-	{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
+	{"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL},
 #endif
 	{NULL, 0, NULL, 0, NULL}
 };
@@ -255,8 +278,6 @@
 static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
 #endif
 
-/* These can't be const since dropbear_ecc_fill_dp() fills out
- ecc_curve at runtime */
 #if DROPBEAR_ECDH
 #if DROPBEAR_ECC_256
 static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
@@ -274,6 +295,7 @@
 static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
 #endif
 
+/* data == NULL for non-kex algorithm identifiers */
 algo_type sshkex[] = {
 #if DROPBEAR_CURVE25519
 	{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
@@ -303,49 +325,122 @@
 	{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
 #endif
 #if DROPBEAR_KEXGUESS2
-	{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
+	{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
+#endif
+#if DROPBEAR_EXT_INFO
+#if DROPBEAR_CLIENT
+	/* Set unusable by svr_algos_initialise() */
+	{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
+#endif
 #endif
 	{NULL, 0, NULL, 0, NULL}
 };
 
-/* algolen specifies the length of algo, algos is our local list to match
- * against.
- * Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
- * otherwise */
-int have_algo(const char* algo, size_t algolen, const algo_type algos[]) {
+/* Output a comma separated list of algorithms to a buffer */
+void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
+	unsigned int i, len;
+	unsigned int donefirst = 0;
+	unsigned int startpos;
 
-	int i;
-
-	for (i = 0; algos[i].name != NULL; i++) {
-		if (strlen(algos[i].name) == algolen
-				&& (strncmp(algos[i].name, algo, algolen) == 0)) {
-			return DROPBEAR_SUCCESS;
+	startpos = buf->pos;
+	/* Placeholder for length */
+	buf_putint(buf, 0); 
+	for (i = 0; localalgos[i].name != NULL; i++) {
+		if (localalgos[i].usable || useall) {
+			if (donefirst) {
+				buf_putbyte(buf, ',');
+			}
+			donefirst = 1;
+			len = strlen(localalgos[i].name);
+			buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
 		}
 	}
+	/* Fill out the length */
+	len = buf->pos - startpos - 4;
+	buf_setpos(buf, startpos);
+	buf_putint(buf, len);
+	TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
+	buf_incrwritepos(buf, len);
+}
 
-	return DROPBEAR_FAILURE;
+void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
+	buf_put_algolist_all(buf, localalgos, 0);
 }
 
-/* Output a comma separated list of algorithms to a buffer */
-void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
+/* returns a list of pointers into algolist, of null-terminated names.
+   ret_list should be passed in with space for *ret_count elements,
+   on return *ret_count has the number of names filled.
+   algolist is modified. */
+static void get_algolist(char* algolist, unsigned int algolist_len,
+				const char* *ret_list, unsigned int *ret_count) {
+	unsigned int max_count = *ret_count;
+	unsigned int i;
 
-	unsigned int i, len;
-	unsigned int donefirst = 0;
-	buffer *algolist = NULL;
+	if (*ret_count == 0) {
+		return;
+	}
+	if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
+		*ret_count = 0;
+		}
 
-	algolist = buf_new(300);
-	for (i = 0; localalgos[i].name != NULL; i++) {
-		if (localalgos[i].usable) {
-			if (donefirst)
-				buf_putbyte(algolist, ',');
-			donefirst = 1;
-			len = strlen(localalgos[i].name);
-			buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
+	/* ret_list will contain a list of the strings parsed out.
+	   We will have at least one string (even if it's just "") */
+	ret_list[0] = algolist;
+	*ret_count = 1;
+	for (i = 0; i < algolist_len; i++) {
+		if (algolist[i] == '\0') {
+			/* someone is trying something strange */
+			*ret_count = 0;
+			return;
+	}
+
+		if (algolist[i] == ',') {
+			if (*ret_count >= max_count) {
+				/* Too many */
+				*ret_count = 0;
+				return;
+			}
+			algolist[i] = '\0';
+			ret_list[*ret_count] = &algolist[i+1];
+			(*ret_count)++;
 		}
 	}
-	buf_putstring(buf, (const char*)algolist->data, algolist->len);
-	TRACE(("algolist add '%*s'", algolist->len, algolist->data))
-	buf_free(algolist);
+}
+
+/* Return DROPBEAR_SUCCESS if the namelist contains algo,
+DROPBEAR_FAILURE otherwise. buf position is not incremented. */
+int buf_has_algo(buffer *buf, const char *algo) {
+	unsigned char* algolist = NULL;
+	unsigned int orig_pos = buf->pos;
+	unsigned int len, remotecount, i;
+	const char *remotenames[MAX_PROPOSED_ALGO];
+	int ret = DROPBEAR_FAILURE;
+
+	algolist = buf_getstring(buf, &len);
+	remotecount = MAX_PROPOSED_ALGO;
+	get_algolist(algolist, len, remotenames, &remotecount);
+	for (i = 0; i < remotecount; i++)
+	{
+		if (strcmp(remotenames[i], algo) == 0) {
+			ret = DROPBEAR_SUCCESS;
+			break;
+		}
+	}
+	if (algolist) {
+		m_free(algolist);
+	}
+	buf_setpos(buf, orig_pos);
+	return ret;
+}
+
+algo_type * first_usable_algo(algo_type algos[]) {
+	int i;
+	for (i = 0; algos[i].name != NULL; i++) {
+		if (algos[i].usable) {
+			return &algos[i];
+		}
+	}
+	return NULL;
 }
 
 /* match the first algorithm in the comma-separated list in buf which is
@@ -354,9 +449,7 @@
  * 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
  * guessed correctly */
 algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
-		enum kexguess2_used *kexguess2, int *goodguess)
-{
-
+		int kexguess2, int *goodguess) {
 	char * algolist = NULL;
 	const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
 	unsigned int len;
@@ -371,40 +464,8 @@
 	/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
 	algolist = buf_getstring(buf, &len);
 	TRACE(("buf_match_algo: %s", algolist))
-	if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
-		goto out;
-	}
-
-	/* remotenames will contain a list of the strings parsed out */
-	/* We will have at least one string (even if it's just "") */
-	remotenames[0] = algolist;
-	remotecount = 1;
-	for (i = 0; i < len; i++) {
-		if (algolist[i] == '\0') {
-			/* someone is trying something strange */
-			goto out;
-		}
-		if (algolist[i] == ',') {
-			algolist[i] = '\0';
-			remotenames[remotecount] = &algolist[i+1];
-			remotecount++;
-		}
-		if (remotecount >= MAX_PROPOSED_ALGO) {
-			break;
-		}
-	}
-	if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
-		for (i = 0; i < remotecount; i++)
-		{
-			if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
-				*kexguess2 = KEXGUESS2_YES;
-				break;
-			}
-		}
-		if (*kexguess2 == KEXGUESS2_LOOK) {
-			*kexguess2 = KEXGUESS2_NO;
-		}
-	}
+	remotecount = MAX_PROPOSED_ALGO;
+	get_algolist(algolist, len, remotenames, &remotecount);
 
 	for (i = 0; localalgos[i].name != NULL; i++) {
 		if (localalgos[i].usable) {
@@ -436,12 +497,11 @@
 			}
 			if (strcmp(servnames[j], clinames[i]) == 0) {
 				/* set if it was a good guess */
-				if (goodguess && kexguess2) {
-					if (*kexguess2 == KEXGUESS2_YES) {
+				if (goodguess != NULL) {
+					if (kexguess2) {
 						if (i == 0) {
 							*goodguess = 1;
 						}
-
 					} else {
 						if (i == 0 && j == 0) {
 							*goodguess = 1;
--- a/common-kex.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/common-kex.c	Fri Jun 26 21:07:34 2020 +0800
@@ -36,6 +36,7 @@
 #include "dbrandom.h"
 #include "runopts.h"
 #include "ecc.h"
+#include "curve25519.h"
 #include "crypto_desc.h"
 
 static void kexinitialise(void);
@@ -64,7 +65,7 @@
 	buf_put_algolist(ses.writepayload, sshkex);
 
 	/* server_host_key_algorithms */
-	buf_put_algolist(ses.writepayload, sshhostkey);
+	buf_put_algolist(ses.writepayload, sigalgs);
 
 	/* encryption_algorithms_client_to_server */
 	buf_put_algolist(ses.writepayload, sshciphers);
@@ -109,8 +110,9 @@
 	ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
 
 	if (ses.send_kex_first_guess) {
-		ses.newkeys->algo_kex = sshkex[0].data;
-		ses.newkeys->algo_hostkey = sshhostkey[0].val;
+		ses.newkeys->algo_kex = first_usable_algo(sshkex)->data;
+		ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val;
+		ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
 		ses.send_kex_first_guess();
 	}
 
@@ -151,6 +153,7 @@
 		TRACE(("switch_keys done"))
 		ses.keys->algo_kex = ses.newkeys->algo_kex;
 		ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
+		ses.keys->algo_signature = ses.newkeys->algo_signature;
 		ses.keys->allow_compress = 0;
 		m_free(ses.newkeys);
 		ses.newkeys = NULL;
@@ -172,6 +175,9 @@
 	
 	/* set up our state */
 	ses.kexstate.sentnewkeys = 1;
+	if (ses.kexstate.donefirstkex) {
+		ses.kexstate.donesecondkex = 1;
+	}
 	ses.kexstate.donefirstkex = 1;
 	ses.dataallowed = 1; /* we can send other packets again now */
 	gen_new_keys();
@@ -194,8 +200,6 @@
 
 /* Set up the kex for the first time */
 void kexfirstinitialise() {
-	ses.kexstate.donefirstkex = 0;
-
 #ifdef DISABLE_ZLIB
 	ses.compress_algos = ssh_nocompress;
 #else
@@ -328,9 +332,13 @@
 	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, 
@@ -340,9 +348,13 @@
 	}
 
 	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, 
@@ -536,6 +548,7 @@
 	TRACE(("leave recv_msg_kexinit"))
 }
 
+#if DROPBEAR_NORMAL_DH
 static void load_dh_p(mp_int * dh_p)
 {
 	bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes, 
@@ -560,9 +573,7 @@
 	/* read the prime and generator*/
 	load_dh_p(&dh_p);
 	
-	if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
-		dropbear_exit("Diffie-Hellman error");
-	}
+	mp_set_ul(&dh_g, DH_G_VAL);
 
 	/* calculate q = (p-1)/2 */
 	/* dh_priv is just a temp var here */
@@ -646,6 +657,7 @@
 	/* calculate the hash H to sign */
 	finish_kexhashbuf();
 }
+#endif
 
 #if DROPBEAR_ECDH
 struct kex_ecdh_param *gen_kexecdh_param() {
@@ -703,23 +715,18 @@
 #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 +743,7 @@
 		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");
@@ -822,21 +829,36 @@
 	int goodguess = 0;
 	int allgood = 1; /* we AND this with each goodguess and see if its still
 						true after */
-
-#if DROPBEAR_KEXGUESS2
-	enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
-#else
-	enum kexguess2_used kexguess2 = KEXGUESS2_NO;
-#endif
+	int kexguess2 = 0;
 
 	buf_incrpos(ses.payload, 16); /* start after the cookie */
 
 	memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
 
 	/* kex_algorithms */
-	algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
+#if DROPBEAR_KEXGUESS2
+	if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) {
+		kexguess2 = 1;
+	}
+#endif
+
+#if DROPBEAR_EXT_INFO
+	/* Determine if SSH_MSG_EXT_INFO messages should be sent.
+	Should be done for the first key exchange. Only required on server side
+    for server-sig-algs */
+	if (IS_DROPBEAR_SERVER) {
+		if (!ses.kexstate.donefirstkex) {
+			if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) {
+				ses.allow_ext_info = 1;
+			}
+		}
+	}
+#endif
+
+	algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
 	allgood &= goodguess;
-	if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
+	if (algo == NULL || algo->data == NULL) {
+		/* kexguess2, ext-info-c, ext-info-s should not match negotiation */
 		erralgo = "kex";
 		goto error;
 	}
@@ -845,17 +867,18 @@
 	ses.newkeys->algo_kex = algo->data;
 
 	/* server_host_key_algorithms */
-	algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
+	algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess);
 	allgood &= goodguess;
 	if (algo == NULL) {
 		erralgo = "hostkey";
 		goto error;
 	}
-	TRACE(("hostkey algo %s", algo->name))
-	ses.newkeys->algo_hostkey = algo->val;
+	TRACE(("signature algo %s", algo->name))
+	ses.newkeys->algo_signature = algo->val;
+	ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
 
 	/* encryption_algorithms_client_to_server */
-	c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
+	c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
 	if (c2s_cipher_algo == NULL) {
 		erralgo = "enc c->s";
 		goto error;
@@ -863,7 +886,7 @@
 	TRACE(("enc c2s is  %s", c2s_cipher_algo->name))
 
 	/* encryption_algorithms_server_to_client */
-	s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
+	s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
 	if (s2c_cipher_algo == NULL) {
 		erralgo = "enc s->c";
 		goto error;
@@ -871,23 +894,33 @@
 	TRACE(("enc s2c is  %s", s2c_cipher_algo->name))
 
 	/* mac_algorithms_client_to_server */
-	c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
+	c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, 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 : "<implicit>"))
 
 	/* mac_algorithms_server_to_client */
-	s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
+	s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, 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 : "<implicit>"))
 
 	/* compression_algorithms_client_to_server */
-	c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
+	c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
 	if (c2s_comp_algo == NULL) {
 		erralgo = "comp c->s";
 		goto error;
@@ -895,7 +928,7 @@
 	TRACE(("hash c2s is  %s", c2s_comp_algo->name))
 
 	/* compression_algorithms_server_to_client */
-	s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
+	s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
 	if (s2c_comp_algo == NULL) {
 		erralgo = "comp s->c";
 		goto error;
@@ -929,8 +962,14 @@
 		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;
@@ -945,8 +984,14 @@
 		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;
--- a/common-runopts.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/common-runopts.c	Fri Jun 26 21:07:34 2020 +0800
@@ -64,44 +64,35 @@
 
 #if DROPBEAR_USER_ALGO_LIST
 void
-parse_ciphers_macs()
-{
-	if (opts.cipher_list)
-	{
-		if (strcmp(opts.cipher_list, "help") == 0)
-		{
+parse_ciphers_macs() {
+	int printed_help = 0;
+	if (opts.cipher_list) {
+		if (strcmp(opts.cipher_list, "help") == 0) {
 			char *ciphers = algolist_string(sshciphers);
-			dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
+			dropbear_log(LOG_INFO, "Available ciphers: %s", ciphers);
 			m_free(ciphers);
-			dropbear_exit(".");
-		}
-
-		if (strcmp(opts.cipher_list, "none") == 0)
-		{
-			/* Encryption is required during authentication */
-			opts.cipher_list = "none,aes128-ctr";
-		}
-
-		if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
-		{
-			dropbear_exit("No valid ciphers specified for '-c'");
+			printed_help = 1;
+		} else {
+			if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0) {
+				dropbear_exit("No valid ciphers specified for '-c'");
+			}
 		}
 	}
 
-	if (opts.mac_list)
-	{
-		if (strcmp(opts.mac_list, "help") == 0)
-		{
+	if (opts.mac_list) {
+		if (strcmp(opts.mac_list, "help") == 0) {
 			char *macs = algolist_string(sshhashes);
-			dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
+			dropbear_log(LOG_INFO, "Available MACs: %s", macs);
 			m_free(macs);
-			dropbear_exit(".");
+			printed_help = 1;
+		} else {
+			if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0) {
+				dropbear_exit("No valid MACs specified for '-m'");
+			}
 		}
-
-		if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
-		{
-			dropbear_exit("No valid MACs specified for '-m'");
-		}
+	}
+	if (printed_help) {
+		dropbear_exit(".");
 	}
 }
 #endif
--- a/common-session.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/common-session.c	Fri Jun 26 21:07:34 2020 +0800
@@ -147,6 +147,10 @@
 
 	ses.allowprivport = 0;
 
+#if DROPBEAR_PLUGIN
+        ses.plugin_session = NULL;
+#endif
+
 	TRACE(("leave session_init"))
 }
 
@@ -366,8 +370,11 @@
 	int len = 0;
 	char done = 0;
 	int i;
-	/* If they send more than 50 lines, something is wrong */
-	for (i = 0; i < 50; i++) {
+
+	/* Servers may send other lines of data before sending the
+	 * version string, client must be able to process such lines.
+	 * If they send more than 50 lines, something is wrong */
+	for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
 		len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
 
 		if (len < 0 && errno != EINTR) {
--- a/config.guess	Thu Mar 21 23:28:59 2019 +0800
+++ b/config.guess	Fri Jun 26 21:07:34 2020 +0800
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2019 Free Software Foundation, Inc.
 
-timestamp='2013-06-10'
+timestamp='2019-03-04'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
 # General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
 #
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
@@ -24,12 +24,12 @@
 # program.  This Exception is an additional permission under section 7
 # of the GNU General Public License, version 3 ("GPLv3").
 #
-# Originally written by Per Bothner.
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 #
-# Please send patches with a ChangeLog entry to [email protected]
+# Please send patches to <[email protected]>.
 
 
 me=`echo "$0" | sed -e 's,.*/,,'`
@@ -39,7 +39,7 @@
 
 Output the configuration name of the system \`$me' is run on.
 
-Operation modes:
+Options:
   -h, --help         print this help, then exit
   -t, --time-stamp   print date of last modification, then exit
   -v, --version      print version number, then exit
@@ -50,7 +50,7 @@
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2019 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -84,8 +84,6 @@
   exit 1
 fi
 
-trap 'exit 1' 1 2 15
-
 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a
 # compiler to aid in system detection is discouraged as it requires
 # temporary files to be created and, as you can see below, it is a
@@ -96,34 +94,38 @@
 
 # Portable tmp directory creation inspired by the Autoconf team.
 
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,)    echo "int x;" > $dummy.c ;
-	for c in cc gcc c89 c99 ; do
-	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
-	     CC_FOR_BUILD="$c"; break ;
-	  fi ;
-	done ;
-	if test x"$CC_FOR_BUILD" = x ; then
-	  CC_FOR_BUILD=no_compiler_found ;
-	fi
-	;;
- ,,*)   CC_FOR_BUILD=$CC ;;
- ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+    : "${TMPDIR=/tmp}"
+    # shellcheck disable=SC2039
+    { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+	{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+	{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+	{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+    dummy=$tmp/dummy
+    case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+	,,)    echo "int x;" > "$dummy.c"
+	       for driver in cc gcc c89 c99 ; do
+		   if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+		       CC_FOR_BUILD="$driver"
+		       break
+		   fi
+	       done
+	       if test x"$CC_FOR_BUILD" = x ; then
+		   CC_FOR_BUILD=no_compiler_found
+	       fi
+	       ;;
+	,,*)   CC_FOR_BUILD=$CC ;;
+	,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+    esac
+}
 
 # This is needed to find uname on a Pyramid OSx when run in the BSD universe.
 # ([email protected] 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+if test -f /.attbin/uname ; then
 	PATH=$PATH:/.attbin ; export PATH
 fi
 
@@ -132,14 +134,14 @@
 UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
 UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
 
-case "${UNAME_SYSTEM}" in
+case "$UNAME_SYSTEM" in
 Linux|GNU|GNU/*)
 	# If the system lacks a compiler, then just pick glibc.
 	# We could probably try harder.
 	LIBC=gnu
 
-	eval $set_cc_for_build
-	cat <<-EOF > $dummy.c
+	set_cc_for_build
+	cat <<-EOF > "$dummy.c"
 	#include <features.h>
 	#if defined(__UCLIBC__)
 	LIBC=uclibc
@@ -149,13 +151,20 @@
 	LIBC=gnu
 	#endif
 	EOF
-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+
+	# If ldd exists, use it to detect musl libc.
+	if command -v ldd >/dev/null && \
+		ldd --version 2>&1 | grep -q ^musl
+	then
+	    LIBC=musl
+	fi
 	;;
 esac
 
 # Note: order is significant - the case branches are not exclusive.
 
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
     *:NetBSD:*:*)
 	# NetBSD (nbsd) targets should (where applicable) match one or
 	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
@@ -168,21 +177,31 @@
 	# Note: NetBSD doesn't particularly care about the vendor
 	# portion of the name.  We always set it to "unknown".
 	sysctl="sysctl -n hw.machine_arch"
-	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
-	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
-	case "${UNAME_MACHINE_ARCH}" in
+	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+	    "/sbin/$sysctl" 2>/dev/null || \
+	    "/usr/sbin/$sysctl" 2>/dev/null || \
+	    echo unknown)`
+	case "$UNAME_MACHINE_ARCH" in
 	    armeb) machine=armeb-unknown ;;
 	    arm*) machine=arm-unknown ;;
 	    sh3el) machine=shl-unknown ;;
 	    sh3eb) machine=sh-unknown ;;
 	    sh5el) machine=sh5le-unknown ;;
-	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	    earmv*)
+		arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+		endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+		machine="${arch}${endian}"-unknown
+		;;
+	    *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
 	esac
 	# The Operating System including object format, if it has switched
-	# to ELF recently, or will in the future.
-	case "${UNAME_MACHINE_ARCH}" in
+	# to ELF recently (or will in the future) and ABI.
+	case "$UNAME_MACHINE_ARCH" in
+	    earm*)
+		os=netbsdelf
+		;;
 	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
-		eval $set_cc_for_build
+		set_cc_for_build
 		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
 			| grep -q __ELF__
 		then
@@ -197,44 +216,67 @@
 		os=netbsd
 		;;
 	esac
+	# Determine ABI tags.
+	case "$UNAME_MACHINE_ARCH" in
+	    earm*)
+		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+		abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+		;;
+	esac
 	# The OS release
 	# Debian GNU/NetBSD machines have a different userland, and
 	# thus, need a distinct triplet. However, they do not need
 	# kernel version information, so it can be replaced with a
 	# suitable tag, in the style of linux-gnu.
-	case "${UNAME_VERSION}" in
+	case "$UNAME_VERSION" in
 	    Debian*)
 		release='-gnu'
 		;;
 	    *)
-		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
 		;;
 	esac
 	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
 	# contains redundant information, the shorter form:
 	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-	echo "${machine}-${os}${release}"
+	echo "$machine-${os}${release}${abi-}"
 	exit ;;
     *:Bitrig:*:*)
 	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
-	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
 	exit ;;
     *:OpenBSD:*:*)
 	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
-	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
+	exit ;;
+    *:LibertyBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+	echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
+	exit ;;
+    *:MidnightBSD:*:*)
+	echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
 	exit ;;
     *:ekkoBSD:*:*)
-	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
 	exit ;;
     *:SolidBSD:*:*)
-	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
 	exit ;;
     macppc:MirBSD:*:*)
-	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
 	exit ;;
     *:MirBSD:*:*)
-	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
+	exit ;;
+    *:Sortix:*:*)
+	echo "$UNAME_MACHINE"-unknown-sortix
 	exit ;;
+    *:Redox:*:*)
+	echo "$UNAME_MACHINE"-unknown-redox
+	exit ;;
+    mips:OSF1:*.*)
+        echo mips-dec-osf1
+        exit ;;
     alpha:OSF1:*:*)
 	case $UNAME_RELEASE in
 	*4.0)
@@ -251,63 +293,54 @@
 	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
 	case "$ALPHA_CPU_TYPE" in
 	    "EV4 (21064)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "EV4.5 (21064)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "LCA4 (21066/21068)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "EV5 (21164)")
-		UNAME_MACHINE="alphaev5" ;;
+		UNAME_MACHINE=alphaev5 ;;
 	    "EV5.6 (21164A)")
-		UNAME_MACHINE="alphaev56" ;;
+		UNAME_MACHINE=alphaev56 ;;
 	    "EV5.6 (21164PC)")
-		UNAME_MACHINE="alphapca56" ;;
+		UNAME_MACHINE=alphapca56 ;;
 	    "EV5.7 (21164PC)")
-		UNAME_MACHINE="alphapca57" ;;
+		UNAME_MACHINE=alphapca57 ;;
 	    "EV6 (21264)")
-		UNAME_MACHINE="alphaev6" ;;
+		UNAME_MACHINE=alphaev6 ;;
 	    "EV6.7 (21264A)")
-		UNAME_MACHINE="alphaev67" ;;
+		UNAME_MACHINE=alphaev67 ;;
 	    "EV6.8CB (21264C)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.8AL (21264B)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.8CX (21264D)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.9A (21264/EV69A)")
-		UNAME_MACHINE="alphaev69" ;;
+		UNAME_MACHINE=alphaev69 ;;
 	    "EV7 (21364)")
-		UNAME_MACHINE="alphaev7" ;;
+		UNAME_MACHINE=alphaev7 ;;
 	    "EV7.9 (21364A)")
-		UNAME_MACHINE="alphaev79" ;;
+		UNAME_MACHINE=alphaev79 ;;
 	esac
 	# A Pn.n version is a patched version.
 	# A Vn.n version is a released version.
 	# A Tn.n version is a released field test version.
 	# A Xn.n version is an unreleased experimental baselevel.
 	# 1.2 uses "1.2" for uname -r.
-	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
 	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
 	exitcode=$?
 	trap '' 0
 	exit $exitcode ;;
-    Alpha\ *:Windows_NT*:*)
-	# How do we know it's Interix rather than the generic POSIX subsystem?
-	# Should we change UNAME_MACHINE based on the output of uname instead
-	# of the specific Alpha model?
-	echo alpha-pc-interix
-	exit ;;
-    21064:Windows_NT:50:3)
-	echo alpha-dec-winnt3.5
-	exit ;;
     Amiga*:UNIX_System_V:4.0:*)
 	echo m68k-unknown-sysv4
 	exit ;;
     *:[Aa]miga[Oo][Ss]:*:*)
-	echo ${UNAME_MACHINE}-unknown-amigaos
+	echo "$UNAME_MACHINE"-unknown-amigaos
 	exit ;;
     *:[Mm]orph[Oo][Ss]:*:*)
-	echo ${UNAME_MACHINE}-unknown-morphos
+	echo "$UNAME_MACHINE"-unknown-morphos
 	exit ;;
     *:OS/390:*:*)
 	echo i370-ibm-openedition
@@ -319,7 +352,7 @@
 	echo powerpc-ibm-os400
 	exit ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
-	echo arm-acorn-riscix${UNAME_RELEASE}
+	echo arm-acorn-riscix"$UNAME_RELEASE"
 	exit ;;
     arm*:riscos:*:*|arm*:RISCOS:*:*)
 	echo arm-unknown-riscos
@@ -346,38 +379,38 @@
 	    sparc) echo sparc-icl-nx7; exit ;;
 	esac ;;
     s390x:SunOS:*:*)
-	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
 	exit ;;
     sun4H:SunOS:5.*:*)
-	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
 	exit ;;
     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
 	exit ;;
     i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
-	echo i386-pc-auroraux${UNAME_RELEASE}
+	echo i386-pc-auroraux"$UNAME_RELEASE"
 	exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
-	eval $set_cc_for_build
-	SUN_ARCH="i386"
+	set_cc_for_build
+	SUN_ARCH=i386
 	# If there is a compiler, see if it is configured for 64-bit objects.
 	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
 	# This test works for both compilers.
-	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
 	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
 		grep IS_64BIT_ARCH >/dev/null
 	    then
-		SUN_ARCH="x86_64"
+		SUN_ARCH=x86_64
 	    fi
 	fi
-	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
 	exit ;;
     sun4*:SunOS:6*:*)
 	# According to config.sub, this is the proper way to canonicalize
 	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
 	# it's likely to be more like Solaris than SunOS4.
-	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
 	exit ;;
     sun4*:SunOS:*:*)
 	case "`/usr/bin/arch -k`" in
@@ -386,25 +419,25 @@
 		;;
 	esac
 	# Japanese Language versions have a version number like `4.1.3-JL'.
-	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
 	exit ;;
     sun3*:SunOS:*:*)
-	echo m68k-sun-sunos${UNAME_RELEASE}
+	echo m68k-sun-sunos"$UNAME_RELEASE"
 	exit ;;
     sun*:*:4.2BSD:*)
 	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
-	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
 	case "`/bin/arch`" in
 	    sun3)
-		echo m68k-sun-sunos${UNAME_RELEASE}
+		echo m68k-sun-sunos"$UNAME_RELEASE"
 		;;
 	    sun4)
-		echo sparc-sun-sunos${UNAME_RELEASE}
+		echo sparc-sun-sunos"$UNAME_RELEASE"
 		;;
 	esac
 	exit ;;
     aushp:SunOS:*:*)
-	echo sparc-auspex-sunos${UNAME_RELEASE}
+	echo sparc-auspex-sunos"$UNAME_RELEASE"
 	exit ;;
     # The situation for MiNT is a little confusing.  The machine name
     # can be virtually everything (everything which is not
@@ -415,44 +448,44 @@
     # MiNT.  But MiNT is downward compatible to TOS, so this should
     # be no problem.
     atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-	echo m68k-atari-mint${UNAME_RELEASE}
+	echo m68k-atari-mint"$UNAME_RELEASE"
 	exit ;;
     atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
-	echo m68k-atari-mint${UNAME_RELEASE}
+	echo m68k-atari-mint"$UNAME_RELEASE"
 	exit ;;
     *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-	echo m68k-atari-mint${UNAME_RELEASE}
+	echo m68k-atari-mint"$UNAME_RELEASE"
 	exit ;;
     milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-	echo m68k-milan-mint${UNAME_RELEASE}
+	echo m68k-milan-mint"$UNAME_RELEASE"
 	exit ;;
     hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-	echo m68k-hades-mint${UNAME_RELEASE}
+	echo m68k-hades-mint"$UNAME_RELEASE"
 	exit ;;
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-	echo m68k-unknown-mint${UNAME_RELEASE}
+	echo m68k-unknown-mint"$UNAME_RELEASE"
 	exit ;;
     m68k:machten:*:*)
-	echo m68k-apple-machten${UNAME_RELEASE}
+	echo m68k-apple-machten"$UNAME_RELEASE"
 	exit ;;
     powerpc:machten:*:*)
-	echo powerpc-apple-machten${UNAME_RELEASE}
+	echo powerpc-apple-machten"$UNAME_RELEASE"
 	exit ;;
     RISC*:Mach:*:*)
 	echo mips-dec-mach_bsd4.3
 	exit ;;
     RISC*:ULTRIX:*:*)
-	echo mips-dec-ultrix${UNAME_RELEASE}
+	echo mips-dec-ultrix"$UNAME_RELEASE"
 	exit ;;
     VAX*:ULTRIX*:*:*)
-	echo vax-dec-ultrix${UNAME_RELEASE}
+	echo vax-dec-ultrix"$UNAME_RELEASE"
 	exit ;;
     2020:CLIX:*:* | 2430:CLIX:*:*)
-	echo clipper-intergraph-clix${UNAME_RELEASE}
+	echo clipper-intergraph-clix"$UNAME_RELEASE"
 	exit ;;
     mips:*:*:UMIPS | mips:*:*:RISCos)
-	eval $set_cc_for_build
-	sed 's/^	//' << EOF >$dummy.c
+	set_cc_for_build
+	sed 's/^	//' << EOF > "$dummy.c"
 #ifdef __cplusplus
 #include <stdio.h>  /* for printf() prototype */
 	int main (int argc, char *argv[]) {
@@ -461,23 +494,23 @@
 #endif
 	#if defined (host_mips) && defined (MIPSEB)
 	#if defined (SYSTYPE_SYSV)
-	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	  printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
 	#endif
 	#if defined (SYSTYPE_SVR4)
-	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	  printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
 	#endif
 	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
-	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	  printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
 	#endif
 	#endif
 	  exit (-1);
 	}
 EOF
-	$CC_FOR_BUILD -o $dummy $dummy.c &&
-	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
-	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	$CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+	  dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
 	    { echo "$SYSTEM_NAME"; exit; }
-	echo mips-mips-riscos${UNAME_RELEASE}
+	echo mips-mips-riscos"$UNAME_RELEASE"
 	exit ;;
     Motorola:PowerMAX_OS:*:*)
 	echo powerpc-motorola-powermax
@@ -503,17 +536,17 @@
     AViiON:dgux:*:*)
 	# DG/UX returns AViiON for all architectures
 	UNAME_PROCESSOR=`/usr/bin/uname -p`
-	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
 	then
-	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
-	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
+	       [ "$TARGET_BINARY_INTERFACE"x = x ]
 	    then
-		echo m88k-dg-dgux${UNAME_RELEASE}
+		echo m88k-dg-dgux"$UNAME_RELEASE"
 	    else
-		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+		echo m88k-dg-dguxbcs"$UNAME_RELEASE"
 	    fi
 	else
-	    echo i586-dg-dgux${UNAME_RELEASE}
+	    echo i586-dg-dgux"$UNAME_RELEASE"
 	fi
 	exit ;;
     M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
@@ -530,7 +563,7 @@
 	echo m68k-tektronix-bsd
 	exit ;;
     *:IRIX*:*:*)
-	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
 	exit ;;
     ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
 	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
@@ -542,14 +575,14 @@
 	if [ -x /usr/bin/oslevel ] ; then
 		IBM_REV=`/usr/bin/oslevel`
 	else
-		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
 	fi
-	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
 	exit ;;
     *:AIX:2:3)
 	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
-		eval $set_cc_for_build
-		sed 's/^		//' << EOF >$dummy.c
+		set_cc_for_build
+		sed 's/^		//' << EOF > "$dummy.c"
 		#include <sys/systemcfg.h>
 
 		main()
@@ -560,7 +593,7 @@
 			exit(0);
 			}
 EOF
-		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
 		then
 			echo "$SYSTEM_NAME"
 		else
@@ -574,26 +607,27 @@
 	exit ;;
     *:AIX:*:[4567])
 	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
-	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+	if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
 		IBM_ARCH=rs6000
 	else
 		IBM_ARCH=powerpc
 	fi
-	if [ -x /usr/bin/oslevel ] ; then
-		IBM_REV=`/usr/bin/oslevel`
+	if [ -x /usr/bin/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
 	else
-		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
 	fi
-	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
 	exit ;;
     *:AIX:*:*)
 	echo rs6000-ibm-aix
 	exit ;;
-    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+    ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
 	echo romp-ibm-bsd4.4
 	exit ;;
     ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
-	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	echo romp-ibm-bsd"$UNAME_RELEASE"   # 4.3 with uname added to
 	exit ;;                             # report: romp-ibm BSD 4.3
     *:BOSX:*:*)
 	echo rs6000-bull-bosx
@@ -608,28 +642,28 @@
 	echo m68k-hp-bsd4.4
 	exit ;;
     9000/[34678]??:HP-UX:*:*)
-	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
-	case "${UNAME_MACHINE}" in
-	    9000/31? )            HP_ARCH=m68000 ;;
-	    9000/[34]?? )         HP_ARCH=m68k ;;
+	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+	case "$UNAME_MACHINE" in
+	    9000/31?)            HP_ARCH=m68000 ;;
+	    9000/[34]??)         HP_ARCH=m68k ;;
 	    9000/[678][0-9][0-9])
 		if [ -x /usr/bin/getconf ]; then
 		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
 		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
-		    case "${sc_cpu_version}" in
-		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
-		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		    case "$sc_cpu_version" in
+		      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
 		      532)                      # CPU_PA_RISC2_0
-			case "${sc_kernel_bits}" in
-			  32) HP_ARCH="hppa2.0n" ;;
-			  64) HP_ARCH="hppa2.0w" ;;
-			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			case "$sc_kernel_bits" in
+			  32) HP_ARCH=hppa2.0n ;;
+			  64) HP_ARCH=hppa2.0w ;;
+			  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
 			esac ;;
 		    esac
 		fi
-		if [ "${HP_ARCH}" = "" ]; then
-		    eval $set_cc_for_build
-		    sed 's/^		//' << EOF >$dummy.c
+		if [ "$HP_ARCH" = "" ]; then
+		    set_cc_for_build
+		    sed 's/^		//' << EOF > "$dummy.c"
 
 		#define _HPUX_SOURCE
 		#include <stdlib.h>
@@ -662,13 +696,13 @@
 		    exit (0);
 		}
 EOF
-		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
 		    test -z "$HP_ARCH" && HP_ARCH=hppa
 		fi ;;
 	esac
-	if [ ${HP_ARCH} = "hppa2.0w" ]
+	if [ "$HP_ARCH" = hppa2.0w ]
 	then
-	    eval $set_cc_for_build
+	    set_cc_for_build
 
 	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
 	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
@@ -679,23 +713,23 @@
 	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
 	    # => hppa64-hp-hpux11.23
 
-	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+	    if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
 		grep -q __LP64__
 	    then
-		HP_ARCH="hppa2.0w"
+		HP_ARCH=hppa2.0w
 	    else
-		HP_ARCH="hppa64"
+		HP_ARCH=hppa64
 	    fi
 	fi
-	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
 	exit ;;
     ia64:HP-UX:*:*)
-	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
-	echo ia64-hp-hpux${HPUX_REV}
+	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux"$HPUX_REV"
 	exit ;;
     3050*:HI-UX:*:*)
-	eval $set_cc_for_build
-	sed 's/^	//' << EOF >$dummy.c
+	set_cc_for_build
+	sed 's/^	//' << EOF > "$dummy.c"
 	#include <unistd.h>
 	int
 	main ()
@@ -720,11 +754,11 @@
 	  exit (0);
 	}
 EOF
-	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+	$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
 		{ echo "$SYSTEM_NAME"; exit; }
 	echo unknown-hitachi-hiuxwe2
 	exit ;;
-    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
 	echo hppa1.1-hp-bsd
 	exit ;;
     9000/8??:4.3bsd:*:*)
@@ -733,7 +767,7 @@
     *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
 	echo hppa1.0-hp-mpeix
 	exit ;;
-    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
 	echo hppa1.1-hp-osf
 	exit ;;
     hp8??:OSF1:*:*)
@@ -741,9 +775,9 @@
 	exit ;;
     i*86:OSF1:*:*)
 	if [ -x /usr/sbin/sysversion ] ; then
-	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	    echo "$UNAME_MACHINE"-unknown-osf1mk
 	else
-	    echo ${UNAME_MACHINE}-unknown-osf1
+	    echo "$UNAME_MACHINE"-unknown-osf1
 	fi
 	exit ;;
     parisc*:Lites*:*:*)
@@ -768,127 +802,120 @@
 	echo c4-convex-bsd
 	exit ;;
     CRAY*Y-MP:*:*:*)
-	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
     CRAY*[A-Z]90:*:*:*)
-	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
 	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
 	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
 	      -e 's/\.[^.]*$/.X/'
 	exit ;;
     CRAY*TS:*:*:*)
-	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
     CRAY*T3E:*:*:*)
-	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
     CRAY*SV1:*:*:*)
-	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
     *:UNICOS/mp:*:*)
-	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
 	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
     5000:UNIX_System_V:4.*:*)
-	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
 	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
-	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
 	exit ;;
     sparc*:BSD/OS:*:*)
-	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	echo sparc-unknown-bsdi"$UNAME_RELEASE"
 	exit ;;
     *:BSD/OS:*:*)
-	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
+	exit ;;
+    arm:FreeBSD:*:*)
+	UNAME_PROCESSOR=`uname -p`
+	set_cc_for_build
+	if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_PCS_VFP
+	then
+	    echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
+	else
+	    echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
+	fi
 	exit ;;
     *:FreeBSD:*:*)
 	UNAME_PROCESSOR=`/usr/bin/uname -p`
-	case ${UNAME_PROCESSOR} in
+	case "$UNAME_PROCESSOR" in
 	    amd64)
-		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
-	    *)
-		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+		UNAME_PROCESSOR=x86_64 ;;
+	    i386)
+		UNAME_PROCESSOR=i586 ;;
 	esac
+	echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
 	exit ;;
     i*:CYGWIN*:*)
-	echo ${UNAME_MACHINE}-pc-cygwin
+	echo "$UNAME_MACHINE"-pc-cygwin
 	exit ;;
     *:MINGW64*:*)
-	echo ${UNAME_MACHINE}-pc-mingw64
+	echo "$UNAME_MACHINE"-pc-mingw64
 	exit ;;
     *:MINGW*:*)
-	echo ${UNAME_MACHINE}-pc-mingw32
+	echo "$UNAME_MACHINE"-pc-mingw32
 	exit ;;
-    i*:MSYS*:*)
-	echo ${UNAME_MACHINE}-pc-msys
-	exit ;;
-    i*:windows32*:*)
-	# uname -m includes "-pc" on this system.
-	echo ${UNAME_MACHINE}-mingw32
+    *:MSYS*:*)
+	echo "$UNAME_MACHINE"-pc-msys
 	exit ;;
     i*:PW*:*)
-	echo ${UNAME_MACHINE}-pc-pw32
+	echo "$UNAME_MACHINE"-pc-pw32
 	exit ;;
     *:Interix*:*)
-	case ${UNAME_MACHINE} in
+	case "$UNAME_MACHINE" in
 	    x86)
-		echo i586-pc-interix${UNAME_RELEASE}
+		echo i586-pc-interix"$UNAME_RELEASE"
 		exit ;;
 	    authenticamd | genuineintel | EM64T)
-		echo x86_64-unknown-interix${UNAME_RELEASE}
+		echo x86_64-unknown-interix"$UNAME_RELEASE"
 		exit ;;
 	    IA64)
-		echo ia64-unknown-interix${UNAME_RELEASE}
+		echo ia64-unknown-interix"$UNAME_RELEASE"
 		exit ;;
 	esac ;;
-    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
-	echo i${UNAME_MACHINE}-pc-mks
-	exit ;;
-    8664:Windows_NT:*)
-	echo x86_64-pc-mks
-	exit ;;
-    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
-	# How do we know it's Interix rather than the generic POSIX subsystem?
-	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
-	# UNAME_MACHINE based on the output of uname instead of i386?
-	echo i586-pc-interix
-	exit ;;
     i*:UWIN*:*)
-	echo ${UNAME_MACHINE}-pc-uwin
+	echo "$UNAME_MACHINE"-pc-uwin
 	exit ;;
     amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
-	echo x86_64-unknown-cygwin
-	exit ;;
-    p*:CYGWIN*:*)
-	echo powerpcle-unknown-cygwin
+	echo x86_64-pc-cygwin
 	exit ;;
     prep*:SunOS:5.*:*)
-	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
 	exit ;;
     *:GNU:*:*)
 	# the GNU system
-	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
 	exit ;;
     *:GNU/*:*:*)
 	# other systems with GNU libc and userland
-	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
 	exit ;;
-    i*86:Minix:*:*)
-	echo ${UNAME_MACHINE}-pc-minix
+    *:Minix:*:*)
+	echo "$UNAME_MACHINE"-unknown-minix
 	exit ;;
     aarch64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     aarch64_be:Linux:*:*)
 	UNAME_MACHINE=aarch64_be
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     alpha:Linux:*:*)
 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -901,129 +928,169 @@
 	  EV68*) UNAME_MACHINE=alphaev68 ;;
 	esac
 	objdump --private-headers /bin/sh | grep -q ld.so.1
-	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     arc:Linux:*:* | arceb:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     arm*:Linux:*:*)
-	eval $set_cc_for_build
+	set_cc_for_build
 	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
 	    | grep -q __ARM_EABI__
 	then
-	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	    echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	else
 	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
 		| grep -q __ARM_PCS_VFP
 	    then
-		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+		echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
 	    else
-		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+		echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
 	    fi
 	fi
 	exit ;;
     avr32*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     cris:Linux:*:*)
-	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
 	exit ;;
     crisv32:Linux:*:*)
-	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+	exit ;;
+    e2k:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     frv:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     hexagon:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     i*86:Linux:*:*)
-	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
 	exit ;;
     ia64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    k1om:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     m32r*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     m68*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     mips:Linux:*:* | mips64:Linux:*:*)
-	eval $set_cc_for_build
-	sed 's/^	//' << EOF >$dummy.c
+	set_cc_for_build
+	IS_GLIBC=0
+	test x"${LIBC}" = xgnu && IS_GLIBC=1
+	sed 's/^	//' << EOF > "$dummy.c"
 	#undef CPU
-	#undef ${UNAME_MACHINE}
-	#undef ${UNAME_MACHINE}el
+	#undef mips
+	#undef mipsel
+	#undef mips64
+	#undef mips64el
+	#if ${IS_GLIBC} && defined(_ABI64)
+	LIBCABI=gnuabi64
+	#else
+	#if ${IS_GLIBC} && defined(_ABIN32)
+	LIBCABI=gnuabin32
+	#else
+	LIBCABI=${LIBC}
+	#endif
+	#endif
+
+	#if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+	CPU=mipsisa64r6
+	#else
+	#if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+	CPU=mipsisa32r6
+	#else
+	#if defined(__mips64)
+	CPU=mips64
+	#else
+	CPU=mips
+	#endif
+	#endif
+	#endif
+
 	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-	CPU=${UNAME_MACHINE}el
+	MIPS_ENDIAN=el
 	#else
 	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-	CPU=${UNAME_MACHINE}
+	MIPS_ENDIAN=
 	#else
-	CPU=
+	MIPS_ENDIAN=
 	#endif
 	#endif
 EOF
-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
-	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`"
+	test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
 	;;
-    or1k:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+    mips64el:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
-    or32:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-"$LIBC"
+	exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     padre:Linux:*:*)
-	echo sparc-unknown-linux-${LIBC}
+	echo sparc-unknown-linux-"$LIBC"
 	exit ;;
     parisc64:Linux:*:* | hppa64:Linux:*:*)
-	echo hppa64-unknown-linux-${LIBC}
+	echo hppa64-unknown-linux-"$LIBC"
 	exit ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
 	# Look for CPU level
 	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
-	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
-	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
-	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	  PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
+	  PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
+	  *)    echo hppa-unknown-linux-"$LIBC" ;;
 	esac
 	exit ;;
     ppc64:Linux:*:*)
-	echo powerpc64-unknown-linux-${LIBC}
+	echo powerpc64-unknown-linux-"$LIBC"
 	exit ;;
     ppc:Linux:*:*)
-	echo powerpc-unknown-linux-${LIBC}
+	echo powerpc-unknown-linux-"$LIBC"
 	exit ;;
     ppc64le:Linux:*:*)
-	echo powerpc64le-unknown-linux-${LIBC}
+	echo powerpc64le-unknown-linux-"$LIBC"
 	exit ;;
     ppcle:Linux:*:*)
-	echo powerpcle-unknown-linux-${LIBC}
+	echo powerpcle-unknown-linux-"$LIBC"
+	exit ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     s390:Linux:*:* | s390x:Linux:*:*)
-	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
 	exit ;;
     sh64*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     sh*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     sparc:Linux:*:* | sparc64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     tile*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     vax:Linux:*:*)
-	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
 	exit ;;
     x86_64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
 	exit ;;
     xtensa*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
 	exit ;;
     i*86:DYNIX/ptx:4*:*)
 	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
@@ -1037,34 +1104,34 @@
 	# I am not positive that other SVR4 systems won't match this,
 	# I just have to hope.  -- rms.
 	# Use sysv4.2uw... so that sysv4* matches it.
-	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
 	exit ;;
     i*86:OS/2:*:*)
 	# If we were able to find `uname', then EMX Unix compatibility
 	# is probably installed.
-	echo ${UNAME_MACHINE}-pc-os2-emx
+	echo "$UNAME_MACHINE"-pc-os2-emx
 	exit ;;
     i*86:XTS-300:*:STOP)
-	echo ${UNAME_MACHINE}-unknown-stop
+	echo "$UNAME_MACHINE"-unknown-stop
 	exit ;;
     i*86:atheos:*:*)
-	echo ${UNAME_MACHINE}-unknown-atheos
+	echo "$UNAME_MACHINE"-unknown-atheos
 	exit ;;
     i*86:syllable:*:*)
-	echo ${UNAME_MACHINE}-pc-syllable
+	echo "$UNAME_MACHINE"-pc-syllable
 	exit ;;
     i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
-	echo i386-unknown-lynxos${UNAME_RELEASE}
+	echo i386-unknown-lynxos"$UNAME_RELEASE"
 	exit ;;
     i*86:*DOS:*:*)
-	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	echo "$UNAME_MACHINE"-pc-msdosdjgpp
 	exit ;;
-    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
-	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+    i*86:*:4.*:*)
+	UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
 	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+		echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
 	else
-		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+		echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
 	fi
 	exit ;;
     i*86:*:5:[678]*)
@@ -1074,12 +1141,12 @@
 	    *Pentium)	     UNAME_MACHINE=i586 ;;
 	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
 	esac
-	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
 	exit ;;
     i*86:*:3.2:*)
 	if test -f /usr/options/cb.name; then
 		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
-		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+		echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
 	elif /bin/uname -X 2>/dev/null >/dev/null ; then
 		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
 		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
@@ -1089,9 +1156,9 @@
 			&& UNAME_MACHINE=i686
 		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
 			&& UNAME_MACHINE=i686
-		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+		echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
 	else
-		echo ${UNAME_MACHINE}-pc-sysv32
+		echo "$UNAME_MACHINE"-pc-sysv32
 	fi
 	exit ;;
     pc:*:*:*)
@@ -1099,7 +1166,7 @@
 	# uname -m prints for DJGPP always 'pc', but it prints nothing about
 	# the processor, so we play safe by assuming i586.
 	# Note: whatever this is, it MUST be the same as what config.sub
-	# prints for the "djgpp" host, or else GDB configury will decide that
+	# prints for the "djgpp" host, or else GDB configure will decide that
 	# this is a cross-build.
 	echo i586-pc-msdosdjgpp
 	exit ;;
@@ -1111,9 +1178,9 @@
 	exit ;;
     i860:*:4.*:*) # i860-SVR4
 	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
-	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	  echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
 	else # Add other i860-SVR4 vendors below as they are discovered.
-	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	  echo i860-unknown-sysv"$UNAME_RELEASE"  # Unknown i860-SVR4
 	fi
 	exit ;;
     mini*:CTIX:SYS*5:*)
@@ -1133,9 +1200,9 @@
 	test -r /etc/.relid \
 	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
 	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	  && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
-	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+	  && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
     3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
 	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
 	  && { echo i486-ncr-sysv4; exit; } ;;
@@ -1144,28 +1211,28 @@
 	test -r /etc/.relid \
 	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
 	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	    && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
-	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	    && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
 	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
-	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+	    && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
     m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
-	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	echo m68k-unknown-lynxos"$UNAME_RELEASE"
 	exit ;;
     mc68030:UNIX_System_V:4.*:*)
 	echo m68k-atari-sysv4
 	exit ;;
     TSUNAMI:LynxOS:2.*:*)
-	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	echo sparc-unknown-lynxos"$UNAME_RELEASE"
 	exit ;;
     rs6000:LynxOS:2.*:*)
-	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	echo rs6000-unknown-lynxos"$UNAME_RELEASE"
 	exit ;;
     PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
-	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	echo powerpc-unknown-lynxos"$UNAME_RELEASE"
 	exit ;;
     SM[BE]S:UNIX_SV:*:*)
-	echo mips-dde-sysv${UNAME_RELEASE}
+	echo mips-dde-sysv"$UNAME_RELEASE"
 	exit ;;
     RM*:ReliantUNIX-*:*:*)
 	echo mips-sni-sysv4
@@ -1176,7 +1243,7 @@
     *:SINIX-*:*:*)
 	if uname -p 2>/dev/null >/dev/null ; then
 		UNAME_MACHINE=`(uname -p) 2>/dev/null`
-		echo ${UNAME_MACHINE}-sni-sysv4
+		echo "$UNAME_MACHINE"-sni-sysv4
 	else
 		echo ns32k-sni-sysv
 	fi
@@ -1196,23 +1263,23 @@
 	exit ;;
     i*86:VOS:*:*)
 	# From [email protected]
-	echo ${UNAME_MACHINE}-stratus-vos
+	echo "$UNAME_MACHINE"-stratus-vos
 	exit ;;
     *:VOS:*:*)
 	# From [email protected]
 	echo hppa1.1-stratus-vos
 	exit ;;
     mc68*:A/UX:*:*)
-	echo m68k-apple-aux${UNAME_RELEASE}
+	echo m68k-apple-aux"$UNAME_RELEASE"
 	exit ;;
     news*:NEWS-OS:6*:*)
 	echo mips-sony-newsos6
 	exit ;;
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
 	if [ -d /usr/nec ]; then
-		echo mips-nec-sysv${UNAME_RELEASE}
+		echo mips-nec-sysv"$UNAME_RELEASE"
 	else
-		echo mips-unknown-sysv${UNAME_RELEASE}
+		echo mips-unknown-sysv"$UNAME_RELEASE"
 	fi
 	exit ;;
     BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
@@ -1231,67 +1298,93 @@
 	echo x86_64-unknown-haiku
 	exit ;;
     SX-4:SUPER-UX:*:*)
-	echo sx4-nec-superux${UNAME_RELEASE}
+	echo sx4-nec-superux"$UNAME_RELEASE"
 	exit ;;
     SX-5:SUPER-UX:*:*)
-	echo sx5-nec-superux${UNAME_RELEASE}
+	echo sx5-nec-superux"$UNAME_RELEASE"
 	exit ;;
     SX-6:SUPER-UX:*:*)
-	echo sx6-nec-superux${UNAME_RELEASE}
+	echo sx6-nec-superux"$UNAME_RELEASE"
 	exit ;;
     SX-7:SUPER-UX:*:*)
-	echo sx7-nec-superux${UNAME_RELEASE}
+	echo sx7-nec-superux"$UNAME_RELEASE"
 	exit ;;
     SX-8:SUPER-UX:*:*)
-	echo sx8-nec-superux${UNAME_RELEASE}
+	echo sx8-nec-superux"$UNAME_RELEASE"
 	exit ;;
     SX-8R:SUPER-UX:*:*)
-	echo sx8r-nec-superux${UNAME_RELEASE}
+	echo sx8r-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    SX-ACE:SUPER-UX:*:*)
+	echo sxace-nec-superux"$UNAME_RELEASE"
 	exit ;;
     Power*:Rhapsody:*:*)
-	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	echo powerpc-apple-rhapsody"$UNAME_RELEASE"
 	exit ;;
     *:Rhapsody:*:*)
-	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
 	exit ;;
     *:Darwin:*:*)
 	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-	eval $set_cc_for_build
+	set_cc_for_build
 	if test "$UNAME_PROCESSOR" = unknown ; then
 	    UNAME_PROCESSOR=powerpc
 	fi
-	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-		grep IS_64BIT_ARCH >/dev/null
-	    then
-		case $UNAME_PROCESSOR in
-		    i386) UNAME_PROCESSOR=x86_64 ;;
-		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
-		esac
+	if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		       (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		       grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
+		# On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+		if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+		       (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		       grep IS_PPC >/dev/null
+		then
+		    UNAME_PROCESSOR=powerpc
+		fi
 	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
 	fi
-	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
 	exit ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
 	UNAME_PROCESSOR=`uname -p`
-	if test "$UNAME_PROCESSOR" = "x86"; then
+	if test "$UNAME_PROCESSOR" = x86; then
 		UNAME_PROCESSOR=i386
 		UNAME_MACHINE=pc
 	fi
-	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
 	exit ;;
     *:QNX:*:4*)
 	echo i386-pc-qnx
 	exit ;;
-    NEO-?:NONSTOP_KERNEL:*:*)
-	echo neo-tandem-nsk${UNAME_RELEASE}
+    NEO-*:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk"$UNAME_RELEASE"
 	exit ;;
     NSE-*:NONSTOP_KERNEL:*:*)
-	echo nse-tandem-nsk${UNAME_RELEASE}
+	echo nse-tandem-nsk"$UNAME_RELEASE"
+	exit ;;
+    NSR-*:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk"$UNAME_RELEASE"
 	exit ;;
-    NSR-?:NONSTOP_KERNEL:*:*)
-	echo nsr-tandem-nsk${UNAME_RELEASE}
+    NSV-*:NONSTOP_KERNEL:*:*)
+	echo nsv-tandem-nsk"$UNAME_RELEASE"
+	exit ;;
+    NSX-*:NONSTOP_KERNEL:*:*)
+	echo nsx-tandem-nsk"$UNAME_RELEASE"
 	exit ;;
     *:NonStop-UX:*:*)
 	echo mips-compaq-nonstopux
@@ -1300,18 +1393,19 @@
 	echo bs2000-siemens-sysv
 	exit ;;
     DS/*:UNIX_System_V:*:*)
-	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
 	exit ;;
     *:Plan9:*:*)
 	# "uname -m" is not consistent, so use $cputype instead. 386
 	# is converted to i386 for consistency with other x86
 	# operating systems.
-	if test "$cputype" = "386"; then
+	# shellcheck disable=SC2154
+	if test "$cputype" = 386; then
 	    UNAME_MACHINE=i386
 	else
 	    UNAME_MACHINE="$cputype"
 	fi
-	echo ${UNAME_MACHINE}-unknown-plan9
+	echo "$UNAME_MACHINE"-unknown-plan9
 	exit ;;
     *:TOPS-10:*:*)
 	echo pdp10-unknown-tops10
@@ -1332,14 +1426,14 @@
 	echo pdp10-unknown-its
 	exit ;;
     SEI:*:*:SEIUX)
-	echo mips-sei-seiux${UNAME_RELEASE}
+	echo mips-sei-seiux"$UNAME_RELEASE"
 	exit ;;
     *:DragonFly:*:*)
-	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
 	exit ;;
     *:*VMS:*:*)
 	UNAME_MACHINE=`(uname -p) 2>/dev/null`
-	case "${UNAME_MACHINE}" in
+	case "$UNAME_MACHINE" in
 	    A*) echo alpha-dec-vms ; exit ;;
 	    I*) echo ia64-dec-vms ; exit ;;
 	    V*) echo vax-dec-vms ; exit ;;
@@ -1348,24 +1442,31 @@
 	echo i386-pc-xenix
 	exit ;;
     i*86:skyos:*:*)
-	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
 	exit ;;
     i*86:rdos:*:*)
-	echo ${UNAME_MACHINE}-pc-rdos
+	echo "$UNAME_MACHINE"-pc-rdos
 	exit ;;
     i*86:AROS:*:*)
-	echo ${UNAME_MACHINE}-pc-aros
+	echo "$UNAME_MACHINE"-pc-aros
 	exit ;;
     x86_64:VMkernel:*:*)
-	echo ${UNAME_MACHINE}-unknown-esx
+	echo "$UNAME_MACHINE"-unknown-esx
+	exit ;;
+    amd64:Isilon\ OneFS:*:*)
+	echo x86_64-unknown-onefs
+	exit ;;
+    *:Unleashed:*:*)
+	echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
 	exit ;;
 esac
 
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <<EOF
 #ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
 #endif
 main ()
 {
@@ -1378,20 +1479,12 @@
 #include <sys/param.h>
   printf ("m68k-sony-newsos%s\n",
 #ifdef NEWSOS4
-	"4"
+  "4"
 #else
-	""
-#endif
-	); exit (0);
-#endif
+  ""
 #endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
-  printf ("arm-acorn-riscix\n"); exit (0);
+  ); exit (0);
 #endif
-
-#if defined (hp300) && !defined (hpux)
-  printf ("m68k-hp-bsd\n"); exit (0);
 #endif
 
 #if defined (NeXT)
@@ -1433,39 +1526,49 @@
 #endif
 
 #if defined (_SEQUENT_)
-    struct utsname un;
-
-    uname(&un);
+  struct utsname un;
 
-    if (strncmp(un.version, "V2", 2) == 0) {
-	printf ("i386-sequent-ptx2\n"); exit (0);
-    }
-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
-	printf ("i386-sequent-ptx1\n"); exit (0);
-    }
-    printf ("i386-sequent-ptx\n"); exit (0);
-
+  uname(&un);
+  if (strncmp(un.version, "V2", 2) == 0) {
+    printf ("i386-sequent-ptx2\n"); exit (0);
+  }
+  if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+    printf ("i386-sequent-ptx1\n"); exit (0);
+  }
+  printf ("i386-sequent-ptx\n"); exit (0);
 #endif
 
 #if defined (vax)
-# if !defined (ultrix)
-#  include <sys/param.h>
-#  if defined (BSD)
-#   if BSD == 43
-      printf ("vax-dec-bsd4.3\n"); exit (0);
-#   else
-#    if BSD == 199006
-      printf ("vax-dec-bsd4.3reno\n"); exit (0);
-#    else
-      printf ("vax-dec-bsd\n"); exit (0);
-#    endif
-#   endif
-#  else
-    printf ("vax-dec-bsd\n"); exit (0);
-#  endif
-# else
-    printf ("vax-dec-ultrix\n"); exit (0);
-# endif
+#if !defined (ultrix)
+#include <sys/param.h>
+#if defined (BSD)
+#if BSD == 43
+  printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+  printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+  printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+  printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include <signal.h>
+#if defined(_SIZE_T_) /* >= ULTRIX4 */
+  printf ("mips-dec-ultrix4\n"); exit (0);
+#else
+#if defined(ULTRIX3) || defined(ultrix3) || defined(SIGLOST)
+  printf ("mips-dec-ultrix3\n"); exit (0);
+#endif
+#endif
+#endif
 #endif
 
 #if defined (alliant) && defined (i860)
@@ -1476,54 +1579,38 @@
 }
 EOF
 
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` &&
 	{ echo "$SYSTEM_NAME"; exit; }
 
 # Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
 
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
-
-# Convex versions that predate uname can use getsysinfo(1)
+echo "$0: unable to guess system type" >&2
 
-if [ -x /usr/convex/getsysinfo ]
-then
-    case `getsysinfo -f cpu_type` in
-    c1*)
-	echo c1-convex-bsd
-	exit ;;
-    c2*)
-	if getsysinfo -f scalar_acc
-	then echo c32-convex-bsd
-	else echo c2-convex-bsd
-	fi
-	exit ;;
-    c34*)
-	echo c34-convex-bsd
-	exit ;;
-    c38*)
-	echo c38-convex-bsd
-	exit ;;
-    c4*)
-	echo c4-convex-bsd
-	exit ;;
-    esac
-fi
+case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+    mips:Linux | mips64:Linux)
+	# If we got here on MIPS GNU/Linux, output extra information.
+	cat >&2 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+	;;
+esac
 
 cat >&2 <<EOF
-$0: unable to guess system type
 
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
 
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 and
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <[email protected]> in order to provide the needed
-information to handle your system.
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to [email protected] to
+provide the necessary information to handle your system.
 
 config.guess timestamp = $timestamp
 
@@ -1542,16 +1629,16 @@
 /usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
 /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
 
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM  = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM  = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
 EOF
 
 exit 1
 
 # Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
+# eval: (add-hook 'before-save-hook 'time-stamp)
 # time-stamp-start: "timestamp='"
 # time-stamp-format: "%:y-%02m-%02d"
 # time-stamp-end: "'"
--- a/config.sub	Thu Mar 21 23:28:59 2019 +0800
+++ b/config.sub	Fri Jun 26 21:07:34 2020 +0800
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2013 Free Software Foundation, Inc.
+#   Copyright 1992-2019 Free Software Foundation, Inc.
 
-timestamp='2013-10-01'
+timestamp='2019-01-05'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
 # General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
 #
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
@@ -25,7 +25,7 @@
 # of the GNU General Public License, version 3 ("GPLv3").
 
 
-# Please send patches with a ChangeLog entry to [email protected]
+# Please send patches to <[email protected]>.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
@@ -33,7 +33,7 @@
 # Otherwise, we print the canonical config type on stdout and succeed.
 
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
@@ -53,12 +53,11 @@
 me=`echo "$0" | sed -e 's,.*/,,'`
 
 usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
-       $0 [OPTION] ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
 
 Canonicalize a configuration name.
 
-Operation modes:
+Options:
   -h, --help         print this help, then exit
   -t, --time-stamp   print date of last modification, then exit
   -v, --version      print version number, then exit
@@ -68,7 +67,7 @@
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright 1992-2019 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -90,12 +89,12 @@
     - )	# Use stdin as input.
        break ;;
     -* )
-       echo "$me: invalid option $1$help"
+       echo "$me: invalid option $1$help" >&2
        exit 1 ;;
 
     *local*)
        # First pass through any local machine types.
-       echo $1
+       echo "$1"
        exit ;;
 
     * )
@@ -111,1211 +110,1164 @@
     exit 1;;
 esac
 
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
-  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
-  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
-  knetbsd*-gnu* | netbsd*-gnu* | \
-  kopensolaris*-gnu* | \
-  storm-chaos* | os2-emx* | rtmk-nova*)
-    os=-$maybe_os
-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
-    ;;
-  android-linux)
-    os=-linux-android
-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
-    ;;
-  *)
-    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
-    if [ $basic_machine != $1 ]
-    then os=`echo $1 | sed 's/.*-/-/'`
-    else os=; fi
-    ;;
-esac
+# Split fields of configuration type
+# shellcheck disable=SC2162
+IFS="-" read field1 field2 field3 field4 <<EOF
+$1
+EOF
 
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work.  We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
-	-sun*os*)
-		# Prevent following clause from handling this invalid input.
+# Separate into logical components for further validation
+case $1 in
+	*-*-*-*-*)
+		echo Invalid configuration \`"$1"\': more than four components >&2
+		exit 1
+		;;
+	*-*-*-*)
+		basic_machine=$field1-$field2
+		os=$field3-$field4
 		;;
-	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
-	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
-	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
-	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-	-apple | -axis | -knuth | -cray | -microblaze*)
-		os=
-		basic_machine=$1
+	*-*-*)
+		# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
+		# parts
+		maybe_os=$field2-$field3
+		case $maybe_os in
+			nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \
+			| linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \
+			| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
+			| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
+			| storm-chaos* | os2-emx* | rtmk-nova*)
+				basic_machine=$field1
+				os=$maybe_os
+				;;
+			android-linux)
+				basic_machine=$field1-unknown
+				os=linux-android
+				;;
+			*)
+				basic_machine=$field1-$field2
+				os=$field3
+				;;
+		esac
 		;;
-	-bluegene*)
-		os=-cnk
-		;;
-	-sim | -cisco | -oki | -wec | -winbond)
-		os=
-		basic_machine=$1
-		;;
-	-scout)
-		;;
-	-wrs)
-		os=-vxworks
-		basic_machine=$1
-		;;
-	-chorusos*)
-		os=-chorusos
-		basic_machine=$1
-		;;
-	-chorusrdb)
-		os=-chorusrdb
-		basic_machine=$1
+	*-*)
+		# A lone config we happen to match not fitting any pattern
+		case $field1-$field2 in
+			decstation-3100)
+				basic_machine=mips-dec
+				os=
+				;;
+			*-*)
+				# Second component is usually, but not always the OS
+				case $field2 in
+					# Prevent following clause from handling this valid os
+					sun*os*)
+						basic_machine=$field1
+						os=$field2
+						;;
+					# Manufacturers
+					dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+					| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+					| unicom* | ibm* | next | hp | isi* | apollo | altos* \
+					| convergent* | ncr* | news | 32* | 3600* | 3100* \
+					| hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+					| ultra | tti* | harris | dolphin | highlevel | gould \
+					| cbm | ns | masscomp | apple | axis | knuth | cray \
+					| microblaze* | sim | cisco \
+					| oki | wec | wrs | winbond)
+						basic_machine=$field1-$field2
+						os=
+						;;
+					*)
+						basic_machine=$field1
+						os=$field2
+						;;
+				esac
+			;;
+		esac
 		;;
-	-hiux*)
-		os=-hiuxwe2
-		;;
-	-sco6)
-		os=-sco5v6
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-sco5)
-		os=-sco3.2v5
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-sco4)
-		os=-sco3.2v4
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-sco3.2.[4-9]*)
-		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-sco3.2v[4-9]*)
-		# Don't forget version if it is 3.2v4 or newer.
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-sco5v6*)
-		# Don't forget version if it is 3.2v4 or newer.
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-sco*)
-		os=-sco3.2v2
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-udk*)
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-isc)
-		os=-isc2.2
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-clix*)
-		basic_machine=clipper-intergraph
-		;;
-	-isc*)
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-		;;
-	-lynx*178)
-		os=-lynxos178
-		;;
-	-lynx*5)
-		os=-lynxos5
-		;;
-	-lynx*)
-		os=-lynxos
-		;;
-	-ptx*)
-		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
-		;;
-	-windowsnt*)
-		os=`echo $os | sed -e 's/windowsnt/winnt/'`
-		;;
-	-psos*)
-		os=-psos
-		;;
-	-mint | -mint[0-9]*)
-		basic_machine=m68k-atari
-		os=-mint
+	*)
+		# Convert single-component short-hands not valid as part of
+		# multi-component configurations.
+		case $field1 in
+			386bsd)
+				basic_machine=i386-pc
+				os=bsd
+				;;
+			a29khif)
+				basic_machine=a29k-amd
+				os=udi
+				;;
+			adobe68k)
+				basic_machine=m68010-adobe
+				os=scout
+				;;
+			alliant)
+				basic_machine=fx80-alliant
+				os=
+				;;
+			altos | altos3068)
+				basic_machine=m68k-altos
+				os=
+				;;
+			am29k)
+				basic_machine=a29k-none
+				os=bsd
+				;;
+			amdahl)
+				basic_machine=580-amdahl
+				os=sysv
+				;;
+			amiga)
+				basic_machine=m68k-unknown
+				os=
+				;;
+			amigaos | amigados)
+				basic_machine=m68k-unknown
+				os=amigaos
+				;;
+			amigaunix | amix)
+				basic_machine=m68k-unknown
+				os=sysv4
+				;;
+			apollo68)
+				basic_machine=m68k-apollo
+				os=sysv
+				;;
+			apollo68bsd)
+				basic_machine=m68k-apollo
+				os=bsd
+				;;
+			aros)
+				basic_machine=i386-pc
+				os=aros
+				;;
+			aux)
+				basic_machine=m68k-apple
+				os=aux
+				;;
+			balance)
+				basic_machine=ns32k-sequent
+				os=dynix
+				;;
+			blackfin)
+				basic_machine=bfin-unknown
+				os=linux
+				;;
+			cegcc)
+				basic_machine=arm-unknown
+				os=cegcc
+				;;
+			convex-c1)
+				basic_machine=c1-convex
+				os=bsd
+				;;
+			convex-c2)
+				basic_machine=c2-convex
+				os=bsd
+				;;
+			convex-c32)
+				basic_machine=c32-convex
+				os=bsd
+				;;
+			convex-c34)
+				basic_machine=c34-convex
+				os=bsd
+				;;
+			convex-c38)
+				basic_machine=c38-convex
+				os=bsd
+				;;
+			cray)
+				basic_machine=j90-cray
+				os=unicos
+				;;
+			crds | unos)
+				basic_machine=m68k-crds
+				os=
+				;;
+			da30)
+				basic_machine=m68k-da30
+				os=
+				;;
+			decstation | pmax | pmin | dec3100 | decstatn)
+				basic_machine=mips-dec
+				os=
+				;;
+			delta88)
+				basic_machine=m88k-motorola
+				os=sysv3
+				;;
+			dicos)
+				basic_machine=i686-pc
+				os=dicos
+				;;
+			djgpp)
+				basic_machine=i586-pc
+				os=msdosdjgpp
+				;;
+			ebmon29k)
+				basic_machine=a29k-amd
+				os=ebmon
+				;;
+			es1800 | OSE68k | ose68k | ose | OSE)
+				basic_machine=m68k-ericsson
+				os=ose
+				;;
+			gmicro)
+				basic_machine=tron-gmicro
+				os=sysv
+				;;
+			go32)
+				basic_machine=i386-pc
+				os=go32
+				;;
+			h8300hms)
+				basic_machine=h8300-hitachi
+				os=hms
+				;;
+			h8300xray)
+				basic_machine=h8300-hitachi
+				os=xray
+				;;
+			h8500hms)
+				basic_machine=h8500-hitachi
+				os=hms
+				;;
+			harris)
+				basic_machine=m88k-harris
+				os=sysv3
+				;;
+			hp300)
+				basic_machine=m68k-hp
+				;;
+			hp300bsd)
+				basic_machine=m68k-hp
+				os=bsd
+				;;
+			hp300hpux)
+				basic_machine=m68k-hp
+				os=hpux
+				;;
+			hppaosf)
+				basic_machine=hppa1.1-hp
+				os=osf
+				;;
+			hppro)
+				basic_machine=hppa1.1-hp
+				os=proelf
+				;;
+			i386mach)
+				basic_machine=i386-mach
+				os=mach
+				;;
+			vsta)
+				basic_machine=i386-pc
+				os=vsta
+				;;
+			isi68 | isi)
+				basic_machine=m68k-isi
+				os=sysv
+				;;
+			m68knommu)
+				basic_machine=m68k-unknown
+				os=linux
+				;;
+			magnum | m3230)
+				basic_machine=mips-mips
+				os=sysv
+				;;
+			merlin)
+				basic_machine=ns32k-utek
+				os=sysv
+				;;
+			mingw64)
+				basic_machine=x86_64-pc
+				os=mingw64
+				;;
+			mingw32)
+				basic_machine=i686-pc
+				os=mingw32
+				;;
+			mingw32ce)
+				basic_machine=arm-unknown
+				os=mingw32ce
+				;;
+			monitor)
+				basic_machine=m68k-rom68k
+				os=coff
+				;;
+			morphos)
+				basic_machine=powerpc-unknown
+				os=morphos
+				;;
+			moxiebox)
+				basic_machine=moxie-unknown
+				os=moxiebox
+				;;
+			msdos)
+				basic_machine=i386-pc
+				os=msdos
+				;;
+			msys)
+				basic_machine=i686-pc
+				os=msys
+				;;
+			mvs)
+				basic_machine=i370-ibm
+				os=mvs
+				;;
+			nacl)
+				basic_machine=le32-unknown
+				os=nacl
+				;;
+			ncr3000)
+				basic_machine=i486-ncr
+				os=sysv4
+				;;
+			netbsd386)
+				basic_machine=i386-pc
+				os=netbsd
+				;;
+			netwinder)
+				basic_machine=armv4l-rebel
+				os=linux
+				;;
+			news | news700 | news800 | news900)
+				basic_machine=m68k-sony
+				os=newsos
+				;;
+			news1000)
+				basic_machine=m68030-sony
+				os=newsos
+				;;
+			necv70)
+				basic_machine=v70-nec
+				os=sysv
+				;;
+			nh3000)
+				basic_machine=m68k-harris
+				os=cxux
+				;;
+			nh[45]000)
+				basic_machine=m88k-harris
+				os=cxux
+				;;
+			nindy960)
+				basic_machine=i960-intel
+				os=nindy
+				;;
+			mon960)
+				basic_machine=i960-intel
+				os=mon960
+				;;
+			nonstopux)
+				basic_machine=mips-compaq
+				os=nonstopux
+				;;
+			os400)
+				basic_machine=powerpc-ibm
+				os=os400
+				;;
+			OSE68000 | ose68000)
+				basic_machine=m68000-ericsson
+				os=ose
+				;;
+			os68k)
+				basic_machine=m68k-none
+				os=os68k
+				;;
+			paragon)
+				basic_machine=i860-intel
+				os=osf
+				;;
+			parisc)
+				basic_machine=hppa-unknown
+				os=linux
+				;;
+			pw32)
+				basic_machine=i586-unknown
+				os=pw32
+				;;
+			rdos | rdos64)
+				basic_machine=x86_64-pc
+				os=rdos
+				;;
+			rdos32)
+				basic_machine=i386-pc
+				os=rdos
+				;;
+			rom68k)
+				basic_machine=m68k-rom68k
+				os=coff
+				;;
+			sa29200)
+				basic_machine=a29k-amd
+				os=udi
+				;;
+			sei)
+				basic_machine=mips-sei
+				os=seiux
+				;;
+			sequent)
+				basic_machine=i386-sequent
+				os=
+				;;
+			sps7)
+				basic_machine=m68k-bull
+				os=sysv2
+				;;
+			st2000)
+				basic_machine=m68k-tandem
+				os=
+				;;
+			stratus)
+				basic_machine=i860-stratus
+				os=sysv4
+				;;
+			sun2)
+				basic_machine=m68000-sun
+				os=
+				;;
+			sun2os3)
+				basic_machine=m68000-sun
+				os=sunos3
+				;;
+			sun2os4)
+				basic_machine=m68000-sun
+				os=sunos4
+				;;
+			sun3)
+				basic_machine=m68k-sun
+				os=
+				;;
+			sun3os3)
+				basic_machine=m68k-sun
+				os=sunos3
+				;;
+			sun3os4)
+				basic_machine=m68k-sun
+				os=sunos4
+				;;
+			sun4)
+				basic_machine=sparc-sun
+				os=
+				;;
+			sun4os3)
+				basic_machine=sparc-sun
+				os=sunos3
+				;;
+			sun4os4)
+				basic_machine=sparc-sun
+				os=sunos4
+				;;
+			sun4sol2)
+				basic_machine=sparc-sun
+				os=solaris2
+				;;
+			sun386 | sun386i | roadrunner)
+				basic_machine=i386-sun
+				os=
+				;;
+			sv1)
+				basic_machine=sv1-cray
+				os=unicos
+				;;
+			symmetry)
+				basic_machine=i386-sequent
+				os=dynix
+				;;
+			t3e)
+				basic_machine=alphaev5-cray
+				os=unicos
+				;;
+			t90)
+				basic_machine=t90-cray
+				os=unicos
+				;;
+			toad1)
+				basic_machine=pdp10-xkl
+				os=tops20
+				;;
+			tpf)
+				basic_machine=s390x-ibm
+				os=tpf
+				;;
+			udi29k)
+				basic_machine=a29k-amd
+				os=udi
+				;;
+			ultra3)
+				basic_machine=a29k-nyu
+				os=sym1
+				;;
+			v810 | necv810)
+				basic_machine=v810-nec
+				os=none
+				;;
+			vaxv)
+				basic_machine=vax-dec
+				os=sysv
+				;;
+			vms)
+				basic_machine=vax-dec
+				os=vms
+				;;
+			vxworks960)
+				basic_machine=i960-wrs
+				os=vxworks
+				;;
+			vxworks68)
+				basic_machine=m68k-wrs
+				os=vxworks
+				;;
+			vxworks29k)
+				basic_machine=a29k-wrs
+				os=vxworks
+				;;
+			xbox)
+				basic_machine=i686-pc
+				os=mingw32
+				;;
+			ymp)
+				basic_machine=ymp-cray
+				os=unicos
+				;;
+			*)
+				basic_machine=$1
+				os=
+				;;
+		esac
 		;;
 esac
 
-# Decode aliases for certain CPU-COMPANY combinations.
+# Decode 1-component or ad-hoc basic machines
 case $basic_machine in
-	# Recognize the basic CPU types without company name.
-	# Some are omitted here because they have special meanings below.
-	1750a | 580 \
-	| a29k \
-	| aarch64 | aarch64_be \
-	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
-	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
-	| am33_2.0 \
-	| arc | arceb \
-	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
-	| avr | avr32 \
-	| be32 | be64 \
-	| bfin \
-	| c4x | c8051 | clipper \
-	| d10v | d30v | dlx | dsp16xx \
-	| epiphany \
-	| fido | fr30 | frv \
-	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
-	| hexagon \
-	| i370 | i860 | i960 | ia64 \
-	| ip2k | iq2000 \
-	| k1om \
-	| le32 | le64 \
-	| lm32 \
-	| m32c | m32r | m32rle | m68000 | m68k | m88k \
-	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
-	| mips | mipsbe | mipseb | mipsel | mipsle \
-	| mips16 \
-	| mips64 | mips64el \
-	| mips64octeon | mips64octeonel \
-	| mips64orion | mips64orionel \
-	| mips64r5900 | mips64r5900el \
-	| mips64vr | mips64vrel \
-	| mips64vr4100 | mips64vr4100el \
-	| mips64vr4300 | mips64vr4300el \
-	| mips64vr5000 | mips64vr5000el \
-	| mips64vr5900 | mips64vr5900el \
-	| mipsisa32 | mipsisa32el \
-	| mipsisa32r2 | mipsisa32r2el \
-	| mipsisa64 | mipsisa64el \
-	| mipsisa64r2 | mipsisa64r2el \
-	| mipsisa64sb1 | mipsisa64sb1el \
-	| mipsisa64sr71k | mipsisa64sr71kel \
-	| mipsr5900 | mipsr5900el \
-	| mipstx39 | mipstx39el \
-	| mn10200 | mn10300 \
-	| moxie \
-	| mt \
-	| msp430 \
-	| nds32 | nds32le | nds32be \
-	| nios | nios2 | nios2eb | nios2el \
-	| ns16k | ns32k \
-	| open8 \
-	| or1k | or32 \
-	| pdp10 | pdp11 | pj | pjl \
-	| powerpc | powerpc64 | powerpc64le | powerpcle \
-	| pyramid \
-	| rl78 | rx \
-	| score \
-	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
-	| sh64 | sh64le \
-	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
-	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
-	| spu \
-	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
-	| ubicom32 \
-	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
-	| we32k \
-	| x86 | xc16x | xstormy16 | xtensa \
-	| z8k | z80)
-		basic_machine=$basic_machine-unknown
+	# Here we handle the default manufacturer of certain CPU types.  It is in
+	# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		cpu=hppa1.1
+		vendor=winbond
+		;;
+	op50n)
+		cpu=hppa1.1
+		vendor=oki
+		;;
+	op60c)
+		cpu=hppa1.1
+		vendor=oki
 		;;
-	c54x)
-		basic_machine=tic54x-unknown
+	ibm*)
+		cpu=i370
+		vendor=ibm
 		;;
-	c55x)
-		basic_machine=tic55x-unknown
-		;;
-	c6x)
-		basic_machine=tic6x-unknown
+	orion105)
+		cpu=clipper
+		vendor=highlevel
 		;;
-	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
-		basic_machine=$basic_machine-unknown
-		os=-none
+	mac | mpw | mac-mpw)
+		cpu=m68k
+		vendor=apple
 		;;
-	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
-		;;
-	ms1)
-		basic_machine=mt-unknown
+	pmac | pmac-mpw)
+		cpu=powerpc
+		vendor=apple
 		;;
 
-	strongarm | thumb | xscale)
-		basic_machine=arm-unknown
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		cpu=m68000
+		vendor=att
+		;;
+	3b*)
+		cpu=we32k
+		vendor=att
+		;;
+	bluegene*)
+		cpu=powerpc
+		vendor=ibm
+		os=cnk
+		;;
+	decsystem10* | dec10*)
+		cpu=pdp10
+		vendor=dec
+		os=tops10
+		;;
+	decsystem20* | dec20*)
+		cpu=pdp10
+		vendor=dec
+		os=tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		cpu=m68k
+		vendor=motorola
+		;;
+	dpx2*)
+		cpu=m68k
+		vendor=bull
+		os=sysv3
+		;;
+	encore | umax | mmax)
+		cpu=ns32k
+		vendor=encore
+		;;
+	elxsi)
+		cpu=elxsi
+		vendor=elxsi
+		os=${os:-bsd}
+		;;
+	fx2800)
+		cpu=i860
+		vendor=alliant
+		;;
+	genix)
+		cpu=ns32k
+		vendor=ns
+		;;
+	h3050r* | hiux*)
+		cpu=hppa1.1
+		vendor=hitachi
+		os=hiuxwe2
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		cpu=hppa1.0
+		vendor=hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		cpu=m68000
+		vendor=hp
+		;;
+	hp9k3[2-9][0-9])
+		cpu=m68k
+		vendor=hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		cpu=hppa1.0
+		vendor=hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		cpu=hppa1.0
+		vendor=hp
+		;;
+	i*86v32)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=sysv32
+		;;
+	i*86v4*)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=sysv4
+		;;
+	i*86v)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=sysv
+		;;
+	i*86sol2)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=solaris2
+		;;
+	j90 | j90-cray)
+		cpu=j90
+		vendor=cray
+		os=${os:-unicos}
 		;;
-	xgate)
-		basic_machine=$basic_machine-unknown
-		os=-none
+	iris | iris4d)
+		cpu=mips
+		vendor=sgi
+		case $os in
+		    irix*)
+			;;
+		    *)
+			os=irix4
+			;;
+		esac
+		;;
+	miniframe)
+		cpu=m68000
+		vendor=convergent
+		;;
+	*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		cpu=m68k
+		vendor=atari
+		os=mint
+		;;
+	news-3600 | risc-news)
+		cpu=mips
+		vendor=sony
+		os=newsos
+		;;
+	next | m*-next)
+		cpu=m68k
+		vendor=next
+		case $os in
+		    nextstep* )
+			;;
+		    ns2*)
+		      os=nextstep2
+			;;
+		    *)
+		      os=nextstep3
+			;;
+		esac
+		;;
+	np1)
+		cpu=np1
+		vendor=gould
+		;;
+	op50n-* | op60c-*)
+		cpu=hppa1.1
+		vendor=oki
+		os=proelf
+		;;
+	pa-hitachi)
+		cpu=hppa1.1
+		vendor=hitachi
+		os=hiuxwe2
+		;;
+	pbd)
+		cpu=sparc
+		vendor=tti
+		;;
+	pbb)
+		cpu=m68k
+		vendor=tti
 		;;
-	xscaleeb)
-		basic_machine=armeb-unknown
+	pc532)
+		cpu=ns32k
+		vendor=pc532
+		;;
+	pn)
+		cpu=pn
+		vendor=gould
+		;;
+	power)
+		cpu=power
+		vendor=ibm
+		;;
+	ps2)
+		cpu=i386
+		vendor=ibm
+		;;
+	rm[46]00)
+		cpu=mips
+		vendor=siemens
+		;;
+	rtpc | rtpc-*)
+		cpu=romp
+		vendor=ibm
+		;;
+	sde)
+		cpu=mipsisa32
+		vendor=sde
+		os=${os:-elf}
+		;;
+	simso-wrs)
+		cpu=sparclite
+		vendor=wrs
+		os=vxworks
+		;;
+	tower | tower-32)
+		cpu=m68k
+		vendor=ncr
+		;;
+	vpp*|vx|vx-*)
+		cpu=f301
+		vendor=fujitsu
+		;;
+	w65)
+		cpu=w65
+		vendor=wdc
+		;;
+	w89k-*)
+		cpu=hppa1.1
+		vendor=winbond
+		os=proelf
+		;;
+	none)
+		cpu=none
+		vendor=none
+		;;
+	leon|leon[3-9])
+		cpu=sparc
+		vendor=$basic_machine
+		;;
+	leon-*|leon[3-9]-*)
+		cpu=sparc
+		vendor=`echo "$basic_machine" | sed 's/-.*//'`
 		;;
 
-	xscaleel)
-		basic_machine=armel-unknown
+	*-*)
+		# shellcheck disable=SC2162
+		IFS="-" read cpu vendor <<EOF
+$basic_machine
+EOF
 		;;
-
 	# We use `pc' rather than `unknown'
 	# because (1) that's what they normally are, and
 	# (2) the word "unknown" tends to confuse beginning users.
 	i*86 | x86_64)
-	  basic_machine=$basic_machine-pc
-	  ;;
-	# Object if more than one company name word.
-	*-*-*)
-		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-		exit 1
+		cpu=$basic_machine
+		vendor=pc
+		;;
+	# These rules are duplicated from below for sake of the special case above;
+	# i.e. things that normalized to x86 arches should also default to "pc"
+	pc98)
+		cpu=i386
+		vendor=pc
+		;;
+	x64 | amd64)
+		cpu=x86_64
+		vendor=pc
+		;;
+	# Recognize the basic CPU types without company name.
+	*)
+		cpu=$basic_machine
+		vendor=unknown
+		;;
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+	# Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+	# some cases the only manufacturer, in others, it is the most popular.
+	craynv-unknown)
+		vendor=cray
+		os=${os:-unicosmp}
+		;;
+	c90-unknown | c90-cray)
+		vendor=cray
+		os=${os:-unicos}
+		;;
+	fx80-unknown)
+		vendor=alliant
+		;;
+	romp-unknown)
+		vendor=ibm
 		;;
-	# Recognize the basic CPU types with company name.
-	580-* \
-	| a29k-* \
-	| aarch64-* | aarch64_be-* \
-	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
-	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
-	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
-	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
-	| avr-* | avr32-* \
-	| be32-* | be64-* \
-	| bfin-* | bs2000-* \
-	| c[123]* | c30-* | [cjt]90-* | c4x-* \
-	| c8051-* | clipper-* | craynv-* | cydra-* \
-	| d10v-* | d30v-* | dlx-* \
-	| elxsi-* \
-	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
-	| h8300-* | h8500-* \
-	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
-	| hexagon-* \
-	| i*86-* | i860-* | i960-* | ia64-* \
-	| ip2k-* | iq2000-* \
-	| k1om-* \
-	| le32-* | le64-* \
-	| lm32-* \
-	| m32c-* | m32r-* | m32rle-* \
-	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
-	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
-	| microblaze-* | microblazeel-* \
-	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
-	| mips16-* \
-	| mips64-* | mips64el-* \
-	| mips64octeon-* | mips64octeonel-* \
-	| mips64orion-* | mips64orionel-* \
-	| mips64r5900-* | mips64r5900el-* \
-	| mips64vr-* | mips64vrel-* \
-	| mips64vr4100-* | mips64vr4100el-* \
-	| mips64vr4300-* | mips64vr4300el-* \
-	| mips64vr5000-* | mips64vr5000el-* \
-	| mips64vr5900-* | mips64vr5900el-* \
-	| mipsisa32-* | mipsisa32el-* \
-	| mipsisa32r2-* | mipsisa32r2el-* \
-	| mipsisa64-* | mipsisa64el-* \
-	| mipsisa64r2-* | mipsisa64r2el-* \
-	| mipsisa64sb1-* | mipsisa64sb1el-* \
-	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
-	| mipsr5900-* | mipsr5900el-* \
-	| mipstx39-* | mipstx39el-* \
-	| mmix-* \
-	| mt-* \
-	| msp430-* \
-	| nds32-* | nds32le-* | nds32be-* \
-	| nios-* | nios2-* | nios2eb-* | nios2el-* \
-	| none-* | np1-* | ns16k-* | ns32k-* \
-	| open8-* \
-	| orion-* \
-	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
-	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
-	| pyramid-* \
-	| rl78-* | romp-* | rs6000-* | rx-* \
-	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
-	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
-	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
-	| sparclite-* \
-	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
-	| tahoe-* \
-	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
-	| tile*-* \
-	| tron-* \
-	| ubicom32-* \
-	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
-	| vax-* \
-	| we32k-* \
-	| x86-* | x86_64-* | xc16x-* | xps100-* \
-	| xstormy16-* | xtensa*-* \
-	| ymp-* \
-	| z8k-* | z80-*)
+	mmix-unknown)
+		vendor=knuth
+		;;
+	microblaze-unknown | microblazeel-unknown)
+		vendor=xilinx
+		;;
+	rs6000-unknown)
+		vendor=ibm
+		;;
+	vax-unknown)
+		vendor=dec
+		;;
+	pdp11-unknown)
+		vendor=dec
+		;;
+	we32k-unknown)
+		vendor=att
+		;;
+	cydra-unknown)
+		vendor=cydrome
 		;;
-	# Recognize the basic CPU types without company name, with glob match.
-	xtensa*)
-		basic_machine=$basic_machine-unknown
-		;;
-	# Recognize the various machine names and aliases which stand
-	# for a CPU type and a company and sometimes even an OS.
-	386bsd)
-		basic_machine=i386-unknown
-		os=-bsd
+	i370-ibm*)
+		vendor=ibm
 		;;
-	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
-		basic_machine=m68000-att
+	orion-unknown)
+		vendor=highlevel
 		;;
-	3b*)
-		basic_machine=we32k-att
-		;;
-	a29khif)
-		basic_machine=a29k-amd
-		os=-udi
+	xps-unknown | xps100-unknown)
+		cpu=xps100
+		vendor=honeywell
 		;;
-	abacus)
-		basic_machine=abacus-unknown
-		;;
-	adobe68k)
-		basic_machine=m68010-adobe
-		os=-scout
-		;;
-	alliant | fx80)
-		basic_machine=fx80-alliant
+
+	# Here we normalize CPU types with a missing or matching vendor
+	dpx20-unknown | dpx20-bull)
+		cpu=rs6000
+		vendor=bull
+		os=${os:-bosx}
 		;;
-	altos | altos3068)
-		basic_machine=m68k-altos
-		;;
-	am29k)
-		basic_machine=a29k-none
-		os=-bsd
-		;;
-	amd64)
-		basic_machine=x86_64-pc
-		;;
+
+	# Here we normalize CPU types irrespective of the vendor
 	amd64-*)
-		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	amdahl)
-		basic_machine=580-amdahl
-		os=-sysv
-		;;
-	amiga | amiga-*)
-		basic_machine=m68k-unknown
-		;;
-	amigaos | amigados)
-		basic_machine=m68k-unknown
-		os=-amigaos
-		;;
-	amigaunix | amix)
-		basic_machine=m68k-unknown
-		os=-sysv4
-		;;
-	apollo68)
-		basic_machine=m68k-apollo
-		os=-sysv
-		;;
-	apollo68bsd)
-		basic_machine=m68k-apollo
-		os=-bsd
-		;;
-	aros)
-		basic_machine=i386-pc
-		os=-aros
-		;;
-	aux)
-		basic_machine=m68k-apple
-		os=-aux
-		;;
-	balance)
-		basic_machine=ns32k-sequent
-		os=-dynix
-		;;
-	blackfin)
-		basic_machine=bfin-unknown
-		os=-linux
+		cpu=x86_64
 		;;
 	blackfin-*)
-		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
-		os=-linux
-		;;
-	bluegene*)
-		basic_machine=powerpc-ibm
-		os=-cnk
+		cpu=bfin
+		os=linux
 		;;
 	c54x-*)
-		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		cpu=tic54x
 		;;
 	c55x-*)
-		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		cpu=tic55x
 		;;
 	c6x-*)
-		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	c90)
-		basic_machine=c90-cray
-		os=-unicos
-		;;
-	cegcc)
-		basic_machine=arm-unknown
-		os=-cegcc
-		;;
-	convex-c1)
-		basic_machine=c1-convex
-		os=-bsd
-		;;
-	convex-c2)
-		basic_machine=c2-convex
-		os=-bsd
-		;;
-	convex-c32)
-		basic_machine=c32-convex
-		os=-bsd
-		;;
-	convex-c34)
-		basic_machine=c34-convex
-		os=-bsd
-		;;
-	convex-c38)
-		basic_machine=c38-convex
-		os=-bsd
-		;;
-	cray | j90)
-		basic_machine=j90-cray
-		os=-unicos
-		;;
-	craynv)
-		basic_machine=craynv-cray
-		os=-unicosmp
-		;;
-	cr16 | cr16-*)
-		basic_machine=cr16-unknown
-		os=-elf
-		;;
-	crds | unos)
-		basic_machine=m68k-crds
-		;;
-	crisv32 | crisv32-* | etraxfs*)
-		basic_machine=crisv32-axis
-		;;
-	cris | cris-* | etrax*)
-		basic_machine=cris-axis
-		;;
-	crx)
-		basic_machine=crx-unknown
-		os=-elf
-		;;
-	da30 | da30-*)
-		basic_machine=m68k-da30
-		;;
-	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
-		basic_machine=mips-dec
-		;;
-	decsystem10* | dec10*)
-		basic_machine=pdp10-dec
-		os=-tops10
-		;;
-	decsystem20* | dec20*)
-		basic_machine=pdp10-dec
-		os=-tops20
-		;;
-	delta | 3300 | motorola-3300 | motorola-delta \
-	      | 3300-motorola | delta-motorola)
-		basic_machine=m68k-motorola
-		;;
-	delta88)
-		basic_machine=m88k-motorola
-		os=-sysv3
-		;;
-	dicos)
-		basic_machine=i686-pc
-		os=-dicos
-		;;
-	djgpp)
-		basic_machine=i586-pc
-		os=-msdosdjgpp
-		;;
-	dpx20 | dpx20-*)
-		basic_machine=rs6000-bull
-		os=-bosx
-		;;
-	dpx2* | dpx2*-bull)
-		basic_machine=m68k-bull
-		os=-sysv3
-		;;
-	ebmon29k)
-		basic_machine=a29k-amd
-		os=-ebmon
-		;;
-	elxsi)
-		basic_machine=elxsi-elxsi
-		os=-bsd
-		;;
-	encore | umax | mmax)
-		basic_machine=ns32k-encore
-		;;
-	es1800 | OSE68k | ose68k | ose | OSE)
-		basic_machine=m68k-ericsson
-		os=-ose
-		;;
-	fx2800)
-		basic_machine=i860-alliant
-		;;
-	genix)
-		basic_machine=ns32k-ns
-		;;
-	gmicro)
-		basic_machine=tron-gmicro
-		os=-sysv
-		;;
-	go32)
-		basic_machine=i386-pc
-		os=-go32
-		;;
-	h3050r* | hiux*)
-		basic_machine=hppa1.1-hitachi
-		os=-hiuxwe2
-		;;
-	h8300hms)
-		basic_machine=h8300-hitachi
-		os=-hms
-		;;
-	h8300xray)
-		basic_machine=h8300-hitachi
-		os=-xray
+		cpu=tic6x
 		;;
-	h8500hms)
-		basic_machine=h8500-hitachi
-		os=-hms
-		;;
-	harris)
-		basic_machine=m88k-harris
-		os=-sysv3
-		;;
-	hp300-*)
-		basic_machine=m68k-hp
-		;;
-	hp300bsd)
-		basic_machine=m68k-hp
-		os=-bsd
-		;;
-	hp300hpux)
-		basic_machine=m68k-hp
-		os=-hpux
-		;;
-	hp3k9[0-9][0-9] | hp9[0-9][0-9])
-		basic_machine=hppa1.0-hp
-		;;
-	hp9k2[0-9][0-9] | hp9k31[0-9])
-		basic_machine=m68000-hp
-		;;
-	hp9k3[2-9][0-9])
-		basic_machine=m68k-hp
-		;;
-	hp9k6[0-9][0-9] | hp6[0-9][0-9])
-		basic_machine=hppa1.0-hp
-		;;
-	hp9k7[0-79][0-9] | hp7[0-79][0-9])
-		basic_machine=hppa1.1-hp
-		;;
-	hp9k78[0-9] | hp78[0-9])
-		# FIXME: really hppa2.0-hp
-		basic_machine=hppa1.1-hp
-		;;
-	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
-		# FIXME: really hppa2.0-hp
-		basic_machine=hppa1.1-hp
-		;;
-	hp9k8[0-9][13679] | hp8[0-9][13679])
-		basic_machine=hppa1.1-hp
-		;;
-	hp9k8[0-9][0-9] | hp8[0-9][0-9])
-		basic_machine=hppa1.0-hp
-		;;
-	hppa-next)
-		os=-nextstep3
-		;;
-	hppaosf)
-		basic_machine=hppa1.1-hp
-		os=-osf
-		;;
-	hppro)
-		basic_machine=hppa1.1-hp
-		os=-proelf
-		;;
-	i370-ibm* | ibm*)
-		basic_machine=i370-ibm
-		;;
-	i*86v32)
-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-		os=-sysv32
-		;;
-	i*86v4*)
-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-		os=-sysv4
-		;;
-	i*86v)
-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-		os=-sysv
-		;;
-	i*86sol2)
-		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-		os=-solaris2
-		;;
-	i386mach)
-		basic_machine=i386-mach
-		os=-mach
-		;;
-	i386-vsta | vsta)
-		basic_machine=i386-unknown
-		os=-vsta
-		;;
-	iris | iris4d)
-		basic_machine=mips-sgi
-		case $os in
-		    -irix*)
-			;;
-		    *)
-			os=-irix4
-			;;
-		esac
-		;;
-	isi68 | isi)
-		basic_machine=m68k-isi
-		os=-sysv
-		;;
-	m68knommu)
-		basic_machine=m68k-unknown
-		os=-linux
-		;;
-	m68knommu-*)
-		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
-		os=-linux
-		;;
-	m88k-omron*)
-		basic_machine=m88k-omron
-		;;
-	magnum | m3230)
-		basic_machine=mips-mips
-		os=-sysv
-		;;
-	merlin)
-		basic_machine=ns32k-utek
-		os=-sysv
-		;;
-	microblaze*)
-		basic_machine=microblaze-xilinx
-		;;
-	mingw64)
-		basic_machine=x86_64-pc
-		os=-mingw64
-		;;
-	mingw32)
-		basic_machine=i686-pc
-		os=-mingw32
-		;;
-	mingw32ce)
-		basic_machine=arm-unknown
-		os=-mingw32ce
-		;;
-	miniframe)
-		basic_machine=m68000-convergent
-		;;
-	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
-		basic_machine=m68k-atari
-		os=-mint
+	e500v[12]-*)
+		cpu=powerpc
+		os=$os"spe"
 		;;
 	mips3*-*)
-		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
-		;;
-	mips3*)
-		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
-		;;
-	monitor)
-		basic_machine=m68k-rom68k
-		os=-coff
-		;;
-	morphos)
-		basic_machine=powerpc-unknown
-		os=-morphos
-		;;
-	msdos)
-		basic_machine=i386-pc
-		os=-msdos
+		cpu=mips64
 		;;
 	ms1-*)
-		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
-		;;
-	msys)
-		basic_machine=i686-pc
-		os=-msys
-		;;
-	mvs)
-		basic_machine=i370-ibm
-		os=-mvs
-		;;
-	nacl)
-		basic_machine=le32-unknown
-		os=-nacl
-		;;
-	ncr3000)
-		basic_machine=i486-ncr
-		os=-sysv4
-		;;
-	netbsd386)
-		basic_machine=i386-unknown
-		os=-netbsd
-		;;
-	netwinder)
-		basic_machine=armv4l-rebel
-		os=-linux
+		cpu=mt
 		;;
-	news | news700 | news800 | news900)
-		basic_machine=m68k-sony
-		os=-newsos
-		;;
-	news1000)
-		basic_machine=m68030-sony
-		os=-newsos
-		;;
-	news-3600 | risc-news)
-		basic_machine=mips-sony
-		os=-newsos
-		;;
-	necv70)
-		basic_machine=v70-nec
-		os=-sysv
-		;;
-	next | m*-next )
-		basic_machine=m68k-next
-		case $os in
-		    -nextstep* )
-			;;
-		    -ns2*)
-		      os=-nextstep2
-			;;
-		    *)
-		      os=-nextstep3
-			;;
-		esac
-		;;
-	nh3000)
-		basic_machine=m68k-harris
-		os=-cxux
+	m68knommu-*)
+		cpu=m68k
+		os=linux
 		;;
-	nh[45]000)
-		basic_machine=m88k-harris
-		os=-cxux
-		;;
-	nindy960)
-		basic_machine=i960-intel
-		os=-nindy
-		;;
-	mon960)
-		basic_machine=i960-intel
-		os=-mon960
-		;;
-	nonstopux)
-		basic_machine=mips-compaq
-		os=-nonstopux
-		;;
-	np1)
-		basic_machine=np1-gould
-		;;
-	neo-tandem)
-		basic_machine=neo-tandem
-		;;
-	nse-tandem)
-		basic_machine=nse-tandem
-		;;
-	nsr-tandem)
-		basic_machine=nsr-tandem
+	m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+		cpu=s12z
 		;;
-	op50n-* | op60c-*)
-		basic_machine=hppa1.1-oki
-		os=-proelf
-		;;
-	openrisc | openrisc-*)
-		basic_machine=or32-unknown
-		;;
-	os400)
-		basic_machine=powerpc-ibm
-		os=-os400
-		;;
-	OSE68000 | ose68000)
-		basic_machine=m68000-ericsson
-		os=-ose
-		;;
-	os68k)
-		basic_machine=m68k-none
-		os=-os68k
-		;;
-	pa-hitachi)
-		basic_machine=hppa1.1-hitachi
-		os=-hiuxwe2
-		;;
-	paragon)
-		basic_machine=i860-intel
-		os=-osf
-		;;
-	parisc)
-		basic_machine=hppa-unknown
-		os=-linux
+	openrisc-*)
+		cpu=or32
 		;;
 	parisc-*)
-		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
-		os=-linux
-		;;
-	pbd)
-		basic_machine=sparc-tti
-		;;
-	pbb)
-		basic_machine=m68k-tti
-		;;
-	pc532 | pc532-*)
-		basic_machine=ns32k-pc532
-		;;
-	pc98)
-		basic_machine=i386-pc
-		;;
-	pc98-*)
-		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	pentium | p5 | k5 | k6 | nexgen | viac3)
-		basic_machine=i586-pc
-		;;
-	pentiumpro | p6 | 6x86 | athlon | athlon_*)
-		basic_machine=i686-pc
-		;;
-	pentiumii | pentium2 | pentiumiii | pentium3)
-		basic_machine=i686-pc
-		;;
-	pentium4)
-		basic_machine=i786-pc
+		cpu=hppa
+		os=linux
 		;;
 	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
-		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		cpu=i586
 		;;
-	pentiumpro-* | p6-* | 6x86-* | athlon-*)
-		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+	pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+		cpu=i686
 		;;
 	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
-		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		cpu=i686
 		;;
 	pentium4-*)
-		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		cpu=i786
 		;;
-	pn)
-		basic_machine=pn-gould
-		;;
-	power)	basic_machine=power-ibm
-		;;
-	ppc | ppcbe)	basic_machine=powerpc-unknown
+	pc98-*)
+		cpu=i386
 		;;
 	ppc-* | ppcbe-*)
-		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	ppcle | powerpclittle | ppc-le | powerpc-little)
-		basic_machine=powerpcle-unknown
+		cpu=powerpc
 		;;
 	ppcle-* | powerpclittle-*)
-		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	ppc64)	basic_machine=powerpc64-unknown
+		cpu=powerpcle
 		;;
-	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
-		basic_machine=powerpc64le-unknown
+	ppc64-*)
+		cpu=powerpc64
 		;;
 	ppc64le-* | powerpc64little-*)
-		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	ps2)
-		basic_machine=i386-ibm
-		;;
-	pw32)
-		basic_machine=i586-unknown
-		os=-pw32
-		;;
-	rdos | rdos64)
-		basic_machine=x86_64-pc
-		os=-rdos
-		;;
-	rdos32)
-		basic_machine=i386-pc
-		os=-rdos
+		cpu=powerpc64le
 		;;
-	rom68k)
-		basic_machine=m68k-rom68k
-		os=-coff
-		;;
-	rm[46]00)
-		basic_machine=mips-siemens
-		;;
-	rtpc | rtpc-*)
-		basic_machine=romp-ibm
-		;;
-	s390 | s390-*)
-		basic_machine=s390-ibm
-		;;
-	s390x | s390x-*)
-		basic_machine=s390x-ibm
-		;;
-	sa29200)
-		basic_machine=a29k-amd
-		os=-udi
-		;;
-	sb1)
-		basic_machine=mipsisa64sb1-unknown
+	sb1-*)
+		cpu=mipsisa64sb1
 		;;
-	sb1el)
-		basic_machine=mipsisa64sb1el-unknown
-		;;
-	sde)
-		basic_machine=mipsisa32-sde
-		os=-elf
-		;;
-	sei)
-		basic_machine=mips-sei
-		os=-seiux
-		;;
-	sequent)
-		basic_machine=i386-sequent
-		;;
-	sh)
-		basic_machine=sh-hitachi
-		os=-hms
-		;;
-	sh5el)
-		basic_machine=sh5le-unknown
+	sb1el-*)
+		cpu=mipsisa64sb1el
 		;;
-	sh64)
-		basic_machine=sh64-unknown
-		;;
-	sparclite-wrs | simso-wrs)
-		basic_machine=sparclite-wrs
-		os=-vxworks
+	sh5e[lb]-*)
+		cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
 		;;
-	sps7)
-		basic_machine=m68k-bull
-		os=-sysv2
-		;;
-	spur)
-		basic_machine=spur-unknown
-		;;
-	st2000)
-		basic_machine=m68k-tandem
-		;;
-	stratus)
-		basic_machine=i860-stratus
-		os=-sysv4
+	spur-*)
+		cpu=spur
 		;;
 	strongarm-* | thumb-*)
-		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
-		;;
-	sun2)
-		basic_machine=m68000-sun
-		;;
-	sun2os3)
-		basic_machine=m68000-sun
-		os=-sunos3
-		;;
-	sun2os4)
-		basic_machine=m68000-sun
-		os=-sunos4
-		;;
-	sun3os3)
-		basic_machine=m68k-sun
-		os=-sunos3
-		;;
-	sun3os4)
-		basic_machine=m68k-sun
-		os=-sunos4
-		;;
-	sun4os3)
-		basic_machine=sparc-sun
-		os=-sunos3
-		;;
-	sun4os4)
-		basic_machine=sparc-sun
-		os=-sunos4
+		cpu=arm
 		;;
-	sun4sol2)
-		basic_machine=sparc-sun
-		os=-solaris2
-		;;
-	sun3 | sun3-*)
-		basic_machine=m68k-sun
-		;;
-	sun4)
-		basic_machine=sparc-sun
-		;;
-	sun386 | sun386i | roadrunner)
-		basic_machine=i386-sun
-		;;
-	sv1)
-		basic_machine=sv1-cray
-		os=-unicos
-		;;
-	symmetry)
-		basic_machine=i386-sequent
-		os=-dynix
-		;;
-	t3e)
-		basic_machine=alphaev5-cray
-		os=-unicos
-		;;
-	t90)
-		basic_machine=t90-cray
-		os=-unicos
-		;;
-	tile*)
-		basic_machine=$basic_machine-unknown
-		os=-linux-gnu
+	tx39-*)
+		cpu=mipstx39
 		;;
-	tx39)
-		basic_machine=mipstx39-unknown
-		;;
-	tx39el)
-		basic_machine=mipstx39el-unknown
-		;;
-	toad1)
-		basic_machine=pdp10-xkl
-		os=-tops20
-		;;
-	tower | tower-32)
-		basic_machine=m68k-ncr
-		;;
-	tpf)
-		basic_machine=s390x-ibm
-		os=-tpf
-		;;
-	udi29k)
-		basic_machine=a29k-amd
-		os=-udi
-		;;
-	ultra3)
-		basic_machine=a29k-nyu
-		os=-sym1
-		;;
-	v810 | necv810)
-		basic_machine=v810-nec
-		os=-none
-		;;
-	vaxv)
-		basic_machine=vax-dec
-		os=-sysv
+	tx39el-*)
+		cpu=mipstx39el
 		;;
-	vms)
-		basic_machine=vax-dec
-		os=-vms
-		;;
-	vpp*|vx|vx-*)
-		basic_machine=f301-fujitsu
-		;;
-	vxworks960)
-		basic_machine=i960-wrs
-		os=-vxworks
-		;;
-	vxworks68)
-		basic_machine=m68k-wrs
-		os=-vxworks
-		;;
-	vxworks29k)
-		basic_machine=a29k-wrs
-		os=-vxworks
-		;;
-	w65*)
-		basic_machine=w65-wdc
-		os=-none
-		;;
-	w89k-*)
-		basic_machine=hppa1.1-winbond
-		os=-proelf
-		;;
-	xbox)
-		basic_machine=i686-pc
-		os=-mingw32
-		;;
-	xps | xps100)
-		basic_machine=xps100-honeywell
+	x64-*)
+		cpu=x86_64
 		;;
 	xscale-* | xscalee[bl]-*)
-		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
+		;;
+
+	# Recognize the canonical CPU Types that limit and/or modify the
+	# company names they are paired with.
+	cr16-*)
+		os=${os:-elf}
 		;;
-	ymp)
-		basic_machine=ymp-cray
-		os=-unicos
+	crisv32-* | etraxfs*-*)
+		cpu=crisv32
+		vendor=axis
+		;;
+	cris-* | etrax*-*)
+		cpu=cris
+		vendor=axis
+		;;
+	crx-*)
+		os=${os:-elf}
+		;;
+	neo-tandem)
+		cpu=neo
+		vendor=tandem
 		;;
-	z8k-*-coff)
-		basic_machine=z8k-unknown
-		os=-sim
+	nse-tandem)
+		cpu=nse
+		vendor=tandem
+		;;
+	nsr-tandem)
+		cpu=nsr
+		vendor=tandem
+		;;
+	nsv-tandem)
+		cpu=nsv
+		vendor=tandem
 		;;
-	z80-*-coff)
-		basic_machine=z80-unknown
-		os=-sim
+	nsx-tandem)
+		cpu=nsx
+		vendor=tandem
 		;;
-	none)
-		basic_machine=none-none
-		os=-none
+	s390-*)
+		cpu=s390
+		vendor=ibm
+		;;
+	s390x-*)
+		cpu=s390x
+		vendor=ibm
+		;;
+	tile*-*)
+		os=${os:-linux-gnu}
 		;;
 
-# Here we handle the default manufacturer of certain CPU types.  It is in
-# some cases the only manufacturer, in others, it is the most popular.
-	w89k)
-		basic_machine=hppa1.1-winbond
-		;;
-	op50n)
-		basic_machine=hppa1.1-oki
-		;;
-	op60c)
-		basic_machine=hppa1.1-oki
-		;;
-	romp)
-		basic_machine=romp-ibm
-		;;
-	mmix)
-		basic_machine=mmix-knuth
-		;;
-	rs6000)
-		basic_machine=rs6000-ibm
-		;;
-	vax)
-		basic_machine=vax-dec
-		;;
-	pdp10)
-		# there are many clones, so DEC is not a safe bet
-		basic_machine=pdp10-unknown
-		;;
-	pdp11)
-		basic_machine=pdp11-dec
-		;;
-	we32k)
-		basic_machine=we32k-att
-		;;
-	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
-		basic_machine=sh-unknown
-		;;
-	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
-		basic_machine=sparc-sun
-		;;
-	cydra)
-		basic_machine=cydra-cydrome
-		;;
-	orion)
-		basic_machine=orion-highlevel
-		;;
-	orion105)
-		basic_machine=clipper-highlevel
-		;;
-	mac | mpw | mac-mpw)
-		basic_machine=m68k-apple
-		;;
-	pmac | pmac-mpw)
-		basic_machine=powerpc-apple
-		;;
-	*-unknown)
-		# Make sure to match an already-canonicalized machine name.
-		;;
 	*)
-		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-		exit 1
+		# Recognize the canonical CPU types that are allowed with any
+		# company name.
+		case $cpu in
+			1750a | 580 \
+			| a29k \
+			| aarch64 | aarch64_be \
+			| abacus \
+			| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+			| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+			| alphapca5[67] | alpha64pca5[67] \
+			| am33_2.0 \
+			| amdgcn \
+			| arc | arceb \
+			| arm  | arm[lb]e | arme[lb] | armv* \
+			| avr | avr32 \
+			| asmjs \
+			| ba \
+			| be32 | be64 \
+			| bfin | bs2000 \
+			| c[123]* | c30 | [cjt]90 | c4x \
+			| c8051 | clipper | craynv | csky | cydra \
+			| d10v | d30v | dlx | dsp16xx \
+			| e2k | elxsi | epiphany \
+			| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+			| h8300 | h8500 \
+			| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+			| hexagon \
+			| i370 | i*86 | i860 | i960 | ia16 | ia64 \
+			| ip2k | iq2000 \
+			| k1om \
+			| le32 | le64 \
+			| lm32 \
+			| m32c | m32r | m32rle \
+			| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+			| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+			| m88110 | m88k | maxq | mb | mcore | mep | metag \
+			| microblaze | microblazeel \
+			| mips | mipsbe | mipseb | mipsel | mipsle \
+			| mips16 \
+			| mips64 | mips64eb | mips64el \
+			| mips64octeon | mips64octeonel \
+			| mips64orion | mips64orionel \
+			| mips64r5900 | mips64r5900el \
+			| mips64vr | mips64vrel \
+			| mips64vr4100 | mips64vr4100el \
+			| mips64vr4300 | mips64vr4300el \
+			| mips64vr5000 | mips64vr5000el \
+			| mips64vr5900 | mips64vr5900el \
+			| mipsisa32 | mipsisa32el \
+			| mipsisa32r2 | mipsisa32r2el \
+			| mipsisa32r6 | mipsisa32r6el \
+			| mipsisa64 | mipsisa64el \
+			| mipsisa64r2 | mipsisa64r2el \
+			| mipsisa64r6 | mipsisa64r6el \
+			| mipsisa64sb1 | mipsisa64sb1el \
+			| mipsisa64sr71k | mipsisa64sr71kel \
+			| mipsr5900 | mipsr5900el \
+			| mipstx39 | mipstx39el \
+			| mmix \
+			| mn10200 | mn10300 \
+			| moxie \
+			| mt \
+			| msp430 \
+			| nds32 | nds32le | nds32be \
+			| nfp \
+			| nios | nios2 | nios2eb | nios2el \
+			| none | np1 | ns16k | ns32k | nvptx \
+			| open8 \
+			| or1k* \
+			| or32 \
+			| orion \
+			| picochip \
+			| pdp10 | pdp11 | pj | pjl | pn | power \
+			| powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+			| pru \
+			| pyramid \
+			| riscv | riscv32 | riscv64 \
+			| rl78 | romp | rs6000 | rx \
+			| score \
+			| sh | shl \
+			| sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+			| sh[1234]e[lb] |  sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+			| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+			| sparclite \
+			| sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+			| spu \
+			| tahoe \
+			| tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+			| tron \
+			| ubicom32 \
+			| v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+			| vax \
+			| visium \
+			| w65 | wasm32 \
+			| we32k \
+			| x86 | x86_64 | xc16x | xgate | xps100 \
+			| xstormy16 | xtensa* \
+			| ymp \
+			| z8k | z80)
+				;;
+
+			*)
+				echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+				exit 1
+				;;
+		esac
 		;;
 esac
 
 # Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
-	*-digital*)
-		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+case $vendor in
+	digital*)
+		vendor=dec
 		;;
-	*-commodore*)
-		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+	commodore*)
+		vendor=cbm
 		;;
 	*)
 		;;
@@ -1323,197 +1275,246 @@
 
 # Decode manufacturer-specific aliases for certain operating systems.
 
-if [ x"$os" != x"" ]
+if [ x$os != x ]
 then
 case $os in
-	# First match some system type aliases
-	# that might get confused with valid system types.
-	# -solaris* is a basic system type, with this one exception.
-	-auroraux)
-		os=-auroraux
+	# First match some system type aliases that might get confused
+	# with valid system types.
+	# solaris* is a basic system type, with this one exception.
+	auroraux)
+		os=auroraux
 		;;
-	-solaris1 | -solaris1.*)
+	bluegene*)
+		os=cnk
+		;;
+	solaris1 | solaris1.*)
 		os=`echo $os | sed -e 's|solaris1|sunos4|'`
 		;;
-	-solaris)
-		os=-solaris2
+	solaris)
+		os=solaris2
 		;;
-	-svr4*)
-		os=-sysv4
+	unixware*)
+		os=sysv4.2uw
 		;;
-	-unixware*)
-		os=-sysv4.2uw
-		;;
-	-gnu/linux*)
+	gnu/linux*)
 		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
 		;;
-	# First accept the basic system types.
+	# es1800 is here to avoid being matched by es* (a different OS)
+	es1800*)
+		os=ose
+		;;
+	# Some version numbers need modification
+	chorusos*)
+		os=chorusos
+		;;
+	isc)
+		os=isc2.2
+		;;
+	sco6)
+		os=sco5v6
+		;;
+	sco5)
+		os=sco3.2v5
+		;;
+	sco4)
+		os=sco3.2v4
+		;;
+	sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		;;
+	sco3.2v[4-9]* | sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		;;
+	scout)
+		# Don't match below
+		;;
+	sco*)
+		os=sco3.2v2
+		;;
+	psos*)
+		os=psos
+		;;
+	# Now accept the basic system types.
 	# The portable systems comes first.
-	# Each alternative MUST END IN A *, to match a version number.
-	# -sysv* is not here because it comes later, after sysvr4.
-	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
-	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
-	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
-	      | -sym* | -kopensolaris* | -plan9* \
-	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-	      | -aos* | -aros* \
-	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
-	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
-	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
-	      | -bitrig* | -openbsd* | -solidbsd* \
-	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
-	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
-	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
-	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
-	      | -chorusos* | -chorusrdb* | -cegcc* \
-	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
-	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
-	      | -uxpv* | -beos* | -mpeix* | -udk* \
-	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
-	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
-	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
-	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
-	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
-	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Each alternative MUST end in a * to match a version number.
+	# sysv* is not here because it comes later, after sysvr4.
+	gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+	     | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\
+	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+	     | sym* | kopensolaris* | plan9* \
+	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+	     | aos* | aros* | cloudabi* | sortix* \
+	     | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+	     | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+	     | knetbsd* | mirbsd* | netbsd* \
+	     | bitrig* | openbsd* | solidbsd* | libertybsd* \
+	     | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \
+	     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+	     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+	     | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \
+	     | chorusrdb* | cegcc* | glidix* \
+	     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+	     | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \
+	     | linux-newlib* | linux-musl* | linux-uclibc* \
+	     | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+	     | interix* | uwin* | mks* | rhapsody* | darwin* \
+	     | openstep* | oskit* | conix* | pw32* | nonstopux* \
+	     | storm-chaos* | tops10* | tenex* | tops20* | its* \
+	     | os2* | vos* | palmos* | uclinux* | nucleus* \
+	     | morphos* | superux* | rtmk* | windiss* \
+	     | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+	     | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+	     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+	     | midnightbsd* | amdhsa* | unleashed* | emscripten*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
-	-qnx*)
-		case $basic_machine in
-		    x86-* | i*86-*)
+	qnx*)
+		case $cpu in
+		    x86 | i*86)
 			;;
 		    *)
-			os=-nto$os
+			os=nto-$os
 			;;
 		esac
 		;;
-	-nto-qnx*)
+	hiux*)
+		os=hiuxwe2
 		;;
-	-nto*)
+	nto-qnx*)
+		;;
+	nto*)
 		os=`echo $os | sed -e 's|nto|nto-qnx|'`
 		;;
-	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
-	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
-	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+	sim | xray | os68k* | v88r* \
+	    | windows* | osx | abug | netware* | os9* \
+	    | macos* | mpw* | magic* | mmixware* | mon960* | lnews*)
 		;;
-	-mac*)
-		os=`echo $os | sed -e 's|mac|macos|'`
+	linux-dietlibc)
+		os=linux-dietlibc
 		;;
-	-linux-dietlibc)
-		os=-linux-dietlibc
-		;;
-	-linux*)
+	linux*)
 		os=`echo $os | sed -e 's|linux|linux-gnu|'`
 		;;
-	-sunos5*)
-		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+	lynx*178)
+		os=lynxos178
 		;;
-	-sunos6*)
-		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+	lynx*5)
+		os=lynxos5
 		;;
-	-opened*)
-		os=-openedition
+	lynx*)
+		os=lynxos
 		;;
-	-os400*)
-		os=-os400
+	mac*)
+		os=`echo "$os" | sed -e 's|mac|macos|'`
 		;;
-	-wince*)
-		os=-wince
+	opened*)
+		os=openedition
 		;;
-	-osfrose*)
-		os=-osfrose
+	os400*)
+		os=os400
 		;;
-	-osf*)
-		os=-osf
+	sunos5*)
+		os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
 		;;
-	-utek*)
-		os=-bsd
+	sunos6*)
+		os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+		;;
+	wince*)
+		os=wince
 		;;
-	-dynix*)
-		os=-bsd
+	utek*)
+		os=bsd
 		;;
-	-acis*)
-		os=-aos
+	dynix*)
+		os=bsd
 		;;
-	-atheos*)
-		os=-atheos
+	acis*)
+		os=aos
 		;;
-	-syllable*)
-		os=-syllable
+	atheos*)
+		os=atheos
+		;;
+	syllable*)
+		os=syllable
 		;;
-	-386bsd)
-		os=-bsd
+	386bsd)
+		os=bsd
 		;;
-	-ctix* | -uts*)
-		os=-sysv
+	ctix* | uts*)
+		os=sysv
 		;;
-	-nova*)
-		os=-rtmk-nova
+	nova*)
+		os=rtmk-nova
 		;;
-	-ns2 )
-		os=-nextstep2
+	ns2)
+		os=nextstep2
 		;;
-	-nsk*)
-		os=-nsk
+	nsk*)
+		os=nsk
 		;;
 	# Preserve the version number of sinix5.
-	-sinix5.*)
+	sinix5.*)
 		os=`echo $os | sed -e 's|sinix|sysv|'`
 		;;
-	-sinix*)
-		os=-sysv4
+	sinix*)
+		os=sysv4
 		;;
-	-tpf*)
-		os=-tpf
+	tpf*)
+		os=tpf
 		;;
-	-triton*)
-		os=-sysv3
+	triton*)
+		os=sysv3
 		;;
-	-oss*)
-		os=-sysv3
+	oss*)
+		os=sysv3
 		;;
-	-svr4)
-		os=-sysv4
+	svr4*)
+		os=sysv4
 		;;
-	-svr3)
-		os=-sysv3
+	svr3)
+		os=sysv3
 		;;
-	-sysvr4)
-		os=-sysv4
+	sysvr4)
+		os=sysv4
 		;;
-	# This must come after -sysvr4.
-	-sysv*)
+	# This must come after sysvr4.
+	sysv*)
+		;;
+	ose*)
+		os=ose
 		;;
-	-ose*)
-		os=-ose
-		;;
-	-es1800*)
-		os=-ose
+	*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+		os=mint
 		;;
-	-xenix)
-		os=-xenix
+	zvmoe)
+		os=zvmoe
 		;;
-	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
-		os=-mint
+	dicos*)
+		os=dicos
 		;;
-	-aros*)
-		os=-aros
-		;;
-	-zvmoe)
-		os=-zvmoe
+	pikeos*)
+		# Until real need of OS specific support for
+		# particular features comes up, bare metal
+		# configurations are quite functional.
+		case $cpu in
+		    arm*)
+			os=eabi
+			;;
+		    *)
+			os=elf
+			;;
+		esac
 		;;
-	-dicos*)
-		os=-dicos
+	nacl*)
+		;;
+	ios)
 		;;
-	-nacl*)
+	none)
 		;;
-	-none)
+	*-eabi)
 		;;
 	*)
-		# Get rid of the `-' at the beginning of $os.
-		os=`echo $os | sed 's/[^-]*-//'`
-		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
 		exit 1
 		;;
 esac
@@ -1529,264 +1530,265 @@
 # will signal an error saying that MANUFACTURER isn't an operating
 # system, and we'll never get to this point.
 
-case $basic_machine in
+case $cpu-$vendor in
 	score-*)
-		os=-elf
+		os=elf
 		;;
 	spu-*)
-		os=-elf
+		os=elf
 		;;
 	*-acorn)
-		os=-riscix1.2
+		os=riscix1.2
 		;;
 	arm*-rebel)
-		os=-linux
+		os=linux
 		;;
 	arm*-semi)
-		os=-aout
+		os=aout
 		;;
 	c4x-* | tic4x-*)
-		os=-coff
+		os=coff
 		;;
 	c8051-*)
-		os=-elf
+		os=elf
+		;;
+	clipper-intergraph)
+		os=clix
 		;;
 	hexagon-*)
-		os=-elf
+		os=elf
 		;;
 	tic54x-*)
-		os=-coff
+		os=coff
 		;;
 	tic55x-*)
-		os=-coff
+		os=coff
 		;;
 	tic6x-*)
-		os=-coff
+		os=coff
 		;;
 	# This must come before the *-dec entry.
 	pdp10-*)
-		os=-tops20
+		os=tops20
 		;;
 	pdp11-*)
-		os=-none
+		os=none
 		;;
 	*-dec | vax-*)
-		os=-ultrix4.2
+		os=ultrix4.2
 		;;
 	m68*-apollo)
-		os=-domain
+		os=domain
 		;;
 	i386-sun)
-		os=-sunos4.0.2
+		os=sunos4.0.2
 		;;
 	m68000-sun)
-		os=-sunos3
+		os=sunos3
 		;;
 	m68*-cisco)
-		os=-aout
+		os=aout
 		;;
 	mep-*)
-		os=-elf
+		os=elf
 		;;
 	mips*-cisco)
-		os=-elf
+		os=elf
 		;;
 	mips*-*)
-		os=-elf
-		;;
-	or1k-*)
-		os=-elf
+		os=elf
 		;;
 	or32-*)
-		os=-coff
+		os=coff
 		;;
 	*-tti)	# must be before sparc entry or we get the wrong os.
-		os=-sysv3
+		os=sysv3
 		;;
 	sparc-* | *-sun)
-		os=-sunos4.1.1
+		os=sunos4.1.1
+		;;
+	pru-*)
+		os=elf
 		;;
 	*-be)
-		os=-beos
-		;;
-	*-haiku)
-		os=-haiku
+		os=beos
 		;;
 	*-ibm)
-		os=-aix
+		os=aix
 		;;
 	*-knuth)
-		os=-mmixware
+		os=mmixware
 		;;
 	*-wec)
-		os=-proelf
+		os=proelf
 		;;
 	*-winbond)
-		os=-proelf
+		os=proelf
 		;;
 	*-oki)
-		os=-proelf
+		os=proelf
 		;;
 	*-hp)
-		os=-hpux
+		os=hpux
 		;;
 	*-hitachi)
-		os=-hiux
+		os=hiux
 		;;
 	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
-		os=-sysv
+		os=sysv
 		;;
 	*-cbm)
-		os=-amigaos
+		os=amigaos
 		;;
 	*-dg)
-		os=-dgux
+		os=dgux
 		;;
 	*-dolphin)
-		os=-sysv3
+		os=sysv3
 		;;
 	m68k-ccur)
-		os=-rtu
+		os=rtu
 		;;
 	m88k-omron*)
-		os=-luna
-		;;
-	*-next )
-		os=-nextstep
-		;;
-	*-sequent)
-		os=-ptx
-		;;
-	*-crds)
-		os=-unos
-		;;
-	*-ns)
-		os=-genix
-		;;
-	i370-*)
-		os=-mvs
+		os=luna
 		;;
 	*-next)
-		os=-nextstep3
+		os=nextstep
+		;;
+	*-sequent)
+		os=ptx
+		;;
+	*-crds)
+		os=unos
+		;;
+	*-ns)
+		os=genix
+		;;
+	i370-*)
+		os=mvs
 		;;
 	*-gould)
-		os=-sysv
+		os=sysv
 		;;
 	*-highlevel)
-		os=-bsd
+		os=bsd
 		;;
 	*-encore)
-		os=-bsd
+		os=bsd
 		;;
 	*-sgi)
-		os=-irix
+		os=irix
 		;;
 	*-siemens)
-		os=-sysv4
+		os=sysv4
 		;;
 	*-masscomp)
-		os=-rtu
+		os=rtu
 		;;
 	f30[01]-fujitsu | f700-fujitsu)
-		os=-uxpv
+		os=uxpv
 		;;
 	*-rom68k)
-		os=-coff
+		os=coff
 		;;
 	*-*bug)
-		os=-coff
+		os=coff
 		;;
 	*-apple)
-		os=-macos
+		os=macos
 		;;
 	*-atari*)
-		os=-mint
+		os=mint
+		;;
+	*-wrs)
+		os=vxworks
 		;;
 	*)
-		os=-none
+		os=none
 		;;
 esac
 fi
 
 # Here we handle the case where we know the os, and the CPU type, but not the
 # manufacturer.  We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
-	*-unknown)
+case $vendor in
+	unknown)
 		case $os in
-			-riscix*)
+			riscix*)
 				vendor=acorn
 				;;
-			-sunos*)
+			sunos*)
 				vendor=sun
 				;;
-			-cnk*|-aix*)
+			cnk*|-aix*)
 				vendor=ibm
 				;;
-			-beos*)
+			beos*)
 				vendor=be
 				;;
-			-hpux*)
+			hpux*)
 				vendor=hp
 				;;
-			-mpeix*)
+			mpeix*)
 				vendor=hp
 				;;
-			-hiux*)
+			hiux*)
 				vendor=hitachi
 				;;
-			-unos*)
+			unos*)
 				vendor=crds
 				;;
-			-dgux*)
+			dgux*)
 				vendor=dg
 				;;
-			-luna*)
+			luna*)
 				vendor=omron
 				;;
-			-genix*)
+			genix*)
 				vendor=ns
 				;;
-			-mvs* | -opened*)
+			clix*)
+				vendor=intergraph
+				;;
+			mvs* | opened*)
 				vendor=ibm
 				;;
-			-os400*)
+			os400*)
 				vendor=ibm
 				;;
-			-ptx*)
+			ptx*)
 				vendor=sequent
 				;;
-			-tpf*)
+			tpf*)
 				vendor=ibm
 				;;
-			-vxsim* | -vxworks* | -windiss*)
+			vxsim* | vxworks* | windiss*)
 				vendor=wrs
 				;;
-			-aux*)
+			aux*)
 				vendor=apple
 				;;
-			-hms*)
+			hms*)
 				vendor=hitachi
 				;;
-			-mpw* | -macos*)
+			mpw* | macos*)
 				vendor=apple
 				;;
-			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+			*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
 				vendor=atari
 				;;
-			-vos*)
+			vos*)
 				vendor=stratus
 				;;
 		esac
-		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
 		;;
 esac
 
-echo $basic_machine$os
+echo "$cpu-$vendor-$os"
 exit
 
 # Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
+# eval: (add-hook 'before-save-hook 'time-stamp)
 # time-stamp-start: "timestamp='"
 # time-stamp-format: "%:y-%02m-%02d"
 # time-stamp-end: "'"
--- a/configure.ac	Thu Mar 21 23:28:59 2019 +0800
+++ b/configure.ac	Fri Jun 26 21:07:34 2020 +0800
@@ -323,17 +323,39 @@
 	]
 )
 
+AC_ARG_ENABLE(plugin,
+	[  --enable-plugin         Enable support for External Public Key Authentication plug-in],
+	[
+		AC_DEFINE(DROPBEAR_PLUGIN, 1, External Public Key Authentication)
+		AC_MSG_NOTICE(Enabling support for External Public Key Authentication)
+		DROPBEAR_PLUGIN=1
+	],
+	[
+		AC_DEFINE(DROPBEAR_PLUGIN, 0, External Public Key Authentication)
+		DROPBEAR_PLUGIN=0
+	]
+
+)
+AC_SUBST(DROPBEAR_PLUGIN)
+
 AC_ARG_ENABLE(fuzz,
 	[  --enable-fuzz           Build fuzzing. Not recommended for deployment.],
 	[
-		AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
-		AC_MSG_NOTICE(Enabling fuzzing)
-		DROPBEAR_FUZZ=1
-		# libfuzzer needs linking with c++ libraries
-		AC_PROG_CXX
+		if test "x$enableval" = "xyes"; then
+            AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
+            AC_MSG_NOTICE(Enabling fuzzing)
+            DROPBEAR_FUZZ=1
+            # libfuzzer needs linking with c++ libraries
+            AC_PROG_CXX
+        else
+            AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
+            AC_MSG_NOTICE(Disabling fuzzing)
+            DROPBEAR_FUZZ=0
+        fi
 	],
 	[
 		AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
+		AC_MSG_NOTICE(Disabling fuzzing)
 		DROPBEAR_FUZZ=0
 	]
 
@@ -348,7 +370,8 @@
 	crypt.h \
 	pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \
 	utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \
-	pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h])
+	pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \
+	sys/random.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
@@ -504,28 +527,29 @@
 AC_CHECK_HEADERS([mach/mach_time.h])
 AC_CHECK_FUNCS(mach_absolute_time)
 
-AC_CHECK_FUNCS(explicit_bzero memset_s)
+AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
 
 AC_ARG_ENABLE(bundled-libtom,
 [  --enable-bundled-libtom       Force using bundled libtomcrypt/libtommath even if a system version exists.
   --disable-bundled-libtom      Force using system libtomcrypt/libtommath, fail if it does not exist.
-                                Default is to use system if available, otherwise bundled.],
+                                Default is to use system if available, otherwise bundled.
+                                Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0],
 	[
 		if test "x$enableval" = "xyes"; then
 			BUNDLED_LIBTOM=1
 			AC_MSG_NOTICE(Forcing bundled libtom*)
 		else
 			BUNDLED_LIBTOM=0
-			AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
-				[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
-			AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
-				[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
+			AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
+				[AC_MSG_ERROR([Missing/old system libtommath and --disable-bundled-libtom was specified])] )
+			AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
+				[AC_MSG_ERROR([Missing/old system libtomcrypt and --disable-bundled-libtom was specified])] )
 		fi
 	],
 	[
 		BUNDLED_LIBTOM=0
-		AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
-		AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
+		AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
+		AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
 	]
 )
 
@@ -858,4 +882,4 @@
 fi
 
 AC_MSG_NOTICE()
-AC_MSG_NOTICE([Now edit options.h to choose features.])
+AC_MSG_NOTICE([Now edit localoptions.h to choose features.])
--- a/curve25519-donna.c	Thu Mar 21 23:28:59 2019 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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 <[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. */
-
-#include <string.h>
-#include <stdint.h>
-
-#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;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/curve25519.c	Fri Jun 26 21:07:34 2020 +0800
@@ -0,0 +1,497 @@
+/*
+ * 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
+void 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);
+}
+#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);
+}
+
+void 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);
+}
+
+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);
+}
+
+void 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);
+}
+
+#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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/curve25519.h	Fri Jun 26 21:07:34 2020 +0800
@@ -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
+
+void dropbear_curve25519_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
+void dropbear_ed25519_make_key(unsigned char *pk, unsigned char  *sk);
+void 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 */
--- a/dbmalloc.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/dbmalloc.c	Fri Jun 26 21:07:34 2020 +0800
@@ -180,3 +180,13 @@
 }
 
 #endif /* DROPBEAR_TRACKING_MALLOC */
+
+void * m_realloc_ltm(void* ptr, size_t oldsize, size_t newsize) {
+   (void)oldsize;
+   return m_realloc(ptr, newsize);
+}
+
+void m_free_ltm(void *mem, size_t size) {
+   (void)size;
+   m_free_direct(mem);
+}
--- a/dbrandom.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/dbrandom.c	Fri Jun 26 21:07:34 2020 +0800
@@ -49,24 +49,19 @@
  *
  */
 
-/* Pass len=0 to hash an entire file */
+/* Pass wantlen=0 to hash an entire file */
 static int
 process_file(hash_state *hs, const char *filename,
-		unsigned int len, int prngd)
-{
-	static int already_blocked = 0;
-	int readfd;
+		unsigned int wantlen, int prngd) {
+	int readfd = -1;
 	unsigned int readcount;
 	int ret = DROPBEAR_FAILURE;
 
+	if (prngd) {
 #if DROPBEAR_USE_PRNGD
-	if (prngd)
-	{
 		readfd = connect_unix(filename);
-	}
-	else
 #endif
-	{
+	} else {
 		readfd = open(filename, O_RDONLY);
 	}
 
@@ -75,58 +70,31 @@
 	}
 
 	readcount = 0;
-	while (len == 0 || readcount < len)
-	{
+	while (wantlen == 0 || readcount < wantlen) {
 		int readlen, wantread;
 		unsigned char readbuf[4096];
-		if (!already_blocked && !prngd)
-		{
-			int res;
-			struct timeval timeout;
-			fd_set read_fds;
-
- 			timeout.tv_sec  = 2;
- 			timeout.tv_usec = 0;
-
-			DROPBEAR_FD_ZERO(&read_fds);
-			FD_SET(readfd, &read_fds);
-			res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
-			if (res == 0)
-			{
-				dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
-				already_blocked = 1;
-			}
-		}
-
-		if (len == 0)
-		{
+		if (wantlen == 0) {
 			wantread = sizeof(readbuf);
-		} 
-		else
-		{
-			wantread = MIN(sizeof(readbuf), len-readcount);
+		} else {
+			wantread = MIN(sizeof(readbuf), wantlen-readcount);
 		}
 
 #if DROPBEAR_USE_PRNGD
-		if (prngd)
-		{
+		if (prngd) {
 			char egdcmd[2];
 			egdcmd[0] = 0x02;	/* blocking read */
 			egdcmd[1] = (unsigned char)wantread;
-			if (write(readfd, egdcmd, 2) < 0)
-			{
+			if (write(readfd, egdcmd, 2) < 0) {
 				dropbear_exit("Can't send command to egd");
 			}
 		}
 #endif
-
 		readlen = read(readfd, readbuf, wantread);
 		if (readlen <= 0) {
 			if (readlen < 0 && errno == EINTR) {
 				continue;
 			}
-			if (readlen == 0 && len == 0)
-			{
+			if (readlen == 0 && wantlen == 0) {
 				/* whole file was read as requested */
 				break;
 			}
@@ -193,6 +161,63 @@
 }
 #endif
 
+
+#ifdef HAVE_GETRANDOM
+/* Reads entropy seed with getrandom(). 
+ * May block if the kernel isn't ready.
+ * Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
+static int process_getrandom(hash_state *hs) {
+	char buf[INIT_SEED_SIZE];
+	ssize_t ret;
+
+	/* First try non-blocking so that we can warn about waiting */
+	ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK);
+	if (ret == -1) {
+		if (errno == ENOSYS) {
+			/* Old kernel */
+			return DROPBEAR_FAILURE;
+		}
+		/* Other errors fall through to blocking getrandom() */
+		TRACE(("first getrandom() failed: %d %s", errno, strerror(errno)))
+		if (errno == EAGAIN) {
+			dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised...");
+		}
+	}
+
+	/* Wait blocking if needed. Loop in case we get EINTR */
+	while (ret != sizeof(buf)) {
+		ret = getrandom(buf, sizeof(buf), 0);
+
+		if (ret == sizeof(buf)) {
+			/* Success */
+			break;
+		}
+		if (ret == -1 && errno == EINTR) {
+			/* Try again. */
+			continue;
+		}
+		if (ret >= 0) {
+			TRACE(("Short read %zd from getrandom() shouldn't happen", ret))
+			/* Try again? */
+			continue;
+		}
+
+		/* Unexpected problem, fall back to /dev/urandom */
+		TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno)))
+		break;
+	}
+
+	if (ret == sizeof(buf)) {
+		/* Success, stir in the entropy */
+		sha1_process(hs, (void*)buf, sizeof(buf));
+		return DROPBEAR_SUCCESS;
+	}
+
+	return DROPBEAR_FAILURE;
+
+}
+#endif /* HAVE_GETRANDOM */
+
 /* Initialise the prng from /dev/urandom or prngd. This function can
  * be called multiple times */
 void seedrandom() {
@@ -202,6 +227,7 @@
 	pid_t pid;
 	struct timeval tv;
 	clock_t clockval;
+	int urandom_seeded = 0;
 
 #if DROPBEAR_FUZZ
 	if (fuzz.fuzzing) {
@@ -215,21 +241,31 @@
 	/* existing state */
 	sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
 
-#if DROPBEAR_USE_PRNGD
-	if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) 
-			!= DROPBEAR_SUCCESS) {
-		dropbear_exit("Failure reading random device %s", 
-				DROPBEAR_PRNGD_SOCKET);
-	}
-#else
-	/* non-blocking random source (probably /dev/urandom) */
-	if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) 
-			!= DROPBEAR_SUCCESS) {
-		dropbear_exit("Failure reading random device %s", 
-				DROPBEAR_URANDOM_DEV);
+#ifdef HAVE_GETRANDOM
+	if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
+		urandom_seeded = 1;
 	}
 #endif
 
+	if (!urandom_seeded) {
+#if DROPBEAR_USE_PRNGD
+		if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) 
+				!= DROPBEAR_SUCCESS) {
+			dropbear_exit("Failure reading random device %s", 
+					DROPBEAR_PRNGD_SOCKET);
+			urandom_seeded = 1;
+		}
+#else
+		/* non-blocking random source (probably /dev/urandom) */
+		if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) 
+				!= DROPBEAR_SUCCESS) {
+			dropbear_exit("Failure reading random device %s", 
+					DROPBEAR_URANDOM_DEV);
+			urandom_seeded = 1;
+		}
+#endif
+	} /* urandom_seeded */
+
 	/* A few other sources to fall back on. 
 	 * Add more here for other platforms */
 #ifdef __linux__
--- a/debian/changelog	Thu Mar 21 23:28:59 2019 +0800
+++ b/debian/changelog	Fri Jun 26 21:07:34 2020 +0800
@@ -1,3 +1,21 @@
+dropbear (2020.79-0.1) unstable; urgency=low
+
+  * New upstream release.
+
+ -- Matt Johnston <[email protected]>  Mon, 15 Jun 2020 22:51:57 +0800
+
+dropbear (2019.78-0.1) unstable; urgency=low
+
+  * New upstream release.
+
+ -- Matt Johnston <[email protected]>  Wed, 27 Mar 2019 22:51:57 +0800
+
+dropbear (2019.77-0.1) unstable; urgency=low
+
+  * New upstream release.
+
+ -- Matt Johnston <[email protected]>  Sat, 23 Mar 2019 22:51:57 +0800
+
 dropbear (2018.76-0.1) unstable; urgency=low
 
   * New upstream release.
--- a/debug.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/debug.h	Fri Jun 26 21:07:34 2020 +0800
@@ -43,12 +43,6 @@
 #define CHECKCLEARTOWRITE()
 #endif
 
-/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
- * output when Dropbear forks. This will allow it gprof to be used.
- * It's useful to run dropbear -F, so you don't fork as much */
-/* (This is Linux specific) */
-/*#define DEBUG_FORKGPROF*/
-
 /* A couple of flags, not usually useful, and mightn't do anything */
 
 /*#define DEBUG_KEXHASH*/
@@ -66,7 +60,9 @@
 
 /* To debug with GDB it is easier to run with no forking of child processes.
    You will need to pass "-F" as well. */
-/* #define DEBUG_NOFORK */
+#ifndef DEBUG_NOFORK
+#define DEBUG_NOFORK 0
+#endif
 
 
 /* For testing as non-root on shadowed systems, include the crypt of a password
--- a/default_options.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/default_options.h	Fri Jun 26 21:07:34 2020 +0800
@@ -22,6 +22,7 @@
 #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.
@@ -47,7 +48,7 @@
 #define DROPBEAR_SMALL_CODE 1
 
 /* Enable X11 Forwarding - server only */
-#define DROPBEAR_X11FWD 1
+#define DROPBEAR_X11FWD 0
 
 /* Enable TCP Fowarding */
 /* 'Local' is "-L" style (client listening port forwarded via server)
@@ -82,27 +83,36 @@
  * Including both AES keysize variants (128 and 256) will result in 
  * a minimal size increase */
 #define DROPBEAR_AES128 1
-#define DROPBEAR_3DES 1
 #define DROPBEAR_AES256 1
+#define DROPBEAR_3DES 0
 #define DROPBEAR_TWOFISH256 0
 #define DROPBEAR_TWOFISH128 0
-/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
-#define DROPBEAR_BLOWFISH 0
+
+/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
+ * generally faster than AES256 on CPU w/o dedicated AES instructions,
+ * having the same key size. Recommended.
+ * Compiling in will add ~5,5kB to binary size on x86-64 */
+#define DROPBEAR_CHACHA20POLY1305 1
+
+/* Enable "Counter Mode" for ciphers. Recommended. */
+#define DROPBEAR_ENABLE_CTR_MODE 1
 
 /* Enable CBC mode for ciphers. This has security issues though
- * is the most compatible with older SSH implementations */
-#define DROPBEAR_ENABLE_CBC_MODE 1
+   may be required for compatibility with old implementations */
+#define DROPBEAR_ENABLE_CBC_MODE 0
 
-/* Enable "Counter Mode" for ciphers. This is more secure than
- * CBC mode against certain attacks. It is recommended for security
- * and forwards compatibility */
-#define DROPBEAR_ENABLE_CTR_MODE 1
+/* Enable "Galois/Counter Mode" for ciphers. This authenticated
+ * encryption mode is combination of CTR mode and GHASH. Recommended
+ * for security and forwards compatibility, but slower than CTR on
+ * CPU w/o dedicated AES/GHASH instructions.
+ * Compiling in will add ~6kB to binary size on x86-64 */
+#define DROPBEAR_ENABLE_GCM_MODE 0
 
 /* Message integrity. sha2-256 is recommended as a default, 
    sha1 for compatibility */
 #define DROPBEAR_SHA1_HMAC 1
-#define DROPBEAR_SHA1_96_HMAC 1
 #define DROPBEAR_SHA2_256_HMAC 1
+#define DROPBEAR_SHA1_96_HMAC 0
 
 /* Hostkey/public key algorithms - at least one required, these are used
  * for hostkey as well as for verifying signatures with pubkey auth.
@@ -116,11 +126,15 @@
  * 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 +157,7 @@
  * 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.
@@ -174,7 +188,7 @@
 #define DO_HOST_LOOKUP 0
 
 /* Whether to print the message of the day (MOTD). */
-#define DO_MOTD 0
+#define DO_MOTD 1
 #define MOTD_FILENAME "/etc/motd"
 
 /* Authentication Types - at least one required.
--- a/dh_groups.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/dh_groups.c	Fri Jun 26 21:07:34 2020 +0800
@@ -1,6 +1,8 @@
 #include "options.h"
 #include "dh_groups.h"
 
+#if DROPBEAR_NORMAL_DH
+
 #if DROPBEAR_DH_GROUP1
 /* diffie-hellman-group1-sha1 value for p */
 const unsigned char dh_p_1[DH_P_1_LEN] = {
@@ -92,3 +94,4 @@
 /* Same for all groups */
 const int DH_G_VAL = 2;
 
+#endif /* DROPBEAR_NORMAL_DH */
--- a/dh_groups.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/dh_groups.h	Fri Jun 26 21:07:34 2020 +0800
@@ -2,6 +2,8 @@
 #define DROPBEAR_DH_GROUPS_H
 #include "options.h"
 
+#if DROPBEAR_NORMAL_DH
+
 #if DROPBEAR_DH_GROUP1
 #define DH_P_1_LEN 128
 extern const unsigned char dh_p_1[DH_P_1_LEN];
@@ -17,8 +19,8 @@
 extern const unsigned char dh_p_16[DH_P_16_LEN];
 #endif
 
-
 extern const int DH_G_VAL;
 
+#endif /* DROPBEAR_NORMAL_DH */
 
 #endif
--- a/dropbear.8	Thu Mar 21 23:28:59 2019 +0800
+++ b/dropbear.8	Fri Jun 26 21:07:34 2020 +0800
@@ -107,7 +107,7 @@
 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 @@
 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. 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dropbear_lint.sh	Fri Jun 26 21:07:34 2020 +0800
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+EXITCODE=0
+
+# #ifdef instead of #if
+grep '#ifdef DROPBEAR' -I *.c *.h && EXITCODE=1
+
+exit $EXITCODE
--- a/dropbearkey.1	Thu Mar 21 23:28:59 2019 +0800
+++ b/dropbearkey.1	Fri Jun 26 21:07:34 2020 +0800
@@ -13,7 +13,7 @@
 .SH DESCRIPTION
 .B dropbearkey
 generates a
-\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
+\fIRSA\fR, \fIDSS\fR, \fIECDSA\fR, or \fIEd25519\fR
 format SSH private key, and saves it to a file for the use with the
 Dropbear client or server.
 Note that 
@@ -26,6 +26,7 @@
 Must be one of
 .I rsa
 .I ecdsa
+.I ed25519
 or
 .IR dss .
 .TP
--- a/dropbearkey.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/dropbearkey.c	Fri Jun 26 21:07:34 2020 +0800
@@ -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"
@@ -76,6 +81,9 @@
 #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"
 					"-s bits	Key size in bits, should be a multiple of 8 (optional)\n"
@@ -95,6 +103,9 @@
 #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 <filename>.\n"
 #if DEBUG_TRACE
 					"-v		verbose\n"
@@ -106,6 +117,14 @@
 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)) {
@@ -114,7 +133,7 @@
 			}
 			break;
 #endif
-#ifdef DROPEAR_DSS
+#if DROPEAR_DSS
 		case DROPBEAR_SIGNKEY_DSS:
 			if (bits != 1024) {
 				dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
@@ -224,6 +243,12 @@
 		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);
--- a/dss.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/dss.c	Fri Jun 26 21:07:34 2020 +0800
@@ -284,6 +284,7 @@
 	unsigned char msghash[SHA1_HASH_SIZE];
 	unsigned int writelen;
 	unsigned int i;
+	size_t written;
 	DEF_MP_INT(dss_k);
 	DEF_MP_INT(dss_m);
 	DEF_MP_INT(dss_temp1);
@@ -340,31 +341,31 @@
 	buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
 	buf_putint(buf, 2*SHA1_HASH_SIZE);
 
-	writelen = mp_unsigned_bin_size(&dss_r);
+	writelen = mp_ubin_size(&dss_r);
 	dropbear_assert(writelen <= SHA1_HASH_SIZE);
 	/* need to pad to 160 bits with leading zeros */
 	for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
 		buf_putbyte(buf, 0);
 	}
-	if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen)) 
+	if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
 			!= MP_OKAY) {
 		dropbear_exit("DSS error");
 	}
 	mp_clear(&dss_r);
-	buf_incrwritepos(buf, writelen);
+	buf_incrwritepos(buf, written);
 
-	writelen = mp_unsigned_bin_size(&dss_s);
+	writelen = mp_ubin_size(&dss_s);
 	dropbear_assert(writelen <= SHA1_HASH_SIZE);
 	/* need to pad to 160 bits with leading zeros */
 	for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
 		buf_putbyte(buf, 0);
 	}
-	if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen)) 
+	if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
 			!= MP_OKAY) {
 		dropbear_exit("DSS error");
 	}
 	mp_clear(&dss_s);
-	buf_incrwritepos(buf, writelen);
+	buf_incrwritepos(buf, written);
 
 	mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
 			&dss_m, NULL);
--- a/dss.h	Thu Mar 21 23:28:59 2019 +0800
+++ b/dss.h	Fri Jun 26 21:07:34 2020 +0800
@@ -30,7 +30,7 @@
 
 #if DROPBEAR_DSS 
 
-typedef struct {
+typedef struct dropbear_DSS_Key {
 
 	mp_int* p;
 	mp_int* q;
--- a/ecc.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/ecc.c	Fri Jun 26 21:07:34 2020 +0800
@@ -166,13 +166,13 @@
 	key = new_ecc_key();
 	key->dp = curve->dp;
 
-	if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
+	if (mp_from_ubin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
 		TRACE(("failed to read x"))
 		goto out;
 	}
 	buf_incrpos(buf, size);
 
-	if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
+	if (mp_from_ubin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
 		TRACE(("failed to read y"))
 		goto out;
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ed25519.c	Fri Jun 26 21:07:34 2020 +0800
@@ -0,0 +1,182 @@
+/*
+ * 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_priv_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 ed25519_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);
+
+	dropbear_ed25519_sign(data_buf->data, data_buf->len, s, &slen, key->priv, key->pub);
+	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(("leave buf_ed25519_verify: 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(("leave buf_ed25519_verify: success!"))
+		ret = DROPBEAR_SUCCESS;
+	}
+
+out:
+	TRACE(("leave buf_ed25519_verify: ret %d", ret))
+	return ret;
+}
+
+#endif /* DROPBEAR_SIGNKEY_VERIFY */
+
+#endif /* DROPBEAR_ED25519 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ed25519.h	Fri Jun 26 21:07:34 2020 +0800
@@ -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 dropbear_ED25519_Key {
+
+	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_ */
--- a/filelist.txt	Thu Mar 21 23:28:59 2019 +0800
+++ b/filelist.txt	Fri Jun 26 21:07:34 2020 +0800
@@ -99,6 +99,10 @@
 
 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
--- a/fuzz-common.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/fuzz-common.c	Fri Jun 26 21:07:34 2020 +0800
@@ -112,6 +112,14 @@
         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);
 }
 
@@ -139,7 +147,7 @@
 void fuzz_fake_send_kexdh_reply(void) {
     assert(!ses.dh_K);
     m_mp_alloc_init_multi(&ses.dh_K, NULL);
-    mp_set_int(ses.dh_K, 12345678);
+    mp_set_ul(ses.dh_K, 12345678uL);
     finish_kexhashbuf();
 }
 
--- a/fuzz-hostkeys.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/fuzz-hostkeys.c	Fri Jun 26 21:07:34 2020 +0800
@@ -127,3 +127,13 @@
   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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fuzzer-kexcurve25519.c	Fri Jun 26 21:07:34 2020 +0800
@@ -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;
+}
--- a/fuzzer-pubkey.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/fuzzer-pubkey.c	Fri Jun 26 21:07:34 2020 +0800
@@ -27,7 +27,7 @@
 		unsigned int algolen;
 		char* algoname = buf_getstring(keyblob, &algolen);
 
-		if (have_algo(algoname, algolen, sshhostkey) == DROPBEAR_FAILURE) {
+		if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNKEY_NONE) {
 			dropbear_exit("fuzzer imagined a bogus algorithm");
 		}
 
--- a/fuzzer-verify.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/fuzzer-verify.c	Fri Jun 26 21:07:34 2020 +0800
@@ -2,6 +2,7 @@
 #include "session.h"
 #include "fuzz-wrapfd.h"
 #include "debug.h"
+#include "dss.h"
 
 static void setup_fuzzer(void) {
 	fuzz_common_setup();
@@ -27,21 +28,35 @@
 
 	if (setjmp(fuzz.jmp) == 0) {
 		sign_key *key = new_sign_key();
-		enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
-		if (buf_get_pub_key(fuzz.input, key, &type) == DROPBEAR_SUCCESS) {
-			if (buf_verify(fuzz.input, key, verifydata) == DROPBEAR_SUCCESS) {
+		enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY;
+		if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
+			enum signature_type sigtype;
+			if (keytype == DROPBEAR_SIGNKEY_RSA) {
+				/* Flip a coin to decide rsa signature type */
+				int flag = buf_getbyte(fuzz.input);
+				if (flag & 0x01) {
+					sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
+				} else {
+					sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
+				}
+			} else {
+				sigtype = signature_type_from_signkey(keytype);
+			}
+			if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) {
 				/* The fuzzer is capable of generating keys with a signature to match.
 				We don't want false positives if the key is bogus, since a client/server 
 				wouldn't be trusting a bogus key anyway */
 				int boguskey = 0;
 
-				if (type == DROPBEAR_SIGNKEY_DSS) {
+				if (keytype == DROPBEAR_SIGNKEY_DSS) {
 					/* So far have seen dss keys with bad p/q/g domain parameters */
-					int pprime, qprime;
-				    assert(mp_prime_is_prime(key->dsskey->p, 5, &pprime) == MP_OKAY);
-				    assert(mp_prime_is_prime(key->dsskey->q, 18, &qprime) == MP_OKAY);
-				    boguskey = !(pprime && qprime);
-				    /* Could also check g**q mod p == 1 */
+					int pprime, qprime, trials;
+					trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
+					assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
+					trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
+					assert(mp_prime_is_prime(key->dsskey->q, trials, &qprime) == MP_OKAY);
+					boguskey = !(pprime && qprime);
+					/* Could also check g**q mod p == 1 */
 				}
 
 				if (!boguskey) {
--- a/fuzzers_test.sh	Thu Mar 21 23:28:59 2019 +0800
+++ b/fuzzers_test.sh	Fri Jun 26 21:07:34 2020 +0800
@@ -4,7 +4,7 @@
 
 result=0
 
-hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
+test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
 for f in `make list-fuzz-targets`; do
     ./$f fuzzcorpus/$f/* || result=1
 done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcm.c	Fri Jun 26 21:07:34 2020 +0800
@@ -0,0 +1,120 @@
+/*
+ * 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 "gcm.h"
+
+#if DROPBEAR_ENABLE_GCM_MODE
+
+#define GHASH_LEN 16
+