changeset 1739:13d834efc376 fuzz

merge from main
author Matt Johnston <matt@ucc.asn.au>
date Thu, 15 Oct 2020 19:55:15 +0800
parents 768ebf737aa0 (current diff) 4f13df974cf4 (diff)
children dfbe947bdf0d
files
diffstat 449 files changed, 18144 insertions(+), 49158 deletions(-) [+]
line wrap: on
line diff
--- a/.gitignore	Wed Feb 28 22:11:39 2018 +0800
+++ b/.gitignore	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/.hgsigs	Thu Oct 15 19:55:15 2020 +0800
@@ -24,3 +24,7 @@
 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=
+88f63b8b0f131f24aa90c9b852622b922b1ad738 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAl71/sAACgkQRJMUlPKcZ3OlSQ/9GYLotOmsYK0gvSfWLYR9a8WGgT/4EU6RgAkMBLS9TBp0E3V4VUDralnqoId7hNO2cUkRS7boOM2g4/YRShah8gonSJa70lKjUpDeQUPuGwUYWLNKr9qxJtnAcd1rOE4WYxKEUfjPWHBbVsT3QIIdj1Zy31GDKZgELRBQeOyt62RdXYHMaMHHDgg2U/wO9bcRRe5G7mYJf7Vm8sAWyTZXvta2jORxgs4XxWe7xJ9Dj0lMSG5HmfvH5NrGHM1GK3pL0GREKj2+xNSFdkSeHIgSSoHM2qZTVSWtNfx0+fZaRBgvXPPYzDTTghj1mKEaPFoRzg/B8s+NmHupJftT1yyapKFjALo1N6eaPHRRSwVfmnoWSJLu4fwL8TK5wMJr9eGl3QgAnperQPEFT9UHJBIwZ1D+RMuI3pEESdHBJFAYIAyisJI6XyzMhLsysoShlHs6OjFcJ9jTe4pzg9pO+KaPbLYsBJxJUsrtHwV8P9CHxY6CEuKm0AZjYDopYhzLuAUjGJjYDf/C9vJ/xtTOqIm9nywfcFwqgLrmQFhNHHGyOJVr+y/cey1sT9E4/gBv9kor+6qSITALv2g0JTaOpzpkE0zbafUy2r777Wex4WNQEha6bYZFi2aiqxqqX93UHzv+YhmN8n9mlc21xoZMPNtAb2mSxx7rO+PScb5uflKOCYE=
--- a/.hgtags	Wed Feb 28 22:11:39 2018 +0800
+++ b/.hgtags	Thu Oct 15 19:55:15 2020 +0800
@@ -56,3 +56,7 @@
 0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
 c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
 1c66ca4f3791c82501c88e7637312182c7294978 DROPBEAR_2018.76
+6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77
+009d52ae26d35f3381c801e02318fa9be34be93c DROPBEAR_2019.78
+e2e4929d057b09422f2ea4556fb64209aff58161 DROPBEAR_2020.79
+73646de50f1351735c868d4874f058ff9ad62c96 DROPBEAR_2020.80
--- a/.travis.yml	Wed Feb 28 22:11:39 2018 +0800
+++ b/.travis.yml	Thu Oct 15 19:55:15 2020 +0800
@@ -3,26 +3,36 @@
 git:
   depth: 3
 
+# use focal which provides libtommath 1.20
+dist: focal
+
 matrix:
   include:
-    # subsequent matrix options use these first settings
-    - os: linux
+    - name: "plain linux"
       compiler: gcc
       env: WEXTRAFLAGS=-Werror
-    - env: MULTI=1 WEXTRAFLAGS=-Werror
-    # libtom has some warnings, so no WEXTRAFLAGS
-    - env: BUNDLEDLIBTOM=--enable-bundled-libtom WEXTRAFLAGS=""
-    - env: NOWRITEV=1 WEXTRAFLAGS=-Werror
-    # libtomcrypt 1.18.1 fixes clang problems, distro doesn't have that yet
-    - os: linux
+    - name: "multi binary"
+      env: MULTI=1 WEXTRAFLAGS=-Werror
+    - name: "bundled libtom, xenial, no writev()"
+      # NOWRITEV is unrelated to libtom/xenial, test here to save a job
+      env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=-Werror NOWRITEV=1 
+      # can use an older distro with bundled libtom
+      dist: xenial
+    - name: "linux clang"
+      os: linux
       compiler: clang
-      env: BUNDLEDLIBTOM=--enable-bundled-libtom WEXTRAFLAGS=""
-    - os: osx
+      env: WEXTRAFLAGS=-Werror
+    - name: "osx"
+      os: osx
       compiler: clang
-      env: WEXTRAFLAGS=""
+      # OS X says daemon() and utmp are deprecated
+      env: WEXTRAFLAGS="-Wno-deprecated-declarations -Werror"
+    # Note: the fuzzing malloc wrapper doesn't replace free() in system libtomcrypt, so need bundled.
+    - name: "fuzzing"
+      env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS=-Werror LDFLAGS=-fsanitize=address EXTRACFLAGS=-fsanitize=address CXX=clang++
+      compiler: clang
 
 # container-based builds
