Merge branch 'dropbear'

Update to dropbear-2020.81.
Does not build.  I did not even resolve the merge conflicts because the
first one I looked at wasn't entirely trivial.
master
Greg Alexander 3 years ago
commit 5f12050fde

@ -1,6 +1,7 @@
repo: d7da3b1e15401eb234ec866d5eac992fc4cd5878
node: d2753238f35f2f80507d1241f03639a20285ef46
node: 4b984c42372d01fcc2fd487c58af6a5aa65eb88e
branch: default
latesttag: DROPBEAR_2019.78
latesttagdistance: 2
changessincelatesttag: 2
latesttag: github/main
latesttag: github/master
latesttagdistance: 1
changessincelatesttag: 1

@ -26,3 +26,5 @@ fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzu
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=

@ -3,30 +3,40 @@ language: c
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
sudo: false
- env: MULTI=1 WEXTRAFLAGS=-Werror
# libtom has some warnings, so no WEXTRAFLAGS
- env: CONFIGURE_FLAGS=--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: CONFIGURE_FLAGS=--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.
- env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS="" LDFLAGS=-fsanitize=address EXTRACFLAGS=-fsanitize=address CXX=clang++
# Address sanitizer
- name: "fuzz-asan"
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
# Undefined Behaviour sanitizer
- name: "fuzz-ubsan"
# don't fail with alignment due to https://github.com/libtom/libtomcrypt/issues/549
env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS=-Werror LDFLAGS=-fsanitize=undefined EXTRACFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -fsanitize-recover=alignment" CXX=clang++
compiler: clang
# sanitizers need ptrace which is privileged https://github.com/travis-ci/travis-ci/issues/9033
sudo: required
# container-based builds
addons:
@ -46,6 +56,7 @@ install:
- 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)
@ -57,6 +68,7 @@ script:
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
- ~/inst/bin/dropbearkey -t ed25519 -f tested25519
- test -z $DO_FUZZ || ./fuzzers_test.sh
branches:

@ -1,3 +1,91 @@
2020.81 - 29 October 2020
- Fix regression in 2020.79 which prevented connecting with some SSH
implementations. Increase MAX_PROPOSED_ALGO to 50, and print a log
message if the limit is hit. This fixes interoperability with sshj
library (used by PyCharm), and GoAnywhere.
Reported by Pirmin Walthert and Piotr Jurkiewicz
- Fix building with non-GCC compilers, reported by Kazuo Kuroi
- Fix potential long delay in dbclient, found by OSS Fuzz
- Fix null pointer dereference crash, found by OSS Fuzz
- libtommath now uses the same random source as Dropbear (in 2020.79
and 2020.80 used getrandom() separately)
- Some fuzzing improvements, start of a dbclient fuzzer
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
@ -146,7 +234,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
@ -158,7 +246,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
@ -178,23 +266,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
@ -240,7 +328,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
@ -521,11 +609,11 @@ kernels, from Steve Dover
- 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
@ -628,7 +716,7 @@ though probably will be soon
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
@ -672,7 +760,7 @@ though probably will be soon
- 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

@ -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.

@ -72,3 +72,6 @@ Current fuzzers are
- [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh.
This is testing libtommath ECC routines.
- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange
like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines.

@ -28,6 +28,8 @@ Basic Dropbear build instructions:
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
recompiling - bad things will happen otherwise)
DEVELOPING.md has some notes on other developer topics, including debugging.
See MULTI for instructions on making all-in-one binaries.
If you want to compile statically use ./configure --enable-static
@ -56,7 +58,7 @@ Compiling for uClibc should be the same as normal, just set CC to the magic
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

@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
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 @@ SOFTWARE.
=====
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 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=====
curve25519-donna:
/* Copyright 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* curve25519-donna: Curve25519 elliptic curve, public key function
*
* http://code.google.com/p/curve25519-donna/
*
* Adam Langley <agl@imperialviolet.org>
*
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
*
* 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.
*/
curve25519.c:
Modified TweetNaCl version 20140427, a self-contained public-domain C library.
https://tweetnacl.cr.yp.to/
Contributors (alphabetical order)
Daniel J. Bernstein, University of Illinois at Chicago and Technische
Universiteit Eindhoven
Bernard van Gastel, Radboud Universiteit Nijmegen
Wesley Janssen, Radboud Universiteit Nijmegen
Tanja Lange, Technische Universiteit Eindhoven
Peter Schwabe, Radboud Universiteit Nijmegen
Sjaak Smetsers, Radboud Universiteit Nijmegen
Acknowledgments
This work was supported by the U.S. National Science Foundation under grant
1018836. "Any opinions, findings, and conclusions or recommendations expressed
in this material are those of the author(s) and do not necessarily reflect the
views of the National Science Foundation."
This work was supported by the Netherlands Organisation for Scientific
Research (NWO) under grant 639.073.005 and Veni 2013 project 13114.

