Compare commits

...

211 Commits

Author SHA1 Message Date
Matt Johnston
cafebe2d30 Reduce sk specific code
The application id can be stored in signkey, then we don't need
to call sk-specific functions from svr-authpubkey
2022-01-22 15:45:07 +08:00
Matt Johnston
cc481a646d Make sk-ecdsa call buf_ecdsa_verify
This reduces code duplication, the SK code just handles the
different message format.
2022-01-22 14:50:42 +08:00
Egor Duda
2634c4586b fix typo 2022-01-17 20:41:56 +03:00
Egor Duda
712d529164 Keys with type sk-* make no sense as host keys, so they should be
disabled
2022-01-17 18:33:24 +03:00
Egor Duda
2ad020ff30 Implement server-side support for sk-ed25519 FIDO2-backed keys 2022-01-16 00:50:39 +03:00
Egor Duda
0c62c0db7f Check if nistp256 curve is used in sk-ecdsa-sha2- key
It's the only allowed curve per PROTOCOL.u2f specification
2021-12-24 14:26:09 +03:00
Egor Duda
2993eedaba Fix one more potential out-of-bounds read 2021-12-24 12:26:31 +03:00
Egor Duda
c66f0e98c9 Fix out-of-bounds read on normal ecdsa-sha2-[identifier] keys 2021-12-24 12:10:36 +03:00
Egor Duda
c8fcc08fe0 Implement server-side support for sk-ecdsa U2F-backed keys 2021-12-23 09:23:34 +03:00
Matt Johnston
483b427335 debugging test runner authorized_keys perms 2021-10-19 13:45:59 +08:00
Matt Johnston
27ffea3223 Debug pytest password auth failing 2021-10-19 13:30:58 +08:00
Matt Robinson
742e296115 Use HOME before /etc/passwd to find id_dropbear (#137)
Currently dbclient uses the value of HOME by default when looking for
~/.ssh/known_hosts, falling back to /etc/passwd if HOME is not set (so
that people can work around broken values in /etc/passwd).

However, when locating the default authentication key (defaults to
~/.ssh/id_dropbear), paths not starting with / are always prefixed with
the value from /etc/passwd.

Make the behaviour consistent by adjusting expand_homedir_path to use
the value of HOME, falling back to /etc/passwd if HOME is not set.
2021-10-19 13:02:47 +08:00
Matt Johnston
0e43d68d81 Remove caching and socat from build.yml
socat isn't needed and it consumes exit codes

Caching seems impossible to invalidate
2021-10-19 12:49:19 +08:00
Matt Johnston
bcb9d78d83 Add configure --enable-werror argument
This should be used instead of putting -Werror in CFLAGS
before configure, as -Werror interferes with conftests.

Update github actions to use that.
2021-10-19 12:16:20 +08:00
Matt Johnston
8da9646c83 Upload config.log on failure
Change tests to avoid double-negative for skipcheck

Skip some actions when running under act
2021-10-19 11:50:12 +08:00
Matt Johnston
da482ede60 github action workaround macos ranlib 2021-10-18 23:45:09 +08:00
Matt Johnston
f0495697e5 disable fuzzstandalone github action for now, needs debugging 2021-10-18 23:36:23 +08:00
Matt Johnston
f9ced2c880 fix github actions arguments
If only we could test this locally with the same setup....
2021-10-18 23:33:41 +08:00
Matt Johnston
17e0c7e76f github action, don't try apt or python on macos 2021-10-18 23:31:23 +08:00
Matt Johnston
30adc15860 Use sudo for the real github action job
(Wasn't required by act's runner)
2021-10-18 23:25:20 +08:00
Matt Johnston
6138bdc62f Add github actions build workflow, remove travis CI 2021-10-18 23:21:52 +08:00
Matt Johnston
e05945f67a Add a default 10 second timeout for tests 2021-10-18 23:20:32 +08:00
Matt Johnston
3e640acd17 Only redirect stderr after the session login. That lets errors
get recorded on the server parent side, rather than being sent
over a SSH connection.
2021-10-18 23:20:08 +08:00
Matt Johnston
ae25761c7c Rename "make test" to "make check". Also run lint 2021-10-18 15:17:14 +08:00
Matt Johnston
e6152ccd7d Update .hgignore and .gitignore with tests 2021-10-18 14:26:59 +08:00
Matt Johnston
8b0d31ab20 Add "make test" target to run pytest
This will create a virtualenv if required.

There is a bit of churn here reverting to autoconf 2.59 in generated
config.h.in and configure
2021-10-18 14:24:32 +08:00
Matt Johnston
65f6e48a06 Add first channel tests
These initial tests are checking various edge cases of channel handling
that have cropped up over the years.
2021-10-18 14:22:37 +08:00
Matt Johnston
a7ef149463 Bring back recently removed channel->flushing
This resolves the "sleep 10&echo hello" case which should
return immediately
2021-10-14 20:55:15 +08:00
Matt Johnston
043b0fbd1b Increase max window size to 10MB, fallback rather than
exiting if an invalid value is given.
2021-10-12 23:32:10 +08:00
Matt Johnston
110b55214b Partial strings from strtoul should return error 2021-10-12 23:31:09 +08:00
Matt Johnston
c08177a3af Banner size should account for newlines 2021-10-12 21:29:42 +08:00
Matt Johnston
3c2436cd05 Comment on reason for DROPBEAR_MAX_PASSWORD_LEN limit 2021-10-12 21:29:25 +08:00
Matt Johnston
f3b72bfd18 Merge 2021-10-11 15:46:49 +08:00
Matt Johnston
f17400e738 Replace ChanType.sepfds with Channel.bidir_fd
This handles the case where a svrchansess has separate FDs
for nopty, but a single FD for pty mode.

The use of sepfds was also previously incorrect for X11 and
agent forwarding
2021-10-11 15:42:14 +08:00
Matt Johnston
8e6f73e879 - Remove "flushing" handling for exited processes, it should be
handled by normal file descriptor reads.

- Fix sesscheckclose() handling if a channel was closed before a
  process was ever launched
2021-10-11 15:16:54 +08:00
Matt Johnston
7c2470ba3a Fix some outdated comments 2021-10-11 15:14:46 +08:00
Matt Johnston
cc59c08605 Move comment to svr_chansess_checksignal() where it belongs 2021-10-11 15:13:42 +08:00
Matt Johnston
661d8ca225 Add a comment about sending initial auth request 2021-10-11 15:12:22 +08:00
fidomax
41d4b4e7f7 keep LANG env variable for child process (#111) 2021-08-19 23:49:52 +08:00
Anton Bershanskiy
dc016f900b Remove unused argument of do_cmd() in scp.c (#125) 2021-08-19 23:40:58 +08:00
Sven Roederer
4c8c879b38 signkey: remove !! from SHA1 digest (#130)
Remove the "!!" chars from message when printing the key-fingerprint, as it's
confusing users. They have been added when switching from MD5, but SHA1 can be
considered as standard today.

Signed-off-by: Sven Roederer <devel-sven@geroedel.de>
2021-08-19 23:39:31 +08:00
Manfred Kaiser
210a983349 added option to disable trivial auth methods (#128)
* added option to disable trivial auth methods

* rename argument to match with other ssh clients

* fixed trivial auth detection for pubkeys
2021-08-19 23:37:14 +08:00
Matt Johnston
69e5709f75 Clarify help text for dropbear -e environment option 2021-08-19 23:17:34 +08:00
Roland Vollgraf
2157d52352 pass on sever process environment to child processes (option -e) (#118) 2021-08-19 23:13:41 +08:00
Matt Johnston
846d38fe43 Add "restrict" authorized_keys option 2021-05-01 20:47:15 +08:00
Matt Johnston
a8d6dac2c5 Don't include .hg_archival.txt in tarballs. They're now reproducible. 2021-03-31 23:31:26 +08:00
Matt Johnston
ee49a1b16d merge 2021-03-31 23:24:55 +08:00
Matt Johnston
325d0c1d02 Add configure script to version control. Set timezone for release tarball 2021-03-31 23:23:14 +08:00
Matt Johnston
17f209f9b7 Update config.sub and config.guess to latest 2021-03-31 23:21:30 +08:00
Matt Johnston
924d5a06a6 Make releases tarballs more deterministic
Not fully tested on different systems yet
2021-03-30 22:08:14 +08:00
Matt Johnston
1bf7acc5bd Remove some obselete autoconf bits.
Keeps autoconf 2.71 happy, though we leave the prereq version at 2.59
2021-03-30 20:42:04 +08:00
ValdikSS
8d0013bbe0 Use MAX_HOST_LEN for TCP forwarding requests (#121)
tcpip-forward request can include hostname, which is later resolved by getaddrinfo() call.
Dropbear incorrectly assumes tcpip-forward includes only IP(v4) address. Fix this.
2021-03-18 21:16:17 +08:00
Matt Johnston
9262ffe861 fuzz: don't push wrapfd descriptors larger than needed 2021-03-08 21:59:10 +08:00
Matt Johnston
1eb369272b fuzz: add -q quiet argument for standalone fuzzers.
travis has a log length limit
2021-03-07 21:26:34 +08:00
Matt Johnston
c0ed29ea02 fuzz: split long argument list with xargs 2021-03-07 16:30:33 +08:00
Matt Johnston
91ca561d7a fuzz: cifuzz fix syntax 2021-03-06 23:44:16 +08:00
Matt Johnston
ba260bd67b fuzz: try run cifuzz on push as well 2021-03-06 23:42:59 +08:00
Matt Johnston
898bff3d4e fuzz: add cifuzz for github pull requests 2021-03-06 23:34:39 +08:00
Matt Johnston
67a8de30b7 Prevent multiple shells being spawned
Existing shells would be leaked.
The old check only caught multiple commands, not shells.
2021-03-06 23:06:43 +08:00
Matt Johnston
6c571c54e5 small tidy of "signal" while loop 2021-03-06 23:05:17 +08:00
Matt Johnston
d2bfa6aedc fuzz: handle errors from wrapfd_new_dummy() 2021-03-06 22:58:57 +08:00
Matt Johnston
d0d1ede191 fuzz: fix crash in newtcpdirect(), don't close the channel too early 2021-03-05 22:51:11 +08:00
Matt Johnston
3c2f113a78 Return errstring on connect failure 2021-03-05 21:13:20 +08:00
Matt Johnston
f193e95a3e fuzz: avoid extraneous printing 2021-03-04 23:57:12 +08:00
Matt Johnston
03481aba06 Define _GNU_SOURCE properly, other header fixes
This lets -std=c89 build for gcc 8.4.0
2021-03-04 21:03:02 +08:00
Matt Johnston
8b0fdf8010 Small cleanups of netio allocated port 2021-03-04 21:02:16 +08:00
Guillaume Picquet
934cc87db3 Update netio.c (#115)
Moved allocated_lport_p and allocated_lport at begin of block to buld in C89
2021-03-04 20:50:13 +08:00
Guillaume Picquet
ae94f64145 Update cli-main.c (#114)
Moved pid_t proxy_cmd_pid declaration at begin of block to allow build in c89 (gcc-2.95)
2021-03-04 20:46:46 +08:00
Matt Johnston
8552a0e9eb Disable UNAUTH_CLOSE_DELAY by default 2021-03-02 22:20:14 +08:00
Matt Johnston
d20420e709 merge 2021-01-29 21:59:12 +08:00
Matt Johnston
e8640bdca3 fuzz: wrap kill() 2021-01-29 21:47:56 +08:00
Xenhat
e4edbf2e57 Update INSTALL (#113)
Make Git/Mercurial instructions easier to understand
2020-12-17 17:35:48 +08:00
Matt Johnston
5d60e5f312 Use buf_eatstring instead 2020-12-10 23:18:48 +08:00
Dirkjan Bussink
38d7da5fe5 Fix handling of replies to global requests (#112)
The current code assumes that all global requests want / need a reply.
This isn't always true and the request itself indicates if it wants a
reply or not.

It causes a specific problem with hostkeys-00@openssh.com messages.
These are sent by OpenSSH after authentication to inform the client of
potential other host keys for the host. This can be used to add a new
type of host key or to rotate host keys.

The initial information message from the server is sent as a global
request, but with want_reply set to false. This means that the server
doesn't expect an answer to this message. Instead the client needs to
send a prove request as a reply if it wants to receive proof of
ownership for the host keys.

The bug doesn't cause any current problems with due to how OpenSSH
treats receiving the failure message. It instead treats it as a
keepalive message and further ignores it.

Arguably this is a protocol violation though of Dropbear and it is only
accidental that it doesn't cause a problem with OpenSSH.

The bug was found when adding host keys support to libssh, which is more
strict protocol wise and treats the unexpected failure message an error,
also see https://gitlab.com/libssh/libssh-mirror/-/merge_requests/145
for more information.

The fix here is to honor the want_reply flag in the global request and
to only send a reply if the other side expects a reply.
2020-12-10 23:13:13 +08:00
Matt Johnston
a6b2eeb190 Fix null pointer dereference removing listeners 2020-12-07 20:03:24 +08:00
Matt Johnston
e12ff23e7d fuzz: add an always-failing dropbear_listen() replacement 2020-12-06 21:54:01 +08:00
Matt Johnston
007a5925dc fuzz: work around fuzz_connect_remote() limitations 2020-12-06 21:27:25 +08:00
Matt Johnston
d439ed26e4 Some minor manpage improvements 2020-12-05 14:56:53 +08:00
Matt Johnston
f9ff3fa23d fuzz: skip custom mutators with -fsanitize=memory 2020-12-05 11:54:53 +08:00
Matt Johnston
2c64335d9c fuzz: make postauth set authdone properly 2020-12-03 22:18:51 +08:00
Matt Johnston
286b6b9f80 Remove unused cli_authinitialise 2020-12-03 21:19:19 +08:00
Matt Johnston
220ba993a2 fuzzing - Set postauth user to root since that's what it runs as 2020-11-17 19:28:11 +08:00
Matt Johnston
3c88d6536a fuzzing: add workaround getpwuid/getpwnam 2020-11-16 22:44:30 +08:00
Matt Johnston
f49b576e93 Fix fuzzing build 2020-11-15 21:22:08 +08:00
Matt Johnston
8ec9016585 Add server postauth fuzzer, wrap connect_remote() 2020-11-13 23:18:05 +08:00
Matt Johnston
15ea6d1106 Remove accidentally committed abort() 2020-11-13 23:16:50 +08:00
Matt Johnston
24cfda9e3c fuzzing - fix some wrong types and -lcrypt on macos 2020-11-02 20:33:48 +08:00
Matt Johnston
121e6e6202 Fuzzing - get rid of "prefix" for streams
Improved packet generation with sshpacketmutator
2020-11-01 23:44:58 +08:00
Matt Johnston
1b6e16ae7c fuzzing - avoid sha1 for random seed every iteration 2020-11-01 14:01:37 +08:00
Matt Johnston
b8352f8164 Move fuzzer-kex initialisation into a constructor function
Hopefully this can avoid hitting AFL timeouts
https://github.com/google/oss-fuzz/pull/2474
2020-10-29 23:00:52 +08:00
Matt Johnston
6aa065b1b4 Use SSH packet mutator for preauth too
Get rid of separate client mutator.
Have 0.1% chance of llvm random mutation
Add comments
2020-10-29 22:41:37 +08:00
Matt Johnston
6cf29061c2 Fix FUZZ_NO_REPLACE_STDERR for fuzz.c 2020-10-29 22:14:38 +08:00
Matt Johnston
f92f0777de Merge from main 2020-10-29 21:51:41 +08:00
Matt Johnston
9c70e4bed1 Added signature for changeset 5879c5829e85 2020-10-29 21:40:34 +08:00
Matt Johnston
a51833c51a Added tag DROPBEAR_2020.81 for changeset 4b984c42372d 2020-10-29 21:40:27 +08:00
Matt Johnston
d852d69b50 Changelog for 2020.81 2020-10-29 21:35:50 +08:00
Matt Johnston
1b603069db Fix fuzzing stderr override on os x 2020-10-26 23:44:43 +08:00
Matt Johnston
bf4058d1df Preallocate memory for sshpacketmutator. Add fuzzer-client_mutator_nomaths 2020-10-26 23:31:24 +08:00
Matt Johnston
4d716b6302 crossover works 2020-10-26 23:06:41 +08:00
Matt Johnston
1260fbc5cd Fix fuzz-sshpacketmutator to work 2020-10-26 22:52:07 +08:00
Matt Johnston
acd6a22a0c Print ascii in printhex too 2020-10-26 22:51:44 +08:00
Matt Johnston
4e8a1da551 Add first try at fuzzing custom mutator 2020-10-25 22:52:36 +08:00
Matt Johnston
754dc50b93 merge from main 2020-10-25 21:47:42 +08:00
Matt Johnston
c7cfa75e92 Disable stderr output for fuzzer by default 2020-10-24 22:40:08 +08:00
Matt Johnston
b070bcd570 Make "Too many remote algorithms" exit rather than log
It's fatal anyway, makes logs more concise.
2020-10-24 19:28:29 +08:00
Matt Johnston
037d26f055 Add buf_decrpos() 2020-10-24 18:56:45 +08:00
Matt Johnston
cb252296c5 Add some more variation to fuzzer random number generation 2020-10-23 23:32:44 +08:00
Matt Johnston
f37def57b0 Move fuzzing code to fuzz/ subdirectory, improve Makefile.in 2020-10-23 23:10:20 +08:00
Matt Johnston
1a208c460b Increase MAX_PROPOSED_ALGO to 50, warn if exceeded 2020-10-23 20:53:58 +08:00
Matt Johnston
34f24b1841 Fix #ifdef DROPBEAR_FUZZ (caught by linter) 2020-10-21 20:49:22 +08:00
Matt Johnston
1a7b944917 Load password and key for client fuzzer.
Add fuzz_dump()
2020-10-20 23:34:38 +08:00
Matt Johnston
3b400bd64e Don't sort objects, it breaks -lcrypt ordering 2020-10-20 23:33:45 +08:00
Matt Johnston
f74baa5830 Add ubsan fuzz run to Travis CI too 2020-10-19 23:38:11 +08:00
Matt Johnston
4c5b8fb6d6 Use Dropbear's random source rather than libtommath's platform 2020-10-19 22:49:19 +08:00
Matt Johnston
d5cc5eb25c Avoid passing NULL to memcpy 2020-10-19 21:38:20 +08:00
Matt Johnston
9f642e2bd4 Fix fuzzer build 2020-10-18 23:32:39 +08:00
Matt Johnston
6ca24af24a Merge fuzz branch 2020-10-18 22:53:44 +08:00
Matt Johnston
400c7c161f Allocate real file descriptors for fuzz input with dup()
--HG--
branch : fuzz
2020-10-18 22:52:24 +08:00
Matt Johnston
5567c238a7 Disallow extra kexinit messages
--HG--
branch : fuzz
2020-10-18 22:17:54 +08:00
Matt Johnston
33eba22966 Add fuzzer-client_nomaths, fix client fuzzer
--HG--
branch : fuzz
2020-10-18 15:08:54 +08:00
Matt Johnston
282fc81981 Get client fuzzer building and starting (fails straight away)
--HG--
branch : fuzz
2020-10-18 12:17:39 +08:00
Matt Johnston
cc1b07dcf1 Make wrapfd share a common buffer for all FDs
--HG--
branch : fuzz
2020-10-15 22:46:24 +08:00
Matt Johnston
0e3e8db5bf merge from main
--HG--
branch : fuzz
2020-10-15 19:55:15 +08:00
Matt Johnston
17873e8c92 Avoid gnu extension conditional operator 2020-10-08 11:00:04 +08:00
Matt Johnston
80e9281701 Change secure.ucc.asn.au/hg to hg.ucc.asn.au 2020-07-28 18:53:48 +08:00
Matt Johnston
926c477188 Added signature for changeset 88f63b8b0f13 2020-06-26 21:57:20 +08:00
Matt Johnston
d999575e34 Added tag DROPBEAR_2020.80 for changeset 73646de50f13 2020-06-26 21:57:18 +08:00
Matt Johnston
5d095e9a27 version 2020.80 2020-06-26 21:45:59 +08:00
Guilhem Moulin
3727b099c5 Don't choke on disabled authorized_keys(5) options
As of 2020.79 X11 forwarding is disabled at build time, which could lock
out users with authorized_keys(5) files containing ‘no-X11-forwarding’
options.
2020-06-26 20:56:03 +08:00
Matt Johnston
45294b458a update CHANGES for 2020.80 2020-06-26 20:55:56 +08:00
Matt Johnston
d51e4a75cd Some notes on style 2020-06-26 20:41:34 +08:00
Matt Johnston
e9f2815144 Refer to libtom license files 2020-06-25 23:18:16 +08:00
Matt Johnston
2771fab0fa merge 2020-06-23 22:25:57 +08:00
Matt Johnston
a7a67585cb move GNU_SOURCE earlier 2020-06-23 22:24:58 +08:00
Ilya
366f01252e fix trace messages (#105) 2020-06-23 22:20:05 +08:00
Matt Johnston
1490c0c3a6 check for poly1305_init in other libtomcrypt configure test 2020-06-23 21:47:54 +08:00
Matt Johnston
3f5c106a88 _GNU_SOURCE for random 2020-06-23 21:38:46 +08:00
Matt Johnston
10e119f638 Disable toom and karatsuba for new libtommath 2020-06-18 19:12:07 +08:00
Matt Johnston
5b68d117c2 Added signature for changeset 4877afd51e04 2020-06-15 23:51:45 +08:00
Matt Johnston
58106b1615 Added tag DROPBEAR_2020.79 for changeset e2e4929d057b 2020-06-15 23:51:39 +08:00
Matt Johnston
1e10af850b can't call "make lint" without configure 2020-06-15 23:38:08 +08:00
Matt Johnston
ee4b4db816 changelog for 2020.79 2020-06-15 23:36:14 +08:00
Gabor Z. Papp
ab9cfce00d Fix "make install" for manpages in out-of-tree builds 2020-06-15 23:17:27 +08:00
Matt Johnston
2b8106b14e Add DEVELOPING.md 2020-06-15 22:30:28 +08:00
Matt Johnston
78c5daee52 Delay seedrandom until connections 2020-06-15 22:24:34 +08:00
Vladislav Grishenko
2301b6ac0b Disallow leading lines before the ident for server (#102)
Per RFC4253 4.2 clients must be able to process other lines of data
before the version string, server behavior is not defined neither
with MUST/SHOULD nor with MAY.
If server process up to 50 lines too - it may cause too long hanging
session with invalid/evil client that consume host resources and
potentially may lead to DDoS on poor embedded boxes.
Let's require first line from client to be version string and fail
early if it's not - matches both RFC and real OpenSSH behavior.
2020-06-15 21:22:18 +08:00
Matt Johnston
a27e8b053e Disable by default 3des, cbc, hmac-sha1-96, x11 forwarding 2020-06-11 00:09:15 +08:00
Matt Johnston
6145289e0d Remove blowfish 2020-06-10 23:42:42 +08:00
Matt Johnston
d14ebdbf0e avoid zero length array in base64_decode 2020-06-10 23:26:05 +08:00
Matt Johnston
4b305c5721 Merge libtomcrypt v1.18.2 2020-06-10 23:16:13 +08:00
Matt Johnston
615885be01 Fix whitespace changes vs upstream libtomcrypt 2020-06-10 23:01:33 +08:00
Vladislav Grishenko
6b823d617c Sync curve25519 license 2020-06-10 22:13:53 +08:00
Kazuo Kuroi
ec993dbdbc Set IOV_MAX for IRIX 2020-06-10 22:09:29 +08:00
Matt Johnston
ad1e9b7e3c void return types for curve25519 2020-05-30 00:05:49 +08:00
Matt Johnston
846b8cdbf7 Remove unused DEBUG_FORKGPROF 2020-05-29 23:32:19 +08:00
Vladislav Grishenko
b0243b0e7b Fix ChaCha20 on 32-bit platforms (#99)
* Fix ChaCha20 on 32-bit platforms

On 32-bit platforms with old compiler STORE64H() parameter is
not auto-expanded to 64-bit value, causing wrong IV data.
Spotted on BCM4706 MIPS32r2 with GCC 4.2.4:
	Exit before auth: Integrity error (bad packet size 2065808956)

* Fix Chacha20-Poly1305 and AES-GCM debug messages

Functions were renamed earlier and trace messages - not.
2020-05-29 21:26:22 +08:00
Matt Johnston
4faf06aae7 Don't warn when SO_PRIORITY fails 2020-05-28 23:26:34 +08:00
Matt Johnston
07d46f9907 Fix typo DROPBEAR_NORMAL_DH 2020-05-28 23:23:54 +08:00
Vladislav Grishenko
413eaf1ba1 Allow DH to be completely disabled (#97)
Reduces binary size by ~2kB by default and by 21kB with no other
libtommath functions users, ex. with curve25519 kex and ed25519
key only.
2020-05-28 23:01:48 +08:00
Matt Johnston
3b359050b4 Fix warning for unused prngd branch 2020-05-28 23:01:15 +08:00
Matt Johnston
a015cc7594 Fix indentation and add braces 2020-05-28 22:55:49 +08:00
Matt Johnston
dc12be0cfe merge 2020-05-28 22:52:01 +08:00
Matt Johnston
89e98a2f83 Use Linux getrandom() to ensure random device is initialised
Remove old code warning about random device being not ready,
/dev/random isn't used by default anyway.
2020-05-28 22:50:41 +08:00
Matt Johnston
5027bc4db1 set up early logging name 2020-05-28 22:02:33 +08:00
Matt Johnston
630f6aa6b9 initialise variable to stop warning 2020-05-28 22:02:03 +08:00
Matt Johnston
8048473eb9 Avoid oss-fuzz $SANITIZER causing wrong build
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22608
2020-05-27 20:33:45 +08:00
Matt Johnston
4216c984ae Mention libtom version requirements, check for poly1305 in libtomcrypt 2020-05-27 00:05:15 +08:00
Matt Johnston
6abf756e51 Bring back -Werror and improve travis tests 2020-05-26 23:53:50 +08:00
Steffen Jaeckel
b4bd23b4d2 Update LibTomMath to 1.2.0 (#84)
* update C files

* update other files

* update headers

* update makefiles

* remove mp_set/get_double()

* use ltm 1.2.0 API

* update ltm_desc

* use bundled tommath if system-tommath is too old

* XMALLOC etc. were changed to MP_MALLOC etc.
2020-05-26 23:36:47 +08:00
Matt Johnston
724e61f8ae try rearrange travis build matrix 2020-05-26 23:27:26 +08:00
Matt Johnston
49667a82de .travis.yml needs spaces not tabs 2020-05-26 23:16:11 +08:00
Matt Johnston
a57114e7fa update travis to Ubuntu focal to provide chacha20 2020-05-26 23:13:48 +08:00
Matt Johnston
cfe90bc6bd Fix untested rsa-sha256 change to fuzzer-verify 2020-05-26 23:13:23 +08:00
Matt Johnston
0aefec6c89 Make "dbclient -m help -c help" work 2020-05-26 20:15:39 +08:00
Matt Johnston
6a3bc73a78 fix typo 2020-05-26 20:15:00 +08:00
Matt Johnston
73aa4f0de9 Get rid of unused "none" cipher option 2020-05-26 20:05:31 +08:00
Matt Johnston
9e25854b41 cast to fix warning 2020-05-26 19:57:28 +08:00
Matt Johnston
d277f140ba merge rsa-sha256 2020-05-26 00:24:02 +08:00
Vladislav Grishenko
61267f8503 CBC mode cleanup (#95)
* Fix CBC mode can't be fully disabled

* Fix CBC mode can't be the only mode
2020-05-25 23:55:13 +08:00
Vladislav Grishenko
d3d0d60076 Add Chacha20-Poly1305, AES128-GCM and AES256-GCM support (#93)
* Add Chacha20-Poly1305 authenticated encryption

* Add general AEAD approach.
* Add chacha20-poly1305@openssh.com algo using LibTomCrypt chacha and
  poly1305 routines.

Chacha20-Poly1305 is generally faster than AES256 on CPU w/o dedicated
AES instructions, having the same key size.
Compiling in will add ~5,5kB to binary size on x86-64.

function                                             old     new   delta
chacha_crypt                                           -    1397   +1397
_poly1305_block                                        -     608    +608
poly1305_done                                          -     595    +595
dropbear_chachapoly_crypt                              -     457    +457
.rodata                                            26976   27392    +416
poly1305_process                                       -     290    +290
poly1305_init                                          -     221    +221
chacha_setup                                           -     218    +218
encrypt_packet                                      1068    1270    +202
dropbear_chachapoly_getlength                          -     147    +147
decrypt_packet                                       756     897    +141
chacha_ivctr64                                         -     137    +137
read_packet                                          543     637     +94
dropbear_chachapoly_start                              -      94     +94
read_kex_algos                                       792     880     +88
chacha_keystream                                       -      69     +69
dropbear_mode_chachapoly                               -      48     +48
sshciphers                                           280     320     +40
dropbear_mode_none                                    24      48     +24
dropbear_mode_ctr                                     24      48     +24
dropbear_mode_cbc                                     24      48     +24
dropbear_chachapoly_mac                                -      24     +24
dropbear_chachapoly                                    -      24     +24
gen_new_keys                                         848     854      +6
------------------------------------------------------------------------------
(add/remove: 14/0 grow/shrink: 10/0 up/down: 5388/0)         Total: 5388 bytes

* Add AES128-GCM and AES256-GCM authenticated encryption

* Add general AES-GCM mode.
* Add aes128-gcm@openssh.com and aes256-gcm@openssh.com algo using
  LibTomCrypt gcm routines.

AES-GCM is combination of AES CTR mode and GHASH, slower than AES-CTR on
CPU w/o dedicated AES/GHASH instructions therefore disabled by default.
Compiling in will add ~6kB to binary size on x86-64.

function                                             old     new   delta
gcm_process                                            -    1060   +1060
.rodata                                            26976   27808    +832
gcm_gf_mult                                            -     820    +820
gcm_add_aad                                            -     660    +660
gcm_shift_table                                        -     512    +512
gcm_done                                               -     471    +471
gcm_add_iv                                             -     384    +384
gcm_init                                               -     347    +347
dropbear_gcm_crypt                                     -     309    +309
encrypt_packet                                      1068    1270    +202
decrypt_packet                                       756     897    +141
gcm_reset                                              -     118    +118
read_packet                                          543     637     +94
read_kex_algos                                       792     880     +88
sshciphers                                           280     360     +80
gcm_mult_h                                             -      80     +80
dropbear_gcm_start                                     -      62     +62
dropbear_mode_gcm                                      -      48     +48
dropbear_mode_none                                    24      48     +24
dropbear_mode_ctr                                     24      48     +24
dropbear_mode_cbc                                     24      48     +24
dropbear_ghash                                         -      24     +24
dropbear_gcm_getlength                                 -      24     +24
gen_new_keys                                         848     854      +6
------------------------------------------------------------------------------
(add/remove: 14/0 grow/shrink: 10/0 up/down: 6434/0)         Total: 6434 bytes
2020-05-25 23:50:25 +08:00
Vladislav Grishenko
91e537e427 Mention Ed25519 in dropbearkey man (#94) 2020-05-25 21:28:27 +08:00
jcmathews
fb9a78c3ee Add files via upload (#90)
When SSHKeepAlive is enabled, dropbear idletimeout is not working as expected.
2020-05-25 21:02:59 +08:00
Haelwenn Monnier
8f8a3dff70 scp.c: Port OpenSSH CVE-2018-20685 fix (#80) 2020-05-25 20:54:29 +08:00
Matt Johnston
c917807b1c rsa-sha256 for ssh-agent 2020-05-25 20:23:02 +08:00
Matt Johnston
701d43b859 send and handle SSH_MSG_EXT_INFO only at the correct point
- other fixes for rsa pubkey auth
- only include ext-info handling when rsa pubkey auth is compiled
2020-05-24 14:16:58 +08:00
Matt Johnston
79bedc90a1 run linter 2020-05-24 13:34:19 +08:00
Matt Johnston
545cc62671 Add linter for #ifdef 2020-05-24 13:15:24 +08:00
Matt Johnston
331d4a714f Make server send SSH_MSG_EXT_INFO
Ensure that only valid hostkey algorithms are sent in the first kex guess
2020-05-21 23:00:22 +08:00
Matt Johnston
2a81289ed3 Make DEBUG_NOFORK a #if not #ifdef 2020-05-21 22:58:56 +08:00
Matt Johnston
5acee497bf ext-info handling for server-sig-algs
only client side is handled
2020-05-19 00:31:41 +08:00
Matt Johnston
972d723484 split signkey_type and signature_type for RSA sha1 vs sha256 2020-05-17 23:58:31 +08:00
Matt Johnston
7dc2f36c3e use sigtype where appropriate 2020-04-06 23:18:26 +08:00
Alexander Dahl
90cfbe1f7a When explicitly passing --disable-fuzz to ./configure fuzz was actually
enabled.

Signed-off-by: Alexander Dahl <ada@thorsis.com>
2020-03-27 23:23:11 +08:00
Alexander Dahl
b681570899 Update remaining advise to edit options.h
You should edit localoptions.h instead.
2020-03-10 15:38:38 +01:00
Matt Johnston
201e359363 Handle early exit when addrstring isn't set 2020-03-18 23:37:45 +08:00
Kevin Darbyshire-Bryant
fa4c4646d8 Improve address logging on early exit messages (#83)
Change 'Early exit' and 'Exit before auth' messages to include the IP
address & port as part of the message.

This allows log scanning utilities such as 'fail2ban' to obtain the
offending IP address as part of the failure event instead of extracting
the PID from the message and then scanning the log again for match
'child connection from' messages

Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
2020-03-18 23:28:56 +08:00
Matt Johnston
6f6aa9db5a merge 2020-03-14 23:33:30 +08:00
Matt Johnston
e35d0784a8 Set SSH_ORIGINAL_COMMAND for "dropbear -c" too, fix build without
DROPBEAR_SVR_PUBKEY_OPTIONS
2020-03-14 23:28:18 +08:00
Matt Johnston
cc6fa57a41 Don't log authorized_keys command= every time 2020-03-14 23:26:37 +08:00
Matt Robinson
a26ad21c0a Fallback for key gen without hard link support (#89)
Add a non-atomic fallback for key generation on platforms where link()
is not permitted (such as most stock Android installs) or on filesystems
without hard link support (such as FAT).
2020-03-14 22:37:35 +08:00
zciendor
002b79e2f9 MOTD enabled by default as the manpage says (#87)
The man page (https://github.com/mkj/dropbear/blob/master/dropbear.8) says MOTD will be printed by default for any login shell, but it was disabled at compile time. Probably happened by accident when this code was moved from `options.h` to `default_options.h`.
2020-03-14 22:21:01 +08:00
Vladislav Grishenko
3d12521735 Add Ed25519 support (#91)
* Add support for Ed25519 as a public key type

Ed25519 is a elliptic curve signature scheme that offers
better security than ECDSA and DSA and good performance. It may be
used for both user and host keys.

OpenSSH key import and fuzzer are not supported yet.

Initially inspired by Peter Szabo.

* Add curve25519 and ed25519 fuzzers

* Add import and export of Ed25519 keys
2020-03-12 00:09:45 +08:00
Matt Johnston
b2007beeb0 bring back fsync_parent_dir 2019-10-18 23:48:16 +08:00
Matt Johnston
8f123fb618 Bring back Dropbear patch to avoid setting AR/LD/RANLIB in LTM 2019-09-17 22:26:03 +08:00
Steffen Jaeckel
c71258625d Prime-related bugfixes (#81)
* Merge pull request #180 from czurnieden/isprimeerror

Fixed bug in mp_prime_isprime
(cherry picked from commit f3ff7064f3301a2fc11b84d389fd67769862d437)

* do 2 MR rounds for numbers >=2048bits

* back-port modified mp_prime_next_prime()
2019-09-17 22:11:09 +08:00
Steffen Jaeckel
615ed4e46a update ltm to 1.1.0 and enable FIPS 186.4 compliant key-generation (#79)
* make key-generation compliant to FIPS 186.4

* fix includes in tommath_class.h

* update fuzzcorpus instead of error-out

* fixup fuzzing make-targets

* update Makefile.in

* apply necessary patches to ltm sources

* clean-up not required ltm files

* update to vanilla ltm 1.1.0

this already only contains the required files

* remove set/get double
2019-09-16 21:50:38 +08:00
Matt Johnston
fa116e983b Rename EPKA -> Plugin 2019-05-15 21:59:45 +08:00
fabriziobertocci
8c6aaf8d36 External Public-Key Authentication API (#72)
* Implemented dynamic loading of an external plug-in shared library to delegate public key authentication

* Moved conditional compilation of the plugin infrastructure into the configure.ac script to be able to add -ldl to dropbear build only when the flag is enabled

* Added tags file to the ignore list

* Updated API to have the constructor to return function pointers in the pliugin instance. Added support for passing user name to the checkpubkey function. Added options to the session returned by the plugin and have dropbear to parse and process them

* Added -rdynamic to the linker flags when EPKA is enabled

* Changed the API to pass a previously created session to the checkPubKey function (created during preauth)

* Added documentation to the API

* Added parameter addrstring to plugin creation function

* Modified the API to retrieve the auth options. Instead of having them as field of the EPKASession struct, they are stored internally (plugin-dependent) in the plugin/session and retrieved through a pointer to a function (in the session)

* Changed option string to be a simple char * instead of unsigned char *
2019-05-15 21:43:57 +08:00
Matt Johnston
cae6e6af10 Added signature for changeset ebcdb893992d 2019-03-27 22:15:23 +08:00
Matt Johnston
f89c5b0390 Added tag DROPBEAR_2019.78 for changeset 009d52ae26d3 2019-03-27 22:15:10 +08:00
Thomas De Schampheleire
49177312fb Introduce extra delay before closing unauthenticated sessions
To make it harder for attackers, introduce a delay to keep an
unauthenticated session open a bit longer, thus blocking a connection
slot until after the delay.

Without this, while there is a limit on the amount of attempts an attacker
can make at the same time (MAX_UNAUTH_PER_IP), the time taken by dropbear to
handle one attempt is still short and thus for each of the allowed parallel
attempts many attempts can be chained one after the other. The attempt rate
is then:
    "MAX_UNAUTH_PER_IP / <process time of one attempt>".

With the delay, this rate becomes:
    "MAX_UNAUTH_PER_IP / UNAUTH_CLOSE_DELAY".
2017-02-15 13:53:04 +01:00
468 changed files with 27472 additions and 48270 deletions

151
.github/workflows/build.yml vendored Normal file
View 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
View 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
View File

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

View File

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

View File

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

View File

@@ -57,3 +57,7 @@ cbd674d63cd4f3781464a8d4056a5506c8ae926f DROPBEAR_2015.67
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

View File

@@ -1,66 +0,0 @@
language: c
git:
depth: 3
matrix:
include:
# subsequent matrix options use these first settings
- os: linux
compiler: gcc
env: WEXTRAFLAGS=-Werror
sudo: false
- env: MULTI=1 WEXTRAFLAGS=-Werror
# libtom has some warnings, so no WEXTRAFLAGS
- env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
- env: NOWRITEV=1 WEXTRAFLAGS=-Werror
# libtomcrypt 1.18.1 fixes clang problems, distro doesn't have that yet
- os: linux
compiler: clang
env: CONFIGURE_FLAGS=--enable-bundled-libtom WEXTRAFLAGS=""
- os: osx
compiler: clang
env: WEXTRAFLAGS=""
# Note: the fuzzing malloc wrapper doesn't replace free() in system libtomcrypt, so need bundled.
- env: DO_FUZZ=1 CONFIGURE_FLAGS="--enable-fuzz --disable-harden --enable-bundled-libtom" WEXTRAFLAGS="" LDFLAGS=-fsanitize=address EXTRACFLAGS=-fsanitize=address CXX=clang++
compiler: clang
# sanitizers need ptrace which is privileged https://github.com/travis-ci/travis-ci/issues/9033
sudo: required
# container-based builds
addons:
apt:
packages:
# packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- zlib1g-dev
- libtomcrypt-dev
- libtommath-dev
- mercurial
before_install:
- if [ "$CC" = "clang" ]; then WEXTRAFLAGS="$WEXTRAFLAGS -Wno-error=incompatible-library-redeclaration" ; fi # workaround
install:
- autoconf
- autoheader
- ./configure $CONFIGURE_FLAGS CFLAGS="-O2 -Wall -Wno-pointer-sign $WEXTRAFLAGS $EXTRACFLAGS" --prefix="$HOME/inst" || (cat config.log; exit 1)
- if [ "$NOWRITEV" = "1" ]; then sed -i -e s/HAVE_WRITEV/DONT_HAVE_WRITEV/ config.h ; fi
- make -j3
- test -z $DO_FUZZ || make fuzzstandalone
# avoid concurrent install, osx/freebsd is racey (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=208093)
- make install
script:
- ~/inst/bin/dropbearkey -t rsa -f testrsa
- ~/inst/bin/dropbearkey -t dss -f testdss
- ~/inst/bin/dropbearkey -t ecdsa -f testec256 -s 256
- ~/inst/bin/dropbearkey -t ecdsa -f testec384 -s 384
- ~/inst/bin/dropbearkey -t ecdsa -f testec521 -s 521
- test -z $DO_FUZZ || ./fuzzers_test.sh
branches:
only:
- master
- coverity

110
CHANGES
View File

@@ -1,3 +1,91 @@
2020.81 - 29 October 2020
- Fix regression in 2020.79 which prevented connecting with some SSH
implementations. Increase MAX_PROPOSED_ALGO to 50, and print a log
message if the limit is hit. This fixes interoperability with sshj
library (used by PyCharm), and GoAnywhere.
Reported by Pirmin Walthert and Piotr Jurkiewicz
- Fix building with non-GCC compilers, reported by Kazuo Kuroi
- Fix potential long delay in dbclient, found by OSS Fuzz
- Fix null pointer dereference crash, found by OSS Fuzz
- libtommath now uses the same random source as Dropbear (in 2020.79
and 2020.80 used getrandom() separately)
- Some fuzzing improvements, start of a dbclient fuzzer
2020.80 - 26 June 2020
- Don't block authorized_keys logins with no-X11-forwarding or no-agent-forwarding
restrictions when X11 or agent forwarding are disabled at compile time.
This is more of a problem now X11 is disabled by default, reported by Guilhem Moulin
- Reduce binary size by 4kB (x64) when using bundled libtommath
- Define GNU_SOURCE for getrandom() on uclibc, reported by Laurent Bercot and
Fabrice Fontaine
- Improve checking libtomcrypt version compatibility
- Add some style notes to DEVELOPING.md
2020.79 - 15 June 2020
- Support ed25519 hostkeys and authorized_keys, many thanks to Vladislav Grishenko.
This also replaces curve25519 with a TweetNaCl implementation that reduces code size.
- Add chacha20-poly1305 authenticated cipher. This will perform faster than AES
on many platforms. Thanks to Vladislav Grishenko
- Support using rsa-sha2 signatures. No changes are needed to hostkeys/authorized_keys
entries, existing RSA keys can be used with the new signature format (signatures
are ephemeral within a session). Old ssh-rsa signatures will no longer
be supported by OpenSSH in future so upgrading is recommended.
- Use getrandom() call on Linux to ensure sufficient entropy has been gathered at startup.
Dropbear now avoids reading from the random source at startup, instead waiting until
the first connection. It is possible that some platforms were running without enough
entropy previously, those could potentially block at first boot generating host keys.
The dropbear "-R" option is one way to avoid that.
- Upgrade libtomcrypt to 1.18.2 and libtommath to 1.2.0, many thanks to Steffen Jaeckel for
updating Dropbear to use the current API. Dropbear's configure script will check
for sufficient system library versions, otherwise using the bundled versions.
- CBC ciphers, 3DES, hmac-sha1-96, and x11 forwarding are now disabled by default.
They can be set in localoptions.h if required.
Blowfish has been removed.
- Support AES GCM, patch from Vladislav Grishenko. This is disabled by default,
Dropbear doesn't currently use hardware accelerated AES.
- Added an API for specifying user public keys as an authorized_keys replacement.
See pubkeyapi.h for details, thanks to Fabrizio Bertocci
- Fix idle detection clashing with keepalives, thanks to jcmathews
- Include IP addresses in more early exit messages making it easier for fail2ban
processing. Patch from Kevin Darbyshire-Bryant
- scp fix for CVE-2018-20685 where a server could modify name of output files
- SSH_ORIGINAL_COMMAND is set for "dropbear -c" forced command too
- Fix writing key files on systems without hard links, from Matt Robinson
- Compatibility fixes for IRIX from Kazuo Kuroi
- Re-enable printing MOTD by default, was lost moving from options.h. Thanks to zciendor
- Call fsync() is called on parent directory when writing key files to ensure they are flushed
- Fix "make install" for manpages in out-of-tree builds, from Gabor Z. Papp
- Some notes are added in DEVELOPING.md
2019.78 - 27 March 2019
- Fix dbclient regression in 2019.77. After exiting the terminal would be left
@@ -146,7 +234,7 @@
dropbear is running with -a (Allow connections to forwarded ports from any host)
This could potentially allow arbitrary code execution as root by an authenticated user.
Affects versions 2013.56 to 2016.74. Thanks to Mark Shepard for reporting the crash.
CVE-2017-9078 https://secure.ucc.asn.au/hg/dropbear/rev/c8114a48837c
CVE-2017-9078 https://hg.ucc.asn.au/dropbear/rev/c8114a48837c
- Security: Fix information disclosure with ~/.ssh/authorized_keys symlink.
Dropbear parsed authorized_keys as root, even if it were a symlink. The fix
@@ -158,7 +246,7 @@
contents of that file.
This information disclosure is to an already authenticated user.
Thanks to Jann Horn of Google Project Zero for reporting this.
CVE-2017-9079 https://secure.ucc.asn.au/hg/dropbear/rev/0d889b068123
CVE-2017-9079 https://hg.ucc.asn.au/dropbear/rev/0d889b068123
- Generate hostkeys with dropbearkey atomically and flush to disk with fsync
Thanks to Andrei Gherzan for a patch
@@ -178,23 +266,23 @@
run arbitrary code as the dbclient user. This could be a problem if scripts
or webpages pass untrusted input to the dbclient program.
CVE-2016-7406
https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb
https://hg.ucc.asn.au/dropbear/rev/b66a483f3dcb
- Security: dropbearconvert import of OpenSSH keys could run arbitrary code as
the local dropbearconvert user when parsing malicious key files
CVE-2016-7407
https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e
https://hg.ucc.asn.au/dropbear/rev/34e6127ef02e
- Security: dbclient could run arbitrary code as the local dbclient user if
particular -m or -c arguments are provided. This could be an issue where
dbclient is used in scripts.
CVE-2016-7408
https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6
https://hg.ucc.asn.au/dropbear/rev/eed9376a4ad6
- Security: dbclient or dropbear server could expose process memory to the
running user if compiled with DEBUG_TRACE and running with -v
CVE-2016-7409
https://secure.ucc.asn.au/hg/dropbear/rev/6a14b1f6dc04
https://hg.ucc.asn.au/dropbear/rev/6a14b1f6dc04
The security issues were reported by an anonymous researcher working with
Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html
@@ -240,7 +328,7 @@
- Validate X11 forwarding input. Could allow bypass of authorized_keys command= restrictions,
found by github.com/tintinweb. Thanks for Damien Miller for a patch. CVE-2016-3116
https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff
https://hg.ucc.asn.au/dropbear/rev/a3e8389e01ff
2015.71 - 3 December 2015
@@ -521,11 +609,11 @@ kernels, from Steve Dover
- Limit the size of decompressed payloads, avoids memory exhaustion denial
of service
Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
https://secure.ucc.asn.au/hg/dropbear/rev/0bf76f54de6f
https://hg.ucc.asn.au/dropbear/rev/0bf76f54de6f
- Avoid disclosing existence of valid users through inconsistent delays
Thanks to Logan Lamb for reporting. CVE-2013-4434
https://secure.ucc.asn.au/hg/dropbear/rev/d7784616409a
https://hg.ucc.asn.au/dropbear/rev/d7784616409a
- Update config.guess and config.sub for newer architectures
@@ -628,7 +716,7 @@ though probably will be soon
This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
Thanks to Danny Fullerton of Mantor Organization for reporting
the bug.
https://secure.ucc.asn.au/hg/dropbear/rev/818108bf7749
https://hg.ucc.asn.au/dropbear/rev/818108bf7749
- Compile fix, only apply IPV6 socket options if they are available in headers
Thanks to Gustavo Zacarias for the patch
@@ -672,7 +760,7 @@ though probably will be soon
- New version numbering scheme.
Source repository has now migrated to Mercurial at
https://secure.ucc.asn.au/hg/dropbear/graph/default
https://hg.ucc.asn.au/dropbear/graph/default
0.53.1 - Wednesday 2 March 2011

75
DEVELOPING.md Normal file
View 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.

View File

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

View File

@@ -6,12 +6,12 @@ Basic Dropbear build instructions:
localoptions.h should be located in the build directory if you are
building out of tree.
- If using a Mercurial or Git checkout, "autoconf; autoheader"
- Configure for your system:
./configure (optionally with --disable-zlib or --disable-syslog,
or --help for other options)
(you'll need to first run "autoconf; autoheader" if you edit configure.ac)
- Compile:
make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp"
@@ -28,6 +28,8 @@ Basic Dropbear build instructions:
recompile after changing the PROGRAMS list, you *MUST* "make clean" before
recompiling - bad things will happen otherwise)
DEVELOPING.md has some notes on other developer topics, including debugging.
See MULTI for instructions on making all-in-one binaries.
If you want to compile statically use ./configure --enable-static
@@ -56,7 +58,7 @@ Compiling for uClibc should be the same as normal, just set CC to the magic
uClibc toolchain compiler (ie export CC=i386-uclibc-gcc or whatever).
You can use "make STATIC=1" to make statically linked binaries, and it is
advisable to strip the binaries too. If you're looking to make a small binary,
you should remove unneeded ciphers and MD5, by editing options.h
you should remove unneeded ciphers and MD5, by editing localoptions.h
It is possible to compile zlib in, by copying zlib.h and zconf.h into a
subdirectory (ie zlibincludes), and

73
LICENSE
View File

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

View File

@@ -35,9 +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 \
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
gensignkey.o gendss.o genrsa.o gened25519.o
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
@@ -52,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
tcp-accept.o listener.o process-packet.o dh_groups.o \
common-runopts.o circbuffer.o curve25519-donna.o list.o netio.o
common-runopts.o circbuffer.o list.o netio.o chachapoly.o gcm.o
KEYOBJS=dropbearkey.o
@@ -61,10 +62,9 @@ CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
ifeq (@DROPBEAR_FUZZ@, 1)
allobjs = $(COMMONOBJS) fuzz-common.o fuzz-wrapfd.o $(CLISVROBJS) $(CLIOBJS) $(SVROBJS) @CRYPTLIB@
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))
allobjs:=$(sort $(allobjs))
dropbearobjs=$(allobjs) svr-main.o
dbclientobjs=$(allobjs) cli-main.o
@@ -72,6 +72,7 @@ ifeq (@DROPBEAR_FUZZ@, 1)
dropbearconvertobjs=$(allobjs) $(CONVERTOBJS)
# CXX only set when fuzzing
CXX=@CXX@
FUZZ_CLEAN=fuzz-clean
else
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
@@ -80,6 +81,15 @@ else
scpobjs=$(SCPOBJS)
endif
ifeq (@DROPBEAR_PLUGIN@, 1)
# rdynamic makes all the global symbols of dropbear available to all the loaded shared libraries
# this allow a plugin to reuse existing crypto/utilities like base64_decode/base64_encode without
# the need to rewrite them.
PLUGIN_LIBS=-ldl -rdynamic
else
PLUGIN_LIBS=
endif
VPATH=@srcdir@
srcdir=@srcdir@
@@ -165,7 +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
@@ -178,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))
@@ -189,7 +199,7 @@ dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@ $(PLUGIN_LIBS)
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
@@ -226,7 +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
@@ -237,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) \
@@ -252,45 +262,49 @@ 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
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-harness.o
fuzzstandalone: fuzz-harness.o fuzz-targets
fuzzstandalone: FUZZLIB=fuzz/fuzz-harness.o
fuzzstandalone: fuzz/fuzz-harness.o fuzz-targets
# exclude svr-main.o to avoid duplicate main
svrfuzzobjs=$(subst svr-main.o, ,$(dropbearobjs))
# build all the fuzzers. This will require fail to link unless built with
# make fuzz-targets FUZZLIB=-lFuzzer.a
# or similar - the library provides main().
# 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)
fuzzer-preauth: fuzzer-preauth.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
$(FUZZ_TARGETS): $(FUZZ_OBJS) $(allobjs) $(LIBTOM_DEPS)
$(CXX) $(CXXFLAGS) fuzz/$@.o $(LDFLAGS) $(allobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-preauth_nomaths: fuzzer-preauth_nomaths.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
# fuzzers that use the custom mutator - these expect a SSH network stream
MUTATOR_FUZZERS=fuzzer-client fuzzer-client_nomaths \
fuzzer-preauth fuzzer-preauth_nomaths fuzzer-postauth_nomaths
fuzzer-pubkey: fuzzer-pubkey.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-verify: fuzzer-verify.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexdh: fuzzer-kexdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
fuzzer-kexecdh: fuzzer-kexecdh.o $(HEADERS) $(LIBTOM_DEPS) Makefile $(svrfuzzobjs)
$(CXX) $(CXXFLAGS) $@.o $(LDFLAGS) $(svrfuzzobjs) -o $@$(EXEEXT) $(LIBTOM_LIBS) $(LIBS) $(FUZZLIB) @CRYPTLIB@
# 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]" > $@
@@ -302,7 +316,12 @@ 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)

1
README
View File

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

View File

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

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

1
auth.h
View File

@@ -30,7 +30,6 @@
#include "chansession.h"
void svr_authinitialise(void);
void cli_authinitialise(void);
/* Server functions */
void recv_msg_userauth_request(void);

View File

@@ -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");
}
}

View File

@@ -39,44 +39,30 @@
/* Create (malloc) a new buffer of size */
buffer* buf_new(unsigned int size) {
buffer* buf;
if (size > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
buf = (buffer*)m_malloc(sizeof(buffer)+size);
if (size > 0) {
buf->data = (unsigned char*)buf + sizeof(buffer);
} else {
buf->data = NULL;
}
buf->data = (unsigned char*)buf + sizeof(buffer);
buf->size = size;
return buf;
}
/* free the buffer's data and the buffer itself */
void buf_free(buffer* buf) {
m_free(buf);
}
/* overwrite the contents of the buffer to clear it */
void buf_burn(const buffer* buf) {
m_burn(buf->data, buf->size);
}
/* resize a buffer, pos and len will be repositioned if required when
* downsizing */
buffer* buf_resize(buffer *buf, unsigned int newsize) {
if (newsize > BUF_MAX_SIZE) {
dropbear_exit("buf->size too big");
}
@@ -139,18 +125,23 @@ void buf_incrwritepos(buffer* buf, unsigned int incr) {
}
}
/* increment the position by incr, negative values are allowed, to
* decrement the pos*/
void buf_incrpos(buffer* buf, int incr) {
/* increment the position by incr */
void buf_incrpos(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR
|| incr < -BUF_MAX_INCR
|| (unsigned int)((int)buf->pos + incr) > buf->len
|| ((int)buf->pos + incr) < 0) {
|| (buf->pos + incr) > buf->len) {
dropbear_exit("Bad buf_incrpos");
}
buf->pos += incr;
}
/* decrement the position by decr */
void buf_decrpos(buffer* buf, unsigned int decr) {
if (decr > buf->pos) {
dropbear_exit("Bad buf_decrpos");
}
buf->pos -= decr;
}
/* Get a byte from the buffer and increment the pos */
unsigned char buf_getbyte(buffer* buf) {
@@ -228,19 +219,37 @@ char* buf_getstring(buffer* buf, unsigned int *retlen) {
}
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
static buffer * buf_getstringbuf_int(buffer *buf, int incllen) {
buffer *ret = NULL;
unsigned int len = buf_getint(buf);
int extra = 0;
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
}
ret = buf_new(len);
if (incllen) {
extra = 4;
}
ret = buf_new(len+extra);
if (incllen) {
buf_putint(ret, len);
}
memcpy(buf_getwriteptr(ret, len), buf_getptr(buf, len), len);
buf_incrpos(buf, len);
buf_incrlen(ret, len);
buf_setpos(ret, 0);
return ret;
}
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
return buf_getstringbuf_int(buf, 0);
}
/* Returns a string in a new buffer, including the length */
buffer * buf_getbuf(buffer *buf) {
return buf_getstringbuf_int(buf, 1);
}
/* Just increment the buffer position the same as if we'd used buf_getstring,
* but don't bother copying/malloc()ing for it */
void buf_eatstring(buffer *buf) {
@@ -289,18 +298,18 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
/* for our purposes we only need positive (or 0) numbers, so will
* fail if we get negative numbers */
void buf_putmpint(buffer* buf, mp_int * mp) {
size_t written;
unsigned int len, pad = 0;
TRACE2(("enter buf_putmpint"))
dropbear_assert(mp != NULL);
if (SIGN(mp) == MP_NEG) {
if (mp_isneg(mp)) {
dropbear_exit("negative bignum");
}
/* zero check */
if (USED(mp) == 1 && DIGIT(mp, 0) == 0) {
if (mp_iszero(mp)) {
len = 0;
} else {
/* SSH spec requires padding for mpints with the MSB set, this code
@@ -321,10 +330,10 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
if (pad) {
buf_putbyte(buf, 0x00);
}
if (mp_to_unsigned_bin(mp, buf_getwriteptr(buf, len-pad)) != MP_OKAY) {
if (mp_to_ubin(mp, buf_getwriteptr(buf, len-pad), len-pad, &written) != MP_OKAY) {
dropbear_exit("mpint error");
}
buf_incrwritepos(buf, len-pad);
buf_incrwritepos(buf, written);
}
TRACE2(("leave buf_putmpint"))
@@ -352,7 +361,7 @@ int buf_getmpint(buffer* buf, mp_int* mp) {
return DROPBEAR_FAILURE;
}
if (mp_read_unsigned_bin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
if (mp_from_ubin(mp, buf_getptr(buf, len), len) != MP_OKAY) {
return DROPBEAR_FAILURE;
}

View File

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

View File

@@ -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,6 +71,9 @@ struct Channel {
/* whether close/eof messages have been exchanged */
int sent_close, recv_close;
int recv_eof, sent_eof;
/* once flushing is set, readfd will close once no more data is available
(not waiting for EOF) */
int flushing;
struct dropbear_progress_connection *conn_pending;
int initconn; /* used for TCP forwarding, whether the channel has been
@@ -77,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);
@@ -89,13 +93,12 @@ 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*);
/* Called to check whether a channel should close, separately from the FD being closed.
/* Called to check whether a channel should close, separately from the FD being EOF.
Used for noticing process exiting */
int (*check_close)(const struct Channel*);
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 */
@@ -104,7 +107,7 @@ struct ChanType {
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[]);

View File

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

View File

@@ -47,7 +47,6 @@
static int new_agent_chan(struct Channel * channel);
const struct ChanType cli_chan_agent = {
0, /* sepfds */
"auth-agent@openssh.com",
new_agent_chan,
NULL,
@@ -94,6 +93,7 @@ static int new_agent_chan(struct Channel * channel) {
channel->readfd = fd;
channel->writefd = fd;
channel->bidir_fd = 1;
return 0;
}
@@ -255,11 +255,12 @@ void cli_load_agent_keys(m_list *ret_list) {
}
void agent_buf_sign(buffer *sigblob, sign_key *key,
const buffer *data_buf) {
const buffer *data_buf, enum signature_type sigtype) {
buffer *request_data = NULL;
buffer *response = NULL;
unsigned int siglen;
int packet_type;
int flags = 0;
/* Request format
byte SSH2_AGENTC_SIGN_REQUEST
@@ -271,7 +272,12 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
buf_put_pub_key(request_data, key, key->type);
buf_putbufstring(request_data, data_buf);
buf_putint(request_data, 0);
#if DROPBEAR_RSA_SHA256
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
flags |= SSH_AGENT_RSA_SHA2_256;
}
#endif
buf_putint(request_data, flags);
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);

View File

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

View File

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

View File

@@ -155,7 +155,7 @@ void cli_auth_password() {
encrypt_packet();
m_burn(password, strlen(password));
cli_ses.is_trivial_auth = 0;
TRACE(("leave cli_auth_password"))
}
#endif /* DROPBEAR_CLI_PASSWORD_AUTH */

View File

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

View File

@@ -46,7 +46,6 @@ 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 */
@@ -344,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;
}
@@ -383,7 +383,6 @@ static int cli_initchansess(struct Channel *channel) {
#if DROPBEAR_CLI_NETCAT
static const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_netcat, /* inithandler */
NULL,

View File

@@ -46,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"))
}

View File

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

View File

@@ -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;
@@ -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,6 +887,7 @@ static void add_extendedopt(const char* origstr) {
#if DROPBEAR_CLI_ANYTCPFWD
"\tExitOnForwardFailure\n"
#endif
"\tDisableTrivialAuth\n"
#ifndef DISABLE_SYSLOG
"\tUseSyslog\n"
#endif
@@ -915,5 +915,10 @@ static void add_extendedopt(const char* origstr) {
return;
}
if (match_extendedopt(&optstr, "DisableTrivialAuth") == DROPBEAR_SUCCESS) {
cli_opts.disable_trivial_auth = parse_flag_value(optstr);
return;
}
dropbear_log(LOG_WARNING, "Ignoring unknown configuration option '%s'", origstr);
}

View File

@@ -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,12 +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_finised()"))
TRACE(("cli_finished()"))
session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
@@ -400,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);
}

View File

@@ -35,7 +35,6 @@
static int newtcpforwarded(struct Channel * channel);
const struct ChanType cli_chan_tcpremote = {
1, /* sepfds */
"forwarded-tcpip",
newtcpforwarded,
NULL,
@@ -51,7 +50,6 @@ 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,
@@ -273,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:

View File

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

View File

@@ -154,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;
@@ -284,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->sent_close
&& channel->type->check_close
&& channel->type->check_close(channel))
{
channel->flushing = 1;
}
/* if a type-specific check_close is defined we will only exit
once that has been triggered. this is only used for a server "session"
channel, to ensure that the shell has exited (and the exit status
channel, to ensure that the shell has exited (and the exit status
retrieved) before we close things up. */
if (!channel->type->check_close
if (!channel->type->check_close
|| channel->sent_close
|| channel->type->check_close(channel)) {
close_allowed = 1;
}
/* In flushing mode we close FDs as soon as pipes are empty.
This is used to drain out FDs when the process exits, in the case
where the FD doesn't have EOF - "sleep 10&echo hello" case */
if (channel->flushing) {
if (channel->readfd >= 0 && !fd_read_pending(channel->readfd)) {
close_chan_fd(channel, channel->readfd, SHUT_RD);
}
if (ERRFD_IS_READ(channel)
&& channel->errfd >= 0 && !fd_read_pending(channel->errfd)) {
close_chan_fd(channel, channel->errfd, SHUT_RD);
}
}
if (channel->recv_close && !write_pending(channel) && close_allowed) {
if (!channel->sent_close) {
TRACE(("Sending MSG_CHANNEL_CLOSE in response to same."))
@@ -317,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
@@ -356,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"))
@@ -365,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);
@@ -373,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))
}
}
@@ -780,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"))
}
@@ -1073,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) {
@@ -1103,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);
@@ -1136,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;
@@ -1152,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() {

View File

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

View File

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

View File

@@ -147,6 +147,10 @@ void common_session_init(int sock_in, int sock_out) {
ses.allowprivport = 0;
#if DROPBEAR_PLUGIN
ses.plugin_session = NULL;
#endif
TRACE(("leave session_init"))
}
@@ -366,8 +370,11 @@ static void read_session_identification() {
int len = 0;
char done = 0;
int i;
/* If they send more than 50 lines, something is wrong */
for (i = 0; i < 50; i++) {
/* Servers may send other lines of data before sending the
* version string, client must be able to process such lines.
* If they send more than 50 lines, something is wrong */
for (i = IS_DROPBEAR_CLIENT ? 50 : 1; i > 0; i--) {
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
if (len < 0 && errno != EINTR) {
@@ -458,6 +465,11 @@ static int ident_readln(int fd, char* buf, int count) {
TRACE(("leave ident_readln: EOF"))
return -1;
}
#if DROPBEAR_FUZZ
fuzz_dump(&in, 1);
#endif
if (in == '\n') {
/* end of ident string */
break;

373
config.guess vendored
View File

@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2019 Free Software Foundation, Inc.
# Copyright 1992-2021 Free Software Foundation, Inc.
timestamp='2019-03-04'
timestamp='2021-01-25'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -27,12 +27,12 @@ timestamp='2019-03-04'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
#
# Please send patches to <config-patches@gnu.org>.
me=`echo "$0" | sed -e 's,.*/,,'`
me=$(echo "$0" | sed -e 's,.*/,,')
usage="\
Usage: $0 [OPTION]
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2019 Free Software Foundation, Inc.
Copyright 1992-2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -99,9 +99,11 @@ tmp=
trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
set_cc_for_build() {
# prevent multiple calls if $tmp is already set
test "$tmp" && return 0
: "${TMPDIR=/tmp}"
# shellcheck disable=SC2039
{ tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
@@ -129,16 +131,14 @@ if test -f /.attbin/uname ; then
PATH=$PATH:/.attbin ; export PATH
fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown
UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown
UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown
UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown
case "$UNAME_SYSTEM" in
Linux|GNU|GNU/*)
# If the system lacks a compiler, then just pick glibc.
# We could probably try harder.
LIBC=gnu
LIBC=unknown
set_cc_for_build
cat <<-EOF > "$dummy.c"
@@ -147,17 +147,29 @@ Linux|GNU|GNU/*)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
#else
#elif defined(__GLIBC__)
LIBC=gnu
#else
#include <stdarg.h>
/* First heuristic to detect musl libc. */
#ifdef __DEFINED_va_list
LIBC=musl
#endif
#endif
EOF
eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')"
# If ldd exists, use it to detect musl libc.
if command -v ldd >/dev/null && \
ldd --version 2>&1 | grep -q ^musl
then
LIBC=musl
# Second heuristic to detect musl libc.
if [ "$LIBC" = unknown ] &&
command -v ldd >/dev/null &&
ldd --version 2>&1 | grep -q ^musl; then
LIBC=musl
fi
# If the system lacks a compiler, then just pick glibc.
# We could probably try harder.
if [ "$LIBC" = unknown ]; then
LIBC=gnu
fi
;;
esac
@@ -176,20 +188,20 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
#
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
"/sbin/$sysctl" 2>/dev/null || \
"/usr/sbin/$sysctl" 2>/dev/null || \
echo unknown)`
UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
/usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
echo unknown))
case "$UNAME_MACHINE_ARCH" in
aarch64eb) machine=aarch64_be-unknown ;;
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
earmv*)
arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,')
endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p')
machine="${arch}${endian}"-unknown
;;
*) machine="$UNAME_MACHINE_ARCH"-unknown ;;
@@ -220,7 +232,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
case "$UNAME_MACHINE_ARCH" in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr")
;;
esac
# The OS release
@@ -233,7 +245,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
release='-gnu'
;;
*)
release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2)
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
@@ -242,15 +254,15 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
echo "$machine-${os}${release}${abi-}"
exit ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')
echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
exit ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')
echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
exit ;;
*:LibertyBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//')
echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
exit ;;
*:MidnightBSD:*:*)
@@ -262,6 +274,9 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
*:SolidBSD:*:*)
echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
exit ;;
*:OS108:*:*)
echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
exit ;;
macppc:MirBSD:*:*)
echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
exit ;;
@@ -271,26 +286,29 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
*:Sortix:*:*)
echo "$UNAME_MACHINE"-unknown-sortix
exit ;;
*:Twizzler:*:*)
echo "$UNAME_MACHINE"-unknown-twizzler
exit ;;
*:Redox:*:*)
echo "$UNAME_MACHINE"-unknown-redox
exit ;;
mips:OSF1:*.*)
echo mips-dec-osf1
exit ;;
echo mips-dec-osf1
exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')
;;
*5.*)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1)
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
UNAME_MACHINE=alpha ;;
@@ -328,7 +346,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)"
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
@@ -362,7 +380,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
exit ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
if test "`(/bin/universe) 2>/dev/null`" = att ; then
if test "$( (/bin/universe) 2>/dev/null)" = att ; then
echo pyramid-pyramid-sysv3
else
echo pyramid-pyramid-bsd
@@ -375,17 +393,17 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
echo sparc-icl-nx6
exit ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
case `/usr/bin/uname -p` in
case $(/usr/bin/uname -p) in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
s390x:SunOS:*:*)
echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
exit ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
exit ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
echo i386-pc-auroraux"$UNAME_RELEASE"
@@ -396,7 +414,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
@@ -404,30 +422,30 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
SUN_ARCH=x86_64
fi
fi
echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
case "$(/usr/bin/arch -k)" in
Series*|S4*)
UNAME_RELEASE=`uname -v`
UNAME_RELEASE=$(uname -v)
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')"
exit ;;
sun3*:SunOS:*:*)
echo m68k-sun-sunos"$UNAME_RELEASE"
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null)
test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
case "`/bin/arch`" in
case "$(/bin/arch)" in
sun3)
echo m68k-sun-sunos"$UNAME_RELEASE"
;;
@@ -507,8 +525,8 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
}
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') &&
SYSTEM_NAME=$("$dummy" "$dummyarg") &&
{ echo "$SYSTEM_NAME"; exit; }
echo mips-mips-riscos"$UNAME_RELEASE"
exit ;;
@@ -535,11 +553,11 @@ EOF
exit ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
UNAME_PROCESSOR=$(/usr/bin/uname -p)
if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
then
if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
[ "$TARGET_BINARY_INTERFACE"x = x ]
if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
test "$TARGET_BINARY_INTERFACE"x = x
then
echo m88k-dg-dgux"$UNAME_RELEASE"
else
@@ -563,17 +581,17 @@ EOF
echo m68k-tektronix-bsd
exit ;;
*:IRIX*:*:*)
echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')"
exit ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX '
i*86:AIX:*:*)
echo i386-ibm-aix
exit ;;
ia64:AIX:*:*)
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
if test -x /usr/bin/oslevel ; then
IBM_REV=$(/usr/bin/oslevel)
else
IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
@@ -593,7 +611,7 @@ EOF
exit(0);
}
EOF
if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy")
then
echo "$SYSTEM_NAME"
else
@@ -606,15 +624,15 @@ EOF
fi
exit ;;
*:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }')
if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
if [ -x /usr/bin/lslpp ] ; then
IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
if test -x /usr/bin/lslpp ; then
IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)
else
IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
@@ -642,14 +660,14 @@ EOF
echo m68k-hp-bsd4.4
exit ;;
9000/[34678]??:HP-UX:*:*)
HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
case "$UNAME_MACHINE" in
9000/31?) HP_ARCH=m68000 ;;
9000/[34]??) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
if test -x /usr/bin/getconf; then
sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null)
sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null)
case "$sc_cpu_version" in
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
@@ -661,7 +679,7 @@ EOF
esac ;;
esac
fi
if [ "$HP_ARCH" = "" ]; then
if test "$HP_ARCH" = ""; then
set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
@@ -696,11 +714,11 @@ EOF
exit (0);
}
EOF
(CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
(CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy")
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
if [ "$HP_ARCH" = hppa2.0w ]
if test "$HP_ARCH" = hppa2.0w
then
set_cc_for_build
@@ -724,7 +742,7 @@ EOF
echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
exit ;;
ia64:HP-UX:*:*)
HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
echo ia64-hp-hpux"$HPUX_REV"
exit ;;
3050*:HI-UX:*:*)
@@ -754,7 +772,7 @@ EOF
exit (0);
}
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") &&
{ echo "$SYSTEM_NAME"; exit; }
echo unknown-hitachi-hiuxwe2
exit ;;
@@ -774,7 +792,7 @@ EOF
echo hppa1.0-hp-osf
exit ;;
i*86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
if test -x /usr/sbin/sysversion ; then
echo "$UNAME_MACHINE"-unknown-osf1mk
else
echo "$UNAME_MACHINE"-unknown-osf1
@@ -823,14 +841,14 @@ EOF
echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/')
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -843,25 +861,25 @@ EOF
echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
exit ;;
arm:FreeBSD:*:*)
UNAME_PROCESSOR=`uname -p`
UNAME_PROCESSOR=$(uname -p)
set_cc_for_build
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi
else
echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf
fi
exit ;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
UNAME_PROCESSOR=$(/usr/bin/uname -p)
case "$UNAME_PROCESSOR" in
amd64)
UNAME_PROCESSOR=x86_64 ;;
i386)
UNAME_PROCESSOR=i586 ;;
esac
echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
exit ;;
i*:CYGWIN*:*)
echo "$UNAME_MACHINE"-pc-cygwin
@@ -897,15 +915,15 @@ EOF
echo x86_64-pc-cygwin
exit ;;
prep*:SunOS:5.*:*)
echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
exit ;;
*:GNU:*:*)
# the GNU system
echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')"
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC"
exit ;;
*:Minix:*:*)
echo "$UNAME_MACHINE"-unknown-minix
@@ -918,7 +936,7 @@ EOF
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -977,6 +995,9 @@ EOF
k1om:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
m32r*:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
@@ -1027,7 +1048,7 @@ EOF
#endif
#endif
EOF
eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`"
eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')"
test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
;;
mips64el:Linux:*:*)
@@ -1047,7 +1068,7 @@ EOF
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in
PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
*) echo hppa-unknown-linux-"$LIBC" ;;
@@ -1065,7 +1086,7 @@ EOF
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-"$LIBC"
exit ;;
riscv32:Linux:*:* | riscv64:Linux:*:*)
riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
@@ -1087,7 +1108,17 @@ EOF
echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
exit ;;
x86_64:Linux:*:*)
echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
set_cc_for_build
LIBCABI=$LIBC
if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_X32 >/dev/null
then
LIBCABI="$LIBC"x32
fi
fi
echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI"
exit ;;
xtensa*:Linux:*:*)
echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
@@ -1127,7 +1158,7 @@ EOF
echo "$UNAME_MACHINE"-pc-msdosdjgpp
exit ;;
i*86:*:4.*:*)
UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//')
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
else
@@ -1136,7 +1167,7 @@ EOF
exit ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
case $(/bin/uname -X | grep "^Machine") in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
@@ -1145,10 +1176,10 @@ EOF
exit ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)
echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
elif /bin/uname -X 2>/dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
@@ -1198,7 +1229,7 @@ EOF
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
&& OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1209,7 +1240,7 @@ EOF
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
OS_REL='.3'
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
&& OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1242,7 +1273,7 @@ EOF
exit ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
UNAME_MACHINE=$( (uname -p) 2>/dev/null)
echo "$UNAME_MACHINE"-sni-sysv4
else
echo ns32k-sni-sysv
@@ -1276,7 +1307,7 @@ EOF
echo mips-sony-newsos6
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
if test -d /usr/nec; then
echo mips-nec-sysv"$UNAME_RELEASE"
else
echo mips-unknown-sysv"$UNAME_RELEASE"
@@ -1324,44 +1355,48 @@ EOF
*:Rhapsody:*:*)
echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
exit ;;
arm64:Darwin:*:*)
echo aarch64-apple-darwin"$UNAME_RELEASE"
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
set_cc_for_build
if test "$UNAME_PROCESSOR" = unknown ; then
UNAME_PROCESSOR=powerpc
UNAME_PROCESSOR=$(uname -p)
case $UNAME_PROCESSOR in
unknown) UNAME_PROCESSOR=powerpc ;;
esac
if command -v xcode-select > /dev/null 2> /dev/null && \
! xcode-select --print-path > /dev/null 2> /dev/null ; then
# Avoid executing cc if there is no toolchain installed as
# cc will be a stub that puts up a graphical alert
# prompting the user to install developer tools.
CC_FOR_BUILD=no_compiler_found
else
set_cc_for_build
fi
if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
i386) UNAME_PROCESSOR=x86_64 ;;
powerpc) UNAME_PROCESSOR=powerpc64 ;;
esac
fi
# On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_PPC >/dev/null
then
UNAME_PROCESSOR=powerpc
fi
if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
i386) UNAME_PROCESSOR=x86_64 ;;
powerpc) UNAME_PROCESSOR=powerpc64 ;;
esac
fi
# On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_PPC >/dev/null
then
UNAME_PROCESSOR=powerpc
fi
elif test "$UNAME_PROCESSOR" = i386 ; then
# Avoid executing cc on OS X 10.9, as it ships with a stub
# that puts up a graphical alert prompting to install
# developer tools. Any system running Mac OS X 10.7 or
# later (Darwin 11 and later) is required to have a 64-bit
# processor. This is not true of the ARM version of Darwin
# that Apple uses in portable devices.
UNAME_PROCESSOR=x86_64
# uname -m returns i386 or x86_64
UNAME_PROCESSOR=$UNAME_MACHINE
fi
echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
UNAME_PROCESSOR=$(uname -p)
if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
@@ -1429,10 +1464,10 @@ EOF
echo mips-sei-seiux"$UNAME_RELEASE"
exit ;;
*:DragonFly:*:*)
echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
exit ;;
*:*VMS:*:*)
UNAME_MACHINE=`(uname -p) 2>/dev/null`
UNAME_MACHINE=$( (uname -p) 2>/dev/null)
case "$UNAME_MACHINE" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
@@ -1442,13 +1477,13 @@ EOF
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')"
exit ;;
i*86:rdos:*:*)
echo "$UNAME_MACHINE"-pc-rdos
exit ;;
i*86:AROS:*:*)
echo "$UNAME_MACHINE"-pc-aros
*:AROS:*:*)
echo "$UNAME_MACHINE"-unknown-aros
exit ;;
x86_64:VMkernel:*:*)
echo "$UNAME_MACHINE"-unknown-esx
@@ -1468,6 +1503,14 @@ cat > "$dummy.c" <<EOF
#include <sys/types.h>
#include <sys/utsname.h>
#endif
#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
#include <signal.h>
#if defined(_SIZE_T_) || defined(SIGLOST)
#include <sys/utsname.h>
#endif
#endif
#endif
main ()
{
#if defined (sony)
@@ -1492,7 +1535,7 @@ main ()
#define __ARCHITECTURE__ "m68k"
#endif
int version;
version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null);
if (version < 4)
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
else
@@ -1554,19 +1597,24 @@ main ()
#else
printf ("vax-dec-bsd\n"); exit (0);
#endif
#else
#if defined(_SIZE_T_) || defined(SIGLOST)
struct utsname un;
uname (&un);
printf ("vax-dec-ultrix%s\n", un.release); exit (0);
#else
printf ("vax-dec-ultrix\n"); exit (0);
#endif
#endif
#endif
#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
#include <signal.h>
#if defined(_SIZE_T_) /* >= ULTRIX4 */
printf ("mips-dec-ultrix4\n"); exit (0);
#if defined(_SIZE_T_) || defined(SIGLOST)
struct utsname *un;
uname (&un);
printf ("mips-dec-ultrix%s\n", un.release); exit (0);
#else
#if defined(ULTRIX3) || defined(ultrix3) || defined(SIGLOST)
printf ("mips-dec-ultrix3\n"); exit (0);
#endif
printf ("mips-dec-ultrix\n"); exit (0);
#endif
#endif
#endif
@@ -1579,7 +1627,7 @@ main ()
}
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` &&
$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) &&
{ echo "$SYSTEM_NAME"; exit; }
# Apollos put the system type in the environment.
@@ -1604,9 +1652,15 @@ This script (version $timestamp), has failed to recognize the
operating system you are using. If your script is old, overwrite *all*
copies of config.guess and config.sub with the latest versions from:
https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
and
https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
EOF
year=$(echo $timestamp | sed 's,-.*,,')
# shellcheck disable=SC2003
if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then
cat >&2 <<EOF
If $0 has already been updated, send the following data and any
information you think might be pertinent to config-patches@gnu.org to
@@ -1614,26 +1668,27 @@ provide the necessary information to handle your system.
config.guess timestamp = $timestamp
uname -m = `(uname -m) 2>/dev/null || echo unknown`
uname -r = `(uname -r) 2>/dev/null || echo unknown`
uname -s = `(uname -s) 2>/dev/null || echo unknown`
uname -v = `(uname -v) 2>/dev/null || echo unknown`
uname -m = $( (uname -m) 2>/dev/null || echo unknown)
uname -r = $( (uname -r) 2>/dev/null || echo unknown)
uname -s = $( (uname -s) 2>/dev/null || echo unknown)
uname -v = $( (uname -v) 2>/dev/null || echo unknown)
/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null)
/bin/uname -X = $( (/bin/uname -X) 2>/dev/null)
hostinfo = `(hostinfo) 2>/dev/null`
/bin/universe = `(/bin/universe) 2>/dev/null`
/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
/bin/arch = `(/bin/arch) 2>/dev/null`
/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
hostinfo = $( (hostinfo) 2>/dev/null)
/bin/universe = $( (/bin/universe) 2>/dev/null)
/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null)
/bin/arch = $( (/bin/arch) 2>/dev/null)
/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null)
/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)
UNAME_MACHINE = "$UNAME_MACHINE"
UNAME_RELEASE = "$UNAME_RELEASE"
UNAME_SYSTEM = "$UNAME_SYSTEM"
UNAME_VERSION = "$UNAME_VERSION"
EOF
fi
exit 1

453
config.h.in Normal file
View 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

665
config.sub vendored

File diff suppressed because it is too large Load Diff

8770
configure vendored Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
# of the platform checks have been taken straight from OpenSSH's configure.ac
# Huge thanks to them for dealing with the horrible platform-specifics :)
AC_PREREQ(2.59)
AC_PREREQ([2.59])
AC_INIT
AC_CONFIG_SRCDIR(buffer.c)
@@ -16,6 +16,7 @@ if test -s "`which hg`" && test -d "$srcdir/.hg"; then
fi
ORIGCFLAGS="$CFLAGS"
LATE_CFLAGS=""
# Checks for programs.
AC_PROG_CC
@@ -47,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],
@@ -124,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
@@ -323,17 +338,40 @@ AC_ARG_ENABLE(shadow,
]
)
AC_ARG_ENABLE(plugin,
[ --enable-plugin Enable support for External Public Key Authentication plug-in],
[
AC_DEFINE(DROPBEAR_PLUGIN, 1, External Public Key Authentication)
AC_MSG_NOTICE(Enabling support for External Public Key Authentication)
DROPBEAR_PLUGIN=1
],
[
AC_DEFINE(DROPBEAR_PLUGIN, 0, External Public Key Authentication)
DROPBEAR_PLUGIN=0
]
)
AC_SUBST(DROPBEAR_PLUGIN)
AC_ARG_ENABLE(fuzz,
[ --enable-fuzz Build fuzzing. Not recommended for deployment.],
[
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
AC_MSG_NOTICE(Enabling fuzzing)
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
AC_PROG_CXX
if test "x$enableval" = "xyes"; then
AC_DEFINE(DROPBEAR_FUZZ, 1, Fuzzing)
AC_MSG_NOTICE(Enabling fuzzing)
DROPBEAR_FUZZ=1
# libfuzzer needs linking with c++ libraries
AC_PROG_CXX
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
]
@@ -342,13 +380,13 @@ 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
@@ -356,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])
@@ -504,28 +541,29 @@ AC_CHECK_FUNCS(clock_gettime)
AC_CHECK_HEADERS([mach/mach_time.h])
AC_CHECK_FUNCS(mach_absolute_time)
AC_CHECK_FUNCS(explicit_bzero memset_s)
AC_CHECK_FUNCS(explicit_bzero memset_s getrandom)
AC_ARG_ENABLE(bundled-libtom,
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
Default is to use system if available, otherwise bundled.],
Default is to use system if available, otherwise bundled.
Dropbear requires system libtommath >= 1.2.0 and libtomcrypt >= 1.18.0],
[
if test "x$enableval" = "xyes"; then
BUNDLED_LIBTOM=1
AC_MSG_NOTICE(Forcing bundled libtom*)
else
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing/old system libtommath and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS",
[AC_MSG_ERROR([Missing/old system libtomcrypt and --disable-bundled-libtom was specified])] )
fi
],
[
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tommath, mp_to_ubin, LIBTOM_LIBS="-ltommath $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tomcrypt, poly1305_init, LIBTOM_LIBS="-ltomcrypt $LIBTOM_LIBS", BUNDLED_LIBTOM=1)
]
)
@@ -835,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()
@@ -858,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.])

View File

@@ -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();

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
DROPBEAR_FD_ZERO(&read_fds);
FD_SET(readfd, &read_fds);
res = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
if (res == 0)
{
dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename);
already_blocked = 1;
}
}
if (len == 0)
{
if (wantlen == 0) {
wantread = sizeof(readbuf);
}
else
{
wantread = MIN(sizeof(readbuf), len-readcount);
} else {
wantread = MIN(sizeof(readbuf), wantlen-readcount);
}
#if DROPBEAR_USE_PRNGD
if (prngd)
{
if (prngd) {
char egdcmd[2];
egdcmd[0] = 0x02; /* blocking read */
egdcmd[1] = (unsigned char)wantread;
if (write(readfd, egdcmd, 2) < 0)
{
if (write(readfd, egdcmd, 2) < 0) {
dropbear_exit("Can't send command to egd");
}
}
#endif
readlen = read(readfd, readbuf, wantread);
if (readlen <= 0) {
if (readlen < 0 && errno == EINTR) {
continue;
}
if (readlen == 0 && len == 0)
{
if (readlen == 0 && wantlen == 0) {
/* whole file was read as requested */
break;
}
@@ -182,17 +150,74 @@ static void write_urandom()
}
#if DROPBEAR_FUZZ
void fuzz_seed(void) {
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() {
@@ -202,6 +227,7 @@ void seedrandom() {
pid_t pid;
struct timeval tv;
clock_t clockval;
int urandom_seeded = 0;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
@@ -215,21 +241,31 @@ void seedrandom() {
/* existing state */
sha1_process(&hs, (void*)hashpool, sizeof(hashpool));
#if DROPBEAR_USE_PRNGD
if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1)
!= DROPBEAR_SUCCESS) {
dropbear_exit("Failure reading random device %s",
DROPBEAR_PRNGD_SOCKET);
}
#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__

View File

@@ -121,7 +121,6 @@ static void generic_dropbear_exit(int exitcode, const char* format,
_dropbear_log(LOG_INFO, fmtbuf, param);
#if DROPBEAR_FUZZ
/* longjmp before cleaning up svr_opts */
if (fuzz.do_jmp) {
longjmp(fuzz.jmp, 1);
}
@@ -258,6 +257,12 @@ int spawn_command(void(*exec_fn)(const void *user_data), const void *exec_data,
const int FDIN = 0;
const int FDOUT = 1;
#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
return fuzz_spawn_command(ret_writefd, ret_readfd, ret_errfd, ret_pid);
}
#endif
/* redirect stdin/stdout/stderr */
if (pipe(infds) != 0) {
return DROPBEAR_FAILURE;
@@ -380,20 +385,37 @@ 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) {
@@ -561,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)
@@ -580,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;
}
}
@@ -686,3 +723,22 @@ void fsync_parent_dir(const char* fn) {
m_free(fn_dir);
#endif
}
int fd_read_pending(int fd) {
fd_set fds;
struct timeval timeout;
DROPBEAR_FD_ZERO(&fds);
FD_SET(fd, &fds);
while (1) {
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if (select(fd+1, &fds, NULL, NULL, &timeout) < 0) {
if (errno == EINTR) {
continue;
}
return 0;
}
return FD_ISSET(fd, &fds);
}
}

View File

@@ -90,6 +90,8 @@ 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)

18
debian/changelog vendored
View File

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

10
debug.h
View File

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

View File

@@ -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.
@@ -242,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"

View File

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

View File

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

View File

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

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

View File

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

View File

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

13
dss.c
View File

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

2
dss.h
View File

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

4
ecc.c
View File

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

@@ -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++) {

193
ed25519.c Normal file
View 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
View 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_ */

View File

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

View File

@@ -1,201 +0,0 @@
#include "includes.h"
#include "includes.h"
#include "fuzz.h"
#include "dbutil.h"
#include "runopts.h"
#include "crypto_desc.h"
#include "session.h"
#include "dbrandom.h"
#include "bignum.h"
#include "fuzz-wrapfd.h"
struct dropbear_fuzz_options fuzz;
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param);
static void load_fixed_hostkeys(void);
void fuzz_common_setup(void) {
fuzz.fuzzing = 1;
fuzz.wrapfds = 1;
fuzz.do_jmp = 1;
fuzz.input = m_malloc(sizeof(buffer));
_dropbear_log = fuzz_dropbear_log;
crypto_init();
fuzz_seed();
/* let any messages get flushed */
setlinebuf(stdout);
}
int fuzz_set_input(const uint8_t *Data, size_t Size) {
fuzz.input->data = (unsigned char*)Data;
fuzz.input->size = Size;
fuzz.input->len = Size;
fuzz.input->pos = 0;
memset(&ses, 0x0, sizeof(ses));
memset(&svr_ses, 0x0, sizeof(svr_ses));
wrapfd_setup();
fuzz_seed();
return DROPBEAR_SUCCESS;
}
#if DEBUG_TRACE
static void fuzz_dropbear_log(int UNUSED(priority), const char* format, va_list param) {
if (debug_trace) {
char printbuf[1024];
vsnprintf(printbuf, sizeof(printbuf), format, param);
fprintf(stderr, "%s\n", printbuf);
}
}
#else
static void fuzz_dropbear_log(int UNUSED(priority), const char* UNUSED(format), va_list UNUSED(param)) {
/* No print */
}
#endif /* DEBUG_TRACE */
void fuzz_svr_setup(void) {
fuzz_common_setup();
_dropbear_exit = svr_dropbear_exit;
char *argv[] = {
"-E",
};
int argc = sizeof(argv) / sizeof(*argv);
svr_getopts(argc, argv);
/* user lookups might be slow, cache it */
fuzz.pw_name = m_strdup("person");
fuzz.pw_dir = m_strdup("/tmp");
fuzz.pw_shell = m_strdup("/bin/zsh");
fuzz.pw_passwd = m_strdup("!!zzznope");
load_fixed_hostkeys();
}
static void load_fixed_hostkeys(void) {
#include "fuzz-hostkeys.c"
buffer *b = buf_new(3000);
enum signkey_type type;
TRACE(("load fixed hostkeys"))
svr_opts.hostkey = new_sign_key();
buf_setlen(b, 0);
buf_putbytes(b, keyr, keyr_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_RSA;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed rsa hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keyd, keyd_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_DSS;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed dss hostkey");
}
buf_setlen(b, 0);
buf_putbytes(b, keye, keye_len);
buf_setpos(b, 0);
type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
if (buf_get_priv_key(b, svr_opts.hostkey, &type) == DROPBEAR_FAILURE) {
dropbear_exit("failed fixed ecdsa hostkey");
}
buf_free(b);
}
void fuzz_kex_fakealgos(void) {
ses.newkeys->recv.crypt_mode = &dropbear_mode_none;
}
void fuzz_get_socket_address(int UNUSED(fd), char **local_host, char **local_port,
char **remote_host, char **remote_port, int UNUSED(host_lookup)) {
if (local_host) {
*local_host = m_strdup("fuzzlocalhost");
}
if (local_port) {
*local_port = m_strdup("1234");
}
if (remote_host) {
*remote_host = m_strdup("fuzzremotehost");
}
if (remote_port) {
*remote_port = m_strdup("9876");
}
}
/* cut down version of svr_send_msg_kexdh_reply() that skips slow maths. Still populates structures */
void fuzz_fake_send_kexdh_reply(void) {
assert(!ses.dh_K);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
mp_set_int(ses.dh_K, 12345678);
finish_kexhashbuf();
}
int fuzz_run_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths) {
static int once = 0;
if (!once) {
fuzz_svr_setup();
fuzz.skip_kexmaths = skip_kexmaths;
once = 1;
}
if (fuzz_set_input(Data, Size) == DROPBEAR_FAILURE) {
return 0;
}
/*
get prefix. input format is
string prefix
uint32 wrapfd seed
... to be extended later
[bytes] ssh input stream
*/
/* be careful to avoid triggering buffer.c assertions */
if (fuzz.input->len < 8) {
return 0;
}
size_t prefix_size = buf_getint(fuzz.input);
if (prefix_size != 4) {
return 0;
}
uint32_t wrapseed = buf_getint(fuzz.input);
wrapfd_setseed(wrapseed);
int fakesock = 20;
wrapfd_add(fakesock, fuzz.input, PLAIN);
m_malloc_set_epoch(1);
if (setjmp(fuzz.jmp) == 0) {
svr_session(fakesock, fakesock);
m_malloc_free_epoch(1, 0);
} else {
m_malloc_free_epoch(1, 1);
TRACE(("dropbear_exit longjmped"))
/* dropbear_exit jumped here */
}
return 0;
}
const void* fuzz_get_algo(const algo_type *algos, const char* name) {
const algo_type *t;
for (t = algos; t->name; t++) {
if (strcmp(t->name, name) == 0) {
return t->data;
}
}
assert(0);
}

View File

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

60
fuzz.h
View File

@@ -8,17 +8,24 @@
#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_preauth(const uint8_t *Data, size_t Size, int skip_kexmaths);
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
@@ -27,10 +34,18 @@ 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(void);
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
@@ -39,6 +54,7 @@ void fuzz_fake_send_kexdh_reply(void);
#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 {
@@ -52,21 +68,47 @@ struct dropbear_fuzz_options {
// whether to skip slow bignum maths
int skip_kexmaths;
// whether is svr_postauth mode
int svr_postauth;
// dropbear_exit() jumps back
int do_jmp;
sigjmp_buf jmp;
uid_t pw_uid;
gid_t pw_gid;
char* pw_name;
char* pw_dir;
char* pw_shell;
char* pw_passwd;
// write out decrypted session data to this FD if it 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;
#endif // DROPBEAR_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
View 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;
}

View File

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

View File

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

View 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;
}

View File

@@ -17,25 +17,33 @@ static const double CHANCE_WRITE2 = 0.5;
struct fdwrap {
enum wrapfd_mode mode;
buffer *buf;
int closein;
int closeout;
};
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
/* for quick selection of in-use descriptors */
static int wrap_used[IOWRAP_MAXFD+1];
static unsigned int nused;
static struct fdwrap wrap_fds[IOWRAP_MAXFD+1] = {{UNUSED, 0, 0}};
static int wrapfd_maxfd = -1;
static unsigned short rand_state[3];
static buffer *input_buf;
static int devnull_fd = -1;
void wrapfd_setup(void) {
static void wrapfd_remove(int fd);
void wrapfd_setup(buffer *buf) {
TRACE(("wrapfd_setup"))
nused = 0;
memset(wrap_fds, 0x0, sizeof(wrap_fds));
memset(wrap_used, 0x0, sizeof(wrap_used));
// clean old ones
int i;
for (i = 0; i <= wrapfd_maxfd; i++) {
if (wrap_fds[i].mode != 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) {
@@ -43,39 +51,55 @@ void wrapfd_setseed(uint32_t seed) {
nrand48(rand_state);
}
void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
TRACE(("wrapfd_add %d buf %p mode %d", fd, buf, mode))
assert(fd >= 0);
assert(fd <= IOWRAP_MAXFD);
assert(wrap_fds[fd].mode == UNUSED);
assert(buf || mode == RANDOMIN);
int wrapfd_new_fuzzinput() {
if (devnull_fd == -1) {
devnull_fd = open("/dev/null", O_RDONLY);
assert(devnull_fd != -1);
}
wrap_fds[fd].mode = mode;
wrap_fds[fd].buf = buf;
int fd = dup(devnull_fd);
assert(fd != -1);
assert(wrap_fds[fd].mode == UNUSED);
wrap_fds[fd].mode = COMMONBUF;
wrap_fds[fd].closein = 0;
wrap_fds[fd].closeout = 0;
wrap_used[nused] = fd;
wrapfd_maxfd = MAX(fd, wrapfd_maxfd);
nused++;
return fd;
}
void wrapfd_remove(int fd) {
unsigned int i, j;
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;
/* remove from used list */
for (i = 0, j = 0; i < nused; i++) {
if (wrap_used[i] != fd) {
wrap_used[j] = wrap_used[i];
j++;
}
}
nused--;
close(fd);
}
int wrapfd_close(int fd) {
@@ -89,7 +113,6 @@ int wrapfd_close(int fd) {
int wrapfd_read(int fd, void *out, size_t count) {
size_t maxread;
buffer *buf;
if (!fuzz.wrapfds) {
return read(fd, out, count);
@@ -115,18 +138,18 @@ int wrapfd_read(int fd, void *out, size_t count) {
return -1;
}
buf = wrap_fds[fd].buf;
if (buf) {
maxread = MIN(buf->len - buf->pos, count);
if (input_buf && 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(buf, maxread), maxread);
buf_incrpos(buf, maxread);
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);
@@ -175,8 +198,6 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
int ret = 0;
int fdlist[IOWRAP_MAXFD+1];
memset(fdlist, 0x0, sizeof(fdlist));
if (!fuzz.wrapfds) {
return select(nfds, readfds, writefds, exceptfds, timeout);
}
@@ -244,3 +265,15 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
return ret;
}
int fuzz_kill(pid_t pid, int sig) {
if (fuzz.fuzzing) {
TRACE(("fuzz_kill ignoring pid %d signal %d", (pid), sig))
if (sig >= 0) {
return 0;
} else {
errno = EINVAL;
return -1;
}
}
return kill(pid, sig);
}

View File

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

View File

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

View 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;
}

View File

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

View File

@@ -6,38 +6,38 @@
#include "algo.h"
#include "bignum.h"
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int once = 0;
static const struct dropbear_kex *ecdh[3]; /* 256, 384, 521 */
static struct key_context* keep_newkeys = NULL;
/* number of generated parameters is limited by the timeout for the first run */
#define NUM_PARAMS 80
static struct kex_ecdh_param *ecdh_params[NUM_PARAMS];
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];
if (!once) {
fuzz_common_setup();
fuzz_svr_setup();
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;
/* ses gets zeroed by fuzz_set_input */
keep_newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
ecdh[0] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp256");
ecdh[1] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp384");
ecdh[2] = fuzz_get_algo(sshkex, "ecdh-sha2-nistp521");
assert(ecdh[0]);
assert(ecdh[1]);
assert(ecdh[2]);
keep_newkeys->algo_hostkey = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
ses.newkeys = keep_newkeys;
/* Pre-generate parameters */
int i;
for (i = 0; i < NUM_PARAMS; i++) {
ses.newkeys->algo_kex = ecdh[i % 3];
ecdh_params[i] = gen_kexecdh_param();
}
once = 1;
/* 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;

View 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
View 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);
}

View 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);
}

View File

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

View File

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

View File

@@ -4,9 +4,11 @@
result=0
hg clone https://secure.ucc.asn.au/hg/dropbear-fuzzcorpus fuzzcorpus || exit 1
test -d fuzzcorpus && hg --repository fuzzcorpus/ pull || hg clone https://hg.ucc.asn.au/dropbear-fuzzcorpus fuzzcorpus || exit 1
for f in `make list-fuzz-targets`; do
./$f fuzzcorpus/$f/* || result=1
# 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
View 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
View 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_ */

View File

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

View File

@@ -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);
}

View File

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

View File

@@ -25,7 +25,6 @@
#ifndef DROPBEAR_INCLUDES_H_
#define DROPBEAR_INCLUDES_H_
#include "options.h"
#include "debug.h"
@@ -124,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"
@@ -164,6 +167,10 @@ typedef u_int32_t uint32_t;
#include <linux/pkt_sched.h>
#endif
#if DROPBEAR_PLUGIN
#include <dlfcn.h>
#endif
#include "fake-rfc2553.h"
#include "fuzz.h"

12
kex.h
View File

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

View File

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

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