-sudo: false
 addons:
   apt:
     packages:
@@ -30,24 +40,30 @@
     - zlib1g-dev
     - libtomcrypt-dev
     - libtommath-dev
-
+    - mercurial
 
 before_install:
   - if [ "$CC" = "clang" ]; then WEXTRAFLAGS="$WEXTRAFLAGS -Wno-error=incompatible-library-redeclaration" ; fi  # workaround
 
-script:
-  - autoconf && autoheader && ./configure "$BUNDLEDLIBTOM" CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix="$HOME/inst"
+install:
+  - autoconf 
+  - autoheader 
+  - ./configure $CONFIGURE_FLAGS CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS $EXTRACFLAGS" --prefix="$HOME/inst" || (cat config.log; exit 1)
   - if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
+  - make lint
   - make -j3 
+  - test -z $DO_FUZZ || make fuzzstandalone
   # avoid concurrent install, osx/freebsd is racey (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=208093)
   - make install 
 
-after_success:
+script:
   - ~/inst/bin/dropbearkey -t rsa -f testrsa
   - ~/inst/bin/dropbearkey -t dss -f testdss
   - ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
   - ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
   - ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
+  - ~/inst/bin/dropbearkey -t ed25519 -f tested25519
+  - test -z $DO_FUZZ || ./fuzzers_test.sh
 
 branches:
   only:
--- a/CHANGES	Wed Feb 28 22:11:39 2018 +0800
+++ b/CHANGES	Thu Oct 15 19:55:15 2020 +0800
@@ -1,13 +1,127 @@
+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
   IMPORTANT
-  Custom configuration is now specified in local_options.h rather than options.h
+  Custom configuration is now specified in localoptions.h rather than options.h
   Available options and defaults can be seen in default_options.h
 
   To migrate your configuration, compare your customised options.h against the
   upstream options.h from your relevant version. Any customised options should
-  be put in localoptions.h
+  be put in localoptions.h in the build directory.
 
 - "configure --enable-static" should now be used instead of "make STATIC=1"
   This will avoid 'hardened build' flags that conflict with static binaries
@@ -101,7 +215,7 @@
   dropbear is running with -a (Allow connections to forwarded ports from any host)
   This could potentially allow arbitrary code execution as root by an authenticated user.
   Affects versions 2013.56 to 2016.74. Thanks to Mark Shepard for reporting the crash.
-  CVE-2017-9078 https://secure.ucc.asn.au/hg/dropbear/rev/c8114a48837c
+  CVE-2017-9078 https://hg.ucc.asn.au/dropbear/rev/c8114a48837c
 
 - Security: Fix information disclosure with ~/.ssh/authorized_keys symlink.
   Dropbear parsed authorized_keys as root, even if it were a symlink. The fix
@@ -113,7 +227,7 @@
   contents of that file.
   This information disclosure is to an already authenticated user.
   Thanks to Jann Horn of Google Project Zero for reporting this.
-  CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123
+  CVE-2017-9079 https://hg.ucc.asn.au/dropbear/rev/0d889b068123
 
 - Generate hostkeys with dropbearkey atomically and flush to disk with fsync
   Thanks to Andrei Gherzan for a patch
@@ -133,23 +247,23 @@
   run arbitrary code as the dbclient user. This could be a problem if scripts
   or webpages pass untrusted input to the dbclient program.
   CVE-2016-7406
-  https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb
+  https://hg.ucc.asn.au/dropbear/rev/b66a483f3dcb
 
 - Security: dropbearconvert import of OpenSSH keys could run arbitrary code as
   the local dropbearconvert user when parsing malicious key files
   CVE-2016-7407
-  https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e
+  https://hg.ucc.asn.au/dropbear/rev/34e6127ef02e
 
 - Security: dbclient could run arbitrary code as the local dbclient user if
   particular -m or -c arguments are provided. This could be an issue where
   dbclient is used in scripts.
   CVE-2016-7408
-  https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6
+  https://hg.ucc.asn.au/dropbear/rev/eed9376a4ad6
 
 - Security: dbclient or dropbear server could expose process memory to the
   running user if compiled with DEBUG_TRACE and running with -v
   CVE-2016-7409
-  https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04
+  https://hg.ucc.asn.au/dropbear/rev/6a14b1f6dc04
 
   The security issues were reported by an anonymous researcher working with
   Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html
@@ -195,7 +309,7 @@
 
 - Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions,
   found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116
-  https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff
+  https://hg.ucc.asn.au/dropbear/rev/a3e8389e01ff
 
 2015.71 - 3 December 2015
 
@@ -476,11 +590,11 @@
 - Limit the size of decompressed payloads, avoids memory exhaustion denial
   of service 
   Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