@ -36,8 +36,9 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
curve25519.o ed25519.o \
dbmalloc.o \
gensignkey.o gendss.o genrsa.o
gensignkey.o gendss.o genrsa.o gened25519.o
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
@ -52,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o dh_groups.o \
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
KEYOBJS=dropbearkey.o
@ -64,7 +65,6 @@ ifeq (@DROPBEAR_FUZZ@, 1)
allobjs = $(COMMONOBJS) fuzz-common.o fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
allobjs:=$(subst svr-main.o, ,$(allobjs))
allobjs:=$(subst cli-main.o, ,$(allobjs))
allobjs:=$(sort $(allobjs))
dropbearobjs=$(allobjs) svr-main.o
dbclientobjs=$(allobjs) cli-main.o
@ -80,6 +80,15 @@ else
scpobjs=$(SCPOBJS)
endif
ifeq (@DROPBEAR_PLUGIN@, 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
VPATH=@srcdir@
srcdir=@srcdir@
@ -165,7 +174,7 @@ insmulti%: dropbearmulti$(EXEEXT)
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
# dropbear should go in sbin, so it needs a separate rule
inst_dropbear: dropbear
@ -178,7 +187,7 @@ inst_%: %
$(INSTALL) -d $(DESTDIR)$(bindir)
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
@ -189,7 +198,7 @@ dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ $(PLUGIN_LIBS)
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
@ -226,7 +235,7 @@ $(STATIC_LTC): $(OPTION_HEADERS)
$(STATIC_LTM): $(OPTION_HEADERS)
$(MAKE) -C libtommath
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint
ltc-clean:
$(MAKE) -C libtomcrypt clean
@ -252,10 +261,14 @@ distclean: clean tidy
tidy:
-rm -f *~ *.gcov */*~
lint:
cd $(srcdir); ./dropbear_lint.sh
## Fuzzing targets
# list of fuzz targets
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths \
fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 fuzzer-client fuzzer-client_nomaths
FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
@ -266,31 +279,39 @@ list-fuzz-targets:
fuzzstandalone: FUZZLIB=fuzz-harness.o
fuzzstandalone: fuzz-harness.o fuzz-targets
# exclude svr-main.o to avoid duplicate main
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(allobjs) fuzz-common.o
# build all the fuzzers. This will require fail to link unless built with
# make fuzz-targets FUZZLIB=-lFuzzer.a
# or similar - the library provides main().
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-verify: fuzzer-verify.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-pubkey: fuzzer-pubkey.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-verify: fuzzer-verify.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexdh: fuzzer-kexdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-client: fuzzer-client.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexecdh: fuzzer-kexecdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-client_nomaths: fuzzer-client_nomaths.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-%.options: Makefile
echo "[libfuzzer]" > $@
@ -302,7 +323,9 @@ fuzz-hostkeys:
dropbearkey -t rsa -f keyr
dropbearkey -t dss -f keyd
dropbearkey -t ecdsa -size 256 -f keye
dropbearkey -t ed25519 -f keyed25519
echo > hostkeys.c
/usr/bin/xxd -i -a keyr >> hostkeys.c
/usr/bin/xxd -i -a keye >> hostkeys.c
/usr/bin/xxd -i -a keyd >> hostkeys.c
/usr/bin/xxd -i -a keyed25519 >> hostkeys.c

@ -55,6 +55,7 @@ To run the server, you need to generate server keys, this is one-off:
./dropbearkey -t rsa -f dropbear_rsa_host_key
./dropbearkey -t dss -f dropbear_dss_host_key
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
./dropbearkey -t ed25519 -f dropbear_ed25519_host_key
or alternatively convert OpenSSH keys to Dropbear:
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key

@ -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

@ -47,7 +47,7 @@ typedef struct Algo_Type algo_type;
/* 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 @@ struct dropbear_cipher_mode {
unsigned long len, void *cipher_state);
int (*decrypt)(const unsigned char *ct, unsigned char *pt,
unsigned long len, void *cipher_state);
int (*aead_crypt)(unsigned int seq,
const unsigned char *in, unsigned char *out,
unsigned long len, unsigned long taglen,
void *cipher_state, int direction);
int (*aead_getlength)(unsigned int seq,
const unsigned char *in, unsigned int *outlen,
unsigned long len, void *cipher_state);
const struct dropbear_hash *aead_mac;
};
struct dropbear_hash {
@ -112,21 +120,17 @@ struct dropbear_kex {
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 "kexguess2@matt.ucc.asn.au"
#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,

@ -86,7 +86,7 @@ void m_mp_free_multi(mp_int **mp, ...)
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");
}
}

@ -39,44 +39,30 @@
/* Create (malloc) a new buffer of size */
buffer* buf_new(unsigned int size) {
buffer* buf;
if (size > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
buf = (buffer*)m_malloc(sizeof(buffer)+size);
if (size > 0) {
buf->data = (unsigned char*)buf + sizeof(buffer);
} else {
buf->data = NULL;
}
buf->data = (unsigned char*)buf + sizeof(buffer);
buf->size = size;
return buf;
}
/* free the buffer's data and the buffer itself */
void buf_free(buffer* buf) {
m_free(buf);
}
/* overwrite the contents of the buffer to clear it */
void buf_burn(const buffer* buf) {
m_burn(buf->data, buf->size);
}
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
buffer* buf_resize(buffer *buf, unsigned int newsize) {
if (newsize > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
@ -139,18 +125,23 @@ void buf_incrwritepos(buffer* buf, unsigned int incr) {
}
}
/* increment the position by incr, negative values are allowed, to
* decrement the pos*/
void buf_incrpos(buffer* buf, int incr) {
/* increment the position by incr */
void buf_incrpos(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR
|| incr < -BUF_MAX_INCR
|| (unsigned int)((int)buf->pos + incr) > buf->len
|| ((int)buf->pos + incr) < 0) {
|| (buf->pos + incr) > buf->len) {
dropbear_exit("Bad buf_incrpos");
}
buf->pos += incr;
}
/* decrement the position by decr */
void buf_decrpos(buffer* buf, unsigned int decr) {
if (decr > buf->pos) {
dropbear_exit("Bad buf_decrpos");
}
buf->pos -= decr;
}
/* Get a byte from the buffer and increment the pos */
unsigned char buf_getbyte(buffer* buf) {
@ -228,19 +219,37 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
}
/* 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 +298,18 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
/* 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 +330,10 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
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 +361,7 @@ int buf_getmpint(buffer* buf, mp_int* mp) {
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;
}

@ -49,7 +49,8 @@ buffer* buf_newcopy(const buffer* buf);
void buf_setlen(buffer* buf, unsigned int len);
void buf_incrlen(buffer* buf, unsigned int incr);
void buf_setpos(buffer* buf, unsigned int pos);
void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */
void buf_incrpos(buffer* buf, unsigned int incr);
void buf_decrpos(buffer* buf, unsigned int decr);
void buf_incrwritepos(buffer* buf, unsigned int incr);
unsigned char buf_getbyte(buffer* buf);
unsigned char buf_getbool(buffer* buf);
@ -58,6 +59,7 @@ unsigned char* buf_getptr(const buffer* buf, unsigned int len);
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);

@ -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 */

@ -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_ */

@ -41,6 +41,9 @@ struct ChanSess {
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 @@ struct ChanSess {
char * agentfile;
char * agentdir;
#endif
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
char *original_command;
#endif
};
struct ChildPid {

@ -255,11 +255,12 @@ 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 sigtype) {
buffer *request_data = NULL;
buffer *response = NULL;
unsigned int siglen;
int packet_type;
int flags = 0;
/* Request format
byte SSH2_AGENTC_SIGN_REQUEST
@ -271,7 +272,12 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
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);

@ -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 @@ void recv_msg_userauth_pk_ok() {
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 @@ void recv_msg_userauth_pk_ok() {
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 @@ void recv_msg_userauth_pk_ok() {
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 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
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 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
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 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
/* 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 @@ int cli_auth_pubkey() {
/* 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;

@ -46,6 +46,13 @@ void send_msg_kexdh_init() {
TRACE(("send_msg_kexdh_init()"))
CHECKCLEARTOWRITE();
#if DROPBEAR_FUZZ
if (fuzz.fuzzing && fuzz.skip_kexmaths) {
return;
}
#endif
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
switch (ses.newkeys->algo_kex->mode) {
#if DROPBEAR_NORMAL_DH
@ -81,7 +88,7 @@ void send_msg_kexdh_init() {
}
cli_ses.curve25519_param = gen_kexcurve25519_param();
}
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
break;
#endif
}
@ -94,16 +101,22 @@ void send_msg_kexdh_init() {
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"))
#if DROPBEAR_FUZZ
if (fuzz.fuzzing && fuzz.skip_kexmaths) {
return;
}
#endif
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 +127,7 @@ void recv_msg_kexdh_reply() {
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 +168,12 @@ void recv_msg_kexdh_reply() {
#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 +188,8 @@ void recv_msg_kexdh_reply() {
#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 +426,38 @@ out:
}
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"))
}

@ -31,9 +31,7 @@
#include "dbrandom.h"
#include "crypto_desc.h"
#include "netio.h"
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
static void cli_dropbear_log(int priority, const char* format, va_list param);
#include "fuzz.h"
#if DROPBEAR_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
@ -98,51 +96,6 @@ int main(int argc, char ** argv) {
}
#endif /* DBMULTI stuff */
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char exitmsg[150];
char fullmsg[300];
/* Note that exit message must be rendered before session cleanup */
/* Render the formatted exit message */
vsnprintf(exitmsg, sizeof(exitmsg), format, param);
/* Add the prefix depending on session/auth state */
if (!ses.init_done) {
snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
} else {
snprintf(fullmsg, sizeof(fullmsg),
"Connection to %s@%s:%s exited: %s",
cli_opts.username, cli_opts.remotehost,
cli_opts.remoteport, exitmsg);
}
/* Do the cleanup first, since then the terminal will be reset */
session_cleanup();
/* Avoid printing onwards from terminal cruft */
fprintf(stderr, "\n");
dropbear_log(LOG_INFO, "%s", fullmsg);
exit(exitcode);
}
static void cli_dropbear_log(int priority,
const char* format, va_list param) {
char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param);
#ifndef DISABLE_SYSLOG
if (opts.usingsyslog) {
syslog(priority, "%s", printbuf);
}
#endif
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
fflush(stderr);
}
static void exec_proxy_cmd(const void *user_data_cmd) {
const char *cmd = user_data_cmd;
char *usershell;
@ -192,4 +145,5 @@ static void kill_proxy_sighandler(int UNUSED(signo)) {
kill_proxy_command();
_exit(1);
}
#endif /* DROPBEAR_CLI_PROXYCMD */

@ -378,6 +378,11 @@ void cli_getopts(int argc, char ** argv) {
}
}
#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 @@ void cli_getopts(int argc, char ** argv) {
/* 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 */

@ -81,6 +81,7 @@ static const packettype cli_packettypes[] = {
{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 */
};
@ -351,12 +352,19 @@ static void cli_session_cleanup(void) {
(void)fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
cli_tty_cleanup();
/* Don't leak */
m_close(cli_ses.stdincopy);
m_close(cli_ses.stdoutcopy);
m_close(cli_ses.stderrcopy);
cli_tty_cleanup();
if (cli_ses.server_sig_algs) {
buf_free(cli_ses.server_sig_algs);
}
}
static void cli_finished() {
TRACE(("cli_finised()"))
TRACE(("cli_finished()"))
session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
@ -404,3 +412,63 @@ static void recv_msg_global_request_cli(void) {
/* Send a proper rejection */
send_msg_request_failure();
}
void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char exitmsg[150];
char fullmsg[300];
/* Note that exit message must be rendered before session cleanup */
/* 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) {
snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
} else {
snprintf(fullmsg, sizeof(fullmsg),
"Connection to %s@%s:%s exited: %s",
cli_opts.username, cli_opts.remotehost,
cli_opts.remoteport, exitmsg);
}
/* Do the cleanup first, since then the terminal will be reset */
session_cleanup();
#if DROPBEAR_FUZZ
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
#endif
/* Avoid printing onwards from terminal cruft */
fprintf(stderr, "\n");
dropbear_log(LOG_INFO, "%s", fullmsg);
exit(exitcode);
}
void cli_dropbear_log(int priority, 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);
#ifndef DISABLE_SYSLOG
if (opts.usingsyslog) {
syslog(priority, "%s", printbuf);
}
#endif
fprintf(stderr, "%s: %s\n", name, printbuf);
fflush(stderr);
}

@ -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_aes256 =
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 @@ const struct dropbear_cipher dropbear_nocipher =
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
#if DROPBEAR_ENABLE_CBC_MODE
const struct dropbear_cipher_mode dropbear_mode_cbc =
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
#endif /* DROPBEAR_ENABLE_CBC_MODE */
const struct dropbear_cipher_mode dropbear_mode_none =
{void_start, void_cipher, void_cipher};
{void_start, void_cipher, void_cipher, NULL, NULL, NULL};
#if DROPBEAR_ENABLE_CTR_MODE
/* a wrapper to make ctr_start and cbc_start look the same */
@ -101,7 +100,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
}
const struct dropbear_cipher_mode dropbear_mode_ctr =
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
#endif /* DROPBEAR_ENABLE_CTR_MODE */
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
@ -137,6 +136,19 @@ const struct dropbear_hash dropbear_nohash =
* that is also supported by the server will get used. */
algo_type sshciphers[] = {
#if DROPBEAR_CHACHA20POLY1305
{"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
#endif
#if DROPBEAR_ENABLE_GCM_MODE
#if DROPBEAR_AES128
{"aes128-gcm@openssh.com", 0, &dropbear_aes128, 1, &dropbear_mode_gcm},
#endif
#if DROPBEAR_AES256
{"aes256-gcm@openssh.com", 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 @@ algo_type sshciphers[] = {
#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 @@ algo_type ssh_nocompress[] = {
{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_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH
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_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0
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 @@ algo_type sshkex[] = {
{"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[]) {
int i;
/* 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;
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);
}
}
return DROPBEAR_FAILURE;
/* 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);
}
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
buf_put_algolist_all(buf, localalgos, 0);
}
unsigned int i, len;
unsigned int donefirst = 0;
buffer *algolist = NULL;
/* 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;
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) {
dropbear_exit("Too many remote algorithms");
*ret_count = 0;
return;
}
algolist[i] = '\0';
ret_list[*ret_count] = &algolist[i+1];
(*ret_count)++;
}
}
}
/* 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];
}
}
buf_putstring(buf, (const char*)algolist->data, algolist->len);
TRACE(("algolist add '%*s'", algolist->len, algolist->data))
buf_free(algolist);
return NULL;
}
/* match the first algorithm in the comma-separated list in buf which is
@ -354,9 +449,7 @@ void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
* 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 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
/* 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 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
}
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;

@ -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 @@ void send_msg_kexinit() {
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 @@ void send_msg_kexinit() {
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 @@ static void switch_keys() {
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 @@ void send_msg_newkeys() {
/* 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 @@ void recv_msg_newkeys() {
/* 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 @@ static void gen_new_keys() {
hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
if (recv_cipher < 0)
dropbear_exit("Crypto error");
int recv_cipher = -1;
if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) {
recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
if (recv_cipher < 0) {
dropbear_exit("Crypto error");
}
}
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
recv_IV, recv_key,
ses.newkeys->recv.algo_crypt->keysize, 0,
@ -340,9 +348,13 @@ static void gen_new_keys() {
}
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
if (trans_cipher < 0)
dropbear_exit("Crypto error");
int trans_cipher = -1;
if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) {
trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
if (trans_cipher < 0) {
dropbear_exit("Crypto error");
}
}
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
trans_IV, trans_key,
ses.newkeys->trans.algo_crypt->keysize, 0,
@ -475,6 +487,12 @@ void recv_msg_kexinit() {
TRACE(("continue recv_msg_kexinit: sent kexinit"))
}
/* "Once a party has sent a SSH_MSG_KEXINIT message ...
further SSH_MSG_KEXINIT messages MUST NOT be sent" */
if (ses.kexstate.recvkexinit) {
dropbear_exit("Unexpected KEXINIT");
}
/* start the kex hash */
local_ident_len = strlen(LOCAL_IDENT);
remote_ident_len = strlen(ses.remoteident);
@ -536,6 +554,7 @@ void recv_msg_kexinit() {
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 +579,7 @@ struct kex_dh_param *gen_kexdh_param() {
/* 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 +663,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
/* calculate the hash H to sign */
finish_kexhashbuf();
}
#endif
#if DROPBEAR_ECDH
struct kex_ecdh_param *gen_kexecdh_param() {
@ -703,23 +721,18 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
#endif /* DROPBEAR_ECDH */
#if DROPBEAR_CURVE25519
struct kex_curve25519_param *gen_kexcurve25519_param () {
struct kex_curve25519_param *gen_kexcurve25519_param() {
/* Per http://cr.yp.to/ecdh.html */
struct kex_curve25519_param *param = m_malloc(sizeof(*param));
const unsigned char basepoint[32] = {9};
genrandom(param->priv, CURVE25519_LEN);
param->priv[0] &= 248;
param->priv[31] &= 127;
param->priv[31] |= 64;
curve25519_donna(param->pub, param->priv, basepoint);
dropbear_curve25519_scalarmult(param->pub, param->priv, basepoint);
return param;
}
void free_kexcurve25519_param(struct kex_curve25519_param *param)
{
void free_kexcurve25519_param(struct kex_curve25519_param *param) {
m_burn(param->priv, CURVE25519_LEN);
m_free(param);
}
@ -736,7 +749,7 @@ void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buff
dropbear_exit("Bad curve25519");
}
curve25519_donna(out, param->priv, buf_pub_them->data);
dropbear_curve25519_scalarmult(out, param->priv, buf_pub_them->data);
if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
dropbear_exit("Bad curve25519");
@ -822,21 +835,36 @@ static void read_kex_algos() {
int goodguess = 0;
int allgood = 1; /* we AND this with each goodguess and see if its still
true after */
#if DROPBEAR_KEXGUESS2
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
#else
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
#endif
int kexguess2 = 0;
buf_incrpos(ses.payload, 16); /* start after the cookie */
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
/* kex_algorithms */
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
#if DROPBEAR_KEXGUESS2
if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) {
kexguess2 = 1;
}
#endif
#if DROPBEAR_EXT_INFO
/* Determine if SSH_MSG_EXT_INFO messages should be sent.
Should be done for the first key exchange. Only required on server side
for server-sig-algs */
if (IS_DROPBEAR_SERVER) {
if (!ses.kexstate.donefirstkex) {
if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) {
ses.allow_ext_info = 1;
}
}
}
#endif
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
if (algo == NULL || algo->data == NULL) {
/* kexguess2, ext-info-c, ext-info-s should not match negotiation */
erralgo = "kex";
goto error;
}
@ -845,17 +873,18 @@ static void read_kex_algos() {
ses.newkeys->algo_kex = algo->data;
/* server_host_key_algorithms */
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
erralgo = "hostkey";
goto error;
}
TRACE(("hostkey algo %s", algo->name))
ses.newkeys->algo_hostkey = algo->val;
TRACE(("signature algo %s", algo->name))
ses.newkeys->algo_signature = algo->val;
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
/* encryption_algorithms_client_to_server */
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
if (c2s_cipher_algo == NULL) {
erralgo = "enc c->s";
goto error;
@ -863,7 +892,7 @@ static void read_kex_algos() {
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
if (s2c_cipher_algo == NULL) {
erralgo = "enc s->c";
goto error;
@ -871,23 +900,33 @@ static void read_kex_algos() {
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
#if DROPBEAR_AEAD_MODE
if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) {
c2s_hash_algo = NULL;
} else
#endif
if (c2s_hash_algo == NULL) {
erralgo = "mac c->s";
goto error;
}
TRACE(("hash c2s is %s", c2s_hash_algo->name))
TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
/* mac_algorithms_server_to_client */
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
#if DROPBEAR_AEAD_MODE
if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) {
s2c_hash_algo = NULL;
} else
#endif
if (s2c_hash_algo == NULL) {
erralgo = "mac s->c";
goto error;
}
TRACE(("hash s2c is %s", s2c_hash_algo->name))
TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
/* compression_algorithms_client_to_server */
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
if (c2s_comp_algo == NULL) {
erralgo = "comp c->s";
goto error;
@ -895,7 +934,7 @@ static void read_kex_algos() {
TRACE(("hash c2s is %s", c2s_comp_algo->name))
/* compression_algorithms_server_to_client */
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
if (s2c_comp_algo == NULL) {
erralgo = "comp s->c";
goto error;
@ -929,8 +968,14 @@ static void read_kex_algos() {
ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->recv.algo_mac =
#if DROPBEAR_AEAD_MODE
s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
#endif
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->trans.algo_mac =
#if DROPBEAR_AEAD_MODE
c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
#endif
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
@ -945,8 +990,14 @@ static void read_kex_algos() {
ses.newkeys->trans.crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->recv.algo_mac =
#if DROPBEAR_AEAD_MODE
c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
#endif
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->trans.algo_mac =
#if DROPBEAR_AEAD_MODE
s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
#endif
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;

@ -64,45 +64,36 @@ out:
#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(".");
}
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
{
dropbear_exit("No valid MACs specified for '-m'");
printed_help = 1;
} else {
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0) {
dropbear_exit("No valid MACs specified for '-m'");
}
}
}
if (printed_help) {
dropbear_exit(".");
}
}
#endif

@ -147,6 +147,10 @@ void common_session_init(int sock_in, int sock_out) {
ses.allowprivport = 0;
#if DROPBEAR_PLUGIN
ses.plugin_session = NULL;
#endif
TRACE(("leave session_init"))
}
@ -366,8 +370,11 @@ static void read_session_identification() {
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) {
@ -458,6 +465,11 @@ static int ident_readln(int fd, char* buf, int count) {
TRACE(("leave ident_readln: EOF"))
return -1;
}
#if DROPBEAR_FUZZ
fuzz_dump(&in, 1);
#endif
if (in == '\n') {
/* end of ident string */
break;

@ -57,6 +57,9 @@
/* Fuzzing */
#undef DROPBEAR_FUZZ
/* External Public Key Authentication */
#undef DROPBEAR_PLUGIN
/* Define to 1 if you have the `basename' function. */
#undef HAVE_BASENAME
@ -111,6 +114,9 @@
/* Define to 1 if you have the `getpass' function. */
#undef HAVE_GETPASS
/* Define to 1 if you have the `getrandom' function. */
#undef HAVE_GETRANDOM
/* Define to 1 if you have the `getspnam' function. */
#undef HAVE_GETSPNAM
@ -312,6 +318,9 @@
/* Define to 1 if `ut_type' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_TYPE
/* Define to 1 if you have the <sys/random.h> header file. */
#undef HAVE_SYS_RANDOM_H
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H

139
dropbear/configure vendored

@ -627,6 +627,7 @@ DROPBEAR_FUZZ
ac_ct_CXX
CXXFLAGS
CXX
DROPBEAR_PLUGIN
CRYPTLIB
EGREP
GREP
@ -703,6 +704,7 @@ enable_pam
enable_openpty
enable_syslog
enable_shadow
enable_plugin
enable_fuzz
enable_bundled_libtom
enable_lastlog
@ -1346,10 +1348,12 @@ Optional Features:
--disable-openpty Don't use openpty, use alternative method
--disable-syslog Don't include syslog support
--disable-shadow Don't use shadow passwords (if available)
--enable-plugin Enable support for External Public Key Authentication plug-in
--enable-fuzz Build fuzzing. Not recommended for deployment.
--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.
Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0
--disable-lastlog Disable use of lastlog even if detected no
--disable-utmp Disable use of utmp even if detected no
--disable-utmpx Disable use of utmpx even if detected no
@ -5206,17 +5210,41 @@ $as_echo "$as_me: Using shadow passwords if available" >&6;}
fi
# Check whether --enable-plugin was given.
if test "${enable_plugin+set}" = set; then :
enableval=$enable_plugin;
$as_echo "#define DROPBEAR_PLUGIN 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: Enabling support for External Public Key Authentication" >&5
$as_echo "$as_me: Enabling support for External Public Key Authentication" >&6;}
DROPBEAR_PLUGIN=1
else
$as_echo "#define DROPBEAR_PLUGIN 0" >>confdefs.h
DROPBEAR_PLUGIN=0
fi
# Check whether --enable-fuzz was given.
if test "${enable_fuzz+set}" = set; then :
enableval=$enable_fuzz;
if test "x$enableval" = "xyes"; then
$as_echo "#define DROPBEAR_FUZZ 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: Enabling fuzzing" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: Enabling fuzzing" >&5
$as_echo "$as_me: Enabling fuzzing" >&6;}
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
ac_ext=cpp
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
@ -5473,12 +5501,22 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
else
$as_echo "#define DROPBEAR_FUZZ 0" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: Disabling fuzzing" >&5
$as_echo "$as_me: Disabling fuzzing" >&6;}
DROPBEAR_FUZZ=0
fi
else
$as_echo "#define DROPBEAR_FUZZ 0" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: Disabling fuzzing" >&5
$as_echo "$as_me: Disabling fuzzing" >&6;}
DROPBEAR_FUZZ=0
@ -5646,7 +5684,8 @@ for ac_header in netinet/in.h netinet/tcp.h \
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
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@ -6543,7 +6582,7 @@ fi
done
for ac_func in explicit_bzero memset_s
for ac_func in explicit_bzero memset_s getrandom
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -6565,9 +6604,9 @@ if test "${enable_bundled_libtom+set}" = set; then :
$as_echo "$as_me: Forcing bundled libtom*" >&6;}
else
BUNDLED_LIBTOM=0
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mp_exptmod in -ltommath" >&5
$as_echo_n "checking for mp_exptmod in -ltommath... " >&6; }
if ${ac_cv_lib_tommath_mp_exptmod+:} false; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mp_to_ubin in -ltommath" >&5
$as_echo_n "checking for mp_to_ubin in -ltommath... " >&6; }
if ${ac_cv_lib_tommath_mp_to_ubin+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@ -6581,35 +6620,35 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
char mp_exptmod ();
char mp_to_ubin ();
int
main ()
{
return mp_exptmod ();
return mp_to_ubin ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_tommath_mp_exptmod=yes
ac_cv_lib_tommath_mp_to_ubin=yes
else
ac_cv_lib_tommath_mp_exptmod=no
ac_cv_lib_tommath_mp_to_ubin=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tommath_mp_exptmod" >&5
$as_echo "$ac_cv_lib_tommath_mp_exptmod" >&6; }
if test "x$ac_cv_lib_tommath_mp_exptmod" = xyes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tommath_mp_to_ubin" >&5
$as_echo "$ac_cv_lib_tommath_mp_to_ubin" >&6; }
if test "x$ac_cv_lib_tommath_mp_to_ubin" = xyes; then :
LIBTOM_LIBS="-ltommath $LIBTOM_LIBS"
else
as_fn_error $? "Missing system libtommath and --disable-bundled-libtom was specified" "$LINENO" 5
as_fn_error $? "Missing/old system libtommath and --disable-bundled-libtom was specified" "$LINENO" 5
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for register_cipher in -ltomcrypt" >&5
$as_echo_n "checking for register_cipher in -ltomcrypt... " >&6; }
if ${ac_cv_lib_tomcrypt_register_cipher+:} false; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for poly1305_init in -ltomcrypt" >&5
$as_echo_n "checking for poly1305_init in -ltomcrypt... " >&6; }
if ${ac_cv_lib_tomcrypt_poly1305_init+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@ -6623,30 +6662,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
char register_cipher ();
char poly1305_init ();
int
main ()
{
return register_cipher ();
return poly1305_init ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_tomcrypt_register_cipher=yes
ac_cv_lib_tomcrypt_poly1305_init=yes
else
ac_cv_lib_tomcrypt_register_cipher=no
ac_cv_lib_tomcrypt_poly1305_init=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tomcrypt_register_cipher" >&5
$as_echo "$ac_cv_lib_tomcrypt_register_cipher" >&6; }
if test "x$ac_cv_lib_tomcrypt_register_cipher" = xyes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tomcrypt_poly1305_init" >&5
$as_echo "$ac_cv_lib_tomcrypt_poly1305_init" >&6; }
if test "x$ac_cv_lib_tomcrypt_poly1305_init" = xyes; then :
LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS"
else
as_fn_error $? "Missing system libtomcrypt and --disable-bundled-libtom was specified" "$LINENO" 5
as_fn_error $? "Missing/old system libtomcrypt and --disable-bundled-libtom was specified" "$LINENO" 5
fi
fi
@ -6654,9 +6693,9 @@ fi
else
BUNDLED_LIBTOM=0
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mp_exptmod in -ltommath" >&5
$as_echo_n "checking for mp_exptmod in -ltommath... " >&6; }
if ${ac_cv_lib_tommath_mp_exptmod+:} false; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mp_to_ubin in -ltommath" >&5
$as_echo_n "checking for mp_to_ubin in -ltommath... " >&6; }
if ${ac_cv_lib_tommath_mp_to_ubin+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@ -6670,35 +6709,35 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
char mp_exptmod ();
char mp_to_ubin ();
int
main ()
{
return mp_exptmod ();
return mp_to_ubin ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_tommath_mp_exptmod=yes
ac_cv_lib_tommath_mp_to_ubin=yes
else
ac_cv_lib_tommath_mp_exptmod=no
ac_cv_lib_tommath_mp_to_ubin=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tommath_mp_exptmod" >&5
$as_echo "$ac_cv_lib_tommath_mp_exptmod" >&6; }
if test "x$ac_cv_lib_tommath_mp_exptmod" = xyes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tommath_mp_to_ubin" >&5
$as_echo "$ac_cv_lib_tommath_mp_to_ubin" >&6; }
if test "x$ac_cv_lib_tommath_mp_to_ubin" = xyes; then :
LIBTOM_LIBS="-ltommath $LIBTOM_LIBS"
else
BUNDLED_LIBTOM=1
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for register_cipher in -ltomcrypt" >&5
$as_echo_n "checking for register_cipher in -ltomcrypt... " >&6; }
if ${ac_cv_lib_tomcrypt_register_cipher+:} false; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for poly1305_init in -ltomcrypt" >&5
$as_echo_n "checking for poly1305_init in -ltomcrypt... " >&6; }
if ${ac_cv_lib_tomcrypt_poly1305_init+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@ -6712,27 +6751,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
char register_cipher ();
char poly1305_init ();
int
main ()
{
return register_cipher ();
return poly1305_init ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_tomcrypt_register_cipher=yes
ac_cv_lib_tomcrypt_poly1305_init=yes
else
ac_cv_lib_tomcrypt_register_cipher=no
ac_cv_lib_tomcrypt_poly1305_init=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tomcrypt_register_cipher" >&5
$as_echo "$ac_cv_lib_tomcrypt_register_cipher" >&6; }
if test "x$ac_cv_lib_tomcrypt_register_cipher" = xyes; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tomcrypt_poly1305_init" >&5
$as_echo "$ac_cv_lib_tomcrypt_poly1305_init" >&6; }
if test "x$ac_cv_lib_tomcrypt_poly1305_init" = xyes; then :
LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS"
else
BUNDLED_LIBTOM=1
@ -8835,5 +8874,5 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
$as_echo "$as_me: " >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: Now edit options.h to choose features." >&5
$as_echo "$as_me: Now edit options.h to choose features." >&6;}
{ $as_echo "$as_me:${as_lineno-$LINENO}: Now edit localoptions.h to choose features." >&5
$as_echo "$as_me: Now edit localoptions.h to choose features." >&6;}

