Compare commits

..

51 Commits

Author SHA1 Message Date
Matt Johnston
0ea2e3463d try fix coverity build
--HG--
branch : coverity
2020-06-26 21:20:57 +08:00
Matt Johnston
ddb6751ab4 merge coverity from main
--HG--
branch : coverity
2020-06-26 21:07:34 +08:00
Matt Johnston
6e3c3c8c51 try for coverity
--HG--
branch : coverity
2019-03-21 23:28:59 +08:00
Matt Johnston
ef080502f8 merge coverity
--HG--
branch : coverity
2019-03-21 00:14:38 +08:00
Matt Johnston
fdbdbe5703 merge coverity
--HG--
branch : coverity
2018-03-21 00:52:02 +08:00
Matt Johnston
921592d37e merge coverity
--HG--
branch : coverity
2018-03-04 15:07:09 +08:00
Matt Johnston
04a02730bc merge coverity
--HG--
branch : coverity
2018-02-26 22:43:12 +08:00
Matt Johnston
dcce2cfd8d merge coverity
--HG--
branch : coverity
2018-02-19 23:14:49 +08:00
Matt Johnston
00a1290173 merge coverity up to date
--HG--
branch : coverity
2018-02-17 11:29:17 +08:00
Matt Johnston
a3a0b26581 limit travis branches
--HG--
branch : coverity
2018-02-10 19:06:13 +08:00
Matt Johnston
276197b404 merge
--HG--
branch : coverity
2018-02-10 19:03:54 +08:00
Matt Johnston
484d1e9b81 merge
--HG--
branch : coverity
2018-02-10 08:27:30 +08:00
Matt Johnston
278a3e43e5 merge
--HG--
branch : coverity
2018-02-09 23:58:47 +08:00
Matt Johnston
2df2117388 update coverity
--HG--
branch : coverity
2018-02-09 23:49:22 +08:00
Matt Johnston
187fc95deb merge
--HG--
branch : coverity
2017-06-24 23:33:16 +08:00
Matt Johnston
b75a033787 merge
--HG--
branch : coverity
2017-06-03 00:10:58 +08:00
Matt Johnston
423be0d5e6 merge coverity
--HG--
branch : coverity
2017-05-18 23:02:39 +08:00
Matt Johnston
68b3ef0734 merge coverity
--HG--
branch : coverity
2016-07-22 00:08:02 +08:00
Matt Johnston
d58e0497cc merge
--HG--
branch : coverity
2016-03-18 22:47:33 +08:00
Matt Johnston
af10eb8346 merge
--HG--
branch : coverity
2016-03-15 23:20:40 +08:00
Matt Johnston
8e93ac9925 merge up to date
--HG--
branch : coverity
2016-03-15 22:45:43 +08:00
Matt Johnston
6d5b27715a merge
--HG--
branch : coverity
2015-12-15 22:24:34 +08:00
Matt Johnston
f295fbe0b2 merge
--HG--
branch : coverity
2015-12-02 22:37:51 +08:00
Matt Johnston
575f0e5f92 merge
--HG--
branch : coverity
2015-11-23 23:04:48 +08:00
Matt Johnston
85374c5ba2 merge
--HG--
branch : coverity
2015-08-07 21:26:03 +08:00
Matt Johnston
83f3f55280 merge
--HG--
branch : coverity
2015-06-23 21:49:04 +08:00
Matt Johnston
b2beb2c2da coverity shouldn't have a matrix
--HG--
branch : coverity
2015-06-13 23:39:55 +08:00
Matt Johnston
48ad370a19 fix travis coverity matrix?
--HG--
branch : coverity
2015-06-13 23:36:03 +08:00
Matt Johnston
c36f94a322 fiddle with coverity travis
--HG--
branch : coverity
2015-06-13 23:32:15 +08:00
Matt Johnston
6493bbb7e7 merge up to date, attempt to fix travis.yml
--HG--
branch : coverity
2015-06-12 23:02:15 +08:00
Matt Johnston
3ec2737d54 merge main
--HG--
branch : coverity
2015-04-14 20:44:30 +08:00
Matt Johnston
72ccfda5b2 merge
--HG--
branch : coverity
2015-03-02 21:17:41 +08:00
Matt Johnston
003ec5d356 merge
--HG--
branch : coverity
2015-02-28 23:25:16 +08:00
Matt Johnston
f91d66448a merge
--HG--
branch : coverity
2015-02-24 22:48:34 +08:00
Matt Johnston
ccfdf7e039 merge
--HG--
branch : coverity
2015-02-10 21:47:43 +08:00
Matt Johnston
95ce05da40 merge
--HG--
branch : coverity
2015-01-28 22:49:55 +08:00
Matt Johnston
c5d53cf81c merge
--HG--
branch : coverity
2015-01-28 21:40:34 +08:00
Matt Johnston
5574460d25 merge
--HG--
branch : coverity
2015-01-04 22:33:12 +08:00
Matt Johnston
233fd96994 merge to coverity
--HG--
branch : coverity
2014-10-21 22:34:20 +08:00
Matt Johnston
d1b29336b1 merge
--HG--
branch : coverity
2014-08-19 23:36:46 +08:00
Matt Johnston
fa5eb62464 merge
--HG--
branch : coverity
2014-08-08 21:26:07 +08:00
Matt Johnston
0b48a4f879 merge
--HG--
branch : coverity
2014-07-28 23:38:54 +08:00
Matt Johnston
00ef081fcf merge
--HG--
branch : coverity
2014-07-28 22:56:07 +08:00
Matt Johnston
dabeaec461 merge
--HG--
branch : coverity
2014-07-26 10:23:53 +08:00
Matt Johnston
d4ed2fffe4 merge
--HG--
branch : coverity
2014-07-25 22:23:50 +08:00
Matt Johnston
0533b87b1a merge
--HG--
branch : coverity
2014-03-08 21:02:02 +08:00
Matt Johnston
7504cd1a1a Don't 'make install' for coverity
--HG--
branch : coverity
2014-03-08 21:00:32 +08:00
Matt Johnston
482dc0eff4 Fix the right build line
--HG--
branch : coverity
2014-03-08 18:16:11 +08:00
Matt Johnston
fc34d02427 Fix quoting for coverity
--HG--
branch : coverity
2014-03-08 18:09:00 +08:00
Matt Johnston
5ce5fbcba0 More for coverity
--HG--
branch : coverity
2014-03-08 16:56:15 +08:00
Matt Johnston
31d2311537 Add coverity bits
--HG--
branch : coverity
2014-03-08 14:56:27 +08:00
124 changed files with 3402 additions and 14437 deletions

View File

@@ -1,9 +0,0 @@
#!/bin/sh
# symlink this to dropbear/dbclient/dropbearkey next to dropbearmulti
# good enough for testing purposes.
DIR=$(dirname $0)
PROG=$(basename $0)
exec $DIR/dropbearmulti $PROG "$@"

View File

@@ -1,25 +0,0 @@
# Checks that autoconf has been run if configure.ac was updated
# Assumes that autoconf 2.69 was run, the same as ubuntu 20.04
name: Autoconf Up To Date
on:
pull_request:
push:
branches:
- master
jobs:
autoconf:
runs-on: 'ubuntu-20.04'
steps:
- name: deps
run: |
sudo apt-get -y update
sudo apt-get -y install autoconf
- uses: actions/checkout@v2
- name: run autoconf
run: autoconf && autoheader
- name: check no difference
run: git diff --exit-code

View File

@@ -1,199 +0,0 @@
# Can be used locally with https://github.com/nektos/act
# Note the XXX line below.
name: BuildTest
on:
pull_request:
push:
branches:
- master
jobs:
build:
runs-on: ${{ matrix.os || 'ubuntu-20.04' }}
strategy:
matrix:
# XXX uncomment the line below to work with act, see https://github.com/nektos/act/issues/996
# name: []
# Rather than a boolean False we use eg
# runcheck: 'no'
# Otherwise GH expressions will make a None var
# compare with False. We want an undefined default of True.
# MULTI and NOWRITEV are passed as integers to the build
include:
- name: plain linux
- name: multi binary
multi: 1
multilink: 1
- name: multi binary, dropbearmulti argv0
multi: 1
multiwrapper: 1
- name: bundled libtom, bionic , no writev()
# test can use an older distro with bundled libtommath
os: ubuntu-18.04
configure_flags: --enable-bundled-libtom --enable-werror
# NOWRITEV is unrelated, test here to save a job
nowritev: 1
# our tests expect >= python3.7
runcheck: 'no'
- name: linux clang
cc: clang
# Some platforms only have old compilers, we try to keep
# compatibilty. For some reason -std=c89 doesn't enforce
# early declarations so we specify it anyway.
- name: c89
extracflags: -std=c89 -Wdeclaration-after-statement
- name: macos 10.15
os: macos-10.15
cc: clang
# OS X says daemon() and utmp are deprecated
extracflags: -Wno-deprecated-declarations
runcheck: 'no'
apt: 'no'
# fails with:
# .../ranlib: file: libtomcrypt.a(cbc_setiv.o) has no symbols
ranlib: ranlib -no_warning_for_no_symbols
- name: macos 11
os: macos-11
cc: clang
extracflags: -Wno-deprecated-declarations
runcheck: 'no'
apt: 'no'
ranlib: ranlib -no_warning_for_no_symbols
# Check that debug code doesn't bitrot
- name: DEBUG_TRACE
localoptions: |
#define DEBUG_TRACE 5
# # Fuzzers run standalone. A bit superfluous with cifuzz, but
# # good to run the whole corpus to keep it working.
# - name: fuzzing with address sanitizer
# configure_flags: --enable-fuzz --disable-harden --enable-bundled-libtom --enable-werror
# ldflags: -fsanitize=address
# extracflags: -fsanitize=address
# # -fsanitize=address prevents aslr, don't test it
# pytest_addopts: -k "not aslr"
# fuzz: True
# cc: clang
# # Undefined Behaviour sanitizer
# - name: fuzzing with undefined behaviour sanitizer
# configure_flags: --enable-fuzz --disable-harden --enable-bundled-libtom --enable-werror
# ldflags: -fsanitize=undefined
# # don't fail with alignment due to https://github.com/libtom/libtomcrypt/issues/549
# extracflags: -fsanitize=undefined -fno-sanitize-recover=undefined -fsanitize-recover=alignment
# pytest_addopts: -k "not aslr"
# fuzz: True
# cc: clang
env:
MULTI: ${{ matrix.multi }}
CC: ${{ matrix.cc || 'gcc' }}
LDFLAGS: ${{ matrix.ldflags }}
EXTRACFLAGS: ${{ matrix.extracflags }}
CONFIGURE_FLAGS: ${{ matrix.configure_flags || '--enable-werror' }}
# for fuzzing
CXX: clang++
RANLIB: ${{ matrix.ranlib || 'ranlib' }}
# pytest in "make check" recognises this for extra arguments
PYTEST_ADDOPTS: ${{ matrix.pytest_addopts }}
# some pytests depend on special setup from this file. see authorized_keys below.
DBTEST_IN_ACTION: true
LOCALOPTIONS: ${{ matrix.localoptions }}
steps:
- name: deps
if: ${{ matrix.apt != 'no' }}
run: |
sudo apt-get -y update
sudo apt-get -y install zlib1g-dev libtomcrypt-dev libtommath-dev mercurial python3-venv $CC
- uses: actions/checkout@v2
- name: configure
run: ./configure $CONFIGURE_FLAGS CFLAGS="-O2 -Wall -Wno-pointer-sign $EXTRACFLAGS" --prefix="$HOME/inst" || (cat config.log; exit 1)
- name: nowritev
if: ${{ matrix.nowritev }}
run: sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h
- name: localoptions
run: |
echo "$LOCALOPTIONS" > localoptions.h
cat localoptions.h
- name: make
run: make -j3
- name: multilink
if: ${{ matrix.multilink }}
run: make multilink
- name: multi wrapper script
if: ${{ matrix.multiwrapper }}
run: |
cp .github/multiwrapper dropbear
cp .github/multiwrapper dbclient
cp .github/multiwrapper dropbearkey
cp .github/multiwrapper dropbearconvert
- name: makefuzz
run: make fuzzstandalone
if: ${{ matrix.fuzz }}
# avoid concurrent install, osx/freebsd is racey (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=208093)
- name: make install
run: make install
- name: keys
run: |
mkdir -p ~/.ssh
# remove old files so we can rerun in-place with "act -r" during test development
rm -vf ~/.ssh/id_dropbear*
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear | grep ^ecdsa > ~/.ssh/authorized_keys
# to test setting SSH_PUBKEYINFO, replace the trailing comment
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear_key2 | grep ^ecdsa | sed 's/[^ ]*$/key2 extra/' >> ~/.ssh/authorized_keys
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear_key3 | grep ^ecdsa | sed 's/[^ ]*$/key3%char/' >> ~/.ssh/authorized_keys
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear_key4 | grep ^ecdsa | sed 's/[^ ]*$/key4,char/' >> ~/.ssh/authorized_keys
chmod 700 ~ ~/.ssh ~/.ssh/authorized_keys
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys
# upload config.log if something has failed
- name: config.log
if: ${{ !env.ACT && (failure() || cancelled()) }}
uses: actions/upload-artifact@v2
with:
name: config.log
path: config.log
- name: check
if: ${{ matrix.runcheck != 'no' }}
run: make check
# Sanity check that the binary runs
- name: genrsa
run: ~/inst/bin/dropbearkey -t rsa -f testrsa
- name: gendss
run: ~/inst/bin/dropbearkey -t dss -f testdss
- name: genecdsa256
run: ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
- name: genecdsa384
run: ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
- name: genecdsa521
run: ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
- name: gened25519
run: ~/inst/bin/dropbearkey -t ed25519 -f tested25519
- name: fuzz
if: ${{ matrix.fuzz }}
run: ./fuzzers_test.sh

View File

@@ -1,30 +0,0 @@
# Runs fuzzers for a little while on pull requests.
# From https://google.github.io/oss-fuzz/getting-started/continuous-integration/
name: CIFuzz
on:
pull_request:
push:
branches:
- master
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'dropbear'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'dropbear'
fuzz-seconds: 1200
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

View File

@@ -1,36 +0,0 @@
name: tarball sha256sum
on:
push:
branches:
- master
jobs:
tarball:
runs-on: 'ubuntu-20.04'
steps:
- uses: actions/checkout@v2
- name: release.sh
run: ./release.sh --testrel | tee log1.txt
- name: extract output
run: |
grep ^SHA256 log1.txt > sha256sum.txt
sed 's/.*= *//' < sha256sum.txt > hash.txt
mv `tail -n1 log1.txt` rel.tar.bz2
- name: sha256sum
uses: actions/upload-artifact@v3
with:
name: sha256sum
path: |
sha256sum.txt
hash.txt
- name: tarball
uses: actions/upload-artifact@v3
with:
name: tarball
# only keep for debugging
retention-days: 3
path: rel.tar.bz2

10
.gitignore vendored
View File

@@ -19,11 +19,9 @@
/fuzzer-*.options
/scp
/scp-progress
config.h
default_options_guard.h
localoptions.h
Makefile
config.h
config.h.in
configure
default_options_guard.h
tags
.pytest*
*.pyc
/test/venv

View File

@@ -1,6 +1,2 @@
\..*\.swp
.*\.o
.*~
tags
.pytest*
.*\.pyc
test/venv

View File

@@ -27,5 +27,3 @@ fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzu
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=
5879c5829e8569466386e7c64252b01b99705628 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAl+axlIACgkQRJMUlPKcZ3PZuhAAkzCj+lOt2hHigIHB0zkNUC9nRIE1TItJD4wqQ03nMY4ycBMsb74o1AHsQTtVG6sm2YGSmQuZ0VxG1iuW9nKTsM1hzB40G45i5waIEzxVG8PbZ2i6zLK2Xz2YQ+FBvIg1EKfH7Dyd3r4FqYxauGOQdrUiKwuc3H4r65HpUmT0tIypqahFoRmj1+K/ZSPak0+ZPL27VQ4b/Ts8QS7XwFYTZsMDovYNdFJmaMhBbBe33/zGFWBPk6NCJWrBd3jmJN/LhZp0a5T4fAZ6iA2WjXDWOSiWZaLLk49zM6WYrc4QihEj7ngecj/UUXKR/sWPva8+rHf9YQLZu2lc6IMABCpUkeKLFoJqzvnKGA2rhl1LpRcnNA30/7yJt0YhfFcKhBkjjSxiOH3v0qMPADHMo5poqCKH/x4TVGVyVgzCqcxd+AzsDu77fzfzbxlyQ7wp+VmwXmeHbPfuBc8u9HUBa6Fc4b667aDD26a2S9VKdRYuSp3DkOwCLJUmRqmw+sXKvXlPyxPMUxOi/4R5nbJacD5Js1AH7WH49pAFMJ6bDCQ8QEmOh+Qpqc3RzTBwt1CLl+zt0NLKDmRYSgAY9GZpuju7r+aj2Semjd7nwmq4Y5xtWCh673lea/n7JS0mtBWouVbGgMJErg7QjuqOS3oE77viLcGLpX9niDcGvCL/N3gE13A=

View File

@@ -59,5 +59,3 @@ c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77
009d52ae26d35f3381c801e02318fa9be34be93c DROPBEAR_2019.78
e2e4929d057b09422f2ea4556fb64209aff58161 DROPBEAR_2020.79
73646de50f1351735c868d4874f058ff9ad62c96 DROPBEAR_2020.80
4b984c42372d01fcc2fd487c58af6a5aa65eb88e DROPBEAR_2020.81

36
.travis.yml Normal file
View File

@@ -0,0 +1,36 @@
language: c
git:
depth: 3
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: "F4rKQrHK/u58vPo3F9+x0WYXAeMFJvvtH9BIGZqx9yw8bUnL+gk0Ge9wnHHTXRcgCTqoc7B35uMS5njpH+Su/esVjrLAq85f/AmQctlRpmApwGK9LyxkIvx3UJN0nqfeeDXA90/8FUZ+n/qnCydXmYCEgqSaBCNydDxW1oqYUIc="
- BUNDLEDLIBTOM=--enable-bundled-libtom
- MULTI=1
before_install:
- echo -n | openssl s_client -connect https://scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
addons:
apt:
packages:
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- zlib1g-dev
- libtomcrypt-dev
- libtommath-dev
coverity_scan:
project:
name: "mkj/dropbear"
description: "Dropbear SSH"
notification_email: matt@ucc.asn.au
build_command_prepend: autoconf && autoheader && ./configure --enable-bundled-libtom CFLAGS='-O2 -Wall -Wno-pointer-sign' --prefix=$HOME/inst
build_command: make MULTI=1
branch_pattern: coverity
branches:
only:
- master
- coverity

173
CHANGES
View File