-  https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f
+  https://hg.ucc.asn.au/dropbear/rev/0bf76f54de6f
 
 - Avoid disclosing existence of valid users through inconsistent delays
   Thanks to Logan Lamb for reporting. CVE-2013-4434
-  https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a
+  https://hg.ucc.asn.au/dropbear/rev/d7784616409a
 
 - Update config.guess and config.sub for newer architectures
 
@@ -583,7 +697,7 @@
   This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
   Thanks to Danny Fullerton of Mantor Organization for reporting
   the bug.
-  https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749
+  https://hg.ucc.asn.au/dropbear/rev/818108bf7749
 
 - Compile fix, only apply IPV6 socket options if they are available in headers
   Thanks to Gustavo Zacarias for the patch
@@ -627,7 +741,7 @@
 - New version numbering scheme.
 
 Source repository has now migrated to Mercurial at 
-https://secure.ucc.asn.au/hg/dropbear/graph/default
+https://hg.ucc.asn.au/dropbear/graph/default
 
 0.53.1 - Wednesday 2 March 2011
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DEVELOPING.md	Thu Oct 15 19:55:15 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.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FUZZER-NOTES.md	Thu Oct 15 19:55:15 2020 +0800
@@ -0,0 +1,77 @@
+# Fuzzing Dropbear
+
+Dropbear is process-per-session so it assumes calling `dropbear_exit()`
+is fine at any point to clean up. This makes fuzzing a bit trickier. 
+A few pieces of wrapping infrastructure are used to work around this.
+
+The [libfuzzer](http://llvm.org/docs/LibFuzzer.html#fuzz-target) harness
+expects a long running process to continually run a test function with 
+a string of crafted input. That process should not leak resources or exit.
+
+## longjmp
+
+When dropbear runs in fuzz mode it sets up a 
+[`setjmp()`](http://man7.org/linux/man-pages/man3/setjmp.3.html) target prior 
+to launching the code to be fuzzed, and then [`dropbear_exit()`](dbutil.c#L125)
+calls `longjmp()` back there. This avoids exiting though it doesn't free 
+memory or other resources.
+
+## malloc Wrapper
+
+Dropbear normally uses a [`m_malloc()`](dbmalloc.c) function that is the same as `malloc()` but
+exits if allocation fails. In fuzzing mode this is replaced with a tracking allocator
+that stores all allocations in a linked list. After the `longjmp()` occurs the fuzzer target
+calls [`m_malloc_free_epoch(1, 1)`](dbmalloc.c) to clean up any unreleased memory.
+
+If the fuzz target runs to completion it calls `m_malloc_free_epoch(1, 0)` which will reset 
+the tracked allocations but will not free memory - that allows libfuzzer's leak checking
+to detect leaks in normal operation.
+
+## File Descriptor Input
+
+As a network process Dropbear reads and writes from a socket. The wrappers for
+`read()`/`write()`/`select()` in [fuzz-wrapfd.c](fuzz-wrapfd.c) will read from the
+fuzzer input that has been set up with `wrapfd_add()`. `write()` output is
+currently discarded.
+These also test error paths such as EINTR and short reads with certain probabilities.
+
+This allows running the entire dropbear server process with network input provided by the
+fuzzer, without many modifications to the main code. At the time of writing this 
+only runs the pre-authentication stages, though post-authentication could be run similarly.
+
+## Encryption and Randomness
+
+When running in fuzzing mode Dropbear uses a [fixed seed](dbrandom.c#L185)
+every time so that failures can be reproduced. 
+
+Since the fuzzer cannot generate valid encrypted input the packet decryption and
+message authentication calls are disabled, see [packet.c](packet.c). 
+MAC failures are set to occur with a low probability to test that error path.
+
+## Fuzzers
+
+Current fuzzers are
+
+- [fuzzer-preauth](fuzzer-preauth.c) - the fuzzer input is treated as a stream of session input. This will
+  test key exchange, packet ordering, authentication attempts etc.
+
+- [fuzzer-preauth_nomaths](fuzzer-preauth_nomaths.c) - the same as fuzzer-preauth but with asymmetric crypto
+  routines replaced with dummies for faster runtime. corpora are shared 
+  between fuzzers by [oss-fuzz](https://github.com/google/oss-fuzz) so this 
+  will help fuzzer-preauth too.
+
+- [fuzzer-verify](fuzzer-verify.c) - read a key and signature from fuzzer input and verify that signature. 
+  It would not be expected to pass, though some keys with bad parameters are 
+  able to validate with a trivial signature - extra checks are added for that.
+
+- [fuzzer-pubkey](fuzzer-pubkey.c) - test parsing of an `authorized_keys` line.
+
+- [fuzzer-kexdh](fuzzer-kexdh.c) - test Diffie-Hellman key exchange where the fuzz input is the 
+  ephemeral public key that would be received over the network. This is testing `mp_expt_mod()`
+  and and other libtommath routines.
+
+- [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	Wed Feb 28 22:11:39 2018 +0800
+++ b/INSTALL	Thu Oct 15 19:55:15 2020 +0800
@@ -3,6 +3,8 @@
 - Edit localoptions.h to set which features you want. Available options
   are described in default_options.h, these will be overridden by
   anything set in localoptions.h
+  localoptions.h should be located in the build directory if you are
+  building out of tree.
 
 - If using a Mercurial or Git checkout, "autoconf; autoheader"
 
@@ -26,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
@@ -54,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	Wed Feb 28 22:11:39 2018 +0800
+++ b/LICENSE	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/Makefile.in	Thu Oct 15 19:55:15 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
 
@@ -61,7 +62,7 @@
 SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
 
 ifeq (@[email protected], 1)
-	allobjs = $(COMMONOBJS) fuzz-common.o  fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS)
+	allobjs = $(COMMONOBJS) fuzz-common.o  fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @[email protected]
 	allobjs:=$(subst svr-main.o, ,$(allobjs))
 	allobjs:=$(subst cli-main.o, ,$(allobjs))
 	allobjs:=$(sort $(allobjs))
@@ -70,6 +71,8 @@
 	dbclientobjs=$(allobjs) cli-main.o
 	dropbearkeyobjs=$(allobjs) $(KEYOBJS)
 	dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
+	# CXX only set when fuzzing
+	[email protected]@
 else
 	dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
 	dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
@@ -78,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]@
 
@@ -163,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
@@ -176,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)) 
 
@@ -187,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)
@@ -224,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
@@ -250,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
+FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519
 
 FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
 
@@ -267,22 +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-targetsk FUZZLIB=-lFuzzer.a 
+# 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-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
+	$(CXX) $(CXXFLAGS) [email protected] $(LDFLAGS) $(svrfuzzobjs) -o [email protected]$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @[email protected]
+
+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
@@ -295,7 +320,9 @@
 	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
--- a/README	Wed Feb 28 22:11:39 2018 +0800
+++ b/README	Thu Oct 15 19:55:15 2020 +0800
@@ -51,10 +51,11 @@
 
 ============================================================================
 
-To run the server, you need to server keys, this is one-off:
+To run the server, you need to generate server keys, this is one-off:
 ./dropbearkey -t rsa -f dropbear_rsa_host_key
 ./dropbearkey -t dss -f dropbear_dss_host_key
 ./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
+./dropbearkey -t ed25519 -f dropbear_ed25519_host_key
 
 or alternatively convert OpenSSH keys to Dropbear:
 ./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
--- a/agentfwd.h	Wed Feb 28 22:11:39 2018 +0800
+++ b/agentfwd.h	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/algo.h	Thu Oct 15 19:55:15 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/auth.h	Wed Feb 28 22:11:39 2018 +0800
+++ b/auth.h	Thu Oct 15 19:55:15 2020 +0800
@@ -37,9 +37,9 @@
 void send_msg_userauth_failure(int partial, int incrfail);
 void send_msg_userauth_success(void);
 void send_msg_userauth_banner(const buffer *msg);
-void svr_auth_password(void);
-void svr_auth_pubkey(void);
-void svr_auth_pam(void);
+void svr_auth_password(int valid_user);
+void svr_auth_pubkey(int valid_user);
+void svr_auth_pam(int valid_user);
 
 #if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
 int svr_pubkey_allows_agentfwd(void);
@@ -78,7 +78,7 @@
 void cli_auth_pubkey_cleanup(void);
 
 
-#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
+#define MAX_USERNAME_LEN 100 /* arbitrary for the moment */
 
 #define AUTH_TYPE_NONE      1
 #define AUTH_TYPE_PUBKEY    (1 << 1)
@@ -108,11 +108,14 @@
 	unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
 							  client and server (though has differing 
 							  meanings). */
+
 	unsigned int perm_warn; /* Server only, set if bad permissions on 
 							   ~/.ssh/authorized_keys have already been
 							   logged. */
 	unsigned int checkusername_failed;  /* Server only, set if checkusername
 	                                has already failed */
+	struct timespec auth_starttime; /* Server only, time of receiving current 
+									SSH_MSG_USERAUTH_REQUEST */
 
 	/* These are only used for the server */
 	uid_t pw_uid;
--- a/bignum.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/bignum.c	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/buffer.c	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/buffer.h	Thu Oct 15 19:55:15 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	Thu Oct 15 19:55:15 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	Thu Oct 15 19:55:15 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/channel.h	Wed Feb 28 22:11:39 2018 +0800
+++ b/channel.h	Thu Oct 15 19:55:15 2020 +0800
@@ -69,10 +69,6 @@
 	int sent_close, recv_close;
 	int recv_eof, sent_eof;
 
-	/* Set after running the ChanType-specific close hander
-	 * to ensure we don't run it twice (nor type->checkclose()). */
-	int close_handler_done;
-
 	struct dropbear_progress_connection *conn_pending;
 	int initconn; /* used for TCP forwarding, whether the channel has been
 					 fully initialised */
@@ -95,10 +91,17 @@
 
 	int sepfds; /* Whether this channel has separate pipes for in/out or not */
 	const char *name;
+	/* Sets up the channel */
 	int (*inithandler)(struct Channel*);
+	/* Called to check whether a channel should close, separately from the FD being closed.
+	Used for noticing process exiting */
 	int (*check_close)(const struct Channel*);
+	/* Handler for ssh_msg_channel_request */
 	void (*reqhandler)(struct Channel*);
+	/* Called prior to sending ssh_msg_channel_close, used for sending exit status */
 	void (*closehandler)(const struct Channel*);
+	/* Frees resources, called just prior to channel being removed */
+	void (*cleanup)(const struct Channel*);
 };
 
 /* Callback for connect_remote */