@ -323,17 +323,39 @@ AC_ARG_ENABLE(shadow,
]
)
AC_ARG_ENABLE(plugin,
[ --enable-plugin Enable support for External Public Key Authentication plug-in],
[
AC_DEFINE(DROPBEAR_PLUGIN, 1, External Public Key Authentication)
AC_MSG_NOTICE(Enabling support for External Public Key Authentication)
DROPBEAR_PLUGIN=1
],
[
AC_DEFINE(DROPBEAR_PLUGIN, 0, External Public Key Authentication)
DROPBEAR_PLUGIN=0
]
)
AC_SUBST(DROPBEAR_PLUGIN)
AC_ARG_ENABLE(fuzz,
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
[
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
AC_MSG_NOTICE(Enabling fuzzing)
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
AC_PROG_CXX
if test "x$enableval" = "xyes"; then
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
AC_MSG_NOTICE(Enabling fuzzing)
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
AC_PROG_CXX
else
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
AC_MSG_NOTICE(Disabling fuzzing)
DROPBEAR_FUZZ=0
fi
],
[
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
AC_MSG_NOTICE(Disabling fuzzing)
DROPBEAR_FUZZ=0
]
@ -348,7 +370,8 @@ AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \
crypt.h \
pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \
utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h])
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \
sys/random.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@ -504,28 +527,29 @@ AC_CHECK_FUNCS(clock_gettime)
AC_CHECK_HEADERS([mach/mach_time.h])
AC_CHECK_FUNCS(mach_absolute_time)
AC_CHECK_FUNCS(explicit_bzero memset_s)
AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
AC_ARG_ENABLE(bundled-libtom,
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
Default is to use system if available, otherwise bundled.],
Default is to use system if available, otherwise bundled.
Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0],
[
if test "x$enableval" = "xyes"; then
BUNDLED_LIBTOM=1
AC_MSG_NOTICE(Forcing bundled libtom*)
else
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing/old system libtommath and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing/old system libtomcrypt and --disable-bundled-libtom was specified])] )
fi
],
[
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
]
)
@ -858,4 +882,4 @@ AC_MSG_NOTICE([crypt() not available, dropbear server will not have password aut
fi
AC_MSG_NOTICE()
AC_MSG_NOTICE([Now edit options.h to choose features.])
AC_MSG_NOTICE([Now edit localoptions.h to choose features.])

@ -3,11 +3,18 @@
#include "crypto_desc.h"
#include "ltc_prng.h"
#include "ecc.h"
#include "dbrandom.h"
#if DROPBEAR_LTC_PRNG
int dropbear_ltc_prng = -1;
#endif
/* Wrapper for libtommath */
static mp_err dropbear_rand_source(void* out, size_t size) {
genrandom((unsigned char*)out, (unsigned int)size);
return MP_OKAY;
}
/* Register the compiled in ciphers.
* This should be run before using any of the ciphers/hashes */
@ -67,6 +74,8 @@ void crypto_init() {
}
#endif
mp_rand_source(dropbear_rand_source);
#if DROPBEAR_ECC
ltc_mp = ltm_desc;
dropbear_ecc_fill_dp();

@ -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 */

@ -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 */

@ -180,3 +180,13 @@ void m_free_direct(void* ptr) {
}
#endif /* DROPBEAR_TRACKING_MALLOC */
void * m_realloc_ltm(void* ptr, size_t oldsize, size_t newsize) {
(void)oldsize;
return m_realloc(ptr, newsize);
}
void m_free_ltm(void *mem, size_t size) {
(void)size;
m_free_direct(mem);
}

@ -49,24 +49,19 @@ static int donerandinit = 0;
*
*/
/* 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,10 +70,10 @@ process_file(hash_state *hs, const char *filename,
}
readcount = 0;
while (len == 0 || readcount < len)
{
while (wantlen == 0 || readcount < wantlen) {
int readlen, wantread;
unsigned char readbuf[4096];
<<<<<<< HEAD
if (!already_blocked && !prngd)
{
int res;
@ -102,33 +97,30 @@ process_file(hash_state *hs, const char *filename,
if (len == 0)
{
=======
if (wantlen == 0) {
>>>>>>> dropbear
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;
}
@ -195,6 +187,63 @@ void fuzz_seed(void) {
}
#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() {
@ -204,6 +253,7 @@ void seedrandom() {
pid_t pid;
struct timeval tv;
clock_t clockval;
int urandom_seeded = 0;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
@ -217,20 +267,30 @@ void seedrandom() {
/* 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);
#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);
}
/* 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 */

@ -121,7 +121,6 @@ static void generic_dropbear_exit(int exitcode, const char* format,
_dropbear_log(LOG_INFO, fmtbuf, param);
#if DROPBEAR_FUZZ
/* longjmp before cleaning up svr_opts */
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
@ -258,6 +257,12 @@ int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
const int FDIN = 0;
const int FDOUT = 1;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return fuzz_spawn_command(ret_writefd, ret_readfd, ret_errfd, ret_pid);
}
#endif
/* redirect stdin/stdout/stderr */
if (pipe(infds) != 0) {
return DROPBEAR_FAILURE;

@ -1,3 +1,21 @@
dropbear (2020.81-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 29 Oct 2020 22:51:57 +0800
dropbear (2020.80-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Fri, 26 Jun 2020 22:51:57 +0800
dropbear (2020.79-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Jun 2020 22:51:57 +0800
dropbear (2019.78-0.1) unstable; urgency=low
* New upstream release.

@ -43,12 +43,6 @@
#define CHECKCLEARTOWRITE()
#endif
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
* output when Dropbear forks. This will allow it gprof to be used.
* It's useful to run dropbear -F, so you don't fork as much */
/* (This is Linux specific) */
/*#define DEBUG_FORKGPROF*/
/* A couple of flags, not usually useful, and mightn't do anything */
/*#define DEBUG_KEXHASH*/
@ -66,7 +60,9 @@ extern int debug_trace;
/* To debug with GDB it is easier to run with no forking of child processes.
You will need to pass "-F" as well. */
/* #define DEBUG_NOFORK */
#ifndef DEBUG_NOFORK
#define DEBUG_NOFORK 0
#endif
/* For testing as non-root on shadowed systems, include the crypt of a password

@ -22,6 +22,7 @@ IMPORTANT: Some options will require "make clean" after changes */
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key"
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
* on chosen ports and keeps accepting connections. This is the default.
@ -47,7 +48,7 @@ IMPORTANT: Some options will require "make clean" after changes */
#define DROPBEAR_SMALL_CODE 1
/* Enable X11 Forwarding - server only */
#define DROPBEAR_X11FWD 1
#define DROPBEAR_X11FWD 0
/* Enable TCP Fowarding */
/* 'Local' is "-L" style (client listening port forwarded via server)
@ -82,27 +83,36 @@ IMPORTANT: Some options will require "make clean" after changes */
* Including both AES keysize variants (128 and 256) will result in
* a minimal size increase */
#define DROPBEAR_AES128 1
#define DROPBEAR_3DES 1
#define DROPBEAR_AES256 1
#define DROPBEAR_3DES 0
#define DROPBEAR_TWOFISH256 0
#define DROPBEAR_TWOFISH128 0
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
#define DROPBEAR_BLOWFISH 0
/* Enable CBC mode for ciphers. This has security issues though
* is the most compatible with older SSH implementations */
#define DROPBEAR_ENABLE_CBC_MODE 1
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
* generally faster than AES256 on CPU w/o dedicated AES instructions,
* having the same key size. Recommended.
* Compiling in will add ~5,5kB to binary size on x86-64 */
#define DROPBEAR_CHACHA20POLY1305 1
/* Enable "Counter Mode" for ciphers. This is more secure than
* CBC mode against certain attacks. It is recommended for security
* and forwards compatibility */
/* Enable "Counter Mode" for ciphers. Recommended. */
#define DROPBEAR_ENABLE_CTR_MODE 1
/* Enable CBC mode for ciphers. This has security issues though
may be required for compatibility with old implementations */
#define DROPBEAR_ENABLE_CBC_MODE 0
/* Enable "Galois/Counter Mode" for ciphers. This authenticated
* encryption mode is combination of CTR mode and GHASH. Recommended
* for security and forwards compatibility, but slower than CTR on
* CPU w/o dedicated AES/GHASH instructions.
* Compiling in will add ~6kB to binary size on x86-64 */
#define DROPBEAR_ENABLE_GCM_MODE 0
/* Message integrity. sha2-256 is recommended as a default,
sha1 for compatibility */
#define DROPBEAR_SHA1_HMAC 1
#define DROPBEAR_SHA1_96_HMAC 1
#define DROPBEAR_SHA2_256_HMAC 1
#define DROPBEAR_SHA1_96_HMAC 0
/* Hostkey/public key algorithms - at least one required, these are used
* for hostkey as well as for verifying signatures with pubkey auth.
@ -116,11 +126,15 @@ IMPORTANT: Some options will require "make clean" after changes */
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64 */
#define DROPBEAR_ECDSA 1
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
binary size - around 7,5kB on x86-64 */
#define DROPBEAR_ED25519 1
/* RSA must be >=1024 */
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
/* DSS is always 1024 */
/* ECDSA defaults to largest size configured, usually 521 */
/* Ed25519 is always 256 */
/* Add runtime flag "-R" to generate hostkeys as-needed when the first
connection using that key type occurs.
@ -143,7 +157,7 @@ IMPORTANT: Some options will require "make clean" after changes */
* group14 is supported by most implementations.
* group16 provides a greater strength level but is slower and increases binary size
* curve25519 and ecdh algorithms are faster than non-elliptic curve methods
* curve25519 increases binary size by ~8kB on x86-64
* curve25519 increases binary size by ~2,5kB on x86-64
* including either ECDH or ECDSA increases binary size by ~30kB on x86-64
* Small systems should generally include either curve25519 or ecdh for performance.
@ -174,7 +188,7 @@ group1 in Dropbear server too */
#define DO_HOST_LOOKUP 0
/* Whether to print the message of the day (MOTD). */
#define DO_MOTD 0
#define DO_MOTD 1
#define MOTD_FILENAME "/etc/motd"
/* Authentication Types - at least one required.

@ -1,6 +1,8 @@
#include "options.h"
#include "dh_groups.h"
#if DROPBEAR_NORMAL_DH
#if DROPBEAR_DH_GROUP1
/* diffie-hellman-group1-sha1 value for p */
const unsigned char dh_p_1[DH_P_1_LEN] = {
@ -92,3 +94,4 @@ const unsigned char dh_p_16[DH_P_16_LEN] = {
/* Same for all groups */
const int DH_G_VAL = 2;
#endif /* DROPBEAR_NORMAL_DH */

@ -2,6 +2,8 @@
#define DROPBEAR_DH_GROUPS_H
#include "options.h"
#if DROPBEAR_NORMAL_DH
#if DROPBEAR_DH_GROUP1
#define DH_P_1_LEN 128
extern const unsigned char dh_p_1[DH_P_1_LEN];
@ -17,8 +19,8 @@ extern const unsigned char dh_p_14[DH_P_14_LEN];
extern const unsigned char dh_p_16[DH_P_16_LEN];
#endif
extern const int DH_G_VAL;
#endif /* DROPBEAR_NORMAL_DH */
#endif

@ -107,7 +107,7 @@ Print the version
Authorized Keys
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
ECDSA, or DSS
ECDSA, Ed25519 or DSS
key. Each line is of the form
.TP
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
@ -146,8 +146,8 @@ key authentication.
Host Key Files
Host key files are read at startup from a standard location, by default
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
/etc/dropbear/dropbear_ecdsa_host_key
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key,
/etc/dropbear/dropbear_ecdsa_host_key and /etc/dropbear/dropbear_ed25519_host_key
If the -r command line option is specified the default files are not loaded.
Host key files are of the form generated by dropbearkey.

@ -0,0 +1,8 @@
#!/bin/sh
EXITCODE=0
# #ifdef instead of #if
grep '#ifdef DROPBEAR' -I *.c *.h && EXITCODE=1
exit $EXITCODE

@ -13,7 +13,7 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
.SH DESCRIPTION
.B dropbearkey
generates a
\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
\fIRSA\fR, \fIDSS\fR, \fIECDSA\fR, or \fIEd25519\fR
format SSH private key, and saves it to a file for the use with the
Dropbear client or server.
Note that
@ -26,6 +26,7 @@ Type of key to generate.
Must be one of
.I rsa
.I ecdsa
.I ed25519
or
.IR dss .
.TP

@ -43,6 +43,10 @@
* mp_int y
* mp_int x
*
* Ed25519:
* string "ssh-ed25519"
* string k (32 bytes) + A (32 bytes)
*
*/
#include "includes.h"
#include "signkey.h"
@ -51,6 +55,7 @@
#include "genrsa.h"
#include "gendss.h"
#include "gened25519.h"
#include "ecdsa.h"
#include "crypto_desc.h"
#include "dbrandom.h"
@ -75,6 +80,9 @@ static void printhelp(char * progname) {
#endif
#if DROPBEAR_ECDSA
" ecdsa\n"
#endif
#if DROPBEAR_ED25519
" ed25519\n"
#endif
"-f filename Use filename for the secret key.\n"
" ~/.ssh/id_dropbear is recommended for client keys.\n"
@ -94,6 +102,9 @@ static void printhelp(char * progname) {
"521 "
#endif
"\n"
#endif
#if DROPBEAR_ED25519
" Ed25519 has a fixed size of 256 bits\n"
#endif
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
#if DEBUG_TRACE
@ -106,6 +117,14 @@ static void printhelp(char * progname) {
static void check_signkey_bits(enum signkey_type type, int bits)
{
switch (type) {
#if DROPBEAR_ED25519
case DROPBEAR_SIGNKEY_ED25519:
if (bits != 256) {
dropbear_exit("Ed25519 keys have a fixed size of 256 bits\n");
exit(EXIT_FAILURE);
}
break;
#endif
#if DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
@ -114,7 +133,7 @@ static void check_signkey_bits(enum signkey_type type, int bits)
}
break;
#endif
#ifdef DROPEAR_DSS
#if DROPEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
@ -224,6 +243,12 @@ int main(int argc, char ** argv) {
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
}
#endif
#if DROPBEAR_ED25519
if (strcmp(typetext, "ed25519") == 0)
{
keytype = DROPBEAR_SIGNKEY_ED25519;
}
#endif
if (keytype == DROPBEAR_SIGNKEY_NONE) {
fprintf(stderr, "Unknown key type '%s'\n", typetext);

@ -284,6 +284,7 @@ void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *da
unsigned char msghash[SHA1_HASH_SIZE];
unsigned int writelen;
unsigned int i;
size_t written;
DEF_MP_INT(dss_k);
DEF_MP_INT(dss_m);
DEF_MP_INT(dss_temp1);
@ -340,31 +341,31 @@ void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *da
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
buf_putint(buf, 2*SHA1_HASH_SIZE);
writelen = mp_unsigned_bin_size(&dss_r);
writelen = mp_ubin_size(&dss_r);
dropbear_assert(writelen <= SHA1_HASH_SIZE);
/* need to pad to 160 bits with leading zeros */
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
buf_putbyte(buf, 0);
}
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
!= MP_OKAY) {
dropbear_exit("DSS error");
}
mp_clear(&dss_r);
buf_incrwritepos(buf, writelen);
buf_incrwritepos(buf, written);
writelen = mp_unsigned_bin_size(&dss_s);
writelen = mp_ubin_size(&dss_s);
dropbear_assert(writelen <= SHA1_HASH_SIZE);
/* need to pad to 160 bits with leading zeros */
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
buf_putbyte(buf, 0);
}
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
!= MP_OKAY) {
dropbear_exit("DSS error");
}
mp_clear(&dss_s);
buf_incrwritepos(buf, writelen);
buf_incrwritepos(buf, written);
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
&dss_m, NULL);

@ -30,7 +30,7 @@
#if DROPBEAR_DSS
typedef struct {
typedef struct dropbear_DSS_Key {
mp_int* p;
mp_int* q;

@ -166,13 +166,13 @@ ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *c
key = new_ecc_key();
key->dp = curve->dp;
if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
if (mp_from_ubin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
TRACE(("failed to read x"))
goto out;
}
buf_incrpos(buf, size);
if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
if (mp_from_ubin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
TRACE(("failed to read y"))
goto out;
}

@ -0,0 +1,182 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
/* Perform Ed25519 operations on data, including reading keys, signing and
* verification. */
#include "includes.h"
#include "dbutil.h"
#include "buffer.h"
#include "ssh.h"
#include "curve25519.h"
#include "ed25519.h"
#if DROPBEAR_ED25519
/* Load a public ed25519 key from a buffer, initialising the values.
* The key will have the same format as buf_put_ed25519_key.
* These should be freed with ed25519_key_free.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) {
unsigned int len;
TRACE(("enter buf_get_ed25519_pub_key"))
dropbear_assert(key != NULL);
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
len = buf_getint(buf);
if (len != CURVE25519_LEN || buf->len - buf->pos < len) {
TRACE(("leave buf_get_ed25519_pub_key: failure"))
return DROPBEAR_FAILURE;
}
m_burn(key->priv, CURVE25519_LEN);
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
buf_incrpos(buf, CURVE25519_LEN);
TRACE(("leave buf_get_ed25519_pub_key: success"))
return DROPBEAR_SUCCESS;
}
/* Same as buf_get_ed25519_pub_key, but reads private key at the end.
* Loads a public and private ed25519 key from a buffer
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_ed25519_priv_key(buffer *buf, dropbear_ed25519_key *key) {
unsigned int len;
TRACE(("enter buf_get_ed25519_priv_key"))
dropbear_assert(key != NULL);
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
len = buf_getint(buf);
if (len != CURVE25519_LEN*2 || buf->len - buf->pos < len) {
TRACE(("leave buf_get_ed25519_priv_key: failure"))
return DROPBEAR_FAILURE;
}
memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
buf_incrpos(buf, CURVE25519_LEN);
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
buf_incrpos(buf, CURVE25519_LEN);
TRACE(("leave buf_get_ed25519_priv_key: success"))
return DROPBEAR_SUCCESS;
}
/* Clear and free the memory used by a public or private key */
void ed25519_key_free(dropbear_ed25519_key *key) {
TRACE2(("enter ed25519_key_free"))
if (key == NULL) {
TRACE2(("leave ed25519_key_free: key == NULL"))
return;
}
m_burn(key->priv, CURVE25519_LEN);
m_free(key);
TRACE2(("leave ed25519_key_free"))
}
/* Put the public ed25519 key into the buffer in the required format */
void buf_put_ed25519_pub_key(buffer *buf, const dropbear_ed25519_key *key) {
TRACE(("enter buf_put_ed25519_pub_key"))
dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
buf_putstring(buf, key->pub, CURVE25519_LEN);
TRACE(("leave buf_put_ed25519_pub_key"))
}
/* Put the public and private ed25519 key into the buffer in the required format */
void buf_put_ed25519_priv_key(buffer *buf, const dropbear_ed25519_key *key) {
TRACE(("enter buf_put_ed25519_priv_key"))
dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
buf_putint(buf, CURVE25519_LEN*2);
buf_putbytes(buf, key->priv, CURVE25519_LEN);
buf_putbytes(buf, key->pub, CURVE25519_LEN);
TRACE(("leave buf_put_ed25519_priv_key"))
}
/* Sign the data presented with key, writing the signature contents
* to the buffer */
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
unsigned char s[64];
unsigned long slen = sizeof(s);
TRACE(("enter buf_put_ed25519_sign"))
dropbear_assert(key != NULL);
dropbear_ed25519_sign(data_buf->data, data_buf->len, s, &slen, key->priv, key->pub);
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
buf_putstring(buf, s, slen);
TRACE(("leave buf_put_ed25519_sign"))
}
#if DROPBEAR_SIGNKEY_VERIFY
/* Verify a signature in buf, made on data by the key given.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
int ret = DROPBEAR_FAILURE;
unsigned char *s;
unsigned long slen;
TRACE(("enter buf_ed25519_verify"))
dropbear_assert(key != NULL);
slen = buf_getint(buf);
if (slen != 64 || buf->len - buf->pos < slen) {
TRACE(("leave buf_ed25519_verify: bad size"))
goto out;
}
s = buf_getptr(buf, slen);
if (dropbear_ed25519_verify(data_buf->data, data_buf->len,
s, slen, key->pub) == 0) {
/* signature is valid */
TRACE(("leave buf_ed25519_verify: success!"))
ret = DROPBEAR_SUCCESS;
}
out:
TRACE(("leave buf_ed25519_verify: ret %d", ret))
return ret;
}
#endif /* DROPBEAR_SIGNKEY_VERIFY */
#endif /* DROPBEAR_ED25519 */

@ -0,0 +1,54 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef DROPBEAR_ED25519_H_
#define DROPBEAR_ED25519_H_
#include "includes.h"
#include "buffer.h"
#if DROPBEAR_ED25519
#define CURVE25519_LEN 32
typedef struct dropbear_ED25519_Key {
unsigned char priv[CURVE25519_LEN];
unsigned char pub[CURVE25519_LEN];
} dropbear_ed25519_key;
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf);
#if DROPBEAR_SIGNKEY_VERIFY
int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
#endif
int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key);
int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key);
void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key);
void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key);
void ed25519_key_free(dropbear_ed25519_key *key);
#endif /* DROPBEAR_ED25519 */
#endif /* DROPBEAR_ED25519_H_ */

@ -99,6 +99,10 @@ rsa.c RSA asymmetric crypto routines
dss.c DSS asymmetric crypto routines
ed25519.c Ed25519 asymmetric crypto routines
gened25519.c Ed25519 key generation
gendss.c DSS key generation
genrsa.c RSA key generation

@ -8,14 +8,17 @@
#include "session.h"
#include "dbrandom.h"
#include "bignum.h"
#include "atomicio.h"
#include "fuzz-wrapfd.h"
struct dropbear_fuzz_options fuzz;
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
static void load_fixed_hostkeys(void);
static void load_fixed_client_key(void);
void fuzz_common_setup(void) {
disallow_core();
fuzz.fuzzing = 1;
fuzz.wrapfds = 1;
fuzz.do_jmp = 1;
@ -36,7 +39,8 @@ int fuzz_set_input(const uint8_t *Data, size_t Size) {
memset(&ses, 0x0, sizeof(ses));
memset(&svr_ses, 0x0, sizeof(svr_ses));
wrapfd_setup();
memset(&cli_ses, 0x0, sizeof(cli_ses));
wrapfd_setup(fuzz.input);
fuzz_seed();
@ -63,24 +67,59 @@ void fuzz_svr_setup(void) {
_dropbear_exit = svr_dropbear_exit;
char *argv[] = {
"dropbear",
"-E",
};
int argc = sizeof(argv) / sizeof(*argv);
svr_getopts(argc, argv);
/* user lookups might be slow, cache it */
fuzz.pw_name = m_strdup("person");
fuzz.pw_dir = m_strdup("/tmp");
fuzz.pw_shell = m_strdup("/bin/zsh");
fuzz.pw_passwd = m_strdup("!!zzznope");
load_fixed_hostkeys();
}
static void load_fixed_hostkeys(void) {
void fuzz_cli_setup(void) {
fuzz_common_setup();
_dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
char *argv[] = {
"dbclient",
"-y",
"localhost",
"uptime"
};
int argc = sizeof(argv) / sizeof(*argv);
cli_getopts(argc, argv);
load_fixed_client_key();
/* Avoid password prompt */
setenv(DROPBEAR_PASSWORD_ENV, "password", 1);
}
#include "fuzz-hostkeys.c"
static void load_fixed_client_key(void) {
buffer *b = buf_new(3000);
sign_key *key;
enum signkey_type keytype;
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
buf_putbytes(b, keyed25519, keyed25519_len);
buf_setpos(b, 0);
if (buf_get_priv_key(b, key, &keytype) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed ed25519 hostkey");
}
list_append(cli_opts.privkeys, key);
buf_free(b);
}
static void load_fixed_hostkeys(void) {
buffer *b = buf_new(3000);
enum signkey_type type;
@ -112,6 +151,14 @@ static void load_fixed_hostkeys(void) {
dropbear_exit("failed fixed ecdsa hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keyed25519, keyed25519_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_ED25519;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed ed25519 hostkey");
}
buf_free(b);
}
@ -139,10 +186,21 @@ void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_por
void fuzz_fake_send_kexdh_reply(void) {
assert(!ses.dh_K);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
mp_set_int(ses.dh_K, 12345678);
mp_set_ul(ses.dh_K, 12345678uL);
finish_kexhashbuf();
}
/* fake version of spawn_command() */
int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
*ret_writefd = wrapfd_new();
*ret_readfd = wrapfd_new();
if (ret_errfd) {
*ret_errfd = wrapfd_new();
}
*ret_pid = 999;
return DROPBEAR_SUCCESS;
}
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
static int once = 0;
if (!once) {
@ -156,7 +214,7 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
}
/*
get prefix. input format is
get prefix, allowing for future extensibility. input format is
string prefix
uint32 wrapfd seed
... to be extended later
@ -174,8 +232,7 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
uint32_t wrapseed = buf_getint(fuzz.input);
wrapfd_setseed(wrapseed);
int fakesock = 20;
wrapfd_add(fakesock, fuzz.input, PLAIN);
int fakesock = wrapfd_new();
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
@ -190,6 +247,52 @@ int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
return 0;
}
int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths) {
static int once = 0;
if (!once) {
fuzz_cli_setup();
fuzz.skip_kexmaths = skip_kexmaths;
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
/*
get prefix, allowing for future extensibility. input format is
string prefix
uint32 wrapfd seed
... to be extended later
[bytes] ssh input stream
*/
/* be careful to avoid triggering buffer.c assertions */
if (fuzz.input->len < 8) {
return 0;
}
size_t prefix_size = buf_getint(fuzz.input);
if (prefix_size != 4) {
return 0;
}
uint32_t wrapseed = buf_getint(fuzz.input);
wrapfd_setseed(wrapseed);
int fakesock = wrapfd_new();
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
cli_session(fakesock, fakesock, NULL, 0);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}
const void* fuzz_get_algo(const algo_type *algos, const char* name) {
const algo_type *t;
for (t = algos; t->name; t++) {
@ -199,3 +302,10 @@ const void* fuzz_get_algo(const algo_type *algos, const char* name) {
}
assert(0);
}
void fuzz_dump(const unsigned char* data, size_t len) {
TRACE(("dump %zu", len))
if (fuzz.dumping) {
assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len);
}
}

@ -9,7 +9,6 @@ int main(int argc, char ** argv) {
buffer *input = buf_new(100000);
for (i = 1; i < argc; i++) {
printf("arg %s\n", argv[i]);
#if DEBUG_TRACE
if (strcmp(argv[i], "-v") == 0) {
debug_trace = 1;
@ -30,6 +29,7 @@ int main(int argc, char ** argv) {
buf_readfile(input, fn);
buf_setpos(input, 0);
/* Run twice to catch problems with statefulness */
fuzz.wrapfds = old_fuzz_wrapfds;
printf("Running %s once \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);

@ -1,5 +1,6 @@
/* To be included in fuzz-common.c */
unsigned char keyr[] = {
static unsigned char keyr[] = {
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00,
0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xb1,
0x06, 0x95, 0xc9, 0xa8, 0x38, 0xb9, 0x99, 0x91, 0xb5, 0x17, 0x39, 0xb9,
@ -69,8 +70,8 @@ unsigned char keyr[] = {
0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
0xa3
};
unsigned int keyr_len = 805;
unsigned char keye[] = {
static unsigned int keyr_len = 805;
static unsigned char keye[] = {
0x00, 0x00, 0x00, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68,
0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
0x00, 0x00, 0x08, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
@ -84,8 +85,8 @@ unsigned char keye[] = {
0x3c, 0x58, 0x28, 0x70, 0x9b, 0x23, 0x39, 0x51, 0xd7, 0xbc, 0xa7, 0x1a,
0xf5, 0xb4, 0x23, 0xd3, 0xf6, 0x17, 0xa6, 0x9c, 0x02
};
unsigned int keye_len = 141;
unsigned char keyd[] = {
static unsigned int keye_len = 141;
static unsigned char keyd[] = {
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x64, 0x73, 0x73, 0x00,
0x00, 0x00, 0x81, 0x00, 0xb0, 0x02, 0x19, 0x8b, 0xf3, 0x46, 0xf9, 0xc5,
0x47, 0x78, 0x3d, 0x7f, 0x04, 0x10, 0x0a, 0x43, 0x8e, 0x00, 0x9e, 0xa4,
@ -126,4 +127,14 @@ unsigned char keyd[] = {
0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
0xf9, 0x39
};
unsigned int keyd_len = 458;
static unsigned int keyd_len = 458;
static unsigned char keyed25519[] = {
0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
};
static unsigned int keyed25519_len = 83;

@ -17,25 +17,33 @@ static const double CHANCE_WRITE2 = 0.5;
struct fdwrap {
enum wrapfd_mode mode;
buffer *buf;
int closein;
int closeout;
};
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
/* for quick selection of in-use descriptors */
static int wrap_used[IOWRAP_MAXFD+1];
static unsigned int nused;
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
static int wrapfd_maxfd = -1;
static unsigned short rand_state[3];
static buffer *input_buf;
static int devnull_fd = -1;
void wrapfd_setup(void) {
static void wrapfd_remove(int fd);
void wrapfd_setup(buffer *buf) {
TRACE(("wrapfd_setup"))
nused = 0;
memset(wrap_fds, 0x0, sizeof(wrap_fds));
memset(wrap_used, 0x0, sizeof(wrap_used));
// clean old ones
int i;
for (i = 0; i <= wrapfd_maxfd; i++) {
if (wrap_fds[i].mode == COMMONBUF) {
wrapfd_remove(i);
}
}
wrapfd_maxfd = -1;
memset(rand_state, 0x0, sizeof(rand_state));
wrapfd_setseed(50);
input_buf = buf;
}
void wrapfd_setseed(uint32_t seed) {
@ -43,39 +51,30 @@ void wrapfd_setseed(uint32_t seed) {
nrand48(rand_state);
}
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode == UNUSED);
assert(buf || mode == RANDOMIN);
int wrapfd_new() {
if (devnull_fd == -1) {
devnull_fd = open("/dev/null", O_RDONLY);
assert(devnull_fd != -1);
}
wrap_fds[fd].mode = mode;
wrap_fds[fd].buf = buf;
int fd = dup(devnull_fd);
assert(fd != -1);
assert(wrap_fds[fd].mode == UNUSED);
wrap_fds[fd].mode = COMMONBUF;
wrap_fds[fd].closein = 0;
wrap_fds[fd].closeout = 0;
wrap_used[nused] = fd;
wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
nused++;
return fd;
}
void wrapfd_remove(int fd) {
unsigned int i, j;
static void wrapfd_remove(int fd) {
TRACE(("wrapfd_remove %d", fd))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode != UNUSED);
wrap_fds[fd].mode = UNUSED;
/* remove from used list */
for (i = 0, j = 0; i < nused; i++) {
if (wrap_used[i] != fd) {
wrap_used[j] = wrap_used[i];
j++;
}
}
nused--;
m_close(fd);
}
int wrapfd_close(int fd) {
@ -89,7 +88,6 @@ int wrapfd_close(int fd) {
int wrapfd_read(int fd, void *out, size_t count) {
size_t maxread;
buffer *buf;
if (!fuzz.wrapfds) {
return read(fd, out, count);
@ -115,15 +113,14 @@ int wrapfd_read(int fd, void *out, size_t count) {
return -1;
}
buf = wrap_fds[fd].buf;
if (buf) {
maxread = MIN(buf->len - buf->pos, count);
if (input_buf) {
maxread = MIN(input_buf->len - input_buf->pos, count);
/* returns 0 if buf is EOF, as intended */
if (maxread > 0) {
maxread = nrand48(rand_state) % maxread + 1;
}
memcpy(out, buf_getptr(buf, maxread), maxread);
buf_incrpos(buf, maxread);
memcpy(out, buf_getptr(input_buf, maxread), maxread);
buf_incrpos(input_buf, maxread);
return maxread;
}
@ -175,8 +172,6 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
int ret = 0;
int fdlist[IOWRAP_MAXFD+1];
memset(fdlist, 0x0, sizeof(fdlist));
if (!fuzz.wrapfds) {
return select(nfds, readfds, writefds, exceptfds, timeout);
}

@ -5,15 +5,13 @@
enum wrapfd_mode {
UNUSED = 0,
PLAIN,
INPROGRESS,
RANDOMIN
COMMONBUF, // using the common buffer
};
void wrapfd_setup(void);
// buf is a common buffer read by all wrapped FDs. doesn't take ownership of buf
void wrapfd_setup(buffer *buf);
void wrapfd_setseed(uint32_t seed);
// doesn't take ownership of buf. buf is optional.
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
int wrapfd_new();
// called via #defines for read/write/select
int wrapfd_read(int fd, void *out, size_t count);

@ -13,12 +13,14 @@
// once per process
void fuzz_common_setup(void);
void fuzz_svr_setup(void);
void fuzz_cli_setup(void);
// must be called once per fuzz iteration.
// returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE
int fuzz_set_input(const uint8_t *Data, size_t Size);
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths);
int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths);
const void* fuzz_get_algo(const algo_type *algos, const char* name);
// fuzzer functions that intrude into general code
@ -28,9 +30,13 @@ int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const unsigned char* keyblob, unsigned int keybloblen);
extern const char * const * fuzz_signkey_names;
void fuzz_seed(void);
// helpers
void fuzz_get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void fuzz_fake_send_kexdh_reply(void);
int fuzz_spawn_command(int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid);
void fuzz_dump(const unsigned char* data, size_t len);
// fake IO wrappers
#ifndef FUZZ_SKIP_WRAP
@ -57,12 +63,11 @@ struct dropbear_fuzz_options {
int do_jmp;
sigjmp_buf jmp;
uid_t pw_uid;
gid_t pw_gid;
char* pw_name;
char* pw_dir;
char* pw_shell;
char* pw_passwd;
// write out decrypted session data to this FD if it's set
// flag - this needs to be set manually in cli-main.c etc
int dumping;
// the file descriptor
int recv_dumpfd;
};
extern struct dropbear_fuzz_options fuzz;

@ -27,7 +27,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
unsigned int algolen;
char* algoname = buf_getstring(keyblob, &algolen);
if (have_algo(algoname, algolen, sshhostkey) == DROPBEAR_FAILURE) {
if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNKEY_NONE) {
dropbear_exit("fuzzer imagined a bogus algorithm");
}

@ -2,6 +2,7 @@
#include "session.h"
#include "fuzz-wrapfd.h"
#include "debug.h"
#include "dss.h"
static void setup_fuzzer(void) {
fuzz_common_setup();
@ -27,21 +28,35 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (setjmp(fuzz.jmp) == 0) {
sign_key *key = new_sign_key();
enum signkey_type type = DROPBEAR_SIGNKEY_ANY;
if (buf_get_pub_key(fuzz.input, key, &type) == DROPBEAR_SUCCESS) {
if (buf_verify(fuzz.input, key, verifydata) == DROPBEAR_SUCCESS) {
enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY;
if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
enum signature_type sigtype;
if (keytype == DROPBEAR_SIGNKEY_RSA) {
/* Flip a coin to decide rsa signature type */
int flag = buf_getbyte(fuzz.input);
if (flag & 0x01) {
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
} else {
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
}
} else {
sigtype = signature_type_from_signkey(keytype);
}
if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) {
/* The fuzzer is capable of generating keys with a signature to match.
We don't want false positives if the key is bogus, since a client/server
wouldn't be trusting a bogus key anyway */
int boguskey = 0;
if (type == DROPBEAR_SIGNKEY_DSS) {
if (keytype == DROPBEAR_SIGNKEY_DSS) {
/* So far have seen dss keys with bad p/q/g domain parameters */
int pprime, qprime;
assert(mp_prime_is_prime(key->dsskey->p, 5, &pprime) == MP_OKAY);
assert(mp_prime_is_prime(key->dsskey->q, 18, &qprime) == MP_OKAY);
boguskey = !(pprime && qprime);
/* Could also check g**q mod p == 1 */
int pprime, qprime, trials;
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
assert(mp_prime_is_prime(key->dsskey->q, trials, &qprime) == MP_OKAY);
boguskey = !(pprime && qprime);
/* Could also check g**q mod p == 1 */
}
if (!boguskey) {

@ -4,7 +4,7 @@
result=0
hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://hg.ucc.asn.au/dropbear-fuzzcorpus fuzzcorpus || exit 1
for f in `make list-fuzz-targets`; do
./$f fuzzcorpus/$f/* || result=1
done

@ -0,0 +1,120 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2020 by Vladislav Grishenko
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "algo.h"
#include "dbutil.h"
#include "gcm.h"
#if DROPBEAR_ENABLE_GCM_MODE
#define GHASH_LEN 16
static const struct dropbear_hash dropbear_ghash =
{NULL, 0, GHASH_LEN};
static int dropbear_gcm_start(int cipher, const unsigned char *IV,
const unsigned char *key, int keylen,
int UNUSED(num_rounds), dropbear_gcm_state *state) {
int err;
TRACE2(("enter dropbear_gcm_start"))
if ((err = gcm_init(&state->gcm, cipher, key, keylen)) != CRYPT_OK) {
return err;
}
memcpy(state->iv, IV, GCM_NONCE_LEN);
TRACE2(("leave dropbear_gcm_start"))
return CRYPT_OK;
}
static int dropbear_gcm_crypt(unsigned int UNUSED(seq),
const unsigned char *in, unsigned char *out,
unsigned long len, unsigned long taglen,
dropbear_gcm_state *state, int direction) {
unsigned char *iv, tag[GHASH_LEN];
int i, err;
TRACE2(("enter dropbear_gcm_crypt"))
if (len < 4 || taglen != GHASH_LEN) {
return CRYPT_ERROR;
}
gcm_reset(&state->gcm);
if ((err = gcm_add_iv(&state->gcm,
state->iv, GCM_NONCE_LEN)) != CRYPT_OK) {
return err;
}
if ((err = gcm_add_aad(&state->gcm, in, 4)) != CRYPT_OK) {
return err;
}
if ((err = gcm_process(&state->gcm, (unsigned char *) in + 4,
len - 4, out + 4, direction)) != CRYPT_OK) {
return err;
}
if (direction == LTC_ENCRYPT) {
gcm_done(&state->gcm, out + len, &taglen);
} else {
gcm_done(&state->gcm, tag, &taglen);
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
return CRYPT_ERROR;
}
}
/* increment invocation counter */
iv = state->iv + GCM_IVFIX_LEN;
for (i = GCM_IVCTR_LEN - 1; i >= 0 && ++iv[i] == 0; i--);
TRACE2(("leave dropbear_gcm_crypt"))
return CRYPT_OK;
}
static int dropbear_gcm_getlength(unsigned int UNUSED(seq),
const unsigned char *in, unsigned int *outlen,
unsigned long len, dropbear_gcm_state* UNUSED(state)) {
TRACE2(("enter dropbear_gcm_getlength"))
if (len < 4) {
return CRYPT_ERROR;
}
LOAD32H(*outlen, in);
TRACE2(("leave dropbear_gcm_getlength"))
return CRYPT_OK;
}
const struct dropbear_cipher_mode dropbear_mode_gcm =
{(void *)dropbear_gcm_start, NULL, NULL,
(void *)dropbear_gcm_crypt,
(void *)dropbear_gcm_getlength, &dropbear_ghash};
#endif /* DROPBEAR_ENABLE_GCM_MODE */

@ -0,0 +1,47 @@
/*
* 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_GCM_H_
#define DROPBEAR_DROPBEAR_GCM_H_
#include "includes.h"
#include "algo.h"
#if DROPBEAR_ENABLE_GCM_MODE
#define GCM_IVFIX_LEN 4
#define GCM_IVCTR_LEN 8
#define GCM_NONCE_LEN (GCM_IVFIX_LEN + GCM_IVCTR_LEN)
typedef struct {
gcm_state gcm;
unsigned char iv[GCM_NONCE_LEN];
} dropbear_gcm_state;
extern const struct dropbear_cipher_mode dropbear_mode_gcm;
#endif /* DROPBEAR_ENABLE_GCM_MODE */
#endif /* DROPBEAR_DROPBEAR_GCM_H_ */

@ -68,6 +68,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
static void getq(const dropbear_dss_key *key) {
unsigned char buf[QSIZE];
int trials;
/* 160 bit prime */
genrandom(buf, QSIZE);
@ -76,8 +77,9 @@ static void getq(const dropbear_dss_key *key) {
bytes_to_mp(key->q, buf, QSIZE);
/* 18 rounds are required according to HAC */
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->q));
if (mp_prime_next_prime(key->q, trials, 0) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}
@ -89,7 +91,7 @@ static void getp(const dropbear_dss_key *key, unsigned int size) {
DEF_MP_INT(tempC);
DEF_MP_INT(tempP);
DEF_MP_INT(temp2q);
int result;
int result, trials;
unsigned char *buf;
m_mp_init_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
@ -129,9 +131,10 @@ static void getp(const dropbear_dss_key *key, unsigned int size) {
exit(1);
}
/* now check for prime, 5 rounds is enough according to HAC */
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->p));
/* result == 1 => p is prime */
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
if (mp_prime_is_prime(key->p, trials, &result) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
exit(1);
}

@ -0,0 +1,47 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
#include "dbrandom.h"
#include "curve25519.h"
#include "gened25519.h"
#if DROPBEAR_ED25519
dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size) {
dropbear_ed25519_key *key;
if (size != 256) {
dropbear_exit("Ed25519 keys have a fixed size of 256 bits");
}
key = m_malloc(sizeof(*key));
dropbear_ed25519_make_key(key->pub, key->priv);
return key;
}
#endif /* DROPBEAR_ED25519 */

@ -0,0 +1,36 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2002,2003 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#ifndef DROPBEAR_GENED25519_H_
#define DROPBEAR_GENED25519_H_
#include "ed25519.h"
#if DROPBEAR_ED25519
dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size);
#endif /* DROPBEAR_ED25519 */
#endif /* DROPBEAR_GENED25519_H_ */

@ -53,10 +53,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
m_mp_init_multi(&pminus, &lcm, &qminus, NULL);
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
mp_set_ul(key->e, RSA_E);
while (1) {
getrsaprime(key->p, &pminus, key->e, size/16);
@ -95,6 +92,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size_bytes) {
unsigned char *buf;
int trials;
DEF_MP_INT(temp_gcd);
buf = (unsigned char*)m_malloc(size_bytes);
@ -108,8 +106,9 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
bytes_to_mp(prime, buf, size_bytes);
/* find the next integer which is prime, 8 round of miller-rabin */
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
/* find the next integer which is prime */
trials = mp_prime_rabin_miller_trials(mp_count_bits(prime));
if (mp_prime_next_prime(prime, trials, 0) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}

@ -4,18 +4,26 @@
#include "ecdsa.h"
#include "genrsa.h"
#include "gendss.h"
#include "gened25519.h"
#include "signkey.h"
#include "dbrandom.h"
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int buf_writefile(buffer * buf, const char * filename) {
static int buf_writefile(buffer * buf, const char * filename, int skip_exist) {
int ret = DROPBEAR_FAILURE;
int fd = -1;
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
filename, strerror(errno));
/* If generating keys on connection (skip_exist) it's OK to get EEXIST
- we probably just lost a race with another connection to generate the key */
if (skip_exist && errno == EEXIST) {
ret = DROPBEAR_SUCCESS;
} else {
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
filename, strerror(errno));
}
goto out;
}
@ -68,6 +76,10 @@ static int get_default_bits(enum signkey_type keytype)
return 384;
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return 256;
#endif
#if DROPBEAR_ED25519
case DROPBEAR_SIGNKEY_ED25519:
return 256;
#endif
default:
return 0;
@ -118,6 +130,11 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
*signkey_key_ptr(key, keytype) = ecckey;
}
break;
#endif
#if DROPBEAR_ED25519
case DROPBEAR_SIGNKEY_ED25519:
key->ed25519key = gen_ed25519_priv_key(bits);
break;
#endif
default:
dropbear_exit("Internal error");
@ -134,7 +151,7 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
fn_temp = m_malloc(strlen(filename) + 30);
snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
ret = buf_writefile(buf, fn_temp);
ret = buf_writefile(buf, fn_temp, 0);
if (ret == DROPBEAR_FAILURE) {
goto out;
@ -143,16 +160,34 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
if (link(fn_temp, filename) < 0) {
/* If generating keys on connection (skipexist) it's OK to get EEXIST
- we probably just lost a race with another connection to generate the key */
<<<<<<< HEAD
/* fallback to rename() if the fs doesn't support link() */
if ((!(skip_exist && errno == EEXIST)) &&
(rename(fn_temp, filename) < 0)) {
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
strerror(errno));
ret = DROPBEAR_FAILURE;
=======
if (!(skip_exist && errno == EEXIST)) {
if (errno == EPERM || errno == EACCES) {
/* Non-atomic fallback when hard-links not allowed or unsupported */
buf_setpos(buf, 0);
ret = buf_writefile(buf, filename, skip_exist);
} else {
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
strerror(errno));
ret = DROPBEAR_FAILURE;
}
>>>>>>> dropbear
goto out;
}
}
/* ensure directory update is flushed to disk, otherwise we can end up
with zero-byte hostkey files if the power goes off */
fsync_parent_dir(filename);
out:
if (buf) {
buf_burn(buf);

@ -25,6 +25,8 @@
#ifndef DROPBEAR_INCLUDES_H_
#define DROPBEAR_INCLUDES_H_
/* uclibc needs _GNU_SOURCE, maybe other things? */
#define _GNU_SOURCE
#include "options.h"
#include "debug.h"
@ -124,6 +126,10 @@
#include <sys/uio.h>
#endif
#ifdef HAVE_SYS_RANDOM_H
#include <sys/random.h>
#endif
#ifdef BUNDLED_LIBTOM
#include "libtomcrypt/src/headers/tomcrypt.h"
#include "libtommath/tommath.h"
@ -164,6 +170,10 @@ typedef u_int32_t uint32_t;
#include <linux/pkt_sched.h>
#endif
#if DROPBEAR_PLUGIN
#include <dlfcn.h>
#endif
#include "fake-rfc2553.h"
#include "fuzz.h"

@ -36,10 +36,12 @@ void recv_msg_newkeys(void);
void kexfirstinitialise(void);
void finish_kexhashbuf(void);
#if DROPBEAR_NORMAL_DH
struct kex_dh_param *gen_kexdh_param(void);
void free_kexdh_param(struct kex_dh_param *param);
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
sign_key *hostkey);
#endif
#if DROPBEAR_ECDH
struct kex_ecdh_param *gen_kexecdh_param(void);
@ -65,6 +67,8 @@ void recv_msg_kexdh_init(void); /* server */
void send_msg_kexdh_init(void); /* client */
void recv_msg_kexdh_reply(void); /* client */
void recv_msg_ext_info(void);
struct KEXState {
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
@ -73,8 +77,9 @@ struct KEXState {
unsigned sentnewkeys : 1; /* set once we've send MSG_NEWKEYS (will be cleared once we have also received */
unsigned recvnewkeys : 1; /* set once we've received MSG_NEWKEYS (cleared once we have also sent */
unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed,
unsigned int donefirstkex; /* Set to 1 after the first kex has completed,
ie the transport layer has been set up */
unsigned int donesecondkex; /* Set to 1 after the second kex has completed */
unsigned our_first_follows_matches : 1;
@ -84,10 +89,12 @@ struct KEXState {
};
#if DROPBEAR_NORMAL_DH
struct kex_dh_param {
mp_int pub; /* e */
mp_int priv; /* x */
};
#endif
#if DROPBEAR_ECDH
struct kex_ecdh_param {
@ -101,9 +108,6 @@ struct kex_curve25519_param {
unsigned char priv[CURVE25519_LEN];
unsigned char pub[CURVE25519_LEN];
};
/* No header file for curve25519_donna */
int curve25519_donna(unsigned char *out, const unsigned char *secret, const unsigned char *other);
#endif
#endif /* DROPBEAR_KEX_H_ */

@ -35,6 +35,18 @@
#include "buffer.h"
#include "dbutil.h"
#include "ecc.h"
#include "ssh.h"
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
static const unsigned char OSSH_PKEY_BLOB[] =
"openssh-key-v1\0" /* AUTH_MAGIC */
"\0\0\0\4none" /* cipher name*/
"\0\0\0\4none" /* kdf name */
"\0\0\0\0" /* kdf */
"\0\0\0\1"; /* key num */
#define OSSH_PKEY_BLOBLEN (sizeof(OSSH_PKEY_BLOB) - 1)
#if DROPBEAR_ECDSA
static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
@ -352,7 +364,7 @@ struct mpint_pos { void *start; int bytes; };
* Code to read and write OpenSSH private keys.
*/
enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
enum { OSSH_DSA, OSSH_RSA, OSSH_EC, OSSH_PKEY };
struct openssh_key {
int type;
int encrypted;
@ -364,11 +376,12 @@ struct openssh_key {
static struct openssh_key *load_openssh_key(const char *filename)
{
struct openssh_key *ret;
buffer *buf = NULL;
FILE *fp = NULL;
char buffer[256];
char *errmsg = NULL, *p = NULL;
int headers_done;
unsigned long len, outlen;
unsigned long len;
ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key));
ret->keyblob = NULL;
@ -397,12 +410,15 @@ static struct openssh_key *load_openssh_key(const char *filename)
ret->type = OSSH_DSA;
else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
ret->type = OSSH_EC;
else if (!strcmp(buffer, "-----BEGIN OPENSSH PRIVATE KEY-----\n"))
ret->type = OSSH_PKEY;
else {
errmsg = "Unrecognised key type";
goto error;
}
headers_done = 0;
buf = buf_new(0);
while (1) {
if (!fgets(buffer, sizeof(buffer), fp)) {
errmsg = "Unexpected end of file";
@ -448,20 +464,31 @@ static struct openssh_key *load_openssh_key(const char *filename)
} else {
headers_done = 1;
len = strlen(buffer);
outlen = len*4/3;
if (ret->keyblob_len + outlen > ret->keyblob_size) {
ret->keyblob_size = ret->keyblob_len + outlen + 256;
ret->keyblob = (unsigned char*)m_realloc(ret->keyblob,
ret->keyblob_size);
}
outlen = ret->keyblob_size - ret->keyblob_len;
if (base64_decode((const unsigned char *)buffer, len,
ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){
errmsg = "Error decoding base64";
goto error;
}
ret->keyblob_len += outlen;
buf = buf_resize(buf, buf->size + len);
buf_putbytes(buf, buffer, len);
}
}
if (buf && buf->len) {
ret->keyblob_size = ret->keyblob_len + buf->len*4/3 + 256;
ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, ret->keyblob_size);
len = ret->keyblob_size;
if (base64_decode((const unsigned char *)buf->data, buf->len,
ret->keyblob, &len) != CRYPT_OK){
errmsg = "Error decoding base64";
goto error;
}
ret->keyblob_len = len;
}
if (ret->type == OSSH_PKEY) {
if (ret->keyblob_len < OSSH_PKEY_BLOBLEN ||
memcmp(ret->keyblob, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN)) {
errmsg = "Error decoding OpenSSH key";
goto error;
}
ret->keyblob_len -= OSSH_PKEY_BLOBLEN;
memmove(ret->keyblob, ret->keyblob + OSSH_PKEY_BLOBLEN, ret->keyblob_len);
}
if (ret->keyblob_len == 0 || !ret->keyblob) {
@ -474,10 +501,18 @@ static struct openssh_key *load_openssh_key(const char *filename)
goto error;
}
if (buf) {
buf_burn(buf);
buf_free(buf);
}
m_burn(buffer, sizeof(buffer));
return ret;
error:
if (buf) {
buf_burn(buf);
buf_free(buf);
}
m_burn(buffer, sizeof(buffer));
if (ret) {
if (ret->keyblob) {
@ -569,6 +604,57 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
#endif
}
/*
* Now we have a decrypted key blob, which contains OpenSSH
* encoded private key. We must now untangle the OpenSSH format.
*/
if (key->type == OSSH_PKEY) {
blobbuf = buf_new(key->keyblob_len);
buf_putbytes(blobbuf, key->keyblob, key->keyblob_len);
buf_setpos(blobbuf, 0);
/* limit length of private key blob */
len = buf_getint(blobbuf);
buf_setlen(blobbuf, blobbuf->pos + len);
type = DROPBEAR_SIGNKEY_ANY;
if (buf_get_pub_key(blobbuf, retkey, &type)
!= DROPBEAR_SUCCESS) {
errmsg = "Error parsing OpenSSH key";
goto ossh_error;
}
/* restore full length */
buf_setlen(blobbuf, key->keyblob_len);
if (type != DROPBEAR_SIGNKEY_NONE) {
retkey->type = type;
/* limit length of private key blob */
len = buf_getint(blobbuf);
buf_setlen(blobbuf, blobbuf->pos + len);
#if DROPBEAR_ED25519
if (type == DROPBEAR_SIGNKEY_ED25519) {
buf_incrpos(blobbuf, 8);
buf_eatstring(blobbuf);
buf_eatstring(blobbuf);
buf_decrpos(blobbuf, SSH_SIGNKEY_ED25519_LEN+4);
if (buf_get_ed25519_priv_key(blobbuf, retkey->ed25519key)
== DROPBEAR_SUCCESS) {
errmsg = NULL;
retval = retkey;
goto error;
}
}
#endif
}
errmsg = "Unsupported OpenSSH key type";
ossh_error:
sign_key_free(retkey);
retkey = NULL;
goto error;
}
/*
* Now we have a decrypted key blob, which contains an ASN.1
* encoded private key. We must now untangle the ASN.1.
@ -781,7 +867,7 @@ static sign_key *openssh_read(const char *filename, const char * UNUSED(passphra
goto error;
}
m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL);
if (mp_read_unsigned_bin(ecc->k, private_key_bytes, private_key_len)
if (mp_from_ubin(ecc->k, private_key_bytes, private_key_len)
!= MP_OKAY) {
errmsg = "Error parsing ECC key";
goto error;
@ -1056,6 +1142,7 @@ static int openssh_write(const char *filename, sign_key *key,
unsigned long pubkey_size = 2*curve_size+1;
int k_size;
int err = 0;
size_t written;
/* version. less than 10 bytes */
buf_incrwritepos(seq_buf,
@ -1063,12 +1150,14 @@ static int openssh_write(const char *filename, sign_key *key,
buf_putbyte(seq_buf, 1);
/* privateKey */
k_size = mp_unsigned_bin_size((*eck)->k);
k_size = mp_ubin_size((*eck)->k);
dropbear_assert(k_size <= curve_size);
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 4, k_size, 0));
mp_to_unsigned_bin((*eck)->k, buf_getwriteptr(seq_buf, k_size));
buf_incrwritepos(seq_buf, k_size);
if (mp_to_ubin((*eck)->k, buf_getwriteptr(seq_buf, k_size), k_size, &written) != MP_OKAY) {
dropbear_exit("ECC error");
}
buf_incrwritepos(seq_buf, written);
/* SECGCurveNames */
switch (key->type)
@ -1129,6 +1218,51 @@ static int openssh_write(const char *filename, sign_key *key,
}
#endif
#if DROPBEAR_ED25519
if (key->type == DROPBEAR_SIGNKEY_ED25519) {
buffer *buf = buf_new(300);
keyblob = buf_new(100);
extrablob = buf_new(200);
/* private key blob w/o header */
buf_put_priv_key(keyblob, key, key->type);
buf_setpos(keyblob, 0);
buf_incrpos(keyblob, buf_getint(keyblob));
len = buf_getint(keyblob);
/* header */
buf_putbytes(buf, OSSH_PKEY_BLOB, OSSH_PKEY_BLOBLEN);
/* public key */
buf_put_pub_key(buf, key, key->type);
/* private key */
buf_incrwritepos(extrablob, 4);
buf_put_pub_key(extrablob, key, key->type);
buf_putstring(extrablob, buf_getptr(keyblob, len), len);
/* comment */
buf_putstring(extrablob, "", 0);
/* padding to cipher block length */
len = (extrablob->len+8) & ~7;
for (i = 1; len - extrablob->len > 0; i++)
buf_putbyte(extrablob, i);
buf_setpos(extrablob, 0);
buf_putbytes(extrablob, "\0\0\0\0\0\0\0\0", 8);
buf_putbufstring(buf, extrablob);
outlen = len = pos = buf->len;
outblob = (unsigned char*)m_malloc(outlen);
memcpy(outblob, buf->data, buf->len);
buf_burn(buf);
buf_free(buf);
buf = NULL;
header = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
footer = "-----END OPENSSH PRIVATE KEY-----\n";
}
#endif
/*
* Padding on OpenSSH keys is deterministic. The number of
* padding bytes is always more than zero, and always at most

@ -1,3 +1,16 @@
July 1st, 2018
v1.18.2
-- Fix Side Channel Based ECDSA Key Extraction (CVE-2018-12437) (PR #408)
-- Fix potential stack overflow when DER flexi-decoding (CVE-2018-0739) (PR #373)
-- Fix two-key 3DES (PR #390)
-- Fix accelerated CTR mode (PR #359)
-- Fix Fortuna PRNG (PR #363)
-- Fix compilation on platforms where cc doesn't point to gcc (PR #382)
-- Fix using the wrong environment variable LT instead of LIBTOOL (PR #392)
-- Fix build on platforms where the compiler provides __WCHAR_MAX__ but wchar.h is not available (PR #390)
-- Fix & re-factor crypt_list_all_sizes() and crypt_list_all_constants() (PR #414)
-- Minor fixes (PR's #350 #351 #375 #377 #378 #379)
January 22nd, 2018
v1.18.1
-- Fix wrong SHA3 blocksizes, thanks to Claus Fischer for reporting this via Mail (PR #329)

@ -65,9 +65,10 @@ int main(int argc, char **argv)
/* get and print the length of the names (and values) list */
if (crypt_list_all_constants(NULL, &names_list_len) != 0) exit(EXIT_FAILURE);
/* get and print the names (and values) list */
names_list = malloc(names_list_len);
if ((names_list = malloc(names_list_len)) == NULL) exit(EXIT_FAILURE);
if (crypt_list_all_constants(names_list, &names_list_len) != 0) exit(EXIT_FAILURE);
printf("%s\n", names_list);
free(names_list);
}
} else if (argc == 3) {
if (strcmp(argv[1], "-s") == 0) {

@ -42,9 +42,10 @@ int main(int argc, char **argv)
printf(" need to allocate %u bytes \n\n", sizes_list_len);
/* get and print the names (and sizes) list */
sizes_list = malloc(sizes_list_len);
if ((sizes_list = malloc(sizes_list_len)) == NULL) exit(EXIT_FAILURE);
if (crypt_list_all_sizes(sizes_list, &sizes_list_len) != 0) exit(EXIT_FAILURE);
printf(" supported sizes:\n\n%s\n\n", sizes_list);
free(sizes_list);
} else if (argc == 2) {
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
char* base = strdup(basename(argv[0]));
@ -60,9 +61,10 @@ int main(int argc, char **argv)
/* get and print the length of the names (and sizes) list */
if (crypt_list_all_sizes(NULL, &sizes_list_len) != 0) exit(EXIT_FAILURE);
/* get and print the names (and sizes) list */
sizes_list = malloc(sizes_list_len);
if ((sizes_list = malloc(sizes_list_len)) == NULL) exit(EXIT_FAILURE);
if (crypt_list_all_sizes(sizes_list, &sizes_list_len) != 0) exit(EXIT_FAILURE);
printf("%s\n", sizes_list);
free(sizes_list);
}
} else if (argc == 3) {
if (strcmp(argv[1], "-s") == 0) {

@ -466,7 +466,7 @@ static void time_cipher_lrw(void)
tally_results(1);
}
#else
static void time_cipher_lrw(void) { fprintf(stderr, "NO LRW\n"); return 0; }
static void time_cipher_lrw(void) { fprintf(stderr, "NO LRW\n"); }
#endif

@ -78,7 +78,7 @@ void cipher_gen(void)
printf("keysize error: %s\n", error_to_string(err));
exit(EXIT_FAILURE);
}
if (kl == lastkl) break;
if (kl == lastkl) continue;
lastkl = kl;
fprintf(out, "Key Size: %d bytes\n", kl);

@ -38,7 +38,7 @@ PROJECT_NAME = LibTomCrypt
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER=1.18.1
PROJECT_NUMBER=1.18.2
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

@ -3666,11 +3666,15 @@ key, and any hash that produces at least a 256--bit output. However, to make th
it has been fixed to those choices.
Fortuna is more secure than Yarrow in the sense that attackers who learn parts of the entropy being
added to the PRNG learn far less about the state than that of Yarrow. Without getting into to many
added to the PRNG learn far less about the state than that of Yarrow. Without getting into too many
details Fortuna has the ability to recover from state determination attacks where the attacker starts
to learn information from the PRNGs output about the internal state. Yarrow on the other hand, cannot
recover from that problem until new entropy is added to the pool and put to use through the ready() function.
For detailed information on how the algorithm works and what you have to do to maintain the secure state
get a copy of the book\footnote{Niels Ferguson and Bruce Schneier, Practical Cryptography. ISBN 0-471-22357-3.} or
read the paper online\footnote{\url{https://www.schneier.com/academic/paperfiles/fortuna.pdf} [Accessed on 7th Dec. 2017]}.
\subsubsection{RC4}
RC4 is an old stream cipher that can also double duty as a PRNG in a pinch. You key RC4 by

@ -27,7 +27,7 @@ EXTRALIBS = -L../libtommath -ltommath
#Compilation flags
LTC_CFLAGS = -Isrc/headers -Itests -DLTC_SOURCE $(CFLAGS)
LTC_LDFLAGS = $(LDFLAGS) $(EXTRALIBS)
VERSION=1.18.1
VERSION=1.18.2
#Libraries to be created
LIBMAIN_S =libtomcrypt.a

@ -22,7 +22,7 @@ EXTRALIBS = ../libtommath/tommath.lib
#Compilation flags
LTC_CFLAGS = /nologo /Isrc/headers/ /Itests/ /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /DLTC_SOURCE /W3 $(CFLAGS)
LTC_LDFLAGS = advapi32.lib $(EXTRALIBS)
VERSION=1.18.1
VERSION=1.18.2
#Libraries to be created (this makefile builds only static libraries)
LIBMAIN_S =tomcrypt.lib

@ -16,19 +16,19 @@
PLATFORM := $(shell uname | sed -e 's/_.*//')
ifndef LT
ifndef LIBTOOL
ifeq ($(PLATFORM), Darwin)
LT:=glibtool
LIBTOOL:=glibtool
else
LT:=libtool
LIBTOOL:=libtool
endif
endif
ifeq ($(PLATFORM), CYGWIN)
NO_UNDEFINED:=-no-undefined
endif
LTCOMPILE = $(LT) --mode=compile --tag=CC $(CC)
INSTALL_CMD = $(LT) --mode=install install
UNINSTALL_CMD = $(LT) --mode=uninstall rm
LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC)
INSTALL_CMD = $(LIBTOOL) --mode=install install
UNINSTALL_CMD = $(LIBTOOL) --mode=uninstall rm
#Output filenames for various targets.
ifndef LIBNAME
@ -49,15 +49,15 @@ src/ciphers/aes/aes_enc.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c
LOBJECTS = $(OBJECTS:.o=.lo)
$(LIBNAME): $(OBJECTS)
$(LT) --mode=link --tag=CC $(CC) $(LTC_CFLAGS) $(CPPFLAGS) $(LTC_LDFLAGS) $(LOBJECTS) $(EXTRALIBS) -o $@ -rpath $(LIBPATH) -version-info $(VERSION_LT) $(NO_UNDEFINED)
$(LIBTOOL) --mode=link --tag=CC $(CC) $(LTC_LDFLAGS) $(LOBJECTS) $(EXTRALIBS) -o $@ -rpath $(LIBPATH) -version-info $(VERSION_LT) $(NO_UNDEFINED)
test: $(call print-help,test,Builds the library and the 'test' application to run all self-tests) $(LIBNAME) $(TOBJECTS)
$(LT) --mode=link --tag=CC $(CC) $(LTC_CFLAGS) $(CPPFLAGS) $(LTC_LDFLAGS) -o $(TEST) $(TOBJECTS) $(LIBNAME) $(EXTRALIBS)
$(LIBTOOL) --mode=link --tag=CC $(CC) $(LTC_LDFLAGS) -o $(TEST) $(TOBJECTS) $(LIBNAME) $(EXTRALIBS)
# build the demos from a template
define DEMO_template
$(1): $(call print-help,$(1),Builds the library and the '$(1)' demo) demos/$(1).o $$(LIBNAME)
$$(LT) --mode=link --tag=CC $$(CC) $$(LTC_CFLAGS) $$(CPPFLAGS) $$(LTC_LDFLAGS) $$^ $$(EXTRALIBS) -o $(1)
$$(LIBTOOL) --mode=link --tag=CC $$(CC) $$(LTC_LDFLAGS) $$^ $$(EXTRALIBS) -o $(1)
endef
$(foreach demo, $(strip $(DEMOS)), $(eval $(call DEMO_template,$(demo))))

@ -39,7 +39,7 @@ EXTRALIBS = ../libtommath/libtommath.a
#Compilation flags
LTC_CFLAGS = -Isrc/headers -Itests -DLTC_SOURCE $(CFLAGS)
LTC_LDFLAGS = $(LDFLAGS) $(EXTRALIBS)
VERSION=1.18.1
VERSION=1.18.2
#Libraries to be created (this makefile builds only static libraries)
LIBMAIN_S =libtomcrypt.a

@ -3,8 +3,8 @@
# (GNU make only)
# The version - BEWARE: VERSION, VERSION_PC and VERSION_LT are updated via ./updatemakes.sh
VERSION=1.18.1
VERSION_PC=1.18.1
VERSION=1.18.2
VERSION_PC=1.18.2
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
VERSION_LT=1:1
@ -13,9 +13,23 @@ ifndef CROSS_COMPILE
CROSS_COMPILE:=
endif
ifeq ($(CC),cc)
CC := $(CROSS_COMPILE)gcc
# We only need to go through this dance of determining the right compiler if we're using
# cross compilation, otherwise $(CC) is fine as-is.
ifneq (,$(CROSS_COMPILE))
ifeq ($(origin CC),default)
CSTR := "\#ifdef __clang__\nCLANG\n\#endif\n"
ifeq ($(PLATFORM),FreeBSD)
# XXX: FreeBSD needs extra escaping for some reason
CSTR := $$$(CSTR)
endif
ifneq (,$(shell echo $(CSTR) | $(CC) -E - | grep CLANG))
CC := $(CROSS_COMPILE)clang
else
CC := $(CROSS_COMPILE)gcc
endif # Clang
endif # cc is Make's default
endif # CROSS_COMPILE non-empty
LD:=$(CROSS_COMPILE)ld
AR:=$(CROSS_COMPILE)ar
@ -24,7 +38,12 @@ AR:=$(CROSS_COMPILE)ar
ARFLAGS:=r
ifndef MAKE
MAKE:=make
# BSDs refer to GNU Make as gmake
ifneq (,$(findstring $(PLATFORM),FreeBSD OpenBSD DragonFly NetBSD))
MAKE=gmake
else
MAKE=make
endif
endif
ifndef INSTALL_CMD
@ -389,7 +408,7 @@ doc/crypt.pdf: $(call print-help,doc/crypt.pdf,Builds the Developer Manual)
$(MAKE) -C doc/ crypt.pdf V=$(V)
install_all: $(call print-help,install_all,Install everything - library bins docs tests) install install_bins install_docs install_test
install_all: $(call print-help,install_all,Install everything - library bins docs tests) install install_bins install_docs
INSTALL_OPTS ?= -m 644

@ -1434,6 +1434,58 @@ Key Size: 8 bytes
Cipher: 3des
Key Size: 16 bytes
0: DF0B6C9C31CD0CE4
1: 9B3503FDF249920B
2: 653924639C39E7FF
3: 6A29E0A7F42025BB
4: 1628B719BC875D20
5: 7D77004A18D0C0B2
6: 4D21684EFE962DC1
7: B6BD7F82B648A364
8: 1F87ABAD83D19E96
9: 3DF3533220C3CDED
10: D0E7D0ABFBA68747
11: 109FE5B38D74E6C9
12: AE12C4B4D523784F
13: 953CD7F264166764
14: 70B3A87D72FA0A22
15: 9C9D09AC66AB8F6D
16: 4A15AEACB35B76F0
17: EFA32F95623BCF1A
18: 679901F7737E195C
19: 221BB06209DDFCF4
20: 0889A953C60BB1BF
21: 88F2249380E2D5D9
22: 5AB26168B7FA24D5
23: 934229150997D390
24: 535E4F4C4DA97062
25: 03E8D711AC2B8154
26: CB5EF6E72EA3EC49
27: 9278A864F488C94A
28: CB91B77401DAF004
29: 4D0BA1C9794E0099
30: 9CFA24A21F48043F
31: BB6B3A33AEEC01F4
32: F2A8566E0FF6033D
33: E6AC213000E955E6
34: 91F5FF42BBE0B81B
35: 6506D72ADEA70E12
36: F9BD8C0506C7CC4E
37: 89CD85D1C98439ED
38: 409410E3E7D66B10
39: 4CA64F96F4F3D216
40: 383D18FBF8C006BC
41: 3806A8CB006EC243
42: EE73C06D903D2FCF
43: 624BFD3FAD7ED9EB
44: 1B5457F2731FB5D1
45: 4EC4632DFAC9D5D6
46: 8F0B3100FAD612C5
47: F955FCAD55AC6C90
48: BEB5F023BD413960
49: BDC369F3288ED754
Key Size: 24 bytes
0: 58ED248F77F6B19E
1: DA5C39983FD34F30

@ -11,8 +11,8 @@
/* AES implementation by Tom St Denis
*
* Derived from the Public Domain source code by
---
---
* rijndael-alg-fst.c
*
* @version 3.0 (December 2000)
@ -27,13 +27,13 @@
/**
@file aes.c
Implementation of AES
*/
*/
#include "tomcrypt.h"
#ifdef LTC_RIJNDAEL
#ifndef ENCRYPT_ONLY
#ifndef ENCRYPT_ONLY
#define SETUP rijndael_setup
#define ECB_ENC rijndael_ecb_encrypt
@ -126,20 +126,20 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
ulong32 temp, *rk;
#ifndef ENCRYPT_ONLY
ulong32 *rrk;
#endif
#endif
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(skey != NULL);
if (keylen != 16 && keylen != 24 && keylen != 32) {
return CRYPT_INVALID_KEYSIZE;
}
if (num_rounds != 0 && num_rounds != (10 + ((keylen/8)-2)*2)) {
return CRYPT_INVALID_ROUNDS;
}
skey->rijndael.Nr = 10 + ((keylen/8)-2)*2;
/* setup the forward key */
i = 0;
rk = skey->rijndael.eK;
@ -164,7 +164,7 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
LOAD32H(rk[5], key + 20);
for (;;) {
#ifdef _MSC_VER
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 5];
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 5];
#else
temp = rk[5];
#endif
@ -186,7 +186,7 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
LOAD32H(rk[7], key + 28);
for (;;) {
#ifdef _MSC_VER
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 7];
temp = skey->rijndael.eK[rk - skey->rijndael.eK + 7];
#else
temp = rk[7];
#endif
@ -210,11 +210,11 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
return CRYPT_ERROR;
}
#ifndef ENCRYPT_ONLY
#ifndef ENCRYPT_ONLY
/* setup the inverse key now */
rk = skey->rijndael.dK;
rrk = skey->rijndael.eK + (28 + keylen) - 4;
/* apply the inverse MixColumn transform to all round keys but the first and the last: */
/* copy first */
*rk++ = *rrk++;
@ -222,11 +222,11 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
*rk++ = *rrk++;
*rk = *rrk;
rk -= 3; rrk -= 3;
for (i = 1; i < skey->rijndael.Nr; i++) {
rrk -= 4;
rk += 4;
#ifdef LTC_SMALL_CODE
#ifdef LTC_SMALL_CODE
temp = rrk[0];
rk[0] = setup_mix2(temp);
temp = rrk[1];
@ -260,8 +260,8 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
Tks1[byte(temp, 2)] ^
Tks2[byte(temp, 1)] ^
Tks3[byte(temp, 0)];
#endif
#endif
}
/* copy last */
@ -273,7 +273,7 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
*rk = *rrk;
#endif /* ENCRYPT_ONLY */
return CRYPT_OK;
return CRYPT_OK;
}
/**
@ -284,21 +284,21 @@ int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *s
@return CRYPT_OK if successful
*/
#ifdef LTC_CLEAN_STACK
static int _rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
static int _rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
#else
int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
#endif
{
ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk;
int Nr, r;
LTC_ARGCHK(pt != NULL);
LTC_ARGCHK(ct != NULL);
LTC_ARGCHK(skey != NULL);
Nr = skey->rijndael.Nr;
rk = skey->rijndael.eK;
/*
* map byte array block to cipher state
* and add initial round key:
@ -336,7 +336,7 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
Te2(byte(s1, 1)) ^
Te3(byte(s2, 0)) ^
rk[3];
if (r == Nr-2) {
if (r == Nr-2) {
break;
}
s0 = t0; s1 = t1; s2 = t2; s3 = t3;
@ -437,7 +437,7 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
(Te4_3[byte(t3, 3)]) ^
(Te4_2[byte(t0, 2)]) ^
(Te4_1[byte(t1, 1)]) ^
(Te4_0[byte(t2, 0)]) ^
(Te4_0[byte(t2, 0)]) ^
rk[3];
STORE32H(s3, ct+12);
@ -445,7 +445,7 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
}
#ifdef LTC_CLEAN_STACK
int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
{
int err = _rijndael_ecb_encrypt(pt, ct, skey);
burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2);
@ -453,17 +453,17 @@ int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
}
#endif
#ifndef ENCRYPT_ONLY
#ifndef ENCRYPT_ONLY
/**
Decrypts a block of text with AES
@param ct The input ciphertext (16 bytes)
@param pt The output plaintext (16 bytes)
@param skey The key as scheduled
@param skey The key as scheduled
@return CRYPT_OK if successful
*/
#ifdef LTC_CLEAN_STACK
static int _rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
static int _rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
#else
int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
#endif
@ -474,7 +474,7 @@ int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
LTC_ARGCHK(pt != NULL);
LTC_ARGCHK(ct != NULL);
LTC_ARGCHK(skey != NULL);
Nr = skey->rijndael.Nr;
rk = skey->rijndael.dK;
@ -515,13 +515,13 @@ int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
Td3(byte(s0, 0)) ^
rk[3];
if (r == Nr-2) {
break;
break;
}
s0 = t0; s1 = t1; s2 = t2; s3 = t3;
}
rk += 4;
#else
#else
/*
* Nr - 1 full rounds:
@ -625,7 +625,7 @@ int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
#ifdef LTC_CLEAN_STACK
int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
{
int err = _rijndael_ecb_decrypt(ct, pt, skey);
burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2);
@ -641,51 +641,51 @@ int ECB_TEST(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
#else
int err;
static const struct {
int keylen;
unsigned char key[32], pt[16], ct[16];
} tests[] = {
{ 16,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
{ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
{ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }
}, {
}, {
24,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
{ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0,
{ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0,
0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }
}, {
32,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }
}
};
symmetric_key key;
unsigned char tmp[2][16];
int i, y;
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
symmetric_key key;
unsigned char tmp[2][16];
int i, y;
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
zeromem(&key, sizeof(key));
if ((err = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
if ((err = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
return err;
}
rijndael_ecb_encrypt(tests[i].pt, tmp[0], &key);
rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
if (compare_testvector(tmp[0], 16, tests[i].ct, 16, "AES Encrypt", i) ||
@ -693,20 +693,20 @@ int ECB_TEST(void)
return CRYPT_FAIL_TESTVECTOR;
}
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
for (y = 0; y < 16; y++) tmp[0][y] = 0;
for (y = 0; y < 1000; y++) rijndael_ecb_encrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 1000; y++) rijndael_ecb_decrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
}
return CRYPT_OK;
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
for (y = 0; y < 16; y++) tmp[0][y] = 0;
for (y = 0; y < 1000; y++) rijndael_ecb_encrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 1000; y++) rijndael_ecb_decrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
}
return CRYPT_OK;
#endif
}
#endif /* ENCRYPT_ONLY */
/** Terminate the context
/** Terminate the context
@param skey The scheduled key
*/
void ECB_DONE(symmetric_key *skey)

@ -95,7 +95,7 @@ static const ulong32 TE0[256] = {
0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL,
};
#ifndef PELI_TAB
#if !defined(PELI_TAB) && defined(LTC_SMALL_CODE)
static const ulong32 Te4[256] = {
0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL,
0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL,
@ -1018,11 +1018,13 @@ static const ulong32 Tks3[] = {
#endif /* SMALL CODE */
#ifndef PELI_TAB
static const ulong32 rcon[] = {
0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL,
0x1B000000UL, 0x36000000UL, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#endif
#endif /* __LTC_AES_TAB_C__ */

File diff suppressed because it is too large Load Diff

@ -8,9 +8,9 @@
* guarantee it works.
*/
/**
/**
@file twofish.c
Implementation of Twofish by Tom St Denis
Implementation of Twofish by Tom St Denis
*/
#include "tomcrypt.h"
@ -146,14 +146,14 @@ static ulong32 gf_mult(ulong32 a, ulong32 b, ulong32 p)
result = P[0] = B[0] = 0;
/* unrolled branchless GF multiplier */
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1];
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1);
result ^= B[a&1];
return result;
}
@ -244,7 +244,7 @@ static void h_func(const unsigned char *in, unsigned char *out, unsigned char *M
unsigned char y[4];
for (x = 0; x < 4; x++) {
y[x] = in[x];
}
}
switch (k) {
case 4:
y[0] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (6 + offset) + 0]);
@ -440,7 +440,7 @@ int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetri
/* small ram variant */
switch (k) {
case 4 : skey->twofish.start = 0; break;
case 3 : skey->twofish.start = 1; break;
case 3 : skey->twofish.start = 1; break;
default: skey->twofish.start = 2; break;
}
#endif
@ -474,18 +474,18 @@ int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ke
int r;
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
ulong32 *S1, *S2, *S3, *S4;
#endif
#endif
LTC_ARGCHK(pt != NULL);
LTC_ARGCHK(ct != NULL);
LTC_ARGCHK(skey != NULL);
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
S1 = skey->twofish.S[0];
S2 = skey->twofish.S[1];
S3 = skey->twofish.S[2];
S4 = skey->twofish.S[3];
#endif
#endif
LOAD32L(a,&pt[0]); LOAD32L(b,&pt[4]);
LOAD32L(c,&pt[8]); LOAD32L(d,&pt[12]);
@ -493,20 +493,20 @@ int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ke
b ^= skey->twofish.K[1];
c ^= skey->twofish.K[2];
d ^= skey->twofish.K[3];
k = skey->twofish.K + 8;
for (r = 8; r != 0; --r) {
t2 = g1_func(b, skey);
t1 = g_func(a, skey) + t2;
c = RORc(c ^ (t1 + k[0]), 1);
d = ROLc(d, 1) ^ (t2 + t1 + k[1]);
t2 = g1_func(d, skey);
t1 = g_func(c, skey) + t2;
a = RORc(a ^ (t1 + k[2]), 1);
b = ROLc(b, 1) ^ (t2 + t1 + k[3]);
k += 4;
}
}
/* output with "undo last swap" */
ta = c ^ skey->twofish.K[4];
@ -534,7 +534,7 @@ int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ke
Decrypts a block of text with Twofish
@param ct The input ciphertext (16 bytes)
@param pt The output plaintext (16 bytes)
@param skey The key as scheduled
@param skey The key as scheduled
@return CRYPT_OK if successful
*/
#ifdef LTC_CLEAN_STACK
@ -547,18 +547,18 @@ int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ke
int r;
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
ulong32 *S1, *S2, *S3, *S4;
#endif
#endif
LTC_ARGCHK(pt != NULL);
LTC_ARGCHK(ct != NULL);
LTC_ARGCHK(skey != NULL);
#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
S1 = skey->twofish.S[0];
S2 = skey->twofish.S[1];
S3 = skey->twofish.S[2];
S4 = skey->twofish.S[3];
#endif
#endif
/* load input */
LOAD32L(ta,&ct[0]); LOAD32L(tb,&ct[4]);
@ -589,7 +589,7 @@ int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ke
b ^= skey->twofish.K[1];
c ^= skey->twofish.K[2];
d ^= skey->twofish.K[3];
/* store */
STORE32L(a, &pt[0]); STORE32L(b, &pt[4]);
STORE32L(c, &pt[8]); STORE32L(d, &pt[12]);
@ -613,8 +613,8 @@ int twofish_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
static const struct {
#else
static const struct {
int keylen;
unsigned char key[32], pt[16], ct[16];
} tests[] = {
@ -634,7 +634,7 @@ int twofish_test(void)
0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 },
{ 0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45,
0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 }
}, {
}, {
32,
{ 0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46,
0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
@ -648,11 +648,11 @@ int twofish_test(void)
};
symmetric_key key;
unsigned char tmp[2][16];
int err, i, y;
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
symmetric_key key;
unsigned char tmp[2][16];
int err, i, y;
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
if ((err = twofish_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
return err;
}
@ -662,17 +662,17 @@ int twofish_test(void)
compare_testvector(tmp[1], 16, tests[i].pt, 16, "Twofish Decrypt", i) != 0) {
return CRYPT_FAIL_TESTVECTOR;
}
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
for (y = 0; y < 16; y++) tmp[0][y] = 0;
for (y = 0; y < 1000; y++) twofish_ecb_encrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 1000; y++) twofish_ecb_decrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
}
return CRYPT_OK;
#endif
/* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
for (y = 0; y < 16; y++) tmp[0][y] = 0;
for (y = 0; y < 1000; y++) twofish_ecb_encrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 1000; y++) twofish_ecb_decrypt(tmp[0], tmp[0], &key);
for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
}
return CRYPT_OK;
#endif
}
/** Terminate the context
/** Terminate the context
@param skey The scheduled key
*/
void twofish_done(symmetric_key *skey)

@ -53,7 +53,7 @@ int ccm_memory(int cipher,
int err;
unsigned long len, L, x, y, z, CTRlen;
#ifdef LTC_FAST
LTC_FAST_TYPE fastMask = ~0; /* initialize fastMask at all zeroes */
LTC_FAST_TYPE fastMask = ~(LTC_FAST_TYPE)0; /* initialize fastMask at all zeroes */
#endif
unsigned char mask = 0xff; /* initialize mask at all zeroes */

@ -10,7 +10,7 @@
#include "tomcrypt.h"
#ifndef LTC_NO_FILE
/**
/**
@file hash_file.c
Hash a file, Tom St Denis
*/
@ -35,7 +35,7 @@ int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *ou
}
in = fopen(fname, "rb");
if (in == NULL) {
if (in == NULL) {
return CRYPT_FILE_NOTFOUND;
}

@ -15,13 +15,13 @@
Hash open files, Tom St Denis
*/
/**
Hash data from an open file handle.
/**
Hash data from an open file handle.
@param hash The index of the hash you want to use
@param in The FILE* handle of the file you want to hash
@param out [out] The destination of the digest
@param outlen [in/out] The max size and resulting size of the digest
@result CRYPT_OK if successful
@result CRYPT_OK if successful
*/
int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
{
@ -58,8 +58,8 @@ int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outle
}
} while (x == LTC_FILE_READ_BUFSIZE);
if ((err = hash_descriptor[hash].done(&md, out)) == CRYPT_OK) {
*outlen = hash_descriptor[hash].hashsize;
}
*outlen = hash_descriptor[hash].hashsize;
}
LBL_CLEANBUF:
zeromem(buf, LTC_FILE_READ_BUFSIZE);

@ -27,14 +27,15 @@ extern "C" {
/* version */
#define CRYPT 0x0118
#define SCRYPT "1.18.1"
#define SCRYPT "1.18.2"
/* max size of either a cipher/hash block or symmetric key [largest of the two] */
#define MAXBLOCKSIZE 128
#ifndef TAB_SIZE
/* descriptor table size */
/* Dropbear change - this should be smaller, saves some size */
#define TAB_SIZE 5
#define TAB_SIZE 32
#endif
/* error codes [will be expanded in future releases] */
enum {

@ -45,7 +45,7 @@ void crypt_argchk(const char *v, const char *s, int d) NORETURN;
#elif ARGTYPE == 3
#define LTC_ARGCHK(x)
#define LTC_ARGCHK(x)
#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
#elif ARGTYPE == 4

@ -74,8 +74,8 @@
#define LTC_NO_MODES
#define LTC_NO_HASHES
#define LTC_NO_MACS
#define LTC_NO_PRNGS
#define LTC_NO_PK
#define LTC_NO_PRNGS
#define LTC_NO_PK
#define LTC_NO_PKCS
#define LTC_NO_MISC
#endif /* LTC_NOTHING */
@ -480,6 +480,13 @@
#endif
#endif
#if defined(LTC_DER)
#ifndef LTC_DER_MAX_RECURSION
/* Maximum recursion limit when processing nested ASN.1 types. */
#define LTC_DER_MAX_RECURSION 30
#endif
#endif
#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(LTC_MKAT)
/* Include the MPI functionality? (required by the PK algorithms) */
#define LTC_MPI

@ -10,9 +10,9 @@
#define LTC_SMALL_CODE
#endif
#if DROPBEAR_BLOWFISH
#define LTC_BLOWFISH
#endif
/* Fewer entries needed */
#define TAB_SIZE 5
#if DROPBEAR_AES
#define LTC_RIJNDAEL
#endif
@ -27,7 +27,7 @@
#define LTC_DES
#endif
#if DROPBEAR_ENABLE_CTR_MODE
#if DROPBEAR_ENABLE_CBC_MODE
#define LTC_CBC_MODE
#endif
@ -35,6 +35,14 @@
#define LTC_CTR_MODE
#endif
#if DROPBEAR_ENABLE_GCM_MODE
#define LTC_GCM_MODE
#endif
#if DROPBEAR_CHACHA20POLY1305
#define LTC_CHACHA
#define LTC_POLY1305
#endif
#if DROPBEAR_SHA512
#define LTC_SHA512

@ -667,16 +667,16 @@ int der_printable_value_decode(int v);
/* UTF-8 */
#if (defined(SIZE_MAX) || __STDC_VERSION__ >= 199901L || defined(WCHAR_MAX) || defined(__WCHAR_MAX__) || defined(_WCHAR_T) || defined(_WCHAR_T_DEFINED) || defined (__WCHAR_TYPE__)) && !defined(LTC_NO_WCHAR)
#include <wchar.h>
#if defined(__WCHAR_MAX__)
#define LTC_WCHAR_MAX __WCHAR_MAX__
#elif defined(WCHAR_MAX)
#define LTC_WCHAR_MAX WCHAR_MAX
#endif
#if defined(__WCHAR_MAX__)
#define LTC_WCHAR_MAX __WCHAR_MAX__
#else
#include <wchar.h>
#define LTC_WCHAR_MAX WCHAR_MAX
#endif
/* please note that it might happen that LTC_WCHAR_MAX is undefined */
#else
typedef ulong32 wchar_t;
#define LTC_WCHAR_MAX 0xFFFFFFFF
typedef ulong32 wchar_t;
#define LTC_WCHAR_MAX 0xFFFFFFFF
#endif
int der_encode_utf8_string(const wchar_t *in, unsigned long inlen,

@ -23,6 +23,11 @@
int blake2bmac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
{
#ifdef LTC_NO_FILE
LTC_UNUSED_PARAM(fname);
LTC_UNUSED_PARAM(key);
LTC_UNUSED_PARAM(keylen);
LTC_UNUSED_PARAM(mac);
LTC_UNUSED_PARAM(maclen);
return CRYPT_NOP;
#else
blake2bmac_state st;

@ -23,6 +23,11 @@
int blake2smac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
{
#ifdef LTC_NO_FILE
LTC_UNUSED_PARAM(fname);
LTC_UNUSED_PARAM(key);
LTC_UNUSED_PARAM(keylen);
LTC_UNUSED_PARAM(mac);
LTC_UNUSED_PARAM(maclen);
return CRYPT_NOP;
#else
blake2smac_state st;

@ -32,6 +32,12 @@ int f9_file(int cipher,
unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
LTC_UNUSED_PARAM(cipher);
LTC_UNUSED_PARAM(key);
LTC_UNUSED_PARAM(keylen);
LTC_UNUSED_PARAM(fname);
LTC_UNUSED_PARAM(out);
LTC_UNUSED_PARAM(outlen);
return CRYPT_NOP;
#else
size_t x;

@ -31,7 +31,12 @@ int hmac_file(int hash, const char *fname,
unsigned char *out, unsigned long *outlen)
{
#ifdef LTC_NO_FILE
(void)hash; (void)fname; (void)key; (void)keylen; (void)out; (void)outlen;
LTC_UNUSED_PARAM(hash);
LTC_UNUSED_PARAM(fname);
LTC_UNUSED_PARAM(key);
LTC_UNUSED_PARAM(keylen);
LTC_UNUSED_PARAM(out);
LTC_UNUSED_PARAM(outlen);
return CRYPT_NOP;
#else
hmac_state hmac;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save