@@ -1,154 +1,3 @@
2022.82 - 1 April 2022
Features and Changes:
Note >> for compatibility/configuration changes
- Implemented OpenSSH format private key handling for dropbearconvert.
Keys can be read in OpenSSH format or the old PEM format.
>> Keys are now written in OpenSSH format rather than PEM.
ED25519 support is now correct. DSS keys are still PEM format.
- Use SHA256 for key fingerprints
- >> Reworked -v verbose printing, specifying multiple times will increase
verbosity. -vvvv is equivalent to the old DEBUG_TRACE -v level, it
can be configured at compile time in localoptions.h (see default_options.h)
Lower -v options can be used to check connection progress or algorithm
negotiation.
Thanks to Hans Harder for the implementation
localoptions.h DEBUG_TRACE should be set to 4 for the same result as the
previous DEBUG_TRACE 1.
- Added server support for U2F/FIDO keys (ecdsa-sk and ed25519-sk) in
authorized_keys. no-touch-required option isn't allowed yet.
Thanks to Egor Duda for the implementation
- autoconf output (configure script etc) is now committed to version control.
>> It isn't necessary to run "autoconf" any more on a checkout.
- sha1 will be omitted from the build if KEX/signing/MAC algorithms don't
require it. Instead sha256 is used for random number generation.
See sysoptions.h to see which algorithms require which hashes.
- Set SSH_PUBKEYINFO environment variable based on the authorized_keys
entry used for auth. The first word of the comment after the key is used
(must only have characters a-z A-Z 0-9 .,_-+@)
Patch from Hans Harder, modified by Matt Johnston
- Let dbclient multihop mode be used with '-J'.
Patch from Hans Harder
- Allow home-directory relative paths ~/path for various settings
and command line options.
*_PRIV_FILENAME DROPBEAR_PIDFILE SFTPSERVER_PATH MOTD_FILENAME
Thanks to Begley Brothers Inc
>> The default DROPBEAR_DEFAULT_CLI_AUTHKEY has now changed, it now needs
a tilde prefix.
- LANG environment variable is carried over from the Dropbear server process
From Maxim Kochetkov
- Add /usr/sbin and /sbin to $PATH when logging in as root.
Patch from Raphaël Hertzog
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=903403
- Added client option "-o DisableTrivialAuth". This can be used to prevent
the server immediately accepting successful authentication (before any auth
request) which could cause UI confusion and security issues with agent
forwarding - it isn't clear which host is prompting to use a key.
Thanks to Manfred Kaiser from Austrian MilCERT
- Add -q client option to hide remote banner, from Hans Harder
- Add -e option to pass all server environment variables to child processes.
This should be used with caution.
Patch from Roland Vollgraf (github #118)
- >> Use DSCP for QoS traffic classes. Priority (tty) traffic is now set to
AF21 "interactive". Previously TOS classes were used, they are not used by
modern traffic classifiers. Non-tty traffic is left at default priority.
- >> Disable dh-group1 key exchange by default. It has been disabled server
side by default since 2018.
- >> Removed Twofish cipher
Fixes:
- Fix flushing channel data when pty was allocated (github #85)
Data wasn't completely transmitted at channel close.
Reported and initial patch thanks to Yousong Zhou
- Dropbear now re-executes itself rather than just forking for each connection
(only on Linux). This allows ASLR to randomise address space for each
connection as a security mitigation. It should not have any visible impact
- if there are any performance impacts in the wild please report it.
- Check authorized_keys permissions as the user, fixes NFS squash root.
Patch from Chris Dragan (github #107)
- A missing home directory is now non-fatal, starting in / instead
- Fixed IPv6 [address]:port parsing for dbclient -b
Reported by Fabio Molinari
- Improve error logging so that they are logged on the server rather than being
sent to the client over the connection
- Max window size is increased to 10MB, more graceful fallback if it's invalid.
- Fix correctness of Dropbear's handling of global requests.
Patch from Dirkjan Bussink
- Fix some small bugs found by fuzzers, null pointer dereference crash and leaks
(post authentication)
- $HOME variable is used before /etc/passwd when expanding paths such as
~/.ssh/id_dropbear (for the client). Patch from Matt Robinson
- C89 build fixes from Guillaume Picquet
Infrastructure:
- Improvements to fuzzers. Added post-auth fuzzer, and a mutator that can
handle the structure of SSH packet streams. Added cifuzz to run on commits
and pull requests.
Thanks to OSS-Fuzz for the tools/clusters and reward funding.
- Dropbear source tarballs generated by release.sh are now reproducible from a
Git or Mercurial checkout, they will be identical on any system. Tested
on ubuntu and macos.
- Added some integration testing using pytest. Currently this has tests
for various channel handling edge cases, ASLR fork randomisation,
dropbearconvert, and SSH_PUBKEYINFO
- Set up github actions. This runs the pytest suite and other checks.
- build matrix includes c89, dropbearmulti, bundled libtom, macos, DEBUG_TRACE
- test for configure script regeneration
- build a tarball for external reproducibility
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
@@ -366,7 +215,7 @@ Infrastructure:
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://hg.ucc.asn.au/dropbear/rev/c8114a48837c
CVE-2017-9078 https://secure.ucc.asn.au/hg/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
@@ -378,7 +227,7 @@ Infrastructure:
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://hg.ucc.asn.au/dropbear/rev/0d889b068123
CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123
- Generate hostkeys with dropbearkey atomically and flush to disk with fsync
Thanks to Andrei Gherzan for a patch
@@ -398,23 +247,23 @@ Infrastructure:
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://hg.ucc.asn.au/dropbear/rev/b66a483f3dcb
https://secure.ucc.asn.au/hg/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://hg.ucc.asn.au/dropbear/rev/34e6127ef02e
https://secure.ucc.asn.au/hg/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://hg.ucc.asn.au/dropbear/rev/eed9376a4ad6
https://secure.ucc.asn.au/hg/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://hg.ucc.asn.au/dropbear/rev/6a14b1f6dc04
https://secure.ucc.asn.au/hg/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
@@ -460,7 +309,7 @@ Infrastructure:
- 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://hg.ucc.asn.au/dropbear/rev/a3e8389e01ff
https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff
2015.71 - 3 December 2015
@@ -741,11 +590,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://hg.ucc.asn.au/dropbear/rev/0bf76f54de6f
https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f
- Avoid disclosing existence of valid users through inconsistent delays
Thanks to Logan Lamb for reporting. CVE-2013-4434
https://hg.ucc.asn.au/dropbear/rev/d7784616409a
https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a
- Update config.guess and config.sub for newer architectures
@@ -848,7 +697,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://hg.ucc.asn.au/dropbear/rev/818108bf7749
https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749
- Compile fix, only apply IPV6 socket options if they are available in headers
Thanks to Gustavo Zacarias for the patch
@@ -892,7 +741,7 @@ though probably will be soon
- New version numbering scheme.
Source repository has now migrated to Mercurial at
https://hg.ucc.asn.au/dropbear/graph/default
https://secure.ucc.asn.au/hg/dropbear/graph/default
0.53.1 - Wednesday 2 March 2011

View File

@@ -6,12 +6,12 @@ Basic Dropbear build instructions:
localoptions.h should be located in the build directory if you are
building out of tree.
- If using a Mercurial or Git checkout, "autoconf; autoheader"
- Configure for your system:
./configure (optionally with --disable-zlib or --disable-syslog,
or --help for other options)
(you'll need to first run "autoconf; autoheader" if you edit configure.ac)
- Compile:
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"

View File

@@ -20,13 +20,13 @@ LIBTOM_LIBS=@LIBTOM_LIBS@
ifeq (@BUNDLED_LIBTOM@, 1)
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
LIBTOM_CLEAN=ltc-clean ltm-clean
CPPFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif
OPTION_HEADERS = default_options_guard.h sysoptions.h
ifneq ($(wildcard localoptions.h),)
CPPFLAGS+=-DLOCALOPTIONS_H_EXISTS
CFLAGS+=-DLOCALOPTIONS_H_EXISTS
OPTION_HEADERS += localoptions.h
endif
@@ -35,8 +35,8 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
signkey.o rsa.o dbrandom.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o sk-ecdsa.o crypto_desc.o \
curve25519.o ed25519.o sk-ed25519.o \
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
curve25519.o ed25519.o \
dbmalloc.o \
gensignkey.o gendss.o genrsa.o gened25519.o
@@ -57,14 +57,15 @@ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
KEYOBJS=dropbearkey.o
CONVERTOBJS=dropbearconvert.o keyimport.o signkey_ossh.o
CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
ifeq (@DROPBEAR_FUZZ@, 1)
allobjs = $(COMMONOBJS) fuzz/fuzz-common.o fuzz/fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
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
@@ -72,7 +73,6 @@ ifeq (@DROPBEAR_FUZZ@, 1)
dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
# CXX only set when fuzzing
CXX=@CXX@
FUZZ_CLEAN=fuzz-clean
else
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
@@ -107,8 +107,8 @@ AR=@AR@
RANLIB=@RANLIB@
STRIP=@STRIP@
INSTALL=@INSTALL@
CPPFLAGS+=@CPPFLAGS@ -I. -I$(srcdir)
CFLAGS+=@CFLAGS@
CPPFLAGS=@CPPFLAGS@
CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
LIBS+=@LIBS@
LDFLAGS=@LDFLAGS@
@@ -119,16 +119,15 @@ STATIC=@STATIC@
# whether we're building client, server, or both for the common objects.
# evilness so we detect 'dropbear' by itself as a word
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdropbearZ, Z$(prog)Z))))
CPPFLAGS+= -DDROPBEAR_SERVER
CFLAGS+= -DDROPBEAR_SERVER
endif
ifneq (,$(strip $(foreach prog, $(PROGRAMS), $(findstring ZdbclientZ, Z$(prog)Z))))
CPPFLAGS+= -DDROPBEAR_CLIENT
CFLAGS+= -DDROPBEAR_CLIENT
endif
# these are exported so that libtomcrypt's makefile will use them
export CC
export CFLAGS
export CPPFLAGS
export RANLIB AR STRIP
ifeq ($(STATIC), 1)
@@ -143,7 +142,7 @@ endif
# for the scp progress meter. The -D doesn't affect anything else.
ifeq ($(SCPPROGRESS), 1)
CPPFLAGS+=-DPROGRESS_METER
CFLAGS+=-DPROGRESS_METER
endif
all: $(TARGETS)
@@ -217,7 +216,7 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
MULTIOBJS=
ifeq ($(MULTI),1)
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
CPPFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
@@ -237,7 +236,7 @@ $(STATIC_LTC): $(OPTION_HEADERS)
$(STATIC_LTM): $(OPTION_HEADERS)
$(MAKE) -C libtommath
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint check
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint
ltc-clean:
$(MAKE) -C libtomcrypt clean
@@ -248,7 +247,7 @@ ltm-clean:
sizes: dropbear
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
clean: $(LIBTOM_CLEAN) $(FUZZ_CLEAN) thisclean
clean: $(LIBTOM_CLEAN) thisclean
thisclean:
-rm -f dropbear$(EXEEXT) dbclient$(EXEEXT) dropbearkey$(EXEEXT) \
@@ -266,46 +265,50 @@ tidy:
lint:
cd $(srcdir); ./dropbear_lint.sh
check: lint
make -C test
## Fuzzing targets
# list of fuzz targets
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths \
fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519 fuzzer-client fuzzer-client_nomaths \
fuzzer-postauth_nomaths
FUZZ_TARGETS=fuzzer-preauth fuzzer-pubkey fuzzer-verify fuzzer-preauth_nomaths fuzzer-kexdh fuzzer-kexecdh fuzzer-kexcurve25519
FUZZER_OPTIONS = $(addsuffix .options, $(FUZZ_TARGETS))
FUZZ_OBJS = $(addprefix fuzz/,$(addsuffix .o,$(FUZZ_TARGETS))) \
fuzz/fuzz-sshpacketmutator.o
list-fuzz-targets:
@echo $(FUZZ_TARGETS)
# fuzzers that don't use libfuzzer, just a standalone harness that feeds inputs
fuzzstandalone: FUZZLIB=fuzz/fuzz-harness.o
fuzzstandalone: fuzz/fuzz-harness.o fuzz-targets
fuzzstandalone: FUZZLIB=fuzz-harness.o
fuzzstandalone: fuzz-harness.o fuzz-targets
# Build all the fuzzers. Usually like
# make fuzz-targets FUZZLIB=-lFuzzer.a
# the library provides main(). Otherwise
# make fuzzstandalone
# provides a main in fuzz-harness.c
# exclude svr-main.o to avoid duplicate main
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
fuzz-harness.o: $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs) fuzz-common.o
# build all the fuzzers. This will require fail to link unless built with
# make fuzz-targets FUZZLIB=-lFuzzer.a
# or similar - the library provides main().
fuzz-targets: $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
$(FUZZ_TARGETS): $(FUZZ_OBJS) $(allobjs) $(LIBTOM_DEPS)
$(CXX) $(CXXFLAGS) fuzz/$@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth: fuzzer-preauth.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
# fuzzers that use the custom mutator - these expect a SSH network stream
MUTATOR_FUZZERS=fuzzer-client fuzzer-client_nomaths \
fuzzer-preauth fuzzer-preauth_nomaths fuzzer-postauth_nomaths
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
# Skip custom mutators for -fsanitize-memory since libfuzzer doesn't initialise memory
# Pending fix for it https://github.com/google/oss-fuzz/issues/4605
ifeq (,$(findstring fsanitize=memory, $(CFLAGS)))
$(MUTATOR_FUZZERS): allobjs += fuzz/fuzz-sshpacketmutator.o
endif
fuzzer-pubkey: fuzzer-pubkey.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-verify: fuzzer-verify.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexdh: fuzzer-kexdh.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexecdh: fuzzer-kexecdh.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexcurve25519: fuzzer-kexcurve25519.o fuzz-harness.o
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-%.options: Makefile
echo "[libfuzzer]" > $@
@@ -324,5 +327,7 @@ fuzz-hostkeys:
/usr/bin/xxd -i -a keyd >> hostkeys.c
/usr/bin/xxd -i -a keyed25519 >> hostkeys.c
fuzz-clean:
-rm -f fuzz/*.o $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
# to make coverity happy?
test:
true

5
SMALL
View File

@@ -9,7 +9,10 @@ The same applies if you are compiling just a client.
---
The following are set in localoptions.h:
The following are set in options.h:
- You can safely disable blowfish and twofish ciphers, and MD5 hmac, without
affecting interoperability
- If you're compiling statically, you can turn off host lookups

2
auth.h
View File

@@ -30,6 +30,7 @@
#include "chansession.h"
void svr_authinitialise(void);
void cli_authinitialise(void);
/* Server functions */
void recv_msg_userauth_request(void);
@@ -125,7 +126,6 @@ struct AuthState {
char *pw_passwd;
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
struct PubKeyOptions* pubkey_options;
char *pubkey_info;
#endif
};

View File

@@ -100,5 +100,5 @@ void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
plus header + some leeway*/
buf_putmpint(buf, mp);
hash_desc->process(hs, buf->data, buf->len);
buf_burn_free(buf);
buf_free(buf);
}

View File