--- a/chansession.h	Wed Feb 28 22:11:39 2018 +0800
+++ b/chansession.h	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-agentfwd.c	Thu Oct 15 19:55:15 2020 +0800
@@ -52,6 +52,7 @@
 	new_agent_chan,
 	NULL,
 	NULL,
+	NULL,
 	NULL
 };
 
@@ -254,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
@@ -270,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	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-authpubkey.c	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-chansession.c	Thu Oct 15 19:55:15 2020 +0800
@@ -52,6 +52,7 @@
 	NULL, /* checkclosehandler */
 	cli_chansessreq, /* reqhandler */
 	cli_closechansess, /* closehandler */
+	NULL, /* cleanup */
 };
 
 static void cli_chansessreq(struct Channel *channel) {
@@ -387,7 +388,8 @@
 	cli_init_netcat, /* inithandler */
 	NULL,
 	NULL,
-	cli_closechansess
+	cli_closechansess,
+	NULL,
 };
 
 void cli_send_netcat_request() {
--- a/cli-kex.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-kex.c	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-main.c	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-runopts.c	Thu Oct 15 19:55:15 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 */
@@ -891,6 +892,7 @@
 #ifndef DISABLE_SYSLOG
 			"\tUseSyslog\n"
 #endif
+			"\tPort\n"
 		);
 		exit(EXIT_SUCCESS);
 	}
