mirror of
https://github.com/clearml/dropbear
synced 2025-06-26 18:17:32 +00:00
Compare commits
365 Commits
DROPBEAR_2
...
matt-sk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cafebe2d30 | ||
|
|
cc481a646d | ||
|
|
2634c4586b | ||
|
|
712d529164 | ||
|
|
2ad020ff30 | ||
|
|
0c62c0db7f | ||
|
|
2993eedaba | ||
|
|
c66f0e98c9 | ||
|
|
c8fcc08fe0 | ||
|
|
483b427335 | ||
|
|
27ffea3223 | ||
|
|
742e296115 | ||
|
|
0e43d68d81 | ||
|
|
bcb9d78d83 | ||
|
|
8da9646c83 | ||
|
|
da482ede60 | ||
|
|
f0495697e5 | ||
|
|
f9ced2c880 | ||
|
|
17e0c7e76f | ||
|
|
30adc15860 | ||
|
|
6138bdc62f | ||
|
|
e05945f67a | ||
|
|
3e640acd17 | ||
|
|
ae25761c7c | ||
|
|
e6152ccd7d | ||
|
|
8b0d31ab20 | ||
|
|
65f6e48a06 | ||
|
|
a7ef149463 | ||
|
|
043b0fbd1b | ||
|
|
110b55214b | ||
|
|
c08177a3af | ||
|
|
3c2436cd05 | ||
|
|
f3b72bfd18 | ||
|
|
f17400e738 | ||
|
|
8e6f73e879 | ||
|
|
7c2470ba3a | ||
|
|
cc59c08605 | ||
|
|
661d8ca225 | ||
|
|
41d4b4e7f7 | ||
|
|
dc016f900b | ||
|
|
4c8c879b38 | ||
|
|
210a983349 | ||
|
|
69e5709f75 | ||
|
|
2157d52352 | ||
|
|
846d38fe43 | ||
|
|
a8d6dac2c5 | ||
|
|
ee49a1b16d | ||
|
|
325d0c1d02 | ||
|
|
17f209f9b7 | ||
|
|
924d5a06a6 | ||
|
|
1bf7acc5bd | ||
|
|
8d0013bbe0 | ||
|
|
9262ffe861 | ||
|
|
1eb369272b | ||
|
|
c0ed29ea02 | ||
|
|
91ca561d7a | ||
|
|
ba260bd67b | ||
|
|
898bff3d4e | ||
|
|
67a8de30b7 | ||
|
|
6c571c54e5 | ||
|
|
d2bfa6aedc | ||
|
|
d0d1ede191 | ||
|
|
3c2f113a78 | ||
|
|
f193e95a3e | ||
|
|
03481aba06 | ||
|
|
8b0fdf8010 | ||
|
|
934cc87db3 | ||
|
|
ae94f64145 | ||
|
|
8552a0e9eb | ||
|
|
d20420e709 | ||
|
|
e8640bdca3 | ||
|
|
e4edbf2e57 | ||
|
|
5d60e5f312 | ||
|
|
38d7da5fe5 | ||
|
|
a6b2eeb190 | ||
|
|
e12ff23e7d | ||
|
|
007a5925dc | ||
|
|
d439ed26e4 | ||
|
|
f9ff3fa23d | ||
|
|
2c64335d9c | ||
|
|
286b6b9f80 | ||
|
|
220ba993a2 | ||
|
|
3c88d6536a | ||
|
|
f49b576e93 | ||
|
|
8ec9016585 | ||
|
|
15ea6d1106 | ||
|
|
24cfda9e3c | ||
|
|
121e6e6202 | ||
|
|
1b6e16ae7c | ||
|
|
b8352f8164 | ||
|
|
6aa065b1b4 | ||
|
|
6cf29061c2 | ||
|
|
f92f0777de | ||
|
|
9c70e4bed1 | ||
|
|
a51833c51a | ||
|
|
d852d69b50 | ||
|
|
1b603069db | ||
|
|
bf4058d1df | ||
|
|
4d716b6302 | ||
|
|
1260fbc5cd | ||
|
|
acd6a22a0c | ||
|
|
4e8a1da551 | ||
|
|
754dc50b93 | ||
|
|
c7cfa75e92 | ||
|
|
b070bcd570 | ||
|
|
037d26f055 | ||
|
|
cb252296c5 | ||
|
|
f37def57b0 | ||
|
|
1a208c460b | ||
|
|
34f24b1841 | ||
|
|
1a7b944917 | ||
|
|
3b400bd64e | ||
|
|
f74baa5830 | ||
|
|
4c5b8fb6d6 | ||
|
|
d5cc5eb25c | ||
|
|
9f642e2bd4 | ||
|
|
6ca24af24a | ||
|
|
400c7c161f | ||
|
|
5567c238a7 | ||
|
|
33eba22966 | ||
|
|
282fc81981 | ||
|
|
cc1b07dcf1 | ||
|
|
0e3e8db5bf | ||
|
|
17873e8c92 | ||
|
|
80e9281701 | ||
|
|
926c477188 | ||
|
|
d999575e34 | ||
|
|
5d095e9a27 | ||
|
|
3727b099c5 | ||
|
|
45294b458a | ||
|
|
d51e4a75cd | ||
|
|
e9f2815144 | ||
|
|
2771fab0fa | ||
|
|
a7a67585cb | ||
|
|
366f01252e | ||
|
|
1490c0c3a6 | ||
|
|
3f5c106a88 | ||
|
|
10e119f638 | ||
|
|
5b68d117c2 | ||
|
|
58106b1615 | ||
|
|
1e10af850b | ||
|
|
ee4b4db816 | ||
|
|
ab9cfce00d | ||
|
|
2b8106b14e | ||
|
|
78c5daee52 | ||
|
|
2301b6ac0b | ||
|
|
a27e8b053e | ||
|
|
6145289e0d | ||
|
|
d14ebdbf0e | ||
|
|
4b305c5721 | ||
|
|
615885be01 | ||
|
|
6b823d617c | ||
|
|
ec993dbdbc | ||
|
|
ad1e9b7e3c | ||
|
|
846b8cdbf7 | ||
|
|
b0243b0e7b | ||
|
|
4faf06aae7 | ||
|
|
07d46f9907 | ||
|
|
413eaf1ba1 | ||
|
|
3b359050b4 | ||
|
|
a015cc7594 | ||
|
|
dc12be0cfe | ||
|
|
89e98a2f83 | ||
|
|
5027bc4db1 | ||
|
|
630f6aa6b9 | ||
|
|
8048473eb9 | ||
|
|
4216c984ae | ||
|
|
6abf756e51 | ||
|
|
b4bd23b4d2 | ||
|
|
724e61f8ae | ||
|
|
49667a82de | ||
|
|
a57114e7fa | ||
|
|
cfe90bc6bd | ||
|
|
0aefec6c89 | ||
|
|
6a3bc73a78 | ||
|
|
73aa4f0de9 | ||
|
|
9e25854b41 | ||
|
|
d277f140ba | ||
|
|
61267f8503 | ||
|
|
d3d0d60076 | ||
|
|
91e537e427 | ||
|
|
fb9a78c3ee | ||
|
|
8f8a3dff70 | ||
|
|
c917807b1c | ||
|
|
701d43b859 | ||
|
|
79bedc90a1 | ||
|
|
545cc62671 | ||
|
|
331d4a714f | ||
|
|
2a81289ed3 | ||
|
|
5acee497bf | ||
|
|
972d723484 | ||
|
|
7dc2f36c3e | ||
|
|
90cfbe1f7a | ||
|
|
b681570899 | ||
|
|
201e359363 | ||
|
|
fa4c4646d8 | ||
|
|
6f6aa9db5a | ||
|
|
e35d0784a8 | ||
|
|
cc6fa57a41 | ||
|
|
a26ad21c0a | ||
|
|
002b79e2f9 | ||
|
|
3d12521735 | ||
|
|
b2007beeb0 | ||
|
|
8f123fb618 | ||
|
|
c71258625d | ||
|
|
615ed4e46a | ||
|
|
fa116e983b | ||
|
|
8c6aaf8d36 | ||
|
|
cae6e6af10 | ||
|
|
f89c5b0390 | ||
|
|
4318631dd6 | ||
|
|
7bc6280613 | ||
|
|
e9231f73c2 | ||
|
|
4fd40e61f7 | ||
|
|
71f818262c | ||
|
|
07f790db5a | ||
|
|
78a3388b98 | ||
|
|
6fecc91d10 | ||
|
|
8b4f60a7a1 | ||
|
|
01cd1bd11f | ||
|
|
f6df3e1fec | ||
|
|
553087b7a6 | ||
|
|
16fb0b0d53 | ||
|
|
493ab8fd81 | ||
|
|
0afcfafbb9 | ||
|
|
0af22aa8e4 | ||
|
|
2fd3b9f560 | ||
|
|
2de3bc9353 | ||
|
|
28b6111db0 | ||
|
|
a0aa274981 | ||
|
|
b016ebedfd | ||
|
|
cb945f9f67 | ||
|
|
df0f1297eb | ||
|
|
fe992bf4ea | ||
|
|
ffde4a524f | ||
|
|
7e03e4d443 | ||
|
|
02ffdd09dc | ||
|
|
6f6ef4834c | ||
|
|
d2e71ade72 | ||
|
|
892c5fc1c8 | ||
|
|
e7504b3311 | ||
|
|
ad3eacf3d6 | ||
|
|
52adbb34c3 | ||
|
|
90f04384ee | ||
|
|
195934be96 | ||
|
|
d740dc5489 | ||
|
|
76933e6c0a | ||
|
|
38c9408cf8 | ||
|
|
397af3e6a6 | ||
|
|
933bc5f8a7 | ||
|
|
ba94bcd2e8 | ||
|
|
56855744b8 | ||
|
|
b4b11c8155 | ||
|
|
f82933108d | ||
|
|
27828c742c | ||
|
|
ed4c38ba46 | ||
|
|
e9edbe8bb2 | ||
|
|
4fd3160179 | ||
|
|
a60725740b | ||
|
|
5d065258da | ||
|
|
149b21d7cf | ||
|
|
145fb96989 | ||
|
|
084ff9b4c8 | ||
|
|
6b05aa4275 | ||
|
|
366fc8f335 | ||
|
|
35f479bd87 | ||
|
|
9d11cad5dc | ||
|
|
0233dcebb4 | ||
|
|
f7dedab4a7 | ||
|
|
129c440362 | ||
|
|
abee8093b3 | ||
|
|
2583b180c9 | ||
|
|
1e1e477d85 | ||
|
|
85eda7d943 | ||
|
|
4b36e24735 | ||
|
|
a5eac0a065 | ||
|
|
7f15910541 | ||
|
|
625b38d7af | ||
|
|
b9edf939f4 | ||
|
|
257bba00ac | ||
|
|
8d0b48f165 | ||
|
|
ce1f9cdf7c | ||
|
|
e612aec5d9 | ||
|
|
5bd0c0d25a | ||
|
|
26ad6853d2 | ||
|
|
8a4f7fe4f8 | ||
|
|
294e98c397 | ||
|
|
c1a2dcb25d | ||
|
|
a0972e0ac6 | ||
|
|
8062a4e8d6 | ||
|
|
a0ab5e86b5 | ||
|
|
a1dcaf82a0 | ||
|
|
78e17f6ee9 | ||
|
|
5ebc48b3f2 | ||
|
|
1ae4237920 | ||
|
|
5ca12d8332 | ||
|
|
7f8702d3d6 | ||
|
|
5f2447edbb | ||
|
|
c658b275fd | ||
|
|
9bbce01e1b | ||
|
|
bbe02dc3cf | ||
|
|
3d76aecaa6 | ||
|
|
5df73215f8 | ||
|
|
573838a027 | ||
|
|
05f4e29a52 | ||
|
|
dbc0520992 | ||
|
|
dcb41e91eb | ||
|
|
7e8094d53a | ||
|
|
f7a664f127 | ||
|
|
89bdf3b0b9 | ||
|
|
597f7eb5e9 | ||
|
|
5cd003d9e6 | ||
|
|
4b7105dfea | ||
|
|
6ac5ea2a9f | ||
|
|
17a9b8802f | ||
|
|
9b6f7fc9af | ||
|
|
5ac4a71000 | ||
|
|
b967dc1fa5 | ||
|
|
2cbe70ba34 | ||
|
|
8e1ea0f27b | ||
|
|
e3246ceb7e | ||
|
|
88ce30beb6 | ||
|
|
723ec19eed | ||
|
|
937e6cb91e | ||
|
|
81b64ea0b5 | ||
|
|
ea0e23c172 | ||
|
|
4d07aa315b | ||
|
|
2e298b25e4 | ||
|
|
25607c04a7 | ||
|
|
cbd5be1b82 | ||
|
|
f24d93d4e4 | ||
|
|
65baa71b58 | ||
|
|
b8fa712847 | ||
|
|
095b067857 | ||
|
|
87c4586d61 | ||
|
|
b17254925d | ||
|
|
cf2c4f44a2 | ||
|
|
2bc55ff428 | ||
|
|
ee5769f31f | ||
|
|
3a8517b06f | ||
|
|
0363d3c32e | ||
|
|
a582c4cdb6 | ||
|
|
a43b6b0323 | ||
|
|
84a143a605 | ||
|
|
114438e669 | ||
|
|
50bde9976b | ||
|
|
18ea116827 | ||
|
|
30d3ccd419 | ||
|
|
fb8fb7fed0 | ||
|
|
1abd239b9d | ||
|
|
9f1c8b2f8f | ||
|
|
c169423051 | ||
|
|
fdc6f32392 | ||
|
|
e7cdb2ebe5 | ||
|
|
4dae8edb76 | ||
|
|
a3e01b8884 | ||
|
|
6d33a2b0bb | ||
|
|
beaff53a79 | ||
|
|
b9b308f2fe | ||
|
|
a7bfd792f7 | ||
|
|
06fd9e3771 | ||
|
|
fb719e3d0b | ||
|
|
9f24cdf74c | ||
|
|
d7471c4f87 | ||
|
|
49177312fb |
151
.github/workflows/build.yml
vendored
Normal file
151
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
# Can be used locally with https://github.com/nektos/act
|
||||
|
||||
name: BuildTest
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os || 'ubuntu-20.04' }}
|
||||
strategy:
|
||||
matrix:
|
||||
# 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
|
||||
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
||||
# # 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
|
||||
# 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
|
||||
# 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' }}
|
||||
|
||||
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: make
|
||||
run: make -j3
|
||||
|
||||
- name: multilink
|
||||
if: ${{ matrix.multi }}
|
||||
run: make multilink
|
||||
|
||||
- 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
|
||||
~/inst/bin/dropbearkey -t ecdsa -f ~/.ssh/id_dropbear | grep ^ecdsa > ~/.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
|
||||
30
.github/workflows/cifuzz.yml
vendored
Normal file
30
.github/workflows/cifuzz.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# 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
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -5,6 +5,7 @@
|
||||
*.bb
|
||||
*.bbg
|
||||
*.prof
|
||||
.*.swp
|
||||
/autom4te.cache
|
||||
/config.log
|
||||
/config.status
|
||||
@@ -13,10 +14,15 @@
|
||||
/dropbearconvert
|
||||
/dropbearkey
|
||||
/dropbearmulti
|
||||
/fuzzcorpus
|
||||
/fuzzer-*
|
||||
/fuzzer-*.options
|
||||
/scp
|
||||
/scp-progress
|
||||
Makefile
|
||||
config.h
|
||||
config.h.in
|
||||
configure
|
||||
default_options_guard.h
|
||||
tags
|
||||
.pytest*
|
||||
*.pyc
|
||||
/test/venv
|
||||
|
||||
6
.hgsigs
6
.hgsigs
@@ -23,3 +23,9 @@ fd1981f41c626a969f07b4823848deaefef3c8aa 0 iQIcBAABCgAGBQJW4W2TAAoJEESTFJTynGdzu
|
||||
70705edee9dd29cd3d410f19fbd15cc3489313e2 0 iQIcBAABCgAGBQJW7CQRAAoJEESTFJTynGdzTj0QAJL38CKSZthBAeI9c6B+IlwIeT6kPZaPqk1pkycCTWOe87NiNU9abrsF+JrjTuRQiO1EpM2IvfQEIXTijUcMxvld3PnzrZDDv6UvBLtOkn3i++HSVRO0MOuTKI8gFDEPUxRtcaCKXEbqYnf1OTK25FT09Vb//qP9mK1thvlLJmbV+D2a9MkMK66rom1d1h+347IsuwsM+ycHjB80VVAQLA7VYLC5YIwmL17dSmcQLvetfikAMwwmUE+KES4qiLSaqOcAWcKcU67RZzgMMv5o0rESlQmv1nj0mHZtHoUR71sd21emPaRXLOr0oT5YogWUphKq2qVthRn2B06+vd3hPdtn92CmJw9j7zT2jl4OeSjNm9qfAajsRzHIANssFxkGAb7w/LxcMoO29JC+01iUUJMdOVm+4Ns6wGI7qxssWPKdB+VbQUDlHrXLR+sopO524uhkYoWB6DVfTj4R6tImaHtj5/VXON0lsYaLGj8cSH60emL6nNQ0lYV/bSlk6l0s+0x3uXGZnp9oKA+vqMzHfG3vJeMm6KUqtFVjUsYx+q8nHm5/SlWxj1EwnkH8s8ELKZAUXjd76nWEwJ7JFRNRSQWvjOUh3/rsOo4JopzZXPsjCjm+Vql9TG0X6hB21noai32oD5RvfhtR/NX6sXNS5TKZz/j/cMsMnAAsSKb6W7Jm
|
||||
9030ffdbe5625e35ed7189ab84a41dfc8d413e9c 0 iQIcBAABCgAGBQJXkOg0AAoJEESTFJTynGdzc1kP/3vSKCnhOOvjCjnpTQadYcCUq8vTNnfLHYVu0R4ItPa/jT6RmxoaYP+lZnLnnBx9+aX7kzwHsa9BUX3MbMEyLrOzX2I+bDJbNPhQyupyCuPYlf5Q9KVcO9YlpbsC4q5XBzCn3j2+pT8kSfi9uD8fgY3TgE4w9meINrfQAealfjwMLT8S/I49/ni0r+usSfk/dnSShJYDUO7Ja0VWbJea/GkkZTu30bCnMUZPjRApipU3hPP63WFjkSMT1rp2mAXbWqyr9lf8z32yxzM9nMSjq4ViRFzFlkGtE3EVRJ4PwkO7JuiWAMPJpiQcEr+r52cCsmWhiGyHuINo01MwoMO9/n6uL1WVa3mJcE9se3xBOvfgDu2FRFGCAdm1tef+AGVo9EG1uJXi0sX2yUc6DMeuYaRWrXMMlZh7zp9cuNU9Y/lLui9RFmq66yeXG3Z2B72doju3Ig5QGrNNw2AOsSzeHdAtOp6ychqPcl9QfIeJQG18KyPSefZKM3G8YRKBRIwXFEH6iZJe5ZIP4iXrHDMn2JqtTRtDqKR8VNDAgb9z4Ffx8QRxFyj5JzTTMM1GddHb9udLvTQlO0ULYG7hCSMRNzvUBE2aTw8frjLRyfyyg3QpDu/hz8op8s1ecE8rTCD8RuX9DiiylNozypPtGNS+UDbAmkc1PCWaRpPVl+9K6787
|
||||
5c9207ceedaea794f958224c19214d66af6e2d56 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlkdtooACgkQRJMUlPKcZ3P6ZxAAmLy/buZB/d96DJF/pViRWt/fWdjQFC4MqWfeSLW02OZ8Qkm1vPL3ln6WPHC2thy3xZWVg2uan3pLk/XXnsIFu8Q7r1EAfFFpvlMUmdl7asE8V6ilaeqmiI7bIvGMFbf4cZkQliLjiFkJX56tFHRCNi+rb7WgRuru3/GzPXUq2AvXZvFpFJgik0B72TxVlmCKeBRZq1FvP0UhAH48RJWYJksdEyzh2paMfjX9ZO5Q2SFFrmPw6k2ArdJFC1AYcgceZC84y06RKJ0WiSntUPlEUXgQbQVVWbtQDhjfJXMr/beuroNdT/vsRraLVkAzvhaDXNnHlAJNLQxci+AcLpnzZhxMW+ax7RRtrpXGxRN4cs0lBGUcSkaDybFqMYXwEjXAE8w6fdJRWCIlxctkAW/iNEO4kAG97hI2Qwcw5oU2Ymnv09zyGR+XJE35pJqPulJHExdwanJHvmjH0QF7TNFS82yxS5dKnP954cj3Lu9SWGYWjxQJRmLtOwb+lqqol4VTxG7Ois4uef9/Tpp9skeMZXVeNlpn2wrp6iFcX3uiiVDg9VKkl3ig6UqCiqQSuiIN87RXwUOeHXlCnW3adz3Xei0ziBrwLSql7lBIHGEAlUUNmJ3CrR8IwQtcynGEMKfNIeZ/XK+uNlm9cJIqZf1fzqc8KexlyS9AS0i/kiYZTr4=
|
||||
2f0c3f3361d3ea4eb9129ed8810699fda7e7a8ee 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlqVb+IACgkQRJMUlPKcZ3OENA//R9HsOUJQB2QZjRgAvqgLn2AMLUvmWb2etTZEc3Nps957Fw1F4kjh6VGfIpWuytfsDx1W8qRx09ikTdb3YteMWCuX8/aFreSPrioYmzrAEcxkZdA7B/jciqU0iXuHiJ9saKk5TR70aNp+iRy0hjAgiYEsVMF9YKHzULOJcHr70x9XVKquubQkwNqJA+/b2JbK2j46wM5nVK/alGSI2kMmEzXmAHQxsvf1OLMvgH8ou/l0xsg/CuFEK299XKfZAbsFEXrjuoWZ1aSa6rTeOWsWli5T+czyyJHI4Eu0Sz/gaR8+MPhJSYes8YjvzEdv32rRMDVOdBq4e+HoTgFt/THYABP6/R1H5fX3Lm4K8u9F9SwJbb/YKRAIrfWDob8ApnGFHk2dyYO20Fskbbg6b1pC7ulDWsufu8lYkQyMlTc3dR6P4eTB6mKO4x+gMG6tIYZ60fiULoEnMJCgegPtevmz+TG1rzdjh3ljiw9Dxz5lNtL+W7sBKKHwhyG0u+bavgmvBMKNL/rdHEM+0yCIz1U6Lb8sVaST1E4zbdm7cWHbSozBij3G0GBSkLFEq7ZLlh8wco9rELRh0Y9fFsWY9j6H/PTOu0GfHrYluFb9WGywHAquQY8j2croRx+MrvTbR1wZrbevPNm9gqk3vgOiDWu7KwxLLqcj+dEQ7tccptVYtbM=
|
||||
07b0d56d186d7eeef4106137a3eba554959ba0e3 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlyWOo8ACgkQRJMUlPKcZ3O+MQ//c5oeDUvZuFiI4FHZqfIK/59YAciTP+9TQmoWDVSuOdkd9ZYJA7b7DCusqP2TWFEIl9M7i5hTLTMD21xuEQQtfOSP6EXpUw6JNdh/lsJs7EDlFANtwkdEozAQozFKnXbJEV3y9WldEWUlmPFjt4fJQIuG10SU7MTJHcSaQddJCh3I1//F4EvgRe+OqyrFwKekGiFdvfjcIFN3lQmk6K1Sc0MgyIO/VVZm/AQpBi0Dlg0yOl+EDcxxlmeSInbvLceWSP6op35I4dE5YWH1UetjzIsr5AIM15/k3viAKDDefY1EMAzK9b7YAF4BLw0a6XoQu0apvcWaALE/bJzWNSg/QbCm2JAZzk21WLLvR+AELzPfKXrHX3o0h51lpQ4rs7EWKUm43dJPoWkcFNOU+BDsNzffcJgChbRs48ut89DYLiGmSxhRxE77VPbA+klgTGdctOTLd8psseRlGYCuGe8zeota80bV9fUZ9WJZHwNgEWGowKUoTjy6l5k9OH3iQuQX3OXoy78ufRgWDulE7noVTMhXurQ8a0Jf2k/MW9dcnqGVkWitCFKPEvZwVmWyW2AWsdMcBJnFFGzDsNSxWTtCF9XcxieDO1IB8vGwYcb1TwEVuVzvR/wwvc3PgVikF+4Qv2NqdoQc1yn2PkocY2hwXyIZUAwz7erNumlTbeC/JK8=
|
||||
ebcdb893992d286d363e60f5353d6e1401e7084b 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAlybhXAACgkQRJMUlPKcZ3O7pQ//QuNJfBVa7ROaOJOR2H/xr6PRn1Fnc6rr/GCF9cqWrbGP6wNo24dRjcu5LxviqPvzfwRXIMXwVz8L/y61/sm6XcA7VFP4+MBoltfeUOdMbfBdtwEUo3WMBdP1w2q5GgYj8ZY6MawiLEqFba5aua7dokTNBOQM3Yebj+9I16MiWEaRSnuwYPoieHW2Fo6oftcIgs/GCXwT2xYzc0n3FpYAbK7u6sEkpL16EstV0Y/G70+X1/4Mg3GM96S5fl9Zbun47W7/+gT4AQVQjE+UnPNDudObAe+2BaOZLFvEbd7iJBBcqtjpBktuP58IEAb3A3srUCy49LNLWk43lj+PtoslK/U6TShKQ2vAgfd//bbn6ieXFJY8N+wYPpJo1m7zpTiEtS7J7wu6vkGGZlqUAj6MHXZj223CgazhSAlg/XFPs9oz3Y96c33Tnd4jB9iEXNNt5jzCAMImx2huSGgnP0JFAbcniq/ug5tl1VWaracvSuJl7fmf17DbmehsLbvtZBoMlePY7Ssfb5IokfVvptt4zRpRZnjtWfHCjtC6zYhtvXTmXH/bqWwx9MMjOf5WPfZoCMvXfMqdVI15FVbxU15WnqjvdvKUCkdz1aMFzxqc4MXgyvjtB9CvO/8WwBOJ2m2nDdiZfh8/H8SawYqEHgB61FX5xA5aXecgXcjQnqWDDxw=
|
||||
4877afd51e041eca7749cc46b57fd80aa23815b4 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAl7nmREACgkQRJMUlPKcZ3PG1BAAnUl0/nTnQ3CMM3S72DT1JQ1eDxZa14r6r1xEPngU83hNNzmPcnfiMDts+Vz1M3PLxNNOXVVt/MTw04+V9joPhhSWEe8O1pd3lAqTPswL7hhIEbVwZwyFCuAV4iAm+tHKzKLjtjgZfMgij6XylOmw18VBw5R+suoOMclJqeHlJ5m0Mq2wRLDE+RdVCAkulTqhGYjJNQUXMMNPx/cxUo3NHsto9pWL3d1285vBByP6BQSaeYlO012InvJRlQuEkK3lnIyzq6voIc6+tMli0q9iyBz+2GIloBQNAnb6EGaXxqAOBW5NRc+/Oauiu8Yf/6JoFlkAIcPXmGRtxiAiynJImhiTaCFdgdxaXLFzjBvq+tcwVXvvNM52fOZ4Z3QgMDu6EgNWfma0lsg4T3ar2ml2/evuWeLVut5ZmYFHarTFX+/pTVy9nAZK/F5ROJM1prTNYI18PZV4qvULta8spGV2Be0rCkQQubp9RWdKHNGZE70lrX5OnNIwE/D3g2QE04243i0IGBwhlDEpYjqujLyHk8W6XE1CORx0hQ0fUjzKZsRvOB7XyMAFpQUVOhoMFcnk5XHDW6B/U7NAxzqNqO+gbHO/UIeuy/KOVlMNJCmtRL/HYNGZ6SCZbRpyX3d8Ow0sasNfJkZrT6a0Tf6lZktWOxtPkoEDLfuCzudzn4JxGQM=
|
||||
88f63b8b0f131f24aa90c9b852622b922b1ad738 0 iQIzBAABCgAdFiEE9zR+8u4uB6JnYoypRJMUlPKcZ3MFAl71/sAACgkQRJMUlPKcZ3OlSQ/9GYLotOmsYK0gvSfWLYR9a8WGgT/4EU6RgAkMBLS9TBp0E3V4VUDralnqoId7hNO2cUkRS7boOM2g4/YRShah8gonSJa70lKjUpDeQUPuGwUYWLNKr9qxJtnAcd1rOE4WYxKEUfjPWHBbVsT3QIIdj1Zy31GDKZgELRBQeOyt62RdXYHMaMHHDgg2U/wO9bcRRe5G7mYJf7Vm8sAWyTZXvta2jORxgs4XxWe7xJ9Dj0lMSG5HmfvH5NrGHM1GK3pL0GREKj2+xNSFdkSeHIgSSoHM2qZTVSWtNfx0+fZaRBgvXPPYzDTTghj1mKEaPFoRzg/B8s+NmHupJftT1yyapKFjALo1N6eaPHRRSwVfmnoWSJLu4fwL8TK5wMJr9eGl3QgAnperQPEFT9UHJBIwZ1D+RMuI3pEESdHBJFAYIAyisJI6XyzMhLsysoShlHs6OjFcJ9jTe4pzg9pO+KaPbLYsBJxJUsrtHwV8P9CHxY6CEuKm0AZjYDopYhzLuAUjGJjYDf/C9vJ/xtTOqIm9nywfcFwqgLrmQFhNHHGyOJVr+y/cey1sT9E4/gBv9kor+6qSITALv2g0JTaOpzpkE0zbafUy2r777Wex4WNQEha6bYZFi2aiqxqqX93UHzv+YhmN8n9mlc21xoZMPNtAb2mSxx7rO+PScb5uflKOCYE=
|
||||
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=
|
||||
|
||||
6
.hgtags
6
.hgtags
@@ -55,3 +55,9 @@ cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
|
||||
309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73
|
||||
0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74
|
||||
c31276613181c5cff7854e7ef586ace03424e55e DROPBEAR_2017.75
|
||||
1c66ca4f3791c82501c88e7637312182c7294978 DROPBEAR_2018.76
|
||||
6d1bbe7d5fa5827c7eae28bca044d691f7efa785 DROPBEAR_2019.77
|
||||
009d52ae26d35f3381c801e02318fa9be34be93c DROPBEAR_2019.78
|
||||
e2e4929d057b09422f2ea4556fb64209aff58161 DROPBEAR_2020.79
|
||||
73646de50f1351735c868d4874f058ff9ad62c96 DROPBEAR_2020.80
|
||||
4b984c42372d01fcc2fd487c58af6a5aa65eb88e DROPBEAR_2020.81
|
||||
|
||||
56
.travis.yml
56
.travis.yml
@@ -1,56 +0,0 @@
|
||||
language: c
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
||||
matrix:
|
||||
include:
|
||||
# subsequent matrix options use these first settings
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
env: WEXTRAFLAGS=-Werror
|
||||
- env: MULTI=1 WEXTRAFLAGS=-Werror
|
||||
# libtom has some warnings, so no WEXTRAFLAGS
|
||||
- env: BUNDLEDLIBTOM=--enable-bundled-libtom WEXTRAFLAGS=""
|
||||
- env: NOWRITEV=1 WEXTRAFLAGS=-Werror
|
||||
# libtomcrypt 1.18.1 fixes clang problems, distro doesn't have that yet
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: BUNDLEDLIBTOM=--enable-bundled-libtom WEXTRAFLAGS=""
|
||||
- os: osx
|
||||
compiler: clang
|
||||
env: WEXTRAFLAGS=""
|
||||
|
||||
# container-based builds
|
||||
sudo: false
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
|
||||
- zlib1g-dev
|
||||
- libtomcrypt-dev
|
||||
- libtommath-dev
|
||||
|
||||
|
||||
before_install:
|
||||
- if [ "$CC" = "clang" ]; then WEXTRAFLAGS="$WEXTRAFLAGS -Wno-error=incompatible-library-redeclaration" ; fi # workaround
|
||||
|
||||
script:
|
||||
- autoconf && autoheader && ./configure "$BUNDLEDLIBTOM" CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS" --prefix="$HOME/inst"
|
||||
- if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
|
||||
- make -j3
|
||||
# avoid concurrent install, osx/freebsd is racey (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=208093)
|
||||
- make install
|
||||
|
||||
after_success:
|
||||
- ~/inst/bin/dropbearkey -t rsa -f testrsa
|
||||
- ~/inst/bin/dropbearkey -t dss -f testdss
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
|
||||
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- coverity
|
||||
|
||||
159
CHANGES
159
CHANGES
@@ -1,13 +1,146 @@
|
||||
2020.81 - 29 October 2020
|
||||
|
||||
- Fix regression in 2020.79 which prevented connecting with some SSH
|
||||
implementations. Increase MAX_PROPOSED_ALGO to 50, and print a log
|
||||
message if the limit is hit. This fixes interoperability with sshj
|
||||
library (used by PyCharm), and GoAnywhere.
|
||||
Reported by Pirmin Walthert and Piotr Jurkiewicz
|
||||
|
||||
- Fix building with non-GCC compilers, reported by Kazuo Kuroi
|
||||
|
||||
- Fix potential long delay in dbclient, found by OSS Fuzz
|
||||
|
||||
- Fix null pointer dereference crash, found by OSS Fuzz
|
||||
|
||||
- libtommath now uses the same random source as Dropbear (in 2020.79
|
||||
and 2020.80 used getrandom() separately)
|
||||
|
||||
- Some fuzzing improvements, start of a dbclient fuzzer
|
||||
|
||||
2020.80 - 26 June 2020
|
||||
|
||||
- Don't block authorized_keys logins with no-X11-forwarding or no-agent-forwarding
|
||||
restrictions when X11 or agent forwarding are disabled at compile time.
|
||||
This is more of a problem now X11 is disabled by default, reported by Guilhem Moulin
|
||||
|
||||
- Reduce binary size by 4kB (x64) when using bundled libtommath
|
||||
|
||||
- Define GNU_SOURCE for getrandom() on uclibc, reported by Laurent Bercot and
|
||||
Fabrice Fontaine
|
||||
|
||||
- Improve checking libtomcrypt version compatibility
|
||||
|
||||
- Add some style notes to DEVELOPING.md
|
||||
|
||||
2020.79 - 15 June 2020
|
||||
|
||||
- Support ed25519 hostkeys and authorized_keys, many thanks to Vladislav Grishenko.
|
||||
This also replaces curve25519 with a TweetNaCl implementation that reduces code size.
|
||||
|
||||
- Add chacha20-poly1305 authenticated cipher. This will perform faster than AES
|
||||
on many platforms. Thanks to Vladislav Grishenko
|
||||
|
||||
- Support using rsa-sha2 signatures. No changes are needed to hostkeys/authorized_keys
|
||||
entries, existing RSA keys can be used with the new signature format (signatures
|
||||
are ephemeral within a session). Old ssh-rsa signatures will no longer
|
||||
be supported by OpenSSH in future so upgrading is recommended.
|
||||
|
||||
- Use getrandom() call on Linux to ensure sufficient entropy has been gathered at startup.
|
||||
Dropbear now avoids reading from the random source at startup, instead waiting until
|
||||
the first connection. It is possible that some platforms were running without enough
|
||||
entropy previously, those could potentially block at first boot generating host keys.
|
||||
The dropbear "-R" option is one way to avoid that.
|
||||
|
||||
- Upgrade libtomcrypt to 1.18.2 and libtommath to 1.2.0, many thanks to Steffen Jaeckel for
|
||||
updating Dropbear to use the current API. Dropbear's configure script will check
|
||||
for sufficient system library versions, otherwise using the bundled versions.
|
||||
|
||||
- CBC ciphers, 3DES, hmac-sha1-96, and x11 forwarding are now disabled by default.
|
||||
They can be set in localoptions.h if required.
|
||||
Blowfish has been removed.
|
||||
|
||||
- Support AES GCM, patch from Vladislav Grishenko. This is disabled by default,
|
||||
Dropbear doesn't currently use hardware accelerated AES.
|
||||
|
||||
- Added an API for specifying user public keys as an authorized_keys replacement.
|
||||
See pubkeyapi.h for details, thanks to Fabrizio Bertocci
|
||||
|
||||
- Fix idle detection clashing with keepalives, thanks to jcmathews
|
||||
|
||||
- Include IP addresses in more early exit messages making it easier for fail2ban
|
||||
processing. Patch from Kevin Darbyshire-Bryant
|
||||
|
||||
- scp fix for CVE-2018-20685 where a server could modify name of output files
|
||||
|
||||
- SSH_ORIGINAL_COMMAND is set for "dropbear -c" forced command too
|
||||
|
||||
- Fix writing key files on systems without hard links, from Matt Robinson
|
||||
|
||||
- Compatibility fixes for IRIX from Kazuo Kuroi
|
||||
|
||||
- Re-enable printing MOTD by default, was lost moving from options.h. Thanks to zciendor
|
||||
|
||||
- Call fsync() is called on parent directory when writing key files to ensure they are flushed
|
||||
|
||||
- Fix "make install" for manpages in out-of-tree builds, from Gabor Z. Papp
|
||||
|
||||
- Some notes are added in DEVELOPING.md
|
||||
|
||||
2019.78 - 27 March 2019
|
||||
|
||||
- Fix dbclient regression in 2019.77. After exiting the terminal would be left
|
||||
in a bad state. Reported by Ryan Woodsmall
|
||||
|
||||
2019.77 - 23 March 2019
|
||||
|
||||
- Fix server -R option with ECDSA - only advertise one key size which will be accepted.
|
||||
Reported by Peter Krefting, 2018.76 regression.
|
||||
|
||||
- Fix server regression in 2018.76 where multiple client -R forwards were all forwarded
|
||||
to the first destination. Reported by Iddo Samet.
|
||||
|
||||
- Make failure delay more consistent to avoid revealing valid usernames, set server password
|
||||
limit of 100 characters. Problem reported by usd responsible disclosure team
|
||||
|
||||
- Change handling of failed authentication to avoid disclosing valid usernames,
|
||||
CVE-2018-15599.
|
||||
|
||||
- Fix dbclient to reliably return the exit code from the remote server.
|
||||
Reported by W. Mike Petullo
|
||||
|
||||
- Fix export of 521-bit ECDSA keys, from Christian Hohnstädt
|
||||
|
||||
- Add -o Port=xxx option to work with sshfs, from xcko
|
||||
|
||||
- Merged fuzzing code, see FUZZER-NOTES.md
|
||||
|
||||
- Add a DROPBEAR_SVR_MULTIUSER=0 compile option to run on
|
||||
single-user Linux kernels (CONFIG_MULTIUSER disabled). From Patrick Stewart
|
||||
|
||||
- Increase allowed username to 100 characters, reported by W. Mike Petullo
|
||||
|
||||
- Update config.sub and config.guess, should now work with RISC-V
|
||||
|
||||
- Cygwin compile fix from karel-m
|
||||
|
||||
- Don't require GNU sed (accidentally in 2018.76), reported by Samuel Hsu
|
||||
|
||||
- Fix for IRIX and writev(), reported by Kazuo Kuroi
|
||||
|
||||
- Other fixes and cleanups from François Perrad, Andre McCurdy, Konstantin Demin,
|
||||
Michael Jones, Pawel Rapkiewicz
|
||||
|
||||
|
||||
2018.76 - 27 February 2018
|
||||
|
||||
> > > Configuration/compatibility changes
|
||||
IMPORTANT
|
||||
Custom configuration is now specified in local_options.h rather than options.h
|
||||
Custom configuration is now specified in localoptions.h rather than options.h
|
||||
Available options and defaults can be seen in default_options.h
|
||||
|
||||
To migrate your configuration, compare your customised options.h against the
|
||||
upstream options.h from your relevant version. Any customised options should
|
||||
be put in localoptions.h
|
||||
be put in localoptions.h in the build directory.
|
||||
|
||||
- "configure --enable-static" should now be used instead of "make STATIC=1"
|
||||
This will avoid 'hardened build' flags that conflict with static binaries
|
||||
@@ -101,7 +234,7 @@
|
||||
dropbear is running with -a (Allow connections to forwarded ports from any host)
|
||||
This could potentially allow arbitrary code execution as root by an authenticated user.
|
||||
Affects versions 2013.56 to 2016.74. Thanks to Mark Shepard for reporting the crash.
|
||||
CVE-2017-9078 https://secure.ucc.asn.au/hg/dropbear/rev/c8114a48837c
|
||||
CVE-2017-9078 https://hg.ucc.asn.au/dropbear/rev/c8114a48837c
|
||||
|
||||
- Security: Fix information disclosure with ~/.ssh/authorized_keys symlink.
|
||||
Dropbear parsed authorized_keys as root, even if it were a symlink. The fix
|
||||
@@ -113,7 +246,7 @@
|
||||
contents of that file.
|
||||
This information disclosure is to an already authenticated user.
|
||||
Thanks to Jann Horn of Google Project Zero for reporting this.
|
||||
CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123
|
||||
CVE-2017-9079 https://hg.ucc.asn.au/dropbear/rev/0d889b068123
|
||||
|
||||
- Generate hostkeys with dropbearkey atomically and flush to disk with fsync
|
||||
Thanks to Andrei Gherzan for a patch
|
||||
@@ -133,23 +266,23 @@
|
||||
run arbitrary code as the dbclient user. This could be a problem if scripts
|
||||
or webpages pass untrusted input to the dbclient program.
|
||||
CVE-2016-7406
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb
|
||||
https://hg.ucc.asn.au/dropbear/rev/b66a483f3dcb
|
||||
|
||||
- Security: dropbearconvert import of OpenSSH keys could run arbitrary code as
|
||||
the local dropbearconvert user when parsing malicious key files
|
||||
CVE-2016-7407
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e
|
||||
https://hg.ucc.asn.au/dropbear/rev/34e6127ef02e
|
||||
|
||||
- Security: dbclient could run arbitrary code as the local dbclient user if
|
||||
particular -m or -c arguments are provided. This could be an issue where
|
||||
dbclient is used in scripts.
|
||||
CVE-2016-7408
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6
|
||||
https://hg.ucc.asn.au/dropbear/rev/eed9376a4ad6
|
||||
|
||||
- Security: dbclient or dropbear server could expose process memory to the
|
||||
running user if compiled with DEBUG_TRACE and running with -v
|
||||
CVE-2016-7409
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04
|
||||
https://hg.ucc.asn.au/dropbear/rev/6a14b1f6dc04
|
||||
|
||||
The security issues were reported by an anonymous researcher working with
|
||||
Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html
|
||||
@@ -195,7 +328,7 @@
|
||||
|
||||
- Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions,
|
||||
found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff
|
||||
https://hg.ucc.asn.au/dropbear/rev/a3e8389e01ff
|
||||
|
||||
2015.71 - 3 December 2015
|
||||
|
||||
@@ -476,11 +609,11 @@ kernels, from Steve Dover
|
||||
- Limit the size of decompressed payloads, avoids memory exhaustion denial
|
||||
of service
|
||||
Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f
|
||||
https://hg.ucc.asn.au/dropbear/rev/0bf76f54de6f
|
||||
|
||||
- Avoid disclosing existence of valid users through inconsistent delays
|
||||
Thanks to Logan Lamb for reporting. CVE-2013-4434
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a
|
||||
https://hg.ucc.asn.au/dropbear/rev/d7784616409a
|
||||
|
||||
- Update config.guess and config.sub for newer architectures
|
||||
|
||||
@@ -583,7 +716,7 @@ though probably will be soon
|
||||
This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
|
||||
Thanks to Danny Fullerton of Mantor Organization for reporting
|
||||
the bug.
|
||||
https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749
|
||||
https://hg.ucc.asn.au/dropbear/rev/818108bf7749
|
||||
|
||||
- Compile fix, only apply IPV6 socket options if they are available in headers
|
||||
Thanks to Gustavo Zacarias for the patch
|
||||
@@ -627,7 +760,7 @@ though probably will be soon
|
||||
- New version numbering scheme.
|
||||
|
||||
Source repository has now migrated to Mercurial at
|
||||
https://secure.ucc.asn.au/hg/dropbear/graph/default
|
||||
https://hg.ucc.asn.au/dropbear/graph/default
|
||||
|
||||
0.53.1 - Wednesday 2 March 2011
|
||||
|
||||
|
||||
75
DEVELOPING.md
Normal file
75
DEVELOPING.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Developer Notes
|
||||
|
||||
## Building
|
||||
|
||||
See [INSTALL](INSTALL) for build instructions.
|
||||
[SMALL](SMALL) has hints for building smaller binaries, also see comments
|
||||
in default_options.h.
|
||||
|
||||
## Debug printing
|
||||
|
||||
Set `#define DEBUG_TRACE 1` in localoptions.h to enable a `-v` option
|
||||
for dropbear and dbclient. That prints various details of the session. For
|
||||
development running `dropbear -F -E` is useful to run in the foreground. You
|
||||
can set `#define DEBUG_NOFORK 1` to make dropbear a one-shot server, easy to
|
||||
run under a debugger.
|
||||
|
||||
## Random sources
|
||||
|
||||
Most cryptography requires a good random entropy source, both to generate secret
|
||||
keys and in the course of a session. Dropbear uses the Linux kernel's
|
||||
`getrandom()` syscall to ensure that the system RNG has been initialised before
|
||||
using it. On some systems there is insufficient entropy gathered during early
|
||||
boot - generating hostkeys then will block for some amount of time.
|
||||
Dropbear has a `-R` option to generate hostkeys upon the first connection
|
||||
as required - that will allow the system more time to gather entropy.
|
||||
|
||||
## Algorithms
|
||||
|
||||
Default algorithm lists are specified in [common-algo.c](common-algo.c).
|
||||
They are in priority order, the client's first matching choice is used
|
||||
(see rfc4253).
|
||||
Dropbear client has `-c` and `-m` arguments to choose which are enabled at
|
||||
runtime (doesn't work for server as of June 2020).
|
||||
|
||||
Enabling/disabling algorithms is done in [localoptions.h](localoptions.h),
|
||||
see [default_options.h](default_options.h).
|
||||
|
||||
## Style
|
||||
|
||||
Source code is indented with tabs, width set to 4 (though width shouldn't
|
||||
matter much). Braces are on the same line as functions/loops/if - try
|
||||
to keep consistency with existing code.
|
||||
|
||||
All `if` statements should have braces, no exceptions.
|
||||
|
||||
Avoid using pointer arithmetic, instead the functions in
|
||||
[buffer.h](buffer.h) should be used.
|
||||
|
||||
Some Dropbear platforms have old compilers.
|
||||
Variable declarations must be at the top of a scope and
|
||||
comments must be `/* */` rather than `//`.
|
||||
|
||||
Pointer variables should be initialised to NULL - it can reduce the
|
||||
severity of bugs.
|
||||
|
||||
## Third party code
|
||||
|
||||
Libtomcrypt and libtommath are periodically synced from upstream, so
|
||||
avoid making changes to that code which will need to be maintained.
|
||||
Improvements can be sent upstream to the libtom project.
|
||||
|
||||
## Non-root user
|
||||
|
||||
Dropbear server will run fine as a non-root user, allowing logins only for
|
||||
that user. Password authentication probably won't work (can't read shadow
|
||||
passwords). You will need to create hostkeys that are readable.
|
||||
|
||||
## Connection setup
|
||||
|
||||
Dropbear implements first_kex_packet_follows to reduce
|
||||
handshake latency (rfc 4253 7.1). Some less common implementations don't
|
||||
handle that, it can be a cause of problems connecting. Note also that
|
||||
Dropbear may send several ssh packets within a single TCP packet - it's just a
|
||||
stream.
|
||||
|
||||
77
FUZZER-NOTES.md
Normal file
77
FUZZER-NOTES.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Fuzzing Dropbear
|
||||
|
||||
Dropbear is process-per-session so it assumes calling `dropbear_exit()`
|
||||
is fine at any point to clean up. This makes fuzzing a bit trickier.
|
||||
A few pieces of wrapping infrastructure are used to work around this.
|
||||
|
||||
The [libfuzzer](http://llvm.org/docs/LibFuzzer.html#fuzz-target) harness
|
||||
expects a long running process to continually run a test function with
|
||||
a string of crafted input. That process should not leak resources or exit.
|
||||
|
||||
## longjmp
|
||||
|
||||
When dropbear runs in fuzz mode it sets up a
|
||||
[`setjmp()`](http://man7.org/linux/man-pages/man3/setjmp.3.html) target prior
|
||||
to launching the code to be fuzzed, and then [`dropbear_exit()`](dbutil.c#L125)
|
||||
calls `longjmp()` back there. This avoids exiting though it doesn't free
|
||||
memory or other resources.
|
||||
|
||||
## malloc Wrapper
|
||||
|
||||
Dropbear normally uses a [`m_malloc()`](dbmalloc.c) function that is the same as `malloc()` but
|
||||
exits if allocation fails. In fuzzing mode this is replaced with a tracking allocator
|
||||
that stores all allocations in a linked list. After the `longjmp()` occurs the fuzzer target
|
||||
calls [`m_malloc_free_epoch(1, 1)`](dbmalloc.c) to clean up any unreleased memory.
|
||||
|
||||
If the fuzz target runs to completion it calls `m_malloc_free_epoch(1, 0)` which will reset
|
||||
the tracked allocations but will not free memory - that allows libfuzzer's leak checking
|
||||
to detect leaks in normal operation.
|
||||
|
||||
## File Descriptor Input
|
||||
|
||||
As a network process Dropbear reads and writes from a socket. The wrappers for
|
||||
`read()`/`write()`/`select()` in [fuzz-wrapfd.c](fuzz-wrapfd.c) will read from the
|
||||
fuzzer input that has been set up with `wrapfd_add()`. `write()` output is
|
||||
currently discarded.
|
||||
These also test error paths such as EINTR and short reads with certain probabilities.
|
||||
|
||||
This allows running the entire dropbear server process with network input provided by the
|
||||
fuzzer, without many modifications to the main code. At the time of writing this
|
||||
only runs the pre-authentication stages, though post-authentication could be run similarly.
|
||||
|
||||
## Encryption and Randomness
|
||||
|
||||
When running in fuzzing mode Dropbear uses a [fixed seed](dbrandom.c#L185)
|
||||
every time so that failures can be reproduced.
|
||||
|
||||
Since the fuzzer cannot generate valid encrypted input the packet decryption and
|
||||
message authentication calls are disabled, see [packet.c](packet.c).
|
||||
MAC failures are set to occur with a low probability to test that error path.
|
||||
|
||||
## Fuzzers
|
||||
|
||||
Current fuzzers are
|
||||
|
||||
- [fuzzer-preauth](fuzzer-preauth.c) - the fuzzer input is treated as a stream of session input. This will
|
||||
test key exchange, packet ordering, authentication attempts etc.
|
||||
|
||||
- [fuzzer-preauth_nomaths](fuzzer-preauth_nomaths.c) - the same as fuzzer-preauth but with asymmetric crypto
|
||||
routines replaced with dummies for faster runtime. corpora are shared
|
||||
between fuzzers by [oss-fuzz](https://github.com/google/oss-fuzz) so this
|
||||
will help fuzzer-preauth too.
|
||||
|
||||
- [fuzzer-verify](fuzzer-verify.c) - read a key and signature from fuzzer input and verify that signature.
|
||||
It would not be expected to pass, though some keys with bad parameters are
|
||||
able to validate with a trivial signature - extra checks are added for that.
|
||||
|
||||
- [fuzzer-pubkey](fuzzer-pubkey.c) - test parsing of an `authorized_keys` line.
|
||||
|
||||
- [fuzzer-kexdh](fuzzer-kexdh.c) - test Diffie-Hellman key exchange where the fuzz input is the
|
||||
ephemeral public key that would be received over the network. This is testing `mp_expt_mod()`
|
||||
and and other libtommath routines.
|
||||
|
||||
- [fuzzer-kexecdh](fuzzer-kexecdh.c) - test Elliptic Curve Diffie-Hellman key exchange like fuzzer-kexdh.
|
||||
This is testing libtommath ECC routines.
|
||||
|
||||
- [fuzzer-kexcurve25519](fuzzer-kexcurve25519.c) - test Curve25519 Elliptic Curve Diffie-Hellman key exchange
|
||||
like fuzzer-kexecdh. This is testing `dropbear_curve25519_scalarmult()` and other libtommath routines.
|
||||
10
INSTALL
10
INSTALL
@@ -3,13 +3,15 @@ Basic Dropbear build instructions:
|
||||
- Edit localoptions.h to set which features you want. Available options
|
||||
are described in default_options.h, these will be overridden by
|
||||
anything set in localoptions.h
|
||||
|
||||
- If using a Mercurial or Git checkout, "autoconf; autoheader"
|
||||
localoptions.h should be located in the build directory if you are
|
||||
building out of tree.
|
||||
|
||||
- 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"
|
||||
@@ -26,6 +28,8 @@ Basic Dropbear build instructions:
|
||||
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
|
||||
recompiling - bad things will happen otherwise)
|
||||
|
||||
DEVELOPING.md has some notes on other developer topics, including debugging.
|
||||
|
||||
See MULTI for instructions on making all-in-one binaries.
|
||||
|
||||
If you want to compile statically use ./configure --enable-static
|
||||
@@ -54,7 +58,7 @@ Compiling for uClibc should be the same as normal, just set CC to the magic
|
||||
uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
|
||||
You can use "make STATIC=1" to make statically linked binaries, and it is
|
||||
advisable to strip the binaries too. If you're looking to make a small binary,
|
||||
you should remove unneeded ciphers and MD5, by editing options.h
|
||||
you should remove unneeded ciphers and MD5, by editing localoptions.h
|
||||
|
||||
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
|
||||
subdirectory (ie zlibincludes), and
|
||||
|
||||
73
LICENSE
73
LICENSE
@@ -8,7 +8,7 @@ The majority of code is written by Matt Johnston, under the license below.
|
||||
Portions of the client-mode work are (c) 2004 Mihnea Stoenescu, under the
|
||||
same license:
|
||||
|
||||
Copyright (c) 2002-2015 Matt Johnston
|
||||
Copyright (c) 2002-2020 Matt Johnston
|
||||
Portions copyright (c) 2004 Mihnea Stoenescu
|
||||
All rights reserved.
|
||||
|
||||
@@ -32,7 +32,8 @@ SOFTWARE.
|
||||
|
||||
=====
|
||||
|
||||
LibTomCrypt and LibTomMath are written by Tom St Denis, and are Public Domain.
|
||||
LibTomCrypt and LibTomMath are written by Tom St Denis and others, see
|
||||
libtomcrypt/LICENSE and libtommath/LICENSE.
|
||||
|
||||
=====
|
||||
|
||||
@@ -90,52 +91,24 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
=====
|
||||
|
||||
curve25519-donna:
|
||||
curve25519.c:
|
||||
|
||||
/* Copyright 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* More information about curve25519 can be found here
|
||||
* http://cr.yp.to/ecdh.html
|
||||
*
|
||||
* djb's sample implementation of curve25519 is written in a special assembly
|
||||
* language called qhasm and uses the floating point registers.
|
||||
*
|
||||
* This is, almost, a clean room reimplementation from the curve25519 paper. It
|
||||
* uses many of the tricks described therein. Only the crecip function is taken
|
||||
* from the sample implementation.
|
||||
*/
|
||||
Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
https://tweetnacl.cr.yp.to/
|
||||
|
||||
Contributors (alphabetical order)
|
||||
Daniel J. Bernstein, University of Illinois at Chicago and Technische
|
||||
Universiteit Eindhoven
|
||||
Bernard van Gastel, Radboud Universiteit Nijmegen
|
||||
Wesley Janssen, Radboud Universiteit Nijmegen
|
||||
Tanja Lange, Technische Universiteit Eindhoven
|
||||
Peter Schwabe, Radboud Universiteit Nijmegen
|
||||
Sjaak Smetsers, Radboud Universiteit Nijmegen
|
||||
|
||||
Acknowledgments
|
||||
This work was supported by the U.S. National Science Foundation under grant
|
||||
1018836. "Any opinions, findings, and conclusions or recommendations expressed
|
||||
in this material are those of the author(s) and do not necessarily reflect the
|
||||
views of the National Science Foundation."
|
||||
This work was supported by the Netherlands Organisation for Scientific
|
||||
Research (NWO) under grant 639.073.005 and Veni 2013 project 13114.
|
||||
|
||||
117
Makefile.in
117
Makefile.in
@@ -35,8 +35,10 @@ 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 crypto_desc.o \
|
||||
gensignkey.o gendss.o genrsa.o
|
||||
ltc_prng.o ecc.o ecdsa.o sk-ecdsa.o crypto_desc.o \
|
||||
curve25519.o ed25519.o sk-ed25519.o \
|
||||
dbmalloc.o \
|
||||
gensignkey.o gendss.o genrsa.o gened25519.o
|
||||
|
||||
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
|
||||
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
|
||||
@@ -51,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
|
||||
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
|
||||
common-channel.o common-chansession.o termcodes.o loginrec.o \
|
||||
tcp-accept.o listener.o process-packet.o dh_groups.o \
|
||||
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
|
||||
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
|
||||
|
||||
KEYOBJS=dropbearkey.o
|
||||
|
||||
@@ -59,11 +61,34 @@ CONVERTOBJS=dropbearconvert.o keyimport.o
|
||||
|
||||
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
|
||||
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
scpobjs=$(SCPOBJS)
|
||||
ifeq (@DROPBEAR_FUZZ@, 1)
|
||||
allobjs = $(COMMONOBJS) fuzz/fuzz-common.o fuzz/fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
|
||||
allobjs:=$(subst svr-main.o, ,$(allobjs))
|
||||
allobjs:=$(subst cli-main.o, ,$(allobjs))
|
||||
|
||||
dropbearobjs=$(allobjs) svr-main.o
|
||||
dbclientobjs=$(allobjs) cli-main.o
|
||||
dropbearkeyobjs=$(allobjs) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
|
||||
# CXX only set when fuzzing
|
||||
CXX=@CXX@
|
||||
FUZZ_CLEAN=fuzz-clean
|
||||
else
|
||||
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
|
||||
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
|
||||
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
|
||||
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
|
||||
scpobjs=$(SCPOBJS)
|
||||
endif
|
||||
|
||||
ifeq (@DROPBEAR_PLUGIN@, 1)
|
||||
# rdynamic makes all the global symbols of dropbear available to all the loaded shared libraries
|
||||
# this allow a plugin to reuse existing crypto/utilities like base64_decode/base64_encode without
|
||||
# the need to rewrite them.
|
||||
PLUGIN_LIBS=-ldl -rdynamic
|
||||
else
|
||||
PLUGIN_LIBS=
|
||||
endif
|
||||
|
||||
VPATH=@srcdir@
|
||||
srcdir=@srcdir@
|
||||
@@ -150,7 +175,7 @@ insmulti%: dropbearmulti$(EXEEXT)
|
||||
-rm -f $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
# dropbear should go in sbin, so it needs a separate rule
|
||||
inst_dropbear: dropbear
|
||||
@@ -163,7 +188,7 @@ inst_%: %
|
||||
$(INSTALL) -d $(DESTDIR)$(bindir)
|
||||
$(INSTALL) $*$(EXEEXT) $(DESTDIR)$(bindir)
|
||||
$(INSTALL) -d $(DESTDIR)$(mandir)/man1
|
||||
if test -e $*.1; then $(INSTALL) -m 644 $*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
if test -e $(srcdir)/$*.1; then $(INSTALL) -m 644 $(srcdir)/$*.1 $(DESTDIR)$(mandir)/man1/$*.1; fi
|
||||
|
||||
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
|
||||
|
||||
@@ -174,13 +199,13 @@ dropbearkey: $(dropbearkeyobjs)
|
||||
dropbearconvert: $(dropbearconvertobjs)
|
||||
|
||||
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ $(PLUGIN_LIBS)
|
||||
|
||||
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
|
||||
dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS)
|
||||
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
|
||||
|
||||
# scp doesn't use the libs so is special.
|
||||
scp: $(SCPOBJS) $(HEADERS) Makefile
|
||||
@@ -211,7 +236,7 @@ $(STATIC_LTC): $(OPTION_HEADERS)
|
||||
$(STATIC_LTM): $(OPTION_HEADERS)
|
||||
$(MAKE) -C libtommath
|
||||
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean
|
||||
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean lint check
|
||||
|
||||
ltc-clean:
|
||||
$(MAKE) -C libtomcrypt clean
|
||||
@@ -222,7 +247,7 @@ ltm-clean:
|
||||
sizes: dropbear
|
||||
objdump -t dropbear|grep ".text"|cut -d "." -f 2|sort -rn
|
||||
|
||||
clean: $(LIBTOM_CLEAN) thisclean
|
||||
clean: $(LIBTOM_CLEAN) $(FUZZ_CLEAN) thisclean
|
||||
|
||||
thisclean:
|
||||
-rm -f dropbear$(EXEEXT) dbclient$(EXEEXT) dropbearkey$(EXEEXT) \
|
||||
@@ -236,3 +261,67 @@ distclean: clean tidy
|
||||
|
||||
tidy:
|
||||
-rm -f *~ *.gcov */*~
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
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@
|
||||
|
||||
# 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
|
||||
|
||||
# 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-%.options: Makefile
|
||||
echo "[libfuzzer]" > $@
|
||||
echo "max_len = 50000" >> $@
|
||||
|
||||
# run this to update hardcoded hostkeys for for fuzzing.
|
||||
# hostkeys.c is checked in to hg.
|
||||
fuzz-hostkeys:
|
||||
dropbearkey -t rsa -f keyr
|
||||
dropbearkey -t dss -f keyd
|
||||
dropbearkey -t ecdsa -size 256 -f keye
|
||||
dropbearkey -t ed25519 -f keyed25519
|
||||
echo > hostkeys.c
|
||||
/usr/bin/xxd -i -a keyr >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keye >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keyd >> hostkeys.c
|
||||
/usr/bin/xxd -i -a keyed25519 >> hostkeys.c
|
||||
|
||||
fuzz-clean:
|
||||
-rm -f fuzz/*.o $(FUZZ_TARGETS) $(FUZZER_OPTIONS)
|
||||
|
||||
3
README
3
README
@@ -51,10 +51,11 @@ dropbearkey's '-y' option.
|
||||
|
||||
============================================================================
|
||||
|
||||
To run the server, you need to server keys, this is one-off:
|
||||
To run the server, you need to generate server keys, this is one-off:
|
||||
./dropbearkey -t rsa -f dropbear_rsa_host_key
|
||||
./dropbearkey -t dss -f dropbear_dss_host_key
|
||||
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
|
||||
./dropbearkey -t ed25519 -f dropbear_ed25519_host_key
|
||||
|
||||
or alternatively convert OpenSSH keys to Dropbear:
|
||||
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
|
||||
/* From OpenSSH authfd.h */
|
||||
#define SSH_AGENT_RSA_SHA2_256 0x02
|
||||
|
||||
/* An agent reply can be reasonably large, as it can
|
||||
* contain a list of all public keys held by the agent.
|
||||
* 10000 is arbitrary */
|
||||
@@ -40,7 +43,7 @@
|
||||
/* client functions */
|
||||
void cli_load_agent_keys(m_list * ret_list);
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const buffer *data_buf);
|
||||
const buffer *data_buf, enum signature_type type);
|
||||
void cli_setup_agent(const struct Channel *channel);
|
||||
|
||||
#ifdef __hpux
|
||||
|
||||
26
algo.h
26
algo.h
@@ -47,7 +47,7 @@ typedef struct Algo_Type algo_type;
|
||||
|
||||
/* lists mapping ssh types of algorithms to internal values */
|
||||
extern algo_type sshkex[];
|
||||
extern algo_type sshhostkey[];
|
||||
extern algo_type sigalgs[];
|
||||
extern algo_type sshciphers[];
|
||||
extern algo_type sshhashes[];
|
||||
extern algo_type ssh_compress[];
|
||||
@@ -72,6 +72,14 @@ struct dropbear_cipher_mode {
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*decrypt)(const unsigned char *ct, unsigned char *pt,
|
||||
unsigned long len, void *cipher_state);
|
||||
int (*aead_crypt)(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
void *cipher_state, int direction);
|
||||
int (*aead_getlength)(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, void *cipher_state);
|
||||
const struct dropbear_hash *aead_mac;
|
||||
};
|
||||
|
||||
struct dropbear_hash {
|
||||
@@ -112,21 +120,17 @@ struct dropbear_kex {
|
||||
const struct ltc_hash_descriptor *hash_desc;
|
||||
};
|
||||
|
||||
int have_algo(const char* algo, size_t algolen, const algo_type algos[]);
|
||||
/* Includes all algorithms is useall is set */
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall);
|
||||
/* Includes "usable" algorithms */
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]);
|
||||
|
||||
enum kexguess2_used {
|
||||
KEXGUESS2_LOOK,
|
||||
KEXGUESS2_NO,
|
||||
KEXGUESS2_YES,
|
||||
};
|
||||
|
||||
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
|
||||
#define KEXGUESS2_ALGO_ID 99
|
||||
|
||||
|
||||
int buf_has_algo(buffer *buf, const char *algo);
|
||||
algo_type * first_usable_algo(algo_type algos[]);
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess);
|
||||
int kexguess2, int *goodguess);
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
int check_user_algos(const char* user_algo_list, algo_type * algos,
|
||||
|
||||
12
auth.h
12
auth.h
@@ -30,16 +30,15 @@
|
||||
#include "chansession.h"
|
||||
|
||||
void svr_authinitialise(void);
|
||||
void cli_authinitialise(void);
|
||||
|
||||
/* Server functions */
|
||||
void recv_msg_userauth_request(void);
|
||||
void send_msg_userauth_failure(int partial, int incrfail);
|
||||
void send_msg_userauth_success(void);
|
||||
void send_msg_userauth_banner(const buffer *msg);
|
||||
void svr_auth_password(void);
|
||||
void svr_auth_pubkey(void);
|
||||
void svr_auth_pam(void);
|
||||
void svr_auth_password(int valid_user);
|
||||
void svr_auth_pubkey(int valid_user);
|
||||
void svr_auth_pam(int valid_user);
|
||||
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
int svr_pubkey_allows_agentfwd(void);
|
||||
@@ -78,7 +77,7 @@ char* getpass_or_cancel(const char* prompt);
|
||||
void cli_auth_pubkey_cleanup(void);
|
||||
|
||||
|
||||
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
|
||||
#define MAX_USERNAME_LEN 100 /* arbitrary for the moment */
|
||||
|
||||
#define AUTH_TYPE_NONE 1
|
||||
#define AUTH_TYPE_PUBKEY (1 << 1)
|
||||
@@ -108,11 +107,14 @@ struct AuthState {
|
||||
unsigned int authdone; /* 0 if we haven't authed, 1 if we have. Applies for
|
||||
client and server (though has differing
|
||||
meanings). */
|
||||
|
||||
unsigned int perm_warn; /* Server only, set if bad permissions on
|
||||
~/.ssh/authorized_keys have already been
|
||||
logged. */
|
||||
unsigned int checkusername_failed; /* Server only, set if checkusername
|
||||
has already failed */
|
||||
struct timespec auth_starttime; /* Server only, time of receiving current
|
||||
SSH_MSG_USERAUTH_REQUEST */
|
||||
|
||||
/* These are only used for the server */
|
||||
uid_t pw_uid;
|
||||
|
||||
2
bignum.c
2
bignum.c
@@ -86,7 +86,7 @@ void m_mp_free_multi(mp_int **mp, ...)
|
||||
|
||||
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
|
||||
|
||||
if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
if (mp_from_ubin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
|
||||
dropbear_exit("Mem alloc error");
|
||||
}
|
||||
}
|
||||
|
||||
71
buffer.c
71
buffer.c
@@ -39,44 +39,30 @@
|
||||
|
||||
/* Create (malloc) a new buffer of size */
|
||||
buffer* buf_new(unsigned int size) {
|
||||
|
||||
buffer* buf;
|
||||
|
||||
if (size > BUF_MAX_SIZE) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
|
||||
buf = (buffer*)m_malloc(sizeof(buffer)+size);
|
||||
|
||||
if (size > 0) {
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
} else {
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
buf->data = (unsigned char*)buf + sizeof(buffer);
|
||||
buf->size = size;
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
/* free the buffer's data and the buffer itself */
|
||||
void buf_free(buffer* buf) {
|
||||
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
/* overwrite the contents of the buffer to clear it */
|
||||
void buf_burn(const buffer* buf) {
|
||||
|
||||
m_burn(buf->data, buf->size);
|
||||
|
||||
}
|
||||
|
||||
/* resize a buffer, pos and len will be repositioned if required when
|
||||
* downsizing */
|
||||
buffer* buf_resize(buffer *buf, unsigned int newsize) {
|
||||
|
||||
if (newsize > BUF_MAX_SIZE) {
|
||||
dropbear_exit("buf->size too big");
|
||||
}
|
||||
@@ -139,18 +125,23 @@ void buf_incrwritepos(buffer* buf, unsigned int incr) {
|
||||
}
|
||||
}
|
||||
|
||||
/* increment the position by incr, negative values are allowed, to
|
||||
* decrement the pos*/
|
||||
void buf_incrpos(buffer* buf, int incr) {
|
||||
/* increment the position by incr */
|
||||
void buf_incrpos(buffer* buf, unsigned int incr) {
|
||||
if (incr > BUF_MAX_INCR
|
||||
|| incr < -BUF_MAX_INCR
|
||||
|| (unsigned int)((int)buf->pos + incr) > buf->len
|
||||
|| ((int)buf->pos + incr) < 0) {
|
||||
|| (buf->pos + incr) > buf->len) {
|
||||
dropbear_exit("Bad buf_incrpos");
|
||||
}
|
||||
buf->pos += incr;
|
||||
}
|
||||
|
||||
/* decrement the position by decr */
|
||||
void buf_decrpos(buffer* buf, unsigned int decr) {
|
||||
if (decr > buf->pos) {
|
||||
dropbear_exit("Bad buf_decrpos");
|
||||
}
|
||||
buf->pos -= decr;
|
||||
}
|
||||
|
||||
/* Get a byte from the buffer and increment the pos */
|
||||
unsigned char buf_getbyte(buffer* buf) {
|
||||
|
||||
@@ -209,6 +200,7 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
|
||||
unsigned int len;
|
||||
char* ret;
|
||||
void* src = NULL;
|
||||
len = buf_getint(buf);
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
@@ -217,8 +209,9 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
if (retlen != NULL) {
|
||||
*retlen = len;
|
||||
}
|
||||
src = buf_getptr(buf, len);
|
||||
ret = m_malloc(len+1);
|
||||
memcpy(ret, buf_getptr(buf, len), len);
|
||||
memcpy(ret, src, len);
|
||||
buf_incrpos(buf, len);
|
||||
ret[len] = '\0';
|
||||
|
||||
@@ -226,19 +219,37 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
static buffer * buf_getstringbuf_int(buffer *buf, int incllen) {
|
||||
buffer *ret = NULL;
|
||||
unsigned int len = buf_getint(buf);
|
||||
int extra = 0;
|
||||
if (len > MAX_STRING_LEN) {
|
||||
dropbear_exit("String too long");
|
||||
}
|
||||
ret = buf_new(len);
|
||||
if (incllen) {
|
||||
extra = 4;
|
||||
}
|
||||
ret = buf_new(len+extra);
|
||||
if (incllen) {
|
||||
buf_putint(ret, len);
|
||||
}
|
||||
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
|
||||
buf_incrpos(buf, len);
|
||||
buf_incrlen(ret, len);
|
||||
buf_setpos(ret, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return a string as a newly allocated buffer */
|
||||
buffer * buf_getstringbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 0);
|
||||
}
|
||||
|
||||
/* Returns a string in a new buffer, including the length */
|
||||
buffer * buf_getbuf(buffer *buf) {
|
||||
return buf_getstringbuf_int(buf, 1);
|
||||
}
|
||||
|
||||
/* Just increment the buffer position the same as if we'd used buf_getstring,
|
||||
* but don't bother copying/malloc()ing for it */
|
||||
void buf_eatstring(buffer *buf) {
|
||||
@@ -287,18 +298,18 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
|
||||
/* for our purposes we only need positive (or 0) numbers, so will
|
||||
* fail if we get negative numbers */
|
||||
void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
|
||||
size_t written;
|
||||
unsigned int len, pad = 0;
|
||||
TRACE2(("enter buf_putmpint"))
|
||||
|
||||
dropbear_assert(mp != NULL);
|
||||
|
||||
if (SIGN(mp) == MP_NEG) {
|
||||
if (mp_isneg(mp)) {
|
||||
dropbear_exit("negative bignum");
|
||||
}
|
||||
|
||||
/* zero check */
|
||||
if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
|
||||
if (mp_iszero(mp)) {
|
||||
len = 0;
|
||||
} else {
|
||||
/* SSH spec requires padding for mpints with the MSB set, this code
|
||||
@@ -319,10 +330,10 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
|
||||
if (pad) {
|
||||
buf_putbyte(buf, 0x00);
|
||||
}
|
||||
if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
|
||||
if (mp_to_ubin(mp, buf_getwriteptr(buf, len-pad), len-pad, &written) != MP_OKAY) {
|
||||
dropbear_exit("mpint error");
|
||||
}
|
||||
buf_incrwritepos(buf, len-pad);
|
||||
buf_incrwritepos(buf, written);
|
||||
}
|
||||
|
||||
TRACE2(("leave buf_putmpint"))
|
||||
@@ -350,7 +361,7 @@ int buf_getmpint(buffer* buf, mp_int* mp) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
if (mp_from_ubin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
4
buffer.h
4
buffer.h
@@ -49,7 +49,8 @@ buffer* buf_newcopy(const buffer* buf);
|
||||
void buf_setlen(buffer* buf, unsigned int len);
|
||||
void buf_incrlen(buffer* buf, unsigned int incr);
|
||||
void buf_setpos(buffer* buf, unsigned int pos);
|
||||
void buf_incrpos(buffer* buf, int incr); /* -ve is ok, to go backwards */
|
||||
void buf_incrpos(buffer* buf, unsigned int incr);
|
||||
void buf_decrpos(buffer* buf, unsigned int decr);
|
||||
void buf_incrwritepos(buffer* buf, unsigned int incr);
|
||||
unsigned char buf_getbyte(buffer* buf);
|
||||
unsigned char buf_getbool(buffer* buf);
|
||||
@@ -58,6 +59,7 @@ unsigned char* buf_getptr(const buffer* buf, unsigned int len);
|
||||
unsigned char* buf_getwriteptr(const buffer* buf, unsigned int len);
|
||||
char* buf_getstring(buffer* buf, unsigned int *retlen);
|
||||
buffer * buf_getstringbuf(buffer *buf);
|
||||
buffer * buf_getbuf(buffer *buf);
|
||||
void buf_eatstring(buffer *buf);
|
||||
void buf_putint(buffer* buf, unsigned int val);
|
||||
void buf_putstring(buffer* buf, const char* str, unsigned int len);
|
||||
|
||||
148
chachapoly.c
Normal file
148
chachapoly.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
#include "chachapoly.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
#define CHACHA20_KEY_LEN 32
|
||||
#define CHACHA20_BLOCKSIZE 8
|
||||
#define POLY1305_KEY_LEN 32
|
||||
#define POLY1305_TAG_LEN 16
|
||||
|
||||
static const struct ltc_cipher_descriptor dummy = {.name = NULL};
|
||||
|
||||
static const struct dropbear_hash dropbear_chachapoly_mac =
|
||||
{NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN};
|
||||
|
||||
const struct dropbear_cipher dropbear_chachapoly =
|
||||
{&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
|
||||
|
||||
static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
const unsigned char *key, int keylen,
|
||||
int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_start"))
|
||||
|
||||
if (keylen != CHACHA20_KEY_LEN*2) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->chacha, key,
|
||||
CHACHA20_KEY_LEN, 20)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN,
|
||||
CHACHA20_KEY_LEN, 20) != CRYPT_OK)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_start"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_crypt(unsigned int seq,
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
dropbear_chachapoly_state *state, int direction) {
|
||||
poly1305_state poly;
|
||||
unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_crypt"))
|
||||
|
||||
if (len < 4 || taglen != POLY1305_TAG_LEN) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
poly1305_init(&poly, key, sizeof(key));
|
||||
if (direction == LTC_DECRYPT) {
|
||||
poly1305_process(&poly, in, len);
|
||||
poly1305_done(&poly, tag, &taglen);
|
||||
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1);
|
||||
if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direction == LTC_ENCRYPT) {
|
||||
poly1305_process(&poly, out, len);
|
||||
poly1305_done(&poly, out + len, &taglen);
|
||||
}
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_crypt"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_chachapoly_getlength(unsigned int seq,
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, dropbear_chachapoly_state *state) {
|
||||
unsigned char seqbuf[8], buf[4];
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_getlength"))
|
||||
|
||||
if (len < sizeof(buf)) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
STORE64H((uint64_t)seq, seqbuf);
|
||||
chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
|
||||
if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LOAD32H(*outlen, buf);
|
||||
|
||||
TRACE2(("leave dropbear_chachapoly_getlength"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_chachapoly =
|
||||
{(void *)dropbear_chachapoly_start, NULL, NULL,
|
||||
(void *)dropbear_chachapoly_crypt,
|
||||
(void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac};
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
44
chachapoly.h
Normal file
44
chachapoly.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
|
||||
typedef struct {
|
||||
chacha_state chacha;
|
||||
chacha_state header;
|
||||
} dropbear_chachapoly_state;
|
||||
|
||||
extern const struct dropbear_cipher dropbear_chachapoly;
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_chachapoly;
|
||||
|
||||
#endif /* DROPBEAR_CHACHA20POLY1305 */
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */
|
||||
24
channel.h
24
channel.h
@@ -60,6 +60,9 @@ 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
|
||||
@@ -68,10 +71,9 @@ struct Channel {
|
||||
/* whether close/eof messages have been exchanged */
|
||||
int sent_close, recv_close;
|
||||
int recv_eof, sent_eof;
|
||||
|
||||
/* Set after running the ChanType-specific close hander
|
||||
* to ensure we don't run it twice (nor type->checkclose()). */
|
||||
int close_handler_done;
|
||||
/* 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
|
||||
@@ -81,8 +83,6 @@ 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);
|
||||
|
||||
@@ -93,15 +93,21 @@ struct Channel {
|
||||
|
||||
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*);
|
||||
int (*check_close)(const struct Channel*);
|
||||
/* Called to check whether a channel should close, separately from the FD being EOF.
|
||||
Used for noticing process exiting */
|
||||
int (*check_close)(struct Channel*);
|
||||
/* Handler for ssh_msg_channel_request */
|
||||
void (*reqhandler)(struct Channel*);
|
||||
/* Called prior to sending ssh_msg_channel_close, used for sending exit status */
|
||||
void (*closehandler)(const struct Channel*);
|
||||
/* Frees resources, called just prior to channel being removed */
|
||||
void (*cleanup)(const struct Channel*);
|
||||
};
|
||||
|
||||
/* Callback for connect_remote */
|
||||
/* Callback for connect_remote. errstring may be NULL if result == DROPBEAR_SUCCESS */
|
||||
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);
|
||||
|
||||
void chaninitialise(const struct ChanType *chantypes[]);
|
||||
|
||||
@@ -41,6 +41,9 @@ struct ChanSess {
|
||||
|
||||
char * cmd; /* command to exec */
|
||||
pid_t pid; /* child process pid */
|
||||
/* command that was sent by the client, if authorized_keys command= or
|
||||
dropbear -c was used */
|
||||
char *original_command;
|
||||
|
||||
/* pty details */
|
||||
int master; /* the master terminal fd*/
|
||||
@@ -72,10 +75,6 @@ struct ChanSess {
|
||||
char * agentfile;
|
||||
char * agentdir;
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_SVR_PUBKEY_OPTIONS_BUILT
|
||||
char *original_command;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ChildPid {
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
static int new_agent_chan(struct Channel * channel);
|
||||
|
||||
const struct ChanType cli_chan_agent = {
|
||||
0, /* sepfds */
|
||||
"auth-agent@openssh.com",
|
||||
new_agent_chan,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -93,6 +93,7 @@ static int new_agent_chan(struct Channel * channel) {
|
||||
|
||||
channel->readfd = fd;
|
||||
channel->writefd = fd;
|
||||
channel->bidir_fd = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -254,11 +255,12 @@ void cli_load_agent_keys(m_list *ret_list) {
|
||||
}
|
||||
|
||||
void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
const buffer *data_buf) {
|
||||
const buffer *data_buf, enum signature_type sigtype) {
|
||||
buffer *request_data = NULL;
|
||||
buffer *response = NULL;
|
||||
unsigned int siglen;
|
||||
int packet_type;
|
||||
int flags = 0;
|
||||
|
||||
/* Request format
|
||||
byte SSH2_AGENTC_SIGN_REQUEST
|
||||
@@ -270,7 +272,12 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
|
||||
buf_put_pub_key(request_data, key, key->type);
|
||||
|
||||
buf_putbufstring(request_data, data_buf);
|
||||
buf_putint(request_data, 0);
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
|
||||
flags |= SSH_AGENT_RSA_SHA2_256;
|
||||
}
|
||||
#endif
|
||||
buf_putint(request_data, flags);
|
||||
|
||||
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
|
||||
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
#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"))
|
||||
@@ -267,6 +261,9 @@ void recv_msg_userauth_success() {
|
||||
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
|
||||
|
||||
TRACE(("received msg_userauth_success"))
|
||||
if (cli_opts.disable_trivial_auth && cli_ses.is_trivial_auth) {
|
||||
dropbear_exit("trivial authentication not allowed");
|
||||
}
|
||||
/* Note: in delayed-zlib mode, setting authdone here
|
||||
* will enable compression in the transport layer */
|
||||
ses.authstate.authdone = 1;
|
||||
|
||||
@@ -114,6 +114,7 @@ void recv_msg_userauth_info_request() {
|
||||
m_free(instruction);
|
||||
|
||||
for (i = 0; i < num_prompts; i++) {
|
||||
cli_ses.is_trivial_auth = 0;
|
||||
unsigned int response_len = 0;
|
||||
prompt = buf_getstring(ses.payload, NULL);
|
||||
cleantext(prompt);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
101
cli-authpubkey.c
101
cli-authpubkey.c
@@ -33,7 +33,7 @@
|
||||
#include "agentfwd.h"
|
||||
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign);
|
||||
|
||||
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
|
||||
* We use it to remove the key we tried from the list */
|
||||
@@ -59,13 +59,15 @@ void recv_msg_userauth_pk_ok() {
|
||||
char* algotype = NULL;
|
||||
unsigned int algolen;
|
||||
enum signkey_type keytype;
|
||||
enum signature_type sigtype;
|
||||
unsigned int remotelen;
|
||||
|
||||
TRACE(("enter recv_msg_userauth_pk_ok"))
|
||||
|
||||
algotype = buf_getstring(ses.payload, &algolen);
|
||||
keytype = signkey_type_from_name(algotype, algolen);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", keytype))
|
||||
sigtype = signature_type_from_name(algotype, algolen);
|
||||
keytype = signkey_type_from_signature(sigtype);
|
||||
TRACE(("recv_msg_userauth_pk_ok: type %d", sigtype))
|
||||
m_free(algotype);
|
||||
|
||||
keybuf = buf_new(MAX_PUBKEY_SIZE);
|
||||
@@ -112,7 +114,7 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("matching key"))
|
||||
/* XXX TODO: if it's an encrypted key, here we ask for their
|
||||
* password */
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
|
||||
send_msg_userauth_pubkey((sign_key*)iter->item, sigtype, 1);
|
||||
} else {
|
||||
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
|
||||
}
|
||||
@@ -120,31 +122,32 @@ void recv_msg_userauth_pk_ok() {
|
||||
TRACE(("leave recv_msg_userauth_pk_ok"))
|
||||
}
|
||||
|
||||
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
|
||||
static void cli_buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
|
||||
const buffer *data_buf) {
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
/* TODO: rsa-sha256 agent */
|
||||
if (key->source == SIGNKEY_SOURCE_AGENT) {
|
||||
/* Format the agent signature ourselves, as buf_put_sign would. */
|
||||
buffer *sigblob;
|
||||
sigblob = buf_new(MAX_PUBKEY_SIZE);
|
||||
agent_buf_sign(sigblob, key, data_buf);
|
||||
agent_buf_sign(sigblob, key, data_buf, sigtype);
|
||||
buf_putbufstring(buf, sigblob);
|
||||
buf_free(sigblob);
|
||||
} else
|
||||
#endif /* DROPBEAR_CLI_AGENTFWD */
|
||||
{
|
||||
buf_put_sign(buf, key, type, data_buf);
|
||||
buf_put_sign(buf, key, sigtype, data_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: make it take an agent reference to use as well */
|
||||
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
static void send_msg_userauth_pubkey(sign_key *key, enum signature_type sigtype, int realsign) {
|
||||
|
||||
const char *algoname = NULL;
|
||||
unsigned int algolen;
|
||||
buffer* sigbuf = NULL;
|
||||
enum signkey_type keytype = signkey_type_from_signature(sigtype);
|
||||
|
||||
TRACE(("enter send_msg_userauth_pubkey"))
|
||||
TRACE(("enter send_msg_userauth_pubkey sigtype %d", sigtype))
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
|
||||
@@ -160,10 +163,9 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
buf_putbyte(ses.writepayload, realsign);
|
||||
|
||||
algoname = signkey_name_from_type(type, &algolen);
|
||||
|
||||
algoname = signature_name_from_type(sigtype, &algolen);
|
||||
buf_putstring(ses.writepayload, algoname, algolen);
|
||||
buf_put_pub_key(ses.writepayload, key, type);
|
||||
buf_put_pub_key(ses.writepayload, key, keytype);
|
||||
|
||||
if (realsign) {
|
||||
TRACE(("realsign"))
|
||||
@@ -172,8 +174,9 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
sigbuf = buf_new(4 + ses.session_id->len + ses.writepayload->len);
|
||||
buf_putbufstring(sigbuf, ses.session_id);
|
||||
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
|
||||
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
|
||||
cli_buf_put_sign(ses.writepayload, key, sigtype, sigbuf);
|
||||
buf_free(sigbuf); /* Nothing confidential in the buffer */
|
||||
cli_ses.is_trivial_auth = 0;
|
||||
}
|
||||
|
||||
encrypt_packet();
|
||||
@@ -182,7 +185,7 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
|
||||
|
||||
/* Returns 1 if a key was tried */
|
||||
int cli_auth_pubkey() {
|
||||
|
||||
enum signature_type sigtype = DROPBEAR_SIGNATURE_NONE;
|
||||
TRACE(("enter cli_auth_pubkey"))
|
||||
|
||||
#if DROPBEAR_CLI_AGENTFWD
|
||||
@@ -190,13 +193,79 @@ int cli_auth_pubkey() {
|
||||
/* get the list of available keys from the agent */
|
||||
cli_load_agent_keys(cli_opts.privkeys);
|
||||
cli_opts.agent_keys_loaded = 1;
|
||||
TRACE(("cli_auth_pubkey: agent keys loaded"))
|
||||
}
|
||||
#endif
|
||||
|
||||
/* iterate through privkeys to remove ones not allowed in server-sig-algs */
|
||||
while (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
if (cli_ses.server_sig_algs) {
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNATURE_RSA_SHA256)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
TRACE(("server-sig-algs allows rsa sha256"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, SSH_SIGNKEY_RSA)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("server-sig-algs allows rsa sha1"))
|
||||
break;
|
||||
}
|
||||
#endif /* DROPBEAR_RSA_SHA256 */
|
||||
} else
|
||||
#endif /* DROPBEAR_RSA */
|
||||
{
|
||||
/* Not RSA */
|
||||
const char *name = NULL;
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
name = signature_name_from_type(sigtype, NULL);
|
||||
if (buf_has_algo(cli_ses.server_sig_algs, name)
|
||||
== DROPBEAR_SUCCESS) {
|
||||
TRACE(("server-sig-algs allows %s", name))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* No match, skip this key */
|
||||
TRACE(("server-sig-algs no match keytype %d, skipping", key->type))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
} else {
|
||||
/* Server didn't provide a server-sig-algs list, we'll
|
||||
assume all except rsa-sha256 are OK. */
|
||||
#if DROPBEAR_RSA
|
||||
if (key->type == DROPBEAR_SIGNKEY_RSA) {
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
TRACE(("no server-sig-algs, using rsa sha1"))
|
||||
break;
|
||||
#else
|
||||
/* only support rsa-sha256, skip this key */
|
||||
TRACE(("no server-sig-algs, skipping rsa sha256"))
|
||||
key = list_remove(cli_opts.privkeys->first);
|
||||
sign_key_free(key);
|
||||
continue;
|
||||
#endif
|
||||
} /* key->type == DROPBEAR_SIGNKEY_RSA */
|
||||
#endif /* DROPBEAR_RSA */
|
||||
sigtype = signature_type_from_signkey(key->type);
|
||||
TRACE(("no server-sig-algs, using key"))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cli_opts.privkeys->first) {
|
||||
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
|
||||
/* Send a trial request */
|
||||
send_msg_userauth_pubkey(key, key->type, 0);
|
||||
send_msg_userauth_pubkey(key, sigtype, 0);
|
||||
cli_ses.lastprivkey = key;
|
||||
TRACE(("leave cli_auth_pubkey-success"))
|
||||
return 1;
|
||||
|
||||
@@ -46,12 +46,12 @@ 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 */
|
||||
cli_chansessreq, /* reqhandler */
|
||||
cli_closechansess, /* closehandler */
|
||||
NULL, /* cleanup */
|
||||
};
|
||||
|
||||
static void cli_chansessreq(struct Channel *channel) {
|
||||
@@ -343,6 +343,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -382,12 +383,12 @@ 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,
|
||||
NULL,
|
||||
cli_closechansess
|
||||
cli_closechansess,
|
||||
NULL,
|
||||
};
|
||||
|
||||
void cli_send_netcat_request() {
|
||||
|
||||
63
cli-kex.c
63
cli-kex.c
@@ -46,6 +46,13 @@ void send_msg_kexdh_init() {
|
||||
TRACE(("send_msg_kexdh_init()"))
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing && fuzz.skip_kexmaths) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
|
||||
switch (ses.newkeys->algo_kex->mode) {
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
@@ -81,7 +88,7 @@ void send_msg_kexdh_init() {
|
||||
}
|
||||
cli_ses.curve25519_param = gen_kexcurve25519_param();
|
||||
}
|
||||
buf_putstring(ses.writepayload, (const char*)cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
@@ -94,16 +101,22 @@ void send_msg_kexdh_init() {
|
||||
void recv_msg_kexdh_reply() {
|
||||
|
||||
sign_key *hostkey = NULL;
|
||||
unsigned int type, keybloblen;
|
||||
unsigned int keytype, keybloblen;
|
||||
unsigned char* keyblob = NULL;
|
||||
|
||||
TRACE(("enter recv_msg_kexdh_reply"))
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing && fuzz.skip_kexmaths) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
|
||||
dropbear_exit("Received out-of-order kexdhreply");
|
||||
}
|
||||
type = ses.newkeys->algo_hostkey;
|
||||
TRACE(("type is %d", type))
|
||||
keytype = ses.newkeys->algo_hostkey;
|
||||
TRACE(("keytype is %d", keytype))
|
||||
|
||||
hostkey = new_sign_key();
|
||||
keybloblen = buf_getint(ses.payload);
|
||||
@@ -114,7 +127,7 @@ void recv_msg_kexdh_reply() {
|
||||
checkhostkey(keyblob, keybloblen);
|
||||
}
|
||||
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
|
||||
if (buf_get_pub_key(ses.payload, hostkey, &keytype) != DROPBEAR_SUCCESS) {
|
||||
TRACE(("failed getting pubkey"))
|
||||
dropbear_exit("Bad KEX packet");
|
||||
}
|
||||
@@ -155,10 +168,12 @@ void recv_msg_kexdh_reply() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
if (cli_ses.dh_param) {
|
||||
free_kexdh_param(cli_ses.dh_param);
|
||||
cli_ses.dh_param = NULL;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ECDH
|
||||
if (cli_ses.ecdh_param) {
|
||||
free_kexecdh_param(cli_ses.ecdh_param);
|
||||
@@ -173,7 +188,8 @@ void recv_msg_kexdh_reply() {
|
||||
#endif
|
||||
|
||||
cli_ses.param_kex_algo = NULL;
|
||||
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
|
||||
if (buf_verify(ses.payload, hostkey, ses.newkeys->algo_signature,
|
||||
ses.hash) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad hostkey signature");
|
||||
}
|
||||
|
||||
@@ -410,3 +426,38 @@ out:
|
||||
}
|
||||
m_free(fingerprint);
|
||||
}
|
||||
|
||||
void recv_msg_ext_info(void) {
|
||||
/* This message is not client-specific in the protocol but Dropbear only handles
|
||||
a server-sent message at present. */
|
||||
unsigned int num_ext;
|
||||
unsigned int i;
|
||||
|
||||
TRACE(("enter recv_msg_ext_info"))
|
||||
|
||||
/* Must be after the first SSH_MSG_NEWKEYS */
|
||||
TRACE(("last %d, donefirst %d, donescond %d", ses.lastpacket, ses.kexstate.donefirstkex, ses.kexstate.donesecondkex))
|
||||
if (!(ses.lastpacket == SSH_MSG_NEWKEYS && !ses.kexstate.donesecondkex)) {
|
||||
TRACE(("leave recv_msg_ext_info: ignoring packet received at the wrong time"))
|
||||
return;
|
||||
}
|
||||
|
||||
num_ext = buf_getint(ses.payload);
|
||||
TRACE(("received SSH_MSG_EXT_INFO with %d items", num_ext))
|
||||
|
||||
for (i = 0; i < num_ext; i++) {
|
||||
unsigned int name_len;
|
||||
char *ext_name = buf_getstring(ses.payload, &name_len);
|
||||
TRACE(("extension %d name '%s'", i, ext_name))
|
||||
if (cli_ses.server_sig_algs == NULL
|
||||
&& name_len == strlen(SSH_SERVER_SIG_ALGS)
|
||||
&& strcmp(ext_name, SSH_SERVER_SIG_ALGS) == 0) {
|
||||
cli_ses.server_sig_algs = buf_getbuf(ses.payload);
|
||||
} else {
|
||||
/* valid extension values could be >MAX_STRING_LEN */
|
||||
buf_eatstring(ses.payload);
|
||||
}
|
||||
m_free(ext_name);
|
||||
}
|
||||
TRACE(("leave recv_msg_ext_info"))
|
||||
}
|
||||
|
||||
52
cli-main.c
52
cli-main.c
@@ -31,9 +31,7 @@
|
||||
#include "dbrandom.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "netio.h"
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
|
||||
static void cli_dropbear_log(int priority, const char* format, va_list param);
|
||||
#include "fuzz.h"
|
||||
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
static void cli_proxy_cmd(int *sock_in, int *sock_out, pid_t *pid_out);
|
||||
@@ -49,6 +47,7 @@ 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;
|
||||
@@ -73,7 +72,6 @@ int main(int argc, char ** argv) {
|
||||
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);
|
||||
@@ -98,51 +96,6 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
#endif /* DBMULTI stuff */
|
||||
|
||||
static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
|
||||
char exitmsg[150];
|
||||
char fullmsg[300];
|
||||
|
||||
/* Note that exit message must be rendered before session cleanup */
|
||||
|
||||
/* Render the formatted exit message */
|
||||
vsnprintf(exitmsg, sizeof(exitmsg), format, param);
|
||||
|
||||
/* Add the prefix depending on session/auth state */
|
||||
if (!ses.init_done) {
|
||||
snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg);
|
||||
} else {
|
||||
snprintf(fullmsg, sizeof(fullmsg),
|
||||
"Connection to %s@%s:%s exited: %s",
|
||||
cli_opts.username, cli_opts.remotehost,
|
||||
cli_opts.remoteport, exitmsg);
|
||||
}
|
||||
|
||||
/* Do the cleanup first, since then the terminal will be reset */
|
||||
session_cleanup();
|
||||
/* Avoid printing onwards from terminal cruft */
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
dropbear_log(LOG_INFO, "%s", fullmsg);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
static void cli_dropbear_log(int priority,
|
||||
const char* format, va_list param) {
|
||||
|
||||
char printbuf[1024];
|
||||
|
||||
vsnprintf(printbuf, sizeof(printbuf), format, param);
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
if (opts.usingsyslog) {
|
||||
syslog(priority, "%s", printbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
static void exec_proxy_cmd(const void *user_data_cmd) {
|
||||
const char *cmd = user_data_cmd;
|
||||
char *usershell;
|
||||
@@ -192,4 +145,5 @@ static void kill_proxy_sighandler(int UNUSED(signo)) {
|
||||
kill_proxy_command();
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_CLI_PROXYCMD */
|
||||
|
||||
@@ -79,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 1MB)\n"
|
||||
"-W <receive_window_buffer> (default %d, larger may be faster, max 10MB)\n"
|
||||
"-K <keepalive> (0 is never, default %d)\n"
|
||||
"-I <idle_timeout> (0 is never, default %d)\n"
|
||||
#if DROPBEAR_CLI_NETCAT
|
||||
@@ -152,6 +152,7 @@ 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;
|
||||
@@ -214,7 +215,7 @@ void cli_getopts(int argc, char ** argv) {
|
||||
cli_opts.always_accept_key = 1;
|
||||
break;
|
||||
case 'p': /* remoteport */
|
||||
next = &cli_opts.remoteport;
|
||||
next = (char**)&cli_opts.remoteport;
|
||||
break;
|
||||
#if DROPBEAR_CLI_PUBKEY_AUTH
|
||||
case 'i': /* an identityfile */
|
||||
@@ -378,6 +379,11 @@ void cli_getopts(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
/* -c help doesn't need a hostname */
|
||||
parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
/* Done with options/flags; now handle the hostname (which may not
|
||||
* start with a hyphen) and optional command */
|
||||
|
||||
@@ -408,10 +414,6 @@ void cli_getopts(int argc, char ** argv) {
|
||||
|
||||
/* And now a few sanity checks and setup */
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
parse_ciphers_macs();
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_CLI_PROXYCMD
|
||||
if (cli_opts.proxycmd) {
|
||||
/* To match the common path of m_freeing it */
|
||||
@@ -449,12 +451,9 @@ void cli_getopts(int argc, char ** argv) {
|
||||
&& cli_opts.no_cmd == 0) {
|
||||
dropbear_exit("Command required for -f");
|
||||
}
|
||||
|
||||
|
||||
if (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);
|
||||
}
|
||||
parse_recv_window(recv_window_arg);
|
||||
}
|
||||
if (keepalive_arg) {
|
||||
unsigned int val;
|
||||
@@ -888,9 +887,11 @@ static void add_extendedopt(const char* origstr) {
|
||||
#if DROPBEAR_CLI_ANYTCPFWD
|
||||
"\tExitOnForwardFailure\n"
|
||||
#endif
|
||||
"\tDisableTrivialAuth\n"
|
||||
#ifndef DISABLE_SYSLOG
|
||||
"\tUseSyslog\n"
|
||||
#endif
|
||||
"\tPort\n"
|
||||
);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@@ -909,5 +910,15 @@ static void add_extendedopt(const char* origstr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (match_extendedopt(&optstr, "Port") == DROPBEAR_SUCCESS) {
|
||||
cli_opts.remoteport = optstr;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ static const packettype cli_packettypes[] = {
|
||||
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
|
||||
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
|
||||
#endif
|
||||
{SSH_MSG_EXT_INFO, recv_msg_ext_info},
|
||||
{0, NULL} /* End */
|
||||
};
|
||||
|
||||
@@ -164,6 +165,7 @@ 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;
|
||||
@@ -244,6 +246,9 @@ 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"))
|
||||
@@ -351,11 +356,19 @@ static void cli_session_cleanup(void) {
|
||||
(void)fcntl(cli_ses.stdoutcopy, F_SETFL, cli_ses.stdoutflags);
|
||||
(void)fcntl(cli_ses.stderrcopy, F_SETFL, cli_ses.stderrflags);
|
||||
|
||||
cli_tty_cleanup();
|
||||
/* Don't leak */
|
||||
m_close(cli_ses.stdincopy);
|
||||
m_close(cli_ses.stdoutcopy);
|
||||
m_close(cli_ses.stderrcopy);
|
||||
|
||||
cli_tty_cleanup();
|
||||
if (cli_ses.server_sig_algs) {
|
||||
buf_free(cli_ses.server_sig_algs);
|
||||
}
|
||||
}
|
||||
|
||||
static void cli_finished() {
|
||||
TRACE(("cli_finished()"))
|
||||
|
||||
session_cleanup();
|
||||
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
|
||||
@@ -399,7 +412,75 @@ void cleantext(char* dirtytext) {
|
||||
}
|
||||
|
||||
static void recv_msg_global_request_cli(void) {
|
||||
TRACE(("recv_msg_global_request_cli"))
|
||||
/* Send a proper rejection */
|
||||
send_msg_request_failure();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
12
cli-tcpfwd.c
12
cli-tcpfwd.c
@@ -35,11 +35,11 @@
|
||||
static int newtcpforwarded(struct Channel * channel);
|
||||
|
||||
const struct ChanType cli_chan_tcpremote = {
|
||||
1, /* sepfds */
|
||||
"forwarded-tcpip",
|
||||
newtcpforwarded,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
@@ -50,11 +50,11 @@ static int cli_localtcp(const char* listenaddr,
|
||||
const char* remoteaddr,
|
||||
unsigned int remoteport);
|
||||
static const struct ChanType cli_chan_tcplocal = {
|
||||
1, /* sepfds */
|
||||
"direct-tcpip",
|
||||
tcp_prio_inithandler,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
@@ -135,7 +135,7 @@ static int cli_localtcp(const char* listenaddr,
|
||||
tcpinfo->chantype = &cli_chan_tcplocal;
|
||||
tcpinfo->tcp_type = direct;
|
||||
|
||||
ret = listen_tcpfwd(tcpinfo);
|
||||
ret = listen_tcpfwd(tcpinfo, NULL);
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
m_free(tcpinfo);
|
||||
@@ -271,12 +271,12 @@ static int newtcpforwarded(struct Channel * channel) {
|
||||
origaddr, origport);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
|
||||
|
||||
snprintf(portstring, sizeof(portstring), "%u", fwd->connectport);
|
||||
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:
|
||||
|
||||
244
common-algo.c
244
common-algo.c
@@ -30,6 +30,9 @@
|
||||
#include "dh_groups.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
#include "gcm.h"
|
||||
#include "chachapoly.h"
|
||||
#include "ssh.h"
|
||||
|
||||
/* This file (algo.c) organises the ciphers which can be used, and is used to
|
||||
* decide which ciphers/hashes/compression/signing to use during key exchange*/
|
||||
@@ -61,10 +64,6 @@ static const struct dropbear_cipher dropbear_aes256 =
|
||||
static const struct dropbear_cipher dropbear_aes128 =
|
||||
{&aes_desc, 16, 16};
|
||||
#endif
|
||||
#if DROPBEAR_BLOWFISH
|
||||
static const struct dropbear_cipher dropbear_blowfish =
|
||||
{&blowfish_desc, 16, 8};
|
||||
#endif
|
||||
#if DROPBEAR_TWOFISH256
|
||||
static const struct dropbear_cipher dropbear_twofish256 =
|
||||
{&twofish_desc, 32, 16};
|
||||
@@ -86,11 +85,11 @@ const struct dropbear_cipher dropbear_nocipher =
|
||||
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
const struct dropbear_cipher_mode dropbear_mode_cbc =
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
|
||||
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_none =
|
||||
{void_start, void_cipher, void_cipher};
|
||||
{void_start, void_cipher, void_cipher, NULL, NULL, NULL};
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
/* a wrapper to make ctr_start and cbc_start look the same */
|
||||
@@ -101,7 +100,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
|
||||
return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
|
||||
}
|
||||
const struct dropbear_cipher_mode dropbear_mode_ctr =
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
|
||||
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
|
||||
#endif /* DROPBEAR_ENABLE_CTR_MODE */
|
||||
|
||||
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
|
||||
@@ -137,6 +136,19 @@ const struct dropbear_hash dropbear_nohash =
|
||||
* that is also supported by the server will get used. */
|
||||
|
||||
algo_type sshciphers[] = {
|
||||
#if DROPBEAR_CHACHA20POLY1305
|
||||
{"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-gcm@openssh.com", 0, &dropbear_aes128, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#if DROPBEAR_AES256
|
||||
{"aes256-gcm@openssh.com", 0, &dropbear_aes256, 1, &dropbear_mode_gcm},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
#if DROPBEAR_AES128
|
||||
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
|
||||
@@ -169,15 +181,18 @@ algo_type sshciphers[] = {
|
||||
#if DROPBEAR_TWOFISH128
|
||||
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
|
||||
#if DROPBEAR_3DES
|
||||
#if DROPBEAR_ENABLE_CTR_MODE
|
||||
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
|
||||
#endif
|
||||
#if DROPBEAR_3DES
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#if DROPBEAR_BLOWFISH
|
||||
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
|
||||
#endif
|
||||
#endif /* DROPBEAR_3DES */
|
||||
|
||||
#if DROPBEAR_ENABLE_CBC_MODE
|
||||
#endif /* DROPBEAR_ENABLE_CBC_MODE */
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -221,23 +236,37 @@ algo_type ssh_nocompress[] = {
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
algo_type sshhostkey[] = {
|
||||
algo_type sigalgs[] = {
|
||||
#if DROPBEAR_ED25519
|
||||
{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
|
||||
#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
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNATURE_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_384
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNATURE_ECDSA_NISTP384, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_ECC_521
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_SK_ECDSA
|
||||
{"sk-ecdsa-sha2-nistp256@openssh.com", DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
|
||||
#if DROPBEAR_RSA_SHA256
|
||||
{"rsa-sha2-256", DROPBEAR_SIGNATURE_RSA_SHA256, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_RSA_SHA1
|
||||
{"ssh-rsa", DROPBEAR_SIGNATURE_RSA_SHA1, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
#if DROPBEAR_DSS
|
||||
{"ssh-dss", DROPBEAR_SIGNKEY_DSS, NULL, 1, NULL},
|
||||
{"ssh-dss", DROPBEAR_SIGNATURE_DSS, NULL, 1, NULL},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
@@ -255,8 +284,6 @@ static const struct dropbear_kex kex_dh_group14_sha256 = {DROPBEAR_KEX_NORMAL_DH
|
||||
static const struct dropbear_kex kex_dh_group16_sha512 = {DROPBEAR_KEX_NORMAL_DH, dh_p_16, DH_P_16_LEN, NULL, &sha512_desc };
|
||||
#endif
|
||||
|
||||
/* These can't be const since dropbear_ecc_fill_dp() fills out
|
||||
ecc_curve at runtime */
|
||||
#if DROPBEAR_ECDH
|
||||
#if DROPBEAR_ECC_256
|
||||
static const struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
|
||||
@@ -274,6 +301,7 @@ static const struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0
|
||||
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
|
||||
#endif
|
||||
|
||||
/* data == NULL for non-kex algorithm identifiers */
|
||||
algo_type sshkex[] = {
|
||||
#if DROPBEAR_CURVE25519
|
||||
{"curve25519-sha256", 0, &kex_curve25519, 1, NULL},
|
||||
@@ -303,49 +331,122 @@ algo_type sshkex[] = {
|
||||
{"diffie-hellman-group16-sha512", 0, &kex_dh_group16_sha512, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
|
||||
{KEXGUESS2_ALGO_NAME, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#if DROPBEAR_EXT_INFO
|
||||
#if DROPBEAR_CLIENT
|
||||
/* Set unusable by svr_algos_initialise() */
|
||||
{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
|
||||
#endif
|
||||
#endif
|
||||
{NULL, 0, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
/* algolen specifies the length of algo, algos is our local list to match
|
||||
* against.
|
||||
* Returns DROPBEAR_SUCCESS if we have a match for algo, DROPBEAR_FAILURE
|
||||
* otherwise */
|
||||
int have_algo(const char* algo, size_t algolen, const algo_type algos[]) {
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (strlen(algos[i].name) == algolen
|
||||
&& (strncmp(algos[i].name, algo, algolen) == 0)) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* Output a comma separated list of algorithms to a buffer */
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
|
||||
void buf_put_algolist_all(buffer * buf, const algo_type localalgos[], int useall) {
|
||||
unsigned int i, len;
|
||||
unsigned int donefirst = 0;
|
||||
buffer *algolist = NULL;
|
||||
unsigned int startpos;
|
||||
|
||||
algolist = buf_new(300);
|
||||
startpos = buf->pos;
|
||||
/* Placeholder for length */
|
||||
buf_putint(buf, 0);
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
if (donefirst)
|
||||
buf_putbyte(algolist, ',');
|
||||
if (localalgos[i].usable || useall) {
|
||||
if (donefirst) {
|
||||
buf_putbyte(buf, ',');
|
||||
}
|
||||
donefirst = 1;
|
||||
len = strlen(localalgos[i].name);
|
||||
buf_putbytes(algolist, (const unsigned char *) localalgos[i].name, len);
|
||||
buf_putbytes(buf, (const unsigned char *) localalgos[i].name, len);
|
||||
}
|
||||
}
|
||||
buf_putstring(buf, (const char*)algolist->data, algolist->len);
|
||||
TRACE(("algolist add '%*s'", algolist->len, algolist->data))
|
||||
buf_free(algolist);
|
||||
/* Fill out the length */
|
||||
len = buf->pos - startpos - 4;
|
||||
buf_setpos(buf, startpos);
|
||||
buf_putint(buf, len);
|
||||
TRACE(("algolist add %d '%*s'", len, len, buf_getptr(buf, len)))
|
||||
buf_incrwritepos(buf, len);
|
||||
}
|
||||
|
||||
void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
buf_put_algolist_all(buf, localalgos, 0);
|
||||
}
|
||||
|
||||
/* returns a list of pointers into algolist, of null-terminated names.
|
||||
ret_list should be passed in with space for *ret_count elements,
|
||||
on return *ret_count has the number of names filled.
|
||||
algolist is modified. */
|
||||
static void get_algolist(char* algolist, unsigned int algolist_len,
|
||||
const char* *ret_list, unsigned int *ret_count) {
|
||||
unsigned int max_count = *ret_count;
|
||||
unsigned int i;
|
||||
|
||||
if (*ret_count == 0) {
|
||||
return;
|
||||
}
|
||||
if (algolist_len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
*ret_count = 0;
|
||||
}
|
||||
|
||||
/* ret_list will contain a list of the strings parsed out.
|
||||
We will have at least one string (even if it's just "") */
|
||||
ret_list[0] = algolist;
|
||||
*ret_count = 1;
|
||||
for (i = 0; i < algolist_len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (algolist[i] == ',') {
|
||||
if (*ret_count >= max_count) {
|
||||
dropbear_exit("Too many remote algorithms");
|
||||
*ret_count = 0;
|
||||
return;
|
||||
}
|
||||
algolist[i] = '\0';
|
||||
ret_list[*ret_count] = &algolist[i+1];
|
||||
(*ret_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return DROPBEAR_SUCCESS if the namelist contains algo,
|
||||
DROPBEAR_FAILURE otherwise. buf position is not incremented. */
|
||||
int buf_has_algo(buffer *buf, const char *algo) {
|
||||
unsigned char* algolist = NULL;
|
||||
unsigned int orig_pos = buf->pos;
|
||||
unsigned int len, remotecount, i;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO];
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
algolist = buf_getstring(buf, &len);
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], algo) == 0) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (algolist) {
|
||||
m_free(algolist);
|
||||
}
|
||||
buf_setpos(buf, orig_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
algo_type * first_usable_algo(algo_type algos[]) {
|
||||
int i;
|
||||
for (i = 0; algos[i].name != NULL; i++) {
|
||||
if (algos[i].usable) {
|
||||
return &algos[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* match the first algorithm in the comma-separated list in buf which is
|
||||
@@ -354,9 +455,7 @@ void buf_put_algolist(buffer * buf, const algo_type localalgos[]) {
|
||||
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
|
||||
* guessed correctly */
|
||||
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
enum kexguess2_used *kexguess2, int *goodguess)
|
||||
{
|
||||
|
||||
int kexguess2, int *goodguess) {
|
||||
char * algolist = NULL;
|
||||
const char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
|
||||
unsigned int len;
|
||||
@@ -371,40 +470,8 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
|
||||
algolist = buf_getstring(buf, &len);
|
||||
TRACE(("buf_match_algo: %s", algolist))
|
||||
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* remotenames will contain a list of the strings parsed out */
|
||||
/* We will have at least one string (even if it's just "") */
|
||||
remotenames[0] = algolist;
|
||||
remotecount = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (algolist[i] == '\0') {
|
||||
/* someone is trying something strange */
|
||||
goto out;
|
||||
}
|
||||
if (algolist[i] == ',') {
|
||||
algolist[i] = '\0';
|
||||
remotenames[remotecount] = &algolist[i+1];
|
||||
remotecount++;
|
||||
}
|
||||
if (remotecount >= MAX_PROPOSED_ALGO) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kexguess2 && *kexguess2 == KEXGUESS2_LOOK) {
|
||||
for (i = 0; i < remotecount; i++)
|
||||
{
|
||||
if (strcmp(remotenames[i], KEXGUESS2_ALGO_NAME) == 0) {
|
||||
*kexguess2 = KEXGUESS2_YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*kexguess2 == KEXGUESS2_LOOK) {
|
||||
*kexguess2 = KEXGUESS2_NO;
|
||||
}
|
||||
}
|
||||
remotecount = MAX_PROPOSED_ALGO;
|
||||
get_algolist(algolist, len, remotenames, &remotecount);
|
||||
|
||||
for (i = 0; localalgos[i].name != NULL; i++) {
|
||||
if (localalgos[i].usable) {
|
||||
@@ -436,12 +503,11 @@ algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
|
||||
}
|
||||
if (strcmp(servnames[j], clinames[i]) == 0) {
|
||||
/* set if it was a good guess */
|
||||
if (goodguess && kexguess2) {
|
||||
if (*kexguess2 == KEXGUESS2_YES) {
|
||||
if (goodguess != NULL) {
|
||||
if (kexguess2) {
|
||||
if (i == 0) {
|
||||
*goodguess = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (i == 0 && j == 0) {
|
||||
*goodguess = 1;
|
||||
|
||||
@@ -144,7 +144,6 @@ static struct Channel* newchannel(unsigned int remotechan,
|
||||
newchan->index = i;
|
||||
newchan->sent_close = newchan->recv_close = 0;
|
||||
newchan->sent_eof = newchan->recv_eof = 0;
|
||||
newchan->close_handler_done = 0;
|
||||
|
||||
newchan->remotechan = remotechan;
|
||||
newchan->transwindow = transwindow;
|
||||
@@ -155,7 +154,6 @@ 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;
|
||||
@@ -285,24 +283,29 @@ 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->close_handler_done
|
||||
&& 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
|
||||
|| channel->close_handler_done
|
||||
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."))
|
||||
@@ -318,22 +321,6 @@ 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
|
||||
@@ -357,8 +344,7 @@ 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* UNUSED(errstring)) {
|
||||
|
||||
void channel_connect_done(int result, int sock, void* user_data, const char* errstring) {
|
||||
struct Channel *channel = user_data;
|
||||
|
||||
TRACE(("enter channel_connect_done"))
|
||||
@@ -366,6 +352,7 @@ void channel_connect_done(int result, int sock, void* user_data, const char* UNU
|
||||
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);
|
||||
@@ -374,9 +361,9 @@ void channel_connect_done(int result, int sock, void* user_data, const char* UNU
|
||||
else
|
||||
{
|
||||
send_msg_channel_open_failure(channel->remotechan,
|
||||
SSH_OPEN_CONNECT_FAILED, "", "");
|
||||
SSH_OPEN_CONNECT_FAILED, errstring, "");
|
||||
remove_channel(channel);
|
||||
TRACE(("leave check_in_progress: fail"))
|
||||
TRACE(("leave check_in_progress: fail. internal errstring: %s", errstring))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,10 +372,8 @@ void channel_connect_done(int result, int sock, void* user_data, const char* UNU
|
||||
static void send_msg_channel_close(struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_close %p", (void*)channel))
|
||||
if (channel->type->closehandler
|
||||
&& !channel->close_handler_done) {
|
||||
if (channel->type->closehandler) {
|
||||
channel->type->closehandler(channel);
|
||||
channel->close_handler_done = 1;
|
||||
}
|
||||
|
||||
CHECKCLEARTOWRITE();
|
||||
@@ -661,10 +646,8 @@ static void remove_channel(struct Channel * channel) {
|
||||
m_close(channel->errfd);
|
||||
}
|
||||
|
||||
if (!channel->close_handler_done
|
||||
&& channel->type->closehandler) {
|
||||
channel->type->closehandler(channel);
|
||||
channel->close_handler_done = 1;
|
||||
if (channel->type->cleanup) {
|
||||
channel->type->cleanup(channel);
|
||||
}
|
||||
|
||||
if (channel->conn_pending) {
|
||||
@@ -690,13 +673,7 @@ void recv_msg_channel_request() {
|
||||
|
||||
TRACE(("enter recv_msg_channel_request %p", (void*)channel))
|
||||
|
||||
if (channel->sent_close) {
|
||||
TRACE(("leave recv_msg_channel_request: already closed channel"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel->type->reqhandler
|
||||
&& !channel->close_handler_done) {
|
||||
if (channel->type->reqhandler) {
|
||||
channel->type->reqhandler(channel);
|
||||
} else {
|
||||
int wantreply;
|
||||
@@ -791,14 +768,6 @@ 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"))
|
||||
}
|
||||
|
||||
@@ -1011,6 +980,11 @@ cleanup:
|
||||
void send_msg_channel_failure(const struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_failure"))
|
||||
|
||||
if (channel->sent_close) {
|
||||
TRACE(("Skipping sending msg_channel_failure for closed channel"))
|
||||
return;
|
||||
}
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_FAILURE);
|
||||
@@ -1024,6 +998,10 @@ void send_msg_channel_failure(const struct Channel *channel) {
|
||||
void send_msg_channel_success(const struct Channel *channel) {
|
||||
|
||||
TRACE(("enter send_msg_channel_success"))
|
||||
if (channel->sent_close) {
|
||||
TRACE(("Skipping sending msg_channel_success for closed channel"))
|
||||
return;
|
||||
}
|
||||
CHECKCLEARTOWRITE();
|
||||
|
||||
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_SUCCESS);
|
||||
@@ -1075,7 +1053,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
|
||||
|
||||
int closein = 0, closeout = 0;
|
||||
|
||||
if (channel->type->sepfds) {
|
||||
if (channel->bidir_fd) {
|
||||
TRACE(("SHUTDOWN(%d, %d)", fd, how))
|
||||
shutdown(fd, how);
|
||||
if (how == 0) {
|
||||
@@ -1105,7 +1083,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->type->sepfds && channel->readfd == FD_CLOSED
|
||||
if (channel->bidir_fd && channel->readfd == FD_CLOSED
|
||||
&& channel->writefd == FD_CLOSED && channel->errfd == FD_CLOSED) {
|
||||
TRACE(("CLOSE (finally) of %d", fd))
|
||||
m_close(fd);
|
||||
@@ -1138,6 +1116,7 @@ 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;
|
||||
|
||||
@@ -1154,7 +1133,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Confirmation that our channel open request (for forwardings) was
|
||||
/* Confirmation that our channel open request was
|
||||
* successful*/
|
||||
void recv_msg_channel_open_confirmation() {
|
||||
|
||||
|
||||
164
common-kex.c
164
common-kex.c
@@ -36,6 +36,7 @@
|
||||
#include "dbrandom.h"
|
||||
#include "runopts.h"
|
||||
#include "ecc.h"
|
||||
#include "curve25519.h"
|
||||
#include "crypto_desc.h"
|
||||
|
||||
static void kexinitialise(void);
|
||||
@@ -48,7 +49,6 @@ static void read_kex_algos(void);
|
||||
/* helper function for gen_new_keys */
|
||||
static void hashkeys(unsigned char *out, unsigned int outlen,
|
||||
const hash_state * hs, const unsigned char X);
|
||||
static void finish_kexhashbuf(void);
|
||||
|
||||
|
||||
/* Send our list of algorithms we can use */
|
||||
@@ -65,7 +65,7 @@ void send_msg_kexinit() {
|
||||
buf_put_algolist(ses.writepayload, sshkex);
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
buf_put_algolist(ses.writepayload, sshhostkey);
|
||||
buf_put_algolist(ses.writepayload, sigalgs);
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
buf_put_algolist(ses.writepayload, sshciphers);
|
||||
@@ -110,8 +110,9 @@ void send_msg_kexinit() {
|
||||
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
|
||||
if (ses.send_kex_first_guess) {
|
||||
ses.newkeys->algo_kex = sshkex[0].data;
|
||||
ses.newkeys->algo_hostkey = sshhostkey[0].val;
|
||||
ses.newkeys->algo_kex = first_usable_algo(sshkex)->data;
|
||||
ses.newkeys->algo_signature = first_usable_algo(sigalgs)->val;
|
||||
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
|
||||
ses.send_kex_first_guess();
|
||||
}
|
||||
|
||||
@@ -152,6 +153,7 @@ static void switch_keys() {
|
||||
TRACE(("switch_keys done"))
|
||||
ses.keys->algo_kex = ses.newkeys->algo_kex;
|
||||
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
|
||||
ses.keys->algo_signature = ses.newkeys->algo_signature;
|
||||
ses.keys->allow_compress = 0;
|
||||
m_free(ses.newkeys);
|
||||
ses.newkeys = NULL;
|
||||
@@ -173,6 +175,9 @@ void send_msg_newkeys() {
|
||||
|
||||
/* set up our state */
|
||||
ses.kexstate.sentnewkeys = 1;
|
||||
if (ses.kexstate.donefirstkex) {
|
||||
ses.kexstate.donesecondkex = 1;
|
||||
}
|
||||
ses.kexstate.donefirstkex = 1;
|
||||
ses.dataallowed = 1; /* we can send other packets again now */
|
||||
gen_new_keys();
|
||||
@@ -195,8 +200,6 @@ void recv_msg_newkeys() {
|
||||
|
||||
/* Set up the kex for the first time */
|
||||
void kexfirstinitialise() {
|
||||
ses.kexstate.donefirstkex = 0;
|
||||
|
||||
#ifdef DISABLE_ZLIB
|
||||
ses.compress_algos = ssh_nocompress;
|
||||
#else
|
||||
@@ -329,9 +332,13 @@ static void gen_new_keys() {
|
||||
hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
|
||||
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
|
||||
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
int recv_cipher = -1;
|
||||
if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) {
|
||||
recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
|
||||
if (recv_cipher < 0) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
|
||||
recv_IV, recv_key,
|
||||
ses.newkeys->recv.algo_crypt->keysize, 0,
|
||||
@@ -341,9 +348,13 @@ static void gen_new_keys() {
|
||||
}
|
||||
|
||||
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
|
||||
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0)
|
||||
dropbear_exit("Crypto error");
|
||||
int trans_cipher = -1;
|
||||
if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) {
|
||||
trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
|
||||
if (trans_cipher < 0) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
}
|
||||
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
|
||||
trans_IV, trans_key,
|
||||
ses.newkeys->trans.algo_crypt->keysize, 0,
|
||||
@@ -391,6 +402,14 @@ int is_compress_recv() {
|
||||
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
|
||||
}
|
||||
|
||||
static void* dropbear_zalloc(void* UNUSED(opaque), uInt items, uInt size) {
|
||||
return m_calloc(items, size);
|
||||
}
|
||||
|
||||
static void dropbear_zfree(void* UNUSED(opaque), void* ptr) {
|
||||
m_free(ptr);
|
||||
}
|
||||
|
||||
/* Set up new zlib compression streams, close the old ones. Only
|
||||
* called from gen_new_keys() */
|
||||
static void gen_new_zstream_recv() {
|
||||
@@ -399,8 +418,8 @@ static void gen_new_zstream_recv() {
|
||||
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->recv.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->recv.zstream->zfree = Z_NULL;
|
||||
ses.newkeys->recv.zstream->zalloc = dropbear_zalloc;
|
||||
ses.newkeys->recv.zstream->zfree = dropbear_zfree;
|
||||
|
||||
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
|
||||
dropbear_exit("zlib error");
|
||||
@@ -423,8 +442,8 @@ static void gen_new_zstream_trans() {
|
||||
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|
||||
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
|
||||
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
|
||||
ses.newkeys->trans.zstream->zalloc = Z_NULL;
|
||||
ses.newkeys->trans.zstream->zfree = Z_NULL;
|
||||
ses.newkeys->trans.zstream->zalloc = dropbear_zalloc;
|
||||
ses.newkeys->trans.zstream->zfree = dropbear_zfree;
|
||||
|
||||
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
|
||||
@@ -468,6 +487,12 @@ void recv_msg_kexinit() {
|
||||
TRACE(("continue recv_msg_kexinit: sent kexinit"))
|
||||
}
|
||||
|
||||
/* "Once a party has sent a SSH_MSG_KEXINIT message ...
|
||||
further SSH_MSG_KEXINIT messages MUST NOT be sent" */
|
||||
if (ses.kexstate.recvkexinit) {
|
||||
dropbear_exit("Unexpected KEXINIT");
|
||||
}
|
||||
|
||||
/* start the kex hash */
|
||||
local_ident_len = strlen(LOCAL_IDENT);
|
||||
remote_ident_len = strlen(ses.remoteident);
|
||||
@@ -529,6 +554,7 @@ void recv_msg_kexinit() {
|
||||
TRACE(("leave recv_msg_kexinit"))
|
||||
}
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
static void load_dh_p(mp_int * dh_p)
|
||||
{
|
||||
bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes,
|
||||
@@ -553,9 +579,7 @@ struct kex_dh_param *gen_kexdh_param() {
|
||||
/* read the prime and generator*/
|
||||
load_dh_p(&dh_p);
|
||||
|
||||
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
|
||||
dropbear_exit("Diffie-Hellman error");
|
||||
}
|
||||
mp_set_ul(&dh_g, DH_G_VAL);
|
||||
|
||||
/* calculate q = (p-1)/2 */
|
||||
/* dh_priv is just a temp var here */
|
||||
@@ -639,6 +663,7 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_ECDH
|
||||
struct kex_ecdh_param *gen_kexecdh_param() {
|
||||
@@ -687,29 +712,27 @@ void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
|
||||
/* K, the shared secret */
|
||||
buf_putmpint(ses.kexhashbuf, ses.dh_K);
|
||||
|
||||
ecc_free(Q_them);
|
||||
m_free(Q_them);
|
||||
|
||||
/* calculate the hash H to sign */
|
||||
finish_kexhashbuf();
|
||||
}
|
||||
#endif /* DROPBEAR_ECDH */
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param () {
|
||||
struct kex_curve25519_param *gen_kexcurve25519_param() {
|
||||
/* Per http://cr.yp.to/ecdh.html */
|
||||
struct kex_curve25519_param *param = m_malloc(sizeof(*param));
|
||||
const unsigned char basepoint[32] = {9};
|
||||
|
||||
genrandom(param->priv, CURVE25519_LEN);
|
||||
param->priv[0] &= 248;
|
||||
param->priv[31] &= 127;
|
||||
param->priv[31] |= 64;
|
||||
|
||||
curve25519_donna(param->pub, param->priv, basepoint);
|
||||
dropbear_curve25519_scalarmult(param->pub, param->priv, basepoint);
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param)
|
||||
{
|
||||
void free_kexcurve25519_param(struct kex_curve25519_param *param) {
|
||||
m_burn(param->priv, CURVE25519_LEN);
|
||||
m_free(param);
|
||||
}
|
||||
@@ -726,7 +749,7 @@ void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buff
|
||||
dropbear_exit("Bad curve25519");
|
||||
}
|
||||
|
||||
curve25519_donna(out, param->priv, buf_pub_them->data);
|
||||
dropbear_curve25519_scalarmult(out, param->priv, buf_pub_them->data);
|
||||
|
||||
if (constant_time_memcmp(zeroes, out, CURVE25519_LEN) == 0) {
|
||||
dropbear_exit("Bad curve25519");
|
||||
@@ -761,8 +784,7 @@ void kexcurve25519_comb_key(const struct kex_curve25519_param *param, const buff
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
|
||||
|
||||
static void finish_kexhashbuf(void) {
|
||||
void finish_kexhashbuf(void) {
|
||||
hash_state hs;
|
||||
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
|
||||
|
||||
@@ -813,21 +835,36 @@ static void read_kex_algos() {
|
||||
int goodguess = 0;
|
||||
int allgood = 1; /* we AND this with each goodguess and see if its still
|
||||
true after */
|
||||
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
|
||||
#else
|
||||
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
|
||||
#endif
|
||||
int kexguess2 = 0;
|
||||
|
||||
buf_incrpos(ses.payload, 16); /* start after the cookie */
|
||||
|
||||
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
|
||||
|
||||
/* kex_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
|
||||
#if DROPBEAR_KEXGUESS2
|
||||
if (buf_has_algo(ses.payload, KEXGUESS2_ALGO_NAME) == DROPBEAR_SUCCESS) {
|
||||
kexguess2 = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_EXT_INFO
|
||||
/* Determine if SSH_MSG_EXT_INFO messages should be sent.
|
||||
Should be done for the first key exchange. Only required on server side
|
||||
for server-sig-algs */
|
||||
if (IS_DROPBEAR_SERVER) {
|
||||
if (!ses.kexstate.donefirstkex) {
|
||||
if (buf_has_algo(ses.payload, SSH_EXT_INFO_C) == DROPBEAR_SUCCESS) {
|
||||
ses.allow_ext_info = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
|
||||
if (algo == NULL || algo->data == NULL) {
|
||||
/* kexguess2, ext-info-c, ext-info-s should not match negotiation */
|
||||
erralgo = "kex";
|
||||
goto error;
|
||||
}
|
||||
@@ -836,17 +873,18 @@ static void read_kex_algos() {
|
||||
ses.newkeys->algo_kex = algo->data;
|
||||
|
||||
/* server_host_key_algorithms */
|
||||
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
|
||||
algo = buf_match_algo(ses.payload, sigalgs, kexguess2, &goodguess);
|
||||
allgood &= goodguess;
|
||||
if (algo == NULL) {
|
||||
erralgo = "hostkey";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hostkey algo %s", algo->name))
|
||||
ses.newkeys->algo_hostkey = algo->val;
|
||||
TRACE(("signature algo %s", algo->name))
|
||||
ses.newkeys->algo_signature = algo->val;
|
||||
ses.newkeys->algo_hostkey = signkey_type_from_signature(ses.newkeys->algo_signature);
|
||||
|
||||
/* encryption_algorithms_client_to_server */
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
|
||||
if (c2s_cipher_algo == NULL) {
|
||||
erralgo = "enc c->s";
|
||||
goto error;
|
||||
@@ -854,7 +892,7 @@ static void read_kex_algos() {
|
||||
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
|
||||
|
||||
/* encryption_algorithms_server_to_client */
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
|
||||
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, 0, NULL);
|
||||
if (s2c_cipher_algo == NULL) {
|
||||
erralgo = "enc s->c";
|
||||
goto error;
|
||||
@@ -862,23 +900,33 @@ static void read_kex_algos() {
|
||||
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
|
||||
|
||||
/* mac_algorithms_client_to_server */
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) {
|
||||
c2s_hash_algo = NULL;
|
||||
} else
|
||||
#endif
|
||||
if (c2s_hash_algo == NULL) {
|
||||
erralgo = "mac c->s";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo->name))
|
||||
TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
|
||||
|
||||
/* mac_algorithms_server_to_client */
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
|
||||
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, 0, NULL);
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) {
|
||||
s2c_hash_algo = NULL;
|
||||
} else
|
||||
#endif
|
||||
if (s2c_hash_algo == NULL) {
|
||||
erralgo = "mac s->c";
|
||||
goto error;
|
||||
}
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo->name))
|
||||
TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
|
||||
|
||||
/* compression_algorithms_client_to_server */
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
|
||||
if (c2s_comp_algo == NULL) {
|
||||
erralgo = "comp c->s";
|
||||
goto error;
|
||||
@@ -886,7 +934,7 @@ static void read_kex_algos() {
|
||||
TRACE(("hash c2s is %s", c2s_comp_algo->name))
|
||||
|
||||
/* compression_algorithms_server_to_client */
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
|
||||
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, 0, NULL);
|
||||
if (s2c_comp_algo == NULL) {
|
||||
erralgo = "comp s->c";
|
||||
goto error;
|
||||
@@ -920,8 +968,14 @@ static void read_kex_algos() {
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
|
||||
ses.newkeys->recv.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->trans.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
|
||||
@@ -936,13 +990,25 @@ static void read_kex_algos() {
|
||||
ses.newkeys->trans.crypt_mode =
|
||||
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
|
||||
ses.newkeys->recv.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)c2s_hash_algo->data;
|
||||
ses.newkeys->trans.algo_mac =
|
||||
#if DROPBEAR_AEAD_MODE
|
||||
s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
|
||||
#endif
|
||||
(struct dropbear_hash*)s2c_hash_algo->data;
|
||||
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
|
||||
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
|
||||
}
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
fuzz_kex_fakealgos();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* reserved for future extensions */
|
||||
buf_getint(ses.payload);
|
||||
|
||||
|
||||
@@ -64,45 +64,36 @@ out:
|
||||
|
||||
#if DROPBEAR_USER_ALGO_LIST
|
||||
void
|
||||
parse_ciphers_macs()
|
||||
{
|
||||
if (opts.cipher_list)
|
||||
{
|
||||
if (strcmp(opts.cipher_list, "help") == 0)
|
||||
{
|
||||
parse_ciphers_macs() {
|
||||
int printed_help = 0;
|
||||
if (opts.cipher_list) {
|
||||
if (strcmp(opts.cipher_list, "help") == 0) {
|
||||
char *ciphers = algolist_string(sshciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
|
||||
dropbear_log(LOG_INFO, "Available ciphers: %s", ciphers);
|
||||
m_free(ciphers);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (strcmp(opts.cipher_list, "none") == 0)
|
||||
{
|
||||
/* Encryption is required during authentication */
|
||||
opts.cipher_list = "none,aes128-ctr";
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
|
||||
{
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0) {
|
||||
dropbear_exit("No valid ciphers specified for '-c'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.mac_list)
|
||||
{
|
||||
if (strcmp(opts.mac_list, "help") == 0)
|
||||
{
|
||||
if (opts.mac_list) {
|
||||
if (strcmp(opts.mac_list, "help") == 0) {
|
||||
char *macs = algolist_string(sshhashes);
|
||||
dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
|
||||
dropbear_log(LOG_INFO, "Available MACs: %s", macs);
|
||||
m_free(macs);
|
||||
dropbear_exit(".");
|
||||
}
|
||||
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
|
||||
{
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
printed_help = 1;
|
||||
} else {
|
||||
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0) {
|
||||
dropbear_exit("No valid MACs specified for '-m'");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (printed_help) {
|
||||
dropbear_exit(".");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -110,4 +101,20 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,16 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
/* Sets it to lowdelay */
|
||||
update_channel_prio();
|
||||
|
||||
#if !DROPBEAR_SVR_MULTIUSER
|
||||
/* A sanity check to prevent an accidental configuration option
|
||||
leaving multiuser systems exposed */
|
||||
errno = 0;
|
||||
getuid();
|
||||
if (errno != ENOSYS) {
|
||||
dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
|
||||
}
|
||||
#endif
|
||||
|
||||
now = monotonic_now();
|
||||
ses.connect_time = now;
|
||||
ses.last_packet_time_keepalive_recv = now;
|
||||
@@ -75,14 +85,18 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
ses.last_packet_time_any_sent = 0;
|
||||
ses.last_packet_time_keepalive_sent = 0;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (!fuzz.fuzzing)
|
||||
#endif
|
||||
{
|
||||
if (pipe(ses.signal_pipe) < 0) {
|
||||
dropbear_exit("Signal pipe failed");
|
||||
}
|
||||
setnonblocking(ses.signal_pipe[0]);
|
||||
setnonblocking(ses.signal_pipe[1]);
|
||||
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
|
||||
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
|
||||
}
|
||||
|
||||
ses.writepayload = buf_new(TRANS_MAX_PAYLOAD_LEN);
|
||||
ses.transseq = 0;
|
||||
@@ -133,6 +147,10 @@ void common_session_init(int sock_in, int sock_out) {
|
||||
|
||||
ses.allowprivport = 0;
|
||||
|
||||
#if DROPBEAR_PLUGIN
|
||||
ses.plugin_session = NULL;
|
||||
#endif
|
||||
|
||||
TRACE(("leave session_init"))
|
||||
}
|
||||
|
||||
@@ -148,13 +166,19 @@ void session_loop(void(*loophandler)(void)) {
|
||||
|
||||
timeout.tv_sec = select_timeout();
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&readfd);
|
||||
DROPBEAR_FD_ZERO(&writefd);
|
||||
DROPBEAR_FD_ZERO(&readfd);
|
||||
|
||||
dropbear_assert(ses.payload == NULL);
|
||||
|
||||
/* We get woken up when signal handlers write to this pipe.
|
||||
SIGCHLD in svr-chansession is the only one currently. */
|
||||
#if DROPBEAR_FUZZ
|
||||
if (!fuzz.fuzzing)
|
||||
#endif
|
||||
{
|
||||
FD_SET(ses.signal_pipe[0], &readfd);
|
||||
}
|
||||
|
||||
/* set up for channels which can be read/written */
|
||||
setchannelfds(&readfd, &writefd, writequeue_has_space);
|
||||
@@ -195,8 +219,8 @@ void session_loop(void(*loophandler)(void)) {
|
||||
* want to iterate over channels etc for reading, to handle
|
||||
* server processes exiting etc.
|
||||
* We don't want to read/write FDs. */
|
||||
FD_ZERO(&writefd);
|
||||
FD_ZERO(&readfd);
|
||||
DROPBEAR_FD_ZERO(&writefd);
|
||||
DROPBEAR_FD_ZERO(&readfd);
|
||||
}
|
||||
|
||||
/* We'll just empty out the pipe if required. We don't do
|
||||
@@ -298,6 +322,16 @@ void session_cleanup() {
|
||||
buf_free(dequeue(&ses.writequeue));
|
||||
}
|
||||
|
||||
m_free(ses.newkeys);
|
||||
#ifndef DISABLE_ZLIB
|
||||
if (ses.keys->recv.zstream != NULL) {
|
||||
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
|
||||
dropbear_exit("Crypto error");
|
||||
}
|
||||
m_free(ses.keys->recv.zstream);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_free(ses.remoteident);
|
||||
m_free(ses.authstate.pw_dir);
|
||||
m_free(ses.authstate.pw_name);
|
||||
@@ -327,7 +361,7 @@ void session_cleanup() {
|
||||
void send_session_identification() {
|
||||
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
|
||||
buf_putbytes(writebuf, (const unsigned char *) LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
|
||||
writebuf_enqueue(writebuf, 0);
|
||||
writebuf_enqueue(writebuf);
|
||||
}
|
||||
|
||||
static void read_session_identification() {
|
||||
@@ -336,8 +370,11 @@ static void read_session_identification() {
|
||||
int len = 0;
|
||||
char done = 0;
|
||||
int i;
|
||||
/* If they send more than 50 lines, something is wrong */
|
||||
for (i = 0; i < 50; i++) {
|
||||
|
||||
/* Servers may send other lines of data before sending the
|
||||
* version string, client must be able to process such lines.
|
||||
* If they send more than 50 lines, something is wrong */
|
||||
for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
|
||||
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
|
||||
|
||||
if (len < 0 && errno != EINTR) {
|
||||
@@ -387,7 +424,7 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
DROPBEAR_FD_ZERO(&fds);
|
||||
|
||||
/* select since it's a non-blocking fd */
|
||||
|
||||
@@ -428,6 +465,11 @@ static int ident_readln(int fd, char* buf, int count) {
|
||||
TRACE(("leave ident_readln: EOF"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
fuzz_dump(&in, 1);
|
||||
#endif
|
||||
|
||||
if (in == '\n') {
|
||||
/* end of ident string */
|
||||
break;
|
||||
|
||||
1100
config.guess
vendored
1100
config.guess
vendored
File diff suppressed because it is too large
Load Diff
453
config.h.in
Normal file
453
config.h.in
Normal file
@@ -0,0 +1,453 @@
|
||||
/* 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 `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/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
|
||||
2917
config.sub
vendored
2917
config.sub
vendored
File diff suppressed because it is too large
Load Diff
102
configure.ac
102
configure.ac
@@ -5,10 +5,18 @@
|
||||
# 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)
|
||||
|
||||
# Record which revision is being built
|
||||
if test -s "`which hg`" && test -d "$srcdir/.hg"; then
|
||||
hgrev=`hg id -i -R "$srcdir"`
|
||||
AC_MSG_NOTICE([Source directory Mercurial base revision $hgrev])
|
||||
fi
|
||||
|
||||
ORIGCFLAGS="$CFLAGS"
|
||||
LATE_CFLAGS=""
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
|
||||
@@ -29,7 +37,7 @@ AC_DEFUN(DB_TRYADDCFLAGS,
|
||||
}])
|
||||
|
||||
# set compile flags prior to other tests
|
||||
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
|
||||
if test -z "$ORIGCFLAGS" && test "$GCC" = "yes"; then
|
||||
AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
|
||||
CFLAGS="-Os -W -Wall"
|
||||
fi
|
||||
@@ -40,6 +48,9 @@ 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],
|
||||
@@ -117,6 +128,17 @@ 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
|
||||
|
||||
@@ -315,16 +337,56 @@ AC_ARG_ENABLE(shadow,
|
||||
AC_MSG_NOTICE(Using shadow passwords if available)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(plugin,
|
||||
[ --enable-plugin Enable support for External Public Key Authentication plug-in],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 1, External Public Key Authentication)
|
||||
AC_MSG_NOTICE(Enabling support for External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=1
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_PLUGIN, 0, External Public Key Authentication)
|
||||
DROPBEAR_PLUGIN=0
|
||||
]
|
||||
|
||||
)
|
||||
AC_SUBST(DROPBEAR_PLUGIN)
|
||||
|
||||
AC_ARG_ENABLE(fuzz,
|
||||
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
|
||||
AC_MSG_NOTICE(Enabling fuzzing)
|
||||
DROPBEAR_FUZZ=1
|
||||
# libfuzzer needs linking with c++ libraries
|
||||
AC_PROG_CXX
|
||||
mkdir -pv fuzz
|
||||
else
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_DEFINE(DROPBEAR_FUZZ, 0, Fuzzing)
|
||||
AC_MSG_NOTICE(Disabling fuzzing)
|
||||
DROPBEAR_FUZZ=0
|
||||
]
|
||||
|
||||
)
|
||||
AC_SUBST(DROPBEAR_FUZZ)
|
||||
AC_SUBST(CXX)
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
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])
|
||||
pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \
|
||||
sys/random.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
@@ -332,7 +394,6 @@ 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])
|
||||
@@ -473,32 +534,36 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
|
||||
AC_CHECK_FUNCS(setutxent utmpxname)
|
||||
AC_CHECK_FUNCS(logout updwtmp logwtmp)
|
||||
|
||||
# POSIX monotonic time
|
||||
AC_CHECK_FUNCS(clock_gettime)
|
||||
|
||||
# OS X monotonic time
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
AC_CHECK_FUNCS(mach_absolute_time)
|
||||
|
||||
AC_CHECK_FUNCS(explicit_bzero memset_s)
|
||||
AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
|
||||
|
||||
AC_ARG_ENABLE(bundled-libtom,
|
||||
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
|
||||
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
|
||||
Default is to use system if available, otherwise bundled.],
|
||||
Default is to use system if available, otherwise bundled.
|
||||
Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0],
|
||||
[
|
||||
if test "x$enableval" = "xyes"; then
|
||||
BUNDLED_LIBTOM=1
|
||||
AC_MSG_NOTICE(Forcing bundled libtom*)
|
||||
else
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtommath and --disable-bundled-libtom was specified])] )
|
||||
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
|
||||
[AC_MSG_ERROR([Missing/old system libtomcrypt and --disable-bundled-libtom was specified])] )
|
||||
fi
|
||||
],
|
||||
[
|
||||
BUNDLED_LIBTOM=0
|
||||
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -808,8 +873,11 @@ if test $BUNDLED_LIBTOM = 1 ; then
|
||||
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
|
||||
fi
|
||||
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
|
||||
# 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_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
@@ -831,4 +899,4 @@ AC_MSG_NOTICE([crypt() not available, dropbear server will not have password aut
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE()
|
||||
AC_MSG_NOTICE([Now edit options.h to choose features.])
|
||||
AC_MSG_NOTICE([Now edit localoptions.h to choose features.])
|
||||
|
||||
@@ -3,11 +3,18 @@
|
||||
#include "crypto_desc.h"
|
||||
#include "ltc_prng.h"
|
||||
#include "ecc.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
#if DROPBEAR_LTC_PRNG
|
||||
int dropbear_ltc_prng = -1;
|
||||
#endif
|
||||
|
||||
/* Wrapper for libtommath */
|
||||
static mp_err dropbear_rand_source(void* out, size_t size) {
|
||||
genrandom((unsigned char*)out, (unsigned int)size);
|
||||
return MP_OKAY;
|
||||
}
|
||||
|
||||
|
||||
/* Register the compiled in ciphers.
|
||||
* This should be run before using any of the ciphers/hashes */
|
||||
@@ -67,6 +74,8 @@ void crypto_init() {
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_rand_source(dropbear_rand_source);
|
||||
|
||||
#if DROPBEAR_ECC
|
||||
ltc_mp = ltm_desc;
|
||||
dropbear_ecc_fill_dp();
|
||||
|
||||
@@ -1,860 +0,0 @@
|
||||
/* Copyright 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* curve25519-donna: Curve25519 elliptic curve, public key function
|
||||
*
|
||||
* http://code.google.com/p/curve25519-donna/
|
||||
*
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
*
|
||||
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
|
||||
*
|
||||
* More information about curve25519 can be found here
|
||||
* http://cr.yp.to/ecdh.html
|
||||
*
|
||||
* djb's sample implementation of curve25519 is written in a special assembly
|
||||
* language called qhasm and uses the floating point registers.
|
||||
*
|
||||
* This is, almost, a clean room reimplementation from the curve25519 paper. It
|
||||
* uses many of the tricks described therein. Only the crecip function is taken
|
||||
* from the sample implementation. */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t limb;
|
||||
|
||||
/* Field element representation:
|
||||
*
|
||||
* Field elements are written as an array of signed, 64-bit limbs, least
|
||||
* significant first. The value of the field element is:
|
||||
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
|
||||
*
|
||||
* i.e. the limbs are 26, 25, 26, 25, ... bits wide. */
|
||||
|
||||
/* Sum two numbers: output += in */
|
||||
static void fsum(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
output[0+i] = output[0+i] + in[0+i];
|
||||
output[1+i] = output[1+i] + in[1+i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the difference of two numbers: output = in - output
|
||||
* (note the order of the arguments!). */
|
||||
static void fdifference(limb *output, const limb *in) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = in[i] - output[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply a number by a scalar: output = in * scalar */
|
||||
static void fscalar_product(limb *output, const limb *in, const limb scalar) {
|
||||
unsigned i;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
output[i] = in[i] * scalar;
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply two numbers: output = in2 * in
|
||||
*
|
||||
* output must be distinct to both inputs. The inputs are reduced coefficient
|
||||
* form, the output is not.
|
||||
*
|
||||
* output[x] <= 14 * the largest product of the input limbs. */
|
||||
static void fproduct(limb *output, const limb *in2, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
|
||||
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[0]);
|
||||
output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[0]);
|
||||
output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[0]);
|
||||
output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
|
||||
2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[0]);
|
||||
output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[0]);
|
||||
output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[0]);
|
||||
output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[0]);
|
||||
output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[0]);
|
||||
output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in2[0])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[0]);
|
||||
output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[1])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[1])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[2]);
|
||||
output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in2[2])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[2]);
|
||||
output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[3])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[3])) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[4]);
|
||||
output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[7])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in2[4])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[4]);
|
||||
output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[5])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[5])) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[6]);
|
||||
output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in2[8])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in2[6])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[6]);
|
||||
output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[7]));
|
||||
output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
|
||||
((limb) ((s32) in2[9])) * ((s32) in[8]);
|
||||
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
/* Reduce a long form to a short form by taking the input mod 2^255 - 19.
|
||||
*
|
||||
* On entry: |output[i]| < 14*2^54
|
||||
* On exit: |output[0..8]| < 280*2^54 */
|
||||
static void freduce_degree(limb *output) {
|
||||
/* Each of these shifts and adds ends up multiplying the value by 19.
|
||||
*
|
||||
* For output[0..8], the absolute entry value is < 14*2^54 and we add, at
|
||||
* most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */
|
||||
output[8] += output[18] << 4;
|
||||
output[8] += output[18] << 1;
|
||||
output[8] += output[18];
|
||||
output[7] += output[17] << 4;
|
||||
output[7] += output[17] << 1;
|
||||
output[7] += output[17];
|
||||
output[6] += output[16] << 4;
|
||||
output[6] += output[16] << 1;
|
||||
output[6] += output[16];
|
||||
output[5] += output[15] << 4;
|
||||
output[5] += output[15] << 1;
|
||||
output[5] += output[15];
|
||||
output[4] += output[14] << 4;
|
||||
output[4] += output[14] << 1;
|
||||
output[4] += output[14];
|
||||
output[3] += output[13] << 4;
|
||||
output[3] += output[13] << 1;
|
||||
output[3] += output[13];
|
||||
output[2] += output[12] << 4;
|
||||
output[2] += output[12] << 1;
|
||||
output[2] += output[12];
|
||||
output[1] += output[11] << 4;
|
||||
output[1] += output[11] << 1;
|
||||
output[1] += output[11];
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
}
|
||||
|
||||
#if (-1 & 3) != 3
|
||||
#error "This code only works on a two's complement system"
|
||||
#endif
|
||||
|
||||
/* return v / 2^26, using only shifts and adds.
|
||||
*
|
||||
* On entry: v can take any value. */
|
||||
static inline limb
|
||||
div_by_2_26(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed. */
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x3ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 6;
|
||||
/* Should return v / (1<<26) */
|
||||
return (v + roundoff) >> 26;
|
||||
}
|
||||
|
||||
/* return v / (2^25), using only shifts and adds.
|
||||
*
|
||||
* On entry: v can take any value. */
|
||||
static inline limb
|
||||
div_by_2_25(const limb v)
|
||||
{
|
||||
/* High word of v; no shift needed*/
|
||||
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
|
||||
/* Set to all 1s if v was negative; else set to 0s. */
|
||||
const int32_t sign = ((int32_t) highword) >> 31;
|
||||
/* Set to 0x1ffffff if v was negative; else set to 0. */
|
||||
const int32_t roundoff = ((uint32_t) sign) >> 7;
|
||||
/* Should return v / (1<<25) */
|
||||
return (v + roundoff) >> 25;
|
||||
}
|
||||
|
||||
/* Reduce all coefficients of the short form input so that |x| < 2^26.
|
||||
*
|
||||
* On entry: |output[i]| < 280*2^54 */
|
||||
static void freduce_coefficients(limb *output) {
|
||||
unsigned i;
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
for (i = 0; i < 10; i += 2) {
|
||||
limb over = div_by_2_26(output[i]);
|
||||
/* The entry condition (that |output[i]| < 280*2^54) means that over is, at
|
||||
* most, 280*2^28 in the first iteration of this loop. This is added to the
|
||||
* next limb and we can approximate the resulting bound of that limb by
|
||||
* 281*2^54. */
|
||||
output[i] -= over << 26;
|
||||
output[i+1] += over;
|
||||
|
||||
/* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
|
||||
* 281*2^29. When this is added to the next limb, the resulting bound can
|
||||
* be approximated as 281*2^54.
|
||||
*
|
||||
* For subsequent iterations of the loop, 281*2^54 remains a conservative
|
||||
* bound and no overflow occurs. */
|
||||
over = div_by_2_25(output[i+1]);
|
||||
output[i+1] -= over << 25;
|
||||
output[i+2] += over;
|
||||
}
|
||||
/* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
|
||||
output[0] += output[10] << 4;
|
||||
output[0] += output[10] << 1;
|
||||
output[0] += output[10];
|
||||
|
||||
output[10] = 0;
|
||||
|
||||
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
|
||||
* So |over| will be no more than 2^16. */
|
||||
{
|
||||
limb over = div_by_2_26(output[0]);
|
||||
output[0] -= over << 26;
|
||||
output[1] += over;
|
||||
}
|
||||
|
||||
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
|
||||
* bound on |output[1]| is sufficient to meet our needs. */
|
||||
}
|
||||
|
||||
/* A helpful wrapper around fproduct: output = in * in2.
|
||||
*
|
||||
* On entry: |in[i]| < 2^27 and |in2[i]| < 2^27.
|
||||
*
|
||||
* output must be distinct to both inputs. The output is reduced degree
|
||||
* (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */
|
||||
static void
|
||||
fmul(limb *output, const limb *in, const limb *in2) {
|
||||
limb t[19];
|
||||
fproduct(t, in, in2);
|
||||
/* |t[i]| < 14*2^54 */
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
/* |t[i]| < 2^26 */
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* Square a number: output = in**2
|
||||
*
|
||||
* output must be distinct from the input. The inputs are reduced coefficient
|
||||
* form, the output is not.
|
||||
*
|
||||
* output[x] <= 14 * the largest product of the input limbs. */
|
||||
static void fsquare_inner(limb *output, const limb *in) {
|
||||
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
|
||||
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
|
||||
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[2]));
|
||||
output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[3]));
|
||||
output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
|
||||
4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
|
||||
2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
|
||||
output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[5]));
|
||||
output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[6]) +
|
||||
2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
|
||||
output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[7]));
|
||||
output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
|
||||
2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[5])));
|
||||
output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[0])) * ((s32) in[9]));
|
||||
output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[1])) * ((s32) in[9])));
|
||||
output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[2])) * ((s32) in[9]));
|
||||
output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
|
||||
2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
|
||||
2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[3])) * ((s32) in[9])));
|
||||
output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[5])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[4])) * ((s32) in[9]));
|
||||
output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[8]) +
|
||||
2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
|
||||
output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
|
||||
((limb) ((s32) in[6])) * ((s32) in[9]));
|
||||
output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
|
||||
4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
|
||||
output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
|
||||
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
|
||||
}
|
||||
|
||||
/* fsquare sets output = in^2.
|
||||
*
|
||||
* On entry: The |in| argument is in reduced coefficients form and |in[i]| <
|
||||
* 2^27.
|
||||
*
|
||||
* On exit: The |output| argument is in reduced coefficients form (indeed, one
|
||||
* need only provide storage for 10 limbs) and |out[i]| < 2^26. */
|
||||
static void
|
||||
fsquare(limb *output, const limb *in) {
|
||||
limb t[19];
|
||||
fsquare_inner(t, in);
|
||||
/* |t[i]| < 14*2^54 because the largest product of two limbs will be <
|
||||
* 2^(27+27) and fsquare_inner adds together, at most, 14 of those
|
||||
* products. */
|
||||
freduce_degree(t);
|
||||
freduce_coefficients(t);
|
||||
/* |t[i]| < 2^26 */
|
||||
memcpy(output, t, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* Take a little-endian, 32-byte number and expand it into polynomial form */
|
||||
static void
|
||||
fexpand(limb *output, const u8 *input) {
|
||||
#define F(n,start,shift,mask) \
|
||||
output[n] = ((((limb) input[start + 0]) | \
|
||||
((limb) input[start + 1]) << 8 | \
|
||||
((limb) input[start + 2]) << 16 | \
|
||||
((limb) input[start + 3]) << 24) >> shift) & mask;
|
||||
F(0, 0, 0, 0x3ffffff);
|
||||
F(1, 3, 2, 0x1ffffff);
|
||||
F(2, 6, 3, 0x3ffffff);
|
||||
F(3, 9, 5, 0x1ffffff);
|
||||
F(4, 12, 6, 0x3ffffff);
|
||||
F(5, 16, 0, 0x1ffffff);
|
||||
F(6, 19, 1, 0x3ffffff);
|
||||
F(7, 22, 3, 0x1ffffff);
|
||||
F(8, 25, 4, 0x3ffffff);
|
||||
F(9, 28, 6, 0x1ffffff);
|
||||
#undef F
|
||||
}
|
||||
|
||||
#if (-32 >> 1) != -16
|
||||
#error "This code only works when >> does sign-extension on negative numbers"
|
||||
#endif
|
||||
|
||||
/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */
|
||||
static s32 s32_eq(s32 a, s32 b) {
|
||||
a = ~(a ^ b);
|
||||
a &= a << 16;
|
||||
a &= a << 8;
|
||||
a &= a << 4;
|
||||
a &= a << 2;
|
||||
a &= a << 1;
|
||||
return a >> 31;
|
||||
}
|
||||
|
||||
/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are
|
||||
* both non-negative. */
|
||||
static s32 s32_gte(s32 a, s32 b) {
|
||||
a -= b;
|
||||
/* a >= 0 iff a >= b. */
|
||||
return ~(a >> 31);
|
||||
}
|
||||
|
||||
/* Take a fully reduced polynomial form number and contract it into a
|
||||
* little-endian, 32-byte array.
|
||||
*
|
||||
* On entry: |input_limbs[i]| < 2^26 */
|
||||
static void
|
||||
fcontract(u8 *output, limb *input_limbs) {
|
||||
int i;
|
||||
int j;
|
||||
s32 input[10];
|
||||
s32 mask;
|
||||
|
||||
/* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
|
||||
for (i = 0; i < 10; i++) {
|
||||
input[i] = input_limbs[i];
|
||||
}
|
||||
|
||||
for (j = 0; j < 2; ++j) {
|
||||
for (i = 0; i < 9; ++i) {
|
||||
if ((i & 1) == 1) {
|
||||
/* This calculation is a time-invariant way to make input[i]
|
||||
* non-negative by borrowing from the next-larger limb. */
|
||||
const s32 mask = input[i] >> 31;
|
||||
const s32 carry = -((input[i] & mask) >> 25);
|
||||
input[i] = input[i] + (carry << 25);
|
||||
input[i+1] = input[i+1] - carry;
|
||||
} else {
|
||||
const s32 mask = input[i] >> 31;
|
||||
const s32 carry = -((input[i] & mask) >> 26);
|
||||
input[i] = input[i] + (carry << 26);
|
||||
input[i+1] = input[i+1] - carry;
|
||||
}
|
||||
}
|
||||
|
||||
/* There's no greater limb for input[9] to borrow from, but we can multiply
|
||||
* by 19 and borrow from input[0], which is valid mod 2^255-19. */
|
||||
{
|
||||
const s32 mask = input[9] >> 31;
|
||||
const s32 carry = -((input[9] & mask) >> 25);
|
||||
input[9] = input[9] + (carry << 25);
|
||||
input[0] = input[0] - (carry * 19);
|
||||
}
|
||||
|
||||
/* After the first iteration, input[1..9] are non-negative and fit within
|
||||
* 25 or 26 bits, depending on position. However, input[0] may be
|
||||
* negative. */
|
||||
}
|
||||
|
||||
/* The first borrow-propagation pass above ended with every limb
|
||||
except (possibly) input[0] non-negative.
|
||||
|
||||
If input[0] was negative after the first pass, then it was because of a
|
||||
carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
|
||||
one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
|
||||
|
||||
In the second pass, each limb is decreased by at most one. Thus the second
|
||||
borrow-propagation pass could only have wrapped around to decrease
|
||||
input[0] again if the first pass left input[0] negative *and* input[1]
|
||||
through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
|
||||
and this last borrow-propagation step will leave input[1] non-negative. */
|
||||
{
|
||||
const s32 mask = input[0] >> 31;
|
||||
const s32 carry = -((input[0] & mask) >> 26);
|
||||
input[0] = input[0] + (carry << 26);
|
||||
input[1] = input[1] - carry;
|
||||
}
|
||||
|
||||
/* All input[i] are now non-negative. However, there might be values between
|
||||
* 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
|
||||
for (j = 0; j < 2; j++) {
|
||||
for (i = 0; i < 9; i++) {
|
||||
if ((i & 1) == 1) {
|
||||
const s32 carry = input[i] >> 25;
|
||||
input[i] &= 0x1ffffff;
|
||||
input[i+1] += carry;
|
||||
} else {
|
||||
const s32 carry = input[i] >> 26;
|
||||
input[i] &= 0x3ffffff;
|
||||
input[i+1] += carry;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const s32 carry = input[9] >> 25;
|
||||
input[9] &= 0x1ffffff;
|
||||
input[0] += 19*carry;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the first carry-chain pass, just above, ended up with a carry from
|
||||
* input[9], and that caused input[0] to be out-of-bounds, then input[0] was
|
||||
* < 2^26 + 2*19, because the carry was, at most, two.
|
||||
*
|
||||
* If the second pass carried from input[9] again then input[0] is < 2*19 and
|
||||
* the input[9] -> input[0] carry didn't push input[0] out of bounds. */
|
||||
|
||||
/* It still remains the case that input might be between 2^255-19 and 2^255.
|
||||
* In this case, input[1..9] must take their maximum value and input[0] must
|
||||
* be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
|
||||
mask = s32_gte(input[0], 0x3ffffed);
|
||||
for (i = 1; i < 10; i++) {
|
||||
if ((i & 1) == 1) {
|
||||
mask &= s32_eq(input[i], 0x1ffffff);
|
||||
} else {
|
||||
mask &= s32_eq(input[i], 0x3ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
/* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
|
||||
* this conditionally subtracts 2^255-19. */
|
||||
input[0] -= mask & 0x3ffffed;
|
||||
|
||||
for (i = 1; i < 10; i++) {
|
||||
if ((i & 1) == 1) {
|
||||
input[i] -= mask & 0x1ffffff;
|
||||
} else {
|
||||
input[i] -= mask & 0x3ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
input[1] <<= 2;
|
||||
input[2] <<= 3;
|
||||
input[3] <<= 5;
|
||||
input[4] <<= 6;
|
||||
input[6] <<= 1;
|
||||
input[7] <<= 3;
|
||||
input[8] <<= 4;
|
||||
input[9] <<= 6;
|
||||
#define F(i, s) \
|
||||
output[s+0] |= input[i] & 0xff; \
|
||||
output[s+1] = (input[i] >> 8) & 0xff; \
|
||||
output[s+2] = (input[i] >> 16) & 0xff; \
|
||||
output[s+3] = (input[i] >> 24) & 0xff;
|
||||
output[0] = 0;
|
||||
output[16] = 0;
|
||||
F(0,0);
|
||||
F(1,3);
|
||||
F(2,6);
|
||||
F(3,9);
|
||||
F(4,12);
|
||||
F(5,16);
|
||||
F(6,19);
|
||||
F(7,22);
|
||||
F(8,25);
|
||||
F(9,28);
|
||||
#undef F
|
||||
}
|
||||
|
||||
/* Input: Q, Q', Q-Q'
|
||||
* Output: 2Q, Q+Q'
|
||||
*
|
||||
* x2 z3: long form
|
||||
* x3 z3: long form
|
||||
* x z: short form, destroyed
|
||||
* xprime zprime: short form, destroyed
|
||||
* qmqp: short form, preserved
|
||||
*
|
||||
* On entry and exit, the absolute value of the limbs of all inputs and outputs
|
||||
* are < 2^26. */
|
||||
static void fmonty(limb *x2, limb *z2, /* output 2Q */
|
||||
limb *x3, limb *z3, /* output Q + Q' */
|
||||
limb *x, limb *z, /* input Q */
|
||||
limb *xprime, limb *zprime, /* input Q' */
|
||||
const limb *qmqp /* input Q - Q' */) {
|
||||
limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
|
||||
zzprime[19], zzzprime[19], xxxprime[19];
|
||||
|
||||
memcpy(origx, x, 10 * sizeof(limb));
|
||||
fsum(x, z);
|
||||
/* |x[i]| < 2^27 */
|
||||
fdifference(z, origx); /* does x - z */
|
||||
/* |z[i]| < 2^27 */
|
||||
|
||||
memcpy(origxprime, xprime, sizeof(limb) * 10);
|
||||
fsum(xprime, zprime);
|
||||
/* |xprime[i]| < 2^27 */
|
||||
fdifference(zprime, origxprime);
|
||||
/* |zprime[i]| < 2^27 */
|
||||
fproduct(xxprime, xprime, z);
|
||||
/* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
|
||||
* 2^(27+27) and fproduct adds together, at most, 14 of those products.
|
||||
* (Approximating that to 2^58 doesn't work out.) */
|
||||
fproduct(zzprime, x, zprime);
|
||||
/* |zzprime[i]| < 14*2^54 */
|
||||
freduce_degree(xxprime);
|
||||
freduce_coefficients(xxprime);
|
||||
/* |xxprime[i]| < 2^26 */
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
/* |zzprime[i]| < 2^26 */
|
||||
memcpy(origxprime, xxprime, sizeof(limb) * 10);
|
||||
fsum(xxprime, zzprime);
|
||||
/* |xxprime[i]| < 2^27 */
|
||||
fdifference(zzprime, origxprime);
|
||||
/* |zzprime[i]| < 2^27 */
|
||||
fsquare(xxxprime, xxprime);
|
||||
/* |xxxprime[i]| < 2^26 */
|
||||
fsquare(zzzprime, zzprime);
|
||||
/* |zzzprime[i]| < 2^26 */
|
||||
fproduct(zzprime, zzzprime, qmqp);
|
||||
/* |zzprime[i]| < 14*2^52 */
|
||||
freduce_degree(zzprime);
|
||||
freduce_coefficients(zzprime);
|
||||
/* |zzprime[i]| < 2^26 */
|
||||
memcpy(x3, xxxprime, sizeof(limb) * 10);
|
||||
memcpy(z3, zzprime, sizeof(limb) * 10);
|
||||
|
||||
fsquare(xx, x);
|
||||
/* |xx[i]| < 2^26 */
|
||||
fsquare(zz, z);
|
||||
/* |zz[i]| < 2^26 */
|
||||
fproduct(x2, xx, zz);
|
||||
/* |x2[i]| < 14*2^52 */
|
||||
freduce_degree(x2);
|
||||
freduce_coefficients(x2);
|
||||
/* |x2[i]| < 2^26 */
|
||||
fdifference(zz, xx); /* does zz = xx - zz */
|
||||
/* |zz[i]| < 2^27 */
|
||||
memset(zzz + 10, 0, sizeof(limb) * 9);
|
||||
fscalar_product(zzz, zz, 121665);
|
||||
/* |zzz[i]| < 2^(27+17) */
|
||||
/* No need to call freduce_degree here:
|
||||
fscalar_product doesn't increase the degree of its input. */
|
||||
freduce_coefficients(zzz);
|
||||
/* |zzz[i]| < 2^26 */
|
||||
fsum(zzz, xx);
|
||||
/* |zzz[i]| < 2^27 */
|
||||
fproduct(z2, zz, zzz);
|
||||
/* |z2[i]| < 14*2^(26+27) */
|
||||
freduce_degree(z2);
|
||||
freduce_coefficients(z2);
|
||||
/* |z2|i| < 2^26 */
|
||||
}
|
||||
|
||||
/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave
|
||||
* them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid
|
||||
* side-channel attacks.
|
||||
*
|
||||
* NOTE that this function requires that 'iswap' be 1 or 0; other values give
|
||||
* wrong results. Also, the two limb arrays must be in reduced-coefficient,
|
||||
* reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,
|
||||
* and all all values in a[0..9],b[0..9] must have magnitude less than
|
||||
* INT32_MAX. */
|
||||
static void
|
||||
swap_conditional(limb a[19], limb b[19], limb iswap) {
|
||||
unsigned i;
|
||||
const s32 swap = (s32) -iswap;
|
||||
|
||||
for (i = 0; i < 10; ++i) {
|
||||
const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
|
||||
a[i] = ((s32)a[i]) ^ x;
|
||||
b[i] = ((s32)b[i]) ^ x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculates nQ where Q is the x-coordinate of a point on the curve
|
||||
*
|
||||
* resultx/resultz: the x coordinate of the resulting curve point (short form)
|
||||
* n: a little endian, 32-byte number
|
||||
* q: a point of the curve (short form) */
|
||||
static void
|
||||
cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
|
||||
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
|
||||
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
|
||||
limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
|
||||
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
|
||||
|
||||
unsigned i, j;
|
||||
|
||||
memcpy(nqpqx, q, sizeof(limb) * 10);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
u8 byte = n[31 - i];
|
||||
for (j = 0; j < 8; ++j) {
|
||||
const limb bit = byte >> 7;
|
||||
|
||||
swap_conditional(nqx, nqpqx, bit);
|
||||
swap_conditional(nqz, nqpqz, bit);
|
||||
fmonty(nqx2, nqz2,
|
||||
nqpqx2, nqpqz2,
|
||||
nqx, nqz,
|
||||
nqpqx, nqpqz,
|
||||
q);
|
||||
swap_conditional(nqx2, nqpqx2, bit);
|
||||
swap_conditional(nqz2, nqpqz2, bit);
|
||||
|
||||
t = nqx;
|
||||
nqx = nqx2;
|
||||
nqx2 = t;
|
||||
t = nqz;
|
||||
nqz = nqz2;
|
||||
nqz2 = t;
|
||||
t = nqpqx;
|
||||
nqpqx = nqpqx2;
|
||||
nqpqx2 = t;
|
||||
t = nqpqz;
|
||||
nqpqz = nqpqz2;
|
||||
nqpqz2 = t;
|
||||
|
||||
byte <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(resultx, nqx, sizeof(limb) * 10);
|
||||
memcpy(resultz, nqz, sizeof(limb) * 10);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Shamelessly copied from djb's code
|
||||
* ----------------------------------------------------------------------------- */
|
||||
static void
|
||||
crecip(limb *out, const limb *z) {
|
||||
limb z2[10];
|
||||
limb z9[10];
|
||||
limb z11[10];
|
||||
limb z2_5_0[10];
|
||||
limb z2_10_0[10];
|
||||
limb z2_20_0[10];
|
||||
limb z2_50_0[10];
|
||||
limb z2_100_0[10];
|
||||
limb t0[10];
|
||||
limb t1[10];
|
||||
int i;
|
||||
|
||||
/* 2 */ fsquare(z2,z);
|
||||
/* 4 */ fsquare(t1,z2);
|
||||
/* 8 */ fsquare(t0,t1);
|
||||
/* 9 */ fmul(z9,t0,z);
|
||||
/* 11 */ fmul(z11,z9,z2);
|
||||
/* 22 */ fsquare(t0,z11);
|
||||
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
|
||||
|
||||
/* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
|
||||
/* 2^7 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^8 - 2^3 */ fsquare(t0,t1);
|
||||
/* 2^9 - 2^4 */ fsquare(t1,t0);
|
||||
/* 2^10 - 2^5 */ fsquare(t0,t1);
|
||||
/* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
|
||||
|
||||
/* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
|
||||
/* 2^12 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
|
||||
|
||||
/* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
|
||||
/* 2^22 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
|
||||
|
||||
/* 2^41 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^42 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
|
||||
|
||||
/* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
|
||||
/* 2^52 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
|
||||
|
||||
/* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
|
||||
/* 2^102 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
|
||||
/* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
|
||||
|
||||
/* 2^201 - 2^1 */ fsquare(t0,t1);
|
||||
/* 2^202 - 2^2 */ fsquare(t1,t0);
|
||||
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
|
||||
/* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
|
||||
|
||||
/* 2^251 - 2^1 */ fsquare(t1,t0);
|
||||
/* 2^252 - 2^2 */ fsquare(t0,t1);
|
||||
/* 2^253 - 2^3 */ fsquare(t1,t0);
|
||||
/* 2^254 - 2^4 */ fsquare(t0,t1);
|
||||
/* 2^255 - 2^5 */ fsquare(t1,t0);
|
||||
/* 2^255 - 21 */ fmul(out,t1,z11);
|
||||
}
|
||||
|
||||
int
|
||||
curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
|
||||
limb bp[10], x[10], z[11], zmone[10];
|
||||
uint8_t e[32];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; ++i) e[i] = secret[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
|
||||
fexpand(bp, basepoint);
|
||||
cmult(x, z, e, bp);
|
||||
crecip(zmone, z);
|
||||
fmul(z, x, zmone);
|
||||
fcontract(mypublic, z);
|
||||
return 0;
|
||||
}
|
||||
497
curve25519.c
Normal file
497
curve25519.c
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbrandom.h"
|
||||
#include "curve25519.h"
|
||||
|
||||
#if DROPBEAR_CURVE25519 || DROPBEAR_ED25519
|
||||
|
||||
/* Modified TweetNaCl version 20140427, a self-contained public-domain C library.
|
||||
* https://tweetnacl.cr.yp.to/ */
|
||||
|
||||
#define FOR(i,n) for (i = 0;i < n;++i)
|
||||
#define sv static void
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned long u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
typedef i64 gf[16];
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
static const gf
|
||||
_121665 = {0xDB41,1};
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
#if DROPBEAR_ED25519
|
||||
static const gf
|
||||
gf0,
|
||||
gf1 = {1},
|
||||
D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
|
||||
X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
|
||||
Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666};
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static const gf
|
||||
D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
|
||||
I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int vn(const u8 *x,const u8 *y,u32 n)
|
||||
{
|
||||
u32 i,d = 0;
|
||||
FOR(i,n) d |= x[i]^y[i];
|
||||
return (1 & ((d - 1) >> 8)) - 1;
|
||||
}
|
||||
|
||||
static int crypto_verify_32(const u8 *x,const u8 *y)
|
||||
{
|
||||
return vn(x,y,32);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
sv set25519(gf r, const gf a)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) r[i]=a[i];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv car25519(gf o)
|
||||
{
|
||||
int i;
|
||||
i64 c;
|
||||
FOR(i,16) {
|
||||
o[i]+=(1LL<<16);
|
||||
c=o[i]>>16;
|
||||
o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15);
|
||||
o[i]-=c<<16;
|
||||
}
|
||||
}
|
||||
|
||||
sv sel25519(gf p,gf q,int b)
|
||||
{
|
||||
i64 t,i,c=~(b-1);
|
||||
FOR(i,16) {
|
||||
t= c&(p[i]^q[i]);
|
||||
p[i]^=t;
|
||||
q[i]^=t;
|
||||
}
|
||||
}
|
||||
|
||||
sv pack25519(u8 *o,const gf n)
|
||||
{
|
||||
int i,j,b;
|
||||
gf m,t;
|
||||
FOR(i,16) t[i]=n[i];
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
car25519(t);
|
||||
FOR(j,2) {
|
||||
m[0]=t[0]-0xffed;
|
||||
for(i=1;i<15;i++) {
|
||||
m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
|
||||
m[i-1]&=0xffff;
|
||||
}
|
||||
m[15]=t[15]-0x7fff-((m[14]>>16)&1);
|
||||
b=(m[15]>>16)&1;
|
||||
m[14]&=0xffff;
|
||||
sel25519(t,m,1-b);
|
||||
}
|
||||
FOR(i,16) {
|
||||
o[2*i]=t[i]&0xff;
|
||||
o[2*i+1]=t[i]>>8;
|
||||
}
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int neq25519(const gf a, const gf b)
|
||||
{
|
||||
u8 c[32],d[32];
|
||||
pack25519(c,a);
|
||||
pack25519(d,b);
|
||||
return crypto_verify_32(c,d);
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
static u8 par25519(const gf a)
|
||||
{
|
||||
u8 d[32];
|
||||
pack25519(d,a);
|
||||
return d[0]&1;
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
sv unpack25519(gf o, const u8 *n)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8);
|
||||
o[15]&=0x7fff;
|
||||
}
|
||||
|
||||
sv A(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]+b[i];
|
||||
}
|
||||
|
||||
sv Z(gf o,const gf a,const gf b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,16) o[i]=a[i]-b[i];
|
||||
}
|
||||
|
||||
sv M(gf o,const gf a,const gf b)
|
||||
{
|
||||
i64 i,j,t[31];
|
||||
FOR(i,31) t[i]=0;
|
||||
FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j];
|
||||
FOR(i,15) t[i]+=38*t[i+16];
|
||||
FOR(i,16) o[i]=t[i];
|
||||
car25519(o);
|
||||
car25519(o);
|
||||
}
|
||||
|
||||
sv S(gf o,const gf a)
|
||||
{
|
||||
M(o,a,a);
|
||||
}
|
||||
|
||||
sv inv25519(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=253;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=2&&a!=4) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
|
||||
#if DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY
|
||||
sv pow2523(gf o,const gf i)
|
||||
{
|
||||
gf c;
|
||||
int a;
|
||||
FOR(a,16) c[a]=i[a];
|
||||
for(a=250;a>=0;a--) {
|
||||
S(c,c);
|
||||
if(a!=1) M(c,c,i);
|
||||
}
|
||||
FOR(a,16) o[a]=c[a];
|
||||
}
|
||||
#endif /* DROPBEAR_ED25519 && DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#if DROPBEAR_CURVE25519
|
||||
void dropbear_curve25519_scalarmult(u8 *q,const u8 *n,const u8 *p)
|
||||
{
|
||||
u8 z[32];
|
||||
i64 x[80],r,i;
|
||||
gf a,b,c,d,e,f;
|
||||
FOR(i,31) z[i]=n[i];
|
||||
z[31]=(n[31]&127)|64;
|
||||
z[0]&=248;
|
||||
unpack25519(x,p);
|
||||
FOR(i,16) {
|
||||
b[i]=x[i];
|
||||
d[i]=a[i]=c[i]=0;
|
||||
}
|
||||
a[0]=d[0]=1;
|
||||
for(i=254;i>=0;--i) {
|
||||
r=(z[i>>3]>>(i&7))&1;
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
A(c,b,d);
|
||||
Z(b,b,d);
|
||||
S(d,e);
|
||||
S(f,a);
|
||||
M(a,c,a);
|
||||
M(c,b,e);
|
||||
A(e,a,c);
|
||||
Z(a,a,c);
|
||||
S(b,a);
|
||||
Z(c,d,f);
|
||||
M(a,c,_121665);
|
||||
A(a,a,d);
|
||||
M(c,c,a);
|
||||
M(a,d,f);
|
||||
M(d,b,x);
|
||||
S(b,e);
|
||||
sel25519(a,b,r);
|
||||
sel25519(c,d,r);
|
||||
}
|
||||
FOR(i,16) {
|
||||
x[i+16]=a[i];
|
||||
x[i+32]=c[i];
|
||||
x[i+48]=b[i];
|
||||
x[i+64]=d[i];
|
||||
}
|
||||
inv25519(x+32,x+32);
|
||||
M(x+16,x+16,x+32);
|
||||
pack25519(q,x+16);
|
||||
}
|
||||
#endif /* DROPBEAR_CURVE25519 */
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
static int crypto_hash(u8 *out,const u8 *m,u64 n)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs, m, n);
|
||||
return sha512_done(&hs, out);
|
||||
}
|
||||
|
||||
sv add(gf p[4],gf q[4])
|
||||
{
|
||||
gf a,b,c,d,t,e,f,g,h;
|
||||
|
||||
Z(a, p[1], p[0]);
|
||||
Z(t, q[1], q[0]);
|
||||
M(a, a, t);
|
||||
A(b, p[0], p[1]);
|
||||
A(t, q[0], q[1]);
|
||||
M(b, b, t);
|
||||
M(c, p[3], q[3]);
|
||||
M(c, c, D2);
|
||||
M(d, p[2], q[2]);
|
||||
A(d, d, d);
|
||||
Z(e, b, a);
|
||||
Z(f, d, c);
|
||||
A(g, d, c);
|
||||
A(h, b, a);
|
||||
|
||||
M(p[0], e, f);
|
||||
M(p[1], h, g);
|
||||
M(p[2], g, f);
|
||||
M(p[3], e, h);
|
||||
}
|
||||
|
||||
sv cswap(gf p[4],gf q[4],u8 b)
|
||||
{
|
||||
int i;
|
||||
FOR(i,4)
|
||||
sel25519(p[i],q[i],b);
|
||||
}
|
||||
|
||||
sv pack(u8 *r,gf p[4])
|
||||
{
|
||||
gf tx, ty, zi;
|
||||
inv25519(zi, p[2]);
|
||||
M(tx, p[0], zi);
|
||||
M(ty, p[1], zi);
|
||||
pack25519(r, ty);
|
||||
r[31] ^= par25519(tx) << 7;
|
||||
}
|
||||
|
||||
sv scalarmult(gf p[4],gf q[4],const u8 *s)
|
||||
{
|
||||
int i;
|
||||
set25519(p[0],gf0);
|
||||
set25519(p[1],gf1);
|
||||
set25519(p[2],gf1);
|
||||
set25519(p[3],gf0);
|
||||
for (i = 255;i >= 0;--i) {
|
||||
u8 b = (s[i/8]>>(i&7))&1;
|
||||
cswap(p,q,b);
|
||||
add(q,p);
|
||||
add(p,p);
|
||||
cswap(p,q,b);
|
||||
}
|
||||
}
|
||||
|
||||
sv scalarbase(gf p[4],const u8 *s)
|
||||
{
|
||||
gf q[4];
|
||||
set25519(q[0],X);
|
||||
set25519(q[1],Y);
|
||||
set25519(q[2],gf1);
|
||||
M(q[3],X,Y);
|
||||
scalarmult(p,q,s);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_make_key(u8 *pk,u8 *sk)
|
||||
{
|
||||
u8 d[64];
|
||||
gf p[4];
|
||||
|
||||
genrandom(sk, 32);
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
scalarbase(p,d);
|
||||
pack(pk,p);
|
||||
}
|
||||
|
||||
static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
|
||||
|
||||
sv modL(u8 *r,i64 x[64])
|
||||
{
|
||||
i64 carry,i,j;
|
||||
for (i = 63;i >= 32;--i) {
|
||||
carry = 0;
|
||||
for (j = i - 32;j < i - 12;++j) {
|
||||
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
|
||||
carry = (x[j] + 128) >> 8;
|
||||
x[j] -= carry << 8;
|
||||
}
|
||||
x[j] += carry;
|
||||
x[i] = 0;
|
||||
}
|
||||
carry = 0;
|
||||
FOR(j,32) {
|
||||
x[j] += carry - (x[31] >> 4) * L[j];
|
||||
carry = x[j] >> 8;
|
||||
x[j] &= 255;
|
||||
}
|
||||
FOR(j,32) x[j] -= carry * L[j];
|
||||
FOR(i,32) {
|
||||
x[i+1] += x[i] >> 8;
|
||||
r[i] = x[i] & 255;
|
||||
}
|
||||
}
|
||||
|
||||
sv reduce(u8 *r)
|
||||
{
|
||||
i64 x[64],i;
|
||||
FOR(i,64) x[i] = (u64) r[i];
|
||||
FOR(i,64) r[i] = 0;
|
||||
modL(r,x);
|
||||
}
|
||||
|
||||
void dropbear_ed25519_sign(const u8 *m,u32 mlen,u8 *s,u32 *slen,const u8 *sk, const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 d[64],h[64],r[64];
|
||||
i64 x[64];
|
||||
gf p[4];
|
||||
u32 i,j;
|
||||
|
||||
crypto_hash(d, sk, 32);
|
||||
d[0] &= 248;
|
||||
d[31] &= 127;
|
||||
d[31] |= 64;
|
||||
|
||||
*slen = 64;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,d + 32,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,r);
|
||||
reduce(r);
|
||||
scalarbase(p,r);
|
||||
pack(s,p);
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
reduce(h);
|
||||
|
||||
FOR(i,64) x[i] = 0;
|
||||
FOR(i,32) x[i] = (u64) r[i];
|
||||
FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j];
|
||||
modL(s + 32,x);
|
||||
}
|
||||
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
static int unpackneg(gf r[4],const u8 p[32])
|
||||
{
|
||||
gf t, chk, num, den, den2, den4, den6;
|
||||
set25519(r[2],gf1);
|
||||
unpack25519(r[1],p);
|
||||
S(num,r[1]);
|
||||
M(den,num,D);
|
||||
Z(num,num,r[2]);
|
||||
A(den,r[2],den);
|
||||
|
||||
S(den2,den);
|
||||
S(den4,den2);
|
||||
M(den6,den4,den2);
|
||||
M(t,den6,num);
|
||||
M(t,t,den);
|
||||
|
||||
pow2523(t,t);
|
||||
M(t,t,num);
|
||||
M(t,t,den);
|
||||
M(t,t,den);
|
||||
M(r[0],t,den);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) M(r[0],r[0],I);
|
||||
|
||||
S(chk,r[0]);
|
||||
M(chk,chk,den);
|
||||
if (neq25519(chk, num)) return -1;
|
||||
|
||||
if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]);
|
||||
|
||||
M(r[3],r[0],r[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dropbear_ed25519_verify(const u8 *m,u32 mlen,const u8 *s,u32 slen,const u8 *pk)
|
||||
{
|
||||
hash_state hs;
|
||||
u8 t[32],h[64];
|
||||
gf p[4],q[4];
|
||||
|
||||
if (slen < 64) return -1;
|
||||
|
||||
if (unpackneg(q,pk)) return -1;
|
||||
|
||||
sha512_init(&hs);
|
||||
sha512_process(&hs,s,32);
|
||||
sha512_process(&hs,pk,32);
|
||||
sha512_process(&hs,m,mlen);
|
||||
sha512_done(&hs,h);
|
||||
|
||||
reduce(h);
|
||||
scalarmult(p,q,h);
|
||||
|
||||
scalarbase(q,s + 32);
|
||||
add(p,q);
|
||||
pack(t,p);
|
||||
|
||||
if (crypto_verify_32(s, t))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519 || DROPBEAR_ED25519 */
|
||||
37
curve25519.h
Normal file
37
curve25519.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_CURVE25519_H
|
||||
#define DROPBEAR_CURVE25519_H
|
||||
|
||||
void dropbear_curve25519_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
|
||||
void dropbear_ed25519_make_key(unsigned char *pk, unsigned char *sk);
|
||||
void dropbear_ed25519_sign(const unsigned char *m, unsigned long mlen,
|
||||
unsigned char *s, unsigned long *slen,
|
||||
const unsigned char *sk, const unsigned char *pk);
|
||||
int dropbear_ed25519_verify(const unsigned char *m, unsigned long mlen,
|
||||
const unsigned char *s, unsigned long slen,
|
||||
const unsigned char *pk);
|
||||
|
||||
#endif /* DROPBEAR_CURVE25519_H */
|
||||
23
dbclient.1
23
dbclient.1
@@ -19,7 +19,7 @@ dbclient \- lightweight SSH client
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dbclient
|
||||
is a small SSH client
|
||||
is the client part of Dropbear SSH
|
||||
.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 the port
|
||||
Forward
|
||||
.I listenport
|
||||
on the local host through the SSH connection to port
|
||||
on the local host through the SSH connection to
|
||||
.I port
|
||||
on the host
|
||||
on
|
||||
.IR host .
|
||||
.TP
|
||||
.B \-R\fR [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
|
||||
Remote port forwarding.
|
||||
Forward the port
|
||||
Forward
|
||||
.I listenport
|
||||
on the remote host through the SSH connection to port
|
||||
on the remote host through the SSH connection to
|
||||
.I port
|
||||
on the host
|
||||
on
|
||||
.IR host .
|
||||
.TP
|
||||
.B \-l \fIuser
|
||||
Username.
|
||||
Login as
|
||||
.I user
|
||||
on the remote host.
|
||||
on the remote host. An alternative is to specify user@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 a command is given. See -t.
|
||||
Don't allocate a PTY. This is the default when 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,10 +149,13 @@ 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
|
||||
|
||||
13
dbhelpers.c
13
dbhelpers.c
@@ -9,16 +9,9 @@ void m_burn(void *data, unsigned int len) {
|
||||
#elif defined(HAVE_EXPLICIT_BZERO)
|
||||
explicit_bzero(data, len);
|
||||
#else
|
||||
/* Based on the method in David Wheeler's
|
||||
* "Secure Programming for Linux and Unix HOWTO". May not be safe
|
||||
* against link-time optimisation. */
|
||||
volatile char *p = data;
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
while (len--) {
|
||||
*p++ = 0x0;
|
||||
}
|
||||
/* This must be volatile to avoid compiler optimisation */
|
||||
volatile void *p = data;
|
||||
memset((void*)p, 0x0, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
192
dbmalloc.c
Normal file
192
dbmalloc.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "dbmalloc.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
|
||||
void * m_calloc(size_t nmemb, size_t size) {
|
||||
if (SIZE_T_MAX / nmemb < size) {
|
||||
dropbear_exit("m_calloc failed");
|
||||
}
|
||||
return m_malloc(nmemb*size);
|
||||
}
|
||||
|
||||
void * m_strdup(const char * str) {
|
||||
char* ret;
|
||||
unsigned int len;
|
||||
len = strlen(str);
|
||||
|
||||
ret = m_malloc(len+1);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_strdup failed");
|
||||
}
|
||||
memcpy(ret, str, len+1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !DROPBEAR_TRACKING_MALLOC
|
||||
|
||||
/* Simple wrappers around malloc etc */
|
||||
void * m_malloc(size_t size) {
|
||||
|
||||
void* ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
ret = calloc(1, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
ret = realloc(ptr, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
/* For fuzzing */
|
||||
|
||||
struct dbmalloc_header {
|
||||
unsigned int epoch;
|
||||
struct dbmalloc_header *prev;
|
||||
struct dbmalloc_header *next;
|
||||
};
|
||||
|
||||
static void put_alloc(struct dbmalloc_header *header);
|
||||
static void remove_alloc(struct dbmalloc_header *header);
|
||||
|
||||
/* end of the linked list */
|
||||
static struct dbmalloc_header* staple;
|
||||
|
||||
unsigned int current_epoch = 0;
|
||||
|
||||
void m_malloc_set_epoch(unsigned int epoch) {
|
||||
current_epoch = epoch;
|
||||
}
|
||||
|
||||
void m_malloc_free_epoch(unsigned int epoch, int dofree) {
|
||||
struct dbmalloc_header* header;
|
||||
struct dbmalloc_header* nextheader = NULL;
|
||||
struct dbmalloc_header* oldstaple = staple;
|
||||
staple = NULL;
|
||||
/* free allocations from this epoch, create a new staple-anchored list from
|
||||
the remainder */
|
||||
for (header = oldstaple; header; header = nextheader)
|
||||
{
|
||||
nextheader = header->next;
|
||||
if (header->epoch == epoch) {
|
||||
if (dofree) {
|
||||
free(header);
|
||||
}
|
||||
} else {
|
||||
header->prev = NULL;
|
||||
header->next = NULL;
|
||||
put_alloc(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void put_alloc(struct dbmalloc_header *header) {
|
||||
assert(header->next == NULL);
|
||||
assert(header->prev == NULL);
|
||||
if (staple) {
|
||||
staple->prev = header;
|
||||
}
|
||||
header->next = staple;
|
||||
staple = header;
|
||||
}
|
||||
|
||||
static void remove_alloc(struct dbmalloc_header *header) {
|
||||
if (header->prev) {
|
||||
header->prev->next = header->next;
|
||||
}
|
||||
if (header->next) {
|
||||
header->next->prev = header->prev;
|
||||
}
|
||||
if (staple == header) {
|
||||
staple = header->next;
|
||||
}
|
||||
header->prev = NULL;
|
||||
header->next = NULL;
|
||||
}
|
||||
|
||||
static struct dbmalloc_header* get_header(void* ptr) {
|
||||
char* bptr = ptr;
|
||||
return (struct dbmalloc_header*)&bptr[-sizeof(struct dbmalloc_header)];
|
||||
}
|
||||
|
||||
void * m_malloc(size_t size) {
|
||||
char* mem = NULL;
|
||||
struct dbmalloc_header* header = NULL;
|
||||
|
||||
if (size == 0 || size > 1e9) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
|
||||
size = size + sizeof(struct dbmalloc_header);
|
||||
|
||||
mem = calloc(1, size);
|
||||
if (mem == NULL) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
header = (struct dbmalloc_header*)mem;
|
||||
put_alloc(header);
|
||||
header->epoch = current_epoch;
|
||||
return &mem[sizeof(struct dbmalloc_header)];
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
char* mem = NULL;
|
||||
struct dbmalloc_header* header = NULL;
|
||||
if (size == 0 || size > 1e9) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
|
||||
header = get_header(ptr);
|
||||
remove_alloc(header);
|
||||
|
||||
size = size + sizeof(struct dbmalloc_header);
|
||||
mem = realloc(header, size);
|
||||
if (mem == NULL) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
|
||||
header = (struct dbmalloc_header*)mem;
|
||||
put_alloc(header);
|
||||
return &mem[sizeof(struct dbmalloc_header)];
|
||||
}
|
||||
|
||||
void m_free_direct(void* ptr) {
|
||||
struct dbmalloc_header* header = NULL;
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
header = get_header(ptr);
|
||||
remove_alloc(header);
|
||||
free(header);
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_TRACKING_MALLOC */
|
||||
|
||||
void * m_realloc_ltm(void* ptr, size_t oldsize, size_t newsize) {
|
||||
(void)oldsize;
|
||||
return m_realloc(ptr, newsize);
|
||||
}
|
||||
|
||||
void m_free_ltm(void *mem, size_t size) {
|
||||
(void)size;
|
||||
m_free_direct(mem);
|
||||
}
|
||||
27
dbmalloc.h
Normal file
27
dbmalloc.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef DBMALLOC_H_
|
||||
#define DBMALLOC_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);
|
||||
void * m_strdup(const char * str);
|
||||
void * m_realloc(void* ptr, size_t size);
|
||||
|
||||
#if DROPBEAR_TRACKING_MALLOC
|
||||
void m_free_direct(void* ptr);
|
||||
void m_malloc_set_epoch(unsigned int epoch);
|
||||
void m_malloc_free_epoch(unsigned int epoch, int dofree);
|
||||
|
||||
#else
|
||||
/* plain wrapper */
|
||||
#define m_free_direct free
|
||||
|
||||
#endif
|
||||
|
||||
#define m_free(X) do {m_free_direct(X); (X) = NULL;} while (0)
|
||||
|
||||
|
||||
#endif /* DBMALLOC_H_ */
|
||||
180
dbrandom.c
180
dbrandom.c
@@ -27,7 +27,7 @@
|
||||
#include "dbutil.h"
|
||||
#include "bignum.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
#include "runopts.h"
|
||||
|
||||
/* this is used to generate unique output from the same hashpool */
|
||||
static uint32_t counter = 0;
|
||||
@@ -49,24 +49,19 @@ static int donerandinit = 0;
|
||||
*
|
||||
*/
|
||||
|
||||
/* Pass len=0 to hash an entire file */
|
||||
/* Pass wantlen=0 to hash an entire file */
|
||||
static int
|
||||
process_file(hash_state *hs, const char *filename,
|
||||
unsigned int len, int prngd)
|
||||
{
|
||||
static int already_blocked = 0;
|
||||
int readfd;
|
||||
unsigned int wantlen, int prngd) {
|
||||
int readfd = -1;
|
||||
unsigned int readcount;
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
|
||||
if (prngd) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (prngd)
|
||||
{
|
||||
readfd = connect_unix(filename);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
readfd = open(filename, O_RDONLY);
|
||||
}
|
||||
|
||||
@@ -75,58 +70,31 @@ process_file(hash_state *hs, const char *filename,
|
||||
}
|
||||
|
||||
readcount = 0;
|
||||
while (len == 0 || readcount < len)
|
||||
{
|
||||
while (wantlen == 0 || readcount < wantlen) {
|
||||
int readlen, wantread;
|
||||
unsigned char readbuf[4096];
|
||||
if (!already_blocked && !prngd)
|
||||
{
|
||||
int res;
|
||||
struct timeval timeout;
|
||||
fd_set read_fds;
|
||||
|
||||
timeout.tv_sec = 2;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(readfd, &read_fds);
|
||||
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
if (res == 0)
|
||||
{
|
||||
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
|
||||
already_blocked = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
if (wantlen == 0) {
|
||||
wantread = sizeof(readbuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
wantread = MIN(sizeof(readbuf), len-readcount);
|
||||
} else {
|
||||
wantread = MIN(sizeof(readbuf), wantlen-readcount);
|
||||
}
|
||||
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (prngd)
|
||||
{
|
||||
if (prngd) {
|
||||
char egdcmd[2];
|
||||
egdcmd[0] = 0x02; /* blocking read */
|
||||
egdcmd[1] = (unsigned char)wantread;
|
||||
if (write(readfd, egdcmd, 2) < 0)
|
||||
{
|
||||
if (write(readfd, egdcmd, 2) < 0) {
|
||||
dropbear_exit("Can't send command to egd");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
readlen = read(readfd, readbuf, wantread);
|
||||
if (readlen <= 0) {
|
||||
if (readlen < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (readlen == 0 && len == 0)
|
||||
{
|
||||
if (readlen == 0 && wantlen == 0) {
|
||||
/* whole file was read as requested */
|
||||
break;
|
||||
}
|
||||
@@ -145,6 +113,12 @@ void addrandom(const unsigned char * buf, unsigned int len)
|
||||
{
|
||||
hash_state hs;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
/* existing state (zeroes on startup) */
|
||||
@@ -157,6 +131,11 @@ void addrandom(const unsigned char * buf, unsigned int len)
|
||||
|
||||
static void write_urandom()
|
||||
{
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if !DROPBEAR_USE_PRNGD
|
||||
/* This is opportunistic, don't worry about failure */
|
||||
unsigned char buf[INIT_SEED_SIZE];
|
||||
@@ -170,6 +149,75 @@ static void write_urandom()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
void fuzz_seed(const unsigned char* dat, unsigned int len) {
|
||||
hash_state hs;
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz"));
|
||||
sha1_process(&hs, dat, len);
|
||||
sha1_done(&hs, hashpool);
|
||||
counter = 0;
|
||||
donerandinit = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_GETRANDOM
|
||||
/* Reads entropy seed with getrandom().
|
||||
* May block if the kernel isn't ready.
|
||||
* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int process_getrandom(hash_state *hs) {
|
||||
char buf[INIT_SEED_SIZE];
|
||||
ssize_t ret;
|
||||
|
||||
/* First try non-blocking so that we can warn about waiting */
|
||||
ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
/* Old kernel */
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
/* Other errors fall through to blocking getrandom() */
|
||||
TRACE(("first getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
if (errno == EAGAIN) {
|
||||
dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised...");
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait blocking if needed. Loop in case we get EINTR */
|
||||
while (ret != sizeof(buf)) {
|
||||
ret = getrandom(buf, sizeof(buf), 0);
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success */
|
||||
break;
|
||||
}
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
/* Try again. */
|
||||
continue;
|
||||
}
|
||||
if (ret >= 0) {
|
||||
TRACE(("Short read %zd from getrandom() shouldn't happen", ret))
|
||||
/* Try again? */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Unexpected problem, fall back to /dev/urandom */
|
||||
TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == sizeof(buf)) {
|
||||
/* Success, stir in the entropy */
|
||||
sha1_process(hs, (void*)buf, sizeof(buf));
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
return DROPBEAR_FAILURE;
|
||||
|
||||
}
|
||||
#endif /* HAVE_GETRANDOM */
|
||||
|
||||
/* Initialise the prng from /dev/urandom or prngd. This function can
|
||||
* be called multiple times */
|
||||
void seedrandom() {
|
||||
@@ -179,27 +227,45 @@ void seedrandom() {
|
||||
pid_t pid;
|
||||
struct timeval tv;
|
||||
clock_t clockval;
|
||||
int urandom_seeded = 0;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* hash in the new seed data */
|
||||
sha1_init(&hs);
|
||||
|
||||
/* existing state */
|
||||
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
|
||||
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
#ifdef HAVE_GETRANDOM
|
||||
if (process_getrandom(&hs) == DROPBEAR_SUCCESS) {
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!urandom_seeded) {
|
||||
#if DROPBEAR_USE_PRNGD
|
||||
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_PRNGD_SOCKET);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#else
|
||||
/* non-blocking random source (probably /dev/urandom) */
|
||||
if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0)
|
||||
!= DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Failure reading random device %s",
|
||||
DROPBEAR_URANDOM_DEV);
|
||||
urandom_seeded = 1;
|
||||
}
|
||||
#endif
|
||||
} /* urandom_seeded */
|
||||
|
||||
/* A few other sources to fall back on.
|
||||
* Add more here for other platforms */
|
||||
#ifdef __linux__
|
||||
|
||||
229
dbutil.c
229
dbutil.c
@@ -120,6 +120,12 @@ static void generic_dropbear_exit(int exitcode, const char* format,
|
||||
|
||||
_dropbear_log(LOG_INFO, fmtbuf, param);
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.do_jmp) {
|
||||
longjmp(fuzz.jmp, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
@@ -251,6 +257,12 @@ int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
|
||||
const int FDIN = 0;
|
||||
const int FDOUT = 1;
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return fuzz_spawn_command(ret_writefd, ret_readfd, ret_errfd, ret_pid);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* redirect stdin/stdout/stderr */
|
||||
if (pipe(infds) != 0) {
|
||||
return DROPBEAR_FAILURE;
|
||||
@@ -373,25 +385,43 @@ 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;
|
||||
int i, j;
|
||||
|
||||
fprintf(stderr, "%s\n", label);
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02x", buf[i]);
|
||||
if (i % 16 == 15) {
|
||||
fprintf(stderr, "\n");
|
||||
/* 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, " ");
|
||||
}
|
||||
}
|
||||
else if (i % 2 == 1) {
|
||||
fprintf(stderr, " ");
|
||||
|
||||
/* print characters */
|
||||
fprintf(stderr, " ");
|
||||
for (i = 0; i < linelen; i++) {
|
||||
char c = buf[j+i];
|
||||
if (!isprint(c)) {
|
||||
c = '.';
|
||||
}
|
||||
fputc(c, stderr);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void printmpint(const char *label, mp_int *mp) {
|
||||
buffer *buf = buf_new(1000);
|
||||
buf_putmpint(buf, mp);
|
||||
fprintf(stderr, "%d bits ", mp_count_bits(mp));
|
||||
printhex(label, buf->data, buf->len);
|
||||
buf_free(buf);
|
||||
|
||||
@@ -520,57 +550,26 @@ void m_close(int fd) {
|
||||
}
|
||||
}
|
||||
|
||||
void * m_malloc(size_t size) {
|
||||
|
||||
void* ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
ret = calloc(1, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_malloc failed");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
void * m_strdup(const char * str) {
|
||||
char* ret;
|
||||
|
||||
ret = strdup(str);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_strdup failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void * m_realloc(void* ptr, size_t size) {
|
||||
|
||||
void *ret;
|
||||
|
||||
if (size == 0) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
ret = realloc(ptr, size);
|
||||
if (ret == NULL) {
|
||||
dropbear_exit("m_realloc failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setnonblocking(int fd) {
|
||||
|
||||
TRACE(("setnonblocking: %d", fd))
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
if (errno == ENODEV) {
|
||||
/* Some devices (like /dev/null redirected in)
|
||||
* can't be set to non-blocking */
|
||||
TRACE(("ignoring ENODEV for setnonblocking"))
|
||||
} else {
|
||||
{
|
||||
dropbear_exit("Couldn't set nonblocking");
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE(("leave setnonblocking"))
|
||||
}
|
||||
@@ -584,8 +583,15 @@ void disallow_core() {
|
||||
/* 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;
|
||||
errno = 0;
|
||||
l = strtoul(str, NULL, 10);
|
||||
char *endp;
|
||||
|
||||
l = strtoul(str, &endp, 10);
|
||||
|
||||
if (endp == str || *endp != '\0') {
|
||||
// parse error
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
@@ -603,11 +609,19 @@ otherwise home directory is prepended */
|
||||
char * expand_homedir_path(const char *inpath) {
|
||||
struct passwd *pw = NULL;
|
||||
if (inpath[0] != '/') {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir) {
|
||||
int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
|
||||
char *homedir = getenv("HOME");
|
||||
|
||||
if (!homedir) {
|
||||
pw = getpwuid(getuid());
|
||||
if (pw) {
|
||||
homedir = pw->pw_dir;
|
||||
}
|
||||
}
|
||||
|
||||
if (homedir) {
|
||||
int len = strlen(inpath) + strlen(homedir) + 2;
|
||||
char *buf = m_malloc(len);
|
||||
snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
|
||||
snprintf(buf, len, "%s/%s", homedir, inpath);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
@@ -628,61 +642,67 @@ int constant_time_memcmp(const void* a, const void *b, size_t n)
|
||||
return c;
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||
/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
|
||||
reach userspace include headers */
|
||||
#ifndef CLOCK_MONOTONIC_COARSE
|
||||
#define CLOCK_MONOTONIC_COARSE 6
|
||||
/* higher-resolution monotonic timestamp, falls back to gettimeofday */
|
||||
void gettime_wrapper(struct timespec *now) {
|
||||
struct timeval tv;
|
||||
#if DROPBEAR_FUZZ
|
||||
if (fuzz.fuzzing) {
|
||||
/* time stands still when fuzzing */
|
||||
now->tv_sec = 5;
|
||||
now->tv_nsec = 0;
|
||||
}
|
||||
#endif
|
||||
/* Some old toolchains know SYS_clock_gettime but not CLOCK_MONOTONIC */
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC 1
|
||||
|
||||
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
/* POSIX monotonic clock. Newer Linux, BSD, MacOSX >10.12 */
|
||||
if (clock_gettime(CLOCK_MONOTONIC, now) == 0) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
static clockid_t get_linux_clock_source() {
|
||||
struct timespec ts;
|
||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
|
||||
return CLOCK_MONOTONIC_COARSE;
|
||||
}
|
||||
|
||||
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
|
||||
return CLOCK_MONOTONIC;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
time_t monotonic_now() {
|
||||
#if defined(__linux__) && defined(SYS_clock_gettime)
|
||||
static clockid_t clock_source = -2;
|
||||
|
||||
if (clock_source == -2) {
|
||||
/* First run, find out which one works.
|
||||
-1 will fall back to time() */
|
||||
clock_source = get_linux_clock_source();
|
||||
}
|
||||
|
||||
if (clock_source >= 0) {
|
||||
struct timespec ts;
|
||||
if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
|
||||
/* Intermittent clock failures should not happen */
|
||||
dropbear_exit("Clock broke");
|
||||
{
|
||||
/* Old linux toolchain - kernel might support it but not the build headers */
|
||||
/* Also glibc <2.17 requires -lrt which we neglect to add */
|
||||
static int linux_monotonic_failed = 0;
|
||||
if (!linux_monotonic_failed) {
|
||||
/* CLOCK_MONOTONIC isn't in some headers */
|
||||
int clock_source_monotonic = 1;
|
||||
if (syscall(SYS_clock_gettime, clock_source_monotonic, now) == 0) {
|
||||
return;
|
||||
} else {
|
||||
/* Don't try again */
|
||||
linux_monotonic_failed = 1;
|
||||
}
|
||||
return ts.tv_sec;
|
||||
}
|
||||
#endif /* linux clock_gettime */
|
||||
}
|
||||
#endif /* linux fallback clock_gettime */
|
||||
|
||||
#if defined(HAVE_MACH_ABSOLUTE_TIME)
|
||||
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||
{
|
||||
/* OS X pre 10.12, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
|
||||
static mach_timebase_info_data_t timebase_info;
|
||||
uint64_t scaled_time;
|
||||
if (timebase_info.denom == 0) {
|
||||
mach_timebase_info(&timebase_info);
|
||||
}
|
||||
return mach_absolute_time() * timebase_info.numer / timebase_info.denom
|
||||
/ 1e9;
|
||||
scaled_time = mach_absolute_time() * timebase_info.numer / timebase_info.denom;
|
||||
now->tv_sec = scaled_time / 1000000000;
|
||||
now->tv_nsec = scaled_time % 1000000000;
|
||||
}
|
||||
#endif /* osx mach_absolute_time */
|
||||
|
||||
/* Fallback for everything else - this will sometimes go backwards */
|
||||
return time(NULL);
|
||||
gettimeofday(&tv, NULL);
|
||||
now->tv_sec = tv.tv_sec;
|
||||
now->tv_nsec = 1000*tv.tv_usec;
|
||||
}
|
||||
|
||||
/* second-resolution monotonic timestamp */
|
||||
time_t monotonic_now() {
|
||||
struct timespec ts;
|
||||
gettime_wrapper(&ts);
|
||||
return ts.tv_sec;
|
||||
}
|
||||
|
||||
void fsync_parent_dir(const char* fn) {
|
||||
@@ -700,6 +720,25 @@ void fsync_parent_dir(const char* fn) {
|
||||
TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
|
||||
}
|
||||
|
||||
free(fn_dir);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
16
dbutil.h
16
dbutil.h
@@ -30,6 +30,7 @@
|
||||
#include "buffer.h"
|
||||
#include "queue.h"
|
||||
#include "dbhelpers.h"
|
||||
#include "dbmalloc.h"
|
||||
|
||||
#ifndef DISABLE_SYSLOG
|
||||
void startsyslog(const char *ident);
|
||||
@@ -66,10 +67,6 @@ int buf_readfile(buffer* buf, const char* filename);
|
||||
int buf_getline(buffer * line, FILE * authfile);
|
||||
|
||||
void m_close(int fd);
|
||||
void * m_malloc(size_t size);
|
||||
void * m_strdup(const char * str);
|
||||
void * m_realloc(void* ptr, size_t size);
|
||||
#define m_free(X) do {free(X); (X) = NULL;} while (0)
|
||||
void setnonblocking(int fd);
|
||||
void disallow_core(void);
|
||||
int m_str_to_uint(const char* str, unsigned int *val);
|
||||
@@ -86,9 +83,20 @@ int constant_time_memcmp(const void* a, const void *b, size_t n);
|
||||
/* Returns a time in seconds that doesn't go backwards - does not correspond to
|
||||
a real-world clock */
|
||||
time_t monotonic_now(void);
|
||||
/* Higher resolution clock_gettime(CLOCK_MONOTONIC) wrapper */
|
||||
void gettime_wrapper(struct timespec *now);
|
||||
|
||||
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)
|
||||
#else
|
||||
#define DROPBEAR_FD_ZERO(fds) FD_ZERO(fds)
|
||||
#endif
|
||||
|
||||
#endif /* DROPBEAR_DBUTIL_H_ */
|
||||
|
||||
30
debian/changelog
vendored
30
debian/changelog
vendored
@@ -1,3 +1,33 @@
|
||||
dropbear (2020.81-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Thu, 29 Oct 2020 22:51:57 +0800
|
||||
|
||||
dropbear (2020.80-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Fri, 26 Jun 2020 22:51:57 +0800
|
||||
|
||||
dropbear (2020.79-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Jun 2020 22:51:57 +0800
|
||||
|
||||
dropbear (2019.78-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Wed, 27 Mar 2019 22:51:57 +0800
|
||||
|
||||
dropbear (2019.77-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
-- Matt Johnston <matt@ucc.asn.au> Sat, 23 Mar 2019 22:51:57 +0800
|
||||
|
||||
dropbear (2018.76-0.1) unstable; urgency=low
|
||||
|
||||
* New upstream release.
|
||||
|
||||
13
debug.h
13
debug.h
@@ -39,13 +39,9 @@
|
||||
/*#define CHECKCLEARTOWRITE() assert(ses.writepayload->len == 0 && \
|
||||
ses.writepayload->pos == 0)*/
|
||||
|
||||
#ifndef CHECKCLEARTOWRITE
|
||||
#define CHECKCLEARTOWRITE()
|
||||
|
||||
/* Define this, compile with -pg and set GMON_OUT_PREFIX=gmon to get gmon
|
||||
* output when Dropbear forks. This will allow it gprof to be used.
|
||||
* It's useful to run dropbear -F, so you don't fork as much */
|
||||
/* (This is Linux specific) */
|
||||
/*#define DEBUG_FORKGPROF*/
|
||||
#endif
|
||||
|
||||
/* A couple of flags, not usually useful, and mightn't do anything */
|
||||
|
||||
@@ -54,6 +50,7 @@
|
||||
|
||||
/* you don't need to touch this block */
|
||||
#if DEBUG_TRACE
|
||||
extern int debug_trace;
|
||||
#define TRACE(X) dropbear_trace X;
|
||||
#define TRACE2(X) dropbear_trace2 X;
|
||||
#else /*DEBUG_TRACE*/
|
||||
@@ -63,7 +60,9 @@
|
||||
|
||||
/* To debug with GDB it is easier to run with no forking of child processes.
|
||||
You will need to pass "-F" as well. */
|
||||
/* #define DEBUG_NOFORK */
|
||||
#ifndef DEBUG_NOFORK
|
||||
#define DEBUG_NOFORK 0
|
||||
#endif
|
||||
|
||||
|
||||
/* For testing as non-root on shadowed systems, include the crypt of a password
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
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. Options defined there will override any options in this
|
||||
file.
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key"
|
||||
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
|
||||
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
|
||||
#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key"
|
||||
|
||||
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
|
||||
* on chosen ports and keeps accepting connections. This is the default.
|
||||
@@ -47,7 +48,7 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
#define DROPBEAR_SMALL_CODE 1
|
||||
|
||||
/* Enable X11 Forwarding - server only */
|
||||
#define DROPBEAR_X11FWD 1
|
||||
#define DROPBEAR_X11FWD 0
|
||||
|
||||
/* Enable TCP Fowarding */
|
||||
/* 'Local' is "-L" style (client listening port forwarded via server)
|
||||
@@ -82,27 +83,36 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
* Including both AES keysize variants (128 and 256) will result in
|
||||
* a minimal size increase */
|
||||
#define DROPBEAR_AES128 1
|
||||
#define DROPBEAR_3DES 1
|
||||
#define DROPBEAR_AES256 1
|
||||
#define DROPBEAR_3DES 0
|
||||
#define DROPBEAR_TWOFISH256 0
|
||||
#define DROPBEAR_TWOFISH128 0
|
||||
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
|
||||
#define DROPBEAR_BLOWFISH 0
|
||||
|
||||
/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
|
||||
* generally faster than AES256 on CPU w/o dedicated AES instructions,
|
||||
* having the same key size. Recommended.
|
||||
* Compiling in will add ~5,5kB to binary size on x86-64 */
|
||||
#define DROPBEAR_CHACHA20POLY1305 1
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. Recommended. */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE 1
|
||||
|
||||
/* Enable CBC mode for ciphers. This has security issues though
|
||||
* is the most compatible with older SSH implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE 1
|
||||
may be required for compatibility with old implementations */
|
||||
#define DROPBEAR_ENABLE_CBC_MODE 0
|
||||
|
||||
/* Enable "Counter Mode" for ciphers. This is more secure than
|
||||
* CBC mode against certain attacks. It is recommended for security
|
||||
* and forwards compatibility */
|
||||
#define DROPBEAR_ENABLE_CTR_MODE 1
|
||||
/* Enable "Galois/Counter Mode" for ciphers. This authenticated
|
||||
* encryption mode is combination of CTR mode and GHASH. Recommended
|
||||
* for security and forwards compatibility, but slower than CTR on
|
||||
* CPU w/o dedicated AES/GHASH instructions.
|
||||
* Compiling in will add ~6kB to binary size on x86-64 */
|
||||
#define DROPBEAR_ENABLE_GCM_MODE 0
|
||||
|
||||
/* Message integrity. sha2-256 is recommended as a default,
|
||||
sha1 for compatibility */
|
||||
#define DROPBEAR_SHA1_HMAC 1
|
||||
#define DROPBEAR_SHA1_96_HMAC 1
|
||||
#define DROPBEAR_SHA2_256_HMAC 1
|
||||
#define DROPBEAR_SHA1_96_HMAC 0
|
||||
|
||||
/* Hostkey/public key algorithms - at least one required, these are used
|
||||
* for hostkey as well as for verifying signatures with pubkey auth.
|
||||
@@ -116,11 +126,17 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
* code (either ECDSA or ECDH) increases binary size - around 30kB
|
||||
* on x86-64 */
|
||||
#define DROPBEAR_ECDSA 1
|
||||
#define DROPBEAR_SK_ECDSA 1
|
||||
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
|
||||
binary size - around 7,5kB on x86-64 */
|
||||
#define DROPBEAR_ED25519 1
|
||||
#define DROPBEAR_SK_ED25519 1
|
||||
|
||||
/* RSA must be >=1024 */
|
||||
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
|
||||
/* DSS is always 1024 */
|
||||
/* ECDSA defaults to largest size configured, usually 521 */
|
||||
/* Ed25519 is always 256 */
|
||||
|
||||
/* Add runtime flag "-R" to generate hostkeys as-needed when the first
|
||||
connection using that key type occurs.
|
||||
@@ -143,7 +159,7 @@ IMPORTANT: Some options will require "make clean" after changes */
|
||||
* group14 is supported by most implementations.
|
||||
* group16 provides a greater strength level but is slower and increases binary size
|
||||
* curve25519 and ecdh algorithms are faster than non-elliptic curve methods
|
||||
* curve25519 increases binary size by ~8kB on x86-64
|
||||
* curve25519 increases binary size by ~2,5kB on x86-64
|
||||
* including either ECDH or ECDSA increases binary size by ~30kB on x86-64
|
||||
|
||||
* Small systems should generally include either curve25519 or ecdh for performance.
|
||||
@@ -174,7 +190,7 @@ group1 in Dropbear server too */
|
||||
#define DO_HOST_LOOKUP 0
|
||||
|
||||
/* Whether to print the message of the day (MOTD). */
|
||||
#define DO_MOTD 0
|
||||
#define DO_MOTD 1
|
||||
#define MOTD_FILENAME "/etc/motd"
|
||||
|
||||
/* Authentication Types - at least one required.
|
||||
@@ -196,6 +212,11 @@ group1 in Dropbear server too */
|
||||
* authorized_keys file into account */
|
||||
#define DROPBEAR_SVR_PUBKEY_OPTIONS 1
|
||||
|
||||
/* Set this to 0 if your system does not have multiple user support.
|
||||
(Linux kernel CONFIG_MULTIUSER option)
|
||||
The resulting binary will not run on a normal system. */
|
||||
#define DROPBEAR_SVR_MULTIUSER 1
|
||||
|
||||
/* Client authentication options */
|
||||
#define DROPBEAR_CLI_PASSWORD_AUTH 1
|
||||
#define DROPBEAR_CLI_PUBKEY_AUTH 1
|
||||
@@ -237,6 +258,12 @@ Homedir is prepended unless path begins with / */
|
||||
/* -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 */
|
||||
#define DROPBEAR_PIDFILE "/var/run/dropbear.pid"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "options.h"
|
||||
#include "dh_groups.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
/* diffie-hellman-group1-sha1 value for p */
|
||||
const unsigned char dh_p_1[DH_P_1_LEN] = {
|
||||
@@ -92,3 +94,4 @@ const unsigned char dh_p_16[DH_P_16_LEN] = {
|
||||
/* Same for all groups */
|
||||
const int DH_G_VAL = 2;
|
||||
|
||||
#endif /* DROPBEAR_NORMAL_DH */
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define DROPBEAR_DH_GROUPS_H
|
||||
#include "options.h"
|
||||
|
||||
#if DROPBEAR_NORMAL_DH
|
||||
|
||||
#if DROPBEAR_DH_GROUP1
|
||||
#define DH_P_1_LEN 128
|
||||
extern const unsigned char dh_p_1[DH_P_1_LEN];
|
||||
@@ -17,8 +19,8 @@ extern const unsigned char dh_p_14[DH_P_14_LEN];
|
||||
extern const unsigned char dh_p_16[DH_P_16_LEN];
|
||||
#endif
|
||||
|
||||
|
||||
extern const int DH_G_VAL;
|
||||
|
||||
#endif /* DROPBEAR_NORMAL_DH */
|
||||
|
||||
#endif
|
||||
|
||||
23
dropbear.8
23
dropbear.8
@@ -35,6 +35,12 @@ 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
|
||||
@@ -60,7 +66,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.
|
||||
@@ -86,7 +92,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
|
||||
if 0 disables keepalives. If no response is received for 3 consecutive keepalives the connection will be closed.
|
||||
of 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.
|
||||
@@ -96,7 +102,8 @@ 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.
|
||||
overrides any authorized_keys command= option. The original command is saved in the
|
||||
SSH_ORIGINAL_COMMAND environment variable (see below).
|
||||
.TP
|
||||
.B \-V
|
||||
Print the version
|
||||
@@ -107,7 +114,7 @@ Print the version
|
||||
Authorized Keys
|
||||
|
||||
~/.ssh/authorized_keys can be set up to allow remote login with a RSA,
|
||||
ECDSA, or DSS
|
||||
ECDSA, Ed25519 or DSS
|
||||
key. Each line is of the form
|
||||
.TP
|
||||
[restrictions] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIgAsp... [comment]
|
||||
@@ -133,6 +140,10 @@ 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.
|
||||
@@ -146,8 +157,8 @@ key authentication.
|
||||
Host Key Files
|
||||
|
||||
Host key files are read at startup from a standard location, by default
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
|
||||
/etc/dropbear/dropbear_ecdsa_host_key
|
||||
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key,
|
||||
/etc/dropbear/dropbear_ecdsa_host_key and /etc/dropbear/dropbear_ed25519_host_key
|
||||
|
||||
If the -r command line option is specified the default files are not loaded.
|
||||
Host key files are of the form generated by dropbearkey.
|
||||
|
||||
8
dropbear_lint.sh
Executable file
8
dropbear_lint.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
EXITCODE=0
|
||||
|
||||
# #ifdef instead of #if
|
||||
grep '#ifdef DROPBEAR' -I *.c *.h && EXITCODE=1
|
||||
|
||||
exit $EXITCODE
|
||||
@@ -13,7 +13,7 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
|
||||
.SH DESCRIPTION
|
||||
.B dropbearkey
|
||||
generates a
|
||||
\fIRSA\fR, \fIDSS\fR, or \fIECDSA\fR
|
||||
\fIRSA\fR, \fIDSS\fR, \fIECDSA\fR, or \fIEd25519\fR
|
||||
format SSH private key, and saves it to a file for the use with the
|
||||
Dropbear client or server.
|
||||
Note that
|
||||
@@ -26,6 +26,7 @@ Type of key to generate.
|
||||
Must be one of
|
||||
.I rsa
|
||||
.I ecdsa
|
||||
.I ed25519
|
||||
or
|
||||
.IR dss .
|
||||
.TP
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
* mp_int y
|
||||
* mp_int x
|
||||
*
|
||||
* Ed25519:
|
||||
* string "ssh-ed25519"
|
||||
* string k (32 bytes) + A (32 bytes)
|
||||
*
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "signkey.h"
|
||||
@@ -51,6 +55,7 @@
|
||||
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "gened25519.h"
|
||||
#include "ecdsa.h"
|
||||
#include "crypto_desc.h"
|
||||
#include "dbrandom.h"
|
||||
@@ -75,6 +80,9 @@ static void printhelp(char * progname) {
|
||||
#endif
|
||||
#if DROPBEAR_ECDSA
|
||||
" ecdsa\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" ed25519\n"
|
||||
#endif
|
||||
"-f filename Use filename for the secret key.\n"
|
||||
" ~/.ssh/id_dropbear is recommended for client keys.\n"
|
||||
@@ -94,6 +102,9 @@ static void printhelp(char * progname) {
|
||||
"521 "
|
||||
#endif
|
||||
"\n"
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
" Ed25519 has a fixed size of 256 bits\n"
|
||||
#endif
|
||||
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
|
||||
#if DEBUG_TRACE
|
||||
@@ -106,6 +117,14 @@ static void printhelp(char * progname) {
|
||||
static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
{
|
||||
switch (type) {
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
if (bits != 256) {
|
||||
dropbear_exit("Ed25519 keys have a fixed size of 256 bits\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_RSA
|
||||
case DROPBEAR_SIGNKEY_RSA:
|
||||
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
|
||||
@@ -114,7 +133,7 @@ static void check_signkey_bits(enum signkey_type type, int bits)
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef DROPEAR_DSS
|
||||
#if DROPEAR_DSS
|
||||
case DROPBEAR_SIGNKEY_DSS:
|
||||
if (bits != 1024) {
|
||||
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
|
||||
@@ -224,6 +243,12 @@ int main(int argc, char ** argv) {
|
||||
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
|
||||
}
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
if (strcmp(typetext, "ed25519") == 0)
|
||||
{
|
||||
keytype = DROPBEAR_SIGNKEY_ED25519;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_NONE) {
|
||||
fprintf(stderr, "Unknown key type '%s'\n", typetext);
|
||||
|
||||
38
dss.c
38
dss.c
@@ -73,6 +73,18 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* test 1 < g < p */
|
||||
if (mp_cmp_d(key->g, 1) != MP_GT) {
|
||||
dropbear_log(LOG_WARNING, "Bad DSS g");
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
if (mp_cmp(key->g, key->p) != MP_LT) {
|
||||
dropbear_log(LOG_WARNING, "Bad DSS g");
|
||||
ret = DROPBEAR_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
TRACE(("leave buf_get_dss_pub_key: success"))
|
||||
out:
|
||||
@@ -172,6 +184,13 @@ int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if DEBUG_DSS_VERIFY
|
||||
printmpint("dss verify p", key->p);
|
||||
printmpint("dss verify q", key->q);
|
||||
printmpint("dss verify g", key->g);
|
||||
printmpint("dss verify y", key->y);
|
||||
#endif
|
||||
|
||||
/* hash the data */
|
||||
sha1_init(&hs);
|
||||
sha1_process(&hs, data_buf->data, data_buf->len);
|
||||
@@ -181,6 +200,9 @@ int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_
|
||||
/* w = (s')-1 mod q */
|
||||
/* let val1 = s' */
|
||||
bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
|
||||
#if DEBUG_DSS_VERIFY
|
||||
printmpint("dss verify s'", &val1);
|
||||
#endif
|
||||
|
||||
if (mp_cmp(&val1, key->q) != MP_LT) {
|
||||
TRACE(("verify failed, s' >= q"))
|
||||
@@ -198,6 +220,9 @@ int buf_dss_verify(buffer* buf, const dropbear_dss_key *key, const buffer *data_
|
||||
/* u1 = ((SHA(M')w) mod q */
|
||||
/* let val1 = SHA(M') = msghash */
|
||||
bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
|
||||
#if DEBUG_DSS_VERIFY
|
||||
printmpint("dss verify r'", &val1);
|
||||
#endif
|
||||
|
||||
/* let val3 = u1 = ((SHA(M')w) mod q */
|
||||
if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
|
||||
@@ -259,6 +284,7 @@ void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *da
|
||||
unsigned char msghash[SHA1_HASH_SIZE];
|
||||
unsigned int writelen;
|
||||
unsigned int i;
|
||||
size_t written;
|
||||
DEF_MP_INT(dss_k);
|
||||
DEF_MP_INT(dss_m);
|
||||
DEF_MP_INT(dss_temp1);
|
||||
@@ -315,31 +341,31 @@ void buf_put_dss_sign(buffer* buf, const dropbear_dss_key *key, const buffer *da
|
||||
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
|
||||
buf_putint(buf, 2*SHA1_HASH_SIZE);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_r);
|
||||
writelen = mp_ubin_size(&dss_r);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_r, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_r);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
writelen = mp_unsigned_bin_size(&dss_s);
|
||||
writelen = mp_ubin_size(&dss_s);
|
||||
dropbear_assert(writelen <= SHA1_HASH_SIZE);
|
||||
/* need to pad to 160 bits with leading zeros */
|
||||
for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
|
||||
buf_putbyte(buf, 0);
|
||||
}
|
||||
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
|
||||
if (mp_to_ubin(&dss_s, buf_getwriteptr(buf, writelen), writelen, &written)
|
||||
!= MP_OKAY) {
|
||||
dropbear_exit("DSS error");
|
||||
}
|
||||
mp_clear(&dss_s);
|
||||
buf_incrwritepos(buf, writelen);
|
||||
buf_incrwritepos(buf, written);
|
||||
|
||||
mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
|
||||
&dss_m, NULL);
|
||||
|
||||
2
dss.h
2
dss.h
@@ -30,7 +30,7 @@
|
||||
|
||||
#if DROPBEAR_DSS
|
||||
|
||||
typedef struct {
|
||||
typedef struct dropbear_DSS_Key {
|
||||
|
||||
mp_int* p;
|
||||
mp_int* q;
|
||||
|
||||
4
ecc.c
4
ecc.c
@@ -166,13 +166,13 @@ ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *c
|
||||
key = new_ecc_key();
|
||||
key->dp = curve->dp;
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
if (mp_from_ubin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read x"))
|
||||
goto out;
|
||||
}
|
||||
buf_incrpos(buf, size);
|
||||
|
||||
if (mp_read_unsigned_bin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
if (mp_from_ubin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) {
|
||||
TRACE(("failed to read y"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
23
ecdsa.c
23
ecdsa.c
@@ -81,18 +81,25 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
|
||||
struct dropbear_ecc_curve **curve;
|
||||
ecc_key *new_key = NULL;
|
||||
|
||||
/* string "ecdsa-sha2-[identifier]" */
|
||||
/* string "ecdsa-sha2-[identifier]" or "sk-ecdsa-sha2-nistp256@openssh.com" */
|
||||
key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
|
||||
/* string "[identifier]" */
|
||||
identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
|
||||
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
|
||||
for (curve = dropbear_ecc_curves; *curve; curve++) {
|
||||
|
||||
2
ecdsa.h
2
ecdsa.h
@@ -16,7 +16,7 @@
|
||||
#elif DROPBEAR_ECC_521
|
||||
#define ECDSA_DEFAULT_SIZE 521
|
||||
#else
|
||||
#define ECDSA_DEFAULT_SIZE 0
|
||||
#error ECDSA cannot be enabled without enabling at least one size (256, 384, 521)
|
||||
#endif
|
||||
|
||||
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
|
||||
|
||||
193
ed25519.c
Normal file
193
ed25519.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
/* Perform Ed25519 operations on data, including reading keys, signing and
|
||||
* verification. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "buffer.h"
|
||||
#include "ssh.h"
|
||||
#include "curve25519.h"
|
||||
#include "ed25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
/* Load a public ed25519 key from a buffer, initialising the values.
|
||||
* The key will have the same format as buf_put_ed25519_key.
|
||||
* These should be freed with ed25519_key_free.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key,
|
||||
enum signkey_type expect_keytype) {
|
||||
|
||||
|
||||
unsigned int len, typelen;
|
||||
char *keytype = NULL;
|
||||
enum signkey_type buf_keytype;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
len = buf_getint(buf);
|
||||
if (len != CURVE25519_LEN || buf->len - buf->pos < len) {
|
||||
TRACE(("leave buf_get_ed25519_pub_key: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
m_burn(key->priv, CURVE25519_LEN);
|
||||
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_get_ed25519_pub_key: success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Same as buf_get_ed25519_pub_key, but reads private key at the end.
|
||||
* Loads a public and private ed25519 key from a buffer
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_get_ed25519_priv_key(buffer *buf, dropbear_ed25519_key *key) {
|
||||
|
||||
unsigned int len;
|
||||
|
||||
TRACE(("enter buf_get_ed25519_priv_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
|
||||
|
||||
len = buf_getint(buf);
|
||||
if (len != CURVE25519_LEN*2 || buf->len - buf->pos < len) {
|
||||
TRACE(("leave buf_get_ed25519_priv_key: failure"))
|
||||
return DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
memcpy(key->priv, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
memcpy(key->pub, buf_getptr(buf, CURVE25519_LEN), CURVE25519_LEN);
|
||||
buf_incrpos(buf, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_get_ed25519_priv_key: success"))
|
||||
return DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Clear and free the memory used by a public or private key */
|
||||
void ed25519_key_free(dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE2(("enter ed25519_key_free"))
|
||||
|
||||
if (key == NULL) {
|
||||
TRACE2(("leave ed25519_key_free: key == NULL"))
|
||||
return;
|
||||
}
|
||||
m_burn(key->priv, CURVE25519_LEN);
|
||||
m_free(key);
|
||||
|
||||
TRACE2(("leave ed25519_key_free"))
|
||||
}
|
||||
|
||||
/* Put the public ed25519 key into the buffer in the required format */
|
||||
void buf_put_ed25519_pub_key(buffer *buf, const dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_ed25519_pub_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putstring(buf, key->pub, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_pub_key"))
|
||||
}
|
||||
|
||||
/* Put the public and private ed25519 key into the buffer in the required format */
|
||||
void buf_put_ed25519_priv_key(buffer *buf, const dropbear_ed25519_key *key) {
|
||||
|
||||
TRACE(("enter buf_put_ed25519_priv_key"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putint(buf, CURVE25519_LEN*2);
|
||||
buf_putbytes(buf, key->priv, CURVE25519_LEN);
|
||||
buf_putbytes(buf, key->pub, CURVE25519_LEN);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_priv_key"))
|
||||
}
|
||||
|
||||
/* Sign the data presented with key, writing the signature contents
|
||||
* to the buffer */
|
||||
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
|
||||
|
||||
unsigned char s[64];
|
||||
unsigned long slen = sizeof(s);
|
||||
|
||||
TRACE(("enter buf_put_ed25519_sign"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
dropbear_ed25519_sign(data_buf->data, data_buf->len, s, &slen, key->priv, key->pub);
|
||||
buf_putstring(buf, SSH_SIGNKEY_ED25519, SSH_SIGNKEY_ED25519_LEN);
|
||||
buf_putstring(buf, s, slen);
|
||||
|
||||
TRACE(("leave buf_put_ed25519_sign"))
|
||||
}
|
||||
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
/* Verify a signature in buf, made on data by the key given.
|
||||
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
int buf_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf) {
|
||||
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
unsigned char *s;
|
||||
unsigned long slen;
|
||||
|
||||
TRACE(("enter buf_ed25519_verify"))
|
||||
dropbear_assert(key != NULL);
|
||||
|
||||
slen = buf_getint(buf);
|
||||
if (slen != 64 || buf->len - buf->pos < slen) {
|
||||
TRACE(("leave buf_ed25519_verify: bad size"))
|
||||
goto out;
|
||||
}
|
||||
s = buf_getptr(buf, slen);
|
||||
|
||||
if (dropbear_ed25519_verify(data_buf->data, data_buf->len,
|
||||
s, slen, key->pub) == 0) {
|
||||
/* signature is valid */
|
||||
TRACE(("leave buf_ed25519_verify: success!"))
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE(("leave buf_ed25519_verify: ret %d", ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_SIGNKEY_VERIFY */
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
56
ed25519.h
Normal file
56
ed25519.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_ED25519_H_
|
||||
#define DROPBEAR_ED25519_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "signkey.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
#define CURVE25519_LEN 32
|
||||
|
||||
typedef struct dropbear_ED25519_Key {
|
||||
|
||||
unsigned char priv[CURVE25519_LEN];
|
||||
unsigned char pub[CURVE25519_LEN];
|
||||
|
||||
} dropbear_ed25519_key;
|
||||
|
||||
void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const buffer *data_buf);
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
|
||||
#endif
|
||||
int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key,
|
||||
enum signkey_type expect_keytype);
|
||||
int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key);
|
||||
void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key);
|
||||
void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key);
|
||||
void ed25519_key_free(dropbear_ed25519_key *key);
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_ED25519_H_ */
|
||||
@@ -99,6 +99,10 @@ rsa.c RSA asymmetric crypto routines
|
||||
|
||||
dss.c DSS asymmetric crypto routines
|
||||
|
||||
ed25519.c Ed25519 asymmetric crypto routines
|
||||
|
||||
gened25519.c Ed25519 key generation
|
||||
|
||||
gendss.c DSS key generation
|
||||
|
||||
genrsa.c RSA key generation
|
||||
|
||||
27
fuzz-wrapfd.h
Normal file
27
fuzz-wrapfd.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#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
|
||||
};
|
||||
|
||||
// buf is a common buffer read by all wrapped FDs. doesn't take ownership of buf
|
||||
void wrapfd_setup(buffer *buf);
|
||||
void wrapfd_setseed(uint32_t seed);
|
||||
int wrapfd_new_fuzzinput(void);
|
||||
int wrapfd_new_dummy(void);
|
||||
|
||||
// called via #defines for read/write/select
|
||||
int wrapfd_read(int fd, void *out, size_t count);
|
||||
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
|
||||
114
fuzz.h
Normal file
114
fuzz.h
Normal file
@@ -0,0 +1,114 @@
|
||||
#ifndef DROPBEAR_FUZZ_H
|
||||
#define DROPBEAR_FUZZ_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if DROPBEAR_FUZZ
|
||||
|
||||
#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);
|
||||
const void* fuzz_get_algo(const algo_type *algos, const char* name);
|
||||
|
||||
// fuzzer functions that intrude into general code
|
||||
void fuzz_kex_fakealgos(void);
|
||||
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_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
|
||||
#define select(nfds, readfds, writefds, exceptfds, timeout) \
|
||||
wrapfd_select(nfds, readfds, writefds, exceptfds, timeout)
|
||||
#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 {
|
||||
int fuzzing;
|
||||
|
||||
// fuzzing input
|
||||
buffer *input;
|
||||
struct dropbear_cipher recv_cipher;
|
||||
struct dropbear_hash recv_mac;
|
||||
int wrapfds;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
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_H */
|
||||
398
fuzz/fuzz-common.c
Normal file
398
fuzz/fuzz-common.c
Normal file
@@ -0,0 +1,398 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
66
fuzz/fuzz-harness.c
Normal file
66
fuzz/fuzz-harness.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "includes.h"
|
||||
#include "buffer.h"
|
||||
#include "dbutil.h"
|
||||
|
||||
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++) {
|
||||
#if DEBUG_TRACE
|
||||
if (strcmp(argv[i], "-v") == 0) {
|
||||
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;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
/* ignore arguments */
|
||||
continue;
|
||||
}
|
||||
|
||||
char* fn = argv[i];
|
||||
buf_setlen(input, 0);
|
||||
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);
|
||||
}
|
||||
LLVMFuzzerTestOneInput(input->data, input->len);
|
||||
if (!quiet) {
|
||||
printf("Running %s twice \n", fn);
|
||||
}
|
||||
LLVMFuzzerTestOneInput(input->data, input->len);
|
||||
if (!quiet) {
|
||||
printf("Done %s\n", fn);
|
||||
}
|
||||
|
||||
/* Disable wrapfd so it won't interfere with buf_readfile() above */
|
||||
old_fuzz_wrapfds = fuzz.wrapfds;
|
||||
fuzz.wrapfds = 0;
|
||||
}
|
||||
|
||||
printf("Finished\n");
|
||||
|
||||
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;
|
||||
}
|
||||
140
fuzz/fuzz-hostkeys.c
Normal file
140
fuzz/fuzz-hostkeys.c
Normal file
@@ -0,0 +1,140 @@
|
||||
/* To be included in fuzz-common.c */
|
||||
|
||||
static unsigned char keyr[] = {
|
||||
0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00,
|
||||
0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xb1,
|
||||
0x06, 0x95, 0xc9, 0xa8, 0x38, 0xb9, 0x99, 0x91, 0xb5, 0x17, 0x39, 0xb9,
|
||||
0xfa, 0xa4, 0x49, 0xf8, 0x2a, 0x4c, 0x14, 0xbd, 0xb6, 0x85, 0xdb, 0x38,
|
||||
0x99, 0x44, 0xfa, 0xd6, 0xaa, 0x67, 0xef, 0x00, 0x75, 0x2b, 0x6a, 0x5c,
|
||||
0x1b, 0x50, 0xa8, 0x52, 0xf9, 0xa7, 0xee, 0xe2, 0xb3, 0x80, 0x38, 0x92,
|
||||
0x20, 0x86, 0x7c, 0xe5, 0x89, 0xb3, 0x06, 0xe4, 0x3b, 0xd1, 0xe2, 0x45,
|
||||
0xea, 0xc1, 0xd5, 0x8e, 0x05, 0xfb, 0x90, 0x29, 0xd9, 0x41, 0xb3, 0x05,
|
||||
0x31, 0x1e, 0xcc, 0xeb, 0x89, 0xdc, 0xd2, 0x6a, 0x99, 0x23, 0xbd, 0x7a,
|
||||
0xbe, 0x8c, 0xe3, 0x3f, 0xa1, 0xe8, 0xf5, 0xb4, 0x51, 0x40, 0xb4, 0xb1,
|
||||
0xc1, 0x16, 0x9f, 0x07, 0xbb, 0x99, 0xaa, 0x4b, 0x8f, 0x11, 0x19, 0x3c,
|
||||
0x18, 0xbd, 0x6e, 0xce, 0x14, 0x54, 0x2c, 0x16, 0x4a, 0x5f, 0x89, 0xe4,
|
||||
0x6b, 0x9f, 0x55, 0x68, 0xcc, 0x09, 0x8e, 0x4b, 0x92, 0xc8, 0x87, 0xfe,
|
||||
0x09, 0xed, 0x53, 0x6e, 0xff, 0x5f, 0x15, 0x0d, 0x19, 0x9d, 0xa6, 0x54,
|
||||
0xd2, 0xea, 0x59, 0x4f, 0xa1, 0x7c, 0xf6, 0xf5, 0x7f, 0x32, 0x23, 0xed,
|
||||
0x72, 0xa8, 0x96, 0x17, 0x87, 0x06, 0xf2, 0xc7, 0xcd, 0xda, 0x4a, 0x10,
|
||||
0xd1, 0xfd, 0xb8, 0xf1, 0xaf, 0x25, 0x55, 0x32, 0x45, 0x39, 0x95, 0xec,
|
||||
0x0c, 0xa9, 0xf0, 0x47, 0x8b, 0x66, 0xe0, 0xb7, 0xa2, 0xf6, 0x35, 0x50,
|
||||
0x27, 0xe7, 0x2f, 0x90, 0x35, 0x5b, 0xd5, 0x62, 0x19, 0xb4, 0x41, 0xd4,
|
||||
0x52, 0xe7, 0x7f, 0x97, 0xfc, 0x5b, 0x4a, 0x5b, 0x19, 0x06, 0x65, 0x2d,
|
||||
0x23, 0x29, 0x15, 0x8b, 0x05, 0xaf, 0xbe, 0xd3, 0x4a, 0x27, 0x5b, 0xc9,
|
||||
0xc0, 0xd0, 0xd2, 0xba, 0x8b, 0x00, 0x7a, 0x2f, 0x39, 0xa0, 0x13, 0xb9,
|
||||
0xe6, 0xf5, 0x4b, 0x21, 0x54, 0x57, 0xb3, 0xf9, 0x6c, 0x6f, 0xd0, 0x17,
|
||||
0xf4, 0x50, 0x9d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xf2, 0xda, 0x5f, 0xfb,
|
||||
0xe2, 0xda, 0xfc, 0xe0, 0xdf, 0x3a, 0x0e, 0x14, 0x18, 0xc1, 0xd9, 0x1f,
|
||||
0x43, 0xe3, 0x65, 0x3e, 0x07, 0xe7, 0x8d, 0xdc, 0x1d, 0x11, 0xc1, 0xd6,
|
||||
0xc0, 0xd8, 0xda, 0x53, 0xf5, 0x04, 0x73, 0x51, 0x1b, 0x26, 0xef, 0x4e,
|
||||
0xf5, 0xce, 0x3d, 0x77, 0x21, 0x94, 0xd0, 0xc7, 0xc1, 0xda, 0x19, 0x7d,
|
||||
0xf8, 0xc5, 0x4c, 0xc8, 0xee, 0x7d, 0xd1, 0xbb, 0x02, 0x90, 0x2b, 0xff,
|
||||
0x4e, 0x4d, 0xd7, 0x9d, 0x72, 0x0c, 0x60, 0x0f, 0x4b, 0x83, 0xf5, 0xc2,
|
||||
0x26, 0xd6, 0x22, 0xb8, 0x60, 0x3a, 0xf9, 0x2f, 0x92, 0x2a, 0x2e, 0x14,
|
||||
0xa7, 0x56, 0x1c, 0x56, 0x05, 0x41, 0x92, 0xac, 0xb1, 0x4e, 0x44, 0x1e,
|
||||
0x70, 0x42, 0xda, 0xc7, 0xc8, 0x9c, 0xae, 0x29, 0x2d, 0x0c, 0x3a, 0xff,
|
||||
0x9b, 0xb6, 0xad, 0xb4, 0xfb, 0x49, 0x28, 0x96, 0x74, 0xf5, 0x94, 0x74,
|
||||
0xb7, 0x40, 0x93, 0x2b, 0x34, 0x29, 0xd2, 0x8a, 0xf3, 0x99, 0xf9, 0xe9,
|
||||
0xd8, 0xcc, 0x48, 0x1d, 0x3e, 0xc1, 0x82, 0x35, 0x4f, 0xef, 0xb1, 0x81,
|
||||
0x3c, 0xe1, 0xa1, 0x03, 0x65, 0xac, 0x21, 0x21, 0x40, 0x61, 0xfb, 0xd3,
|
||||
0x54, 0xac, 0xa1, 0xf2, 0xf0, 0x61, 0xd9, 0x01, 0x4e, 0xc2, 0x28, 0xb1,
|
||||
0x7c, 0x27, 0x6e, 0x56, 0x68, 0x69, 0x8f, 0xc5, 0xfd, 0xca, 0x39, 0x6e,
|
||||
0x22, 0x09, 0xf1, 0xb4, 0xd5, 0xac, 0xb8, 0xe0, 0x1b, 0x21, 0x86, 0xf4,
|
||||
0xc8, 0x15, 0xc6, 0x1f, 0x21, 0xae, 0xcb, 0xab, 0x5a, 0x09, 0x30, 0x9e,
|
||||
0xdd, 0x6c, 0x38, 0x59, 0xec, 0x59, 0x3a, 0x08, 0xee, 0x46, 0x7b, 0x78,
|
||||
0x23, 0xbc, 0xfc, 0xe2, 0xda, 0xe8, 0x1a, 0x65, 0xe6, 0xe0, 0x78, 0xd3,
|
||||
0xb0, 0x03, 0x2e, 0xf1, 0xb8, 0xca, 0x8e, 0x90, 0x75, 0xaf, 0xf7, 0xa8,
|
||||
0x48, 0xed, 0x82, 0xc9, 0xcf, 0x44, 0x56, 0xfc, 0x05, 0xfd, 0x6b, 0x00,
|
||||
0x00, 0x00, 0x81, 0x00, 0xfc, 0x94, 0xdf, 0x42, 0xc7, 0x9a, 0xa2, 0xff,
|
||||
0x32, 0xdf, 0x06, 0xb6, 0x4d, 0x90, 0x31, 0x28, 0x28, 0xdb, 0x03, 0xf9,
|
||||
0xa6, 0xb3, 0xa2, 0x91, 0x4c, 0xdf, 0x6e, 0xf6, 0xb9, 0x44, 0x3b, 0xdd,
|
||||
0x17, 0xc1, 0xc8, 0x1d, 0xd1, 0xc0, 0xc0, 0x30, 0x22, 0xbe, 0x24, 0x2e,
|
||||
0x0e, 0xdf, 0xe0, 0x18, 0x37, 0x3e, 0xb8, 0x7f, 0xb2, 0x50, 0x34, 0xc4,
|
||||
0x08, 0x5e, 0x69, 0x1f, 0xd5, 0xc9, 0xce, 0x47, 0x7d, 0x75, 0x5e, 0x3b,
|
||||
0x87, 0xdd, 0x46, 0x35, 0x01, 0x0f, 0x17, 0x8a, 0xf1, 0xf1, 0xc4, 0xa9,
|
||||
0x94, 0xa7, 0x6e, 0xce, 0x80, 0xe3, 0x17, 0x2e, 0xb0, 0xef, 0x63, 0xa7,
|
||||
0x11, 0x86, 0x96, 0x4a, 0x63, 0x2d, 0x9e, 0x92, 0x62, 0x43, 0x43, 0x72,
|
||||
0xa5, 0xdc, 0xa0, 0xcd, 0x19, 0x93, 0xd7, 0xe0, 0x80, 0x41, 0x27, 0xea,
|
||||
0xe4, 0xe8, 0xc1, 0x91, 0x9e, 0x13, 0xb3, 0x9c, 0xd1, 0xed, 0xcb, 0xbf,
|
||||
0x00, 0x00, 0x00, 0x81, 0x00, 0xb3, 0x6b, 0xee, 0xa4, 0x70, 0x4e, 0xfb,
|
||||
0xf9, 0x7e, 0x2e, 0x74, 0x5d, 0x3e, 0x8b, 0x3f, 0xff, 0x8c, 0xde, 0x68,
|
||||
0x38, 0xda, 0xce, 0xc0, 0x66, 0x4b, 0xca, 0x35, 0xc3, 0x97, 0xa8, 0xf0,
|
||||
0x00, 0x8e, 0xb3, 0x46, 0x60, 0xd0, 0x4d, 0x7e, 0x7b, 0xdf, 0x17, 0x7b,
|
||||
0x2f, 0xc4, 0x16, 0xee, 0x45, 0xdb, 0xa5, 0x5d, 0xc0, 0x72, 0xe9, 0xc6,
|
||||
0x91, 0x0f, 0xd9, 0x30, 0x74, 0x6c, 0xde, 0x93, 0xb5, 0xb6, 0xaf, 0x52,
|
||||
0x53, 0x3c, 0x08, 0x55, 0xea, 0xb8, 0x66, 0x07, 0xbe, 0xce, 0xf9, 0x80,
|
||||
0x8d, 0xe0, 0xca, 0xdc, 0x63, 0xe8, 0x58, 0x94, 0x22, 0x4f, 0x08, 0x66,
|
||||
0x13, 0x9e, 0x63, 0x2e, 0x92, 0x7a, 0xb6, 0x66, 0x94, 0x9b, 0x71, 0x66,
|
||||
0xd3, 0x08, 0xc9, 0x89, 0xea, 0x78, 0x35, 0x0d, 0xf2, 0x25, 0x55, 0xd4,
|
||||
0xb0, 0x9b, 0xea, 0x18, 0x77, 0xf6, 0x25, 0x02, 0xb4, 0x5e, 0x71, 0xea,
|
||||
0xa3
|
||||
};
|
||||
static unsigned int keyr_len = 805;
|
||||
static unsigned char keye[] = {
|
||||
0x00, 0x00, 0x00, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x2d, 0x73, 0x68,
|
||||
0x61, 0x32, 0x2d, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
|
||||
0x00, 0x00, 0x08, 0x6e, 0x69, 0x73, 0x74, 0x70, 0x32, 0x35, 0x36, 0x00,
|
||||
0x00, 0x00, 0x41, 0x04, 0x0a, 0x00, 0x6c, 0x7c, 0x1c, 0xc4, 0x03, 0x44,
|
||||
0x46, 0x70, 0xba, 0x00, 0x7c, 0x79, 0x89, 0x7b, 0xc3, 0xd6, 0x32, 0x98,
|
||||
0x34, 0xe7, 0x1c, 0x60, 0x04, 0x73, 0xd9, 0xb5, 0x7e, 0x94, 0x04, 0x04,
|
||||
0xea, 0xc8, 0xb8, 0xfb, 0xd4, 0x70, 0x9f, 0x29, 0xa7, 0x8d, 0x9a, 0x64,
|
||||
0x3a, 0x8c, 0x45, 0x23, 0x37, 0x5a, 0x2b, 0x4f, 0x54, 0x91, 0x80, 0xf1,
|
||||
0xac, 0x3a, 0xf5, 0x6d, 0xfa, 0xe8, 0x76, 0x20, 0x00, 0x00, 0x00, 0x21,
|
||||
0x00, 0xc2, 0xaf, 0xbe, 0xdc, 0x06, 0xff, 0x3d, 0x08, 0x9b, 0x73, 0xe0,
|
||||
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[] = {
|
||||
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,
|
||||
0x30, 0xfd, 0x47, 0xb9, 0x05, 0x9e, 0x95, 0xaa, 0x37, 0x9a, 0x91, 0xbf,
|
||||
0xf8, 0xb9, 0xe0, 0x8d, 0x97, 0x49, 0x87, 0xe2, 0xe6, 0x90, 0xc1, 0xe4,
|
||||
0x61, 0x57, 0x77, 0xfd, 0x91, 0x1d, 0xe1, 0x4b, 0xa0, 0xb2, 0xbc, 0xa1,
|
||||
0x6a, 0x6a, 0xdd, 0x31, 0xda, 0xe7, 0x54, 0x03, 0xfd, 0x48, 0x62, 0x8a,
|
||||
0x1d, 0x1d, 0xe2, 0x26, 0x76, 0x29, 0x08, 0xab, 0x65, 0x88, 0x74, 0x02,
|
||||
0x1e, 0xa9, 0x29, 0x1b, 0x69, 0x3b, 0xb4, 0x5f, 0x62, 0x80, 0xa3, 0xa6,
|
||||
0x4b, 0xc3, 0x0e, 0x89, 0x24, 0xe4, 0x8a, 0x31, 0xae, 0x89, 0x7a, 0x7a,
|
||||
0x58, 0x44, 0x46, 0x77, 0x62, 0x33, 0xa2, 0x5d, 0x17, 0x0e, 0x0b, 0x64,
|
||||
0xee, 0x1a, 0x02, 0xbd, 0xf8, 0x27, 0x86, 0xe1, 0x87, 0x92, 0x84, 0xc7,
|
||||
0x00, 0x00, 0x00, 0x15, 0x00, 0xb3, 0x8b, 0x81, 0x39, 0x9c, 0xba, 0xe1,
|
||||
0x1d, 0x9a, 0x8b, 0x89, 0xb3, 0x08, 0x9b, 0x12, 0xa8, 0x7b, 0xea, 0x25,
|
||||
0x8d, 0x00, 0x00, 0x00, 0x80, 0x76, 0x3f, 0x72, 0xb2, 0xef, 0xc3, 0x16,
|
||||
0xd8, 0x09, 0x36, 0x23, 0x03, 0xf9, 0x5c, 0xac, 0x8b, 0x51, 0x35, 0x2e,
|
||||
0x36, 0xba, 0x39, 0xd0, 0x57, 0x19, 0x4f, 0x14, 0x8b, 0xea, 0x32, 0xfc,
|
||||
0x86, 0x41, 0xea, 0x85, 0x71, 0x4d, 0x52, 0x0c, 0xff, 0xc1, 0xd3, 0xd5,
|
||||
0xcd, 0x2e, 0x37, 0xcc, 0xe1, 0xcc, 0x22, 0x38, 0xa8, 0x47, 0x16, 0x34,
|
||||
0x3b, 0x32, 0x9c, 0x2f, 0x0f, 0xcd, 0x5f, 0x7f, 0x06, 0x64, 0x89, 0xc5,
|
||||
0x02, 0x4f, 0x9a, 0x70, 0x11, 0xf0, 0xaa, 0xe1, 0x7a, 0x75, 0x49, 0x8d,
|
||||
0x0f, 0x8d, 0x5b, 0x54, 0xe2, 0xe7, 0x10, 0x6e, 0xe5, 0xbd, 0xb7, 0x62,
|
||||
0xf7, 0x40, 0x59, 0x39, 0x31, 0xd9, 0x13, 0x7b, 0xa3, 0xdf, 0x0d, 0x31,
|
||||
0x52, 0x43, 0xe0, 0xaf, 0x19, 0x12, 0x15, 0x12, 0x34, 0x01, 0x6f, 0xcf,
|
||||
0x62, 0x21, 0xe4, 0xc8, 0x34, 0x69, 0xc9, 0x85, 0xe3, 0xde, 0xd7, 0x0c,
|
||||
0xac, 0x00, 0x00, 0x00, 0x80, 0x41, 0xa3, 0xc5, 0xa4, 0x89, 0x86, 0xc8,
|
||||
0x17, 0xf3, 0x8e, 0x68, 0x72, 0xbe, 0x13, 0x8b, 0x63, 0xe3, 0x07, 0xe3,
|
||||
0xd5, 0xa4, 0xa2, 0xd3, 0x2c, 0x2f, 0xbe, 0x16, 0x71, 0xc9, 0x79, 0x64,
|
||||
0x5a, 0x1e, 0x19, 0x82, 0x07, 0xe2, 0x93, 0xda, 0x22, 0xcf, 0x6d, 0xdd,
|
||||
0x38, 0xcb, 0x6e, 0x6b, 0x0f, 0x95, 0x8d, 0xfa, 0x3f, 0xbb, 0xb8, 0x6a,
|
||||
0x7d, 0xc3, 0x22, 0x1e, 0x49, 0xcf, 0x98, 0x73, 0x05, 0x5d, 0x97, 0xfa,
|
||||
0x4c, 0xf2, 0x82, 0x3d, 0x98, 0x61, 0x4e, 0x96, 0x80, 0x26, 0x79, 0xda,
|
||||
0x24, 0xf8, 0xa1, 0x9c, 0x71, 0x82, 0xe6, 0xc7, 0xdc, 0xc2, 0xa5, 0xd0,
|
||||
0xf4, 0x36, 0xba, 0xaa, 0xee, 0xd3, 0x43, 0x46, 0x1d, 0xaa, 0x53, 0xea,
|
||||
0x85, 0x2c, 0x1b, 0xc8, 0x7c, 0x3c, 0xe7, 0x06, 0x44, 0xab, 0x16, 0xad,
|
||||
0xc6, 0x54, 0x91, 0x9a, 0xb9, 0xc0, 0xeb, 0x93, 0x8c, 0xca, 0x39, 0xcf,
|
||||
0x6f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x90, 0x26, 0x0a, 0xfc, 0x15, 0x99,
|
||||
0x7b, 0xac, 0xaa, 0x0c, 0xa2, 0xca, 0x7b, 0xa8, 0xd4, 0xdf, 0x68, 0x56,
|
||||
0xf9, 0x39
|
||||
};
|
||||
static unsigned int keyd_len = 458;
|
||||
static unsigned char keyed25519[] = {
|
||||
0x00, 0x00, 0x00, 0x0b, 0x73, 0x73, 0x68, 0x2d, 0x65, 0x64, 0x32, 0x35,
|
||||
0x35, 0x31, 0x39, 0x00, 0x00, 0x00, 0x40, 0x10, 0xb3, 0x79, 0x06, 0xe5,
|
||||
0x9b, 0xe7, 0xe4, 0x6e, 0xec, 0xfe, 0xa5, 0x39, 0x21, 0x7c, 0xf6, 0x66,
|
||||
0x8c, 0x0b, 0x6a, 0x01, 0x09, 0x05, 0xc7, 0x4f, 0x64, 0xa8, 0x24, 0xd2,
|
||||
0x8d, 0xbd, 0xdd, 0xc6, 0x3c, 0x99, 0x1b, 0x2d, 0x3e, 0x33, 0x90, 0x19,
|
||||
0xa4, 0xd5, 0xe9, 0x23, 0xfe, 0x8e, 0xd6, 0xd4, 0xf9, 0xb1, 0x11, 0x69,
|
||||
0x7c, 0x57, 0x52, 0x0e, 0x41, 0xdb, 0x1b, 0x12, 0x87, 0xfa, 0xc9
|
||||
};
|
||||
static unsigned int keyed25519_len = 83;
|
||||
306
fuzz/fuzz-sshpacketmutator.c
Normal file
306
fuzz/fuzz-sshpacketmutator.c
Normal file
@@ -0,0 +1,306 @@
|
||||
/* 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;
|
||||
}
|
||||
|
||||
279
fuzz/fuzz-wrapfd.c
Normal file
279
fuzz/fuzz-wrapfd.c
Normal file
@@ -0,0 +1,279 @@
|
||||
#define FUZZ_SKIP_WRAP 1
|
||||
#include "includes.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
|
||||
#include "dbutil.h"
|
||||
|
||||
#include "fuzz.h"
|
||||
|
||||
#define IOWRAP_MAXFD (FD_SETSIZE-1)
|
||||
static const int MAX_RANDOM_IN = 50000;
|
||||
static const double CHANCE_CLOSE = 1.0 / 600;
|
||||
static const double CHANCE_INTR = 1.0 / 900;
|
||||
static const double CHANCE_READ1 = 0.96;
|
||||
static const double CHANCE_READ2 = 0.5;
|
||||
static const double CHANCE_WRITE1 = 0.96;
|
||||
static const double CHANCE_WRITE2 = 0.5;
|
||||
|
||||
struct fdwrap {
|
||||
enum wrapfd_mode mode;
|
||||
int closein;
|
||||
int closeout;
|
||||
};
|
||||
|
||||
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
|
||||
static int wrapfd_maxfd = -1;
|
||||
static unsigned short rand_state[3];
|
||||
static buffer *input_buf;
|
||||
static int devnull_fd = -1;
|
||||
|
||||
static void wrapfd_remove(int fd);
|
||||
|
||||
void wrapfd_setup(buffer *buf) {
|
||||
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;
|
||||
|
||||
memset(rand_state, 0x0, sizeof(rand_state));
|
||||
wrapfd_setseed(50);
|
||||
input_buf = buf;
|
||||
}
|
||||
|
||||
void wrapfd_setseed(uint32_t seed) {
|
||||
memcpy(rand_state, &seed, sizeof(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);
|
||||
assert(wrap_fds[fd].mode == UNUSED);
|
||||
wrap_fds[fd].mode = COMMONBUF;
|
||||
wrap_fds[fd].closein = 0;
|
||||
wrap_fds[fd].closeout = 0;
|
||||
wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
int wrapfd_close(int fd) {
|
||||
if (fd >= 0 && fd <= IOWRAP_MAXFD && wrap_fds[fd].mode != UNUSED) {
|
||||
wrapfd_remove(fd);
|
||||
return 0;
|
||||
} else {
|
||||
return close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int wrapfd_read(int fd, void *out, size_t count) {
|
||||
size_t maxread;
|
||||
|
||||
if (!fuzz.wrapfds) {
|
||||
return read(fd, out, count);
|
||||
}
|
||||
|
||||
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
|
||||
/* XXX - assertion failure? */
|
||||
TRACE(("Bad read descriptor %d\n", fd))
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(count != 0);
|
||||
|
||||
if (wrap_fds[fd].closein || erand48(rand_state) < CHANCE_CLOSE) {
|
||||
wrap_fds[fd].closein = 1;
|
||||
errno = ECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (erand48(rand_state) < CHANCE_INTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (input_buf && wrap_fds[fd].mode == COMMONBUF) {
|
||||
maxread = MIN(input_buf->len - input_buf->pos, count);
|
||||
/* returns 0 if buf is EOF, as intended */
|
||||
if (maxread > 0) {
|
||||
maxread = nrand48(rand_state) % maxread + 1;
|
||||
}
|
||||
memcpy(out, buf_getptr(input_buf, maxread), maxread);
|
||||
buf_incrpos(input_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);
|
||||
return maxread;
|
||||
}
|
||||
|
||||
int wrapfd_write(int fd, const void* in, size_t count) {
|
||||
unsigned const volatile char* volin = in;
|
||||
unsigned int i;
|
||||
|
||||
if (!fuzz.wrapfds) {
|
||||
return write(fd, in, count);
|
||||
}
|
||||
|
||||
if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode == UNUSED) {
|
||||
/* XXX - assertion failure? */
|
||||
TRACE(("Bad read descriptor %d\n", fd))
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(count != 0);
|
||||
|
||||
/* force read to exercise sanitisers */
|
||||
for (i = 0; i < count; i++) {
|
||||
(void)volin[i];
|
||||
}
|
||||
|
||||
if (wrap_fds[fd].closeout || erand48(rand_state) < CHANCE_CLOSE) {
|
||||
wrap_fds[fd].closeout = 1;
|
||||
errno = ECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (erand48(rand_state) < CHANCE_INTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nrand48(rand_state) % (count+1);
|
||||
}
|
||||
|
||||
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds, struct timeval *timeout) {
|
||||
int i, nset, sel;
|
||||
int ret = 0;
|
||||
int fdlist[IOWRAP_MAXFD+1];
|
||||
|
||||
if (!fuzz.wrapfds) {
|
||||
return select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
|
||||
assert(nfds <= IOWRAP_MAXFD+1);
|
||||
|
||||
if (erand48(rand_state) < CHANCE_INTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read */
|
||||
if (readfds != NULL && erand48(rand_state) < CHANCE_READ1) {
|
||||
for (i = 0, nset = 0; i < nfds; i++) {
|
||||
if (FD_ISSET(i, readfds)) {
|
||||
assert(wrap_fds[i].mode != UNUSED);
|
||||
fdlist[nset] = i;
|
||||
nset++;
|
||||
}
|
||||
}
|
||||
DROPBEAR_FD_ZERO(readfds);
|
||||
|
||||
if (nset > 0) {
|
||||
/* set one */
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
FD_SET(sel, readfds);
|
||||
ret++;
|
||||
|
||||
if (erand48(rand_state) < CHANCE_READ2) {
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
if (!FD_ISSET(sel, readfds)) {
|
||||
FD_SET(sel, readfds);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* write */
|
||||
if (writefds != NULL && erand48(rand_state) < CHANCE_WRITE1) {
|
||||
for (i = 0, nset = 0; i < nfds; i++) {
|
||||
if (FD_ISSET(i, writefds)) {
|
||||
assert(wrap_fds[i].mode != UNUSED);
|
||||
fdlist[nset] = i;
|
||||
nset++;
|
||||
}
|
||||
}
|
||||
DROPBEAR_FD_ZERO(writefds);
|
||||
|
||||
/* set one */
|
||||
if (nset > 0) {
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
FD_SET(sel, writefds);
|
||||
ret++;
|
||||
|
||||
if (erand48(rand_state) < CHANCE_WRITE2) {
|
||||
sel = fdlist[nrand48(rand_state) % nset];
|
||||
if (!FD_ISSET(sel, writefds)) {
|
||||
FD_SET(sel, writefds);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
6
fuzz/fuzzer-client.c
Normal file
6
fuzz/fuzzer-client.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "fuzz.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return fuzz_run_client(Data, Size, 0);
|
||||
}
|
||||
|
||||
6
fuzz/fuzzer-client_nomaths.c
Normal file
6
fuzz/fuzzer-client_nomaths.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "fuzz.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return fuzz_run_client(Data, Size, 1);
|
||||
}
|
||||
|
||||
69
fuzz/fuzzer-kexcurve25519.c
Normal file
69
fuzz/fuzzer-kexcurve25519.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "runopts.h"
|
||||
#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) {
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
|
||||
with DROPBEAR_KEX_CURVE25519 */
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Choose from the collection of curve25519 params */
|
||||
unsigned int e = buf_getint(fuzz.input);
|
||||
struct kex_curve25519_param *curve25519_param = curve25519_params[e % NUM_PARAMS];
|
||||
|
||||
buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
|
||||
|
||||
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
|
||||
kexcurve25519_comb_key(curve25519_param, ecdh_qs, svr_opts.hostkey);
|
||||
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
buf_free(ecdh_qs);
|
||||
|
||||
buf_free(ses.hash);
|
||||
buf_free(ses.session_id);
|
||||
/* kexhashbuf is freed in kexdh_comb_key */
|
||||
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
72
fuzz/fuzzer-kexdh.c
Normal file
72
fuzz/fuzzer-kexdh.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "runopts.h"
|
||||
#include "algo.h"
|
||||
#include "bignum.h"
|
||||
|
||||
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) {
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
|
||||
with DROPBEAR_KEX_NORMAL_DH */
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* Choose from the collection of ecdh params */
|
||||
unsigned int e = buf_getint(fuzz.input);
|
||||
struct kex_dh_param * dh_param = dh_params[e % NUM_PARAMS];
|
||||
|
||||
DEF_MP_INT(dh_e);
|
||||
m_mp_init(&dh_e);
|
||||
if (buf_getmpint(fuzz.input, &dh_e) != DROPBEAR_SUCCESS) {
|
||||
dropbear_exit("Bad kex value");
|
||||
}
|
||||
|
||||
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
|
||||
kexdh_comb_key(dh_param, &dh_e, svr_opts.hostkey);
|
||||
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
mp_clear(&dh_e);
|
||||
|
||||
buf_free(ses.hash);
|
||||
buf_free(ses.session_id);
|
||||
/* kexhashbuf is freed in kexdh_comb_key */
|
||||
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
82
fuzz/fuzzer-kexecdh.c
Normal file
82
fuzz/fuzzer-kexecdh.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "runopts.h"
|
||||
#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) {
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
/* Based on recv_msg_kexdh_init()/send_msg_kexdh_reply()
|
||||
with DROPBEAR_KEX_ECDH */
|
||||
ses.newkeys = keep_newkeys;
|
||||
|
||||
/* random choice of ecdh 256, 384, 521 */
|
||||
unsigned char b = buf_getbyte(fuzz.input);
|
||||
ses.newkeys->algo_kex = ecdh[b % 3];
|
||||
|
||||
/* Choose from the collection of ecdh params */
|
||||
unsigned int e = buf_getint(fuzz.input);
|
||||
struct kex_ecdh_param *ecdh_param = ecdh_params[e % NUM_PARAMS];
|
||||
|
||||
buffer * ecdh_qs = buf_getstringbuf(fuzz.input);
|
||||
|
||||
ses.kexhashbuf = buf_new(KEXHASHBUF_MAX_INTS);
|
||||
kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
|
||||
|
||||
mp_clear(ses.dh_K);
|
||||
m_free(ses.dh_K);
|
||||
buf_free(ecdh_qs);
|
||||
|
||||
buf_free(ses.hash);
|
||||
buf_free(ses.session_id);
|
||||
/* kexhashbuf is freed in kexdh_comb_key */
|
||||
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
fuzz/fuzzer-postauth_nomaths.c
Normal file
6
fuzz/fuzzer-postauth_nomaths.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "fuzz.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return fuzz_run_server(Data, Size, 1, 1);
|
||||
}
|
||||
|
||||
6
fuzz/fuzzer-preauth.c
Normal file
6
fuzz/fuzzer-preauth.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "fuzz.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return fuzz_run_server(Data, Size, 0, 0);
|
||||
}
|
||||
|
||||
6
fuzz/fuzzer-preauth_nomaths.c
Normal file
6
fuzz/fuzzer-preauth_nomaths.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "fuzz.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return fuzz_run_server(Data, Size, 1, 0);
|
||||
}
|
||||
|
||||
54
fuzz/fuzzer-pubkey.c
Normal file
54
fuzz/fuzzer-pubkey.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void setup_fuzzer(void) {
|
||||
fuzz_common_setup();
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
if (!once) {
|
||||
setup_fuzzer();
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
buffer *line = buf_getstringbuf(fuzz.input);
|
||||
buffer *keyblob = buf_getstringbuf(fuzz.input);
|
||||
|
||||
unsigned int algolen;
|
||||
char* algoname = buf_getstring(keyblob, &algolen);
|
||||
|
||||
if (signature_type_from_name(algoname, algolen) == DROPBEAR_SIGNATURE_NONE) {
|
||||
dropbear_exit("fuzzer imagined a bogus algorithm");
|
||||
}
|
||||
|
||||
int ret = fuzz_checkpubkey_line(line, 5, "/home/me/authorized_keys",
|
||||
algoname, algolen,
|
||||
keyblob->data, keyblob->len);
|
||||
|
||||
if (ret == DROPBEAR_SUCCESS) {
|
||||
/* fuzz_checkpubkey_line() should have cleaned up for failure */
|
||||
svr_pubkey_options_cleanup();
|
||||
}
|
||||
|
||||
buf_free(line);
|
||||
buf_free(keyblob);
|
||||
m_free(algoname);
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
79
fuzz/fuzzer-verify.c
Normal file
79
fuzz/fuzzer-verify.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "fuzz.h"
|
||||
#include "session.h"
|
||||
#include "fuzz-wrapfd.h"
|
||||
#include "debug.h"
|
||||
#include "dss.h"
|
||||
|
||||
static void setup_fuzzer(void) {
|
||||
fuzz_common_setup();
|
||||
}
|
||||
|
||||
static buffer *verifydata;
|
||||
|
||||
/* Tests reading a public key and verifying a signature */
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
static int once = 0;
|
||||
if (!once) {
|
||||
setup_fuzzer();
|
||||
verifydata = buf_new(30);
|
||||
buf_putstring(verifydata, "x", 1);
|
||||
once = 1;
|
||||
}
|
||||
|
||||
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_malloc_set_epoch(1);
|
||||
|
||||
if (setjmp(fuzz.jmp) == 0) {
|
||||
sign_key *key = new_sign_key();
|
||||
enum signkey_type keytype = DROPBEAR_SIGNKEY_ANY;
|
||||
if (buf_get_pub_key(fuzz.input, key, &keytype) == DROPBEAR_SUCCESS) {
|
||||
enum signature_type sigtype;
|
||||
if (keytype == DROPBEAR_SIGNKEY_RSA) {
|
||||
/* Flip a coin to decide rsa signature type */
|
||||
int flag = buf_getbyte(fuzz.input);
|
||||
if (flag & 0x01) {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA256;
|
||||
} else {
|
||||
sigtype = DROPBEAR_SIGNATURE_RSA_SHA1;
|
||||
}
|
||||
} else {
|
||||
sigtype = signature_type_from_signkey(keytype);
|
||||
}
|
||||
if (buf_verify(fuzz.input, key, sigtype, verifydata) == DROPBEAR_SUCCESS) {
|
||||
/* The fuzzer is capable of generating keys with a signature to match.
|
||||
We don't want false positives if the key is bogus, since a client/server
|
||||
wouldn't be trusting a bogus key anyway */
|
||||
int boguskey = 0;
|
||||
|
||||
if (keytype == DROPBEAR_SIGNKEY_DSS) {
|
||||
/* So far have seen dss keys with bad p/q/g domain parameters */
|
||||
int pprime, qprime, trials;
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->p));
|
||||
assert(mp_prime_is_prime(key->dsskey->p, trials, &pprime) == MP_OKAY);
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->dsskey->q));
|
||||
assert(mp_prime_is_prime(key->dsskey->q, trials, &qprime) == MP_OKAY);
|
||||
boguskey = !(pprime && qprime);
|
||||
/* Could also check g**q mod p == 1 */
|
||||
}
|
||||
|
||||
if (!boguskey) {
|
||||
printf("Random key/signature managed to verify!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
sign_key_free(key);
|
||||
m_malloc_free_epoch(1, 0);
|
||||
} else {
|
||||
m_malloc_free_epoch(1, 1);
|
||||
TRACE(("dropbear_exit longjmped"))
|
||||
/* dropbear_exit jumped here */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
14
fuzzers_test.sh
Executable file
14
fuzzers_test.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
# runs fuzz corpus with standalone fuzzers
|
||||
|
||||
result=0
|
||||
|
||||
test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://hg.ucc.asn.au/dropbear-fuzzcorpus fuzzcorpus || exit 1
|
||||
for f in `make list-fuzz-targets`; do
|
||||
# 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
|
||||
done
|
||||
|
||||
exit $result
|
||||
120
gcm.c
Normal file
120
gcm.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
#include "dbutil.h"
|
||||
#include "gcm.h"
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
|
||||
#define GHASH_LEN 16
|
||||
|
||||
static const struct dropbear_hash dropbear_ghash =
|
||||
{NULL, 0, GHASH_LEN};
|
||||
|
||||
static int dropbear_gcm_start(int cipher, const unsigned char *IV,
|
||||
const unsigned char *key, int keylen,
|
||||
int UNUSED(num_rounds), dropbear_gcm_state *state) {
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_gcm_start"))
|
||||
|
||||
if ((err = gcm_init(&state->gcm, cipher, key, keylen)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
memcpy(state->iv, IV, GCM_NONCE_LEN);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_start"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_gcm_crypt(unsigned int UNUSED(seq),
|
||||
const unsigned char *in, unsigned char *out,
|
||||
unsigned long len, unsigned long taglen,
|
||||
dropbear_gcm_state *state, int direction) {
|
||||
unsigned char *iv, tag[GHASH_LEN];
|
||||
int i, err;
|
||||
|
||||
TRACE2(("enter dropbear_gcm_crypt"))
|
||||
|
||||
if (len < 4 || taglen != GHASH_LEN) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
gcm_reset(&state->gcm);
|
||||
|
||||
if ((err = gcm_add_iv(&state->gcm,
|
||||
state->iv, GCM_NONCE_LEN)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = gcm_add_aad(&state->gcm, in, 4)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = gcm_process(&state->gcm, (unsigned char *) in + 4,
|
||||
len - 4, out + 4, direction)) != CRYPT_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (direction == LTC_ENCRYPT) {
|
||||
gcm_done(&state->gcm, out + len, &taglen);
|
||||
} else {
|
||||
gcm_done(&state->gcm, tag, &taglen);
|
||||
if (constant_time_memcmp(in + len, tag, taglen) != 0) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment invocation counter */
|
||||
iv = state->iv + GCM_IVFIX_LEN;
|
||||
for (i = GCM_IVCTR_LEN - 1; i >= 0 && ++iv[i] == 0; i--);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_crypt"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
static int dropbear_gcm_getlength(unsigned int UNUSED(seq),
|
||||
const unsigned char *in, unsigned int *outlen,
|
||||
unsigned long len, dropbear_gcm_state* UNUSED(state)) {
|
||||
TRACE2(("enter dropbear_gcm_getlength"))
|
||||
|
||||
if (len < 4) {
|
||||
return CRYPT_ERROR;
|
||||
}
|
||||
|
||||
LOAD32H(*outlen, in);
|
||||
|
||||
TRACE2(("leave dropbear_gcm_getlength"))
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
const struct dropbear_cipher_mode dropbear_mode_gcm =
|
||||
{(void *)dropbear_gcm_start, NULL, NULL,
|
||||
(void *)dropbear_gcm_crypt,
|
||||
(void *)dropbear_gcm_getlength, &dropbear_ghash};
|
||||
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
47
gcm.h
Normal file
47
gcm.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Dropbear SSH
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* Copyright (c) 2020 by Vladislav Grishenko
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_DROPBEAR_GCM_H_
|
||||
#define DROPBEAR_DROPBEAR_GCM_H_
|
||||
|
||||
#include "includes.h"
|
||||
#include "algo.h"
|
||||
|
||||
#if DROPBEAR_ENABLE_GCM_MODE
|
||||
|
||||
#define GCM_IVFIX_LEN 4
|
||||
#define GCM_IVCTR_LEN 8
|
||||
#define GCM_NONCE_LEN (GCM_IVFIX_LEN + GCM_IVCTR_LEN)
|
||||
|
||||
typedef struct {
|
||||
gcm_state gcm;
|
||||
unsigned char iv[GCM_NONCE_LEN];
|
||||
} dropbear_gcm_state;
|
||||
|
||||
extern const struct dropbear_cipher_mode dropbear_mode_gcm;
|
||||
|
||||
#endif /* DROPBEAR_ENABLE_GCM_MODE */
|
||||
|
||||
#endif /* DROPBEAR_DROPBEAR_GCM_H_ */
|
||||
13
gendss.c
13
gendss.c
@@ -68,6 +68,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
|
||||
static void getq(const dropbear_dss_key *key) {
|
||||
|
||||
unsigned char buf[QSIZE];
|
||||
int trials;
|
||||
|
||||
/* 160 bit prime */
|
||||
genrandom(buf, QSIZE);
|
||||
@@ -76,8 +77,9 @@ static void getq(const dropbear_dss_key *key) {
|
||||
|
||||
bytes_to_mp(key->q, buf, QSIZE);
|
||||
|
||||
/* 18 rounds are required according to HAC */
|
||||
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
|
||||
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->q));
|
||||
if (mp_prime_next_prime(key->q, trials, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -89,7 +91,7 @@ static void getp(const dropbear_dss_key *key, unsigned int size) {
|
||||
DEF_MP_INT(tempC);
|
||||
DEF_MP_INT(tempP);
|
||||
DEF_MP_INT(temp2q);
|
||||
int result;
|
||||
int result, trials;
|
||||
unsigned char *buf;
|
||||
|
||||
m_mp_init_multi(&tempX, &tempC, &tempP, &temp2q, NULL);
|
||||
@@ -129,9 +131,10 @@ static void getp(const dropbear_dss_key *key, unsigned int size) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* now check for prime, 5 rounds is enough according to HAC */
|
||||
/* ask FIPS 186.4 how many Rabin-Miller trials are required */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(key->p));
|
||||
/* result == 1 => p is prime */
|
||||
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
|
||||
if (mp_prime_is_prime(key->p, trials, &result) != MP_OKAY) {
|
||||
fprintf(stderr, "DSS key generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
47
gened25519.c
Normal file
47
gened25519.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "dbutil.h"
|
||||
#include "dbrandom.h"
|
||||
#include "curve25519.h"
|
||||
#include "gened25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size) {
|
||||
|
||||
dropbear_ed25519_key *key;
|
||||
|
||||
if (size != 256) {
|
||||
dropbear_exit("Ed25519 keys have a fixed size of 256 bits");
|
||||
}
|
||||
|
||||
key = m_malloc(sizeof(*key));
|
||||
dropbear_ed25519_make_key(key->pub, key->priv);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
36
gened25519.h
Normal file
36
gened25519.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Dropbear - a SSH2 server
|
||||
*
|
||||
* Copyright (c) 2002,2003 Matt Johnston
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE. */
|
||||
|
||||
#ifndef DROPBEAR_GENED25519_H_
|
||||
#define DROPBEAR_GENED25519_H_
|
||||
|
||||
#include "ed25519.h"
|
||||
|
||||
#if DROPBEAR_ED25519
|
||||
|
||||
dropbear_ed25519_key * gen_ed25519_priv_key(unsigned int size);
|
||||
|
||||
#endif /* DROPBEAR_ED25519 */
|
||||
|
||||
#endif /* DROPBEAR_GENED25519_H_ */
|
||||
11
genrsa.c
11
genrsa.c
@@ -53,10 +53,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
|
||||
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
|
||||
m_mp_init_multi(&pminus, &lcm, &qminus, NULL);
|
||||
|
||||
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
mp_set_ul(key->e, RSA_E);
|
||||
|
||||
while (1) {
|
||||
getrsaprime(key->p, &pminus, key->e, size/16);
|
||||
@@ -95,6 +92,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
mp_int* rsa_e, unsigned int size_bytes) {
|
||||
|
||||
unsigned char *buf;
|
||||
int trials;
|
||||
DEF_MP_INT(temp_gcd);
|
||||
|
||||
buf = (unsigned char*)m_malloc(size_bytes);
|
||||
@@ -108,8 +106,9 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
|
||||
|
||||
bytes_to_mp(prime, buf, size_bytes);
|
||||
|
||||
/* find the next integer which is prime, 8 round of miller-rabin */
|
||||
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
|
||||
/* find the next integer which is prime */
|
||||
trials = mp_prime_rabin_miller_trials(mp_count_bits(prime));
|
||||
if (mp_prime_next_prime(prime, trials, 0) != MP_OKAY) {
|
||||
fprintf(stderr, "RSA generation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
43
gensignkey.c
43
gensignkey.c
@@ -4,18 +4,26 @@
|
||||
#include "ecdsa.h"
|
||||
#include "genrsa.h"
|
||||
#include "gendss.h"
|
||||
#include "gened25519.h"
|
||||
#include "signkey.h"
|
||||
#include "dbrandom.h"
|
||||
|
||||
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
|
||||
static int buf_writefile(buffer * buf, const char * filename) {
|
||||
static int buf_writefile(buffer * buf, const char * filename, int skip_exist) {
|
||||
int ret = DROPBEAR_FAILURE;
|
||||
int fd = -1;
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
|
||||
filename, strerror(errno));
|
||||
/* If generating keys on connection (skip_exist) it's OK to get EEXIST
|
||||
- we probably just lost a race with another connection to generate the key */
|
||||
if (skip_exist && errno == EEXIST) {
|
||||
ret = DROPBEAR_SUCCESS;
|
||||
} else {
|
||||
dropbear_log(LOG_ERR, "Couldn't create new file %s: %s",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -68,6 +76,10 @@ static int get_default_bits(enum signkey_type keytype)
|
||||
return 384;
|
||||
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
|
||||
return 256;
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
return 256;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
@@ -118,6 +130,11 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
|
||||
*signkey_key_ptr(key, keytype) = ecckey;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if DROPBEAR_ED25519
|
||||
case DROPBEAR_SIGNKEY_ED25519:
|
||||
key->ed25519key = gen_ed25519_priv_key(bits);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
dropbear_exit("Internal error");
|
||||
@@ -134,7 +151,7 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
|
||||
|
||||
fn_temp = m_malloc(strlen(filename) + 30);
|
||||
snprintf(fn_temp, strlen(filename)+30, "%s.tmp%d", filename, getpid());
|
||||
ret = buf_writefile(buf, fn_temp);
|
||||
ret = buf_writefile(buf, fn_temp, 0);
|
||||
|
||||
if (ret == DROPBEAR_FAILURE) {
|
||||
goto out;
|
||||
@@ -144,14 +161,24 @@ int signkey_generate(enum signkey_type keytype, int bits, const char* filename,
|
||||
/* If generating keys on connection (skipexist) it's OK to get EEXIST
|
||||
- we probably just lost a race with another connection to generate the key */
|
||||
if (!(skip_exist && errno == EEXIST)) {
|
||||
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
|
||||
strerror(errno));
|
||||
/* XXX fallback to non-atomic copy for some filesystems? */
|
||||
ret = DROPBEAR_FAILURE;
|
||||
if (errno == EPERM || errno == EACCES) {
|
||||
/* Non-atomic fallback when hard-links not allowed or unsupported */
|
||||
buf_setpos(buf, 0);
|
||||
ret = buf_writefile(buf, filename, skip_exist);
|
||||
} else {
|
||||
dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", filename,
|
||||
strerror(errno));
|
||||
ret = DROPBEAR_FAILURE;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure directory update is flushed to disk, otherwise we can end up
|
||||
with zero-byte hostkey files if the power goes off */
|
||||
fsync_parent_dir(filename);
|
||||
|
||||
out:
|
||||
if (buf) {
|
||||
buf_burn(buf);
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
# Wrap all "#define X Y" with a #ifndef X...#endif"
|
||||
|
||||
sed -E 's/^( *#define ([^ ]+) .*)/#ifndef \2\
|
||||
sed 's/^\( *#define \([^ ][^ ]*\) .*\)/#ifndef \2\
|
||||
\1\
|
||||
#endif/'
|
||||
|
||||
17
includes.h
17
includes.h
@@ -25,7 +25,6 @@
|
||||
#ifndef DROPBEAR_INCLUDES_H_
|
||||
#define DROPBEAR_INCLUDES_H_
|
||||
|
||||
|
||||
#include "options.h"
|
||||
#include "debug.h"
|
||||
|
||||
@@ -56,6 +55,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#ifdef HAVE_UTMP_H
|
||||
#include <utmp.h>
|
||||
@@ -123,6 +123,10 @@
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_RANDOM_H
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
|
||||
#ifdef BUNDLED_LIBTOM
|
||||
#include "libtomcrypt/src/headers/tomcrypt.h"
|
||||
#include "libtommath/tommath.h"
|
||||
@@ -131,7 +135,6 @@
|
||||
#include <tommath.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#ifndef HAVE_U_INT8_T
|
||||
@@ -155,13 +158,23 @@ typedef unsigned int u_int32_t;
|
||||
typedef u_int32_t uint32_t;
|
||||
#endif /* HAVE_UINT32_T */
|
||||
|
||||
#ifndef SIZE_T_MAX
|
||||
#define SIZE_T_MAX ULONG_MAX
|
||||
#endif /* SIZE_T_MAX */
|
||||
|
||||
#ifdef HAVE_LINUX_PKT_SCHED_H
|
||||
#include <linux/types.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#endif
|
||||
|
||||
#if DROPBEAR_PLUGIN
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "fake-rfc2553.h"
|
||||
|
||||
#include "fuzz.h"
|
||||
|
||||
#ifndef LOG_AUTHPRIV
|
||||
#define LOG_AUTHPRIV LOG_AUTH
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user