@@ -39,32 +39,44 @@
/* 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);
buf->data = (unsigned char*)buf + sizeof(buffer);
if (size > 0) {
buf->data = (unsigned char*)buf + sizeof(buffer);
} else {
buf->data = NULL;
}
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 then free it */
void buf_burn_free(buffer* buf) {
/* overwrite the contents of the buffer to clear it */
void buf_burn(const buffer* buf) {
m_burn(buf->data, buf->size);
m_free(buf);
}
}
/* 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");
}
@@ -127,23 +139,18 @@ void buf_incrwritepos(buffer* buf, unsigned int incr) {
}
}
/* increment the position by incr */
void buf_incrpos(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) {
if (incr > BUF_MAX_INCR
|| (buf->pos + incr) > buf->len) {
|| incr < -BUF_MAX_INCR
|| (unsigned int)((int)buf->pos + incr) > buf->len
|| ((int)buf->pos + incr) < 0) {
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) {

View File

@@ -44,13 +44,12 @@ buffer * buf_new(unsigned int size);
/* Possibly returns a new buffer*, like realloc() */
buffer * buf_resize(buffer *buf, unsigned int newsize);
void buf_free(buffer* buf);
void buf_burn_free(buffer* buf);
void buf_burn(const buffer* buf);
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, unsigned int incr);
void buf_decrpos(buffer* buf, unsigned int decr);
void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */
void buf_incrwritepos(buffer* buf, unsigned int incr);
unsigned char buf_getbyte(buffer* buf);
unsigned char buf_getbool(buffer* buf);

View File

@@ -28,7 +28,6 @@
#include "includes.h"
#include "buffer.h"
#include "circbuffer.h"
#include "netio.h"
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
#define SSH_OPEN_CONNECT_FAILED 2
@@ -42,6 +41,13 @@
struct ChanType;
enum dropbear_channel_prio {
DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */
DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */
DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */
DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */
};
struct Channel {
unsigned int index; /* the local channel index */
@@ -54,9 +60,6 @@ struct Channel {
int readfd; /* read from insecure side, written to wire */
int errfd; /* used like writefd or readfd, depending if it's client or server.
Doesn't exactly belong here, but is cleaner here */
int bidir_fd; /* a boolean indicating that writefd/readfd are the same
file descriptor (bidirectional), such as a network socket or PTY.
That is handled differently when closing FDs */
circbuffer *writebuf; /* data from the wire, for local consumption. Can be
initially NULL */
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
@@ -65,9 +68,6 @@ struct Channel {
/* whether close/eof messages have been exchanged */
int sent_close, recv_close;
int recv_eof, sent_eof;
/* once flushing is set, readfd will close once no more data is available
(not waiting for EOF) */
int flushing;
struct dropbear_progress_connection *conn_pending;
int initconn; /* used for TCP forwarding, whether the channel has been
@@ -77,22 +77,25 @@ struct Channel {
for this channel (and are awaiting a confirmation
or failure). */
int flushing;
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
void (*read_mangler)(const struct Channel*, const unsigned char* bytes, int *len);
const struct ChanType* type;
enum dropbear_prio prio;
enum dropbear_channel_prio prio;
};
struct ChanType {
int sepfds; /* Whether this channel has separate pipes for in/out or not */
const char *name;
/* Sets up the channel */
int (*inithandler)(struct Channel*);
/* Called to check whether a channel should close, separately from the FD being EOF.
/* Called to check whether a channel should close, separately from the FD being closed.
Used for noticing process exiting */
int (*check_close)(struct Channel*);
int (*check_close)(const struct Channel*);
/* Handler for ssh_msg_channel_request */
void (*reqhandler)(struct Channel*);
/* Called prior to sending ssh_msg_channel_close, used for sending exit status */
@@ -101,7 +104,7 @@ struct ChanType {
void (*cleanup)(const struct Channel*);
};
/* Callback for connect_remote. errstring may be NULL if result == DROPBEAR_SUCCESS */
/* Callback for connect_remote */
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);
void chaninitialise(const struct ChanType *chantypes[]);

View File

@@ -47,6 +47,7 @@
static int new_agent_chan(struct Channel * channel);
const struct ChanType cli_chan_agent = {
0, /* sepfds */
"auth-agent@openssh.com",
new_agent_chan,
NULL,
@@ -93,7 +94,6 @@ static int new_agent_chan(struct Channel * channel) {
channel->readfd = fd;
channel->writefd = fd;
channel->bidir_fd = 1;
return 0;
}

View File

@@ -32,6 +32,12 @@
#include "packet.h"
#include "runopts.h"
void cli_authinitialise() {
memset(&ses.authstate, 0, sizeof(ses.authstate));
}
/* Send a "none" auth request to get available methods */
void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods"))
@@ -82,11 +88,6 @@ void recv_msg_userauth_banner() {
return;
}
if (cli_opts.quiet) {
TRACE(("not showing banner"))
return;
}
banner = buf_getstring(ses.payload, &bannerlen);
buf_eatstring(ses.payload); /* The language string */
@@ -265,10 +266,7 @@ void recv_msg_userauth_success() {
/* This function can validly get called multiple times
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
DEBUG1(("received msg_userauth_success"))
if (cli_opts.disable_trivial_auth && cli_ses.is_trivial_auth) {
dropbear_exit("trivial authentication not allowed");
}
TRACE(("received msg_userauth_success"))
/* Note: in delayed-zlib mode, setting authdone here
* will enable compression in the transport layer */
ses.authstate.authdone = 1;

View File

@@ -115,7 +115,6 @@ void recv_msg_userauth_info_request() {
for (i = 0; i < num_prompts; i++) {
unsigned int response_len = 0;
cli_ses.is_trivial_auth = 0;
prompt = buf_getstring(ses.payload, NULL);
cleantext(prompt);

View File

@@ -120,7 +120,7 @@ void cli_auth_password() {
char* password = NULL;
char prompt[80];
DEBUG1(("enter cli_auth_password"))
TRACE(("enter cli_auth_password"))
CHECKCLEARTOWRITE();
snprintf(prompt, sizeof(prompt), "%s@%s's password: ",
@@ -155,7 +155,7 @@ void cli_auth_password() {
encrypt_packet();
m_burn(password, strlen(password));
cli_ses.is_trivial_auth = 0;
TRACE(("leave cli_auth_password"))
}
#endif /* DROPBEAR_CLI_PASSWORD_AUTH */

View File

@@ -125,7 +125,7 @@ void recv_msg_userauth_pk_ok() {
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 */
// TODO: rsa-sha256 agent
if (key->source == SIGNKEY_SOURCE_AGENT) {
/* Format the agent signature ourselves, as buf_put_sign would. */
buffer *sigblob;
@@ -147,7 +147,7 @@ static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype,
buffer* sigbuf = NULL;
enum signkey_type keytype = signkey_type_from_signature(sigtype);
DEBUG1(("enter send_msg_userauth_pubkey %s", signature_name_from_type(sigtype, NULL)))
TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
@@ -176,7 +176,6 @@ static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype,
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
cli_buf_put_sign(ses.writepayload, key, sigtype, sigbuf);
buf_free(sigbuf); /* Nothing confidential in the buffer */
cli_ses.is_trivial_auth = 0;
}
encrypt_packet();

View File

@@ -46,6 +46,7 @@ static int cli_init_netcat(struct Channel *channel);
static void cli_tty_setup(void);
const struct ChanType clichansess = {
0, /* sepfds */
"session", /* name */
cli_initchansess, /* inithandler */
NULL, /* checkclosehandler */
@@ -343,11 +344,11 @@ static int cli_init_stdpipe_sess(struct Channel *channel) {
setnonblocking(STDERR_FILENO);
channel->extrabuf = cbuf_new(opts.recv_window);
channel->bidir_fd = 0;
return 0;
}
static int cli_init_netcat(struct Channel *channel) {
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
return cli_init_stdpipe_sess(channel);
}
@@ -360,9 +361,12 @@ static int cli_initchansess(struct Channel *channel) {
cli_setup_agent(channel);
}
#endif
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
channel->prio = DROPBEAR_PRIO_LOWDELAY;
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
} else {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
send_chansess_shell_req(channel);
@@ -371,7 +375,7 @@ static int cli_initchansess(struct Channel *channel) {
cli_tty_setup();
channel->read_mangler = cli_escape_handler;
cli_ses.last_char = '\r';
}
}
return 0; /* Success */
}
@@ -379,6 +383,7 @@ static int cli_initchansess(struct Channel *channel) {
#if DROPBEAR_CLI_NETCAT
static const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_netcat, /* inithandler */
NULL,

View File

@@ -46,13 +46,6 @@ 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
@@ -105,12 +98,6 @@ void recv_msg_kexdh_reply() {
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");
@@ -371,7 +358,7 @@ static void checkhostkey(const unsigned char* keyblob, unsigned int keybloblen)
if (ret == DROPBEAR_SUCCESS) {
/* Good matching key */
DEBUG1(("server match %s", fingerprint))
TRACE(("good matching key"))
goto out;
}

View File

@@ -31,7 +31,9 @@
#include "dbrandom.h"
#include "crypto_desc.h"
#include "netio.h"
#include "fuzz.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);
#if DROPBEAR_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
@@ -47,7 +49,6 @@ int main(int argc, char ** argv) {
int sock_in, sock_out;
struct dropbear_progress_connection *progress = NULL;
pid_t proxy_cmd_pid = 0;
_dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
@@ -65,17 +66,14 @@ int main(int argc, char ** argv) {
}
#endif
if (cli_opts.bind_address) {
DEBUG1(("connect to: user=%s host=%s/%s bind_address=%s:%s", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address, cli_opts.bind_port))
} else {
DEBUG1(("connect to: user=%s host=%s/%s",cli_opts.username,cli_opts.remotehost,cli_opts.remoteport))
}
TRACE(("user='%s' host='%s' port='%s' bind_address='%s' bind_port='%s'", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport, cli_opts.bind_address, cli_opts.bind_port))
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dropbear_exit("signal() error");
}
pid_t proxy_cmd_pid = 0;
#if DROPBEAR_CLI_PROXYCMD
if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out, &proxy_cmd_pid);
@@ -88,9 +86,8 @@ int main(int argc, char ** argv) {
} else
#endif
{
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port,
DROPBEAR_PRIO_LOWDELAY);
progress = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
cli_connected, &ses, cli_opts.bind_address, cli_opts.bind_port);
sock_in = sock_out = -1;
}
@@ -101,6 +98,58 @@ 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);
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();
/* 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];
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);
}
static void exec_proxy_cmd(const void *user_data_cmd) {
const char *cmd = user_data_cmd;
char *usershell;
@@ -139,7 +188,6 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out) {
ret = spawn_command(exec_proxy_cmd, ex_cmd,
sock_out, sock_in, NULL, pid_out);
DEBUG1(("cmd: %s pid=%d", ex_cmd,*pid_out))
m_free(ex_cmd);
if (ret == DROPBEAR_FAILURE) {
dropbear_exit("Failed running proxy command");
@@ -151,5 +199,4 @@ static void kill_proxy_sighandler(int UNUSED(signo)) {
kill_proxy_command();
_exit(1);
}
#endif /* DROPBEAR_CLI_PROXYCMD */

View File

@@ -62,7 +62,6 @@ static void printhelp() {
"-T Don't allocate a pty\n"
"-N Don't run a remote command\n"
"-f Run in background after auth\n"
"-q quiet, don't show remote banner\n"
"-y Always accept remote host key if unknown\n"
"-y -y Don't perform any remote host key checking (caution)\n"
"-s Request a subsystem (use by external sftp)\n"
@@ -80,7 +79,7 @@ static void printhelp() {
#if DROPBEAR_CLI_REMOTETCPFWD
"-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
"-I <idle_timeout> (0 is never, default %d)\n"
#if DROPBEAR_CLI_NETCAT
@@ -96,7 +95,7 @@ static void printhelp() {
"-b [bind_address][:bind_port]\n"
"-V Version\n"
#if DEBUG_TRACE
"-v verbose (repeat for more verbose)\n"
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname,
#if DROPBEAR_CLI_PUBKEY_AUTH
@@ -142,7 +141,6 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.username = NULL;
cli_opts.cmd = NULL;
cli_opts.no_cmd = 0;
cli_opts.quiet = 0;
cli_opts.backgrounded = 0;
cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
cli_opts.always_accept_key = 0;
@@ -154,7 +152,6 @@ void cli_getopts(int argc, char ** argv) {
#if DROPBEAR_CLI_ANYTCPFWD
cli_opts.exit_on_fwd_failure = 0;
#endif
cli_opts.disable_trivial_auth = 0;
#if DROPBEAR_CLI_LOCALTCPFWD
cli_opts.localfwds = list_new();
opts.listen_fwd_all = 0;
@@ -216,9 +213,6 @@ void cli_getopts(int argc, char ** argv) {
}
cli_opts.always_accept_key = 1;
break;
case 'q': /* quiet */
cli_opts.quiet = 1;
break;
case 'p': /* remoteport */
next = (char**)&cli_opts.remoteport;
break;
@@ -302,7 +296,7 @@ void cli_getopts(int argc, char ** argv) {
#endif
#if DEBUG_TRACE
case 'v':
debug_trace++;
debug_trace = 1;
break;
#endif
case 'F':
@@ -419,7 +413,7 @@ void cli_getopts(int argc, char ** argv) {
/* And now a few sanity checks and setup */
#if DROPBEAR_CLI_PROXYCMD
#if DROPBEAR_CLI_PROXYCMD
if (cli_opts.proxycmd) {
/* To match the common path of m_freeing it */
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
@@ -431,10 +425,14 @@ void cli_getopts(int argc, char ** argv) {
}
if (bind_arg) {
if (split_address_port(bind_arg,
&cli_opts.bind_address, &cli_opts.bind_port)
== DROPBEAR_FAILURE) {
dropbear_exit("Bad -b argument");
/* split [host][:port] */
char *port = strrchr(bind_arg, ':');
if (port) {
cli_opts.bind_port = m_strdup(port+1);
*port = '\0';
}
if (strlen(bind_arg) > 0) {
cli_opts.bind_address = m_strdup(bind_arg);
}
}
@@ -452,9 +450,12 @@ void cli_getopts(int argc, char ** argv) {
&& cli_opts.no_cmd == 0) {
dropbear_exit("Command required for -f");
}
if (recv_window_arg) {
parse_recv_window(recv_window_arg);
opts.recv_window = atol(recv_window_arg);
if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) {
dropbear_exit("Bad recv window '%s'", recv_window_arg);
}
}
if (keepalive_arg) {
unsigned int val;
@@ -478,17 +479,6 @@ void cli_getopts(int argc, char ** argv) {
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#if DROPBEAR_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
/* We don't want to include default id_dropbear as a
-i argument for multihop, so handle it later. */
#if (DROPBEAR_CLI_PUBKEY_AUTH)
{
char *expand_path = expand_homedir_path(DROPBEAR_DEFAULT_CLI_AUTHKEY);
@@ -497,6 +487,14 @@ void cli_getopts(int argc, char ** argv) {
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#if DROPBEAR_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
}
#if DROPBEAR_CLI_PUBKEY_AUTH
@@ -527,11 +525,11 @@ static void loadidentityfile(const char* filename, int warnfail) {
static char*
multihop_passthrough_args() {
char *ret;
unsigned int len, total;
int total;
unsigned int len = 0;
m_list_elem *iter;
/* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */
len = 30; /* space for "-q -y -y -W <size>\0" */
#if DROPBEAR_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
@@ -539,40 +537,45 @@ multihop_passthrough_args() {
len += 3 + strlen(key->filename);
}
#endif /* DROPBEAR_CLI_PUBKEY_AUTH */
if (cli_opts.proxycmd) {
/* "-J 'cmd'" */
len += 6 + strlen(cli_opts.proxycmd);
}
len += 30; /* space for -W <size>, terminator. */
ret = m_malloc(len);
total = 0;
if (cli_opts.quiet) {
total += m_snprintf(ret+total, len-total, "-q ");
if (cli_opts.no_hostkey_check)
{
int written = snprintf(ret+total, len-total, "-y -y ");
total += written;
}
else if (cli_opts.always_accept_key)
{
int written = snprintf(ret+total, len-total, "-y ");
total += written;
}
if (cli_opts.no_hostkey_check) {
total += m_snprintf(ret+total, len-total, "-y -y ");
} else if (cli_opts.always_accept_key) {
total += m_snprintf(ret+total, len-total, "-y ");
}
if (cli_opts.proxycmd) {
total += m_snprintf(ret+total, len-total, "-J '%s' ", cli_opts.proxycmd);
}
if (opts.recv_window != DEFAULT_RECV_WINDOW) {
total += m_snprintf(ret+total, len-total, "-W %u ", opts.recv_window);
if (opts.recv_window != DEFAULT_RECV_WINDOW)
{
int written = snprintf(ret+total, len-total, "-W %u ", opts.recv_window);
total += written;
}
#if DROPBEAR_CLI_PUBKEY_AUTH
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
total += m_snprintf(ret+total, len-total, "-i %s ", key->filename);
const size_t size = len - total;
int written = snprintf(ret+total, size, "-i %s ", key->filename);
dropbear_assert((unsigned int)written < size);
total += written;
}
#endif /* DROPBEAR_CLI_PUBKEY_AUTH */
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
if (total > 0)
{
total--;
}
return ret;
}
@@ -586,9 +589,6 @@ multihop_passthrough_args() {
* dbclient -J "dbclient -B madako:22 wrt" madako
* etc for as many hosts as we want.
*
* Note that "-J" arguments aren't actually used, instead
* below sets cli_opts.proxycmd directly.
*
* Ports for hosts can be specified as host/port.
*/
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
@@ -607,7 +607,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
&& strchr(cli_opts.username, '@')) {
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
hostbuf = m_malloc(len);
m_snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
} else {
hostbuf = m_strdup(orighostarg);
}
@@ -630,18 +630,19 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
/* Set up the proxycmd */
unsigned int cmd_len = 0;
char *passthrough_args = multihop_passthrough_args();
if (cli_opts.proxycmd) {
dropbear_exit("-J can't be used with multihop mode");
}
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
cmd_len = strlen(argv0) + strlen(remainder)
cmd_len = strlen(argv0) + strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ strlen(passthrough_args)
+ 30;
/* replace proxycmd. old -J arguments have been copied
to passthrough_args */
cli_opts.proxycmd = m_realloc(cli_opts.proxycmd, cmd_len);
m_snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
cli_opts.proxycmd = m_malloc(cmd_len);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
passthrough_args, remainder);
#ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */
@@ -888,7 +889,6 @@ static void add_extendedopt(const char* origstr) {
#if DROPBEAR_CLI_ANYTCPFWD
"\tExitOnForwardFailure\n"
#endif
"\tDisableTrivialAuth\n"
#ifndef DISABLE_SYSLOG
"\tUseSyslog\n"
#endif
@@ -916,10 +916,5 @@ static void add_extendedopt(const char* origstr) {
return;
}
if (match_extendedopt(&optstr, "DisableTrivialAuth") == DROPBEAR_SUCCESS) {
cli_opts.disable_trivial_auth = parse_flag_value(optstr);
return;
}
dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr);
}

View File

@@ -102,9 +102,6 @@ void cli_connected(int result, int sock, void* userdata, const char *errstring)
dropbear_exit("Connect failed: %s", errstring);
}
myses->sock_in = myses->sock_out = sock;
DEBUG1(("cli_connected"))
ses.socket_prio = DROPBEAR_PRIO_NORMAL;
/* switches to lowdelay */
update_channel_prio();
}
@@ -168,7 +165,6 @@ static void cli_session_init(pid_t proxy_cmd_pid) {
/* Auth */
cli_ses.lastprivkey = NULL;
cli_ses.lastauthtype = 0;
cli_ses.is_trivial_auth = 1;
/* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed;
@@ -249,9 +245,6 @@ static void cli_sessionloop() {
/* We've got the transport layer sorted, we now need to request
* userauth */
send_msg_service_request(SSH_SERVICE_USERAUTH);
/* We aren't using any "implicit server authentication" methods,
so don't need to wait for a response for SSH_SERVICE_USERAUTH
before sending the auth messages (rfc4253 10) */
cli_auth_getmethods();
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: sent userauth methods req"))
@@ -359,11 +352,6 @@ 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);
/* 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);
@@ -415,75 +403,7 @@ void cleantext(char* dirtytext) {
}
static void recv_msg_global_request_cli(void) {
unsigned int wantreply = 0;
buf_eatstring(ses.payload);
wantreply = buf_getbool(ses.payload);
TRACE(("recv_msg_global_request_cli: want_reply: %u", wantreply));
if (wantreply) {
/* Send a proper rejection */
send_msg_request_failure();
}
TRACE(("recv_msg_global_request_cli"))
/* 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);
}

View File

@@ -35,6 +35,7 @@
static int newtcpforwarded(struct Channel * channel);
const struct ChanType cli_chan_tcpremote = {
1, /* sepfds */
"forwarded-tcpip",
newtcpforwarded,
NULL,
@@ -50,8 +51,9 @@ static int cli_localtcp(const char* listenaddr,
const char* remoteaddr,
unsigned int remoteport);
static const struct ChanType cli_chan_tcplocal = {
1, /* sepfds */
"direct-tcpip",
NULL,
tcp_prio_inithandler,
NULL,
NULL,
NULL,
@@ -271,11 +273,12 @@ static int newtcpforwarded(struct Channel * channel) {
origaddr, origport);
goto out;
}
snprintf(portstring, sizeof(portstring), "%u", fwd->connectport);
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done,
channel, NULL, NULL, DROPBEAR_PRIO_NORMAL);
channel->conn_pending = connect_remote(fwd->connectaddr, portstring, channel_connect_done, channel, NULL, NULL);
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
err = SSH_OPEN_IN_PROGRESS;
out:

View File

@@ -64,6 +64,14 @@ static const struct dropbear_cipher dropbear_aes256 =
static const struct dropbear_cipher dropbear_aes128 =
{&aes_desc, 16, 16};
#endif
#if DROPBEAR_TWOFISH256
static const struct dropbear_cipher dropbear_twofish256 =
{&twofish_desc, 32, 16};
#endif
#if DROPBEAR_TWOFISH128
static const struct dropbear_cipher dropbear_twofish128 =
{&twofish_desc, 16, 16};
#endif
#if DROPBEAR_3DES
static const struct dropbear_cipher dropbear_3des =
{&des3_desc, 24, 8};
@@ -148,6 +156,15 @@ algo_type sshciphers[] = {
#if DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif
#if DROPBEAR_TWOFISH_CTR
/* twofish ctr is conditional as it hasn't been tested for interoperability, see options.h */
#if DROPBEAR_TWOFISH256
{"twofish256-ctr", 0, &dropbear_twofish256, 1, &dropbear_mode_ctr},
#endif
#if DROPBEAR_TWOFISH128
{"twofish128-ctr", 0, &dropbear_twofish128, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_TWOFISH_CTR */
#endif /* DROPBEAR_ENABLE_CTR_MODE */
#if DROPBEAR_ENABLE_CBC_MODE
@@ -157,6 +174,13 @@ algo_type sshciphers[] = {
#if DROPBEAR_AES256
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif
#if DROPBEAR_TWOFISH256
{"twofish256-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
{"twofish-cbc", 0, &dropbear_twofish256, 1, &dropbear_mode_cbc},
#endif
#if DROPBEAR_TWOFISH128
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif
#endif /* DROPBEAR_ENABLE_CBC_MODE */
#if DROPBEAR_3DES
@@ -215,9 +239,6 @@ algo_type ssh_nocompress[] = {
algo_type sigalgs[] = {
#if DROPBEAR_ED25519
{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
#if DROPBEAR_SK_ED25519
{"sk-ssh-ed25519@openssh.com", DROPBEAR_SIGNATURE_SK_ED25519, NULL, 1, NULL},
#endif
#endif
#if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256
@@ -229,9 +250,6 @@ algo_type sigalgs[] = {
#if DROPBEAR_ECC_521
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
#endif
#if DROPBEAR_SK_ECDSA
{"sk-ecdsa-sha2-nistp256@openssh.com", DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256, NULL, 1, NULL},
#endif
#endif
#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
@@ -341,7 +359,7 @@ void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall
len = buf->pos - startpos - 4;
buf_setpos(buf, startpos);
buf_putint(buf, len);
TRACE(("algolist add %d '%.*s'", len, len, buf_getptr(buf, len)))
TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
buf_incrwritepos(buf, len);
}
@@ -363,7 +381,7 @@ static void get_algolist(char* algolist, unsigned int algolist_len,
}
if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
*ret_count = 0;
}
}
/* ret_list will contain a list of the strings parsed out.
We will have at least one string (even if it's just "") */
@@ -374,11 +392,11 @@ static void get_algolist(char* algolist, unsigned int algolist_len,
/* someone is trying something strange */
*ret_count = 0;
return;
}
}
if (algolist[i] == ',') {
if (*ret_count >= max_count) {
dropbear_exit("Too many remote algorithms");
/* Too many */
*ret_count = 0;
return;
}
@@ -445,7 +463,7 @@ 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);
DEBUG3(("buf_match_algo: %s", algolist))
TRACE(("buf_match_algo: %s", algolist))
remotecount = MAX_PROPOSED_ALGO;
get_algolist(algolist, len, remotenames, &remotecount);

View File

@@ -154,6 +154,7 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->readfd = FD_UNINIT;
newchan->errfd = FD_CLOSED; /* this isn't always set to start with */
newchan->await_open = 0;
newchan->flushing = 0;
newchan->writebuf = cbuf_new(opts.recv_window);
newchan->recvwindow = opts.recv_window;
@@ -162,7 +163,7 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
newchan->prio = DROPBEAR_PRIO_NORMAL;
newchan->prio = DROPBEAR_CHANNEL_PRIO_EARLY; /* inithandler sets it */
ses.channels[i] = newchan;
ses.chancount++;
@@ -283,29 +284,24 @@ static void check_close(struct Channel *channel) {
channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
if (!channel->flushing
&& !channel->sent_close
&& channel->type->check_close
&& channel->type->check_close(channel))
{
channel->flushing = 1;
}
/* if a type-specific check_close is defined we will only exit
once that has been triggered. this is only used for a server "session"
channel, to ensure that the shell has exited (and the exit status
channel, to ensure that the shell has exited (and the exit status
retrieved) before we close things up. */
if (!channel->type->check_close
if (!channel->type->check_close
|| channel->sent_close
|| channel->type->check_close(channel)) {
close_allowed = 1;
}
/* In flushing mode we close FDs as soon as pipes are empty.
This is used to drain out FDs when the process exits, in the case
where the FD doesn't have EOF - "sleep 10&echo hello" case */
if (channel->flushing) {
if (channel->readfd >= 0 && !fd_read_pending(channel->readfd)) {
close_chan_fd(channel, channel->readfd, SHUT_RD);
}
if (ERRFD_IS_READ(channel)
&& channel->errfd >= 0 && !fd_read_pending(channel->errfd)) {
close_chan_fd(channel, channel->errfd, SHUT_RD);
}
}
if (channel->recv_close && !write_pending(channel) && close_allowed) {
if (!channel->sent_close) {
TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."))
@@ -321,6 +317,22 @@ static void check_close(struct Channel *channel) {
close_chan_fd(channel, channel->writefd, SHUT_WR);
}
/* Special handling for flushing read data after an exit. We
read regardless of whether the select FD was set,
and if there isn't data available, the channel will get closed. */
if (channel->flushing) {
TRACE(("might send data, flushing"))
if (channel->readfd >= 0 && channel->transwindow > 0) {
TRACE(("send data readfd"))
send_msg_channel_data(channel, 0);
}
if (ERRFD_IS_READ(channel) && channel->errfd >= 0
&& channel->transwindow > 0) {
TRACE(("send data errfd"))
send_msg_channel_data(channel, 1);
}
}
/* If we're not going to send any more data, send EOF */
if (!channel->sent_eof
&& channel->readfd == FD_CLOSED
@@ -344,7 +356,8 @@ static void check_close(struct Channel *channel) {
* if so, set up the channel properly. Otherwise, the channel is cleaned up, so
* it is important that the channel reference isn't used after a call to this
* function */
void channel_connect_done(int result, int sock, void* user_data, const char* errstring) {
void channel_connect_done(int result, int sock, void* user_data, const char* UNUSED(errstring)) {
struct Channel *channel = user_data;
TRACE(("enter channel_connect_done"))
@@ -352,7 +365,6 @@ void channel_connect_done(int result, int sock, void* user_data, const char* err
if (result == DROPBEAR_SUCCESS)
{
channel->readfd = channel->writefd = sock;
channel->bidir_fd = 1;
channel->conn_pending = NULL;
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
@@ -361,9 +373,9 @@ void channel_connect_done(int result, int sock, void* user_data, const char* err
else
{
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, errstring, "");
SSH_OPEN_CONNECT_FAILED, "", "");
remove_channel(channel);
TRACE(("leave check_in_progress: fail. internal errstring: %s", errstring))
TRACE(("leave check_in_progress: fail"))
}
}
@@ -768,6 +780,14 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
channel->transwindow -= len;
encrypt_packet();
/* If we receive less data than we requested when flushing, we've
reached the equivalent of EOF */
if (channel->flushing && len < (ssize_t)maxlen)
{
TRACE(("closing from channel, flushing out."))
close_chan_fd(channel, fd, SHUT_RD);
}
TRACE(("leave send_msg_channel_data"))
}
@@ -955,7 +975,9 @@ void recv_msg_channel_open() {
}
}
update_channel_prio();
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
/* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow,
@@ -968,6 +990,8 @@ failure:
cleanup:
m_free(type);
update_channel_prio();
TRACE(("leave recv_msg_channel_open"))
}
@@ -1049,7 +1073,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
int closein = 0, closeout = 0;
if (channel->bidir_fd) {
if (channel->type->sepfds) {
TRACE(("SHUTDOWN(%d, %d)", fd, how))
shutdown(fd, how);
if (how == 0) {
@@ -1079,7 +1103,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
/* if we called shutdown on it and all references are gone, then we
* need to close() it to stop it lingering */
if (channel->bidir_fd && channel->readfd == FD_CLOSED
if (channel->type->sepfds && channel->readfd == FD_CLOSED
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
TRACE(("CLOSE (finally) of %d", fd))
m_close(fd);
@@ -1112,7 +1136,6 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
chan->writefd = chan->readfd = fd;
ses.maxfd = MAX(ses.maxfd, fd);
chan->bidir_fd = 1;
chan->await_open = 1;
@@ -1129,7 +1152,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
return DROPBEAR_SUCCESS;
}
/* Confirmation that our channel open request was
/* Confirmation that our channel open request (for forwardings) was
* successful*/
void recv_msg_channel_open_confirmation() {
@@ -1162,8 +1185,11 @@ void recv_msg_channel_open_confirmation() {
}
}
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
update_channel_prio();
TRACE(("leave recv_msg_channel_open_confirmation"))
}

View File

@@ -249,7 +249,7 @@ static void kexinitialise() {
/* Helper function for gen_new_keys, creates a hash. It makes a copy of the
* already initialised hash_state hs, which should already have processed
* the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
* out must have at least min(hash_size, outlen) bytes allocated.
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
*
* See Section 7.2 of rfc4253 (ssh transport) for details */
static void hashkeys(unsigned char *out, unsigned int outlen,
@@ -306,7 +306,8 @@ static void gen_new_keys() {
mp_clear(ses.dh_K);
m_free(ses.dh_K);
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
buf_burn_free(ses.hash);
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
if (IS_DROPBEAR_CLIENT) {
@@ -486,12 +487,6 @@ 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);
@@ -802,7 +797,8 @@ void finish_kexhashbuf(void) {
}
#endif
buf_burn_free(ses.kexhashbuf);
buf_burn(ses.kexhashbuf);
buf_free(ses.kexhashbuf);
m_burn(&hs, sizeof(hash_state));
ses.kexhashbuf = NULL;
@@ -867,7 +863,7 @@ static void read_kex_algos() {
goto error;
}
TRACE(("kexguess2 %d", kexguess2))
DEBUG3(("kex algo %s", algo->name))
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->data;
/* server_host_key_algorithms */
@@ -877,7 +873,7 @@ static void read_kex_algos() {
erralgo = "hostkey";
goto error;
}
DEBUG2(("hostkey algo %s", algo->name))
TRACE(("signature algo %s", algo->name))
ses.newkeys->algo_signature = algo->val;
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
@@ -887,7 +883,7 @@ static void read_kex_algos() {
erralgo = "enc c->s";
goto error;
}
DEBUG2(("enc c2s is %s", c2s_cipher_algo->name))
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
@@ -895,7 +891,7 @@ static void read_kex_algos() {
erralgo = "enc s->c";
goto error;
}
DEBUG2(("enc s2c is %s", s2c_cipher_algo->name))
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
@@ -908,7 +904,7 @@ static void read_kex_algos() {
erralgo = "mac c->s";
goto error;
}
DEBUG2(("hmac c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
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, 0, NULL);
@@ -921,7 +917,7 @@ static void read_kex_algos() {
erralgo = "mac s->c";
goto error;
}
DEBUG2(("hmac s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
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, 0, NULL);
@@ -929,7 +925,7 @@ static void read_kex_algos() {
erralgo = "comp c->s";
goto error;
}
DEBUG2(("comp c2s is %s", c2s_comp_algo->name))
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, 0, NULL);
@@ -937,7 +933,7 @@ static void read_kex_algos() {
erralgo = "comp s->c";
goto error;
}
DEBUG2(("comp s2c is %s", s2c_comp_algo->name))
TRACE(("hash s2c is %s", s2c_comp_algo->name))
/* languages_client_to_server */
buf_eatstring(ses.payload);

View File

@@ -1,19 +1,19 @@
/*
* 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
@@ -35,7 +35,7 @@ runopts opts; /* GLOBAL */
/* returns success or failure, and the keytype in *type. If we want
* to restrict the type, type can contain a type to return */
int readhostkey(const char * filename, sign_key * hostkey,
int readhostkey(const char * filename, sign_key * hostkey,
enum signkey_type *type) {
int ret = DROPBEAR_FAILURE;
@@ -57,7 +57,8 @@ int readhostkey(const char * filename, sign_key * hostkey,
ret = DROPBEAR_SUCCESS;
out:
buf_burn_free(buf);
buf_burn(buf);
buf_free(buf);
return ret;
}
@@ -100,74 +101,4 @@ void print_version() {
fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION);
}
void parse_recv_window(const char* recv_window_arg) {
int ret;
unsigned int rw;
ret = m_str_to_uint(recv_window_arg, &rw);
if (ret == DROPBEAR_FAILURE || rw == 0 || rw > MAX_RECV_WINDOW) {
if (rw > MAX_RECV_WINDOW) {
opts.recv_window = MAX_RECV_WINDOW;
}
dropbear_log(LOG_WARNING, "Bad recv window '%s', using %d",
recv_window_arg, opts.recv_window);
} else {
opts.recv_window = rw;
}
}
/* Splits addr:port. Handles IPv6 [2001:0011::4]:port style format.
Returns first/second parts as malloced strings, second will
be NULL if no separator is found.
:port -> (NULL, "port")
port -> (port, NULL)
addr:port (addr, port)
addr: -> (addr, "")
Returns DROPBEAR_SUCCESS/DROPBEAR_FAILURE */
int split_address_port(const char* spec, char **first, char ** second) {
char *spec_copy = NULL, *addr = NULL, *colon = NULL;
int ret = DROPBEAR_FAILURE;
*first = NULL;
*second = NULL;
spec_copy = m_strdup(spec);
addr = spec_copy;
if (*addr == '[') {
addr++;
colon = strchr(addr, ']');
if (!colon) {
dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
goto out;
}
*colon = '\0';
colon++;
if (*colon == '\0') {
/* No port part */
colon = NULL;
} else if (*colon != ':') {
dropbear_log(LOG_WARNING, "Bad address '%s'", spec);
goto out;
}
} else {
/* search for ':', that separates address and port */
colon = strrchr(addr, ':');
}
/* colon points to ':' now, or is NULL */
if (colon) {
/* Split the address/port */
*colon = '\0';
colon++;
*second = m_strdup(colon);
}
if (strlen(addr)) {
*first = m_strdup(addr);
}
ret = DROPBEAR_SUCCESS;
out:
m_free(spec_copy);
return ret;
}

View File

@@ -64,7 +64,7 @@ void common_session_init(int sock_in, int sock_out) {
setnonblocking(sock_out);
}
ses.socket_prio = DROPBEAR_PRIO_NORMAL;
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
@@ -285,7 +285,8 @@ static void cleanup_buf(buffer **buf) {
if (!*buf) {
return;
}
buf_burn_free(*buf);
buf_burn(*buf);
buf_free(*buf);
*buf = NULL;
}
@@ -403,7 +404,7 @@ static void read_session_identification() {
dropbear_exit("Incompatible remote version '%s'", ses.remoteident);
}
DEBUG1(("remoteident: %s", ses.remoteident))
TRACE(("remoteident: %s", ses.remoteident))
}
@@ -464,11 +465,6 @@ 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;
@@ -666,16 +662,26 @@ void update_channel_prio() {
return;
}
new_prio = DROPBEAR_PRIO_NORMAL;
new_prio = DROPBEAR_PRIO_BULK;
for (i = 0; i < ses.chansize; i++) {
struct Channel *channel = ses.channels[i];
if (!channel) {
if (!channel || channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
if (channel && channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
TRACE(("update_channel_prio: early %d", channel->index))
}
continue;
}
any = 1;
if (channel->prio == DROPBEAR_PRIO_LOWDELAY) {
if (channel->prio == DROPBEAR_CHANNEL_PRIO_INTERACTIVE)
{
TRACE(("update_channel_prio: lowdelay %d", channel->index))
new_prio = DROPBEAR_PRIO_LOWDELAY;
break;
} else if (channel->prio == DROPBEAR_CHANNEL_PRIO_UNKNOWABLE
&& new_prio == DROPBEAR_PRIO_BULK)
{
TRACE(("update_channel_prio: unknowable %d", channel->index))
new_prio = DROPBEAR_PRIO_DEFAULT;
}
}

1271
config.guess vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1,459 +0,0 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Using AIX */
#undef AIX
/* Broken getaddrinfo */
#undef BROKEN_GETADDRINFO
/* Use bundled libtom */
#undef BUNDLED_LIBTOM
/* lastlog file location */
#undef CONF_LASTLOG_FILE
/* utmpx file location */
#undef CONF_UTMPX_FILE
/* utmp file location */
#undef CONF_UTMP_FILE
/* wtmpx file location */
#undef CONF_WTMPX_FILE
/* wtmp file location */
#undef CONF_WTMP_FILE
/* Disable use of lastlog() */
#undef DISABLE_LASTLOG
/* Use PAM */
#undef DISABLE_PAM
/* Disable use of pututline() */
#undef DISABLE_PUTUTLINE
/* Disable use of pututxline() */
#undef DISABLE_PUTUTXLINE
/* Using syslog */
#undef DISABLE_SYSLOG
/* Disable use of utmp */
#undef DISABLE_UTMP
/* Disable use of utmpx */
#undef DISABLE_UTMPX
/* Disable use of wtmp */
#undef DISABLE_WTMP
/* Disable use of wtmpx */
#undef DISABLE_WTMPX
/* Use zlib */
#undef DISABLE_ZLIB
/* Fuzzing */
#undef DROPBEAR_FUZZ
/* External Public Key Authentication */
#undef DROPBEAR_PLUGIN
/* Define to 1 if you have the `basename' function. */
#undef HAVE_BASENAME
/* Define to 1 if you have the `clearenv' function. */
#undef HAVE_CLEARENV
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define if gai_strerror() returns const char * */
#undef HAVE_CONST_GAI_STRERROR_PROTO
/* crypt() function */
#undef HAVE_CRYPT
/* Define to 1 if you have the <crypt.h> header file. */
#undef HAVE_CRYPT_H
/* Define to 1 if you have the `daemon' function. */
#undef HAVE_DAEMON
/* Use /dev/ptc & /dev/pts */
#undef HAVE_DEV_PTS_AND_PTC
/* Define to 1 if you have the `endutent' function. */
#undef HAVE_ENDUTENT
/* Define to 1 if you have the `endutxent' function. */
#undef HAVE_ENDUTXENT
/* Define to 1 if you have the `explicit_bzero' function. */
#undef HAVE_EXPLICIT_BZERO
/* Define to 1 if you have the `fexecve' function. */
#undef HAVE_FEXECVE
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Define to 1 if you have the `freeaddrinfo' function. */
#undef HAVE_FREEADDRINFO
/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getgrouplist' function. */
#undef HAVE_GETGROUPLIST
/* Define to 1 if you have the `getnameinfo' function. */
#undef HAVE_GETNAMEINFO
/* 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
/* Define to 1 if you have the `getusershell' function. */
#undef HAVE_GETUSERSHELL
/* Define to 1 if you have the `getutent' function. */
#undef HAVE_GETUTENT
/* Define to 1 if you have the `getutid' function. */
#undef HAVE_GETUTID
/* Define to 1 if you have the `getutline' function. */
#undef HAVE_GETUTLINE
/* Define to 1 if you have the `getutxent' function. */
#undef HAVE_GETUTXENT
/* Define to 1 if you have the `getutxid' function. */
#undef HAVE_GETUTXID
/* Define to 1 if you have the `getutxline' function. */
#undef HAVE_GETUTXLINE
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <lastlog.h> header file. */
#undef HAVE_LASTLOG_H
/* Define to 1 if you have the <libgen.h> header file. */
#undef HAVE_LIBGEN_H
/* Define to 1 if you have the `pam' library (-lpam). */
#undef HAVE_LIBPAM
/* Define to 1 if you have the <libutil.h> header file. */
#undef HAVE_LIBUTIL_H
/* Define to 1 if you have the `z' library (-lz). */
#undef HAVE_LIBZ
/* Define to 1 if you have the <linux/pkt_sched.h> header file. */
#undef HAVE_LINUX_PKT_SCHED_H
/* Have login() function */
#undef HAVE_LOGIN
/* Define to 1 if you have the `logout' function. */
#undef HAVE_LOGOUT
/* Define to 1 if you have the `logwtmp' function. */
#undef HAVE_LOGWTMP
/* Define to 1 if you have the `mach_absolute_time' function. */
#undef HAVE_MACH_ABSOLUTE_TIME
/* Define to 1 if you have the <mach/mach_time.h> header file. */
#undef HAVE_MACH_MACH_TIME_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset_s' function. */
#undef HAVE_MEMSET_S
/* Define to 1 if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
/* Define to 1 if you have the <netinet/in_systm.h> header file. */
#undef HAVE_NETINET_IN_SYSTM_H
/* Define to 1 if you have the <netinet/tcp.h> header file. */
#undef HAVE_NETINET_TCP_H
/* Have openpty() function */
#undef HAVE_OPENPTY
/* Define to 1 if you have the `pam_fail_delay' function. */
#undef HAVE_PAM_FAIL_DELAY
/* Define to 1 if you have the <pam/pam_appl.h> header file. */
#undef HAVE_PAM_PAM_APPL_H
/* Define to 1 if you have the <paths.h> header file. */
#undef HAVE_PATHS_H
/* Define to 1 if you have the <pty.h> header file. */
#undef HAVE_PTY_H
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if you have the `pututline' function. */
#undef HAVE_PUTUTLINE
/* Define to 1 if you have the `pututxline' function. */
#undef HAVE_PUTUTXLINE
/* Define to 1 if you have the <security/pam_appl.h> header file. */
#undef HAVE_SECURITY_PAM_APPL_H
/* Define to 1 if you have the `setutent' function. */
#undef HAVE_SETUTENT
/* Define to 1 if you have the `setutxent' function. */
#undef HAVE_SETUTXENT
/* Define to 1 if you have the <shadow.h> header file. */
#undef HAVE_SHADOW_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the <stropts.h> header file. */
#undef HAVE_STROPTS_H
/* Have struct addrinfo */
#undef HAVE_STRUCT_ADDRINFO
/* Have struct in6_addr */
#undef HAVE_STRUCT_IN6_ADDR
/* Have struct sockaddr_in6 */
#undef HAVE_STRUCT_SOCKADDR_IN6
/* Define to 1 if the system has the type `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE
/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
/* Define to 1 if `ut_addr' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_ADDR
/* Define to 1 if `ut_addr_v6' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_ADDR_V6
/* Define to 1 if `ut_host' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_HOST
/* Define to 1 if `ut_id' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_ID
/* Define to 1 if `ut_syslen' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_SYSLEN
/* Define to 1 if `ut_time' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_TIME
/* Define to 1 if `ut_tv' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_TV
/* Define to 1 if `ut_type' is a member of `struct utmpx'. */
#undef HAVE_STRUCT_UTMPX_UT_TYPE
/* Define to 1 if `ut_addr' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_ADDR
/* Define to 1 if `ut_addr_v6' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_ADDR_V6
/* Define to 1 if `ut_exit' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_EXIT
/* Define to 1 if `ut_host' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_HOST
/* Define to 1 if `ut_id' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_ID
/* Define to 1 if `ut_pid' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_PID
/* Define to 1 if `ut_time' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_TIME
/* Define to 1 if `ut_tv' is a member of `struct utmp'. */
#undef HAVE_STRUCT_UTMP_UT_TV
/* 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/prctl.h> header file. */
#undef HAVE_SYS_PRCTL_H
/* 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
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/uio.h> header file. */
#undef HAVE_SYS_UIO_H
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if the system has the type `uint16_t'. */
#undef HAVE_UINT16_T
/* Define to 1 if the system has the type `uint32_t'. */
#undef HAVE_UINT32_T
/* Define to 1 if the system has the type `uint8_t'. */
#undef HAVE_UINT8_T
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `updwtmp' function. */
#undef HAVE_UPDWTMP
/* Define to 1 if you have the <util.h> header file. */
#undef HAVE_UTIL_H
/* Define to 1 if you have the `utmpname' function. */
#undef HAVE_UTMPNAME
/* Define to 1 if you have the `utmpxname' function. */
#undef HAVE_UTMPXNAME
/* Define to 1 if you have the <utmpx.h> header file. */
#undef HAVE_UTMPX_H
/* Define to 1 if you have the <utmp.h> header file. */
#undef HAVE_UTMP_H
/* Define to 1 if the system has the type `u_int16_t'. */
#undef HAVE_U_INT16_T
/* Define to 1 if the system has the type `u_int32_t'. */
#undef HAVE_U_INT32_T
/* Define to 1 if the system has the type `u_int8_t'. */
#undef HAVE_U_INT8_T
/* Define to 1 if you have the `writev' function. */
#undef HAVE_WRITEV
/* Define to 1 if you have the `_getpty' function. */
#undef HAVE__GETPTY
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to the type of arg 1 for `select'. */
#undef SELECT_TYPE_ARG1
/* Define to the type of args 2, 3 and 4 for `select'. */
#undef SELECT_TYPE_ARG234
/* Define to the type of arg 5 for `select'. */
#undef SELECT_TYPE_ARG5
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Use /dev/ptmx */
#undef USE_DEV_PTMX
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Use GNU extensions if glibc */
#undef _GNU_SOURCE
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> doesn't define. */
#undef gid_t
/* Define to `int' if <sys/types.h> does not define. */
#undef mode_t
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
/* type to use in place of socklen_t if not defined */
#undef socklen_t
/* Define to `int' if <sys/types.h> doesn't define. */
#undef uid_t

1043
config.sub vendored

File diff suppressed because it is too large Load Diff

8770
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
# of the platform checks have been taken straight from OpenSSH's configure.ac
# Huge thanks to them for dealing with the horrible platform-specifics :)
AC_PREREQ([2.59])
AC_PREREQ(2.59)
AC_INIT
AC_CONFIG_SRCDIR(buffer.c)
@@ -16,7 +16,6 @@ if test -s "`which hg`" && test -d "$srcdir/.hg"; then
fi
ORIGCFLAGS="$CFLAGS"
LATE_CFLAGS=""
# Checks for programs.
AC_PROG_CC
@@ -48,9 +47,6 @@ DB_TRYADDCFLAGS([-Wno-pointer-sign])
AC_MSG_NOTICE([Checking if compiler '$CC' supports -fno-strict-overflow])
DB_TRYADDCFLAGS([-fno-strict-overflow])
# needed for various extensions. define early before autoconf tests
AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions if glibc])
STATIC=0
AC_ARG_ENABLE(static,
[ --enable-static Build static binaries],
@@ -128,17 +124,6 @@ if test "$hardenbuild" -eq 1; then
fi
AC_ARG_ENABLE(werror,
[ --enable-werror Set -Werror when building],
[
if test "x$enableval" = "xyes"; then
# -Werror shouldn't be set when configure runs tests.
# We add it to the Makefile's CFLAGS
LATE_CFLAGS+="$LATE_CFLAGS -Werror"
AC_MSG_NOTICE(Enabling -Werror)
fi
], [])
# large file support is useful for scp
AC_SYS_LARGEFILE
@@ -362,7 +347,6 @@ AC_ARG_ENABLE(fuzz,
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
AC_PROG_CXX
mkdir -pv fuzz
else
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
AC_MSG_NOTICE(Disabling fuzzing)
@@ -380,13 +364,14 @@ AC_SUBST(DROPBEAR_FUZZ)
AC_SUBST(CXX)
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
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 \
sys/random.h sys/prctl.h])
sys/random.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -394,6 +379,7 @@ AC_TYPE_UID_T
AC_TYPE_MODE_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_CHECK_TYPES([uint8_t, u_int8_t, uint16_t, u_int16_t, uint32_t, u_int32_t])
AC_CHECK_TYPES([struct sockaddr_storage])
@@ -841,7 +827,7 @@ AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([getpass getspnam getusershell putenv])
AC_CHECK_FUNCS([clearenv strlcpy strlcat daemon basename _getpty getaddrinfo ])
AC_CHECK_FUNCS([freeaddrinfo getnameinfo fork writev getgrouplist fexecve])
AC_CHECK_FUNCS([freeaddrinfo getnameinfo fork writev getgrouplist])
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
@@ -873,11 +859,8 @@ if test $BUNDLED_LIBTOM = 1 ; then
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
fi
# flags that should be set in Makefile but not for configure tests
CFLAGS="$CFLAGS $LATE_CFLAGS"
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES(Makefile $LIBTOM_FILES test/Makefile)
AC_CONFIG_HEADER(config.h)
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
AC_OUTPUT
AC_MSG_NOTICE()

View File

@@ -3,18 +3,11 @@
#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 */
@@ -24,6 +17,12 @@ void crypto_init() {
#if DROPBEAR_AES
&aes_desc,
#endif
#if DROPBEAR_BLOWFISH
&blowfish_desc,
#endif
#if DROPBEAR_TWOFISH
&twofish_desc,
#endif
#if DROPBEAR_3DES
&des3_desc,
#endif
@@ -31,9 +30,8 @@ void crypto_init() {
};
const struct ltc_hash_descriptor *reghashes[] = {
#if DROPBEAR_SHA1_HMAC
/* we need sha1 for hostkey stuff regardless */
&sha1_desc,
#endif
#if DROPBEAR_MD5_HMAC
&md5_desc,
#endif
@@ -47,9 +45,9 @@ void crypto_init() {
&sha512_desc,
#endif
NULL
};
};
int i;
for (i = 0; regciphers[i] != NULL; i++) {
if (register_cipher(regciphers[i]) == -1) {
dropbear_exit("Error registering crypto");
@@ -69,8 +67,6 @@ void crypto_init() {
}
#endif
mp_rand_source(dropbear_rand_source);
#if DROPBEAR_ECC
ltc_mp = ltm_desc;
dropbear_ecc_fill_dp();

View File

@@ -19,7 +19,7 @@ dbclient \- lightweight SSH client
.SH DESCRIPTION
.B dbclient
is the client part of Dropbear SSH
is a small SSH client
.SH OPTIONS
.TP
.TP
@@ -44,27 +44,27 @@ from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is use
.TP
.B \-L\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Local port forwarding.
Forward
Forward the port
.I listenport
on the local host through the SSH connection to
on the local host through the SSH connection to port
.I port
on
on the host
.IR host .
.TP
.B \-R\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Remote port forwarding.
Forward
Forward the port
.I listenport
on the remote host through the SSH connection to
on the remote host through the SSH connection to port
.I port
on
on the host
.IR host .
.TP
.B \-l \fIuser
Username.
Login as
.I user
on the remote host. An alternative is to specify user@host.
on the remote host.
.TP
.B \-t
Allocate a PTY. This is the default when no command is given, it gives a full
@@ -72,7 +72,7 @@ interactive remote session. The main effect is that keystrokes are sent remotely
immediately as opposed to local line-based editing.
.TP
.B \-T
Don't allocate a PTY. This is the default when a command is given. See -t.
Don't allocate a PTY. This is the default a command is given. See -t.
.TP
.B \-N
Don't request a remote shell or run any commands. Any command arguments are ignored.
@@ -149,13 +149,10 @@ The following options have currently been implemented:
.RS
.TP
.B ExitOnForwardFailure
Specifies whether dbclient should terminate the connection if it cannot set up all requested local and remote port forwardings. The argument must be "yes" or "no". The default is "no".
Specifies whether dbclient should terminate the connection if it cannot set up all requested local and remote port forwardings. The argument must be yes or no. The default is no.
.TP
.B UseSyslog
Send dbclient log messages to syslog in addition to stderr.
.TP
.B Port
Specify a listening port, like the \fI-p\fR argument.
.RE
.TP
.B \-s

View File

@@ -1,9 +1,9 @@
#ifndef DBMALLOC_H_
#define DBMALLOC_H_
#include "stdint.h"
#include "stdlib.h"
#include "options.h"
#include <stdint.h>
#include <stdlib.h>
void * m_malloc(size_t size);
void * m_calloc(size_t nmemb, size_t size);

View File

@@ -23,15 +23,20 @@
* SOFTWARE. */
#include "includes.h"
#include "dbutil.h"
static int runprog(const char *multipath,
const char *progname, int argc, char ** argv, int *match) {
/* definitions are cleanest if we just put them here */
int dropbear_main(int argc, char ** argv);
int cli_main(int argc, char ** argv);
int dropbearkey_main(int argc, char ** argv);
int dropbearconvert_main(int argc, char ** argv);
int scp_main(int argc, char ** argv);
static int runprog(const char *progname, int argc, char ** argv, int *match) {
*match = DROPBEAR_SUCCESS;
#ifdef DBMULTI_dropbear
if (strcmp(progname, "dropbear") == 0) {
return dropbear_main(argc, argv, multipath);
return dropbear_main(argc, argv);
}
#endif
#ifdef DBMULTI_dbclient
@@ -62,16 +67,12 @@ static int runprog(const char *multipath,
int main(int argc, char ** argv) {
int i;
for (i = 0; i < 2; i++) {
const char* multipath = NULL;
if (i == 1) {
multipath = argv[0];
}
/* Try symlink first, then try as an argument eg "dropbearmulti dbclient host ..." */
if (argc > i) {
int match, res;
/* figure which form we're being called as */
const char* progname = basename(argv[i]);
res = runprog(multipath, progname, argc-i, &argv[i], &match);
res = runprog(progname, argc-i, &argv[i], &match);
if (match == DROPBEAR_SUCCESS) {
return res;
}

View File

@@ -34,7 +34,7 @@ static uint32_t counter = 0;
/* the max value for the counter, so it won't integer overflow */
#define MAX_COUNTER (1<<30)
static unsigned char hashpool[SHA256_HASH_SIZE] = {0};
static unsigned char hashpool[SHA1_HASH_SIZE] = {0};
static int donerandinit = 0;
#define INIT_SEED_SIZE 32 /* 256 bits */
@@ -100,7 +100,7 @@ process_file(hash_state *hs, const char *filename,
}
goto out;
}
sha256_process(hs, readbuf, readlen);
sha1_process(hs, readbuf, readlen);
readcount += readlen;
}
ret = DROPBEAR_SUCCESS;
@@ -120,13 +120,13 @@ void addrandom(const unsigned char * buf, unsigned int len)
#endif
/* hash in the new seed data */
sha256_init(&hs);
sha1_init(&hs);
/* existing state (zeroes on startup) */
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
/* new */
sha256_process(&hs, buf, len);
sha256_done(&hs, hashpool);
sha1_process(&hs, buf, len);
sha1_done(&hs, hashpool);
}
static void write_urandom()
@@ -150,12 +150,12 @@ static void write_urandom()
}
#if DROPBEAR_FUZZ
void fuzz_seed(const unsigned char* dat, unsigned int len) {
void fuzz_seed(void) {
hash_state hs;
sha256_init(&hs);
sha256_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha256_process(&hs, dat, len);
sha256_done(&hs, hashpool);
sha1_init(&hs);
sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
}
@@ -209,7 +209,7 @@ static int process_getrandom(hash_state *hs) {
if (ret == sizeof(buf)) {
/* Success, stir in the entropy */
sha256_process(hs, (void*)buf, sizeof(buf));
sha1_process(hs, (void*)buf, sizeof(buf));
return DROPBEAR_SUCCESS;
}
@@ -221,6 +221,7 @@ static int process_getrandom(hash_state *hs) {
/* Initialise the prng from /dev/urandom or prngd. This function can
* be called multiple times */
void seedrandom() {
hash_state hs;
pid_t pid;
@@ -235,10 +236,10 @@ void seedrandom() {
#endif
/* hash in the new seed data */
sha256_init(&hs);
sha1_init(&hs);
/* existing state */
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
#ifdef HAVE_GETRANDOM
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
@@ -288,21 +289,21 @@ void seedrandom() {
#endif
pid = getpid();
sha256_process(&hs, (void*)&pid, sizeof(pid));
sha1_process(&hs, (void*)&pid, sizeof(pid));
/* gettimeofday() doesn't completely fill out struct timeval on
OS X (10.8.3), avoid valgrind warnings by clearing it first */
memset(&tv, 0x0, sizeof(tv));
gettimeofday(&tv, NULL);
sha256_process(&hs, (void*)&tv, sizeof(tv));
sha1_process(&hs, (void*)&tv, sizeof(tv));
clockval = clock();
sha256_process(&hs, (void*)&clockval, sizeof(clockval));
sha1_process(&hs, (void*)&clockval, sizeof(clockval));
/* When a private key is read by the client or server it will
* be added to the hashpool - see runopts.c */
sha256_done(&hs, hashpool);
sha1_done(&hs, hashpool);
counter = 0;
donerandinit = 1;
@@ -316,7 +317,7 @@ void seedrandom() {
void genrandom(unsigned char* buf, unsigned int len) {
hash_state hs;
unsigned char hash[SHA256_HASH_SIZE];
unsigned char hash[SHA1_HASH_SIZE];
unsigned int copylen;
if (!donerandinit) {
@@ -324,17 +325,17 @@ void genrandom(unsigned char* buf, unsigned int len) {
}
while (len > 0) {
sha256_init(&hs);
sha256_process(&hs, (void*)hashpool, sizeof(hashpool));
sha256_process(&hs, (void*)&counter, sizeof(counter));
sha256_done(&hs, hash);
sha1_init(&hs);
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
sha1_process(&hs, (void*)&counter, sizeof(counter));
sha1_done(&hs, hash);
counter++;
if (counter > MAX_COUNTER) {
seedrandom();
}
copylen = MIN(len, SHA256_HASH_SIZE);
copylen = MIN(len, SHA1_HASH_SIZE);
memcpy(buf, hash, copylen);
len -= copylen;
buf += copylen;

182
dbutil.c
View File

@@ -121,6 +121,7 @@ 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);
}
@@ -155,7 +156,7 @@ void dropbear_log(int priority, const char* format, ...) {
}
#if DEBUG_TRACE
#if DEBUG_TRACE
static double debug_start_time = -1;
@@ -185,63 +186,39 @@ static double time_since_start()
return nowf - debug_start_time;
}
static void dropbear_tracelevel(int level, const char *format, va_list param)
{
if (debug_trace == 0 || debug_trace < level) {
void dropbear_trace(const char* format, ...) {
va_list param;
if (!debug_trace) {
return;
}
fprintf(stderr, "TRACE%d (%d) %f: ", level, getpid(), time_since_start());
va_start(param, format);
fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
}
#if (DEBUG_TRACE>=1)
void dropbear_trace1(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(1, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=2)
void dropbear_trace2(const char* format, ...) {
static int trace_env = -1;
va_list param;
va_start(param, format);
dropbear_tracelevel(2, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=3)
void dropbear_trace3(const char* format, ...) {
va_list param;
if (trace_env == -1) {
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
}
if (!(debug_trace && trace_env)) {
return;
}
va_start(param, format);
dropbear_tracelevel(3, format, param);
fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
#endif
#if (DEBUG_TRACE>=4)
void dropbear_trace4(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(4, format, param);
va_end(param);
}
#endif
#if (DEBUG_TRACE>=5)
void dropbear_trace5(const char* format, ...) {
va_list param;
va_start(param, format);
dropbear_tracelevel(5, format, param);
va_end(param);
}
#endif
#endif
#endif /* DEBUG_TRACE */
/* Connect to a given unix socket. The socket is blocking */
#if ENABLE_CONNECT_UNIX
@@ -281,12 +258,6 @@ 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;
@@ -409,37 +380,20 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
#if DEBUG_TRACE
void printhex(const char * label, const unsigned char * buf, int len) {
int i, j;
int i;
fprintf(stderr, "%s\n", label);
/* for each 16 byte line */
for (j = 0; j < len; j += 16) {
const int linelen = MIN(16, len - j);
/* print hex digits */
for (i = 0; i < 16; i++) {
if (i < linelen) {
fprintf(stderr, "%02x", buf[j+i]);
} else {
fprintf(stderr, " ");
}
// separator between pairs
if (i % 2 ==1) {
fprintf(stderr, " ");
}
for (i = 0; i < len; i++) {
fprintf(stderr, "%02x", buf[i]);
if (i % 16 == 15) {
fprintf(stderr, "\n");
}
/* print characters */
fprintf(stderr, " ");
for (i = 0; i < linelen; i++) {
char c = buf[j+i];
if (!isprint(c)) {
c = '.';
}
fputc(c, stderr);
else if (i % 2 == 1) {
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
void printmpint(const char *label, mp_int *mp) {
@@ -599,28 +553,16 @@ void setnonblocking(int fd) {
}
void disallow_core() {
struct rlimit lim = {0};
if (getrlimit(RLIMIT_CORE, &lim) < 0) {
TRACE(("getrlimit(RLIMIT_CORE) failed"));
}
lim.rlim_cur = 0;
if (setrlimit(RLIMIT_CORE, &lim) < 0) {
TRACE(("setrlimit(RLIMIT_CORE) failed"));
}
struct rlimit lim;
lim.rlim_cur = lim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &lim);
}
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
int m_str_to_uint(const char* str, unsigned int *val) {
unsigned long l;
char *endp;
l = strtoul(str, &endp, 10);
if (endp == str || *endp != '\0') {
/* parse error */
return DROPBEAR_FAILURE;
}
errno = 0;
l = strtoul(str, NULL, 10);
/* The c99 spec doesn't actually seem to define EINVAL, but most platforms
* I've looked at mention it in their manpage */
if ((l == 0 && errno == EINVAL)
@@ -633,24 +575,16 @@ int m_str_to_uint(const char* str, unsigned int *val) {
}
}
/* Returns malloced path. inpath beginning with '~/' expanded,
otherwise returned as-is */
/* Returns malloced path. inpath beginning with '/' is returned as-is,
otherwise home directory is prepended */
char * expand_homedir_path(const char *inpath) {
struct passwd *pw = NULL;
if (strncmp(inpath, "~/", 2) == 0) {
char *homedir = getenv("HOME");
if (!homedir) {
pw = getpwuid(getuid());
if (pw) {
homedir = pw->pw_dir;
}
}
if (homedir) {
int len = strlen(inpath)-2 + strlen(homedir) + 2;
if (inpath[0] != '/') {
pw = getpwuid(getuid());
if (pw && pw->pw_dir) {
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
char *buf = m_malloc(len);
snprintf(buf, len, "%s/%s", homedir, inpath+2);
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
return buf;
}
}
@@ -752,35 +686,3 @@ void fsync_parent_dir(const char* fn) {
m_free(fn_dir);
#endif
}
int fd_read_pending(int fd) {
fd_set fds;
struct timeval timeout;
DROPBEAR_FD_ZERO(&fds);
FD_SET(fd, &fds);
while (1) {
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL, &timeout) < 0) {
if (errno == EINTR) {
continue;
}
return 0;
}
return FD_ISSET(fd, &fds);
}
}
int m_snprintf(char *str, size_t size, const char *format, ...) {
va_list param;
int ret;
va_start(param, format);
ret = vsnprintf(str, size, format, param);
va_end(param);
if (ret < 0) {
dropbear_exit("snprintf failed");
}
return ret;
}

View File

@@ -47,11 +47,8 @@ void dropbear_log(int priority, const char* format, ...) ATTRIB_PRINTF(2,3) ;
void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
#if DEBUG_TRACE
void dropbear_trace1(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace3(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace4(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace5(const char* format, ...) ATTRIB_PRINTF(1,2);
void printhex(const char * label, const unsigned char * buf, int len);
void printmpint(const char *label, mp_int *mp);
void debug_start_net(void);
@@ -73,8 +70,6 @@ void m_close(int fd);
void setnonblocking(int fd);
void disallow_core(void);
int m_str_to_uint(const char* str, unsigned int *val);
/* The same as snprintf() but exits rather than returning negative */
int m_snprintf(char *str, size_t size, const char *format, ...);
/* Used to force mp_ints to be initialised */
#define DEF_MP_INT(X) mp_int X = {0, 0, 0, NULL}
@@ -95,8 +90,6 @@ char * expand_homedir_path(const char *inpath);
void fsync_parent_dir(const char* fn);
int fd_read_pending(int fd);
#if DROPBEAR_MSAN
/* FD_ZERO seems to leave some memory uninitialized. clear it to avoid false positives */
#define DROPBEAR_FD_ZERO(fds) do { memset((fds), 0x0, sizeof(fd_set)); FD_ZERO(fds); } while(0)
@@ -104,12 +97,4 @@ int fd_read_pending(int fd);
#define DROPBEAR_FD_ZERO(fds) FD_ZERO(fds)
#endif
/* dropbearmulti entry points */
int dropbear_main(int argc, char ** argv, const char * multipath);
int cli_main(int argc, char ** argv);
int dropbearkey_main(int argc, char ** argv);
int dropbearconvert_main(int argc, char ** argv);
int scp_main(int argc, char ** argv);
#endif /* DROPBEAR_DBUTIL_H_ */

18
debian/changelog vendored
View File

@@ -1,21 +1,3 @@
dropbear (2022.82-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Fri, 1 Apr 2022 22:51:57 +0800
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.

38
debug.h
View File

@@ -48,43 +48,15 @@
/*#define DEBUG_KEXHASH*/
/*#define DEBUG_RSA*/
/* The level of TRACE() statements */
#define DROPBEAR_VERBOSE_LEVEL 4
/* you don't need to touch this block */
#if DEBUG_TRACE
extern int debug_trace;
#endif
/* Enable debug trace levels.
We can't use __VA_ARGS_ here because Dropbear supports
old ~C89 compilers */
/* Default is to discard output ... */
#define DEBUG1(X)
#define DEBUG2(X)
#define DEBUG3(X)
#define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/
#define TRACE(X)
#define TRACE2(X)
/* ... unless DEBUG_TRACE is high enough */
#if (DEBUG_TRACE>=1)
#undef DEBUG1
#define DEBUG1(X) dropbear_trace1 X;
#endif
#if (DEBUG_TRACE>=2)
#undef DEBUG2
#define DEBUG2(X) dropbear_trace2 X;
#endif
#if (DEBUG_TRACE>=3)
#undef DEBUG3
#define DEBUG3(X) dropbear_trace3 X;
#endif
#if (DEBUG_TRACE>=4)
#undef TRACE
#define TRACE(X) dropbear_trace4 X;
#endif
#if (DEBUG_TRACE>=5)
#undef TRACE2
#define TRACE2(X) dropbear_trace5 X;
#endif
#endif /*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. */

View File

@@ -6,7 +6,7 @@
default_options.h documents compile-time options, and provides default values.
Local customisation should be added to localoptions.h which is
used if it exists in the build directory. Options defined there will override
used if it exists in the build directory. Options defined there will override
any options in this file.
Options can also be defined with -DDROPBEAR_XXX=[0,1] in Makefile CFLAGS
@@ -18,9 +18,7 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Listen on all interfaces */
#define DROPBEAR_DEFADDRESS ""
/* Default hostkey paths - these can be specified on the command line.
* Homedir is prepended if path begins with ~/
*/
/* Default hostkey paths - these can be specified on the command line */
#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"
@@ -39,18 +37,8 @@ IMPORTANT: Some options will require "make clean" after changes */
#define NON_INETD_MODE 1
#define INETD_MODE 1
/* By default Dropbear will re-execute itself for each incoming connection so
that memory layout may be re-randomised (ASLR) - exploiting
vulnerabilities becomes harder. Re-exec causes slightly more memory use
per connection.
This option is ignored on non-Linux platforms at present */
#define DROPBEAR_REEXEC 1
/* Include verbose debug output, enabled with -v at runtime (repeat to increase).
* define which level of debug output you compile in
* TRACE1 - TRACE3 = approx 4 Kb (connection, remote identity, algos, auth type info)
* TRACE4 = approx 17 Kb (detailed before connection)
* TRACE5 = approx 8 Kb (detailed after connection) */
/* Include verbose debug output, enabled with -v at runtime.
* This will add a reasonable amount to your executable size. */
#define DEBUG_TRACE 0
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
@@ -78,7 +66,7 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Note: Both DROPBEAR_CLI_PROXYCMD and DROPBEAR_CLI_NETCAT must be set to
* allow multihop dbclient connections */
/* Allow using -J <proxycommand> to run the connection through a
/* Allow using -J <proxycommand> to run the connection through a
pipe to a program, rather the normal TCP connection */
#define DROPBEAR_CLI_PROXYCMD 1
@@ -92,11 +80,13 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Encryption - at least one required.
* AES128 should be enabled, some very old implementations might only
* support 3DES.
* Including both AES keysize variants (128 and 256) will result in
* Including both AES keysize variants (128 and 256) will result in
* a minimal size increase */
#define DROPBEAR_AES128 1
#define DROPBEAR_AES256 1
#define DROPBEAR_3DES 0
#define DROPBEAR_TWOFISH256 0
#define DROPBEAR_TWOFISH128 0
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
* generally faster than AES256 on CPU w/o dedicated AES instructions,
@@ -118,7 +108,7 @@ IMPORTANT: Some options will require "make clean" after changes */
* 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,
/* Message integrity. sha2-256 is recommended as a default,
sha1 for compatibility */
#define DROPBEAR_SHA1_HMAC 1
#define DROPBEAR_SHA2_256_HMAC 1
@@ -127,25 +117,18 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Hostkey/public key algorithms - at least one required, these are used
* for hostkey as well as for verifying signatures with pubkey auth.
* Removing either of these won't save very much space.
* RSA is recommended.
* RSA is recommended
* DSS may be necessary to connect to some systems though
* is not recommended for new keys.
* See: RSA_PRIV_FILENAME and DSS_PRIV_FILENAME */
is not recommended for new keys */
#define DROPBEAR_RSA 1
#define DROPBEAR_DSS 1
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64.
* See: ECDSA_PRIV_FILENAME */
* 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.
* See: ED25519_PRIV_FILENAME */
binary size - around 7,5kB on x86-64 */
#define DROPBEAR_ED25519 1
/* SK_ECDSA/SK_ED25519 allows u2f security keys for public key auth.
* This is currently server-only. */
#define DROPBEAR_SK_ECDSA 1
#define DROPBEAR_SK_ED25519 1
/* RSA must be >=1024 */
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
@@ -179,13 +162,13 @@ IMPORTANT: Some options will require "make clean" after changes */
* Small systems should generally include either curve25519 or ecdh for performance.
* curve25519 is less widely supported but is faster
*/
*/
#define DROPBEAR_DH_GROUP14_SHA1 1
#define DROPBEAR_DH_GROUP14_SHA256 1
#define DROPBEAR_DH_GROUP16 0
#define DROPBEAR_CURVE25519 1
#define DROPBEAR_ECDH 1
#define DROPBEAR_DH_GROUP1 0
#define DROPBEAR_DH_GROUP1 1
/* When group1 is enabled it will only be allowed by Dropbear client
not as a server, due to concerns over its strength. Set to 0 to allow
@@ -220,8 +203,7 @@ group1 in Dropbear server too */
* You can't enable both PASSWORD and PAM. */
#define DROPBEAR_SVR_PAM_AUTH 0
/* ~/.ssh/authorized_keys authentication.
* You must define DROPBEAR_SVR_PUBKEY_AUTH in order to use plugins. */
/* ~/.ssh/authorized_keys authentication */
#define DROPBEAR_SVR_PUBKEY_AUTH 1
/* Whether to take public key options in
@@ -237,10 +219,9 @@ group1 in Dropbear server too */
#define DROPBEAR_CLI_PASSWORD_AUTH 1
#define DROPBEAR_CLI_PUBKEY_AUTH 1
/* A default argument for dbclient -i <privatekey>.
* Homedir is prepended if path begins with ~/
*/
#define DROPBEAR_DEFAULT_CLI_AUTHKEY "~/.ssh/id_dropbear"
/* A default argument for dbclient -i <privatekey>.
Homedir is prepended unless path begins with / */
#define DROPBEAR_DEFAULT_CLI_AUTHKEY ".ssh/id_dropbear"
/* Allow specifying the password for dbclient via the DROPBEAR_PASSWORD
* environment variable. */
@@ -275,16 +256,8 @@ group1 in Dropbear server too */
/* -T server option overrides */
#define MAX_AUTH_TRIES 10
/* Delay introduced before closing an unauthenticated session (seconds).
Disabled by default, can be set to say 30 seconds to reduce the speed
of password brute forcing. Note that there is a risk of denial of
service by setting this */
#define UNAUTH_CLOSE_DELAY 0
/* The default file to store the daemon's process ID, for shutdown
* scripts etc. This can be overridden with the -P flag.
* Homedir is prepended if path begins with ~/
*/
scripts etc. This can be overridden with the -P flag */
#define DROPBEAR_PIDFILE "/var/run/dropbear.pid"
/* The command to invoke for xauth when using X11 forwarding.
@@ -292,11 +265,9 @@ group1 in Dropbear server too */
#define XAUTH_COMMAND "/usr/bin/xauth -q"
/* If you want to enable running an sftp server (such as the one included with
* OpenSSH), set the path below and set DROPBEAR_SFTPSERVER.
* The sftp-server program is not provided by Dropbear itself.
* Homedir is prepended if path begins with ~/
*/
/* if you want to enable running an sftp server (such as the one included with
* OpenSSH), set the path below and set DROPBEAR_SFTPSERVER.
* The sftp-server program is not provided by Dropbear itself */
#define DROPBEAR_SFTPSERVER 1
#define SFTPSERVER_PATH "/usr/libexec/sftp-server"
@@ -339,6 +310,5 @@ be overridden at runtime with -I. 0 disables idle timeouts */
/* The default path. This will often get replaced by the shell */
#define DEFAULT_PATH "/usr/bin:/bin"
#define DEFAULT_ROOT_PATH "/usr/sbin:/usr/bin:/sbin:/bin"
#endif /* DROPBEAR_DEFAULT_OPTIONS_H_ */

View File

@@ -35,12 +35,6 @@ Don't fork into background.
.B \-E
Log to standard error rather than syslog.
.TP
.B \-e
Pass on the server environment to all child processes. This is required, for example,
if Dropbear is launched on the fly from a SLURM workload manager. The environment is not
passed by default. Note that this could expose secrets in environment variables from
the calling process - use with caution.
.TP
.B \-m
Don't display the message of the day on login.
.TP
@@ -66,7 +60,7 @@ and TCP
.I port.
If just a port is given listen
on all addresses.
Up to 10 can be specified (default 22 if none specified).
up to 10 can be specified (default 22 if none specified).
.TP
.B \-i
Service program mode.
@@ -92,7 +86,7 @@ Ensure that traffic is transmitted at a certain interval in seconds. This is
useful for working around firewalls or routers that drop connections after
a certain period of inactivity. The trade-off is that a session may be
closed if there is a temporary lapse of network connectivity. A setting
of 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
.TP
.B \-I \fIidle_timeout
Disconnect the session if no traffic is transmitted or received for \fIidle_timeout\fR seconds.
@@ -102,8 +96,7 @@ Set the number of authentication attempts allowed per connection. If unspecified
.TP
.B \-c \fIforced_command
Disregard the command provided by the user and always run \fIforced_command\fR. This also
overrides any authorized_keys command= option. The original command is saved in the
SSH_ORIGINAL_COMMAND environment variable (see below).
overrides any authorized_keys command= option.
.TP
.B \-V
Print the version
@@ -140,10 +133,6 @@ Don't allow X11 forwarding for this connection
Disable PTY allocation. Note that a user can still obtain most of the
same functionality with other means even if no-pty is set.
.TP
.B restrict
Applies all the no- restrictions listed above.
.TP
.B command=\fR"\fIforced_command\fR"
Disregard the command provided by the user and always run \fIforced_command\fR.

View File

@@ -9,7 +9,7 @@ dropbearconvert \- convert between Dropbear and OpenSSH private key formats
.I output_file
.SH DESCRIPTION
.B Dropbear
and
and
.B OpenSSH
SSH implementations have different private key formats.
.B dropbearconvert
@@ -24,15 +24,15 @@ first.
.SH ARGUMENTS
.TP
.I input_type
Either
Either
.I dropbear
or
or
.I openssh
.TP
.I output_type
Either
Either
.I dropbear
or
or
.I openssh
.TP
.I input_file
@@ -40,15 +40,6 @@ An existing Dropbear or OpenSSH private key file
.TP
.I output_file
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
.SH SUPPORTED FORMATS
.B dropbearconvert
can read OpenSSH format files, and older PEM format files (
.B ssh-keygen
.I -m PEM
).
.B dropbearconvert
will write OpenSSH format files, usable with OpenSSH 6.5 and later.
Reading OpenSSH format DSS files or PKCS8 files is not currently supported.
.SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
.SH AUTHOR

View File

@@ -69,7 +69,7 @@ int main(int argc, char ** argv) {
#if DEBUG_TRACE
/* It's hard for it to get in the way _too_ much */
debug_trace = DROPBEAR_VERBOSE_LEVEL;
debug_trace = 1;
#endif
/* get the commandline options */

View File

@@ -195,7 +195,7 @@ int main(int argc, char ** argv) {
break;
#if DEBUG_TRACE
case 'v':
debug_trace = DROPBEAR_VERBOSE_LEVEL;
debug_trace = 1;
break;
#endif
default:
@@ -309,7 +309,8 @@ static int printpubfile(const char* filename) {
err = DROPBEAR_SUCCESS;
out:
buf_burn_free(buf);
buf_burn(buf);
buf_free(buf);
buf = NULL;
if (key) {
sign_key_free(key);
@@ -341,7 +342,7 @@ static void printpubkey(sign_key * key, int keytype) {
err = base64_encode(buf_getptr(buf, len), len, base64key, &base64len);
if (err != CRYPT_OK) {
dropbear_exit("base64 failed");
fprintf(stderr, "base64 failed");
}
typestring = signkey_name_from_type(keytype, NULL);

23
ecdsa.c
View File

@@ -81,25 +81,18 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
struct dropbear_ecc_curve **curve;
ecc_key *new_key = NULL;
/* string "ecdsa-sha2-[identifier]" or "sk-ecdsa-sha2-nistp256@openssh.com" */
/* string "ecdsa-sha2-[identifier]" */
key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
/* string "[identifier]" */
identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
if (strcmp (key_ident, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) {
if (strcmp (identifier, "nistp256") != 0) {
TRACE(("mismatching identifiers"))
goto out;
}
} else {
if (key_ident_len != identifier_len + strlen ("ecdsa-sha2-")) {
TRACE(("Bad identifier lengths"))
goto out;
}
if (memcmp(&key_ident[strlen ("ecdsa-sha2-")], identifier, identifier_len) != 0) {
TRACE(("mismatching identifiers"))
goto out;
}
if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
TRACE(("Bad identifier lengths"))
goto out;
}
if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) {
TRACE(("mismatching identifiers"))
goto out;
}
for (curve = dropbear_ecc_curves; *curve; curve++) {

View File

@@ -38,25 +38,14 @@
* 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,
enum signkey_type expect_keytype) {
int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) {
unsigned int len, typelen;
char *keytype = NULL;
enum signkey_type buf_keytype;
unsigned int len;
TRACE(("enter buf_get_ed25519_pub_key"))
dropbear_assert(key != NULL);
/* consume and check the key string */
keytype = buf_getstring(buf, &typelen);
buf_keytype = signkey_type_from_name(keytype, typelen);
m_free(keytype);
if (buf_keytype != expect_keytype) {
TRACE(("leave buf_get_ed25519_pub_key: mismatch key type"))
return DROPBEAR_FAILURE;
}
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
len = buf_getint(buf);
if (len != CURVE25519_LEN || buf->len - buf->pos < len) {

View File

@@ -27,7 +27,6 @@
#include "includes.h"
#include "buffer.h"
#include "signkey.h"
#if DROPBEAR_ED25519
@@ -44,8 +43,7 @@ void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const bu
#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,
enum signkey_type expect_keytype);
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);

209
fuzz-common.c Normal file
View File

@@ -0,0 +1,209 @@
#include "includes.h"
#include "includes.h"
#include "fuzz.h"
#include "dbutil.h"
#include "runopts.h"
#include "crypto_desc.h"
#include "session.h"
#include "dbrandom.h"
#include "bignum.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);
void fuzz_common_setup(void) {
fuzz.fuzzing = 1;
fuzz.wrapfds = 1;
fuzz.do_jmp = 1;
fuzz.input = m_malloc(sizeof(buffer));
_dropbear_log = fuzz_dropbear_log;
crypto_init();
fuzz_seed();
/* let any messages get flushed */
setlinebuf(stdout);
}
int fuzz_set_input(const uint8_t *Data, size_t Size) {
fuzz.input->data = (unsigned char*)Data;
fuzz.input->size = Size;
fuzz.input->len = Size;
fuzz.input->pos = 0;
memset(&ses, 0x0, sizeof(ses));
memset(&svr_ses, 0x0, sizeof(svr_ses));
wrapfd_setup();
fuzz_seed();
return DROPBEAR_SUCCESS;
}
#if DEBUG_TRACE
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
if (debug_trace) {
char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param);
fprintf(stderr, "%s\n", printbuf);
}
}
#else
static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
/* No print */
}
#endif /* DEBUG_TRACE */
void fuzz_svr_setup(void) {
fuzz_common_setup();
_dropbear_exit = svr_dropbear_exit;
char *argv[] = {
"-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) {
#include "fuzz-hostkeys.c"
buffer *b = buf_new(3000);
enum signkey_type type;
TRACE(("load fixed hostkeys"))
svr_opts.hostkey = new_sign_key();
buf_setlen(b, 0);
buf_putbytes(b, keyr, keyr_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_RSA;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed rsa hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keyd, keyd_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_DSS;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed dss hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keye, keye_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
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);
}
void fuzz_kex_fakealgos(void) {
ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
}
void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
if (local_host) {
*local_host = m_strdup("fuzzlocalhost");
}
if (local_port) {
*local_port = m_strdup("1234");
}
if (remote_host) {
*remote_host = m_strdup("fuzzremotehost");
}
if (remote_port) {
*remote_port = m_strdup("9876");
}
}
/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
void fuzz_fake_send_kexdh_reply(void) {
assert(!ses.dh_K);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
mp_set_ul(ses.dh_K, 12345678uL);
finish_kexhashbuf();
}
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
static int once = 0;
if (!once) {
fuzz_svr_setup();
fuzz.skip_kexmaths = skip_kexmaths;
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
/*
get prefix. 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 = 20;
wrapfd_add(fakesock, fuzz.input, PLAIN);
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
svr_session(fakesock, fakesock);
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++) {
if (strcmp(t->name, name) == 0) {
return t->data;
}
}
assert(0);
}

View File

@@ -7,19 +7,15 @@ extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
int main(int argc, char ** argv) {
int i;
buffer *input = buf_new(100000);
int quiet = 0;
for (i = 1; i < argc; i++) {
printf("arg %s\n", argv[i]);
#if DEBUG_TRACE
if (strcmp(argv[i], "-v") == 0) {
debug_trace++;
fprintf(stderr, "debug level -> %d\n", debug_trace);
debug_trace = 1;
TRACE(("debug printing on"))
}
#endif
if (strcmp(argv[i], "-q") == 0) {
printf("Running quiet\n");
quiet = 1;
}
}
int old_fuzz_wrapfds = 0;
@@ -34,19 +30,12 @@ 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;
if (!quiet) {
printf("Running %s once \n", fn);
}
printf("Running %s once \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);
if (!quiet) {
printf("Running %s twice \n", fn);
}
printf("Running %s twice \n", fn);
LLVMFuzzerTestOneInput(input->data, input->len);
if (!quiet) {
printf("Done %s\n", fn);
}
printf("Done %s\n", fn);
/* Disable wrapfd so it won't interfere with buf_readfile() above */
old_fuzz_wrapfds = fuzz.wrapfds;
@@ -57,10 +46,3 @@ int main(int argc, char ** argv) {
return 0;
}
// Just to let it link
size_t LLVMFuzzerMutate(uint8_t *UNUSED(Data), size_t UNUSED(Size), size_t UNUSED(MaxSize)) {
printf("standalone fuzzer harness shouldn't call LLVMFuzzerMutate");
abort();
return 0;
}

View File

@@ -1,6 +1,5 @@
/* To be included in fuzz-common.c */
static unsigned char keyr[] = {
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,
@@ -70,8 +69,8 @@ static unsigned char keyr[] = {
0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
0xa3
};
static unsigned int keyr_len = 805;
static unsigned char keye[] = {
unsigned int keyr_len = 805;
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,
@@ -85,8 +84,8 @@ static unsigned char keye[] = {
0x3c, 0x58, 0x28, 0x70, 0x9b, 0x23, 0x39, 0x51, 0xd7, 0xbc, 0xa7, 0x1a,
0xf5, 0xb4, 0x23, 0xd3, 0xf6, 0x17, 0xa6, 0x9c, 0x02
};
static unsigned int keye_len = 141;
static unsigned char keyd[] = {
unsigned int keye_len = 141;
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,
@@ -127,8 +126,8 @@ static unsigned char keyd[] = {
0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
0xf9, 0x39
};
static unsigned int keyd_len = 458;
static unsigned char keyed25519[] = {
unsigned int keyd_len = 458;
unsigned char keyed25519[] = {
0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
@@ -137,4 +136,4 @@ static unsigned char keyed25519[] = {
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;
unsigned int keyed25519_len = 83;

View File

@@ -17,33 +17,25 @@ 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] = {{UNUSED, 0, 0}};
static int wrapfd_maxfd = -1;
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 unsigned short rand_state[3];
static buffer *input_buf;
static int devnull_fd = -1;
static void wrapfd_remove(int fd);
void wrapfd_setup(buffer *buf) {
void wrapfd_setup(void) {
TRACE(("wrapfd_setup"))
// clean old ones
int i;
for (i = 0; i <= wrapfd_maxfd; i++) {
if (wrap_fds[i].mode != UNUSED) {
wrapfd_remove(i);
}
}
wrapfd_maxfd = -1;
nused = 0;
memset(wrap_fds, 0x0, sizeof(wrap_fds));
memset(wrap_used, 0x0, sizeof(wrap_used));
memset(rand_state, 0x0, sizeof(rand_state));
wrapfd_setseed(50);
input_buf = buf;
}
void wrapfd_setseed(uint32_t seed) {
@@ -51,55 +43,39 @@ void wrapfd_setseed(uint32_t seed) {
nrand48(rand_state);
}
int wrapfd_new_fuzzinput() {
if (devnull_fd == -1) {
devnull_fd = open("/dev/null", O_RDONLY);
assert(devnull_fd != -1);
}
int fd = dup(devnull_fd);
assert(fd != -1);
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);
wrap_fds[fd].mode = COMMONBUF;
assert(buf || mode == RANDOMIN);
wrap_fds[fd].mode = mode;
wrap_fds[fd].buf = buf;
wrap_fds[fd].closein = 0;
wrap_fds[fd].closeout = 0;
wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
wrap_used[nused] = fd;
return fd;
nused++;
}
int wrapfd_new_dummy() {
if (devnull_fd == -1) {
devnull_fd = open("/dev/null", O_RDONLY);
assert(devnull_fd != -1);
}
int fd = dup(devnull_fd);
if (fd == -1) {
return -1;
}
if (fd > IOWRAP_MAXFD) {
close(fd);
errno = EMFILE;
return -1;
}
assert(wrap_fds[fd].mode == UNUSED);
wrap_fds[fd].mode = DUMMY;
wrap_fds[fd].closein = 0;
wrap_fds[fd].closeout = 0;
wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
return fd;
}
static void wrapfd_remove(int fd) {
void wrapfd_remove(int fd) {
unsigned int i, j;
TRACE(("wrapfd_remove %d", fd))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode != UNUSED);
wrap_fds[fd].mode = UNUSED;
close(fd);
/* 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--;
}
int wrapfd_close(int fd) {
@@ -113,6 +89,7 @@ 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);
@@ -138,18 +115,18 @@ int wrapfd_read(int fd, void *out, size_t count) {
return -1;
}
if (input_buf && wrap_fds[fd].mode == COMMONBUF) {
maxread = MIN(input_buf->len - input_buf->pos, count);
buf = wrap_fds[fd].buf;
if (buf) {
maxread = MIN(buf->len - buf->pos, count);
/* returns 0 if buf is EOF, as intended */
if (maxread > 0) {
maxread = nrand48(rand_state) % maxread + 1;
}
memcpy(out, buf_getptr(input_buf, maxread), maxread);
buf_incrpos(input_buf, maxread);
memcpy(out, buf_getptr(buf, maxread), maxread);
buf_incrpos(buf, maxread);
return maxread;
}
// return fixed output, of random length
maxread = MIN(MAX_RANDOM_IN, count);
maxread = nrand48(rand_state) % maxread + 1;
memset(out, 0xef, maxread);
@@ -198,6 +175,8 @@ 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);
}
@@ -265,15 +244,3 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
return ret;
}
int fuzz_kill(pid_t pid, int sig) {
if (fuzz.fuzzing) {
TRACE(("fuzz_kill ignoring pid %d signal %d", (pid), sig))
if (sig >= 0) {
return 0;
} else {
errno = EINVAL;
return -1;
}
}
return kill(pid, sig);
}

View File

@@ -1,20 +1,19 @@
#ifndef FUZZ_WRAPFD_H
#define FUZZ_WRAPFD_H
#include "includes.h"
#include "buffer.h"
enum wrapfd_mode {
UNUSED = 0,
COMMONBUF, // using the common buffer
DUMMY, // reads return fixed output, of random length
PLAIN,
INPROGRESS,
RANDOMIN
};
// buf is a common buffer read by all wrapped FDs. doesn't take ownership of buf
void wrapfd_setup(buffer *buf);
void wrapfd_setup(void);
void wrapfd_setseed(uint32_t seed);
int wrapfd_new_fuzzinput(void);
int wrapfd_new_dummy(void);
// doesn't take ownership of buf. buf is optional.
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode);
// called via #defines for read/write/select
int wrapfd_read(int fd, void *out, size_t count);
@@ -22,6 +21,5 @@ int wrapfd_write(int fd, const void* in, size_t count);
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
int wrapfd_close(int fd);
int fuzz_kill(pid_t pid, int sig);
#endif // FUZZ_WRAPFD_H

60
fuzz.h
View File

@@ -8,24 +8,17 @@
#include "includes.h"
#include "buffer.h"
#include "algo.h"
#include "netio.h"
#include "fuzz-wrapfd.h"
// once per process
void fuzz_common_setup(void);
void fuzz_svr_setup(void);
void fuzz_cli_setup(void);
// constructor attribute so it runs before main(), including
// in non-fuzzing mode.
void fuzz_early_setup(void) __attribute__((constructor));
// 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_server(const uint8_t *Data, size_t Size, int skip_kexmaths, int postauth);
int fuzz_run_client(const uint8_t *Data, size_t Size, int skip_kexmaths);
int fuzz_run_preauth(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
@@ -34,18 +27,10 @@ int fuzz_checkpubkey_line(buffer* line, int line_num, char* filename,
const char* algo, unsigned int algolen,
const unsigned char* keyblob, unsigned int keybloblen);
extern const char * const * fuzz_signkey_names;
void fuzz_seed(const unsigned char* dat, unsigned int len);
void fuzz_svr_hook_preloop(void);
int fuzz_dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
// helpers
void fuzz_seed(void);
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
@@ -54,7 +39,6 @@ void fuzz_dump(const unsigned char* data, size_t len);
#define write(fd, buf, count) wrapfd_write(fd, buf, count)
#define read(fd, buf, count) wrapfd_read(fd, buf, count)
#define close(fd) wrapfd_close(fd)
#define kill(pid, sig) fuzz_kill(pid, sig)
#endif // FUZZ_SKIP_WRAP
struct dropbear_fuzz_options {
@@ -68,47 +52,21 @@ struct dropbear_fuzz_options {
// whether to skip slow bignum maths
int skip_kexmaths;
// whether is svr_postauth mode
int svr_postauth;
// dropbear_exit() jumps back
int do_jmp;
sigjmp_buf jmp;
// write out decrypted session data to this FD if it is set
// flag - this needs to be set manually in cli-main.c etc
int dumping;
// the file descriptor
int recv_dumpfd;
// avoid filling fuzzing logs, this points to /dev/null
FILE *fake_stderr;
uid_t pw_uid;
gid_t pw_gid;
char* pw_name;
char* pw_dir;
char* pw_shell;
char* pw_passwd;
};
extern struct dropbear_fuzz_options fuzz;
/* guard for when fuzz.h is included by fuzz-common.c */
#ifndef FUZZ_NO_REPLACE_STDERR
/* This is a bodge but seems to work.
glibc stdio.h has the comment
"C89/C99 say they're macros. Make them happy." */
/* OS X has it as a macro */
#ifdef stderr
#undef stderr
#endif
#define stderr (fuzz.fake_stderr)
#endif /* FUZZ_NO_REPLACE_STDERR */
struct passwd* fuzz_getpwuid(uid_t uid);
struct passwd* fuzz_getpwnam(const char *login);
/* guard for when fuzz.h is included by fuzz-common.c */
#ifndef FUZZ_NO_REPLACE_GETPW
#define getpwnam(x) fuzz_getpwnam(x)
#define getpwuid(x) fuzz_getpwuid(x)
#endif // FUZZ_NO_REPLACE_GETPW
#endif /* DROPBEAR_FUZZ */
#endif // DROPBEAR_FUZZ
#endif /* DROPBEAR_FUZZ_H */

View File

@@ -1,398 +0,0 @@
#define FUZZ_NO_REPLACE_STDERR
#define FUZZ_NO_REPLACE_GETPW
#include "includes.h"
#include "includes.h"
#include "dbutil.h"
#include "runopts.h"
#include "crypto_desc.h"
#include "session.h"
#include "dbrandom.h"
#include "bignum.h"
#include "atomicio.h"
#include "fuzz-wrapfd.h"
#include "fuzz.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);
// This runs automatically before main, due to contructor attribute in fuzz.h
void fuzz_early_setup(void) {
/* Set stderr to point to normal stderr by default */
fuzz.fake_stderr = stderr;
}
void fuzz_common_setup(void) {
disallow_core();
fuzz.fuzzing = 1;
fuzz.wrapfds = 1;
fuzz.do_jmp = 1;
fuzz.input = m_malloc(sizeof(buffer));
_dropbear_log = fuzz_dropbear_log;
crypto_init();
fuzz_seed("start", 5);
/* let any messages get flushed */
setlinebuf(stdout);
#if DEBUG_TRACE
if (debug_trace)
{
fprintf(stderr, "Dropbear fuzzer: -v specified, not disabling stderr output\n");
}
else
#endif
if (getenv("DROPBEAR_KEEP_STDERR")) {
fprintf(stderr, "Dropbear fuzzer: DROPBEAR_KEEP_STDERR, not disabling stderr output\n");
}
else
{
fprintf(stderr, "Dropbear fuzzer: Disabling stderr output\n");
fuzz.fake_stderr = fopen("/dev/null", "w");
assert(fuzz.fake_stderr);
}
}
int fuzz_set_input(const uint8_t *Data, size_t Size) {
fuzz.input->data = (unsigned char*)Data;
fuzz.input->size = Size;
fuzz.input->len = Size;
fuzz.input->pos = 0;
memset(&ses, 0x0, sizeof(ses));
memset(&svr_ses, 0x0, sizeof(svr_ses));
memset(&cli_ses, 0x0, sizeof(cli_ses));
wrapfd_setup(fuzz.input);
// printhex("input", fuzz.input->data, fuzz.input->len);
fuzz_seed(fuzz.input->data, MIN(fuzz.input->len, 16));
return DROPBEAR_SUCCESS;
}
#if DEBUG_TRACE
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
if (debug_trace) {
char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param);
fprintf(stderr, "%s\n", printbuf);
}
}
#else
static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
/* No print */
}
#endif /* DEBUG_TRACE */
void fuzz_svr_setup(void) {
fuzz_common_setup();
_dropbear_exit = svr_dropbear_exit;
char *argv[] = {
"dropbear",
"-E",
};
int argc = sizeof(argv) / sizeof(*argv);
svr_getopts(argc, argv);
load_fixed_hostkeys();
}
void fuzz_svr_hook_preloop() {
if (fuzz.svr_postauth) {
ses.authstate.authdone = 1;
fill_passwd("root");
}
}
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;
TRACE(("load fixed hostkeys"))
svr_opts.hostkey = new_sign_key();
buf_setlen(b, 0);
buf_putbytes(b, keyr, keyr_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_RSA;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed rsa hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keyd, keyd_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_DSS;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed dss hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keye, keye_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
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);
}
void fuzz_kex_fakealgos(void) {
ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
ses.newkeys->recv.algo_mac = &dropbear_nohash;
}
void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
if (local_host) {
*local_host = m_strdup("fuzzlocalhost");
}
if (local_port) {
*local_port = m_strdup("1234");
}
if (remote_host) {
*remote_host = m_strdup("fuzzremotehost");
}
if (remote_port) {
*remote_port = m_strdup("9876");
}
}
/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
void fuzz_fake_send_kexdh_reply(void) {
assert(!ses.dh_K);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
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_dummy();
*ret_readfd = wrapfd_new_dummy();
if (ret_errfd) {
*ret_errfd = wrapfd_new_dummy();
}
if (*ret_writefd == -1 || *ret_readfd == -1 || (ret_errfd && *ret_errfd == -1)) {
m_close(*ret_writefd);
m_close(*ret_readfd);
if (ret_errfd) {
m_close(*ret_errfd);
}
return DROPBEAR_FAILURE;
} else {
*ret_pid = 999;
return DROPBEAR_SUCCESS;
}
}
/* Fake dropbear_listen, always returns failure for now.
TODO make it sometimes return success with wrapfd_new_dummy() sockets.
Making the listeners fake a new incoming connection will be harder. */
/* Listen on address:port.
* Special cases are address of "" listening on everything,
* and address of NULL listening on localhost only.
* Returns the number of sockets bound on success, or -1 on failure. On
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
int fuzz_dropbear_listen(const char* UNUSED(address), const char* UNUSED(port),
int *UNUSED(socks), unsigned int UNUSED(sockcount), char **errstring, int *UNUSED(maxfd)) {
if (errstring) {
*errstring = m_strdup("fuzzing can't listen (yet)");
}
return -1;
}
int fuzz_run_server(const uint8_t *Data, size_t Size, int skip_kexmaths, int postauth) {
static int once = 0;
if (!once) {
fuzz_svr_setup();
fuzz.skip_kexmaths = skip_kexmaths;
once = 1;
}
fuzz.svr_postauth = postauth;
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
uint32_t wrapseed;
genrandom((void*)&wrapseed, sizeof(wrapseed));
wrapfd_setseed(wrapseed);
int fakesock = wrapfd_new_fuzzinput();
m_malloc_set_epoch(1);
fuzz.do_jmp = 1;
if (setjmp(fuzz.jmp) == 0) {
svr_session(fakesock, fakesock);
m_malloc_free_epoch(1, 0);
} else {
fuzz.do_jmp = 0;
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
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;
}
// Allow to proceed sooner
ses.kexstate.donefirstkex = 1;
uint32_t wrapseed;
genrandom((void*)&wrapseed, sizeof(wrapseed));
wrapfd_setseed(wrapseed);
int fakesock = wrapfd_new_fuzzinput();
m_malloc_set_epoch(1);
fuzz.do_jmp = 1;
if (setjmp(fuzz.jmp) == 0) {
cli_session(fakesock, fakesock, NULL, 0);
m_malloc_free_epoch(1, 0);
} else {
fuzz.do_jmp = 0;
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++) {
if (strcmp(t->name, name) == 0) {
return t->data;
}
}
assert(0);
}
void fuzz_dump(const unsigned char* data, size_t len) {
if (fuzz.dumping) {
TRACE(("dump %zu", len))
assert(atomicio(vwrite, fuzz.recv_dumpfd, (void*)data, len) == len);
}
}
static struct passwd pwd_root = {
.pw_name = "root",
.pw_passwd = "!",
.pw_uid = 0,
.pw_gid = 0,
.pw_dir = "/root",
.pw_shell = "/bin/sh",
};
static struct passwd pwd_other = {
.pw_name = "other",
.pw_passwd = "!",
.pw_uid = 100,
.pw_gid = 100,
.pw_dir = "/home/other",
.pw_shell = "/bin/sh",
};
/* oss-fuzz runs fuzzers under minijail, without /etc/passwd.
We provide sufficient values for the fuzzers to run */
struct passwd* fuzz_getpwnam(const char *login) {
if (!fuzz.fuzzing) {
return getpwnam(login);
}
if (strcmp(login, pwd_other.pw_name) == 0) {
return &pwd_other;
}
if (strcmp(login, pwd_root.pw_name) == 0) {
return &pwd_root;
}
return NULL;
}
struct passwd* fuzz_getpwuid(uid_t uid) {
if (!fuzz.fuzzing) {
return getpwuid(uid);
}
if (uid == pwd_other.pw_uid) {
return &pwd_other;
}
if (uid == pwd_root.pw_uid) {
return &pwd_root;
}
return NULL;
}

View File

@@ -1,306 +0,0 @@
/* A mutator/crossover for SSH protocol streams.
Attempts to mutate each SSH packet individually, keeping
lengths intact.
It will prepend a SSH-2.0-dbfuzz\r\n version string.
Linking this file to a binary will make libfuzzer pick up the custom mutator.
Care is taken to avoid memory allocation which would otherwise
slow exec/s substantially */
#include "fuzz.h"
#include "dbutil.h"
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
static const char* FIXED_VERSION = "SSH-2.0-dbfuzz\r\n";
static const char* FIXED_IGNORE_MSG =
"\x00\x00\x00\x10\x06\x02\x00\x00\x00\x00\x11\x22\x33\x44\x55\x66";
static const unsigned int FIXED_IGNORE_MSG_LEN = 16;
#define MAX_FUZZ_PACKETS 500
/* XXX This might need tuning */
static const size_t MAX_OUT_SIZE = 50000;
/* Splits packets from an input stream buffer "inp".
The initial SSH version identifier is discarded.
If packets are not recognised it will increment until an uint32 of valid
packet length is found. */
/* out_packets an array of num_out_packets*buffer, each of size RECV_MAX_PACKET_LEN */
static void fuzz_get_packets(buffer *inp, buffer **out_packets, unsigned int *num_out_packets) {
/* Skip any existing banner. Format is
SSH-protoversion-softwareversion SP comments CR LF
so we look for SSH-2. then a subsequent LF */
unsigned char* version = memmem(inp->data, inp->len, "SSH-2.", strlen("SSH-2."));
if (version) {
buf_incrpos(inp, version - inp->data);
unsigned char* newline = memchr(&inp->data[inp->pos], '\n', inp->len - inp->pos);
if (newline) {
buf_incrpos(inp, newline - &inp->data[inp->pos]+1);
} else {
/* Give up on any version string */
buf_setpos(inp, 0);
}
}
const unsigned int max_out_packets = *num_out_packets;
*num_out_packets = 0;
while (1) {
if (inp->pos + 4 > inp->len) {
/* End of input */
break;
}
if (*num_out_packets >= max_out_packets) {
/* End of output */
break;
}
/* Read packet */
unsigned int packet_len = buf_getint(inp);
if (packet_len > RECV_MAX_PACKET_LEN-4) {
/* Bad length, try skipping a single byte */
buf_decrpos(inp, 3);
continue;
}
packet_len = MIN(packet_len, inp->len - inp->pos);
/* Check the packet length makes sense */
if (packet_len >= MIN_PACKET_LEN-4) {
/* Copy to output buffer. We're reusing buffers */
buffer* new_packet = out_packets[*num_out_packets];
(*num_out_packets)++;
buf_setlen(new_packet, 0);
// packet_len doesn't include itself
buf_putint(new_packet, packet_len);
buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len);
}
buf_incrpos(inp, packet_len);
}
}
/* Mutate a packet buffer in-place.
Returns DROPBEAR_FAILURE if it's too short */
static int buf_llvm_mutate(buffer *buf) {
int ret;
/* Position it after packet_length and padding_length */
const unsigned int offset = 5;
buf_setpos(buf, 0);
buf_incrwritepos(buf, offset);
size_t max_size = buf->size - buf->pos;
size_t new_size = LLVMFuzzerMutate(buf_getwriteptr(buf, max_size),
buf->len - buf->pos, max_size);
size_t new_total = new_size + 1 + 4;
// Round down to a block size
new_total = new_total - (new_total % dropbear_nocipher.blocksize);
if (new_total >= 16) {
buf_setlen(buf, new_total);
// Fix up the length fields
buf_setpos(buf, 0);
// packet_length doesn't include itself, does include padding_length byte
buf_putint(buf, new_size+1);
// always just put minimum padding length = 4
buf_putbyte(buf, 4);
ret = DROPBEAR_SUCCESS;
} else {
// instead put a fake packet
buf_setlen(buf, 0);
buf_putbytes(buf, FIXED_IGNORE_MSG, FIXED_IGNORE_MSG_LEN);
ret = DROPBEAR_FAILURE;
}
return ret;
}
/* Persistent buffers to avoid constant allocations */
static buffer *oup;
static buffer *alloc_packetA;
static buffer *alloc_packetB;
static buffer* packets1[MAX_FUZZ_PACKETS];
static buffer* packets2[MAX_FUZZ_PACKETS];
/* Allocate buffers once at startup.
'constructor' here so it runs before dbmalloc's interceptor */
static void alloc_static_buffers() __attribute__((constructor));
static void alloc_static_buffers() {
int i;
oup = buf_new(MAX_OUT_SIZE);
alloc_packetA = buf_new(RECV_MAX_PACKET_LEN);
alloc_packetB = buf_new(RECV_MAX_PACKET_LEN);
for (i = 0; i < MAX_FUZZ_PACKETS; i++) {
packets1[i] = buf_new(RECV_MAX_PACKET_LEN);
}
for (i = 0; i < MAX_FUZZ_PACKETS; i++) {
packets2[i] = buf_new(RECV_MAX_PACKET_LEN);
}
}
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed) {
buf_setlen(alloc_packetA, 0);
buf_setlen(alloc_packetB, 0);
buf_setlen(oup, 0);
unsigned int i;
size_t ret_len;
unsigned short randstate[3] = {0,0,0};
memcpy(randstate, &Seed, sizeof(Seed));
// printhex("mutator input", Data, Size);
/* 0.1% chance straight llvm mutate */
// if (nrand48(randstate) % 1000 == 0) {
// ret_len = LLVMFuzzerMutate(Data, Size, MaxSize);
// // printhex("mutator straight llvm", Data, ret_len);
// return ret_len;
// }
buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0};
buffer *inp = &inp_buf;
/* Parse packets */
unsigned int num_packets = MAX_FUZZ_PACKETS;
buffer **packets = packets1;
fuzz_get_packets(inp, packets, &num_packets);
if (num_packets == 0) {
// Make up a packet, writing direct to the buffer
inp->size = MaxSize;
buf_setlen(inp, 0);
buf_putbytes(inp, FIXED_VERSION, strlen(FIXED_VERSION));
buf_putbytes(inp, FIXED_IGNORE_MSG, FIXED_IGNORE_MSG_LEN);
// printhex("mutator no input", Data, inp->len);
return inp->len;
}
/* Start output */
/* Put a new banner to output */
buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION));
/* Iterate output */
for (i = 0; i < num_packets+1; i++) {
// These are pointers to output
buffer *out_packetA = NULL, *out_packetB = NULL;
buf_setlen(alloc_packetA, 0);
buf_setlen(alloc_packetB, 0);
/* 2% chance each */
const int optA = nrand48(randstate) % 50;
if (optA == 0) {
/* Copy another */
unsigned int other = nrand48(randstate) % num_packets;
out_packetA = packets[other];
// printf("copy another %d / %d len %u\n", other, num_packets, out_packetA->len);
}
if (optA == 1) {
/* Mutate another */
unsigned int other = nrand48(randstate) % num_packets;
out_packetA = alloc_packetA;
buffer *from = packets[other];
buf_putbytes(out_packetA, from->data, from->len);
if (buf_llvm_mutate(out_packetA) == DROPBEAR_FAILURE) {
out_packetA = NULL;
}
// printf("mutate another %d / %d len %u -> %u\n", other, num_packets, from->len, out_packetA->len);
}
if (i < num_packets) {
int optB = nrand48(randstate) % 100;
if (optB == 1) {
/* small chance of drop */
/* Drop it */
//printf("%d drop\n", i);
} else {
/* Odds of modification are proportional to packet position.
First packet has 20% chance, last has 100% chance */
int optC = nrand48(randstate) % 1000;
int mutate_cutoff = MAX(200, (1000 * (i+1) / num_packets));
if (optC < mutate_cutoff) {
// // printf("%d mutate\n", i);
out_packetB = alloc_packetB;
buffer *from = packets[i];
buf_putbytes(out_packetB, from->data, from->len);
if (buf_llvm_mutate(out_packetB) == DROPBEAR_FAILURE) {
out_packetB = from;
}
// printf("mutate self %d / %d len %u -> %u\n", i, num_packets, from->len, out_packetB->len);
} else {
/* Copy as-is */
out_packetB = packets[i];
// printf("%d as-is len %u\n", i, out_packetB->len);
}
}
}
if (out_packetA && oup->len + out_packetA->len <= oup->size) {
buf_putbytes(oup, out_packetA->data, out_packetA->len);
}
if (out_packetB && oup->len + out_packetB->len <= oup->size) {
buf_putbytes(oup, out_packetB->data, out_packetB->len);
}
}
ret_len = MIN(MaxSize, oup->len);
memcpy(Data, oup->data, ret_len);
// printhex("mutator done", Data, ret_len);
return ret_len;
}
size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
const uint8_t *Data2, size_t Size2,
uint8_t *Out, size_t MaxOutSize,
unsigned int Seed) {
unsigned short randstate[3] = {0,0,0};
memcpy(randstate, &Seed, sizeof(Seed));
unsigned int i;
buffer inp_buf1 = {.data = (void*)Data1, .size = Size1, .len = Size1, .pos = 0};
buffer *inp1 = &inp_buf1;
buffer inp_buf2 = {.data = (void*)Data2, .size = Size2, .len = Size2, .pos = 0};
buffer *inp2 = &inp_buf2;
unsigned int num_packets1 = MAX_FUZZ_PACKETS;
fuzz_get_packets(inp1, packets1, &num_packets1);
unsigned int num_packets2 = MAX_FUZZ_PACKETS;
fuzz_get_packets(inp2, packets2, &num_packets2);
// fprintf(stderr, "input 1 %u packets\n", num_packets1);
// printhex("crossover input1", Data1, Size1);
// fprintf(stderr, "input 2 %u packets\n", num_packets2);
// printhex("crossover input2", Data2, Size2);
buf_setlen(oup, 0);
/* Put a new banner to output */
buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION));
if (num_packets1 == 0 && num_packets2 == 0) {
buf_putbytes(oup, FIXED_IGNORE_MSG, FIXED_IGNORE_MSG_LEN);
} else {
unsigned int min_out = MIN(num_packets1, num_packets2);
unsigned int max_out = num_packets1 + num_packets2;
unsigned int num_out = min_out + nrand48(randstate) % (max_out-min_out+1);
for (i = 0; i < num_out; i++) {
unsigned int choose = nrand48(randstate) % (num_packets1 + num_packets2);
buffer *p = NULL;
if (choose < num_packets1) {
p = packets1[choose];
} else {
p = packets2[choose-num_packets1];
}
if (oup->len + p->len <= oup->size) {
buf_putbytes(oup, p->data, p->len);
}
}
}
size_t ret_len = MIN(MaxOutSize, oup->len);
memcpy(Out, oup->data, ret_len);
// printhex("crossover output", Out, ret_len);
return ret_len;
}

View File

@@ -1,6 +0,0 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_server(Data, Size, 1, 1);
}

View File

@@ -1,6 +0,0 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_server(Data, Size, 0, 0);
}

View File

@@ -1,6 +0,0 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_server(Data, Size, 1, 0);
}

View File

@@ -6,30 +6,33 @@
#include "algo.h"
#include "bignum.h"
static struct key_context* keep_newkeys = NULL;
/* An arbitrary limit */
#define NUM_PARAMS 80
static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
static void setup() __attribute__((constructor));
// Perform initial setup here to avoid hitting timeouts on first run
static void setup() {
fuzz_common_setup();
fuzz_svr_setup();
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
curve25519_params[i] = gen_kexcurve25519_param();
}
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run.
TODO move this to the libfuzzer initialiser function instead if the timeout
doesn't apply there */
#define NUM_PARAMS 20
static struct kex_curve25519_param *curve25519_params[NUM_PARAMS];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "curve25519-sha256");
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ED25519;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
curve25519_params[i] = gen_kexcurve25519_param();
}
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}

View File

@@ -6,29 +6,33 @@
#include "algo.h"
#include "bignum.h"
static struct key_context* keep_newkeys = NULL;
#define NUM_PARAMS 80
static struct kex_dh_param *dh_params[NUM_PARAMS];
static void setup() __attribute__((constructor));
// Perform initial setup here to avoid hitting timeouts on first run
static void setup() {
fuzz_common_setup();
fuzz_svr_setup();
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
dh_params[i] = gen_kexdh_param();
}
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run.
TODO move this to the libfuzzer initialiser function instead if the timeout
doesn't apply there */
#define NUM_PARAMS 20
static struct kex_dh_param *dh_params[NUM_PARAMS];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
keep_newkeys->algo_kex = fuzz_get_algo(sshkex, "diffie-hellman-group14-sha256");
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
dh_params[i] = gen_kexdh_param();
}
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}

View File

@@ -6,38 +6,38 @@
#include "algo.h"
#include "bignum.h"
static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters. An arbitrary limit, but will delay startup */
#define NUM_PARAMS 80
static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
static void setup() __attribute__((constructor));
// Perform initial setup here to avoid hitting timeouts on first run
static void setup() {
fuzz_common_setup();
fuzz_svr_setup();
/* ses gets zeroed by fuzz_set_input */
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
assert(ecdh[0]);
assert(ecdh[1]);
assert(ecdh[2]);
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
ses.newkeys->algo_kex = ecdh[i % 3];
ecdh_params[i] = gen_kexecdh_param();
}
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run */
#define NUM_PARAMS 80
static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
/* ses gets zeroed by fuzz_set_input */
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
assert(ecdh[0]);
assert(ecdh[1]);
assert(ecdh[2]);
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
ses.newkeys->algo_kex = ecdh[i % 3];
ecdh_params[i] = gen_kexecdh_param();
}
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;

View File

@@ -1,6 +1,6 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_client(Data, Size, 0);
return fuzz_run_preauth(Data, Size, 0);
}

View File

@@ -1,6 +1,6 @@
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return fuzz_run_client(Data, Size, 1);
return fuzz_run_preauth(Data, Size, 1);
}

View File

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

View File

@@ -4,11 +4,9 @@
result=0
test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://hg.ucc.asn.au/dropbear-fuzzcorpus fuzzcorpus || exit 1
test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
for f in `make list-fuzz-targets`; do
# use xargs to split the too-long argument list
# -q quiet because travis has a logfile limit
echo fuzzcorpus/$f/* | xargs -n 1000 ./$f -q || result=1
./$f fuzzcorpus/$f/* || result=1
done
exit $result

View File

@@ -181,7 +181,8 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
out:
if (buf) {
buf_burn_free(buf);
buf_burn(buf);
buf_free(buf);
}
if (fn_temp) {

View File

@@ -25,6 +25,9 @@
#ifndef DROPBEAR_INCLUDES_H_
#define DROPBEAR_INCLUDES_H_
/* uclibc needs _GNU_SOURCE, maybe other things? */
#define _GNU_SOURCE
#include "options.h"
#include "debug.h"
@@ -127,10 +130,6 @@
#include <sys/random.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#ifdef BUNDLED_LIBTOM
#include "libtomcrypt/src/headers/tomcrypt.h"
#include "libtommath/tommath.h"
@@ -175,8 +174,6 @@ typedef u_int32_t uint32_t;
#include <dlfcn.h>
#endif
extern char** environ;
#include "fake-rfc2553.h"
#include "fuzz.h"

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@ ARFLAGS = r
EXTRALIBS = ../libtommath/libtommath.a
#Compilation flags
LTC_CFLAGS = -Isrc/headers/ -I$(srcdir)/src/headers/ -I../ -I$(srcdir)/../ -DLTC_SOURCE -I../libtommath/ -I$(srcdir)/../libtommath/ $(CFLAGS) $(CPPFLAGS)
LTC_CFLAGS = -Isrc/headers/ -I$(srcdir)/src/headers/ -I../ -I$(srcdir)/../ -DLTC_SOURCE -I../libtommath/ -I$(srcdir)/../libtommath/ $(CFLAGS)
LTC_LDFLAGS = $(LDFLAGS) $(EXTRALIBS)
VERSION=1.18.1

View File

@@ -16,6 +16,12 @@
#if DROPBEAR_AES
#define LTC_RIJNDAEL
#endif
/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
* (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
#if DROPBEAR_TWOFISH
#define LTC_TWOFISH
#define LTC_TWOFISH_SMALL
#endif
#if DROPBEAR_3DES
#define LTC_DES
@@ -50,9 +56,7 @@
#define LTC_SHA256
#endif
#if DROPBEAR_SHA1
#define LTC_SHA1
#endif
#if DROPBEAR_MD5
#define LTC_MD5

View File

@@ -8,7 +8,6 @@ srcdir=@srcdir@
# So that libtommath can include Dropbear headers for options and m_burn()
CFLAGS += -I$(srcdir) -I../libtomcrypt/src/headers/ -I$(srcdir)/../libtomcrypt/src/headers/ -I../ -I$(srcdir)/../
CFLAGS += -Wno-deprecated
CFLAGS += $(CPPFLAGS)
V = 1

View File

@@ -3,13 +3,11 @@
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* Dropbear sets this separately, avoid platform code */
mp_err(*s_mp_rand_source)(void *out, size_t size) = NULL;
mp_err(*s_mp_rand_source)(void *out, size_t size) = s_mp_rand_platform;
void mp_rand_source(mp_err(*source)(void *out, size_t size))
{
/* Dropbear, don't reset to platform if source==NULL */
s_mp_rand_source = source;
s_mp_rand_source = (source == NULL) ? s_mp_rand_platform : source;
}
mp_err mp_rand(mp_int *a, int digits)

View File

@@ -1316,8 +1316,6 @@
#undef BN_S_MP_KARATSUBA_SQR_C
#undef BN_S_MP_TOOM_MUL_C
#undef BN_S_MP_TOOM_SQR_C
/* Dropbear uses its own random source */
#undef BN_S_MP_RAND_PLATFORM_C
#include "dbmalloc.h"
#define MP_MALLOC m_malloc

View File

@@ -139,7 +139,7 @@ struct Listener * get_listener(int type, const void* typedata,
struct Listener* listener;
for (i = 0, listener = ses.listeners[i]; i < ses.listensize; i++) {
if (listener && listener->type == type
if (listener->type == type
&& match(typedata, listener->typedata)) {
return listener;
}

93
netio.c
View File

@@ -20,7 +20,6 @@ struct dropbear_progress_connection {
char* errstring;
char *bind_address, *bind_port;
enum dropbear_prio prio;
};
/* Deallocate a progress connection. Removes from the pending list if iter!=NULL.
@@ -111,7 +110,6 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
ses.maxfd = MAX(ses.maxfd, c->sock);
set_sock_nodelay(c->sock);
set_sock_priority(c->sock, c->prio);
setnonblocking(c->sock);
#if DROPBEAR_CLIENT_TCP_FAST_OPEN
@@ -174,8 +172,8 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
/* Connect via TCP to a host. */
struct dropbear_progress_connection *connect_remote(const char* remotehost, const char* remoteport,
connect_callback cb, void* cb_data,
const char* bind_address, const char* bind_port, enum dropbear_prio prio)
connect_callback cb, void* cb_data,
const char* bind_address, const char* bind_port)
{
struct dropbear_progress_connection *c = NULL;
int err;
@@ -187,17 +185,9 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons
c->sock = -1;
c->cb = cb;
c->cb_data = cb_data;
c->prio = prio;
list_append(&ses.conn_pending, c);
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
c->errstring = m_strdup("fuzzing connect_remote always fails");
return c;
}
#endif
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
@@ -366,7 +356,12 @@ void set_listen_fast_open(int sock) {
void set_sock_priority(int sock, enum dropbear_prio prio) {
int rc;
int val;
#ifdef IPTOS_LOWDELAY
int iptos_val = 0;
#endif
#ifdef HAVE_LINUX_PKT_SCHED_H
int so_prio_val = 0;
#endif
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
@@ -374,51 +369,37 @@ void set_sock_priority(int sock, enum dropbear_prio prio) {
return;
}
#endif
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
#ifdef IP_TOS
/* Set the DSCP field for outbound IP packet priority.
rfc4594 has some guidance to meanings.
We set AF21 as "Low-Latency" class for interactive (tty session,
also handshake/setup packets). Other traffic is left at the default.
OpenSSH at present uses AF21/CS1, rationale
https://cvsweb.openbsd.org/src/usr.bin/ssh/readconf.c#rev1.284
Old Dropbear/OpenSSH and Debian/Ubuntu OpenSSH (at Jan 2022) use
IPTOS_LOWDELAY/IPTOS_THROUGHPUT
DSCP constants are from Linux headers, applicable to other platforms
such as macos.
*/
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
if (prio == DROPBEAR_PRIO_LOWDELAY) {
val = 0x48; /* IPTOS_DSCP_AF21 */
} else {
val = 0; /* default */
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif /* IP_TOS */
#endif
#ifdef HAVE_LINUX_PKT_SCHED_H
/* Set scheduling priority within the local Linux network stack */
if (prio == DROPBEAR_PRIO_LOWDELAY) {
val = TC_PRIO_INTERACTIVE;
} else {
val = 0;
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set SO_PRIORITY (%s)", strerror(errno)))
}
@@ -472,16 +453,8 @@ int dropbear_listen(const char* address, const char* port,
struct linger linger;
int val;
int sock;
uint16_t *allocated_lport_p = NULL;
int allocated_lport = 0;
TRACE(("enter dropbear_listen"))
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return fuzz_dropbear_listen(address, port, socks, sockcount, errstring, maxfd);
}
#endif
TRACE(("enter dropbear_listen"))
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
@@ -517,15 +490,20 @@ int dropbear_listen(const char* address, const char* port,
return -1;
}
/* When listening on server-assigned-port 0
/*
* when listening on server-assigned-port 0
* the assigned ports may differ for address families (v4/v6)
* causing problems for tcpip-forward.
* Caller can do a get_socket_address to discover assigned-port
* hence, use same port for all address families */
allocated_lport = 0;
* causing problems for tcpip-forward
* caller can do a get_socket_address to discover assigned-port
* hence, use same port for all address families
*/
u_int16_t *allocated_lport_p = NULL;
int allocated_lport = 0;
nsock = 0;
for (res = res0; res != NULL && nsock < sockcount;
res = res->ai_next) {
if (allocated_lport > 0) {
if (AF_INET == res->ai_family) {
allocated_lport_p = &((struct sockaddr_in *)res->ai_addr)->sin_port;
@@ -536,8 +514,11 @@ int dropbear_listen(const char* address, const char* port,
}
/* Get a socket */
socks[nsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
socks[nsock] = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
sock = socks[nsock]; /* For clarity */
if (sock < 0) {
err = errno;
TRACE(("socket() failed"))
@@ -561,6 +542,7 @@ int dropbear_listen(const char* address, const char* port,
}
}
#endif
set_sock_nodelay(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
@@ -582,6 +564,7 @@ int dropbear_listen(const char* address, const char* port,
}
*maxfd = MAX(*maxfd, sock);
nsock++;
}

View File

@@ -6,8 +6,9 @@
#include "queue.h"
enum dropbear_prio {
DROPBEAR_PRIO_NORMAL = 0, /* the rest - tcp-fwd, scp, rsync, git, etc */
DROPBEAR_PRIO_LOWDELAY, /* pty shell, x11 */
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
void set_sock_nodelay(int sock);
@@ -29,8 +30,7 @@ typedef void(*connect_callback)(int result, int sock, void* data, const char* er
/* Always returns a progress connection, if it fails it will call the callback at a later point */
struct dropbear_progress_connection * connect_remote (const char* remotehost, const char* remoteport,
connect_callback cb, void *cb_data, const char* bind_address, const char* bind_port,
enum dropbear_prio prio);
connect_callback cb, void *cb_data, const char* bind_address, const char* bind_port);
/* Sets up for select() */
void set_connect_fds(fd_set *writefd);

View File

@@ -344,12 +344,7 @@ void decrypt_packet() {
if (checkmac() != DROPBEAR_SUCCESS) {
dropbear_exit("Integrity error");
}
}
#if DROPBEAR_FUZZ
fuzz_dump(ses.readbuf->data, ses.readbuf->len);
#endif
/* get padding length */
buf_setpos(ses.readbuf, PACKET_PADDING_OFF);

View File

@@ -1,47 +1,22 @@
#!/bin/sh
set -e
if [ "$1" = '--testrel' ]; then
# --testrel won't check changelog version correctness and will build in a temporary dir
TESTREL=1
else
TESTREL=0
VERSION=$(echo '#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp - | sh)
echo Releasing version "$VERSION" ...
if ! head -n1 CHANGES | grep -q $VERSION ; then
echo "CHANGES needs updating"
exit 1
fi
VERSION=$(echo '#include "default_options.h"\n#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp -DHAVE_CRYPT - | sh)
if [ $TESTREL -eq 1 ]; then
echo Making test tarball for "$VERSION" ...
echo Not checking version mismatches.
WORKDIR=$(mktemp -d)
TARSUFFIX="-testrel"
else
echo Releasing version "$VERSION" ...
if ! head -n1 CHANGES | grep -q $VERSION ; then
echo "CHANGES needs updating"
exit 1
fi
if ! head -n1 debian/changelog | grep -q $VERSION ; then
echo "debian/changelog needs updating"
exit 1
fi
WORKDIR=$PWD/..
TARSUFFIX=""
if ! head -n1 debian/changelog | grep -q $VERSION ; then
echo "debian/changelog needs updating"
exit 1
fi
RELDIR=$WORKDIR/dropbear-$VERSION
ARCHIVE=${RELDIR}${TARSUFFIX}.tar.bz2
head -n1 CHANGES
if tar --version | grep -q 'GNU tar'; then
TAR=tar
else
TAR=gtar
fi
#sleep 3
RELDIR=$PWD/../dropbear-$VERSION
ARCHIVE=${RELDIR}.tar.bz2
if test -e $RELDIR; then
echo "$RELDIR exists"
exit 1
@@ -52,33 +27,19 @@ if test -e $ARCHIVE; then
exit 1
fi
if [ -d .hg ]; then
hg archive "$RELDIR" || exit 2
# .hg_archival.txt seems to differ between hg versions, isn't good for reproducibility
rm "$RELDIR/.hg_archival.txt"
elif [ -d .git ]; then
git -c tar.umask=0022 archive --format tar -o /dev/stdout --prefix=dropbear-$VERSION/ HEAD | tar xf - -C $WORKDIR || exit 2
else
echo "This isn't a hg or git checkout"
exit 1
fi
hg archive "$RELDIR" || exit 2
chmod -R a+rX $RELDIR
(cd "$RELDIR" && autoconf && autoheader) || exit 2
RELDATE=$(head -n1 CHANGES | cut -d - -f 2)
# timezone keeps it consistent, choose a plausible release time
RELTIME="22:30:00 +0800"
rm -r "$RELDIR/autom4te.cache" || exit 2
# from https://reproducible-builds.org/docs/archives/
TAROPTS="--sort=name --owner=0 --group=0 --numeric-owner"
(cd "$RELDIR/.." && $TAR cjf $ARCHIVE $TAROPTS --mtime="$RELDATE $RELTIME" `basename "$RELDIR"`) || exit 2
rm "$RELDIR/.hgtags"
(cd "$RELDIR/.." && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
ls -l $ARCHIVE
openssl sha256 $ARCHIVE
echo Done to
echo "$ARCHIVE"
if [ $TESTREL -eq 0 ]; then
echo Sign it with
echo gpg2 --detach-sign -a -u F29C6773 "$ARCHIVE"
fi
echo Sign it with
echo gpg2 --detach-sign -a -u F29C6773 "$ARCHIVE"

View File

@@ -72,15 +72,13 @@ typedef struct svr_runopts {
int forkbg;
/* ports and addresses are arrays of the portcount
/* ports and addresses are arrays of the portcount
listening ports. strings are malloced. */
char *ports[DROPBEAR_MAX_PORTS];
unsigned int portcount;
char *addresses[DROPBEAR_MAX_PORTS];
int inetdmode;
/* Hidden "-2" flag indicates it's re-executing itself */
int reexec_child;
/* Flags indicating whether to use ipv4 and ipv6 */
/* not used yet
@@ -92,6 +90,7 @@ typedef struct svr_runopts {
/* whether to print the MOTD */
int domotd;
#endif
int norootlogin;
#ifdef HAVE_GETGROUPLIST
@@ -131,8 +130,6 @@ typedef struct svr_runopts {
char *pubkey_plugin_options;
#endif
int pass_on_env;
} svr_runopts;
extern svr_runopts svr_opts;
@@ -154,7 +151,6 @@ typedef struct cli_runopts {
int always_accept_key;
int no_hostkey_check;
int no_cmd;
int quiet;
int backgrounded;
int is_subsystem;
#if DROPBEAR_CLI_PUBKEY_AUTH
@@ -163,7 +159,6 @@ typedef struct cli_runopts {
#if DROPBEAR_CLI_ANYTCPFWD
int exit_on_fwd_failure;
#endif
int disable_trivial_auth;
#if DROPBEAR_CLI_REMOTETCPFWD
m_list * remotefwds;
#endif
@@ -197,7 +192,5 @@ void parse_ciphers_macs(void);
#endif
void print_version(void);
void parse_recv_window(const char* recv_window_arg);
int split_address_port(const char* spec, char **first, char ** second);
#endif /* DROPBEAR_RUNOPTS_H_ */

7
scp.c
View File

@@ -185,7 +185,7 @@ arg_setup(char *host, char *remuser, char *cmd)
}
int
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
{
int pin[2], pout[2], reserved[2];
@@ -532,7 +532,8 @@ toremote(char *targ, int argc, char **argv)
bp = xmalloc(len);
(void) snprintf(bp, len, "%s -t %s", cmd, targ);
host = cleanhostname(thost);
if (do_cmd(host, tuser, bp, &remin, &remout) < 0)
if (do_cmd(host, tuser, bp, &remin,
&remout, argc) < 0)
exit(1);
if (response() < 0)
exit(1);
@@ -583,7 +584,7 @@ tolocal(int argc, char **argv)
len = strlen(src) + CMDNEEDS + 20;
bp = xmalloc(len);
(void) snprintf(bp, len, "%s -f %s", cmd, src);
if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) {
(void) xfree(bp);
++errs;
continue;

View File

@@ -64,8 +64,6 @@ void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
void cli_session(int sock_in, int sock_out, struct dropbear_progress_connection *progress, pid_t proxy_cmd_pid) ATTRIB_NORETURN;
void cli_connected(int result, int sock, void* userdata, const char *errstring);
void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
void cli_dropbear_log(int priority, const char* format, va_list param);
void cleantext(char* dirtytext);
void kill_proxy_command(void);
@@ -316,7 +314,6 @@ struct clientsession {
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
for the last type of auth we tried */
int is_trivial_auth;
int ignore_next_auth_response;
#if DROPBEAR_CLI_INTERACT_AUTH
int auth_interact_failed; /* flag whether interactive auth can still

177
signkey.c
View File

@@ -28,8 +28,6 @@
#include "buffer.h"
#include "ssh.h"
#include "ecdsa.h"
#include "sk-ecdsa.h"
#include "sk-ed25519.h"
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
@@ -45,15 +43,9 @@ static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
"ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521",
#if DROPBEAR_SK_ECDSA
"sk-ecdsa-sha2-nistp256@openssh.com",
#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
"ssh-ed25519",
#if DROPBEAR_SK_ED25519
"sk-ssh-ed25519@openssh.com",
#endif /* DROPBEAR_SK_ED25519 */
#endif /* DROPBEAR_ED25519 */
/* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */
};
@@ -188,17 +180,11 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) {
switch (type) {
#if DROPBEAR_ED25519
case DROPBEAR_SIGNKEY_ED25519:
#if DROPBEAR_SK_ED25519
case DROPBEAR_SIGNKEY_SK_ED25519:
#endif
return (void**)&key->ed25519key;
#endif
#if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
#if DROPBEAR_SK_ECDSA
case DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256:
#endif
return (void**)&key->ecckey256;
#endif
#if DROPBEAR_ECC_384
@@ -249,7 +235,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
*type = keytype;
/* Rewind the buffer back before "ssh-rsa" etc */
buf_decrpos(buf, len + 4);
buf_incrpos(buf, -len - 4);
#if DROPBEAR_DSS
if (keytype == DROPBEAR_SIGNKEY_DSS) {
@@ -274,11 +260,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#endif
#if DROPBEAR_ECDSA
if (signkey_is_ecdsa(keytype)
#if DROPBEAR_SK_ECDSA
|| keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256
#endif
) {
if (signkey_is_ecdsa(keytype)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck) {
if (*eck) {
@@ -294,14 +276,10 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#endif
#if DROPBEAR_ED25519
if (keytype == DROPBEAR_SIGNKEY_ED25519
#if DROPBEAR_SK_ED25519
|| keytype == DROPBEAR_SIGNKEY_SK_ED25519
#endif
) {
if (keytype == DROPBEAR_SIGNKEY_ED25519) {
ed25519_key_free(key->ed25519key);
key->ed25519key = m_malloc(sizeof(*key->ed25519key));
ret = buf_get_ed25519_pub_key(buf, key->ed25519key, keytype);
ret = buf_get_ed25519_pub_key(buf, key->ed25519key);
if (ret == DROPBEAR_FAILURE) {
m_free(key->ed25519key);
key->ed25519key = NULL;
@@ -309,19 +287,6 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#endif
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
if (0
#if DROPBEAR_SK_ED25519
|| keytype == DROPBEAR_SIGNKEY_SK_ED25519
#endif
#if DROPBEAR_SK_ECDSA
|| keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256
#endif
) {
key->sk_app = buf_getstring(buf, &key->sk_applen);
}
#endif
TRACE2(("leave buf_get_pub_key"))
return ret;
@@ -351,7 +316,7 @@ int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
*type = keytype;
/* Rewind the buffer back before "ssh-rsa" etc */
buf_decrpos(buf, len + 4);
buf_incrpos(buf, -len - 4);
#if DROPBEAR_DSS
if (keytype == DROPBEAR_SIGNKEY_DSS) {
@@ -436,11 +401,7 @@ void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
}
#endif
#if DROPBEAR_ED25519
if (type == DROPBEAR_SIGNKEY_ED25519
#if DROPBEAR_SK_ED25519
|| type == DROPBEAR_SIGNKEY_SK_ED25519
#endif
) {
if (type == DROPBEAR_SIGNKEY_ED25519) {
buf_put_ed25519_pub_key(pubkeys, key->ed25519key);
}
#endif
@@ -534,52 +495,103 @@ void sign_key_free(sign_key *key) {
#endif
m_free(key->filename);
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
if (key->sk_app) {
m_free(key->sk_app);
}
#endif
m_free(key);
TRACE2(("leave sign_key_free"))
}
static char * sign_key_sha256_fingerprint(const unsigned char* keyblob,
static char hexdig(unsigned char x) {
if (x > 0xf)
return 'X';
if (x < 10)
return '0' + x;
else
return 'a' + x - 10;
}
/* Since we're not sure if we'll have md5 or sha1, we present both.
* MD5 is used in preference, but sha1 could still be useful */
#if DROPBEAR_MD5_HMAC
static char * sign_key_md5_fingerprint(const unsigned char* keyblob,
unsigned int keybloblen) {
char * ret;
hash_state hs;
unsigned char hash[SHA256_HASH_SIZE];
unsigned int b64chars, start;
unsigned long b64size;
const char *prefix = "SHA256:";
int err;
unsigned char hash[MD5_HASH_SIZE];
unsigned int i;
unsigned int buflen;
sha256_init(&hs);
sha256_process(&hs, keyblob, keybloblen);
sha256_done(&hs, hash);
md5_init(&hs);
/* eg "SHA256:P9szN0L2ls6KxkVv7Bppv3asnZCn03rY7Msm/c8+ZgA"
* 256/6 = 42.66 => 43 base64 chars. OpenSSH discards
* base64 padding output. */
start = strlen(prefix);
b64chars = 43;
/* space for discarded b64 padding and null terminator */
b64size = b64chars + 4;
ret = m_malloc(start + b64size);
/* skip the size int of the string - this is a bit messy */
md5_process(&hs, keyblob, keybloblen);
memcpy(ret, prefix, start);
err = base64_encode(hash, SHA256_HASH_SIZE, &ret[start], &b64size);
if (err != CRYPT_OK) {
dropbear_exit("base64 failed");
md5_done(&hs, hash);
/* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 4 + 3*MD5_HASH_SIZE;
ret = (char*)m_malloc(buflen);
memset(ret, 'Z', buflen);
strcpy(ret, "md5 ");
for (i = 0; i < MD5_HASH_SIZE; i++) {
unsigned int pos = 4 + i*3;
ret[pos] = hexdig(hash[i] >> 4);
ret[pos+1] = hexdig(hash[i] & 0x0f);
ret[pos+2] = ':';
}
ret[start + b64chars] = '\0';
ret[buflen-1] = 0x0;
return ret;
}
/* This will return a freshly malloced string */
#else /* use SHA1 rather than MD5 for fingerprint */
static char * sign_key_sha1_fingerprint(const unsigned char* keyblob,
unsigned int keybloblen) {
char * ret;
hash_state hs;
unsigned char hash[SHA1_HASH_SIZE];
unsigned int i;
unsigned int buflen;
sha1_init(&hs);
/* skip the size int of the string - this is a bit messy */
sha1_process(&hs, keyblob, keybloblen);
sha1_done(&hs, hash);
/* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 7 + 3*SHA1_HASH_SIZE;
ret = (char*)m_malloc(buflen);
strcpy(ret, "sha1!! ");
for (i = 0; i < SHA1_HASH_SIZE; i++) {
unsigned int pos = 7 + 3*i;
ret[pos] = hexdig(hash[i] >> 4);
ret[pos+1] = hexdig(hash[i] & 0x0f);
ret[pos+2] = ':';
}
ret[buflen-1] = 0x0;
return ret;
}
#endif /* MD5/SHA1 switch */
/* This will return a freshly malloced string, containing a fingerprint
* in either sha1 or md5 */
char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen) {
return sign_key_sha256_fingerprint(keyblob, keybloblen);
#if DROPBEAR_MD5_HMAC
return sign_key_md5_fingerprint(keyblob, keybloblen);
#else
return sign_key_sha1_fingerprint(keyblob, keybloblen);
#endif
}
void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
@@ -627,7 +639,6 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
}
#if DROPBEAR_SIGNKEY_VERIFY
/* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
* If FAILURE is returned, the position of
* buf is undefined. If SUCCESS is returned, buf will be positioned after the
@@ -684,22 +695,6 @@ int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype,
return buf_ed25519_verify(buf, key->ed25519key, data_buf);
}
#endif
#if DROPBEAR_SK_ECDSA
if (keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck && *eck) {
return buf_sk_ecdsa_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen);
}
}
#endif
#if DROPBEAR_SK_ED25519
if (keytype == DROPBEAR_SIGNKEY_SK_ED25519) {
dropbear_ed25519_key **eck = (dropbear_ed25519_key**)signkey_key_ptr(key, keytype);
if (eck && *eck) {
return buf_sk_ed25519_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen);
}
}
#endif
dropbear_exit("Non-matching signing type");
return DROPBEAR_FAILURE;

View File

@@ -44,15 +44,9 @@ enum signkey_type {
DROPBEAR_SIGNKEY_ECDSA_NISTP256,
DROPBEAR_SIGNKEY_ECDSA_NISTP384,
DROPBEAR_SIGNKEY_ECDSA_NISTP521,
#if DROPBEAR_SK_ECDSA
DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
DROPBEAR_SIGNKEY_ED25519,
#if DROPBEAR_SK_ED25519
DROPBEAR_SIGNKEY_SK_ED25519,
#endif
#endif
DROPBEAR_SIGNKEY_NUM_NAMED,
DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */
@@ -69,15 +63,9 @@ enum signature_type {
DROPBEAR_SIGNATURE_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_ECDSA_NISTP256,
DROPBEAR_SIGNATURE_ECDSA_NISTP384 = DROPBEAR_SIGNKEY_ECDSA_NISTP384,
DROPBEAR_SIGNATURE_ECDSA_NISTP521 = DROPBEAR_SIGNKEY_ECDSA_NISTP521,
#if DROPBEAR_SK_ECDSA
DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
DROPBEAR_SIGNATURE_ED25519 = DROPBEAR_SIGNKEY_ED25519,
#if DROPBEAR_SK_ED25519
DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
#endif
#endif
#if DROPBEAR_RSA_SHA1
DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
@@ -122,12 +110,6 @@ struct SIGN_key {
#if DROPBEAR_ED25519
struct dropbear_ED25519_Key * ed25519key;
#endif
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
/* application ID for U2F/FIDO key types, a malloced string */
char * sk_app;
unsigned int sk_applen;
#endif
};
typedef struct SIGN_key sign_key;
@@ -148,7 +130,6 @@ void sign_key_free(sign_key *key);
void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, const buffer *data_buf);
#if DROPBEAR_SIGNKEY_VERIFY
int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf);
int sk_buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf, char* app, unsigned int applen);
char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen);
#endif
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,

View File

@@ -1,161 +0,0 @@
#include "includes.h"
#include "dbutil.h"
#include "ssh.h"
#include "signkey_ossh.h"
#include "bignum.h"
#include "ecdsa.h"
#include "sk-ecdsa.h"
#include "sk-ed25519.h"
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
#if DROPBEAR_RSA
/* OpenSSH raw private RSA format is
string "ssh-rsa"
mpint n
mpint e
mpint d
mpint iqmp (q^-1) mod p
mpint p
mpint q
*/
void buf_put_rsa_priv_ossh(buffer *buf, const sign_key *akey) {
const dropbear_rsa_key *key = akey->rsakey;
mp_int iqmp;
dropbear_assert(key != NULL);
if (!(key->p && key->q)) {
dropbear_exit("Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
}
m_mp_init(&iqmp);
/* iqmp = (q^-1) mod p */
if (mp_invmod(key->q, key->p, &iqmp) != MP_OKAY) {
dropbear_exit("Bignum error for iqmp\n");
}
buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
buf_putmpint(buf, key->n);
buf_putmpint(buf, key->e);
buf_putmpint(buf, key->d);
buf_putmpint(buf, &iqmp);
buf_putmpint(buf, key->p);
buf_putmpint(buf, key->q);
mp_clear(&iqmp);
}
int buf_get_rsa_priv_ossh(buffer *buf, sign_key *akey) {
int ret = DROPBEAR_FAILURE;
dropbear_rsa_key *key = NULL;
mp_int iqmp;
rsa_key_free(akey->rsakey);
akey->rsakey = m_malloc(sizeof(*akey->rsakey));
key = akey->rsakey;
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
buf_eatstring(buf);
m_mp_init(&iqmp);
if (buf_getmpint(buf, key->n) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->e) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->d) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, &iqmp) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->p) == DROPBEAR_SUCCESS
&& buf_getmpint(buf, key->q) == DROPBEAR_SUCCESS) {
ret = DROPBEAR_SUCCESS;
}
mp_clear(&iqmp);
return ret;
}
#endif /* DROPBEAR_RSA */
#if DROPBEAR_ED25519
/* OpenSSH raw private ed25519 format is
string "ssh-ed25519"
uint32 32
byte[32] pubkey
uint32 64
byte[32] privkey
byte[32] pubkey
*/
void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey) {
const dropbear_ed25519_key *key = akey->ed25519key;
dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
buf_putint(buf, CURVE25519_LEN);
buf_putbytes(buf, key->pub, CURVE25519_LEN);
buf_putint(buf, CURVE25519_LEN*2);
buf_putbytes(buf, key->priv, CURVE25519_LEN);
buf_putbytes(buf, key->pub, CURVE25519_LEN);
}
int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey) {
dropbear_ed25519_key *key = NULL;
uint32_t len;
ed25519_key_free(akey->ed25519key);
akey->ed25519key = m_malloc(sizeof(*akey->ed25519key));
key = akey->ed25519key;
/* Parse past the first string and pubkey */
if (buf_get_ed25519_pub_key(buf, key, DROPBEAR_SIGNKEY_ED25519)
== DROPBEAR_FAILURE) {
dropbear_log(LOG_ERR, "Error parsing ed25519 key, pubkey");
return DROPBEAR_FAILURE;
}
len = buf_getint(buf);
if (len != 2*CURVE25519_LEN) {
dropbear_log(LOG_ERR, "Error parsing ed25519 key, bad length");
return DROPBEAR_FAILURE;
}
memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
buf_incrpos(buf, CURVE25519_LEN);
/* Sanity check */
if (memcmp(buf_getptr(buf, CURVE25519_LEN), key->pub,
CURVE25519_LEN) != 0) {
dropbear_log(LOG_ERR, "Error parsing ed25519 key, mismatch pubkey");
return DROPBEAR_FAILURE;
}
return DROPBEAR_SUCCESS;
}
#endif /* DROPBEAR_ED255219 */
#if DROPBEAR_ECDSA
/* OpenSSH raw private ecdsa format is the same as Dropbear's.
# First part is the same as the SSH wire pubkey format
string "ecdsa-sha2-[identifier]"
string [identifier]
string Q
# With private part appended
mpint d
*/
void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *key) {
ecc_key **eck = (ecc_key**)signkey_key_ptr((sign_key*)key, key->type);
if (eck && *eck) {
buf_put_ecdsa_priv_key(buf, *eck);
return;
}
dropbear_exit("ecdsa key is not set");
}
int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *key) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
if (eck) {
if (*eck) {
ecc_free(*eck);
m_free(*eck);
*eck = NULL;
}
*eck = buf_get_ecdsa_priv_key(buf);
if (*eck) {
return DROPBEAR_SUCCESS;
}
}
return DROPBEAR_FAILURE;
}
#endif /* DROPBEAR_ECDSA */

View File

@@ -1,15 +0,0 @@
#ifndef DROPBEAR_SIGNKEY_OSSH_H_
#define DROPBEAR_SIGNKEY_OSSH_H_
#include "signkey.h"
/* Helpers for OpenSSH format keys in dropbearconvert */
void buf_put_rsa_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_rsa_priv_ossh(buffer *buf, sign_key *akey);
void buf_put_ed25519_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_ed25519_priv_ossh(buffer *buf, sign_key *akey);
void buf_put_ecdsa_priv_ossh(buffer *buf, const sign_key *akey);
int buf_get_ecdsa_priv_ossh(buffer *buf, sign_key *akey);
#endif /* DROPBEAR_SIGNKEY_OSSH_H_ */

View File

@@ -1,56 +0,0 @@
#include "includes.h"
#if DROPBEAR_SK_ECDSA
#include "dbutil.h"
#include "ecc.h"
#include "ecdsa.h"
#include "sk-ecdsa.h"
#include "ssh.h"
int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen) {
hash_state hs;
unsigned char subhash[SHA256_HASH_SIZE];
buffer *sk_buffer = NULL, *sig_buffer = NULL;
unsigned char flags;
unsigned int counter;
int ret;
TRACE(("buf_sk_ecdsa_verify"))
/* from https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.u2f */
/* ecdsa signature to verify (r, s) */
sig_buffer = buf_getbuf(buf);
flags = buf_getbyte (buf);
counter = buf_getint (buf);
/* create the message to be signed */
sk_buffer = buf_new (2*SHA256_HASH_SIZE+5);
sha256_init (&hs);
sha256_process (&hs, app, applen);
sha256_done (&hs, subhash);
buf_putbytes (sk_buffer, subhash, sizeof (subhash));
buf_putbyte (sk_buffer, flags);
buf_putint (sk_buffer, counter);
sha256_init (&hs);
sha256_process (&hs, data_buf->data, data_buf->len);
sha256_done (&hs, subhash);
buf_putbytes (sk_buffer, subhash, sizeof (subhash));
ret = buf_ecdsa_verify(sig_buffer, key, sk_buffer);
buf_free(sk_buffer);
buf_free(sig_buffer);
/* TODO: allow "no-touch-required" or "verify-required" authorized_keys options */
if (!(flags & SSH_SK_USER_PRESENCE_REQD)) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-presence not set");
}
ret = DROPBEAR_FAILURE;
}
TRACE(("leave buf_sk_ecdsa_verify, ret=%d", ret))
return ret;
}
#endif /* DROPBEAR_SK_ECDSA */

View File

@@ -1,15 +0,0 @@
#ifndef DROPBEAR_SK_ECDSA_H_
#define DROPBEAR_SK_ECDSA_H_
#include "includes.h"
#if DROPBEAR_SK_ECDSA
#include "buffer.h"
#include "signkey.h"
int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen);
#endif
#endif /* DROPBEAR_SK_ECDSA_H_ */

View File

@@ -1,68 +0,0 @@
#include "includes.h"
#if DROPBEAR_SK_ED25519
#include "dbutil.h"
#include "buffer.h"
#include "curve25519.h"
#include "ed25519.h"
#include "ssh.h"
int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen) {
int ret = DROPBEAR_FAILURE;
unsigned char *s;
unsigned long slen;
hash_state hs;
unsigned char hash[SHA256_HASH_SIZE];
buffer *sk_buffer = NULL;
unsigned char flags;
unsigned int counter;
TRACE(("enter buf_sk_ed25519_verify"))
dropbear_assert(key != NULL);
slen = buf_getint(buf);
if (slen != 64 || buf->len - buf->pos < slen) {
TRACE(("leave buf_sk_ed25519_verify: bad size"))
goto out;
}
s = buf_getptr(buf, slen);
buf_incrpos(buf, slen);
flags = buf_getbyte (buf);
counter = buf_getint (buf);
/* create the message to be signed */
sk_buffer = buf_new (2*SHA256_HASH_SIZE+5);
sha256_init (&hs);
sha256_process (&hs, app, applen);
sha256_done (&hs, hash);
buf_putbytes (sk_buffer, hash, sizeof (hash));
buf_putbyte (sk_buffer, flags);
buf_putint (sk_buffer, counter);
sha256_init (&hs);
sha256_process (&hs, data_buf->data, data_buf->len);
sha256_done (&hs, hash);
buf_putbytes (sk_buffer, hash, sizeof (hash));
if (dropbear_ed25519_verify(sk_buffer->data, sk_buffer->len,
s, slen, key->pub) == 0) {
/* signature is valid */
TRACE(("leave buf_sk_ed25519_verify: success!"))
ret = DROPBEAR_SUCCESS;
}
/* TODO: allow "no-touch-required" or "verify-required" authorized_keys options */
if (!(flags & SSH_SK_USER_PRESENCE_REQD)) {
if (ret == DROPBEAR_SUCCESS) {
dropbear_log(LOG_WARNING, "Rejecting, user-presence not set");
}
ret = DROPBEAR_FAILURE;
}
out:
buf_free(sk_buffer);
TRACE(("leave buf_sk_ed25519_verify: ret %d", ret))
return ret;
}
#endif /* DROPBEAR_SK_ED25519 */

View File

@@ -1,15 +0,0 @@
#ifndef DROPBEAR_SK_ED25519_H_
#define DROPBEAR_SK_ED25519_H_
#include "includes.h"
#if DROPBEAR_SK_ED25519
#include "buffer.h"
#include "ed25519.h"
int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen);
#endif
#endif /* DROPBEAR_SK_ED25519_H_ */

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