@@ -909,5 +911,10 @@
 	}
 #endif
 
+	if (match_extendedopt(&optstr, "Port") == DROPBEAR_SUCCESS) {
+		cli_opts.remoteport = optstr;
+		return;
+	}
+
 	dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr);
 }
--- a/cli-session.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-session.c	Thu Oct 15 19:55:15 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,10 +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_finished()"))
 
 	session_cleanup();
 	fprintf(stderr, "Connection to %[email protected]%s:%s closed.\n", cli_opts.username,
--- a/cli-tcpfwd.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/cli-tcpfwd.c	Thu Oct 15 19:55:15 2020 +0800
@@ -40,6 +40,7 @@
 	newtcpforwarded,
 	NULL,
 	NULL,
+	NULL,
 	NULL
 };
 #endif
@@ -55,6 +56,7 @@
 	tcp_prio_inithandler,
 	NULL,
 	NULL,
+	NULL,
 	NULL
 };
 #endif
@@ -135,7 +137,7 @@
 	tcpinfo->chantype = &cli_chan_tcplocal;
 	tcpinfo->tcp_type = direct;
 
-	ret = listen_tcpfwd(tcpinfo);
+	ret = listen_tcpfwd(tcpinfo, NULL);
 
 	if (ret == DROPBEAR_FAILURE) {
 		m_free(tcpinfo);
--- a/common-algo.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/common-algo.c	Thu Oct 15 19:55:15 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-channel.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/common-channel.c	Thu Oct 15 19:55:15 2020 +0800
@@ -144,7 +144,6 @@
 	newchan->index = i;
 	newchan->sent_close = newchan->recv_close = 0;
 	newchan->sent_eof = newchan->recv_eof = 0;
-	newchan->close_handler_done = 0;
 
 	newchan->remotechan = remotechan;
 	newchan->transwindow = transwindow;
@@ -286,7 +285,7 @@
 				channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
 
 	if (!channel->flushing 
-		&& !channel->close_handler_done
+		&& !channel->sent_close
 		&& channel->type->check_close
 		&& channel->type->check_close(channel))
 	{
@@ -298,7 +297,7 @@
 	   channel, to ensure that the shell has exited (and the exit status 
 	   retrieved) before we close things up. */
 	if (!channel->type->check_close	
-		|| channel->close_handler_done
+		|| channel->sent_close
 		|| channel->type->check_close(channel)) {
 		close_allowed = 1;
 	}
@@ -385,10 +384,8 @@
 static void send_msg_channel_close(struct Channel *channel) {
 
 	TRACE(("enter send_msg_channel_close %p", (void*)channel))
-	if (channel->type->closehandler 
-			&& !channel->close_handler_done) {
+	if (channel->type->closehandler) {
 		channel->type->closehandler(channel);
-		channel->close_handler_done = 1;
 	}
 	
 	CHECKCLEARTOWRITE();
@@ -661,10 +658,8 @@
 		m_close(channel->errfd);
 	}
 
-	if (!channel->close_handler_done
-		&& channel->type->closehandler) {
-		channel->type->closehandler(channel);
-		channel->close_handler_done = 1;
+	if (channel->type->cleanup) {
+		channel->type->cleanup(channel);
 	}
 
 	if (channel->conn_pending) {
@@ -690,13 +685,7 @@
 
 	TRACE(("enter recv_msg_channel_request %p", (void*)channel))
 
-	if (channel->sent_close) {
-		TRACE(("leave recv_msg_channel_request: already closed channel"))
-		return;
-	}
-
-	if (channel->type->reqhandler 
-			&& !channel->close_handler_done) {
+	if (channel->type->reqhandler) {
 		channel->type->reqhandler(channel);
 	} else {
 		int wantreply;
@@ -1011,6 +1000,11 @@
 void send_msg_channel_failure(const struct Channel *channel) {
 
 	TRACE(("enter send_msg_channel_failure"))
+
+	if (channel->sent_close) {
+		TRACE(("Skipping sending msg_channel_failure for closed channel"))
+		return;
+	}
 	CHECKCLEARTOWRITE();
 
 	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
@@ -1024,6 +1018,10 @@
 void send_msg_channel_success(const struct Channel *channel) {
 
 	TRACE(("enter send_msg_channel_success"))
+	if (channel->sent_close) {
+		TRACE(("Skipping sending msg_channel_success for closed channel"))
+		return;
+	}
 	CHECKCLEARTOWRITE();
 
 	buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);
--- a/common-kex.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/common-kex.c	Thu Oct 15 19:55:15 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() {
@@ -694,29 +706,27 @@
 	/* K, the shared secret */
 	buf_putmpint(ses.kexhashbuf, ses.dh_K);
 
+	ecc_free(Q_them);
+	m_free(Q_them);
+
 	/* calculate the hash H to sign */
 	finish_kexhashbuf();
 }
 #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);
 }
@@ -733,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");
@@ -819,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;
 	}
@@ -842,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;
@@ -860,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;
@@ -868,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;
@@ -892,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;
@@ -926,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;
@@ -942,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	Wed Feb 28 22:11:39 2018 +0800
+++ b/common-runopts.c	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/common-session.c	Thu Oct 15 19:55:15 2020 +0800
@@ -68,6 +68,16 @@
 	/* Sets it to lowdelay */
 	update_channel_prio();
 
+#if !DROPBEAR_SVR_MULTIUSER
+	/* A sanity check to prevent an accidental configuration option
+	   leaving multiuser systems exposed */
+	errno = 0;
+	getuid();
+	if (errno != ENOSYS) {
+		dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
+	}
+#endif
+
 	now = monotonic_now();
 	ses.connect_time = now;
 	ses.last_packet_time_keepalive_recv = now;
@@ -137,6 +147,10 @@
 
 	ses.allowprivport = 0;
 
+#if DROPBEAR_PLUGIN
+        ses.plugin_session = NULL;
+#endif
+
 	TRACE(("leave session_init"))
 }
 
@@ -152,8 +166,9 @@
 
 		timeout.tv_sec = select_timeout();
 		timeout.tv_usec = 0;
-		FD_ZERO(&writefd);
-		FD_ZERO(&readfd);
+		DROPBEAR_FD_ZERO(&writefd);
+		DROPBEAR_FD_ZERO(&readfd);
+
 		dropbear_assert(ses.payload == NULL);
 
 		/* We get woken up when signal handlers write to this pipe.
@@ -204,8 +219,8 @@
 			 * want to iterate over channels etc for reading, to handle
 			 * server processes exiting etc. 
 			 * We don't want to read/write FDs. */
-			FD_ZERO(&writefd);
-			FD_ZERO(&readfd);
+			DROPBEAR_FD_ZERO(&writefd);
+			DROPBEAR_FD_ZERO(&readfd);
 		}
 		
 		/* We'll just empty out the pipe if required. We don't do
@@ -346,7 +361,7 @@
 void send_session_identification() {
 	buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
 	buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
-	writebuf_enqueue(writebuf, 0);
+	writebuf_enqueue(writebuf);
 }
 
 static void read_session_identification() {
@@ -355,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) {
@@ -406,7 +424,7 @@
 		return -1;
 	}
 
-	FD_ZERO(&fds);
+	DROPBEAR_FD_ZERO(&fds);
 
 	/* select since it's a non-blocking fd */
 	
--- a/config.guess	Wed Feb 28 22:11:39 2018 +0800
+++ b/config.guess	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/config.sub	Thu Oct 15 19:55:15 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	Wed Feb 28 22:11:39 2018 +0800
+++ b/configure.ac	Thu Oct 15 19:55:15 2020 +0800
@@ -10,11 +10,12 @@
 AC_CONFIG_SRCDIR(buffer.c)
 
 # Record which revision is being built
-if which -s hg && test -d "$srcdir/.hg"; then
+if test -s "`which hg`" && test -d "$srcdir/.hg"; then
 	hgrev=`hg id -i -R "$srcdir"`
 	AC_MSG_NOTICE([Source directory Mercurial base revision $hgrev])
 fi
 
+ORIGCFLAGS="$CFLAGS"
 # Checks for programs.
 AC_PROG_CC
 
@@ -35,7 +36,7 @@
 }])
 
 # set compile flags prior to other tests
-if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
+if test -z "$ORIGCFLAGS" && test "$GCC" = "yes"; then
 	AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
 	CFLAGS="-Os -W -Wall"
 fi
@@ -322,20 +323,45 @@
 	]
 )
 
+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
+		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
 	]
 
 )
 AC_SUBST(DROPBEAR_FUZZ)
+AC_SUBST(CXX)
 
 # Checks for header files.
 AC_HEADER_STDC
@@ -344,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
@@ -493,32 +520,36 @@
 AC_CHECK_FUNCS(setutxent utmpxname)
 AC_CHECK_FUNCS(logout updwtmp logwtmp)
 
+# POSIX monotonic time
+AC_CHECK_FUNCS(clock_gettime)
+
 # OS X monotonic time
 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)
 	]
 )
 
@@ -851,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	Wed Feb 28 22:11:39 2018 +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	Thu Oct 15 19:55:15 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	Thu Oct 15 19:55:15 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/dbhelpers.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/dbhelpers.c	Thu Oct 15 19:55:15 2020 +0800
@@ -9,8 +9,9 @@
 #elif defined(HAVE_EXPLICIT_BZERO)
 	explicit_bzero(data, len);
 #else
+	/* This must be volatile to avoid compiler optimisation */
 	volatile void *p = data;
-    memset(p, 0x0, len);
+	memset((void*)p, 0x0, len);
 #endif
 }
 
--- a/dbmalloc.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/dbmalloc.c	Thu Oct 15 19:55:15 2020 +0800
@@ -1,6 +1,64 @@
 #include "dbmalloc.h"
 #include "dbutil.h"
 
+
+void * m_calloc(size_t nmemb, size_t size) {
+    if (SIZE_T_MAX / nmemb < size) {
+        dropbear_exit("m_calloc failed");
+    }
+    return m_malloc(nmemb*size);
+}
+
+void * m_strdup(const char * str) {
+    char* ret;
+    unsigned int len;
+    len = strlen(str);
+
+    ret = m_malloc(len+1);
+    if (ret == NULL) {
+        dropbear_exit("m_strdup failed");
+    }
+    memcpy(ret, str, len+1);
+    return ret;
+}
+
+#if !DROPBEAR_TRACKING_MALLOC
+
+/* Simple wrappers around malloc etc */
+void * m_malloc(size_t size) {
+
+	void* ret;
+
+	if (size == 0) {
+		dropbear_exit("m_malloc failed");
+	}
+	ret = calloc(1, size);
+	if (ret == NULL) {
+		dropbear_exit("m_malloc failed");
+	}
+	return ret;
+
+}
+
+void * m_realloc(void* ptr, size_t size) {
+
+	void *ret;
+
+	if (size == 0) {
+		dropbear_exit("m_realloc failed");
+	}
+	ret = realloc(ptr, size);
+	if (ret == NULL) {
+		dropbear_exit("m_realloc failed");
+	}
+	return ret;
+}
+
+
+#else
+
+/* For fuzzing */
+
 struct dbmalloc_header {
     unsigned int epoch;
     struct dbmalloc_header *prev;
@@ -90,13 +148,6 @@
     return &mem[sizeof(struct dbmalloc_header)];
 }
 
-void * m_calloc(size_t nmemb, size_t size) {
-    if (SIZE_T_MAX / nmemb < size) {
-        dropbear_exit("m_calloc failed");
-    }
-    return m_malloc(nmemb*size);
-}
-
 void * m_realloc(void* ptr, size_t size) {
     char* mem = NULL;
     struct dbmalloc_header* header = NULL;
@@ -128,17 +179,14 @@
     free(header);
 }
 
-void * m_strdup(const char * str) {
-    char* ret;
-    unsigned int len;
-    len = strlen(str);
+#endif /* DROPBEAR_TRACKING_MALLOC */
 
-    ret = m_malloc(len+1);
-    if (ret == NULL) {
-        dropbear_exit("m_strdup failed");
-    }
-    memcpy(ret, str, len+1);
-    return ret;
+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/dbmalloc.h	Wed Feb 28 22:11:39 2018 +0800
+++ b/dbmalloc.h	Thu Oct 15 19:55:15 2020 +0800
@@ -1,16 +1,27 @@
 #ifndef DBMALLOC_H_
 #define DBMALLOC_H_
 
-#include "includes.h"
+#include "stdint.h"
+#include "stdlib.h"
+#include "options.h"
 
 void * m_malloc(size_t size);
 void * m_calloc(size_t nmemb, size_t size);
 void * m_strdup(const char * str);
 void * m_realloc(void* ptr, size_t size);
+
+#if DROPBEAR_TRACKING_MALLOC
 void m_free_direct(void* ptr);
-#define m_free(X) do {m_free_direct(X); (X) = NULL;} while (0)
-
 void m_malloc_set_epoch(unsigned int epoch);
 void m_malloc_free_epoch(unsigned int epoch, int dofree);
 
+#else
+/* plain wrapper */
+#define m_free_direct free
+
+#endif
+
+#define m_free(X) do {m_free_direct(X); (X) = NULL;} while (0)
+
+
 #endif /* DBMALLOC_H_ */
--- a/dbrandom.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/dbrandom.c	Thu Oct 15 19:55:15 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;
-
-			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/dbutil.c	Wed Feb 28 22:11:39 2018 +0800
+++ b/dbutil.c	Thu Oct 15 19:55:15 2020 +0800
@@ -605,71 +605,67 @@
 	return c;
 }
 
-#if defined(__linux__) && defined(SYS_clock_gettime)
-/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
-reach userspace include headers */
-#ifndef CLOCK_MONOTONIC_COARSE
-#define CLOCK_MONOTONIC_COARSE 6
-#endif
-/* Some old toolchains know SYS_clock_gettime but not CLOCK_MONOTONIC */
-#ifndef CLOCK_MONOTONIC
-#define CLOCK_MONOTONIC 1
-#endif
-static clockid_t get_linux_clock_source() {
-	struct timespec ts;
-	if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
-		return CLOCK_MONOTONIC_COARSE;
-	}
-
-	if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
-		return CLOCK_MONOTONIC;
-	}
-	return -1;
-}
-#endif 
-
-time_t monotonic_now() {
+/* higher-resolution monotonic timestamp, falls back to gettimeofday */
+void gettime_wrapper(struct timespec *now) {
+	struct timeval tv;
 #if DROPBEAR_FUZZ
 	if (fuzz.fuzzing) {
 		/* time stands still when fuzzing */
-		return 5;
+		now->tv_sec = 5;
+		now->tv_nsec = 0;
 	}
 #endif
+
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+	/* POSIX monotonic clock. Newer Linux, BSD, MacOSX >10.12 */
+	if (clock_gettime(CLOCK_MONOTONIC, now) == 0) {
+		return;
+	}
+#endif
+
 #if defined(__linux__) && defined(SYS_clock_gettime)
 	{
-	static clockid_t clock_source = -2;
-
-	if (clock_source == -2) {
-		/* First run, find out which one works. 
-		-1 will fall back to time() */
-		clock_source = get_linux_clock_source();
-	}
-
-	if (clock_source >= 0) {
-		struct timespec ts;
-		if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
-			/* Intermittent clock failures should not happen */
-			dropbear_exit("Clock broke");
+	/* Old linux toolchain - kernel might support it but not the build headers */
+	/* Also glibc <2.17 requires -lrt which we neglect to add */
+	static int linux_monotonic_failed = 0;
+	if (!linux_monotonic_failed) {
+		/* CLOCK_MONOTONIC isn't in some headers */
+		int clock_source_monotonic = 1; 
+		if (syscall(SYS_clock_gettime, clock_source_monotonic, now) == 0) {
+			return;
+		} else {
+			/* Don't try again */
+			linux_monotonic_failed = 1;
 		}
-		return ts.tv_sec;
 	}
 	}
-#endif /* linux clock_gettime */
+#endif /* linux fallback clock_gettime */
 
 #if defined(HAVE_MACH_ABSOLUTE_TIME)
 	{
-	/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
+	/* OS X pre 10.12, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
 	static mach_timebase_info_data_t timebase_info;
+	uint64_t scaled_time;
 	if (timebase_info.denom == 0) {
 		mach_timebase_info(&timebase_info);
 	}
-	return mach_absolute_time() * timebase_info.numer / timebase_info.denom
-		/ 1e9;
+	scaled_time = mach_absolute_time() * timebase_info.numer / timebase_info.denom;
+	now->tv_sec = scaled_time / 1000000000;
+	now->tv_nsec = scaled_time % 1000000000;
 	}
 #endif /* osx mach_absolute_time */
 
 	/* Fallback for everything else - this will sometimes go backwards */
-	return time(NULL);
+	gettimeofday(&tv, NULL);
+	now->tv_sec = tv.tv_sec;
+	now->tv_nsec = 1000*tv.tv_usec;
+}
+
+/* second-resolution monotonic timestamp */
+time_t monotonic_now() {
+	struct timespec ts;
+	gettime_wrapper(&ts);
+	return ts.tv_sec;
 }
 
 void fsync_parent_dir(const char* fn) {
@@ -687,6 +683,6 @@
 		TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
 	}
 </