Compare commits

...

266 Commits

Author SHA1 Message Date
Matt Johnston
dd0352d93b changelog for 2015.67 2015-01-28 22:54:23 +08:00
Matt Johnston
30ec18d938 merge 2015-01-28 22:49:40 +08:00
Matt Johnston
9d495ab2b5 changes for 2015.67 2015-01-28 22:49:28 +08:00
Matt Johnston
9174de47a9 Fix bad multi-statement define for m_free(), detected by Coverity 2015-01-28 22:43:01 +08:00
Christian Engelmayer
d857faf18e When clearing the memory of 'key' in function openssh_read(), only the size
of the pointer to the data instead of the whole size of struct openssh_key
is cleared. Correct the size calculation as detected by Coverity CID 1191543.
2015-01-28 22:42:29 +08:00
Matt Johnston
d5c8ba1690 Initialise sa_mask 2015-01-28 22:33:34 +08:00
Matt Johnston
9bb9b4829d Fix memory leak of ecdsa structure, found by Coverity 2015-01-28 22:29:18 +08:00
Matt Johnston
e25c297c3c Document ~/.ssh/id_dropbear 2015-01-28 22:22:32 +08:00
Elan Ruusamäe
b9073961f7 Allow configure with libtomcrypt/libtommath directories missing
if using bundled libraries
2015-01-28 22:05:24 +08:00
Matt Johnston
a7a79d569a Disable non-delayed zlib for server 2015-01-28 21:38:27 +08:00
Matt Johnston
6165f53fcd Default client key path ~/.ssh/id_dropbear 2015-01-24 00:05:26 +08:00
Fedor Brunner
4122cac66b Prefer stronger algorithms in algorithm negotiation.
Prefer diffie-hellman-group14-sha1 (2048 bit) over
diffie-hellman-group1-sha1 (1024 bit).

Due to meet-in-the-middle attacks the effective key length of
three key 3DES is 112 bits. AES is stronger and faster then 3DES.

Prefer to delay the start of compression until after authentication
has completed. This avoids exposing compression code to attacks
from unauthenticated users.

(github pull request #9)
2015-01-23 23:00:25 +08:00
Like Ma
a1dcebe4f4 Fix installing dropbear.8 error when building in a separate directory.
(fix pull request #6)
2015-01-23 22:59:30 +08:00
Matt Johnston
6cbb23a819 Add config option to disable cbc. Disable twofish by default 2015-01-23 22:37:14 +08:00
Like Ma
5c57a31184 Fix variables may be uninitialized.
(fixup of pull request #7)
2015-01-23 22:23:23 +08:00
Fedor Brunner
7b2c42aa75 Integrity error (bad packet size %u) negative length
When corrupted packet is received negative length of packet is
    displayed.
    (re-apply of pull request #8)
2015-01-23 22:21:06 +08:00
Matt Johnston
1ed8d3938e Enable sha2 HMACs by default, they're required for ecdsa already 2015-01-13 20:55:04 +08:00
Matt Johnston
b24984deb3 clear hash state memory after use 2015-01-04 23:10:59 +08:00
Matt Johnston
eabd9f5e60 clarify bad/unknown 2015-01-04 22:32:38 +08:00
Catalin Patulea
d4609682af Handle invalid agent keys by skipping rather than exiting.
My agent exposes both conventional keys and certs (ecdsa-sha2-nistp256-cert-v01@openssh.com) and I want dropbear to be able to use the former.
2015-01-01 17:47:46 -05:00
Matt Johnston
634415f79e Open directories O_RDONLY for fsync, add debugging if it fails 2015-01-04 22:22:43 +08:00
Matt Johnston
4ba830fc31 Make sure hostkeys are flushed to disk to avoid empty files if the power
fails. Based on patch from Peter Korsgaard
2014-11-08 22:15:16 +08:00
Matt Johnston
3022a46039 Added signature for changeset 2d421bc0545d 2014-10-23 22:09:46 +08:00
Matt Johnston
d9a868ff60 Added tag DROPBEAR_2014.66 for changeset 735511a4c761 2014-10-23 22:09:22 +08:00
Matt Johnston
c890a0c133 changelog, version number bump 2014-10-23 21:43:00 +08:00
Matt Johnston
9ec934a94a Remove -o from scp help 2014-10-23 20:52:10 +08:00
Matt Johnston
5e606a964b increae MAX_STRING_LEN for sun ssh 2014-10-23 20:50:06 +08:00
Steven Honeyman
d88034434c Don't print "Failed loading hostkey" when -R delayed hostkey option is enabled 2014-10-22 07:12:52 +08:00
Matt Johnston
776d908703 Combine code for SSH_CONNECTION and SSH_CLIENT 2014-10-21 22:33:49 +08:00
Matt Johnston
444b15889f Merge pull request #5 from rcleere/ssh_client
Add SSH_CLIENT environment variable
2014-10-21 21:43:20 +08:00
Ryan Cleere
957450582f Add SSH_CLIENT environment variable 2014-10-20 12:59:47 -05:00
Matt Johnston
6d2d3669f3 Make keepalive handling more robust, this should now match what OpenSSH does 2014-08-19 23:08:56 +08:00
Whoopie
1387654cc8 Fix wtmp, testing for wtmp.h and wtmpx.h doesn't make sense 2014-08-13 22:07:43 +08:00
Matt Johnston
10eb218fb0 Don't send SSH_MSG_UNIMPLEMENTED for keepalive responses 2014-08-13 21:48:47 +08:00
Matt Johnston
bfb2b30de6 Added signature for changeset caac692b366c 2014-08-08 21:53:47 +08:00
Matt Johnston
426d4d72c6 Added tag DROPBEAR_2014.65 for changeset e9579816f20e 2014-08-08 21:53:42 +08:00
Matt Johnston
cce29ba38c 2014.64 2014-08-08 21:40:42 +08:00
Mike Frysinger
ed2e276b3a use xauth in /usr/bin
Since the x.org rework, X has been installed into standard paths and not
its own random prefixes.  I think it's time we update the default paths
accordingly.
2014-08-01 06:14:19 -04:00
Matt Johnston
12a020aa62 Don't warn about ENOTSOCK when setting priority 2014-08-06 22:16:38 +08:00
Matt Johnston
b969101b33 Be a bit safer in case pw_name doesn't exist 2014-08-06 22:10:57 +08:00
Matt Johnston
86a742f635 merge 2014-08-06 22:08:16 +08:00
Matt Johnston
9468f7f6d6 Merge pull request #2 from iquaba/patch-1
Try without identifying current user
2014-08-06 22:04:49 +08:00
Matt Johnston
628a3f5cca Test for EAGAIN too 2014-08-06 21:55:43 +08:00
iquaba
e815e97440 Try without identifying current user
Small change that warns the user if the current user cannot be identified rather than aborting.  This came in handy when I put dropbear on a dlink that did not have a true user environment.  Falling back on the "-l" option and user@ options works just fine as a client.  The only implication I found is that the -J option will fail ungracefully without a known own_user.
2014-08-06 08:48:43 -05:00
Matt Johnston
0e7409c7ff Make sure the check_close() handler runs when a server child process exits 2014-07-28 23:23:49 +08:00
Matt Johnston
393ca2a290 Fix some format string warnings 2014-07-28 22:59:16 +08:00
Matt Johnston
ad1d48e07b Fix clock_gettime handling 2014-07-28 22:48:48 +08:00
Matt Johnston
ac98aae160 Added signature for changeset 96584b934d04 2014-07-27 23:11:52 +08:00
Matt Johnston
c1267398a2 Added tag DROPBEAR_2014.64 for changeset 0d2d39957c02 2014-07-27 23:11:47 +08:00
Matt Johnston
8c3a2bb63e Archive should be bz2 nor gz 2014-07-27 22:56:35 +08:00
Matt Johnston
923fc9087c - Don't use multichar constants since recent gcc complains
- Add release script
- Simplify print_version
2014-07-27 22:55:29 +08:00
Matt Johnston
83511fecc0 Version 2014.64 2014-07-27 22:25:18 +08:00
Matt Johnston
ed0552f214 Add '-V' for version
-h should exit with success
Update manpages
2014-07-27 22:06:26 +08:00
Matt Johnston
5cf83a7212 Avoid use-after-free when channel inithandler fails. Thanks to Coverity 2014-07-26 10:18:55 +08:00
Matt Johnston
7808eff0a9 changes for 2014.64 2014-07-25 22:22:39 +08:00
Matt Johnston
da57dd13c5 Set tcp priority as follows:
if (connecting || ptys || x11) tos = LOWDELAY;
else if (tcp_forwards) tos = 0;
else tos = BULK;

TCP forwards could be either lowdelay or bulk, hence the default priority.
2014-07-16 22:53:32 +08:00
Matt Johnston
f1826ea389 Fix auth timeout regression 2014-07-09 22:02:22 +08:00
Matt Johnston
c884e5000e Make -K keepalive behave like OpenSSH's ServerAliveInterval 2014-07-09 00:15:20 +08:00
Matt Johnston
1ccac01cee Make sure client exit messages don't get lost 2014-07-09 00:13:17 +08:00
Matt Johnston
50a5d3756f Send a failure response if a client receives a global request 2014-07-08 21:59:36 +08:00
Matt Johnston
ca86726f9f Improve handling lots of concurrent forwarded connections. Increase
connection backlog, avoid check_close() for channels that haven't had IO
2014-06-25 23:42:39 +08:00
Matt Johnston
6b5317e7cc Fix compiling with ECDSA and DSS disabled 2014-06-25 23:37:44 +08:00
Matt Johnston
2a1d28ea3a Be more careful in case a platform doesn't define UIO_MAXIOV nor IOV_MAX 2014-05-20 21:21:02 +08:00
Ronny Meeus
0e0ff51582 Limit size of the iovect passed to writev in packet.c 2014-05-20 21:18:48 +08:00
Ronny Meeus
cd700aaf6e Print errno information in write_packet 2014-05-20 20:56:59 +08:00
Matt Johnston
188ec1e258 Fix pubkey auth if the first key presented fails (infinite loop of
auth requests). Regresssion in ff597bf2cfb0
2014-04-23 16:22:50 +08:00
Matt Johnston
d01fb265d6 Fix monotonic_now() on OS X 2014-03-21 22:16:42 +08:00
Matt Johnston
db688e3ec1 Experiment of always writing data if available. Might waste a writev() with
EAGAIN but always saves a select() - needs testing with bandwidth-limited
and CPU-limited situations.
2014-03-15 11:37:02 +08:00
Matt Johnston
e767bbb41f Add new monotonic_now() wrapper so that timeouts are unaffected by
system clock changes
2014-03-13 23:50:09 +08:00
Matt Johnston
2b599df57a Fix typo 2014-03-13 23:08:47 +08:00
Yousong Zhou
5baa10a6b6 Use AUTH_TIMEOUT only before authdone != 1.
While at it, fix a few indentations and typo.
2014-03-13 16:28:16 +08:00
Matt Johnston
3e1a389629 Don't need to mkdir 2014-03-08 21:00:57 +08:00
Matt Johnston
37e6207396 Fix env vars for travis again 2014-03-07 21:46:51 +08:00
Matt Johnston
927a2dc849 Fix "make install" dependency so that it works without prior "make" 2014-03-07 21:30:20 +08:00
Matt Johnston
ce9f9594da Add some tests for multi 2014-03-07 21:14:12 +08:00
Matt Johnston
f0bf37b6cb Install system libtom libs, run dropbearkey when it's done 2014-03-07 21:03:43 +08:00
Matt Johnston
2f0b35a105 The arguments are for configure, not make! 2014-03-07 20:52:57 +08:00
Matt Johnston
7a9ed81f5f Add Travis CI autobuilder config 2014-03-07 20:44:32 +08:00
Matt Johnston
12e7d570a2 Make some debug info conditional 2014-02-24 20:53:32 +08:00
Matt Johnston
bb7934bf04 A few fixes for cases where compression increases payload sizes, and
be more precise about maximum channel sizes
2014-02-22 18:02:09 +08:00
Matt Johnston
fb3c718963 Fix typo in Catalin's name 2014-02-19 22:18:11 +08:00
Matt Johnston
231fc607f9 Added signature for changeset 277429102f13 2014-02-19 22:14:58 +08:00
Matt Johnston
9594a3aa45 Added tag DROPBEAR_2014.63 for changeset 2351b2da8e0d 2014-02-19 22:14:52 +08:00
Matt Johnston
162fcab347 2014.63 2014-02-19 22:04:35 +08:00
Catalin Patulea
0c8bdfd7cd README: fix ecdsa key generation command 2014-02-09 03:56:50 -05:00
Matt Johnston
5e4dc71907 CHANGES for 2014.63 2014-02-19 22:01:01 +08:00
Matt Johnston
3e4433f715 - Fix dbclient with port 0 for server-allocated
- Fix port forwards with a bind address of 127.0.0.1 vs "localhost" etc
2014-02-18 21:33:56 +08:00
Matt Johnston
29062e629f Fix building with system libtomcrypt/libtommath 2014-02-18 21:03:27 +08:00
Steve Dover
47f7272ba1 Add linux/types.h to includes to avoid missing ___u64 etc 2014-02-17 22:05:59 +08:00
Matt Johnston
bf6f3f613d Read (and enqueue) packets from interactive input even when
we're waiting for a key exchange.

This should hopefully fix the situation where "~." doesn't work to terminate a
client session when a laptop wakes up. The client will be stuck waiting for a
key exchange on a dead connection, so won't have read the escape character
2014-02-17 21:41:06 +08:00
Matt Johnston
0c9a643216 Change port separator to ^ since % is used in ipv6 addresses 2014-02-15 21:42:35 +08:00
Matt Johnston
fa2d843403 Disable immediate auth for delayed-zlib mode 2014-02-15 21:23:41 +08:00
Matt Johnston
1dc5312f00 - Save errno in signal handlers
- Use _exit() in segv handler
2014-02-15 21:13:57 +08:00
Matt Johnston
73444f2957 generate RSA keys of exact length 2014-02-14 23:18:45 +08:00
Matt Johnston
a18a6b8db8 cleanup before clearing keys 2014-02-12 22:15:02 +08:00
Nicolas Boos
bf56591fb8 Fix linking -lcrypt for systems without libcrypt in /usr/lib 2014-02-07 07:57:45 +08:00
Nicolas Boos
5ea428a30d Avoid linking dropbearconvert and dropbearkey to libz or libutil 2014-02-07 07:53:32 +08:00
Matt Johnston
af524c4d65 Fix check for EINTR 2014-01-28 22:44:24 +08:00
Matt Johnston
2bc9f35052 Back out accidentally committed files 2014-01-23 22:29:04 +08:00
Matt Johnston
55a0c5068f requirenext doesn't need two values 2014-01-23 22:25:52 +08:00
Matt Johnston
8128b15e41 Fix failing rekeying when we receive a still-in-flight packet 2014-01-23 21:56:35 +08:00
Matt Johnston
8081b0e033 Forgot to save the change 2014-01-17 21:42:32 +08:00
Matt Johnston
61cecbb337 DROPBEAR_CLI_AUTH_IMMEDIATE fixed, now enabled by default 2014-01-17 21:39:27 +08:00
Mike Frysinger
aee1309c91 Fix so that "make install" for multi target won't fail on scp which doesn't
have a manpage
2013-12-11 21:50:33 +08:00
Mike Frysinger
710c1df413 Turn dropbearmulti into a real target so we don't constantly re-link it 2013-12-11 21:48:02 +08:00
Matt Johnston
0f165a95a8 Added signature for changeset 3d1d7d151c0c 2013-12-03 22:00:38 +08:00
Matt Johnston
581f04c80b Added tag DROPBEAR_2013.62 for changeset 3d1d7d151c0c 2013-12-03 22:00:29 +08:00
Matt Johnston
511be4acc6 2013.62 2013-12-03 21:39:06 +08:00
Matt Johnston
d77b29f1d7 Update to 2013-10-01 2013-12-03 21:36:12 +08:00
Matt Johnston
092a4d9a7e Fix disabling DSS key 2013-12-03 21:26:59 +08:00
Matt Johnston
b3cab3ce31 Log when generating a hostkey 2013-12-03 21:13:58 +08:00
Matt Johnston
e5279b0e2e Update README 2013-12-03 21:03:23 +08:00
Matt Johnston
9ff337aa3b Exit if we don't have keys and -R wasn't specified 2013-12-03 20:59:03 +08:00
Catalin Patulea
441facc6e0 Fix TRACEs of cli_send_netcat_request 2013-12-03 00:06:35 +08:00
Matt Johnston
998d6cdfc4 - Sockets are set to lowdelay priority initially to improve conneciton setup
time
- Set non-pty connections to bulk for client and server
2013-12-03 00:04:48 +08:00
Catalin Patulea
ddc10b2d0c Set IPTOS_LOWDELAY on PTY sessions only 2013-12-02 22:55:43 +08:00
Matt Johnston
4f6f651b7d Only define LTM_DESC if it isn't already 2013-12-02 22:15:17 +08:00
Matt Johnston
68c7667a20 merge 2013-11-27 21:32:45 +08:00
Matt Johnston
0b62d71e70 - Increase buffer size, fixes converting 521bit ECC key
- Fix assertion that key size is exactly curve size
2013-11-27 21:30:05 +08:00
Matt Johnston
be5780ef90 Fix library order of libtom* 2013-11-25 23:39:15 +08:00
Matt Johnston
e5c52796c3 Try and fix utmp handling 2013-11-25 23:30:01 +08:00
Matt Johnston
c5e36f8e3c Fix some warnings 2013-11-25 23:08:33 +08:00
Matt Johnston
5a85c4b91b Added signature for changeset 9ec083a21adf 2013-11-14 22:39:27 +08:00
Matt Johnston
0201072c1b Added tag DROPBEAR_2013.61test for changeset e894dbc015ba 2013-11-14 22:39:16 +08:00
Matt Johnston
aa029ed991 2013.61test 2013-11-14 22:24:10 +08:00
Matt Johnston
0777e896f1 docs for ecdsa 2013-11-14 22:14:09 +08:00
Matt Johnston
7f90231b8f another new config.guess 2013-06-10 2013-11-14 22:07:18 +08:00
Matt Johnston
cbe63bbabe rename random.h to dbrandom.h since some OSes have a system random.h
--HG--
rename : random.c => dbrandom.c
rename : random.h => dbrandom.h
2013-11-14 22:05:47 +08:00
Matt Johnston
de1deaf0bd use oldstyle comments 2013-11-14 22:03:30 +08:00
Matt Johnston
e00a97944a Replace some deprecated macros with other ones, from Daniel Richard G. 2013-11-14 21:45:50 +08:00
Matt Johnston
a65f84db38 - Some fixes for old compilers like tru64 v4 from Daniel Richard G.
- Don't warn about blocking random device for prngd
2013-11-14 21:36:45 +08:00
Matt Johnston
8c8ecec3e9 merge ecc again 2013-11-14 20:45:46 +08:00
Matt Johnston
b77864931b Don't exit fatally if authorized_keys has a line like
command="something" ssh-rsa

--HG--
branch : ecc
2013-11-12 23:58:51 +08:00
Matt Johnston
e60a84d0ed Various cleanups and fixes for warnings
--HG--
branch : ecc
2013-11-12 23:02:32 +08:00
Matt Johnston
f025277147 comments, turn off debugging options
--HG--
branch : ecc
2013-11-09 00:14:28 +08:00
Matt Johnston
1e00d0b926 - Make curve25519 work after fixing a typo, interoperates with OpenSSH
- comment on ecc binary size effects

--HG--
branch : ecc
2013-11-09 00:02:26 +08:00
Matt Johnston
29b1455f36 Merge
--HG--
branch : ecc
2013-11-08 23:32:13 +08:00
Matt Johnston
0162c116da curve25519
--HG--
branch : ecc
2013-11-08 23:11:43 +08:00
Matt Johnston
58fe1c2d2a Add '-R' for delayed hostkey option
--HG--
branch : keyondemand
2013-11-07 23:49:37 +08:00
Matt Johnston
4363b8b32d refactor key generation, make it generate as required.
Needs UI in server command line options

--HG--
branch : keyondemand
2013-11-07 00:18:52 +08:00
Matt Johnston
cfac8435a7 merge yet again 2013-11-01 00:21:59 +08:00
Matt Johnston
35f26ff855 merge again 2013-11-01 00:19:25 +08:00
Matt Johnston
f66fc01620 Merge 2013-11-01 00:14:48 +08:00
Matt Johnston
082a2dde35 Fix specifying a keysize for key generation, fix key name arguments
--HG--
branch : ecc
2013-11-01 00:13:09 +08:00
Matt Johnston
814ab77538 Default to some larger key sizes
--HG--
branch : ecc
2013-10-31 22:49:15 +08:00
Matt Johnston
8eefb092c8 Merge in ECC 2013-10-21 22:57:21 +08:00
Matt Johnston
55e7f0486a Fix shadowed "ret" variable
--HG--
branch : ecc
2013-10-21 22:50:52 +08:00
Matt Johnston
88ac2da7c2 A few small fixes for ECC compilation
--HG--
branch : ecc
2013-10-21 22:46:12 +08:00
Matt Johnston
27510a6e9e merge
--HG--
branch : ecc
2013-10-20 21:07:05 +08:00
Matt Johnston
7fda6418e1 writing out openssh ecc keys works
--HG--
branch : ecc
2013-10-20 21:06:18 +08:00
Matt Johnston
45bd0edae5 Merge in changes from the past couple of releases
--HG--
branch : ecc
2013-10-18 21:38:01 +08:00
Matt Johnston
3d733a16e9 Added signature for changeset a50a1dc74331 2013-10-16 22:55:03 +08:00
Matt Johnston
fe623afaad Added signature for changeset 025237c9f0a1 2013-10-16 22:52:43 +08:00
Matt Johnston
b840a980e3 Added tag DROPBEAR_2013.60 for changeset a50a1dc74331 2013-10-16 22:52:05 +08:00
Matt Johnston
2ec98eb048 Update debian changelog for 2013.60 too 2013-10-16 22:34:25 +08:00
Matt Johnston
253cd3b66b - 2013.60, update CHANGES
- Add CVE references to CHANGES
2013-10-16 22:32:31 +08:00
Matt Johnston
920120d05a Make --disable-bundled-libtom work, based on patch from Mike Frysinger 2013-10-15 22:55:44 +08:00
Matt Johnston
4ba058986e - Fix "inst_scp" target since there isn't a manpage
- Fix "make install MULTI=1"
2013-10-09 22:24:39 +08:00
Matt Johnston
03b7255ddd Add @exec_prefix@ that was missing 2013-10-09 21:58:07 +08:00
Matt Johnston
2de7f8b224 Added signature for changeset deb211f75ca1 2013-10-04 22:40:28 +08:00
Matt Johnston
bbf2f1d571 Added tag DROPBEAR_2013.59 for changeset 7b68e581985f 2013-10-04 22:39:09 +08:00
Matt Johnston
9cdd5e99a4 Fix up debian build 2013-10-04 22:22:35 +08:00
Matt Johnston
897ed7125b Fix debian installation of manpages 2013-10-04 21:49:32 +08:00
Matt Johnston
459d259185 Version 2013.59 2013-10-04 21:41:19 +08:00
Matt Johnston
aac6336e49 Don't say "SSH 2" any more since protocol version 1 is irrelevant 2013-10-03 23:50:04 +08:00
Matt Johnston
fc1155f974 Add manpage for dropbearconvert
Move dropbearkey to manual section 1
Add install target for manpages

--HG--
rename : dropbearkey.8 => dropbearkey.1
2013-10-03 23:45:25 +08:00
Matt Johnston
6a09fa23d0 Get rid of spurious newlines in pam log messages 2013-10-03 23:04:26 +08:00
Matt Johnston
142a0f8a83 Send PAM error messages as a banner messages
Patch from Martin Donnelly, modified.
2013-10-03 23:04:11 +08:00
Matt Johnston
d1dec41f76 Constant time memcmp for the hmac and password crypt 2013-10-03 22:25:30 +08:00
Matt Johnston
69a165db86 Only send a failure response to a channel request if wantreply is set. 2013-09-21 00:34:36 +08:00
Matt Johnston
dffb33cecf Improve EOF handling for half-close. Patch from Catalin Patulea
Fixes the situation
$ ./dbclient root@1.2.3.4 'cat; echo foo'
^D
<no output>
2013-09-21 00:17:22 +08:00
Matt Johnston
e7917c16c9 Remove accidental one second sleep leftover from debugging 2013-08-12 22:41:00 +08:00
Matt Johnston
e05b7f0b76 merge 2013-07-08 22:43:56 +08:00
Matt Johnston
aeea70f95f strdup the proxycmd to avoid crash when freeing, from Lluís Batlle i Rossell 2013-07-08 22:42:32 +08:00
Matt Johnston
ded40babb5 limit how much we read from rt_cache etc 2013-05-28 22:16:57 +08:00
Matt Johnston
e355f69401 merge 2013-05-26 18:43:00 +08:00
Matt Johnston
c2b1327deb merge 2013-05-26 18:42:17 +08:00
Matt Johnston
f7ba7444e8 improve auth failure delays to avoid indicating which users exist 2013-05-26 18:39:24 +08:00
Matt Johnston
aafeebd0c8 have separate ecdsa keys for each size
fix crash from the mp_alloc_init_multi change in RSA

--HG--
branch : ecc
2013-05-25 00:54:19 +08:00
Matt Johnston
6b0d47b364 hackish ECC import code from OpenSSH
--HG--
branch : ecc
2013-05-23 22:18:33 +08:00
Matt Johnston
d9e790e7dc Add m_mp_alloc_init_multi() helper
--HG--
branch : ecc
2013-05-23 22:18:16 +08:00
Matt Johnston
51b5cdd430 Enable SMALL_CODE by default
--HG--
branch : ecc
2013-05-21 13:44:48 +08:00
Matt Johnston
aced7b5b00 Fix static library order, libtomcrypt depends on libtommath
--HG--
branch : ecc
2013-05-21 13:20:02 +08:00
Matt Johnston
0475594cb2 Fix broken disablekey()
--HG--
branch : ecc
2013-05-21 12:15:48 +08:00
Matt Johnston
04518e9e80 merge in HEAD
--HG--
branch : ecc
2013-05-21 12:09:35 +08:00
Matt Johnston
a57947c513 Fix bad comma in header list 2013-05-13 21:35:13 +08:00
Matt Johnston
372e81a842 Update config.guess and config.sub 2013-05-13 21:06:35 +08:00
Matt Johnston
41f531ceaf quieten the compiler
--HG--
branch : ecc
2013-05-09 23:27:23 +08:00
Matt Johnston
b46d46667f merge
--HG--
branch : ecc
2013-05-09 23:25:39 +08:00
Matt Johnston
226671b550 Fix build for dropbearkey and ecdsa with certain options
--HG--
branch : ecc
2013-05-09 23:24:58 +08:00
Matt Johnston
916cfa6b83 Fix ecdsa verification
--HG--
branch : ecc
2013-05-09 23:24:05 +08:00
Matt Johnston
49263b5314 Limit decompressed size 2013-05-08 23:23:14 +08:00
Matt Johnston
95a21c8fd7 ecdsa is working
--HG--
branch : ecc
2013-05-03 23:07:48 +08:00
Matt Johnston
57166b400c Avoid segfault for locked accounts (invalid salt to crypt()) 2013-04-29 23:42:37 +08:00
Matt Johnston
79660f2eb1 more ecdsa signkey work, not correct
--HG--
branch : ecc
2013-04-28 23:17:43 +08:00
Matt Johnston
3ea9068e18 Save with utf8 encoding 2013-04-18 23:15:17 +08:00
Matt Johnston
e4c672bdbb Added signature for changeset f168962bab85 2013-04-18 23:10:24 +08:00
Matt Johnston
791a78ad1f Added tag DROPBEAR_2013.58 for changeset e76614145aea 2013-04-18 23:10:19 +08:00
Matt Johnston
6da90b34fe 2013.58 2013-04-18 22:57:47 +08:00
Matt Johnston
43769b5bb3 Don't enable CLI_IMMEDIATE_AUTH by default, it breaks blank password logins 2013-04-18 21:47:38 +08:00
Matt Johnston
f98eb5808b Use % rather than # for port delimiter 2013-04-17 23:17:27 +08:00
Matt Johnston
3525cabf48 Use '#' for host#port separator, document it. This fixes scp
in multihop
2013-04-17 22:48:43 +08:00
Matt Johnston
54a76342f5 If running as non-root only allow that user to log in 2013-04-17 22:29:18 +08:00
Matt Johnston
154a65fc31 Fix build when zlib is disabled, from
http://freetz.org/browser/trunk/make/dropbear/patches/350-no_zlib_fix.patch
2013-04-16 22:16:32 +08:00
Matt Johnston
bd7a46f514 Added signature for changeset 095b46180bbc 2013-04-15 22:11:11 +08:00
Matt Johnston
79a307bca2 Added tag DROPBEAR_2013.57 for changeset 96b8bcb88017 2013-04-15 22:10:49 +08:00
Matt Johnston
38f42a0fa2 Fix error message for requirenext change 2013-04-15 22:01:41 +08:00
Matt Johnston
b4cdfcb506 bump version to 2013.57 2013-04-15 21:56:04 +08:00
Matt Johnston
d3cef72f26 changelog updates for 2013.57 2013-04-15 21:51:27 +08:00
Matt Johnston
ef151888fb requirenext fixup for firstkexfollows 2013-04-14 23:16:16 +08:00
Matt Johnston
ba15bbfe33 Document escape chars 2013-04-14 23:08:57 +08:00
Matt Johnston
3bdfae61a2 merge 2013-04-14 22:49:19 +08:00
Matt Johnston
4404126501 -y -y to disable hostkey checking
fix missing trailing space when passing arguments for multihop mode
From Hans Harder
2013-04-14 22:49:10 +08:00
Matt Johnston
5c87c6a435 A bit of work on ecdsa for host/auth keys
--HG--
branch : ecc
2013-04-14 00:50:03 +08:00
Matt Johnston
adeb372a66 Fix zlib for split newkeys 2013-04-11 23:03:58 +08:00
Matt Johnston
c0d7c6693f run closehandlers on cleanup 2013-04-10 21:32:55 +08:00
Matt Johnston
3ec4670478 reset terminal modes before printing a message 2013-04-10 21:32:44 +08:00
Matt Johnston
f842712551 A bit of debugging output
--HG--
branch : ecc
2013-04-09 22:47:03 +08:00
Matt Johnston
9f01625e23 Be safer with how we handle ltc_ecc_sets[] (particularly with
system libtomcrypt)

A bit of progress with ecdsa code

--HG--
branch : ecc
2013-04-09 22:44:19 +08:00
Matt Johnston
7f091e7019 start on ecdsa keys
--HG--
branch : ecc
2013-04-09 00:36:04 +08:00
Matt Johnston
4f07805d0a - Rename buf_put_ecc_pubkey_string() to buf_put_ecc_raw_pubkey_string()
- Reindent ecc.c properly

--HG--
branch : ecc
2013-04-08 23:56:31 +08:00
Matt Johnston
a7d1a9cfcb add printmpint() for debugging
--HG--
branch : ecc
2013-04-08 23:12:35 +08:00
Matt Johnston
48c83aa9d0 ecdh works against OpenSSH
--HG--
branch : ecc
2013-04-08 23:12:20 +08:00
Matt Johnston
c797c1750c - Fix various hardcoded uses of SHA1
- rename curves to nistp256 etc
- fix svr-auth.c TRACE problem

--HG--
branch : ecc
2013-04-08 00:10:57 +08:00
Matt Johnston
c6bdc810ab ecc kind of works, needs fixing/testing
--HG--
branch : ecc
2013-04-07 01:36:42 +08:00
Matt Johnston
a8135dec1e Make _sign and _verify functions take a buffer* rather than void* and int
--HG--
branch : ecc
2013-04-06 16:00:37 +08:00
Matt Johnston
2fdb5fd6ce setup tcp after requesting a channel - might hide some DNS latency 2013-04-04 07:51:13 +08:00
Matt Johnston
7f42096d0f Take transmit and receive keys into use separately 2013-04-04 00:18:50 +08:00
Matt Johnston
e2c813df4d Fix MAC bug which would prevent asymmetric hashes 2013-04-03 23:54:58 +08:00
Matt Johnston
a2f70a3751 Just put the version string on the queue, don't use atomicio 2013-04-03 19:23:53 +08:00
Matt Johnston
286fa93a8d fix leftover kexguess debugging 2013-04-03 07:34:18 +08:00
Matt Johnston
557d86aa79 Fix a few options and headers 2013-04-03 07:33:47 +08:00
Matt Johnston
8e68d5e2d5 merge 2013-04-03 00:50:46 +08:00
Matt Johnston
1a16da38d5 merge kexguess branch 2013-04-03 00:49:24 +08:00
Matt Johnston
cbd3d5e3a5 Put some #ifdef options around first-follows options in case they
need to be disabled

--HG--
branch : kexguess
2013-04-03 00:43:31 +08:00
Matt Johnston
78fbed8c3e Don't usually need to recalculate dh_e for the repeated kexdh_init packet
--HG--
branch : kexguess
2013-04-03 00:32:55 +08:00
Matt Johnston
f267ca1f3a Add sentinel attribute
--HG--
branch : kexguess
2013-04-03 00:32:05 +08:00
Matt Johnston
a6eb824950 add IUTF8 2013-04-02 19:11:13 +08:00
Matt Johnston
dcd1527a11 fix tabs 2013-04-02 18:59:00 +08:00
Matt Johnston
f8a92d1eed merge 2013-04-02 18:54:04 +08:00
Matt Johnston
e55e468754 Fix segfault when /dev/urandom isn't writable 2013-04-02 18:53:18 +08:00
Matt Johnston
ff2aa20565 Be a bit more careful about when we want to use CLI_AUTH_IMMEDIATE
Only use it if we have pubkeys to try, or we have $DROPBEAR_PASSWORD set
2013-04-02 00:11:53 +08:00
Matt Johnston
90b5691183 Run the cleanup handler also when we close due to TCP connection being closed 2013-04-01 22:26:55 +08:00
Matt Johnston
5af0d33164 Try password before interactive - bit of a hack 2013-04-01 22:26:24 +08:00
Matt Johnston
e5072c6b12 merge from head roundtrip changes
--HG--
branch : kexguess
2013-04-01 00:13:41 +08:00
Matt Johnston
90cf7f012c Move the more verbose TRACE() statements into TRACE2() 2013-04-01 00:07:26 +08:00
Matt Johnston
484516da51 Send an auth packet straight away, save another roundtrip
This needs a bit of testing to make sure it doesn't have side-effects.
2013-03-31 23:48:25 +08:00
Matt Johnston
5abe22d1a5 Fix incorrect logic for USE_VFORK and calling arg_setup() 2013-03-31 23:29:03 +08:00
Matt Johnston
f6b304250b Try using writev() for writing packets out to tcp 2013-03-31 23:15:35 +08:00
Matt Johnston
36526700a9 Don't bother waiting for a ssh-connection service reply - the server
will disconnect if it wasn't accepted
2013-03-31 21:38:17 +08:00
Matt Johnston
32294978a3 merge
--HG--
branch : kexguess
2013-03-31 00:41:15 +08:00
Matt Johnston
a0e931005b send out our kexinit packet before blocking to read the SSH version string 2013-03-31 00:40:00 +08:00
Matt Johnston
9c7485331a Get rid of client/server specific buf_match_algo, use single
function with a couple of if statements instead

--HG--
branch : kexguess
2013-03-30 23:55:05 +08:00
Matt Johnston
99d9cf500b Add kexguess2 behaviour
--HG--
branch : kexguess
2013-03-29 23:29:48 +08:00
Matt Johnston
4f62da0f0d first_kex_packet_follows working, needs tidying
--HG--
branch : kexguess
2013-03-29 20:44:13 +08:00
Matt Johnston
b4bcc60657 More changes for KEX and ECDH. Set up hash descriptors, make ECC code work,
ses.hash and ses.session_id are now buffers (doesn't compile)

--HG--
branch : ecc
2013-03-29 00:28:09 +08:00
Matt Johnston
5139bd42f6 Set LTC_SOURCE for proper ltm_desc etc
--HG--
branch : ecc
2013-03-29 00:26:46 +08:00
Matt Johnston
cf7a271f90 ecc key import function
--HG--
branch : ecc
2013-03-27 23:50:52 +08:00
Matt Johnston
74cad1612f more bits on ecc branch
--HG--
branch : ecc
2013-03-27 00:38:03 +08:00
Matt Johnston
73e22c115c refactor kexdh code a bit, start working on ecdh etc
--HG--
branch : ecc
2013-03-26 01:35:22 +08:00
Matt Johnston
9be0d6b53d Define _GNU_SOURCE for vasprintf 2013-03-24 00:02:20 +08:00
Mike Frysinger
bbf6d5f2f5 rename configure.in -> configure.ac
Latest autotools warn now if the file is named configure.in

--HG--
rename : configure.in => configure.ac
2013-03-24 00:00:39 +08:00
Matt Johnston
c4861340e9 Fix a few compile warnings 2013-03-23 23:17:01 +08:00
Matt Johnston
5996c3824c Add ~. and ~^Z handling to exit/suspend dbclient 2013-03-23 23:16:06 +08:00
Matt Johnston
c172fb3b32 Added signature for changeset 9b80981212fe 2013-03-21 23:35:07 +08:00
Matt Johnston
03a0d11c4d Added tag DROPBEAR_2013.56 for changeset 1b8b2b9d6e94 2013-03-21 23:33:12 +08:00
112 changed files with 6784 additions and 2339 deletions

12
.hgsigs
View File

@@ -1,3 +1,15 @@
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 0 iD8DBQBOuADmjPn4sExkf7wRAv/fAJ9FJFvjDoF+wd1ipDx1wkzdeBQNqgCgykUrSbXv76FBbxKntVbk9oS3GjI=
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 0 iD8DBQBOuSlQjPn4sExkf7wRAvkbAKCgE1e8xEMQ16CGeoywhIQ0QR4eNgCfZdYYlzjb/+521Uvh5/7FRYEmrho=
85f835f2fe0ac2c503c50a414de127222fb0a57c 0 iD8DBQBPRkMUjPn4sExkf7wRAvM4AJ9mw2OAkyjhSbamM1MizlEJUX18HACgoFKQkYf6BnYxN34Nv2HhM0cmzUc=
9b80981212fe6c01b7c16b3ca7c4e66af56f12f1 0 iEYEABECAAYFAlFLKKcACgkQjPn4sExkf7xK7wCfcioCmJPsysSbQO6+4qZMVe0mmLwAn2/o+wRf4MrUXlohrr7aXEF9vdSB
095b46180bbc412b029420587736a6185afc17e1 0 iEYEABECAAYFAlFsCnkACgkQjPn4sExkf7xLrwCfeMWjUaSmfU/fvseT5TdrYRqBEVQAoLz5SFLEA40C5f8zE8Ma/vgVJVIC
f168962bab857ca030829e4cd73d9b32c868c874 0 iEYEABECAAYFAlFwDNwACgkQjPn4sExkf7wJ6QCePVovn/avKXUyNwNBYCcov6JLYqkAnRCPQdkXgv20N3t10r6PRMBBo1/S
deb211f75ca194e2fcf0d2e5f71c60474e42ec95 0 iEYEABECAAYFAlJO01cACgkQjPn4sExkf7yDqACaA/P+Yl/K2Cv3OC5G0b7ck2Kb75EAoIeW7qpCyclzJLWwk95koED+4lxD
025237c9f0a1a60a616f984d82fb2a9270d3b0ea 0 iEYEABECAAYFAlJeqDYACgkQjPn4sExkf7y5nQCfW6t+TJySBTTo+gCfDUBPRVxvNe8AoIn/15aWfqH/A2G9uikfoVtWK3pd
a50a1dc743317fad9b3737bc68fbca640659bb6d 0 iEYEABECAAYFAlJeqL0ACgkQjPn4sExkf7yVqACg6IP0fU29+Feh/TDeemDA+2XAzrIAoIdZfMDvVYlDoWotZD8ACFnf5H1P
9ec083a21adfcb099f21eb03704b66d14a4ba800 0 iEYEABECAAYFAlKE4JoACgkQjPn4sExkf7wLDgCghkVGwMjI138bEv+ORVzN7zIH7cEAoLckaxZc1k1aXlmlSCRlP8cuKH3o
3d1d7d151c0ce3a79da62e86463f5632fa2b144a 0 iEYEABECAAYFAlKd5AEACgkQjPn4sExkf7wzWgCfdvPEEIdlMPqcbOQMJ7b+eAyy164An2ip1lPh1eS5g26/gSfruvWBVym4
277429102f1337bd10c89107d3e01de509cc1a7e 0 iEYEABECAAYFAlMEvF4ACgkQjPn4sExkf7xeVQCgtbxJ4G3hsFwUOM0K1WGr1J2vsbEAoMM8dEyr1mdrbgO1tzNLfD1nxbyn
96584b934d04ebab443f603e78d38fe692d36313 0 iEYEABECAAYFAlPVFrQACgkQjPn4sExkf7xr6ACglRiLE21vRrS1rJ809o2yMADIKtwAn1f5SyZUngSde8eE55JxCMwtMC5m
caac692b366c153cea0e9cd59aa2d79a7d843d4e 0 iEYEABECAAYFAlPk1mcACgkQjPn4sExkf7wLpgCeOqMYqpkf4lYUuyrn9VYThNpc7PkAn3JOSNgIqkKUcmSy6FstrI8jwJzq
2d421bc0545d1be6d59a4ebfe61606d94b124b0c 0 iEYEABECAAYFAlRJDCQACgkQjPn4sExkf7xUYACcCwVJkYWXJn5x/D5A+qMupy778lEAn0rg1oNiq96YU/4jOPsS5IMItihu

11
.hgtags
View File

@@ -35,3 +35,14 @@ d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55
0000000000000000000000000000000000000000 t:ltc-0.95-orig
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
0000000000000000000000000000000000000000 t:ltc-0.95-db-merge1
1b8b2b9d6e94bc3cc5e61b620476ea36cc466e1b DROPBEAR_2013.56
96b8bcb88017815040949a417caa55686271e8a9 DROPBEAR_2013.57
e76614145aea67f66e4a4257685c771efba21aa1 DROPBEAR_2013.58
7b68e581985fd4ea50869f8608ab95cda5d17876 DROPBEAR_2013.59
a50a1dc743317fad9b3737bc68fbca640659bb6d DROPBEAR_2013.60
e894dbc015ba7ff4c3bf897ee20e28ca90c55a16 DROPBEAR_2013.61test
3d1d7d151c0ce3a79da62e86463f5632fa2b144a DROPBEAR_2013.62
2351b2da8e0d08dcc6e64fcc328b53b9630bda68 DROPBEAR_2014.63
0d2d39957c029adb7f4327d37fe6b4900f0736d9 DROPBEAR_2014.64
e9579816f20ea85affc6135e87f8477992808948 DROPBEAR_2014.65
735511a4c761141416ad0e6728989d2dafa55bc2 DROPBEAR_2014.66

20
.travis.yml Normal file
View File

@@ -0,0 +1,20 @@
language: c
compiler:
- gcc
script:
- autoconf && autoheader && ./configure $BUNDLEDLIBTOM CFLAGS="-O2 -Wall -Wno-pointer-sign" --prefix=$HOME/inst && make install
- ~/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
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq libz-dev libtomcrypt-dev libtommath-dev
env:
- BUNDLEDLIBTOM=--disable-bundled-libtom
- BUNDLEDLIBTOM=--enable-bundled-libtom
- MULTI=1

272
CHANGES
View File

@@ -1,3 +1,259 @@
2015.67 - Wednesday 28 January 2015
- Call fsync() after generating private keys to ensure they aren't lost if a
reboot occurs. Thanks to Peter Korsgaard
- Disable non-delayed zlib compression by default on the server. Can be
enabled if required for old clients with DROPBEAR_SERVER_DELAY_ZLIB
- Default client key path ~/.ssh/id_dropbear
- Prefer stronger algorithms by default, from Fedor Brunner.
AES256 over 3DES
Diffie-hellman group14 over group1
- Add option to disable CBC ciphers.
- Disable twofish in default options.h
- Enable sha2 HMAC algorithms by default, the code was already required
for ECC key exchange. sha1 is the first preference still for performance.
- Fix installing dropbear.8 in a separate build directory, from Like Ma
- Allow configure to succeed if libtomcrypt/libtommath are missing, from Elan Ruusamäe
- Don't crash if ssh-agent provides an unknown type of key. From Catalin Patulea
- Minor bug fixes, a few issues found by Coverity scan
2014.66 - Thursday 23 October 2014
- Use the same keepalive handling behaviour as OpenSSH. This will work better
with some SSH implementations that have different behaviour with unknown
message types.
- Don't reply with SSH_MSG_UNIMPLEMENTED when we receive a reply to our own
keepalive message
- Set $SSH_CLIENT to keep bash happy, patch from Ryan Cleere
- Fix wtmp which broke since 2013.62, patch from Whoopie
2014.65 - Friday 8 August 2014
- Fix 2014.64 regression, server session hang on exit with scp (and probably
others), thanks to NiLuJe for tracking it down
- Fix 2014.64 regression, clock_gettime() error handling which broke on older
Linux kernels, reported by NiLuJe
- Fix 2014.64 regression, writev() could occassionally fail with EAGAIN which
wasn't caught
- Avoid error message when trying to set QoS on proxycommand or multihop pipes
- Use /usr/bin/xauth, thanks to Mike Frysinger
- Don't exit the client if the local user entry can't be found, thanks to iquaba
2014.64 - Sunday 27 July 2014
- Fix compiling with ECDSA and DSS disabled
- Don't exit abruptly if too many outgoing packets are queued for writev(). Patch
thanks to Ronny Meeus
- The -K keepalive option now behaves more like OpenSSH's "ServerAliveInterval".
If no response is received after 3 keepalives then the session is terminated. This
will close connections faster than waiting for a TCP timeout.
- Rework TCP priority setting. New settings are
if (connecting || ptys || x11) tos = LOWDELAY
else if (tcp_forwards) tos = 0
else tos = BULK
Thanks to Catalin Patulea for the suggestion.
- Improve handling of many concurrent new TCP forwarded connections, should now
be able to handle as many as MAX_CHANNELS. Thanks to Eduardo Silva for reporting
and investigating it.
- Make sure that exit messages from the client are printed, regression in 2013.57
- Use monotonic clock where available, timeouts won't be affected by system time
changes
- Add -V for version
2014.63 - Wednesday 19 February 2014
- Fix ~. to terminate a client interactive session after waking a laptop
from sleep.
- Changed port separator syntax again, now using host^port. This is because
IPv6 link-local addresses use %. Reported by Gui Iribarren
- Avoid constantly relinking dropbearmulti target, fix "make install"
for multi target, thanks to Mike Frysinger
- Avoid getting stuck in a loop writing huge key files, reported by Bruno
Thomsen
- Don't link dropbearkey or dropbearconvert to libz or libutil,
thanks to Nicolas Boos
- Fix linking -lcrypt on systems without /usr/lib, thanks to Nicolas Boos
- Avoid crash on exit due to cleaned up keys before last packets are sent,
debugged by Ronald Wahl
- Fix a race condition in rekeying where Dropbear would exit if it received a
still-in-flight packet after initiating rekeying. Reported by Oliver Metz.
This is a longstanding bug but is triggered more easily since 2013.57
- Fix README for ecdsa keys, from Catalin Patulea
- Ensure that generated RSA keys are always exactly the length
requested. Previously Dropbear always generated N+16 or N+15 bit keys.
Thanks to Unit 193
- Fix DROPBEAR_CLI_IMMEDIATE_AUTH mode which saves a network round trip if the
first public key succeeds. Still not enabled by default, needs more
compatibility testing with other implementations.
- Fix for port 0 forwarding in the client and port forwarding with Apache MINA SSHD. Thanks to
- Fix for bad system linux/pkt-sched.h header file with older Linux
kernels, from Steve Dover
- Fix signal handlers so that errno is saved, thanks to Erik Ahlén for a patch
and Mark Wickham for independently spotting the same problem.
2013.62 - Tuesday 3 December 2013
- Disable "interactive" QoS connection options when a connection doesn't
have a PTY (eg scp, rsync). Thanks to Catalin Patulea for the patch.
- Log when a hostkey is generated with -R, fix some bugs in handling server
hostkey commandline options
- Fix crash in Dropbearconvert and 521 bit key, reported by NiLuJe
- Update config.guess and config.sub again
2013.61test - Thursday 14 November 2013
- ECC (elliptic curve) support. Supports ECDSA hostkeys (requires new keys to
be generated) and ECDH for setting up encryption keys (no intervention
required). This is significantly faster.
- curve25519-sha256@libssh.org support for setting up encryption keys. This is
another elliptic curve mode with less potential of NSA interference in
algorithm parameters. curve25519-donna code thanks to Adam Langley
- -R option to automatically generate hostkeys. This is recommended for
embedded platforms since it allows the system random number device
/dev/urandom a longer startup time to generate a secure seed before the
hostkey is required.
- Compile fixes for old vendor compilers like Tru64 from Daniel Richard G.
- Make authorized_keys handling more robust, don't exit encountering
malformed lines. Thanks to Lorin Hochstein and Mark Stillwell
2013.60 - Wednesday 16 October 2013
- Fix "make install" so that it doesn't always install to /bin and /sbin
- Fix "make install MULTI=1", installing manpages failed
- Fix "make install" when scp is included since it has no manpage
- Make --disable-bundled-libtom work
2013.59 - Friday 4 October 2013
- Fix crash from -J command
Thanks to Lluís Batlle i Rossell and Arnaud Mouiche for patches
- Avoid reading too much from /proc/net/rt_cache since that causes
system slowness.
- Improve EOF handling for half-closed connections
Thanks to Catalin Patulea
- Send a banner message to report PAM error messages intended for the user
Patch from Martin Donnelly
- Limit the size of decompressed payloads, avoids memory exhaustion denial
of service
Thanks to Logan Lamb for reporting and investigating it. CVE-2013-4421
- Avoid disclosing existence of valid users through inconsistent delays
Thanks to Logan Lamb for reporting. CVE-2013-4434
- Update config.guess and config.sub for newer architectures
- Avoid segfault in server for locked accounts
- "make install" now installs manpages
dropbearkey.8 has been renamed to dropbearkey.1
manpage added for dropbearconvert
- Get rid of one second delay when running non-interactive commands
2013.58 - Thursday 18 April 2013
- Fix building with Zlib disabled, thanks to Hans Harder and cuma@freetz
- Use % as a separator for ports, fixes scp in multihop mode, from Hans Harder
- Reject logins for other users when running as non-root, from Hans Harder
- Disable client immediate authentication request by default, it prevents
passwordless logins from working
2013.57 - Monday 15 April 2013
- Decreased connection setup time particularly with high latency connections,
the number of round trips has been reduced for both client and server.
CPU time hasn't been changed.
- Client will send an initial key exchange guess to save a round trip.
Dropbear implements an extension kexguess2@matt.ucc.asn.au to allow the first
packet guess to succeed in wider circumstances than the standard behaviour.
When communicating with other implementations the standard behaviour is used.
- Client side: when public key or password authentication with
$DROPBEAR_PASSWORD is used an initial authentication request will
be sent immediately rather than querying the list of available methods.
This behaviour is enabled by CLI_IMMEDIATE_AUTH option (on by default),
please let the Dropbear author know if it causes any interoperability
problems.
- Implement client escape characters ~. (terminate session) and
~^Z (background session)
- Server will more reliably clean up utmp when connection is closed, reported by
Mattias Walström
- Don't crash if /dev/urandom isn't writable (RHEL5), thanks to Scott Case
- Add "-y -y" client option to skip host key checking, thanks to Hans Harder
- scp didn't work properly on systems using vfork(), thanks to Frank Van Uffelen
- Added IUTF8 terminal mode support (Linux and Mac OS). Not standardised yet
though probably will be soon
- Some verbose DROPBEAR_TRACE output is now hidden unless $DROPBEAR_TRACE2
enviroment variable is set
- Fix using asymmetric MAC algorithms (broke in )
- Renamed configure.in to configure.ac to quieten autoconf, from Mike Frysinger
2013.56 - Thursday 21 March 2013
- Allow specifying cipher (-c) and MAC (-m) lists for dbclient
@@ -20,10 +276,10 @@
- Allow using IPv6 bracket notation for addresses in server "-p" option, from Ben Jencks
- A few improvements for Android from Reimar Döffinger
- A few improvements for Android from Reimar Döffinger
- Fix memory leak for TCP forwarded connections to hosts that timed out,
reported by Norbert Benczúr. Appears to be a very long-standing bug.
reported by Norbert Benczúr. Appears to be a very long-standing bug.
- Fix "make clean" for out of tree builds
@@ -235,7 +491,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
- Security: dbclient previously would prompt to confirm a
mismatching hostkey but wouldn't warn loudly. It will now
exit upon a mismatch.
exit upon a mismatch. CVE-2007-1099
- Compile fixes, make sure that all variable definitions are at the start
of a scope.
@@ -297,7 +553,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
(thanks to Tomas Vanek for helping track it down)
- Implement per-IP pre-authentication connection limits
(after some poking from Pablo Fernandez)
(after some poking from Pablo Fernandez) CVE-2006-1206
- Exit gracefully if trying to connect to as SSH v1 server
(reported by Rushi Lala)
@@ -318,7 +574,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
- SECURITY: fix for buffer allocation error in server code, could potentially
allow authenticated users to gain elevated privileges. All multi-user systems
running the server should upgrade (or apply the patch available on the
Dropbear webpage).
Dropbear webpage). CVE-2005-4178
- Fix channel handling code so that redirecting to /dev/null doesn't use
100% CPU.
@@ -525,7 +781,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
- SECURITY: Don't try to free() uninitialised variables in DSS verification
code. Thanks to Arne Bernin for pointing out this bug. This is possibly
exploitable, all users with DSS and pubkey-auth compiled in are advised to
upgrade.
upgrade. CVE-2004-2486
- Clean up agent forwarding socket files correctly, patch from Gerrit Pape.
@@ -649,7 +905,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
Lobenstock and Mihnea Stoenescu
- Use daemon() function if available (or our own copy) rather than separate
code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard
code (thanks to Frédéric Lavernhe for the report and debugging, and Bernard
Blackham for his suggestion on what to look at)
- Fixed up support for first_kex_packet_follows, required to talk to ssh.com
@@ -768,7 +1024,7 @@ https://secure.ucc.asn.au/hg/dropbear/graph/default
- Various signedness fixes
- Can listen on multiple ports
- added option to disable openpty with configure script,
(from K.-P. Kirchdörfer <kapeka at epost.de>)
(from K.-P. Kirchdörfer <kapeka at epost.de>)
- Various cleanups to bignum code
(thanks to Tom St Denis <tomstdenis at iahu.ca>)
- Fix compile error when disabling RSA

54
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-2008 Matt Johnston
Copyright (c) 2002-2014 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.
@@ -87,3 +87,55 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE 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.
=====
curve25519-donna:
/* Copyright 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* curve25519-donna: Curve25519 elliptic curve, public key function
*
* http://code.google.com/p/curve25519-donna/
*
* Adam Langley <agl@imperialviolet.org>
*
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
*
* More information about curve25519 can be found here
* http://cr.yp.to/ecdh.html
*
* djb's sample implementation of curve25519 is written in a special assembly
* language called qhasm and uses the floating point registers.
*
* This is, almost, a clean room reimplementation from the curve25519 paper. It
* uses many of the tricks described therein. Only the crecip function is taken
* from the sample implementation.
*/

4
MULTI
View File

@@ -20,7 +20,3 @@ etc
then execute as normal:
./dropbear <options here>
"make install" doesn't currently work for multi-binary configuration, though
in most situations where it is being used, the target and build systems will
differ.

View File

@@ -13,50 +13,54 @@ ifndef PROGRAMS
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
endif
LTC=libtomcrypt/libtomcrypt.a
LTM=libtommath/libtommath.a
STATIC_LTC=libtomcrypt/libtomcrypt.a
STATIC_LTM=libtommath/libtommath.a
LIBTOM_LIBS=@LIBTOM_LIBS@
ifeq (@BUNDLED_LIBTOM@, 1)
LIBTOM_DEPS=$(LTC) $(LTM)
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBS+=$(LTC) $(LTM)
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif
COMMONOBJS=dbutil.o buffer.o \
dss.o bignum.o \
signkey.o rsa.o random.o \
signkey.o rsa.o dbrandom.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o
atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
gensignkey.o gendss.o genrsa.o
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.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 \
svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
svr-tcpfwd.o svr-authpam.o
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-runopts.o cli-chansession.o \
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.o \
cli-agentfwd.o list.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 \
common-runopts.o circbuffer.o
common-runopts.o circbuffer.o curve25519-donna.o
KEYOBJS=dropbearkey.o gendss.o genrsa.o
KEYOBJS=dropbearkey.o
CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
dss.h bignum.h signkey.h rsa.h random.h service.h auth.h \
dss.h bignum.h signkey.h rsa.h dbrandom.h service.h auth.h \
debug.h channel.h chansession.h config.h queue.h sshpty.h \
termcodes.h gendss.h genrsa.h runopts.h includes.h \
loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
listener.h fake-rfc2553.h
listener.h fake-rfc2553.h ecc.h ecdsa.h
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) @CRYPTLIB@
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
@@ -66,9 +70,11 @@ VPATH=@srcdir@
srcdir=@srcdir@
prefix=@prefix@
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
sbindir=${exec_prefix}/sbin
exec_prefix=@exec_prefix@
datarootdir = @datarootdir@
bindir=@bindir@
sbindir=@sbindir@
mandir=@mandir@
CC=@CC@
AR=@AR@
@@ -120,36 +126,34 @@ strip: $(TARGETS)
install: $(addprefix inst_, $(TARGETS))
installdropbearmulti: insdbmulti $(addprefix insmulti, $(PROGRAMS))
insdbmulti: dropbearmulti
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
$(INSTALL) -m 755 dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)
-chown root $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
-chgrp 0 $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT)
insmultidropbear: dropbearmulti
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
$(INSTALL) -d $(DESTDIR)$(sbindir)
-rm -f $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-ln -s $(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
insmulti%: dropbearmulti
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
$(INSTALL) -d $(DESTDIR)$(bindir)
-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
# dropbear should go in sbin, so it needs a seperate rule
inst_dropbear: dropbear
$(INSTALL) -d -m 755 $(DESTDIR)$(sbindir)
$(INSTALL) -m 755 dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
-chown root $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
-chgrp 0 $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
$(INSTALL) -d $(DESTDIR)$(sbindir)
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 $(srcdir)/dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
inst_%: $*
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
$(INSTALL) -m 755 $*$(EXEEXT) $(DESTDIR)$(bindir)
-chown root $(DESTDIR)$(bindir)/$*$(EXEEXT)
-chgrp 0 $(DESTDIR)$(bindir)/$*$(EXEEXT)
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
inst_dropbearmulti: $(addprefix insmulti, $(PROGRAMS))
# for some reason the rule further down doesn't like $($@objs) as a prereq.
@@ -158,8 +162,14 @@ dbclient: $(dbclientobjs)
dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
dropbear: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
dbclient: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS) $(LIBS)
dropbearkey dropbearconvert: $(HEADERS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBTOM_LIBS)
# scp doesn't use the libs so is special.
scp: $(SCPOBJS) $(HEADERS) Makefile
@@ -169,14 +179,14 @@ scp: $(SCPOBJS) $(HEADERS) Makefile
# multi-binary compilation.
MULTIOBJS=
ifeq ($(MULTI),1)
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs))) @CRYPTLIB@
MULTIOBJS=dbmulti.o $(sort $(foreach prog, $(PROGRAMS), $($(prog)objs)))
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
dropbearmulti: multilink
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
multibinary: $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
multibinary: dropbearmulti$(EXEEXT)
multilink: multibinary $(addprefix link, $(PROGRAMS))
@@ -184,10 +194,10 @@ link%:
-rm -f $*$(EXEEXT)
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
$(LTC): options.h
cd libtomcrypt && $(MAKE) clean && $(MAKE)
$(STATIC_LTC): options.h
cd libtomcrypt && $(MAKE)
$(LTM): options.h
$(STATIC_LTM): options.h
cd libtommath && $(MAKE)
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean

12
README
View File

@@ -1,4 +1,4 @@
This is Dropbear, a smallish SSH 2 server and client.
This is Dropbear, a smallish SSH server and client.
https://matt.ucc.asn.au/dropbear/dropbear.html
INSTALL has compilation instructions.
@@ -42,8 +42,7 @@ If you have an OpenSSH-style private key ~/.ssh/id_rsa, you need to do:
dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_rsa.db
dbclient -i ~/.ssh/id_rsa.db <hostname>
Currently encrypted keys aren't supported, neither is agent forwarding. At some
stage both hopefully will be.
Dropbear does not support encrypted hostkeys though can connect to ssh-agent.
============================================================================
@@ -52,13 +51,18 @@ dropbearkey's '-y' option.
============================================================================
To run the server, you need to generate server keys, this is one-off:
To run the server, you need to 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
or alternatively convert OpenSSH keys to Dropbear:
./dropbearconvert openssh dropbear /etc/ssh/ssh_host_dsa_key dropbear_dss_host_key
You can also get Dropbear to create keys when the first connection is made -
this is preferable to generating keys when the system boots. Make sure
/etc/dropbear/ exists and then pass '-R' to the dropbear server.
============================================================================
If the server is run as non-root, you most likely won't be able to allocate a

View File

@@ -40,7 +40,7 @@
/* client functions */
void cli_load_agent_keys(m_list * ret_list);
void agent_buf_sign(buffer *sigblob, sign_key *key,
const unsigned char *data, unsigned int len);
buffer *data_buf);
void cli_setup_agent(struct Channel *channel);
#ifdef __hpux

61
algo.h
View File

@@ -35,7 +35,7 @@
struct Algo_Type {
unsigned char *name; /* identifying name */
const unsigned char *name; /* identifying name */
char val; /* a value for this cipher, or -1 for invalid */
const void *data; /* algorithm specific data */
char usable; /* whether we can use this algorithm */
@@ -51,6 +51,7 @@ extern algo_type sshhostkey[];
extern algo_type sshciphers[];
extern algo_type sshhashes[];
extern algo_type ssh_compress[];
extern algo_type ssh_delaycompress[];
extern algo_type ssh_nocompress[];
extern const struct dropbear_cipher dropbear_nocipher;
@@ -59,8 +60,8 @@ extern const struct dropbear_hash dropbear_nohash;
struct dropbear_cipher {
const struct ltc_cipher_descriptor *cipherdesc;
unsigned long keysize;
unsigned char blocksize;
const unsigned long keysize;
const unsigned char blocksize;
};
struct dropbear_cipher_mode {
@@ -74,19 +75,52 @@ struct dropbear_cipher_mode {
};
struct dropbear_hash {
const struct ltc_hash_descriptor *hashdesc;
unsigned long keysize;
unsigned char hashsize;
const struct ltc_hash_descriptor *hash_desc;
const unsigned long keysize;
/* hashsize may be truncated from the size returned by hash_desc,
eg sha1-96 */
const unsigned char hashsize;
};
enum dropbear_kex_mode {
DROPBEAR_KEX_NORMAL_DH,
DROPBEAR_KEX_ECDH,
DROPBEAR_KEX_CURVE25519,
};
struct dropbear_kex {
enum dropbear_kex_mode mode;
/* "normal" DH KEX */
const unsigned char *dh_p_bytes;
const int dh_p_len;
/* elliptic curve DH KEX */
#ifdef DROPBEAR_ECDH
const struct dropbear_ecc_curve *ecc_curve;
#else
const void* dummy;
#endif
/* both */
const struct ltc_hash_descriptor *hash_desc;
};
void crypto_init();
int have_algo(char* algo, size_t algolen, algo_type algos[]);
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess);
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess);
enum kexguess2_used {
KEXGUESS2_LOOK,
KEXGUESS2_NO,
KEXGUESS2_YES,
};
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
#define KEXGUESS2_ALGO_ID 99
algo_type * buf_match_algo(buffer* buf, algo_type localalgos[],
enum kexguess2_used *kexguess2, int *goodguess);
#ifdef ENABLE_USER_ALGO_LIST
int check_user_algos(const char* user_algo_list, algo_type * algos,
@@ -94,5 +128,10 @@ int check_user_algos(const char* user_algo_list, algo_type * algos,
char * algolist_string(algo_type algos[]);
#endif
enum {
DROPBEAR_COMP_NONE,
DROPBEAR_COMP_ZLIB,
DROPBEAR_COMP_ZLIB_DELAY,
};
#endif /* _ALGO_H_ */

5
auth.h
View File

@@ -36,6 +36,7 @@ void cli_authinitialise();
void recv_msg_userauth_request();
void send_msg_userauth_failure(int partial, int incrfail);
void send_msg_userauth_success();
void send_msg_userauth_banner(buffer *msg);
void svr_auth_password();
void svr_auth_pubkey();
void svr_auth_pam();
@@ -67,7 +68,7 @@ void recv_msg_userauth_pk_ok();
void recv_msg_userauth_info_request();
void cli_get_user();
void cli_auth_getmethods();
void cli_auth_try();
int cli_auth_try();
void recv_msg_userauth_banner();
void cli_pubkeyfail();
void cli_auth_password();
@@ -105,7 +106,7 @@ struct AuthState {
valid */
unsigned int failcount; /* Number of (failed) authentication attempts.*/
unsigned authdone : 1; /* 0 if we haven't authed, 1 if we have. Applies for
client and server (though has differing [obvious]
client and server (though has differing
meanings). */
unsigned perm_warn : 1; /* Server only, set if bad permissions on
~/.ssh/authorized_keys have already been

View File

@@ -52,6 +52,22 @@ void m_mp_init_multi(mp_int *mp, ...)
va_end(args);
}
void m_mp_alloc_init_multi(mp_int **mp, ...)
{
mp_int** cur_arg = mp;
va_list args;
va_start(args, mp); /* init args to next argument from caller */
while (cur_arg != NULL) {
*cur_arg = m_malloc(sizeof(mp_int));
if (mp_init(*cur_arg) != MP_OKAY) {
dropbear_exit("Mem alloc error");
}
cur_arg = va_arg(args, mp_int**);
}
va_end(args);
}
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) {
@@ -60,16 +76,13 @@ void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
}
/* hash the ssh representation of the mp_int mp */
void sha1_process_mp(hash_state *hs, mp_int *mp) {
int i;
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, mp_int *mp) {
buffer * buf;
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
plus header + some leeway*/
buf_putmpint(buf, mp);
i = buf->pos;
buf_setpos(buf, 0);
sha1_process(hs, buf_getptr(buf, i), i);
hash_desc->process(hs, buf->data, buf->len);
buf_free(buf);
}

View File

@@ -26,10 +26,13 @@
#define _BIGNUM_H_
#include "includes.h"
#include "dbutil.h"
void m_mp_init(mp_int *mp);
void m_mp_init_multi(mp_int *mp, ...);
void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
void sha1_process_mp(hash_state *hs, mp_int *mp);
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
hash_state *hs, mp_int *mp);
#endif /* _BIGNUM_H_ */

View File

@@ -269,6 +269,11 @@ void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len) {
}
/* puts an entire buffer as a SSH string. ignore pos of buf_str. */
void buf_putbufstring(buffer *buf, const buffer* buf_str) {
buf_putstring(buf, buf_str->data, buf_str->len);
}
/* put the set of len bytes into the buffer, incrementing the pos, increasing
* len if required */
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
@@ -282,7 +287,7 @@ void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len) {
void buf_putmpint(buffer* buf, mp_int * mp) {
unsigned int len, pad = 0;
TRACE(("enter buf_putmpint"))
TRACE2(("enter buf_putmpint"))
dropbear_assert(mp != NULL);
@@ -318,7 +323,7 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
buf_incrwritepos(buf, len-pad);
}
TRACE(("leave buf_putmpint"))
TRACE2(("leave buf_putmpint"))
}
/* Retrieve an mp_int from the buffer.

View File

@@ -59,6 +59,7 @@ buffer * buf_getstringbuf(buffer *buf);
void buf_eatstring(buffer *buf);
void buf_putint(buffer* buf, unsigned int val);
void buf_putstring(buffer* buf, const unsigned char* str, unsigned int len);
void buf_putbufstring(buffer *buf, const buffer* buf_str);
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
void buf_putmpint(buffer* buf, mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp);

View File

@@ -29,14 +29,6 @@
#include "buffer.h"
#include "circbuffer.h"
/* channel->type values */
#define CHANNEL_ID_NONE 0
#define CHANNEL_ID_SESSION 1
#define CHANNEL_ID_X11 2
#define CHANNEL_ID_AGENT 3
#define CHANNEL_ID_TCPDIRECT 4
#define CHANNEL_ID_TCPFORWARDED 5
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
#define SSH_OPEN_CONNECT_FAILED 2
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
@@ -49,6 +41,13 @@
struct ChanType;
enum dropbear_channel_prio {
DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */
DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */
DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */
DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */
};
struct Channel {
unsigned int index; /* the local channel index */
@@ -83,8 +82,12 @@ struct Channel {
int flushing;
/* Used by client chansession to handle ~ escaping, NULL ignored otherwise */
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
const struct ChanType* type;
enum dropbear_channel_prio prio;
};
struct ChanType {
@@ -95,7 +98,6 @@ struct ChanType {
int (*check_close)(struct Channel*);
void (*reqhandler)(struct Channel*);
void (*closehandler)(struct Channel*);
};
void chaninitialise(const struct ChanType *chantypes[]);
@@ -103,6 +105,9 @@ void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel();
/* Returns an arbitrary channel that is in a ready state - not
being initialised and no EOF in either direction. NULL if none. */
struct Channel* get_any_ready_channel();
void recv_msg_channel_open();
void recv_msg_channel_request();
@@ -126,5 +131,10 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type);
void recv_msg_channel_open_confirmation();
void recv_msg_channel_open_failure();
#endif
void start_send_channel_request(struct Channel *channel, unsigned char *type);
void send_msg_request_success();
void send_msg_request_failure();
#endif /* _CHANNEL_H_ */

View File

@@ -51,9 +51,12 @@ struct ChanSess {
/* exit details */
struct exitinfo exit;
/* Used to set $SSH_CONNECTION in the child session.
Is only set temporarily before forking */
/* These are only set temporarily before forking */
/* Used to set $SSH_CONNECTION in the child session. */
char *connection_string;
/* Used to set $SSH_CLIENT in the child session. */
char *client_string;
#ifndef DISABLE_X11FWD
struct Listener * x11listener;
@@ -89,7 +92,6 @@ void cli_chansess_winchange();
#ifdef ENABLE_CLI_NETCAT
void cli_send_netcat_request();
#endif
void cli_start_send_channel_request(struct Channel *channel, unsigned char *type);
void svr_chansessinitialise();
extern const struct ChanType svrchansess;

View File

@@ -34,7 +34,7 @@
#include "channel.h"
#include "packet.h"
#include "buffer.h"
#include "random.h"
#include "dbrandom.h"
#include "listener.h"
#include "runopts.h"
#include "atomicio.h"
@@ -73,8 +73,8 @@ static int connect_agent() {
return fd;
}
// handle a request for a connection to the locally running ssh-agent
// or forward.
/* handle a request for a connection to the locally running ssh-agent
or forward. */
static int new_agent_chan(struct Channel * channel) {
int fd = -1;
@@ -94,7 +94,6 @@ static int new_agent_chan(struct Channel * channel) {
channel->readfd = fd;
channel->writefd = fd;
// success
return 0;
}
@@ -156,8 +155,6 @@ static buffer * agent_request(unsigned char type, buffer *data) {
goto out;
}
TRACE(("agent_request readlen is %d", readlen))
buf_resize(inbuf, readlen);
buf_setpos(inbuf, 0);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
@@ -167,7 +164,6 @@ static buffer * agent_request(unsigned char type, buffer *data) {
}
buf_incrwritepos(inbuf, readlen);
buf_setpos(inbuf, 0);
TRACE(("agent_request success, length %d", readlen))
out:
if (payload)
@@ -205,7 +201,7 @@ static void agent_get_key_list(m_list * ret_list)
num = buf_getint(inbuf);
for (i = 0; i < num; i++) {
sign_key * pubkey = NULL;
int key_type = DROPBEAR_SIGNKEY_ANY;
enum signkey_type key_type = DROPBEAR_SIGNKEY_ANY;
buffer * key_buf;
/* each public key is encoded as a string */
@@ -214,13 +210,14 @@ static void agent_get_key_list(m_list * ret_list)
ret = buf_get_pub_key(key_buf, pubkey, &key_type);
buf_free(key_buf);
if (ret != DROPBEAR_SUCCESS) {
/* This is slack, properly would cleanup vars etc */
dropbear_exit("Bad pubkey received from agent");
}
pubkey->type = key_type;
pubkey->source = SIGNKEY_SOURCE_AGENT;
TRACE(("Skipping bad/unknown type pubkey from agent"));
sign_key_free(pubkey);
} else {
pubkey->type = key_type;
pubkey->source = SIGNKEY_SOURCE_AGENT;
list_append(ret_list, pubkey);
list_append(ret_list, pubkey);
}
/* We'll ignore the comment for now. might want it later.*/
buf_eatstring(inbuf);
@@ -238,7 +235,7 @@ void cli_setup_agent(struct Channel *channel) {
return;
}
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
start_send_channel_request(channel, "auth-agent-req@openssh.com");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
encrypt_packet();
@@ -257,7 +254,7 @@ void cli_load_agent_keys(m_list *ret_list) {
}
void agent_buf_sign(buffer *sigblob, sign_key *key,
const unsigned char *data, unsigned int len) {
buffer *data_buf) {
buffer *request_data = NULL;
buffer *response = NULL;
unsigned int siglen;
@@ -269,10 +266,10 @@ void agent_buf_sign(buffer *sigblob, sign_key *key,
string data
uint32 flags
*/
request_data = buf_new(MAX_PUBKEY_SIZE + len + 12);
request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
buf_put_pub_key(request_data, key, key->type);
buf_putstring(request_data, data, len);
buf_putbufstring(request_data, data_buf);
buf_putint(request_data, 0);
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);

View File

@@ -1,99 +0,0 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "algo.h"
#include "dbutil.h"
/*
* The chosen [encryption | MAC | compression] algorithm to each
* direction MUST be the first algorithm on the client's list
* that is also on the server's list.
*/
algo_type * cli_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess) {
unsigned char * algolist = NULL;
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int count, i, j;
algo_type * ret = NULL;
*goodguess = 0;
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
TRACE(("cli_buf_match_algo: %s", algolist))
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
goto out; /* just a sanity check, no other use */
}
/* remotealgos will contain a list of the strings parsed out */
/* We will have at least one string (even if it's just "") */
remotealgos[0] = algolist;
count = 1;
/* Iterate through, replacing ','s with NULs, to split it into
* words. */
for (i = 0; i < len; i++) {
if (algolist[i] == '\0') {
/* someone is trying something strange */
goto out;
}
if (algolist[i] == ',') {
algolist[i] = '\0';
remotealgos[count] = &algolist[i+1];
count++;
}
if (count >= MAX_PROPOSED_ALGO) {
break;
}
}
/* iterate and find the first match */
for (j = 0; localalgos[j].name != NULL; j++) {
if (localalgos[j].usable) {
len = strlen(localalgos[j].name);
for (i = 0; i < count; i++) {
if (len == strlen(remotealgos[i])
&& strncmp(localalgos[j].name,
remotealgos[i], len) == 0) {
if (i == 0 && j == 0) {
/* was a good guess */
*goodguess = 1;
}
ret = &localalgos[j];
goto out;
}
}
}
}
out:
m_free(algolist);
return ret;
}

View File

@@ -40,11 +40,8 @@ void cli_authinitialise() {
/* Send a "none" auth request to get available methods */
void cli_auth_getmethods() {
TRACE(("enter cli_auth_getmethods"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_REQUEST);
buf_putstring(ses.writepayload, cli_opts.username,
strlen(cli_opts.username));
@@ -53,8 +50,27 @@ void cli_auth_getmethods() {
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
encrypt_packet();
TRACE(("leave cli_auth_getmethods"))
#ifdef DROPBEAR_CLI_IMMEDIATE_AUTH
/* We can't haven't two auth requests in-flight with delayed zlib mode
since if the first one succeeds then the remote side will
expect the second one to be compressed.
Race described at
http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/zlib-openssh.html
*/
if (ses.keys->trans.algo_comp != DROPBEAR_COMP_ZLIB_DELAY) {
ses.authstate.authtypes = AUTH_TYPE_PUBKEY;
if (getenv(DROPBEAR_PASSWORD_ENV)) {
ses.authstate.authtypes |= AUTH_TYPE_PASSWORD | AUTH_TYPE_INTERACT;
}
if (cli_auth_try() == DROPBEAR_SUCCESS) {
TRACE(("skipped initial none auth query"))
/* Note that there will be two auth responses in-flight */
cli_ses.ignore_next_auth_response = 1;
}
}
#endif
TRACE(("leave cli_auth_getmethods"))
}
void recv_msg_userauth_banner() {
@@ -144,31 +160,46 @@ void recv_msg_userauth_failure() {
TRACE(("<- MSG_USERAUTH_FAILURE"))
TRACE(("enter recv_msg_userauth_failure"))
if (ses.authstate.authdone) {
TRACE(("leave recv_msg_userauth_failure, already authdone."))
return;
}
if (cli_ses.state != USERAUTH_REQ_SENT) {
/* Perhaps we should be more fatal? */
dropbear_exit("Unexpected userauth failure");
}
/* When DROPBEAR_CLI_IMMEDIATE_AUTH is set there will be an initial response for
the "none" auth request, and then a response to the immediate auth request.
We need to be careful handling them. */
if (cli_ses.ignore_next_auth_response) {
cli_ses.state = USERAUTH_REQ_SENT;
cli_ses.ignore_next_auth_response = 0;
TRACE(("leave recv_msg_userauth_failure, ignored response, state set to USERAUTH_REQ_SENT"));
return;
} else {
#ifdef ENABLE_CLI_PUBKEY_AUTH
/* If it was a pubkey auth request, we should cross that key
* off the list. */
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
cli_pubkeyfail();
}
/* If it was a pubkey auth request, we should cross that key
* off the list. */
if (cli_ses.lastauthtype == AUTH_TYPE_PUBKEY) {
cli_pubkeyfail();
}
#endif
#ifdef ENABLE_CLI_INTERACT_AUTH
/* If we get a failure message for keyboard interactive without
* receiving any request info packet, then we don't bother trying
* keyboard interactive again */
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
&& !cli_ses.interact_request_received) {
TRACE(("setting auth_interact_failed = 1"))
cli_ses.auth_interact_failed = 1;
}
/* If we get a failure message for keyboard interactive without
* receiving any request info packet, then we don't bother trying
* keyboard interactive again */
if (cli_ses.lastauthtype == AUTH_TYPE_INTERACT
&& !cli_ses.interact_request_received) {
TRACE(("setting auth_interact_failed = 1"))
cli_ses.auth_interact_failed = 1;
}
#endif
cli_ses.lastauthtype = AUTH_TYPE_NONE;
cli_ses.state = USERAUTH_FAIL_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
}
methods = buf_getstring(ses.payload, &methlen);
@@ -221,13 +252,14 @@ void recv_msg_userauth_failure() {
}
m_free(methods);
cli_ses.state = USERAUTH_FAIL_RCVD;
TRACE(("leave recv_msg_userauth_failure"))
}
void recv_msg_userauth_success() {
/* This function can validly get called multiple times
if DROPBEAR_CLI_IMMEDIATE_AUTH is set */
TRACE(("received msg_userauth_success"))
/* Note: in delayed-zlib mode, setting authdone here
* will enable compression in the transport layer */
@@ -240,7 +272,7 @@ void recv_msg_userauth_success() {
#endif
}
void cli_auth_try() {
int cli_auth_try() {
int finished = 0;
TRACE(("enter cli_auth_try"))
@@ -256,37 +288,40 @@ void cli_auth_try() {
}
#endif
#ifdef ENABLE_CLI_INTERACT_AUTH
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
} else if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
if (cli_ses.auth_interact_failed) {
finished = 0;
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_PASSWORD)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
} else {
cli_auth_interactive();
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
cli_auth_password();
finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
}
}
#endif
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use password auth unencrypted.\n");
} else if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
cli_auth_password();
finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
#ifdef ENABLE_CLI_INTERACT_AUTH
if (!finished && (ses.authstate.authtypes & AUTH_TYPE_INTERACT)) {
if (ses.keys->trans.algo_crypt->cipherdesc == NULL) {
fprintf(stderr, "Sorry, I won't let you use interactive auth unencrypted.\n");
} else {
if (!cli_ses.auth_interact_failed) {
cli_auth_interactive();
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
finished = 1;
}
}
}
#endif
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
if (!finished) {
dropbear_exit("No auth methods could be used.");
if (finished) {
TRACE(("leave cli_auth_try success"))
return DROPBEAR_SUCCESS;
}
TRACE(("leave cli_auth_try"))
TRACE(("leave cli_auth_try failure"))
return DROPBEAR_FAILURE;
}
/* A helper for getpass() that exits if the user cancels. The returned

View File

@@ -121,23 +121,19 @@ void recv_msg_userauth_pk_ok() {
}
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
const unsigned char *data, unsigned int len)
{
buffer *data_buf) {
#ifdef ENABLE_CLI_AGENTFWD
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, len);
buf_setpos(sigblob, 0);
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
sigblob->len);
agent_buf_sign(sigblob, key, data_buf);
buf_putbufstring(buf, sigblob);
buf_free(sigblob);
} else
#endif /* ENABLE_CLI_AGENTFWD */
{
buf_put_sign(buf, key, type, data, len);
buf_put_sign(buf, key, type, data_buf);
}
}
@@ -173,10 +169,10 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
TRACE(("realsign"))
/* We put the signature as well - this contains string(session id), then
* the contents of the write payload to this point */
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
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->data, sigbuf->len);
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
buf_free(sigbuf); /* Nothing confidential in the buffer */
}

View File

@@ -38,9 +38,10 @@
static void cli_closechansess(struct Channel *channel);
static int cli_initchansess(struct Channel *channel);
static void cli_chansessreq(struct Channel *channel);
static void send_chansess_pty_req(struct Channel *channel);
static void send_chansess_shell_req(struct Channel *channel);
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
static int cli_init_netcat(struct Channel *channel);
static void cli_tty_setup();
@@ -70,7 +71,9 @@ static void cli_chansessreq(struct Channel *channel) {
TRACE(("got exit-signal, ignoring it"))
} else {
TRACE(("unknown request '%s'", type))
send_msg_channel_failure(channel);
if (wantreply) {
send_msg_channel_failure(channel);
}
goto out;
}
@@ -81,25 +84,12 @@ out:
/* If the main session goes, we close it up */
static void cli_closechansess(struct Channel *UNUSED(channel)) {
cli_tty_cleanup(); /* Restore tty modes etc */
/* This channel hasn't gone yet, so we have > 1 */
if (ses.chancount > 1) {
dropbear_log(LOG_INFO, "Waiting for other channels to close...");
}
cli_tty_cleanup(); /* Restore tty modes etc */
}
void cli_start_send_channel_request(struct Channel *channel,
unsigned char *type) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
buf_putint(ses.writepayload, channel->remotechan);
buf_putstring(ses.writepayload, type, strlen(type));
}
/* Taken from OpenSSH's sshtty.c:
@@ -286,7 +276,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
TRACE(("enter send_chansess_pty_req"))
cli_start_send_channel_request(channel, "pty-req");
start_send_channel_request(channel, "pty-req");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
@@ -329,7 +319,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
reqtype = "shell";
}
cli_start_send_channel_request(channel, reqtype);
start_send_channel_request(channel, reqtype);
/* XXX TODO */
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
@@ -356,6 +346,11 @@ static int cli_init_stdpipe_sess(struct Channel *channel) {
return 0;
}
static int cli_init_netcat(struct Channel *channel) {
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
return cli_init_stdpipe_sess(channel);
}
static int cli_initchansess(struct Channel *channel) {
cli_init_stdpipe_sess(channel);
@@ -368,13 +363,18 @@ static int cli_initchansess(struct Channel *channel) {
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
} else {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
send_chansess_shell_req(channel);
if (cli_opts.wantpty) {
cli_tty_setup();
}
channel->read_mangler = cli_escape_handler;
cli_ses.last_char = '\r';
}
return 0; /* Success */
}
@@ -384,7 +384,7 @@ static int cli_initchansess(struct Channel *channel) {
static const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_stdpipe_sess, /* inithandler */
cli_init_netcat, /* inithandler */
NULL,
NULL,
cli_closechansess
@@ -395,6 +395,7 @@ void cli_send_netcat_request() {
const unsigned char* source_host = "127.0.0.1";
const int source_port = 22;
TRACE(("enter cli_send_netcat_request"))
cli_opts.wantpty = 0;
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
@@ -411,7 +412,7 @@ void cli_send_netcat_request() {
buf_putint(ses.writepayload, source_port);
encrypt_packet();
TRACE(("leave cli_send_chansess_request"))
TRACE(("leave cli_send_netcat_request"))
}
#endif
@@ -429,3 +430,59 @@ void cli_send_chansess_request() {
TRACE(("leave cli_send_chansess_request"))
}
/* returns 1 if the character should be consumed, 0 to pass through */
static int
do_escape(unsigned char c) {
switch (c) {
case '.':
dropbear_exit("Terminated");
return 1;
break;
case 0x1a:
/* ctrl-z */
cli_tty_cleanup();
kill(getpid(), SIGTSTP);
/* after continuation */
cli_tty_setup();
cli_ses.winchange = 1;
return 1;
break;
}
return 0;
}
static
void cli_escape_handler(struct Channel* UNUSED(channel), unsigned char* buf, int *len) {
char c;
int skip_char = 0;
/* only handle escape characters if they are read one at a time. simplifies
the code and avoids nasty people putting ~. at the start of a line to paste */
if (*len != 1) {
cli_ses.last_char = 0x0;
return;
}
c = buf[0];
if (cli_ses.last_char == DROPBEAR_ESCAPE_CHAR) {
skip_char = do_escape(c);
cli_ses.last_char = 0x0;
} else {
if (c == DROPBEAR_ESCAPE_CHAR) {
if (cli_ses.last_char == '\r') {
cli_ses.last_char = DROPBEAR_ESCAPE_CHAR;
skip_char = 1;
} else {
cli_ses.last_char = 0x0;
}
} else {
cli_ses.last_char = c;
}
}
if (skip_char) {
*len = 0;
}
}

139
cli-kex.c
View File

@@ -33,44 +33,73 @@
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
#include "random.h"
#include "dbrandom.h"
#include "runopts.h"
#include "signkey.h"
#include "ecc.h"
static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
#define MAX_KNOWNHOSTS_LINE 4500
void send_msg_kexdh_init() {
cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
m_mp_init_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
gen_kexdh_vals(cli_ses.dh_e, cli_ses.dh_x);
TRACE(("send_msg_kexdh_init()"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
buf_putmpint(ses.writepayload, cli_ses.dh_e);
switch (ses.newkeys->algo_kex->mode) {
case DROPBEAR_KEX_NORMAL_DH:
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.dh_param) {
if (cli_ses.dh_param) {
free_kexdh_param(cli_ses.dh_param);
}
cli_ses.dh_param = gen_kexdh_param();
}
buf_putmpint(ses.writepayload, &cli_ses.dh_param->pub);
break;
case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.ecdh_param) {
if (cli_ses.ecdh_param) {
free_kexecdh_param(cli_ses.ecdh_param);
}
cli_ses.ecdh_param = gen_kexecdh_param();
}
buf_put_ecc_raw_pubkey_string(ses.writepayload, &cli_ses.ecdh_param->key);
#endif
break;
#ifdef DROPBEAR_CURVE25519
case DROPBEAR_KEX_CURVE25519:
if (ses.newkeys->algo_kex != cli_ses.param_kex_algo
|| !cli_ses.curve25519_param) {
if (cli_ses.curve25519_param) {
free_kexcurve25519_param(cli_ses.curve25519_param);
}
cli_ses.curve25519_param = gen_kexcurve25519_param();
}
buf_putstring(ses.writepayload, cli_ses.curve25519_param->pub, CURVE25519_LEN);
#endif
break;
}
cli_ses.param_kex_algo = ses.newkeys->algo_kex;
encrypt_packet();
ses.requirenext = SSH_MSG_KEXDH_REPLY;
}
/* Handle a diffie-hellman key exchange reply. */
void recv_msg_kexdh_reply() {
DEF_MP_INT(dh_f);
sign_key *hostkey = NULL;
unsigned int type, keybloblen;
unsigned char* keyblob = NULL;
TRACE(("enter recv_msg_kexdh_reply"))
if (cli_ses.kex_state != KEXDH_INIT_SENT) {
dropbear_exit("Received out-of-order kexdhreply");
}
m_mp_init(&dh_f);
type = ses.newkeys->algo_hostkey;
TRACE(("type is %d", type))
@@ -88,19 +117,59 @@ void recv_msg_kexdh_reply() {
dropbear_exit("Bad KEX packet");
}
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
TRACE(("failed getting mpint"))
dropbear_exit("Bad KEX packet");
switch (ses.newkeys->algo_kex->mode) {
case DROPBEAR_KEX_NORMAL_DH:
{
DEF_MP_INT(dh_f);
m_mp_init(&dh_f);
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
TRACE(("failed getting mpint"))
dropbear_exit("Bad KEX packet");
}
kexdh_comb_key(cli_ses.dh_param, &dh_f, hostkey);
mp_clear(&dh_f);
}
break;
case DROPBEAR_KEX_ECDH:
#ifdef DROPBEAR_ECDH
{
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
kexecdh_comb_key(cli_ses.ecdh_param, ecdh_qs, hostkey);
buf_free(ecdh_qs);
}
#endif
break;
#ifdef DROPBEAR_CURVE25519
case DROPBEAR_KEX_CURVE25519:
{
buffer *ecdh_qs = buf_getstringbuf(ses.payload);
kexcurve25519_comb_key(cli_ses.curve25519_param, ecdh_qs, hostkey);
buf_free(ecdh_qs);
}
#endif
break;
}
kexdh_comb_key(cli_ses.dh_e, cli_ses.dh_x, &dh_f, hostkey);
mp_clear(&dh_f);
mp_clear_multi(cli_ses.dh_e, cli_ses.dh_x, NULL);
m_free(cli_ses.dh_e);
m_free(cli_ses.dh_x);
if (cli_ses.dh_param) {
free_kexdh_param(cli_ses.dh_param);
cli_ses.dh_param = NULL;
}
#ifdef DROPBEAR_ECDH
if (cli_ses.ecdh_param) {
free_kexecdh_param(cli_ses.ecdh_param);
cli_ses.ecdh_param = NULL;
}
#endif
#ifdef DROPBEAR_CURVE25519
if (cli_ses.curve25519_param) {
free_kexcurve25519_param(cli_ses.curve25519_param);
cli_ses.curve25519_param = NULL;
}
#endif
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
!= DROPBEAR_SUCCESS) {
cli_ses.param_kex_algo = NULL;
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
dropbear_exit("Bad hostkey signature");
}
@@ -112,7 +181,8 @@ void recv_msg_kexdh_reply() {
TRACE(("leave recv_msg_kexdh_init"))
}
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen,
const char* algoname) {
char* fp = NULL;
FILE *tty = NULL;
@@ -120,14 +190,16 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
fp = sign_key_fingerprint(keyblob, keybloblen);
if (cli_opts.always_accept_key) {
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(fingerprint %s)\n",
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(%s fingerprint %s)\n",
cli_opts.remotehost,
algoname,
fp);
m_free(fp);
return;
}
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n) ",
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ",
cli_opts.remotehost,
algoname,
fp);
m_free(fp);
@@ -217,16 +289,22 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
buffer * line = NULL;
int ret;
if (cli_opts.no_hostkey_check) {
fprintf(stderr, "Caution, skipping hostkey check for %s\n", cli_opts.remotehost);
return;
}
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
hostsfile = open_known_hosts_file(&readonly);
if (!hostsfile) {
ask_to_confirm(keyblob, keybloblen);
ask_to_confirm(keyblob, keybloblen, algoname);
/* ask_to_confirm will exit upon failure */
return;
}
line = buf_new(MAX_KNOWNHOSTS_LINE);
hostlen = strlen(cli_opts.remotehost);
algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen);
do {
if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
@@ -246,7 +324,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
/* Compare hostnames */
if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
hostlen) != 0) {
TRACE(("hosts don't match"))
continue;
}
@@ -280,17 +357,18 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
/* The keys didn't match. eep. Note that we're "leaking"
the fingerprint strings here, but we're exiting anyway */
dropbear_exit("\n\nHost key mismatch for %s !\n"
dropbear_exit("\n\n%s host key mismatch for %s !\n"
"Fingerprint is %s\n"
"Expected %s\n"
"If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts",
algoname,
cli_opts.remotehost,
sign_key_fingerprint(keyblob, keybloblen),
fingerprint ? fingerprint : "UNKNOWN");
} while (1); /* keep going 'til something happens */
/* Key doesn't exist yet */
ask_to_confirm(keyblob, keybloblen);
ask_to_confirm(keyblob, keybloblen, algoname);
/* If we get here, they said yes */
@@ -309,7 +387,6 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
buf_putbytes(line, algoname, algolen);
buf_putbyte(line, ' ');
len = line->size - line->pos;
TRACE(("keybloblen %d, len %d", keybloblen, len))
/* The only failure with base64 is buffer_overflow, but buf_getwriteptr
* will die horribly in the case anyway */
base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len);

View File

@@ -28,6 +28,8 @@
#include "dbutil.h"
#include "runopts.h"
#include "session.h"
#include "dbrandom.h"
#include "crypto_desc.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);
@@ -51,6 +53,9 @@ int main(int argc, char ** argv) {
disallow_core();
seedrandom();
crypto_init();
cli_getopts(argc, argv);
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
@@ -98,11 +103,11 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
}
/* Do the cleanup first, since then the terminal will be reset */
cli_session_cleanup();
common_session_cleanup();
session_cleanup();
/* Avoid printing onwards from terminal cruft */
fprintf(stderr, "\n");
_dropbear_log(LOG_INFO, fmtbuf, param);
exit(exitcode);
}
@@ -114,7 +119,7 @@ static void cli_dropbear_log(int UNUSED(priority),
vsnprintf(printbuf, sizeof(printbuf), format, param);
fprintf(stderr, "%s: %s\n", cli_opts.progname, printbuf);
fflush(stderr);
}
static void exec_proxy_cmd(void *user_data_cmd) {
@@ -139,4 +144,4 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
*sock_in = *sock_out = -1;
}
}
#endif // ENABLE_CLI_PROXYCMD
#endif /* ENABLE_CLI_PROXYCMD */

View File

@@ -38,7 +38,7 @@ static void parse_hostname(const char* orighostarg);
static void parse_multihop_hostname(const char* orighostarg, const char* argv0);
static void fill_own_user();
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename);
static void loadidentityfile(const char* filename, int warnfail);
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
static void addforward(const char* str, m_list *fwdlist);
@@ -62,9 +62,10 @@ static void printhelp() {
"-N Don't run a remote command\n"
"-f Run in background after auth\n"
"-y Always accept remote host key if unknown\n"
"-y -y Don't perform any remote host key checking (caution)\n"
"-s Request a subsystem (use by external sftp)\n"
#ifdef ENABLE_CLI_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)\n"
"-i <identityfile> (multiple allowed, default %s)\n"
#endif
#ifdef ENABLE_CLI_AGENTFWD
"-A Enable agent auth forwarding\n"
@@ -89,10 +90,14 @@ static void printhelp() {
"-c <cipher list> Specify preferred ciphers ('-c help' to list options)\n"
"-m <MAC list> Specify preferred MACs for packet verification (or '-m help')\n"
#endif
"-V Version\n"
#ifdef DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
,DROPBEAR_VERSION, cli_opts.progname,
#ifdef ENABLE_CLI_PUBKEY_AUTH
DROPBEAR_DEFAULT_CLI_AUTHKEY,
#endif
DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE, DEFAULT_IDLE_TIMEOUT);
}
@@ -130,6 +135,7 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.backgrounded = 0;
cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
cli_opts.always_accept_key = 0;
cli_opts.no_hostkey_check = 0;
cli_opts.is_subsystem = 0;
#ifdef ENABLE_CLI_PUBKEY_AUTH
cli_opts.privkeys = list_new();
@@ -150,7 +156,7 @@ void cli_getopts(int argc, char ** argv) {
cli_opts.proxycmd = NULL;
#endif
#ifndef DISABLE_ZLIB
opts.enable_compress = 1;
opts.compress_mode = DROPBEAR_COMPRESS_ON;
#endif
#ifdef ENABLE_USER_ALGO_LIST
opts.cipher_list = NULL;
@@ -161,6 +167,8 @@ void cli_getopts(int argc, char ** argv) {
opts.ipv6 = 1;
*/
opts.recv_window = DEFAULT_RECV_WINDOW;
opts.keepalive_secs = DEFAULT_KEEPALIVE;
opts.idle_timeout_secs = DEFAULT_IDLE_TIMEOUT;
fill_own_user();
@@ -169,7 +177,7 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_PUBKEY_AUTH
if (nextiskey) {
/* Load a hostkey since the previous argument was "-i" */
loadidentityfile(argv[i]);
loadidentityfile(argv[i], 1);
nextiskey = 0;
continue;
}
@@ -213,6 +221,10 @@ void cli_getopts(int argc, char ** argv) {
switch (argv[i][1]) {
case 'y': /* always accept the remote hostkey */
if (cli_opts.always_accept_key) {
/* twice means no checking at all */
cli_opts.no_hostkey_check = 1;
}
cli_opts.always_accept_key = 1;
break;
case 'p': /* remoteport */
@@ -222,7 +234,7 @@ void cli_getopts(int argc, char ** argv) {
case 'i': /* an identityfile */
/* Keep scp happy when it changes "-i file" to "-ifile" */
if (strlen(argv[i]) > 2) {
loadidentityfile(&argv[i][2]);
loadidentityfile(&argv[i][2], 1);
} else {
nextiskey = 1;
}
@@ -316,6 +328,10 @@ void cli_getopts(int argc, char ** argv) {
#ifndef ENABLE_CLI_LOCALTCPFWD
case 'L':
#endif
case 'V':
print_version();
exit(EXIT_SUCCESS);
break;
case 'o':
case 'b':
next = &dummy;
@@ -377,6 +393,13 @@ void cli_getopts(int argc, char ** argv) {
exit(EXIT_FAILURE);
}
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
/* To match the common path of m_freeing it */
cli_opts.proxycmd = m_strdup(cli_opts.proxycmd);
}
#endif
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
@@ -424,6 +447,14 @@ void cli_getopts(int argc, char ** argv) {
}
#endif
#ifdef DROPBEAR_DEFAULT_CLI_AUTHKEY
{
char *expand_path = expand_tilde(DROPBEAR_DEFAULT_CLI_AUTHKEY);
loadidentityfile(expand_path, 0);
m_free(expand_path);
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
@@ -435,14 +466,18 @@ void cli_getopts(int argc, char ** argv) {
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename) {
static void loadidentityfile(const char* filename, int warnfail) {
sign_key *key;
int keytype;
enum signkey_type keytype;
TRACE(("loadidentityfile %s", filename))
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
if (warnfail) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
}
sign_key_free(key);
} else {
key->type = keytype;
@@ -461,20 +496,31 @@ multihop_passthrough_args() {
int total;
unsigned int len = 0;
m_list_elem *iter;
/* Fill out -i and -W options that make sense for all
/* Fill out -i, -y, -W options that make sense for all
* the intermediate processes */
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
len += 3 + strlen(key->filename);
}
len += 20; // space for -W <size>, terminator.
len += 30; /* space for -W <size>, terminator. */
ret = m_malloc(len);
total = 0;
if (cli_opts.no_hostkey_check)
{
int written = snprintf(ret+total, len-total, "-y -y ");
total += written;
}
else if (cli_opts.always_accept_key)
{
int written = snprintf(ret+total, len-total, "-y ");
total += written;
}
if (opts.recv_window != DEFAULT_RECV_WINDOW)
{
int written = snprintf(ret+total, len-total, "-W %d", opts.recv_window);
int written = snprintf(ret+total, len-total, "-W %d ", opts.recv_window);
total += written;
}
@@ -482,11 +528,17 @@ multihop_passthrough_args() {
{
sign_key * key = (sign_key*)iter->item;
const size_t size = len - total;
int written = snprintf(ret+total, size, "-i %s", key->filename);
int written = snprintf(ret+total, size, "-i %s ", key->filename);
dropbear_assert((unsigned int)written < size);
total += written;
}
/* if args were passed, total will be not zero, and it will have a space at the end, so remove that */
if (total > 0)
{
total--;
}
return ret;
}
@@ -557,7 +609,7 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
passthrough_args, remainder);
#ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */
opts.enable_compress = 0;
opts.compress_mode = DROPBEAR_COMPRESS_OFF;
#endif
m_free(passthrough_args);
}
@@ -587,7 +639,11 @@ static void parse_hostname(const char* orighostarg) {
cli_opts.username = m_strdup(cli_opts.own_user);
}
port = strchr(cli_opts.remotehost, '/');
port = strchr(cli_opts.remotehost, '^');
if (!port) {
/* legacy separator */
port = strchr(cli_opts.remotehost, '/');
}
if (port) {
*port = '\0';
cli_opts.remoteport = port+1;
@@ -642,11 +698,13 @@ static void fill_own_user() {
uid = getuid();
pw = getpwuid(uid);
if (pw == NULL || pw->pw_name == NULL) {
dropbear_exit("Unknown own user");
if (pw && pw->pw_name != NULL) {
cli_opts.own_user = m_strdup(pw->pw_name);
} else {
dropbear_log(LOG_INFO, "Warning: failed to identify current user. Trying anyway.");
cli_opts.own_user = m_strdup("unknown");
}
cli_opts.own_user = m_strdup(pw->pw_name);
}
#ifdef ENABLE_CLI_ANYTCPFWD

View File

@@ -1,85 +0,0 @@
/*
* Dropbear SSH
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "service.h"
#include "dbutil.h"
#include "packet.h"
#include "buffer.h"
#include "session.h"
#include "ssh.h"
void send_msg_service_request(char* servicename) {
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
buf_putstring(ses.writepayload, servicename, strlen(servicename));
encrypt_packet();
TRACE(("leave send_msg_service_request"))
}
/* This just sets up the state variables right for the main client session loop
* to deal with */
void recv_msg_service_accept() {
unsigned char* servicename;
unsigned int len;
TRACE(("enter recv_msg_service_accept"))
servicename = buf_getstring(ses.payload, &len);
/* ssh-userauth */
if (cli_ses.state == SERVICE_AUTH_REQ_SENT
&& len == SSH_SERVICE_USERAUTH_LEN
&& strncmp(SSH_SERVICE_USERAUTH, servicename, len) == 0) {
cli_ses.state = SERVICE_AUTH_ACCEPT_RCVD;
m_free(servicename);
TRACE(("leave recv_msg_service_accept: done ssh-userauth"))
return;
}
/* ssh-connection */
if (cli_ses.state == SERVICE_CONN_REQ_SENT
&& len == SSH_SERVICE_CONNECTION_LEN
&& strncmp(SSH_SERVICE_CONNECTION, servicename, len) == 0) {
if (ses.authstate.authdone != 1) {
dropbear_exit("Request for connection before auth");
}
cli_ses.state = SERVICE_CONN_ACCEPT_RCVD;
m_free(servicename);
TRACE(("leave recv_msg_service_accept: done ssh-connection"))
return;
}
dropbear_exit("Unrecognised service accept");
}

View File

@@ -31,16 +31,20 @@
#include "packet.h"
#include "tcpfwd.h"
#include "channel.h"
#include "random.h"
#include "dbrandom.h"
#include "service.h"
#include "runopts.h"
#include "chansession.h"
#include "agentfwd.h"
#include "crypto_desc.h"
static void cli_remoteclosed();
static void cli_sessionloop();
static void cli_session_init();
static void cli_finished();
static void recv_msg_service_accept(void);
static void cli_session_cleanup(void);
static void recv_msg_global_request_cli(void);
struct clientsession cli_ses; /* GLOBAL */
@@ -65,9 +69,16 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_CHANNEL_OPEN_FAILURE, recv_msg_channel_open_failure},
{SSH_MSG_USERAUTH_BANNER, recv_msg_userauth_banner}, /* client */
{SSH_MSG_USERAUTH_SPECIFIC_60, recv_msg_userauth_specific_60}, /* client */
{SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_cli},
{SSH_MSG_CHANNEL_SUCCESS, ignore_recv_response},
{SSH_MSG_CHANNEL_FAILURE, ignore_recv_response},
#ifdef ENABLE_CLI_REMOTETCPFWD
{SSH_MSG_REQUEST_SUCCESS, cli_recv_msg_request_success}, /* client */
{SSH_MSG_REQUEST_FAILURE, cli_recv_msg_request_failure}, /* client */
#else
/* For keepalive */
{SSH_MSG_REQUEST_SUCCESS, ignore_recv_response},
{SSH_MSG_REQUEST_FAILURE, ignore_recv_response},
#endif
{0, 0} /* End */
};
@@ -84,10 +95,6 @@ static const struct ChanType *cli_chantypes[] = {
void cli_session(int sock_in, int sock_out) {
seedrandom();
crypto_init();
common_session_init(sock_in, sock_out);
chaninitialise(cli_chantypes);
@@ -99,7 +106,7 @@ void cli_session(int sock_in, int sock_out) {
sessinitdone = 1;
/* Exchange identification */
session_identification();
send_session_identification();
send_msg_kexinit();
@@ -109,6 +116,12 @@ void cli_session(int sock_in, int sock_out) {
}
#ifdef USE_KEX_FIRST_FOLLOWS
static void cli_send_kex_first_guess() {
send_msg_kexdh_init();
}
#endif
static void cli_session_init() {
cli_ses.state = STATE_NOTHING;
@@ -142,37 +155,61 @@ static void cli_session_init() {
/* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed;
ses.buf_match_algo = cli_buf_match_algo;
ses.extra_session_cleanup = cli_session_cleanup;
/* packet handlers */
ses.packettypes = cli_packettypes;
ses.isserver = 0;
#ifdef USE_KEX_FIRST_FOLLOWS
ses.send_kex_first_guess = cli_send_kex_first_guess;
#endif
}
static void send_msg_service_request(char* servicename) {
TRACE(("enter send_msg_service_request: servicename='%s'", servicename))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_SERVICE_REQUEST);
buf_putstring(ses.writepayload, servicename, strlen(servicename));
encrypt_packet();
TRACE(("leave send_msg_service_request"))
}
static void recv_msg_service_accept(void) {
/* do nothing, if it failed then the server MUST have disconnected */
}
/* This function drives the progress of the session - it initiates KEX,
* service, userauth and channel requests */
static void cli_sessionloop() {
TRACE(("enter cli_sessionloop"))
TRACE2(("enter cli_sessionloop"))
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
cli_ses.kex_state = KEXINIT_RCVD;
if (ses.lastpacket == 0) {
TRACE2(("exit cli_sessionloop: no real packets yet"))
return;
}
if (cli_ses.kex_state == KEXINIT_RCVD) {
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
* negotiation would have failed. */
send_msg_kexdh_init();
cli_ses.kex_state = KEXDH_INIT_SENT;
if (!ses.kexstate.our_first_follows_matches) {
send_msg_kexdh_init();
}
cli_ses.kex_state = KEXDH_INIT_SENT;
TRACE(("leave cli_sessionloop: done with KEXINIT_RCVD"))
return;
}
/* A KEX has finished, so we should go back to our KEX_NOTHING state */
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
&& ses.kexstate.sentkexinit == 0) {
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.sentnewkeys) {
cli_ses.kex_state = KEX_NOTHING;
}
@@ -182,10 +219,10 @@ static void cli_sessionloop() {
return;
}
/* We should exit if we haven't donefirstkex: we shouldn't reach here
* in normal operation */
if (ses.kexstate.donefirstkex == 0) {
TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"))
/* We might reach here if we have partial packet reads or have
* received SSG_MSG_IGNORE etc. Just skip it */
TRACE2(("donefirstkex false\n"))
return;
}
@@ -195,19 +232,19 @@ static void cli_sessionloop() {
/* We've got the transport layer sorted, we now need to request
* userauth */
send_msg_service_request(SSH_SERVICE_USERAUTH);
cli_ses.state = SERVICE_AUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: sent userauth service req"))
return;
/* userauth code */
case SERVICE_AUTH_ACCEPT_RCVD:
cli_auth_getmethods();
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: sent userauth methods req"))
return;
case USERAUTH_REQ_SENT:
TRACE(("leave cli_sessionloop: waiting, req_sent"))
return;
case USERAUTH_FAIL_RCVD:
cli_auth_try();
if (cli_auth_try() == DROPBEAR_FAILURE) {
dropbear_exit("No auth methods could be used.");
}
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: cli_auth_try"))
return;
@@ -238,13 +275,6 @@ static void cli_sessionloop() {
}
}
#ifdef ENABLE_CLI_LOCALTCPFWD
setup_localtcp();
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
setup_remotetcp();
#endif
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.netcat_host) {
cli_send_netcat_request();
@@ -253,6 +283,14 @@ static void cli_sessionloop() {
if (!cli_opts.no_cmd) {
cli_send_chansess_request();
}
#ifdef ENABLE_CLI_LOCALTCPFWD
setup_localtcp();
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
setup_remotetcp();
#endif
TRACE(("leave cli_sessionloop: running"))
cli_ses.state = SESSION_RUNNING;
return;
@@ -274,11 +312,11 @@ static void cli_sessionloop() {
break;
}
TRACE(("leave cli_sessionloop: fell out"))
TRACE2(("leave cli_sessionloop: fell out"))
}
void cli_session_cleanup() {
static void cli_session_cleanup(void) {
if (!sessinitdone) {
return;
@@ -296,8 +334,7 @@ void cli_session_cleanup() {
static void cli_finished() {
cli_session_cleanup();
common_session_cleanup();
session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport);
exit(cli_ses.retval);
@@ -337,3 +374,9 @@ void cleantext(unsigned char* dirtytext) {
/* Null terminate */
dirtytext[j] = '\0';
}
static void recv_msg_global_request_cli(void) {
TRACE(("recv_msg_global_request_cli"))
/* Send a proper rejection */
send_msg_request_failure();
}

View File

@@ -52,7 +52,7 @@ static int cli_localtcp(const char* listenaddr,
static const struct ChanType cli_chan_tcplocal = {
1, /* sepfds */
"direct-tcpip",
NULL,
tcp_prio_inithandler,
NULL,
NULL,
NULL
@@ -161,9 +161,10 @@ void cli_recv_msg_request_success() {
if (!fwd->have_reply) {
fwd->have_reply = 1;
if (fwd->listenport == 0) {
/* The server should let us know which port was allocated if we requestd port 0 */
/* The server should let us know which port was allocated if we requested port 0 */
int allocport = buf_getint(ses.payload);
if (allocport > 0) {
fwd->listenport = allocport;
dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d",
allocport, fwd->connectaddr, fwd->connectport);
}
@@ -193,8 +194,8 @@ void setup_remotetcp() {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->listenaddr)
{
// we store the addresses so that we can compare them
// when the server sends them back
/* we store the addresses so that we can compare them
when the server sends them back */
if (opts.listen_fwd_all) {
fwd->listenaddr = m_strdup("");
} else {
@@ -220,18 +221,33 @@ static int newtcpforwarded(struct Channel * channel) {
origaddr = buf_getstring(ses.payload, NULL);
origport = buf_getint(ses.payload);
/* Find which port corresponds */
/* Find which port corresponds. First try and match address as well as port,
in case they want to forward different ports separately ... */
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
fwd = (struct TCPFwdEntry*)iter->item;
if (origport == fwd->listenport
&& (strcmp(origaddr, fwd->listenaddr) == 0)) {
&& strcmp(origaddr, fwd->listenaddr) == 0) {
break;
}
}
if (!iter)
{
/* ... otherwise try to generically match the only forwarded port
without address (also handles ::1 vs 127.0.0.1 vs localhost case).
rfc4254 is vague about the definition of "address that was connected" */
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
fwd = (struct TCPFwdEntry*)iter->item;
if (origport == fwd->listenport) {
break;
}
}
}
if (iter == NULL) {
/* We didn't request forwarding on that port */
cleantext(origaddr);
cleantext(origaddr);
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
origaddr, origport);
goto out;
@@ -251,6 +267,8 @@ static int newtcpforwarded(struct Channel * channel) {
* progress succeeds */
channel->writefd = sock;
channel->initconn = 1;
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
err = SSH_OPEN_IN_PROGRESS;

View File

@@ -23,23 +23,28 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#include "algo.h"
#include "session.h"
#include "dbutil.h"
#include "kex.h"
#include "ltc_prng.h"
#include "ecc.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*/
static int void_cipher(const unsigned char* in, unsigned char* out,
unsigned long len, void *cipher_state) {
unsigned long len, void* UNUSED(cipher_state)) {
if (in != out) {
memmove(out, in, len);
}
return CRYPT_OK;
}
static int void_start(int cipher, const unsigned char *IV,
const unsigned char *key,
int keylen, int num_rounds, void *cipher_state) {
static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
const unsigned char* UNUSED(key),
int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
return CRYPT_OK;
}
@@ -79,10 +84,14 @@ const struct dropbear_cipher dropbear_nocipher =
/* A few void* s are required to silence warnings
* about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
#ifdef DROPBEAR_ENABLE_CBC_MODE
const struct dropbear_cipher_mode dropbear_mode_cbc =
{(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
#endif // DROPBEAR_ENABLE_CBC_MODE
const struct dropbear_cipher_mode dropbear_mode_none =
{void_start, void_cipher, void_cipher};
#ifdef DROPBEAR_ENABLE_CTR_MODE
/* a wrapper to make ctr_start and cbc_start look the same */
static int dropbear_big_endian_ctr_start(int cipher,
@@ -93,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
}
const struct dropbear_cipher_mode dropbear_mode_ctr =
{(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
#endif
#endif // DROPBEAR_ENABLE_CTR_MODE
/* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
{&hash_desc, keysize, hashsize} */
@@ -132,21 +141,15 @@ algo_type sshciphers[] = {
#ifdef DROPBEAR_AES128
{"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_3DES
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_AES256
{"aes256-ctr", 0, &dropbear_aes256, 1, &dropbear_mode_ctr},
#endif
#endif /* DROPBEAR_ENABLE_CTR_MODE */
/* CBC modes are always enabled */
#ifdef DROPBEAR_ENABLE_CBC_MODE
#ifdef DROPBEAR_AES128
{"aes128-cbc", 0, &dropbear_aes128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_3DES
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_AES256
{"aes256-cbc", 0, &dropbear_aes256, 1, &dropbear_mode_cbc},
#endif
@@ -157,9 +160,16 @@ algo_type sshciphers[] = {
#ifdef DROPBEAR_TWOFISH128
{"twofish128-cbc", 0, &dropbear_twofish128, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_3DES
{"3des-ctr", 0, &dropbear_3des, 1, &dropbear_mode_ctr},
#endif
#ifdef DROPBEAR_3DES
{"3des-cbc", 0, &dropbear_3des, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_BLOWFISH
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif
#endif /* DROPBEAR_ENABLE_CBC_MODE */
#ifdef DROPBEAR_NONE_CIPHER
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
#endif
@@ -190,7 +200,13 @@ algo_type sshhashes[] = {
#ifndef DISABLE_ZLIB
algo_type ssh_compress[] = {
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
algo_type ssh_delaycompress[] = {
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
@@ -203,6 +219,17 @@ algo_type ssh_nocompress[] = {
};
algo_type sshhostkey[] = {
#ifdef DROPBEAR_ECDSA
#ifdef DROPBEAR_ECC_256
{"ecdsa-sha2-nistp256", DROPBEAR_SIGNKEY_ECDSA_NISTP256, NULL, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_384
{"ecdsa-sha2-nistp384", DROPBEAR_SIGNKEY_ECDSA_NISTP384, NULL, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_521
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNKEY_ECDSA_NISTP521, NULL, 1, NULL},
#endif
#endif
#ifdef DROPBEAR_RSA
{"ssh-rsa", DROPBEAR_SIGNKEY_RSA, NULL, 1, NULL},
#endif
@@ -212,62 +239,51 @@ algo_type sshhostkey[] = {
{NULL, 0, NULL, 0, NULL}
};
static const struct dropbear_kex kex_dh_group1 = {DROPBEAR_KEX_NORMAL_DH, dh_p_1, DH_P_1_LEN, NULL, &sha1_desc };
static const struct dropbear_kex kex_dh_group14 = {DROPBEAR_KEX_NORMAL_DH, dh_p_14, DH_P_14_LEN, NULL, &sha1_desc };
/* These can't be const since dropbear_ecc_fill_dp() fills out
ecc_curve at runtime */
#ifdef DROPBEAR_ECDH
#ifdef DROPBEAR_ECC_256
static struct dropbear_kex kex_ecdh_nistp256 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp256, &sha256_desc };
#endif
#ifdef DROPBEAR_ECC_384
static struct dropbear_kex kex_ecdh_nistp384 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp384, &sha384_desc };
#endif
#ifdef DROPBEAR_ECC_521
static struct dropbear_kex kex_ecdh_nistp521 = {DROPBEAR_KEX_ECDH, NULL, 0, &ecc_curve_nistp521, &sha512_desc };
#endif
#endif /* DROPBEAR_ECDH */
#ifdef DROPBEAR_CURVE25519
/* Referred to directly */
static const struct dropbear_kex kex_curve25519 = {DROPBEAR_KEX_CURVE25519, NULL, 0, NULL, &sha256_desc };
#endif
algo_type sshkex[] = {
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
{"diffie-hellman-group14-sha1", DROPBEAR_KEX_DH_GROUP14, NULL, 1, NULL},
#ifdef DROPBEAR_CURVE25519
{"curve25519-sha256@libssh.org", 0, &kex_curve25519, 1, NULL},
#endif
#ifdef DROPBEAR_ECDH
#ifdef DROPBEAR_ECC_521
{"ecdh-sha2-nistp521", 0, &kex_ecdh_nistp521, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_384
{"ecdh-sha2-nistp384", 0, &kex_ecdh_nistp384, 1, NULL},
#endif
#ifdef DROPBEAR_ECC_256
{"ecdh-sha2-nistp256", 0, &kex_ecdh_nistp256, 1, NULL},
#endif
#endif
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
{"diffie-hellman-group1-sha1", 0, &kex_dh_group1, 1, NULL},
#ifdef USE_KEXGUESS2
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
/* Register the compiled in ciphers.
* This should be run before using any of the ciphers/hashes */
void crypto_init() {
const struct ltc_cipher_descriptor *regciphers[] = {
#ifdef DROPBEAR_AES
&aes_desc,
#endif
#ifdef DROPBEAR_BLOWFISH
&blowfish_desc,
#endif
#ifdef DROPBEAR_TWOFISH
&twofish_desc,
#endif
#ifdef DROPBEAR_3DES
&des3_desc,
#endif
NULL
};
const struct ltc_hash_descriptor *reghashes[] = {
/* we need sha1 for hostkey stuff regardless */
&sha1_desc,
#ifdef DROPBEAR_MD5_HMAC
&md5_desc,
#endif
#ifdef DROPBEAR_SHA2_256_HMAC
&sha256_desc,
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
&sha512_desc,
#endif
NULL
};
int i;
for (i = 0; regciphers[i] != NULL; i++) {
if (register_cipher(regciphers[i]) == -1) {
dropbear_exit("Error registering crypto");
}
}
for (i = 0; reghashes[i] != NULL; i++) {
if (register_hash(reghashes[i]) == -1) {
dropbear_exit("Error registering crypto");
}
}
}
/* 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
@@ -293,7 +309,7 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
unsigned int donefirst = 0;
buffer *algolist = NULL;
algolist = buf_new(160);
algolist = buf_new(200);
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
if (donefirst)
@@ -307,6 +323,122 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
buf_free(algolist);
}
/* match the first algorithm in the comma-separated list in buf which is
* also in localalgos[], or return NULL on failure.
* (*goodguess) is set to 1 if the preferred client/server algos match,
* 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)
{
unsigned char * algolist = NULL;
const unsigned char *remotenames[MAX_PROPOSED_ALGO], *localnames[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int remotecount, localcount, clicount, servcount, i, j;
algo_type * ret = NULL;
const unsigned char **clinames, **servnames;
if (goodguess) {
*goodguess = 0;
}
/* 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;
}
}
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
localnames[i] = localalgos[i].name;
} else {
localnames[i] = NULL;
}
}
localcount = i;
if (IS_DROPBEAR_SERVER) {
clinames = remotenames;
clicount = remotecount;
servnames = localnames;
servcount = localcount;
} else {
clinames = localnames;
clicount = localcount;
servnames = remotenames;
servcount = remotecount;
}
/* iterate and find the first match */
for (i = 0; i < clicount; i++) {
for (j = 0; j < servcount; j++) {
if (!(servnames[j] && clinames[i])) {
/* unusable algos are NULL */
continue;
}
if (strcmp(servnames[j], clinames[i]) == 0) {
/* set if it was a good guess */
if (goodguess && kexguess2) {
if (*kexguess2 == KEXGUESS2_YES) {
if (i == 0) {
*goodguess = 1;
}
} else {
if (i == 0 && j == 0) {
*goodguess = 1;
}
}
}
/* set the algo to return */
if (IS_DROPBEAR_SERVER) {
ret = &localalgos[j];
} else {
ret = &localalgos[i];
}
goto out;
}
}
}
out:
m_free(algolist);
return ret;
}
#ifdef DROPBEAR_NONE_CIPHER
void
@@ -337,7 +469,7 @@ get_algo_usable(algo_type algos[], const char * algo_name)
return 0;
}
#endif // DROPBEAR_NONE_CIPHER
#endif /* DROPBEAR_NONE_CIPHER */
#ifdef ENABLE_USER_ALGO_LIST
@@ -418,4 +550,4 @@ check_user_algos(const char* user_algo_list, algo_type * algos,
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
return num_ret;
}
#endif // ENABLE_USER_ALGO_LIST
#endif /* ENABLE_USER_ALGO_LIST */

View File

@@ -59,6 +59,13 @@ static void close_chan_fd(struct Channel *channel, int fd, int how);
#define ERRFD_IS_READ(channel) ((channel)->extrabuf == NULL)
#define ERRFD_IS_WRITE(channel) (!ERRFD_IS_READ(channel))
/* allow space for:
* 1 byte byte SSH_MSG_CHANNEL_DATA
* 4 bytes uint32 recipient channel
* 4 bytes string data
*/
#define RECV_MAX_CHANNEL_DATA_LEN (RECV_MAX_PAYLOAD_LEN-(1+4+4))
/* Initialise all the channels */
void chaninitialise(const struct ChanType *chantypes[]) {
@@ -165,7 +172,9 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->extrabuf = NULL; /* The user code can set it up */
newchan->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN;
newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
newchan->prio = DROPBEAR_CHANNEL_PRIO_EARLY; /* inithandler sets it */
ses.channels[i] = newchan;
ses.chancount++;
@@ -201,11 +210,14 @@ struct Channel* getchannel() {
/* Iterate through the channels, performing IO if available */
void channelio(fd_set *readfds, fd_set *writefds) {
/* Listeners such as TCP, X11, agent-auth */
struct Channel *channel;
unsigned int i;
/* foreach channel */
for (i = 0; i < ses.chansize; i++) {
/* Close checking only needs to occur for channels that had IO events */
int do_check_close = 0;
channel = ses.channels[i];
if (channel == NULL) {
@@ -217,6 +229,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
if (channel->readfd >= 0 && FD_ISSET(channel->readfd, readfds)) {
TRACE(("send normal readfd"))
send_msg_channel_data(channel, 0);
do_check_close = 1;
}
/* read stderr data and send it over the wire */
@@ -224,6 +237,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
&& FD_ISSET(channel->errfd, readfds)) {
TRACE(("send normal errfd"))
send_msg_channel_data(channel, 1);
do_check_close = 1;
}
/* write to program/pipe stdin */
@@ -235,20 +249,28 @@ void channelio(fd_set *readfds, fd_set *writefds) {
check_in_progress(), as it may be NULL */
}
writechannel(channel, channel->writefd, channel->writebuf);
do_check_close = 1;
}
/* stderr for client mode */
if (ERRFD_IS_WRITE(channel)
&& channel->errfd >= 0 && FD_ISSET(channel->errfd, writefds)) {
writechannel(channel, channel->errfd, channel->extrabuf);
do_check_close = 1;
}
if (ses.channel_signal_pending) {
/* SIGCHLD can change channel state for server sessions */
do_check_close = 1;
ses.channel_signal_pending = 0;
}
/* handle any channel closing etc */
check_close(channel);
if (do_check_close) {
check_close(channel);
}
}
/* Listeners such as TCP, X11, agent-auth */
#ifdef USING_LISTENERS
handle_listeners(readfds);
#endif
@@ -273,10 +295,10 @@ static unsigned int write_pending(struct Channel * channel) {
static void check_close(struct Channel *channel) {
int close_allowed = 0;
TRACE(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
channel->writefd, channel->readfd,
channel->errfd, channel->sent_close, channel->recv_close))
TRACE(("writebuf size %d extrabuf size %d",
TRACE2(("writebuf size %d extrabuf size %d",
channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
@@ -307,7 +329,9 @@ static void check_close(struct Channel *channel) {
return;
}
if (channel->recv_eof && !write_pending(channel)) {
if ((channel->recv_eof && !write_pending(channel))
/* have a server "session" and child has exited */
|| (channel->type->check_close && close_allowed)) {
close_chan_fd(channel, channel->writefd, SHUT_WR);
}
@@ -336,6 +360,7 @@ static void check_close(struct Channel *channel) {
/* And if we can't receive any more data from them either, close up */
if (channel->readfd == FD_CLOSED
&& channel->writefd == FD_CLOSED
&& (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)
&& !channel->sent_close
&& close_allowed
@@ -471,8 +496,13 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
continue;
}
/* Stuff to put over the wire */
if (channel->transwindow > 0) {
/* Stuff to put over the wire.
Avoid queueing data to send if we're in the middle of a
key re-exchange (!dataallowed), but still read from the
FD if there's the possibility of "~."" to kill an
interactive session (the read_mangler) */
if (channel->transwindow > 0
&& (ses.dataallowed || channel->read_mangler)) {
if (channel->readfd >= 0) {
FD_SET(channel->readfd, readfds);
@@ -552,21 +582,29 @@ static void remove_channel(struct Channel * channel) {
}
/* close the FDs in case they haven't been done
* yet (they might have been shutdown etc) */
TRACE(("CLOSE writefd %d", channel->writefd))
close(channel->writefd);
TRACE(("CLOSE readfd %d", channel->readfd))
close(channel->readfd);
TRACE(("CLOSE errfd %d", channel->errfd))
close(channel->errfd);
if (IS_DROPBEAR_SERVER || (channel->writefd != STDOUT_FILENO)) {
/* close the FDs in case they haven't been done
* yet (they might have been shutdown etc) */
TRACE(("CLOSE writefd %d", channel->writefd))
close(channel->writefd);
TRACE(("CLOSE readfd %d", channel->readfd))
close(channel->readfd);
TRACE(("CLOSE errfd %d", channel->errfd))
close(channel->errfd);
}
channel->typedata = NULL;
if (!channel->close_handler_done
&& channel->type->closehandler) {
channel->type->closehandler(channel);
channel->close_handler_done = 1;
}
ses.channels[channel->index] = NULL;
m_free(channel);
ses.chancount--;
update_channel_prio();
TRACE(("leave remove_channel"))
}
@@ -589,7 +627,12 @@ void recv_msg_channel_request() {
&& !channel->close_handler_done) {
channel->type->reqhandler(channel);
} else {
send_msg_channel_failure(channel);
int wantreply;
buf_eatstring(ses.payload);
wantreply = buf_getbool(ses.payload);
if (wantreply) {
send_msg_channel_failure(channel);
}
}
TRACE(("leave recv_msg_channel_request"))
@@ -625,7 +668,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
* exttype if is extended */
maxlen = MIN(maxlen,
ses.writepayload->size - 1 - 4 - 4 - (isextended ? 4 : 0));
TRACE(("maxlen %d", maxlen))
TRACE(("maxlen %zd", maxlen))
if (maxlen == 0) {
TRACE(("leave send_msg_channel_data: no window"))
return;
@@ -643,6 +686,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
/* read the data */
len = read(fd, buf_getwriteptr(ses.writepayload, maxlen), maxlen);
if (len <= 0) {
if (len == 0 || errno != EINTR) {
/* This will also get hit in the case of EAGAIN. The only
@@ -650,12 +694,22 @@ static void send_msg_channel_data(struct Channel *channel, int isextended) {
in which case it can be treated the same as EOF */
close_chan_fd(channel, fd, SHUT_RD);
}
ses.writepayload->len = ses.writepayload->pos = 0;
buf_setpos(ses.writepayload, 0);
buf_setlen(ses.writepayload, 0);
TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d",
len, errno, fd))
return;
}
if (channel->read_mangler) {
channel->read_mangler(channel, buf_getwriteptr(ses.writepayload, len), &len);
if (len == 0) {
buf_setpos(ses.writepayload, 0);
buf_setlen(ses.writepayload, 0);
return;
}
}
TRACE(("send_msg_channel_data: len %d fd %d", len, fd))
buf_incrwritepos(ses.writepayload, len);
/* ... real size here */
@@ -846,6 +900,10 @@ void recv_msg_channel_open() {
}
}
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
chan_initwritebuf(channel);
/* success */
@@ -859,6 +917,8 @@ failure:
cleanup:
m_free(type);
update_channel_prio();
TRACE(("leave recv_msg_channel_open"))
}
@@ -974,7 +1034,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
* for X11, agent, tcp forwarding, and should be filled with channel-specific
* options, with the calling function calling encrypt_packet() after
* completion. It is mandatory for the caller to encrypt_packet() if
* DROPBEAR_SUCCESS is returned */
* a channel is returned. NULL is returned on failure. */
int send_msg_channel_open_init(int fd, const struct ChanType *type) {
struct Channel* chan;
@@ -1005,7 +1065,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
buf_putstring(ses.writepayload, type->name, strlen(type->name));
buf_putint(ses.writepayload, chan->index);
buf_putint(ses.writepayload, opts.recv_window);
buf_putint(ses.writepayload, RECV_MAX_PAYLOAD_LEN);
buf_putint(ses.writepayload, RECV_MAX_CHANNEL_DATA_LEN);
TRACE(("leave send_msg_channel_open_init()"))
return DROPBEAR_SUCCESS;
@@ -1040,9 +1100,14 @@ void recv_msg_channel_open_confirmation() {
if (ret > 0) {
remove_channel(channel);
TRACE(("inithandler returned failure %d", ret))
return;
}
}
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
update_channel_prio();
TRACE(("leave recv_msg_channel_open_confirmation"))
}
@@ -1062,3 +1127,42 @@ void recv_msg_channel_open_failure() {
remove_channel(channel);
}
#endif /* USING_LISTENERS */
void send_msg_request_success() {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
encrypt_packet();
}
void send_msg_request_failure() {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
encrypt_packet();
}
struct Channel* get_any_ready_channel() {
if (ses.chancount == 0) {
return NULL;
}
size_t i;
for (i = 0; i < ses.chansize; i++) {
struct Channel *chan = ses.channels[i];
if (chan
&& !(chan->sent_eof || chan->recv_eof)
&& !(chan->await_open || chan->initconn)) {
return chan;
}
}
return NULL;
}
void start_send_channel_request(struct Channel *channel,
unsigned char *type) {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_REQUEST);
buf_putint(ses.writepayload, channel->remotechan);
buf_putstring(ses.writepayload, type, strlen(type));
}

View File

@@ -32,12 +32,13 @@
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
#include "random.h"
#include "dbrandom.h"
#include "runopts.h"
#include "ecc.h"
#include "crypto_desc.h"
/* diffie-hellman-group1-sha1 value for p */
#define DH_P_1_LEN 128
static const unsigned char dh_p_1[DH_P_1_LEN] = {
const unsigned char dh_p_1[DH_P_1_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
@@ -51,8 +52,7 @@ static const unsigned char dh_p_1[DH_P_1_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
/* diffie-hellman-group14-sha1 value for p */
#define DH_P_14_LEN 256
static const unsigned char dh_p_14[DH_P_14_LEN] = {
const unsigned char dh_p_14[DH_P_14_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
@@ -80,14 +80,16 @@ static const unsigned char dh_p_14[DH_P_14_LEN] = {
static const int DH_G_VAL = 2;
static void kexinitialise();
void gen_new_keys();
static void gen_new_keys();
#ifndef DISABLE_ZLIB
static void gen_new_zstreams();
static void gen_new_zstream_recv();
static void gen_new_zstream_trans();
#endif
static void read_kex_algos();
/* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, int outlen,
const hash_state * hs, unsigned const char X);
static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X);
static void finish_kexhashbuf(void);
/* Send our list of algorithms we can use */
@@ -131,8 +133,8 @@ void send_msg_kexinit() {
/* languages_server_to_client */
buf_putstring(ses.writepayload, "", 0);
/* first_kex_packet_follows - unimplemented for now */
buf_putbyte(ses.writepayload, 0x00);
/* first_kex_packet_follows */
buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL));
/* reserved unit32 */
buf_putint(ses.writepayload, 0);
@@ -144,16 +146,60 @@ void send_msg_kexinit() {
encrypt_packet();
ses.dataallowed = 0; /* don't send other packets during kex */
ses.kexstate.sentkexinit = 1;
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.send_kex_first_guess();
}
TRACE(("DATAALLOWED=0"))
TRACE(("-> KEXINIT"))
ses.kexstate.sentkexinit = 1;
}
/* *** NOTE regarding (send|recv)_msg_newkeys ***
* Changed by mihnea from the original kex.c to set dataallowed after a
* completed key exchange, no matter the order in which it was performed.
* This enables client mode without affecting server functionality.
*/
static void switch_keys() {
TRACE2(("enter switch_keys"))
if (!(ses.kexstate.sentkexinit && ses.kexstate.recvkexinit)) {
dropbear_exit("Unexpected newkeys message");
}
if (!ses.keys) {
ses.keys = m_malloc(sizeof(*ses.newkeys));
}
if (ses.kexstate.recvnewkeys && ses.newkeys->recv.valid) {
TRACE(("switch_keys recv"))
#ifndef DISABLE_ZLIB
gen_new_zstream_recv();
#endif
ses.keys->recv = ses.newkeys->recv;
m_burn(&ses.newkeys->recv, sizeof(ses.newkeys->recv));
ses.newkeys->recv.valid = 0;
}
if (ses.kexstate.sentnewkeys && ses.newkeys->trans.valid) {
TRACE(("switch_keys trans"))
#ifndef DISABLE_ZLIB
gen_new_zstream_trans();
#endif
ses.keys->trans = ses.newkeys->trans;
m_burn(&ses.newkeys->trans, sizeof(ses.newkeys->trans));
ses.newkeys->trans.valid = 0;
}
if (ses.kexstate.sentnewkeys && ses.kexstate.recvnewkeys)
{
TRACE(("switch_keys done"))
ses.keys->algo_kex = ses.newkeys->algo_kex;
ses.keys->algo_hostkey = ses.newkeys->algo_hostkey;
ses.keys->allow_compress = 0;
m_free(ses.newkeys);
ses.newkeys = NULL;
kexinitialise();
}
TRACE2(("leave switch_keys"))
}
/* Bring new keys into use after a key exchange, and let the client know*/
void send_msg_newkeys() {
@@ -164,44 +210,25 @@ void send_msg_newkeys() {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
encrypt_packet();
/* set up our state */
if (ses.kexstate.recvnewkeys) {
TRACE(("while RECVNEWKEYS=1"))
gen_new_keys();
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"))
ses.dataallowed = 1; /* we can send other packets again now */
ses.kexstate.donefirstkex = 1;
} else {
ses.kexstate.sentnewkeys = 1;
TRACE(("SENTNEWKEYS=1"))
}
ses.kexstate.sentnewkeys = 1;
ses.kexstate.donefirstkex = 1;
ses.dataallowed = 1; /* we can send other packets again now */
gen_new_keys();
switch_keys();
TRACE(("-> MSG_NEWKEYS"))
TRACE(("leave send_msg_newkeys"))
}
/* Bring the new keys into use after a key exchange */
void recv_msg_newkeys() {
TRACE(("<- MSG_NEWKEYS"))
TRACE(("enter recv_msg_newkeys"))
/* simply check if we've sent SSH_MSG_NEWKEYS, and if so,
* switch to the new keys */
if (ses.kexstate.sentnewkeys) {
TRACE(("while SENTNEWKEYS=1"))
gen_new_keys();
kexinitialise(); /* we've finished with this kex */
TRACE((" -> DATAALLOWED=1"))
ses.dataallowed = 1; /* we can send other packets again now */
ses.kexstate.donefirstkex = 1;
} else {
TRACE(("RECVNEWKEYS=1"))
ses.kexstate.recvnewkeys = 1;
}
ses.kexstate.recvnewkeys = 1;
switch_keys();
TRACE(("leave recv_msg_newkeys"))
}
@@ -211,14 +238,24 @@ void recv_msg_newkeys() {
void kexfirstinitialise() {
ses.kexstate.donefirstkex = 0;
#ifndef DISABLE_ZLIB
if (opts.enable_compress) {
ses.compress_algos = ssh_compress;
} else
#endif
#ifdef DISABLE_ZLIB
ses.compress_algos = ssh_nocompress;
#else
switch (opts.compress_mode)
{
ses.compress_algos = ssh_nocompress;
case DROPBEAR_COMPRESS_DELAYED:
ses.compress_algos = ssh_delaycompress;
break;
case DROPBEAR_COMPRESS_ON:
ses.compress_algos = ssh_compress;
break;
case DROPBEAR_COMPRESS_OFF:
ses.compress_algos = ssh_nocompress;
break;
}
#endif
kexinitialise();
}
@@ -236,12 +273,14 @@ static void kexinitialise() {
ses.kexstate.sentnewkeys = 0;
/* first_packet_follows */
ses.kexstate.firstfollows = 0;
ses.kexstate.them_firstfollows = 0;
ses.kexstate.datatrans = 0;
ses.kexstate.datarecv = 0;
ses.kexstate.lastkextime = time(NULL);
ses.kexstate.our_first_follows_matches = 0;
ses.kexstate.lastkextime = monotonic_now();
}
@@ -251,27 +290,30 @@ static void kexinitialise() {
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
*
* See Section 7.2 of rfc4253 (ssh transport) for details */
static void hashkeys(unsigned char *out, int outlen,
static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X) {
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
hash_state hs2;
int offset;
unsigned int offset;
unsigned char tmpout[MAX_HASH_SIZE];
memcpy(&hs2, hs, sizeof(hash_state));
sha1_process(&hs2, &X, 1);
sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
sha1_done(&hs2, out);
for (offset = SHA1_HASH_SIZE;
hash_desc->process(&hs2, &X, 1);
hash_desc->process(&hs2, ses.session_id->data, ses.session_id->len);
hash_desc->done(&hs2, tmpout);
memcpy(out, tmpout, MIN(hash_desc->hashsize, outlen));
for (offset = hash_desc->hashsize;
offset < outlen;
offset += SHA1_HASH_SIZE)
offset += hash_desc->hashsize)
{
/* need to extend */
unsigned char k2[SHA1_HASH_SIZE];
memcpy(&hs2, hs, sizeof(hash_state));
sha1_process(&hs2, out, offset);
sha1_done(&hs2, k2);
memcpy(&out[offset], k2, MIN(outlen - offset, SHA1_HASH_SIZE));
hash_desc->process(&hs2, out, offset);
hash_desc->done(&hs2, tmpout);
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
}
m_burn(&hs2, sizeof(hash_state));
}
/* Generate the actual encryption/integrity keys, using the results of the
@@ -281,8 +323,7 @@ static void hashkeys(unsigned char *out, int outlen,
* ses.newkeys is the new set of keys which are generated, these are only
* taken into use after both sides have sent a newkeys message */
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
void gen_new_keys() {
static void gen_new_keys() {
unsigned char C2S_IV[MAX_IV_LEN];
unsigned char C2S_key[MAX_KEY_LEN];
@@ -292,26 +333,26 @@ void gen_new_keys() {
unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;
hash_state hs;
unsigned int C2S_keysize, S2C_keysize;
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
char mactransletter, macrecvletter; /* Client or server specific */
TRACE(("enter gen_new_keys"))
/* the dh_K and hash are the start of all hashes, we make use of that */
sha1_init(&hs);
sha1_process_mp(&hs, ses.dh_K);
hash_desc->init(&hs);
hash_process_mp(hash_desc, &hs, ses.dh_K);
mp_clear(ses.dh_K);
m_free(ses.dh_K);
sha1_process(&hs, ses.hash, SHA1_HASH_SIZE);
m_burn(ses.hash, SHA1_HASH_SIZE);
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
if (IS_DROPBEAR_CLIENT) {
trans_IV = C2S_IV;
recv_IV = S2C_IV;
trans_key = C2S_key;
recv_key = S2C_key;
C2S_keysize = ses.newkeys->trans.algo_crypt->keysize;
S2C_keysize = ses.newkeys->recv.algo_crypt->keysize;
mactransletter = 'E';
macrecvletter = 'F';
} else {
@@ -319,16 +360,14 @@ void gen_new_keys() {
recv_IV = C2S_IV;
trans_key = S2C_key;
recv_key = C2S_key;
C2S_keysize = ses.newkeys->recv.algo_crypt->keysize;
S2C_keysize = ses.newkeys->trans.algo_crypt->keysize;
mactransletter = 'F';
macrecvletter = 'E';
}
hashkeys(C2S_IV, SHA1_HASH_SIZE, &hs, 'A');
hashkeys(S2C_IV, SHA1_HASH_SIZE, &hs, 'B');
hashkeys(C2S_key, C2S_keysize, &hs, 'C');
hashkeys(S2C_key, S2C_keysize, &hs, 'D');
hashkeys(C2S_IV, sizeof(C2S_IV), &hs, 'A');
hashkeys(S2C_IV, sizeof(S2C_IV), &hs, 'B');
hashkeys(C2S_key, sizeof(C2S_key), &hs, 'C');
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);
@@ -354,32 +393,27 @@ void gen_new_keys() {
}
}
if (ses.newkeys->trans.algo_mac->hashdesc != NULL) {
if (ses.newkeys->trans.algo_mac->hash_desc != NULL) {
hashkeys(ses.newkeys->trans.mackey,
ses.newkeys->trans.algo_mac->keysize, &hs, mactransletter);
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hashdesc->name);
ses.newkeys->trans.hash_index = find_hash(ses.newkeys->trans.algo_mac->hash_desc->name);
}
if (ses.newkeys->recv.algo_mac->hashdesc != NULL) {
if (ses.newkeys->recv.algo_mac->hash_desc != NULL) {
hashkeys(ses.newkeys->recv.mackey,
ses.newkeys->recv.algo_mac->keysize, &hs, macrecvletter);
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hashdesc->name);
ses.newkeys->recv.hash_index = find_hash(ses.newkeys->recv.algo_mac->hash_desc->name);
}
#ifndef DISABLE_ZLIB
gen_new_zstreams();
#endif
/* Switch over to the new keys */
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
ses.keys = ses.newkeys;
ses.newkeys = NULL;
/* Ready to switch over */
ses.newkeys->trans.valid = 1;
ses.newkeys->recv.valid = 1;
m_burn(C2S_IV, sizeof(C2S_IV));
m_burn(C2S_key, sizeof(C2S_key));
m_burn(S2C_IV, sizeof(S2C_IV));
m_burn(S2C_key, sizeof(S2C_key));
m_burn(&hs, sizeof(hash_state));
TRACE(("leave gen_new_keys"))
}
@@ -400,7 +434,7 @@ int is_compress_recv() {
/* Set up new zlib compression streams, close the old ones. Only
* called from gen_new_keys() */
static void gen_new_zstreams() {
static void gen_new_zstream_recv() {
/* create new zstreams */
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
@@ -415,6 +449,17 @@ static void gen_new_zstreams() {
} else {
ses.newkeys->recv.zstream = NULL;
}
/* clean up old keys */
if (ses.keys->recv.zstream != NULL) {
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("Crypto error");
}
m_free(ses.keys->recv.zstream);
}
}
static void gen_new_zstream_trans() {
if (ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
@@ -432,14 +477,6 @@ static void gen_new_zstreams() {
ses.newkeys->trans.zstream = NULL;
}
/* clean up old keys */
if (ses.keys->recv.zstream != NULL) {
if (inflateEnd(ses.keys->recv.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
dropbear_exit("Crypto error");
}
m_free(ses.keys->recv.zstream);
}
if (ses.keys->trans.zstream != NULL) {
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
/* Z_DATA_ERROR is ok, just means that stream isn't ended */
@@ -457,9 +494,6 @@ static void gen_new_zstreams() {
* and we calculate the first portion of the key-exchange-hash for used
* later in the key exchange. No response is sent, as the client should
* initiate the diffie-hellman key exchange */
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
/* Belongs in common_kex.c where it should be moved after review */
void recv_msg_kexinit() {
unsigned int kexhashbuf_len = 0;
@@ -502,7 +536,7 @@ void recv_msg_kexinit() {
/* I_S, the payload of the server's SSH_MSG_KEXINIT */
buf_setpos(ses.payload, 0);
buf_putstring(ses.kexhashbuf, ses.payload->data, ses.payload->len);
ses.requirenext = SSH_MSG_KEXDH_REPLY;
} else {
/* SERVER */
@@ -536,28 +570,24 @@ void recv_msg_kexinit() {
static void load_dh_p(mp_int * dh_p)
{
switch (ses.newkeys->algo_kex) {
case DROPBEAR_KEX_DH_GROUP1:
bytes_to_mp(dh_p, dh_p_1, DH_P_1_LEN);
break;
case DROPBEAR_KEX_DH_GROUP14:
bytes_to_mp(dh_p, dh_p_14, DH_P_14_LEN);
break;
}
bytes_to_mp(dh_p, ses.newkeys->algo_kex->dh_p_bytes,
ses.newkeys->algo_kex->dh_p_len);
}
/* Initialises and generate one side of the diffie-hellman key exchange values.
* See the transport rfc 4253 section 8 for details */
/* dh_pub and dh_priv MUST be already initialised */
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
struct kex_dh_param *gen_kexdh_param() {
struct kex_dh_param *param = NULL;
DEF_MP_INT(dh_p);
DEF_MP_INT(dh_q);
DEF_MP_INT(dh_g);
TRACE(("enter send_msg_kexdh_reply"))
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
TRACE(("enter gen_kexdh_vals"))
param = m_malloc(sizeof(*param));
m_mp_init_multi(&param->pub, &param->priv, &dh_g, &dh_p, &dh_q, NULL);
/* read the prime and generator*/
load_dh_p(&dh_p);
@@ -568,33 +598,39 @@ void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
/* calculate q = (p-1)/2 */
/* dh_priv is just a temp var here */
if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) {
if (mp_sub_d(&dh_p, 1, &param->priv) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
if (mp_div_2(&param->priv, &dh_q) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
/* Generate a private portion 0 < dh_priv < dh_q */
gen_random_mpint(&dh_q, dh_priv);
gen_random_mpint(&dh_q, &param->priv);
/* f = g^y mod p */
if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
if (mp_exptmod(&dh_g, &param->priv, &dh_p, &param->pub) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
return param;
}
void free_kexdh_param(struct kex_dh_param *param)
{
mp_clear_multi(&param->pub, &param->priv, NULL);
m_free(param);
}
/* This function is fairly common between client/server, with some substitution
* of dh_e/dh_f etc. Hence these arguments:
* dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is
* vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
sign_key *hostkey) {
mp_int dh_p;
mp_int *dh_e = NULL, *dh_f = NULL;
hash_state hs;
/* read the prime and generator*/
m_mp_init(&dh_p);
@@ -607,9 +643,8 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
}
/* K = e^y mod p = f^x mod p */
ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
m_mp_init(ses.dh_K);
if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) {
m_mp_alloc_init_multi(&ses.dh_K, NULL);
if (mp_exptmod(dh_pub_them, &param->priv, &dh_p, ses.dh_K) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
@@ -619,11 +654,11 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
/* From here on, the code needs to work with the _same_ vars on each side,
* not vice-versaing for client/server */
if (IS_DROPBEAR_CLIENT) {
dh_e = dh_pub_us;
dh_e = &param->pub;
dh_f = dh_pub_them;
} else {
dh_e = dh_pub_them;
dh_f = dh_pub_us;
dh_f = &param->pub;
}
/* Create the remainder of the hash buffer, to generate the exchange hash */
@@ -637,21 +672,150 @@ void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
buf_putmpint(ses.kexhashbuf, ses.dh_K);
/* calculate the hash H to sign */
sha1_init(&hs);
finish_kexhashbuf();
}
#ifdef DROPBEAR_ECDH
struct kex_ecdh_param *gen_kexecdh_param() {
struct kex_ecdh_param *param = m_malloc(sizeof(*param));
if (ecc_make_key_ex(NULL, dropbear_ltc_prng,
&param->key, ses.newkeys->algo_kex->ecc_curve->dp) != CRYPT_OK) {
dropbear_exit("ECC error");
}
return param;
}
void free_kexecdh_param(struct kex_ecdh_param *param) {
ecc_free(&param->key);
m_free(param);
}
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
sign_key *hostkey) {
const struct dropbear_kex *algo_kex = ses.newkeys->algo_kex;
/* public keys from client and server */
ecc_key *Q_C, *Q_S, *Q_them;
Q_them = buf_get_ecc_raw_pubkey(pub_them, algo_kex->ecc_curve);
ses.dh_K = dropbear_ecc_shared_secret(Q_them, &param->key);
/* Create the remainder of the hash buffer, to generate the exchange hash
See RFC5656 section 4 page 7 */
if (IS_DROPBEAR_CLIENT) {
Q_C = &param->key;
Q_S = Q_them;
} else {
Q_C = Q_them;
Q_S = &param->key;
}
/* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* Q_C, client's ephemeral public key octet string */
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_C);
/* Q_S, server's ephemeral public key octet string */
buf_put_ecc_raw_pubkey_string(ses.kexhashbuf, Q_S);
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);
/* calculate the hash H to sign */
finish_kexhashbuf();
}
#endif /* DROPBEAR_ECDH */
#ifdef DROPBEAR_CURVE25519
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);
return param;
}
void free_kexcurve25519_param(struct kex_curve25519_param *param)
{
m_burn(param->priv, CURVE25519_LEN);
m_free(param);
}
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *buf_pub_them,
sign_key *hostkey) {
unsigned char out[CURVE25519_LEN];
const unsigned char* Q_C = NULL;
const unsigned char* Q_S = NULL;
if (buf_pub_them->len != CURVE25519_LEN)
{
dropbear_exit("Bad curve25519");
}
curve25519_donna(out, param->priv, buf_pub_them->data);
m_mp_alloc_init_multi(&ses.dh_K, NULL);
bytes_to_mp(ses.dh_K, out, CURVE25519_LEN);
m_burn(out, sizeof(out));
/* Create the remainder of the hash buffer, to generate the exchange hash.
See RFC5656 section 4 page 7 */
if (IS_DROPBEAR_CLIENT) {
Q_C = param->pub;
Q_S = buf_pub_them->data;
} else {
Q_S = param->pub;
Q_C = buf_pub_them->data;
}
/* K_S, the host key */
buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
/* Q_C, client's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_C, CURVE25519_LEN);
/* Q_S, server's ephemeral public key octet string */
buf_putstring(ses.kexhashbuf, Q_S, CURVE25519_LEN);
/* K, the shared secret */
buf_putmpint(ses.kexhashbuf, ses.dh_K);
/* calculate the hash H to sign */
finish_kexhashbuf();
}
#endif /* DROPBEAR_CURVE25519 */
static void finish_kexhashbuf(void) {
hash_state hs;
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
hash_desc->init(&hs);
buf_setpos(ses.kexhashbuf, 0);
sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
ses.kexhashbuf->len);
sha1_done(&hs, ses.hash);
ses.hash = buf_new(hash_desc->hashsize);
hash_desc->done(&hs, buf_getwriteptr(ses.hash, hash_desc->hashsize));
buf_setlen(ses.hash, hash_desc->hashsize);
#if defined(DEBUG_KEXHASH) && defined(DEBUG_TRACE)
if (!debug_trace) {
printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len);
printhex("kexhash", ses.hash->data, ses.hash->len);
}
#endif
buf_burn(ses.kexhashbuf);
buf_free(ses.kexhashbuf);
m_burn(&hs, sizeof(hash_state));
ses.kexhashbuf = NULL;
/* first time around, we set the session_id to H */
if (ses.session_id == NULL) {
/* create the session_id, this never needs freeing */
ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
ses.session_id = buf_newcopy(ses.hash);
}
}
@@ -676,22 +840,29 @@ static void read_kex_algos() {
int allgood = 1; /* we AND this with each goodguess and see if its still
true after */
#ifdef USE_KEXGUESS2
enum kexguess2_used kexguess2 = KEXGUESS2_LOOK;
#else
enum kexguess2_used kexguess2 = KEXGUESS2_NO;
#endif
buf_incrpos(ses.payload, 16); /* start after the cookie */
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
/* kex_algorithms */
algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
erralgo = "kex";
goto error;
}
TRACE(("kexguess2 %d", kexguess2))
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->val;
ses.newkeys->algo_kex = algo->data;
/* server_host_key_algorithms */
algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
erralgo = "hostkey";
@@ -701,7 +872,7 @@ static void read_kex_algos() {
ses.newkeys->algo_hostkey = algo->val;
/* encryption_algorithms_client_to_server */
c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
if (c2s_cipher_algo == NULL) {
erralgo = "enc c->s";
goto error;
@@ -709,7 +880,7 @@ static void read_kex_algos() {
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
if (s2c_cipher_algo == NULL) {
erralgo = "enc s->c";
goto error;
@@ -717,7 +888,7 @@ static void read_kex_algos() {
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
if (c2s_hash_algo == NULL) {
erralgo = "mac c->s";
goto error;
@@ -725,7 +896,7 @@ static void read_kex_algos() {
TRACE(("hash c2s is %s", c2s_hash_algo->name))
/* mac_algorithms_server_to_client */
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
if (s2c_hash_algo == NULL) {
erralgo = "mac s->c";
goto error;
@@ -733,7 +904,7 @@ static void read_kex_algos() {
TRACE(("hash s2c is %s", s2c_hash_algo->name))
/* compression_algorithms_client_to_server */
c2s_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
if (c2s_comp_algo == NULL) {
erralgo = "comp c->s";
goto error;
@@ -741,7 +912,7 @@ static void read_kex_algos() {
TRACE(("hash c2s is %s", c2s_comp_algo->name))
/* compression_algorithms_server_to_client */
s2c_comp_algo = ses.buf_match_algo(ses.payload, ses.compress_algos, &goodguess);
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
if (s2c_comp_algo == NULL) {
erralgo = "comp s->c";
goto error;
@@ -754,9 +925,10 @@ static void read_kex_algos() {
/* languages_server_to_client */
buf_eatstring(ses.payload);
/* first_kex_packet_follows */
/* their first_kex_packet_follows */
if (buf_getbool(ses.payload)) {
ses.kexstate.firstfollows = 1;
TRACE(("them kex firstfollows. allgood %d", allgood))
ses.kexstate.them_firstfollows = 1;
/* if the guess wasn't good, we ignore the packet sent */
if (!allgood) {
ses.ignorenext = 1;
@@ -799,6 +971,11 @@ static void read_kex_algos() {
/* reserved for future extensions */
buf_getint(ses.payload);
if (ses.send_kex_first_guess && allgood) {
TRACE(("our_first_follows_matches 1"))
ses.kexstate.our_first_follows_matches = 1;
}
return;
error:

View File

@@ -29,13 +29,14 @@
#include "dbutil.h"
#include "auth.h"
#include "algo.h"
#include "random.h"
#include "dbrandom.h"
runopts opts; /* GLOBAL */
/* returns success or failure, and the keytype in *type. If we want
* to restrict the type, type can contain a type to return */
int readhostkey(const char * filename, sign_key * hostkey, int *type) {
int readhostkey(const char * filename, sign_key * hostkey,
enum signkey_type *type) {
int ret = DROPBEAR_FAILURE;
buffer *buf;
@@ -105,3 +106,8 @@ parse_ciphers_macs()
}
#endif
void print_version() {
fprintf(stderr, "Dropbear v%s\n", DROPBEAR_VERSION);
}

View File

@@ -30,15 +30,15 @@
#include "buffer.h"
#include "dss.h"
#include "ssh.h"
#include "random.h"
#include "dbrandom.h"
#include "kex.h"
#include "channel.h"
#include "atomicio.h"
#include "runopts.h"
static void checktimeouts();
static long select_timeout();
static int ident_readln(int fd, char* buf, int count);
static void read_session_identification();
struct sshsession ses; /* GLOBAL */
@@ -49,10 +49,9 @@ int sessinitdone = 0; /* GLOBAL */
/* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
int exitflag = 0; /* GLOBAL */
/* called only at the start of a session, set up initial state */
void common_session_init(int sock_in, int sock_out) {
time_t now;
TRACE(("enter session_init"))
@@ -60,9 +59,15 @@ void common_session_init(int sock_in, int sock_out) {
ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out);
ses.connect_time = 0;
ses.last_trx_packet_time = 0;
ses.last_packet_time = 0;
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
now = monotonic_now();
ses.last_packet_time_keepalive_recv = now;
ses.last_packet_time_idle = now;
ses.last_packet_time_any_sent = 0;
ses.last_packet_time_keepalive_sent = 0;
if (pipe(ses.signal_pipe) < 0) {
dropbear_exit("Signal pipe failed");
@@ -103,7 +108,7 @@ void common_session_init(int sock_in, int sock_out) {
ses.keys->recv.algo_mac = &dropbear_nohash;
ses.keys->trans.algo_mac = &dropbear_nohash;
ses.keys->algo_kex = -1;
ses.keys->algo_kex = NULL;
ses.keys->algo_hostkey = -1;
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
@@ -141,7 +146,10 @@ void session_loop(void(*loophandler)()) {
FD_ZERO(&writefd);
FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
if (ses.sock_in != -1) {
/* during initial setup we flush out the KEXINIT packet before
* attempting to read the remote version string, which might block */
if (ses.sock_in != -1 && (ses.remoteident || isempty(&ses.writequeue))) {
FD_SET(ses.sock_in, &readfd);
}
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
@@ -152,10 +160,9 @@ void session_loop(void(*loophandler)()) {
SIGCHLD in svr-chansession is the only one currently. */
FD_SET(ses.signal_pipe[0], &readfd);
/* set up for channels which require reading/writing */
if (ses.dataallowed) {
setchannelfds(&readfd, &writefd);
}
/* set up for channels which can be read/written */
setchannelfds(&readfd, &writefd);
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
if (exitflag) {
@@ -186,16 +193,15 @@ void session_loop(void(*loophandler)()) {
/* check for auth timeout, rekeying required etc */
checktimeouts();
/* process session socket's incoming/outgoing data */
if (ses.sock_out != -1) {
if (FD_ISSET(ses.sock_out, &writefd) && !isempty(&ses.writequeue)) {
write_packet();
}
}
/* process session socket's incoming data */
if (ses.sock_in != -1) {
if (FD_ISSET(ses.sock_in, &readfd)) {
read_packet();
if (!ses.remoteident) {
/* blocking read of the version string */
read_session_identification();
} else {
read_packet();
}
}
/* Process the decrypted packet. After this, the read buffer
@@ -211,10 +217,16 @@ void session_loop(void(*loophandler)()) {
/* process pipes etc for the channels, ses.dataallowed == 0
* during rekeying ) */
if (ses.dataallowed) {
channelio(&readfd, &writefd);
channelio(&readfd, &writefd);
/* process session socket's outgoing data */
if (ses.sock_out != -1) {
if (!isempty(&ses.writequeue)) {
write_packet();
}
}
if (loophandler) {
loophandler();
}
@@ -225,7 +237,7 @@ void session_loop(void(*loophandler)()) {
}
/* clean up a session on exit */
void common_session_cleanup() {
void session_cleanup() {
TRACE(("enter session_cleanup"))
@@ -234,31 +246,45 @@ void common_session_cleanup() {
TRACE(("leave session_cleanup: !sessinitdone"))
return;
}
m_free(ses.session_id);
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
if (ses.extra_session_cleanup) {
ses.extra_session_cleanup();
}
chancleanup();
/* Cleaning up keys must happen after other cleanup
functions which might queue packets */
if (ses.session_id) {
buf_burn(ses.session_id);
buf_free(ses.session_id);
ses.session_id = NULL;
}
if (ses.hash) {
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
}
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
TRACE(("leave session_cleanup"))
}
void send_session_identification() {
buffer *writebuf = buf_new(strlen(LOCAL_IDENT "\r\n") + 1);
buf_putbytes(writebuf, LOCAL_IDENT "\r\n", strlen(LOCAL_IDENT "\r\n"));
buf_putbyte(writebuf, 0x0); /* packet type */
buf_setpos(writebuf, 0);
enqueue(&ses.writequeue, writebuf);
}
void session_identification() {
static void read_session_identification() {
/* max length of 255 chars */
char linebuf[256];
int len = 0;
char done = 0;
int i;
/* write our version string, this blocks */
if (atomicio(write, ses.sock_out, LOCAL_IDENT "\r\n",
strlen(LOCAL_IDENT "\r\n")) == DROPBEAR_FAILURE) {
ses.remoteclosed();
}
/* If they send more than 50 lines, something is wrong */
for (i = 0; i < 50; i++) {
len = ident_readln(ses.sock_in, linebuf, sizeof(linebuf));
@@ -368,11 +394,37 @@ static int ident_readln(int fd, char* buf, int count) {
return pos+1;
}
void send_msg_ignore() {
void ignore_recv_response() {
// Do nothing
TRACE(("Ignored msg_request_response"))
}
static void send_msg_keepalive() {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_IGNORE);
buf_putstring(ses.writepayload, "", 0);
time_t old_time_idle = ses.last_packet_time_idle;
struct Channel *chan = get_any_ready_channel();
if (chan) {
/* Channel requests are preferable, more implementations
handle them than SSH_MSG_GLOBAL_REQUEST */
TRACE(("keepalive channel request %d", chan->index))
start_send_channel_request(chan, DROPBEAR_KEEPALIVE_STRING);
} else {
TRACE(("keepalive global request"))
/* Some peers will reply with SSH_MSG_REQUEST_FAILURE,
some will reply with SSH_MSG_UNIMPLEMENTED, some will exit. */
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, DROPBEAR_KEEPALIVE_STRING,
strlen(DROPBEAR_KEEPALIVE_STRING));
}
buf_putbyte(ses.writepayload, 1); /* want_reply */
encrypt_packet();
ses.last_packet_time_keepalive_sent = monotonic_now();
/* keepalives shouldn't update idle timeout, reset it back */
ses.last_packet_time_idle = old_time_idle;
}
/* Check all timeouts which are required. Currently these are the time for
@@ -380,13 +432,8 @@ void send_msg_ignore() {
static void checktimeouts() {
time_t now;
now = time(NULL);
now = monotonic_now();
if (ses.connect_time != 0 && now - ses.connect_time >= AUTH_TIMEOUT) {
dropbear_close("Timeout before auth");
}
/* we can't rekey if we haven't done remote ident exchange yet */
if (ses.remoteident == NULL) {
return;
@@ -399,13 +446,30 @@ static void checktimeouts() {
send_msg_kexinit();
}
if (opts.keepalive_secs > 0
&& now - ses.last_trx_packet_time >= opts.keepalive_secs) {
send_msg_ignore();
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
/* Avoid sending keepalives prior to auth - those are
not valid pre-auth packet types */
/* Send keepalives if we've been idle */
if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
send_msg_keepalive();
}
/* Also send an explicit keepalive message to trigger a response
if the remote end hasn't sent us anything */
if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
&& now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
send_msg_keepalive();
}
if (now - ses.last_packet_time_keepalive_recv
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
dropbear_exit("Keepalive timeout");
}
}
if (opts.idle_timeout_secs > 0 && ses.last_packet_time > 0
&& now - ses.last_packet_time >= opts.idle_timeout_secs) {
if (opts.idle_timeout_secs > 0
&& now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
dropbear_close("Idle timeout");
}
}
@@ -416,12 +480,13 @@ static long select_timeout() {
long ret = LONG_MAX;
if (KEX_REKEY_TIMEOUT > 0)
ret = MIN(KEX_REKEY_TIMEOUT, ret);
if (AUTH_TIMEOUT > 0)
/* AUTH_TIMEOUT is only relevant before authdone */
if (ses.authstate.authdone != 1 && AUTH_TIMEOUT > 0)
ret = MIN(AUTH_TIMEOUT, ret);
if (opts.keepalive_secs > 0)
ret = MIN(opts.keepalive_secs, ret);
if (opts.idle_timeout_secs > 0)
ret = MIN(opts.idle_timeout_secs, ret);
if (opts.idle_timeout_secs > 0)
ret = MIN(opts.idle_timeout_secs, ret);
return ret;
}
@@ -470,3 +535,47 @@ void fill_passwd(const char* username) {
}
}
/* Called when channels are modified */
void update_channel_prio() {
enum dropbear_prio new_prio;
int any = 0;
unsigned int i;
TRACE(("update_channel_prio"))
new_prio = DROPBEAR_PRIO_BULK;
for (i = 0; i < ses.chansize; i++) {
struct Channel *channel = ses.channels[i];
if (!channel || channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
if (channel && channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
TRACE(("update_channel_prio: early %d", channel->index))
}
continue;
}
any = 1;
if (channel->prio == DROPBEAR_CHANNEL_PRIO_INTERACTIVE)
{
TRACE(("update_channel_prio: lowdelay %d", channel->index))
new_prio = DROPBEAR_PRIO_LOWDELAY;
break;
} else if (channel->prio == DROPBEAR_CHANNEL_PRIO_UNKNOWABLE
&& new_prio == DROPBEAR_PRIO_BULK)
{
TRACE(("update_channel_prio: unknowable %d", channel->index))
new_prio = DROPBEAR_PRIO_DEFAULT;
}
}
if (any == 0) {
/* lowdelay during setup */
TRACE(("update_channel_prio: not any"))
new_prio = DROPBEAR_PRIO_LOWDELAY;
}
if (new_prio != ses.socket_prio) {
TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio))
set_sock_priority(ses.sock_out, new_prio);
ses.socket_prio = new_prio;
}
}

645
config.guess vendored
View File

@@ -1,14 +1,12 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
# Inc.
# Copyright 1992-2013 Free Software Foundation, Inc.
timestamp='2007-01-15'
timestamp='2013-06-10'
# 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
# the Free Software Foundation; either version 2 of the License, or
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -17,26 +15,22 @@ timestamp='2007-01-15'
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Per Bothner <per@bothner.com>.
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
# the same distribution terms that you use for the rest of that
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1.
# Originally written by Per Bothner.
#
# The plan is that this can be called by configure scripts if you
# don't specify an explicit build system type.
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
me=`echo "$0" | sed -e 's,.*/,,'`
@@ -56,8 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Copyright 1992-2013 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."
@@ -139,12 +132,33 @@ 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
eval $set_cc_for_build
cat <<-EOF > $dummy.c
#include <features.h>
#if defined(__UCLIBC__)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
#else
LIBC=gnu
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
;;
esac
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
@@ -170,7 +184,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep __ELF__ >/dev/null
| grep -q __ELF__
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
@@ -180,7 +194,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
fi
;;
*)
os=netbsd
os=netbsd
;;
esac
# The OS release
@@ -201,6 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
exit ;;
*: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.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
@@ -223,7 +241,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
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
@@ -269,7 +287,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# 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'`
exit ;;
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
exit $exitcode ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
@@ -295,12 +316,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
echo s390-ibm-zvmoe
exit ;;
*:OS400:*:*)
echo powerpc-ibm-os400
echo powerpc-ibm-os400
exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit ;;
arm:riscos:*:*|arm:RISCOS:*:*)
arm*:riscos:*:*|arm*:RISCOS:*:*)
echo arm-unknown-riscos
exit ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
@@ -324,14 +345,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 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/[^.]*//'`
exit ;;
sun4H:SunOS:5.*:*)
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/[^.]*//'`
exit ;;
i86pc:SunOS:5.*:*)
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
echo i386-pc-auroraux${UNAME_RELEASE}
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
SUN_ARCH="i386"
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH="x86_64"
fi
fi
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
@@ -375,23 +415,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
echo m68k-milan-mint${UNAME_RELEASE}
exit ;;
echo m68k-milan-mint${UNAME_RELEASE}
exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
echo m68k-hades-mint${UNAME_RELEASE}
exit ;;
echo m68k-hades-mint${UNAME_RELEASE}
exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
echo m68k-unknown-mint${UNAME_RELEASE}
exit ;;
echo m68k-unknown-mint${UNAME_RELEASE}
exit ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
exit ;;
@@ -461,8 +501,8 @@ EOF
echo m88k-motorola-sysv3
exit ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
@@ -475,7 +515,7 @@ EOF
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
exit ;;
exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit ;;
@@ -532,7 +572,7 @@ EOF
echo rs6000-ibm-aix3.2
fi
exit ;;
*:AIX:*:[45])
*:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
@@ -575,52 +615,52 @@ EOF
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
32) HP_ARCH="hppa2.0n" ;;
64) HP_ARCH="hppa2.0w" ;;
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
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
32) HP_ARCH="hppa2.0n" ;;
64) HP_ARCH="hppa2.0w" ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
esac ;;
esac
esac ;;
esac
fi
if [ "${HP_ARCH}" = "" ]; then
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
sed 's/^ //' << EOF >$dummy.c
#define _HPUX_SOURCE
#include <stdlib.h>
#include <unistd.h>
#define _HPUX_SOURCE
#include <stdlib.h>
#include <unistd.h>
int main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
#endif
long cpu = sysconf (_SC_CPU_VERSION);
int main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
#endif
long cpu = sysconf (_SC_CPU_VERSION);
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
case CPU_PA_RISC2_0:
#if defined(_SC_KERNEL_BITS)
switch (bits)
{
case 64: puts ("hppa2.0w"); break;
case 32: puts ("hppa2.0n"); break;
default: puts ("hppa2.0"); break;
} break;
#else /* !defined(_SC_KERNEL_BITS) */
puts ("hppa2.0"); break;
#endif
default: puts ("hppa1.0"); break;
}
exit (0);
}
switch (cpu)
{
case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
case CPU_PA_RISC2_0:
#if defined(_SC_KERNEL_BITS)
switch (bits)
{
case 64: puts ("hppa2.0w"); break;
case 32: puts ("hppa2.0n"); break;
default: puts ("hppa2.0"); break;
} break;
#else /* !defined(_SC_KERNEL_BITS) */
puts ("hppa2.0"); break;
#endif
default: puts ("hppa1.0"); break;
}
exit (0);
}
EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
@@ -640,7 +680,7 @@ EOF
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep __LP64__ >/dev/null
grep -q __LP64__
then
HP_ARCH="hppa2.0w"
else
@@ -711,22 +751,22 @@ EOF
exit ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
exit ;;
exit ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
exit ;;
exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
exit ;;
exit ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
exit ;;
exit ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
exit ;;
exit ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
@@ -750,14 +790,14 @@ EOF
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/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
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/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
@@ -769,37 +809,51 @@ EOF
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
case ${UNAME_MACHINE} in
pc98)
echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
amd64)
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
esac
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
exit ;;
*:MINGW64*:*)
echo ${UNAME_MACHINE}-pc-mingw64
exit ;;
*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
i*:MSYS*:*)
echo ${UNAME_MACHINE}-pc-msys
exit ;;
i*:windows32*:*)
# uname -m includes "-pc" on this system.
echo ${UNAME_MACHINE}-mingw32
# uname -m includes "-pc" on this system.
echo ${UNAME_MACHINE}-mingw32
exit ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit ;;
x86:Interix*:[3456]*)
echo i586-pc-interix${UNAME_RELEASE}
exit ;;
EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*)
echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;;
*:Interix*:*)
case ${UNAME_MACHINE} in
x86)
echo i586-pc-interix${UNAME_RELEASE}
exit ;;
authenticamd | genuineintel | EM64T)
echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;;
IA64)
echo ia64-unknown-interix${UNAME_RELEASE}
exit ;;
esac ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
exit ;;
8664:Windows_NT:*)
echo x86_64-pc-mks
exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -820,93 +874,21 @@ EOF
exit ;;
*:GNU:*:*)
# the GNU system
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
arm*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
aarch64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
avr32*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
cris:Linux:*:*)
echo cris-axis-linux-gnu
exit ;;
crisv32:Linux:*:*)
echo crisv32-axis-linux-gnu
exit ;;
frv:Linux:*:*)
echo frv-unknown-linux-gnu
exit ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
mips:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef mips
#undef mipsel
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=mipsel
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=mips
#else
CPU=
#endif
#endif
EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
/^CPU/{
s: ::g
p
}'`"
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef mips64
#undef mips64el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=mips64el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=mips64
#else
CPU=
#endif
#endif
EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
/^CPU/{
s: ::g
p
}'`"
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
or32:Linux:*:*)
echo or32-unknown-linux-gnu
exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-gnu
exit ;;
ppc64:Linux:*:*)
echo powerpc64-unknown-linux-gnu
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -917,106 +899,132 @@ EOF
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arc:Linux:*:* | arceb:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arm*:Linux:*:*)
eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
else
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
fi
fi
exit ;;
avr32*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
cris:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
hexagon:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
i*86:Linux:*:*)
echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef ${UNAME_MACHINE}
#undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=${UNAME_MACHINE}el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=${UNAME_MACHINE}
#else
CPU=
#endif
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
;;
or1k:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
or32:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
padre:Linux:*:*)
echo sparc-unknown-linux-${LIBC}
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-${LIBC}
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
PA7*) echo hppa1.1-unknown-linux-gnu ;;
PA8*) echo hppa2.0-unknown-linux-gnu ;;
*) echo hppa-unknown-linux-gnu ;;
PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
*) echo hppa-unknown-linux-${LIBC} ;;
esac
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-gnu
ppc64:Linux:*:*)
echo powerpc64-unknown-linux-${LIBC}
exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-${LIBC}
exit ;;
ppc64le:Linux:*:*)
echo powerpc64le-unknown-linux-${LIBC}
exit ;;
ppcle:Linux:*:*)
echo powerpcle-unknown-linux-${LIBC}
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
exit ;;
sh64*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
tile*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-gnu
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;;
x86_64:Linux:*:*)
echo x86_64-unknown-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
xtensa:Linux:*:*)
echo xtensa-unknown-linux-gnu
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
i*86:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us. cd to the root directory to prevent
# problems with other programs or directories called `ld' in the path.
# Set LC_ALL=C to ensure ld outputs messages in English.
ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
| sed -ne '/supported targets:/!d
s/[ ][ ]*/ /g
s/.*supported targets: *//
s/ .*//
p'`
case "$ld_supported_targets" in
elf32-i386)
TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
;;
a.out-i386-linux)
echo "${UNAME_MACHINE}-pc-linux-gnuaout"
exit ;;
coff-i386)
echo "${UNAME_MACHINE}-pc-linux-gnucoff"
exit ;;
"")
# Either a pre-BFD a.out linker (linux-gnuoldld) or
# one that does not give us useful --help.
echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
exit ;;
esac
# Determine whether the default compiler is a.out or elf
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include <features.h>
#ifdef __ELF__
# ifdef __GLIBC__
# if __GLIBC__ >= 2
LIBC=gnu
# else
LIBC=gnulibc1
# endif
# else
LIBC=gnulibc1
# endif
#else
#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
LIBC=gnu
#else
LIBC=gnuaout
#endif
#endif
#ifdef __dietlibc__
LIBC=dietlibc
#endif
EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
/^LIBC/{
s: ::g
p
}'`"
test x"${LIBC}" != x && {
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit
}
test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
@@ -1024,11 +1032,11 @@ EOF
echo i386-sequent-sysv4
exit ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
# Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit ;;
i*86:OS/2:*:*)
@@ -1045,7 +1053,7 @@ EOF
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;;
i*86:*DOS:*:*)
@@ -1060,7 +1068,7 @@ EOF
fi
exit ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
# UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
@@ -1088,10 +1096,13 @@ EOF
exit ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i386.
echo i386-pc-msdosdjgpp
exit ;;
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configury will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit ;;
@@ -1126,8 +1137,18 @@ EOF
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4; exit; } ;;
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4; exit; } ;;
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`
/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 \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;;
@@ -1140,7 +1161,7 @@ EOF
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;;
SM[BE]S:UNIX_SV:*:*)
@@ -1160,10 +1181,10 @@ EOF
echo ns32k-sni-sysv
fi
exit ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
echo i586-unisys-sysv4
exit ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
echo i586-unisys-sysv4
exit ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <hewes@openmarket.com>.
# How about differentiating between stratus architectures? -djm
@@ -1189,11 +1210,11 @@ EOF
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
echo mips-unknown-sysv${UNAME_RELEASE}
fi
exit ;;
exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
exit ;;
@@ -1203,6 +1224,12 @@ EOF
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
exit ;;
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
echo i586-pc-haiku
exit ;;
x86_64:Haiku:*:*)
echo x86_64-unknown-haiku
exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
exit ;;
@@ -1229,9 +1256,21 @@ EOF
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
case $UNAME_PROCESSOR in
unknown) UNAME_PROCESSOR=powerpc ;;
esac
eval $set_cc_for_build
if test "$UNAME_PROCESSOR" = unknown ; then
UNAME_PROCESSOR=powerpc
fi
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
i386) UNAME_PROCESSOR=x86_64 ;;
powerpc) UNAME_PROCESSOR=powerpc64 ;;
esac
fi
fi
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
@@ -1245,7 +1284,10 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
NSE-?:NONSTOP_KERNEL:*:*)
NEO-?:NONSTOP_KERNEL:*:*)
echo neo-tandem-nsk${UNAME_RELEASE}
exit ;;
NSE-*:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
NSR-?:NONSTOP_KERNEL:*:*)
@@ -1290,13 +1332,13 @@ EOF
echo pdp10-unknown-its
exit ;;
SEI:*:*:SEIUX)
echo mips-sei-seiux${UNAME_RELEASE}
echo mips-sei-seiux${UNAME_RELEASE}
exit ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
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 ;;
@@ -1311,11 +1353,14 @@ EOF
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
exit ;;
i*86:AROS:*:*)
echo ${UNAME_MACHINE}-pc-aros
exit ;;
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
eval $set_cc_for_build
cat >$dummy.c <<EOF
#ifdef _SEQUENT_
@@ -1333,11 +1378,11 @@ main ()
#include <sys/param.h>
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
"4"
"4"
#else
""
""
#endif
); exit (0);
); exit (0);
#endif
#endif
@@ -1471,9 +1516,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
If the version you run ($0) is already up to date, please
send the following data and any information you think might be

379
config.sub vendored
View File

@@ -1,44 +1,40 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
# Inc.
# Copyright 1992-2013 Free Software Foundation, Inc.
timestamp='2007-01-18'
timestamp='2013-10-01'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
# can handle that machine. It does not imply ALL GNU software can.
#
# 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
# the Free Software Foundation; either version 2 of the License, or
# 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
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# the same distribution terms that you use for the rest of that
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
@@ -72,8 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Copyright 1992-2013 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."
@@ -120,12 +115,18 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
android-linux)
os=-linux-android
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
;;
*)
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ $basic_machine != $1 ]
@@ -148,10 +149,13 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis | -knuth | -cray)
-apple | -axis | -knuth | -cray | -microblaze*)
os=
basic_machine=$1
;;
-bluegene*)
os=-cnk
;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
@@ -166,10 +170,10 @@ case $os in
os=-chorusos
basic_machine=$1
;;
-chorusrdb)
os=-chorusrdb
-chorusrdb)
os=-chorusrdb
basic_machine=$1
;;
;;
-hiux*)
os=-hiuxwe2
;;
@@ -214,6 +218,12 @@ case $os in
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-lynx*178)
os=-lynxos178
;;
-lynx*5)
os=-lynxos5
;;
-lynx*)
os=-lynxos
;;
@@ -238,24 +248,35 @@ case $basic_machine in
# Some are omitted here because they have special meanings below.
1750a | 580 \
| a29k \
| aarch64 | aarch64_be \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
| arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
| be32 | be64 \
| bfin \
| c4x | clipper \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \
| epiphany \
| fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| k1om \
| le32 | le64 \
| lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
| maxq | mb | microblaze | mcore | mep \
| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
| mips64vr | mips64vrel \
| mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \
| mips64r5900 | mips64r5900el \
| mips64vr | mips64vrel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
@@ -266,31 +287,45 @@ case $basic_machine in
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| moxie \
| mt \
| msp430 \
| nios | nios2 \
| nds32 | nds32le | nds32be \
| nios | nios2 | nios2eb | nios2el \
| ns16k | ns32k \
| or32 \
| open8 \
| or1k | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
| rl78 | rx \
| score \
| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
| spu | strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| v850 | v850e \
| spu \
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| we32k \
| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
| z8k)
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
basic_machine=$basic_machine-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12)
# Motorola 68HC11/12.
c54x)
basic_machine=tic54x-unknown
;;
c55x)
basic_machine=tic55x-unknown
;;
c6x)
basic_machine=tic6x-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
@@ -300,6 +335,21 @@ case $basic_machine in
basic_machine=mt-unknown
;;
strongarm | thumb | xscale)
basic_machine=arm-unknown
;;
xgate)
basic_machine=$basic_machine-unknown
os=-none
;;
xscaleeb)
basic_machine=armeb-unknown
;;
xscaleel)
basic_machine=armel-unknown
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
@@ -314,29 +364,38 @@ case $basic_machine in
# Recognize the basic CPU types with company name.
580-* \
| a29k-* \
| aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| clipper-* | craynv-* | cydra-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
| k1om-* \
| le32-* | le64-* \
| lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | maxq-* | mcore-* \
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
| microblaze-* | microblazeel-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
| mips64vr-* | mips64vrel-* \
| mips64octeon-* | mips64octeonel-* \
| mips64orion-* | mips64orionel-* \
| mips64r5900-* | mips64r5900el-* \
| mips64vr-* | mips64vrel-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
@@ -347,31 +406,41 @@ case $basic_machine in
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipsr5900-* | mipsr5900el-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nios-* | nios2-* \
| nds32-* | nds32le-* | nds32be-* \
| nios-* | nios2-* | nios2eb-* | nios2el-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| open8-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
| romp-* | rs6000-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
| tron-* \
| v850-* | v850e-* | vax-* \
| ubicom32-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
| xstormy16-* | xtensa-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
| ymp-* \
| z8k-*)
| z8k-* | z80-*)
;;
# Recognize the basic CPU types without company name, with glob match.
xtensa*)
basic_machine=$basic_machine-unknown
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -389,7 +458,7 @@ case $basic_machine in
basic_machine=a29k-amd
os=-udi
;;
abacus)
abacus)
basic_machine=abacus-unknown
;;
adobe68k)
@@ -435,6 +504,10 @@ case $basic_machine in
basic_machine=m68k-apollo
os=-bsd
;;
aros)
basic_machine=i386-pc
os=-aros
;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -443,10 +516,35 @@ case $basic_machine in
basic_machine=ns32k-sequent
os=-dynix
;;
blackfin)
basic_machine=bfin-unknown
os=-linux
;;
blackfin-*)
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
bluegene*)
basic_machine=powerpc-ibm
os=-cnk
;;
c54x-*)
basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c55x-*)
basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c6x-*)
basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c90)
basic_machine=c90-cray
os=-unicos
;;
cegcc)
basic_machine=arm-unknown
os=-cegcc
;;
convex-c1)
basic_machine=c1-convex
os=-bsd
@@ -475,8 +573,8 @@ case $basic_machine in
basic_machine=craynv-cray
os=-unicosmp
;;
cr16c)
basic_machine=cr16c-unknown
cr16 | cr16-*)
basic_machine=cr16-unknown
os=-elf
;;
crds | unos)
@@ -514,6 +612,10 @@ case $basic_machine in
basic_machine=m88k-motorola
os=-sysv3
;;
dicos)
basic_machine=i686-pc
os=-dicos
;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
@@ -629,7 +731,6 @@ case $basic_machine in
i370-ibm* | ibm*)
basic_machine=i370-ibm
;;
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
@@ -668,6 +769,14 @@ case $basic_machine in
basic_machine=m68k-isi
os=-sysv
;;
m68knommu)
basic_machine=m68k-unknown
os=-linux
;;
m68knommu-*)
basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
m88k-omron*)
basic_machine=m88k-omron
;;
@@ -679,10 +788,21 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
microblaze*)
basic_machine=microblaze-xilinx
;;
mingw64)
basic_machine=x86_64-pc
os=-mingw64
;;
mingw32)
basic_machine=i386-pc
basic_machine=i686-pc
os=-mingw32
;;
mingw32ce)
basic_machine=arm-unknown
os=-mingw32ce
;;
miniframe)
basic_machine=m68000-convergent
;;
@@ -711,10 +831,18 @@ case $basic_machine in
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
msys)
basic_machine=i686-pc
os=-msys
;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
nacl)
basic_machine=le32-unknown
os=-nacl
;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
@@ -779,6 +907,12 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
neo-tandem)
basic_machine=neo-tandem
;;
nse-tandem)
basic_machine=nse-tandem
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
@@ -809,6 +943,14 @@ case $basic_machine in
basic_machine=i860-intel
os=-osf
;;
parisc)
basic_machine=hppa-unknown
os=-linux
;;
parisc-*)
basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
pbd)
basic_machine=sparc-tti
;;
@@ -853,9 +995,10 @@ case $basic_machine in
;;
power) basic_machine=power-ibm
;;
ppc) basic_machine=powerpc-unknown
ppc | ppcbe) basic_machine=powerpc-unknown
;;
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
@@ -880,7 +1023,11 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
rdos)
rdos | rdos64)
basic_machine=x86_64-pc
os=-rdos
;;
rdos32)
basic_machine=i386-pc
os=-rdos
;;
@@ -949,6 +1096,9 @@ case $basic_machine in
basic_machine=i860-stratus
os=-sysv4
;;
strongarm-* | thumb-*)
basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
sun2)
basic_machine=m68000-sun
;;
@@ -1005,17 +1155,9 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tic55x | c55x*)
basic_machine=tic55x-unknown
os=-coff
;;
tic6x | c6x*)
basic_machine=tic6x-unknown
os=-coff
tile*)
basic_machine=$basic_machine-unknown
os=-linux-gnu
;;
tx39)
basic_machine=mipstx39-unknown
@@ -1084,6 +1226,9 @@ case $basic_machine in
xps | xps100)
basic_machine=xps100-honeywell
;;
xscale-* | xscalee[bl]-*)
basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
;;
ymp)
basic_machine=ymp-cray
os=-unicos
@@ -1092,6 +1237,10 @@ case $basic_machine in
basic_machine=z8k-unknown
os=-sim
;;
z80-*-coff)
basic_machine=z80-unknown
os=-sim
;;
none)
basic_machine=none-none
os=-none
@@ -1130,7 +1279,7 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
@@ -1177,9 +1326,12 @@ esac
if [ x"$os" != x"" ]
then
case $os in
# First match some system type aliases
# that might get confused with valid system types.
# First match some system type aliases
# that might get confused with valid system types.
# -solaris* is a basic system type, with this one exception.
-auroraux)
os=-auroraux
;;
-solaris1 | -solaris1.*)
os=`echo $os | sed -e 's|solaris1|sunos4|'`
;;
@@ -1200,21 +1352,23 @@ case $os in
# Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* \
| -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -openbsd* | -solidbsd* \
| -bitrig* | -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
@@ -1222,7 +1376,7 @@ case $os in
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1261,7 +1415,7 @@ case $os in
-opened*)
os=-openedition
;;
-os400*)
-os400*)
os=-os400
;;
-wince*)
@@ -1310,7 +1464,7 @@ case $os in
-sinix*)
os=-sysv4
;;
-tpf*)
-tpf*)
os=-tpf
;;
-triton*)
@@ -1346,12 +1500,14 @@ case $os in
-aros*)
os=-aros
;;
-kaos*)
os=-kaos
;;
-zvmoe)
os=-zvmoe
;;
-dicos*)
os=-dicos
;;
-nacl*)
;;
-none)
;;
*)
@@ -1374,10 +1530,10 @@ else
# system, and we'll never get to this point.
case $basic_machine in
score-*)
score-*)
os=-elf
;;
spu-*)
spu-*)
os=-elf
;;
*-acorn)
@@ -1389,8 +1545,23 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
c4x-* | tic4x-*)
os=-coff
c4x-* | tic4x-*)
os=-coff
;;
c8051-*)
os=-elf
;;
hexagon-*)
os=-elf
;;
tic54x-*)
os=-coff
;;
tic55x-*)
os=-coff
;;
tic6x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
@@ -1410,14 +1581,11 @@ case $basic_machine in
;;
m68000-sun)
os=-sunos3
# This also exists in the configure program, but was not the
# default.
# os=-sunos4
;;
m68*-cisco)
os=-aout
;;
mep-*)
mep-*)
os=-elf
;;
mips*-cisco)
@@ -1426,6 +1594,9 @@ case $basic_machine in
mips*-*)
os=-elf
;;
or1k-*)
os=-elf
;;
or32-*)
os=-coff
;;
@@ -1444,7 +1615,7 @@ case $basic_machine in
*-ibm)
os=-aix
;;
*-knuth)
*-knuth)
os=-mmixware
;;
*-wec)
@@ -1549,7 +1720,7 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
-aix*)
-cnk*|-aix*)
vendor=ibm
;;
-beos*)

View File

@@ -5,8 +5,9 @@
# 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.50)
AC_INIT(buffer.c)
AC_PREREQ(2.59)
AC_INIT
AC_CONFIG_SRCDIR(buffer.c)
OLDCFLAGS=$CFLAGS
# Checks for programs.
@@ -20,7 +21,7 @@ AC_SUBST(LD)
if test -z "$OLDCFLAGS" && test "$GCC" = "yes"; then
AC_MSG_NOTICE(No \$CFLAGS set... using "-Os -W -Wall" for GCC)
CFLAGS="-Os -W -Wall"
CFLAGS="-Os -W -Wall -Wno-pointer-sign"
fi
# large file support is useful for scp
@@ -211,7 +212,7 @@ AC_ARG_ENABLE(shadow,
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.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])
AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.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])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -221,7 +222,8 @@ AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_CHECK_TYPES([uint16_t, u_int16_t, struct sockaddr_storage])
AC_CHECK_TYPES([uint8_t, u_int8_t, uint16_t, u_int16_t, uint32_t, u_int32_t])
AC_CHECK_TYPES([struct sockaddr_storage])
AC_CHECK_TYPE([socklen_t], ,[
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
@@ -231,15 +233,15 @@ AC_CHECK_TYPE([socklen_t], ,[
curl_cv_socklen_t_equiv=
for arg2 in "struct sockaddr" void; do
for t in int size_t unsigned long "unsigned long"; do
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/socket.h>
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
int getpeername (int, $arg2 *, $t *);
],[
]],[[
$t len;
getpeername(0,0,&len);
],[
]])],[
curl_cv_socklen_t_equiv="$t"
break
])
@@ -259,12 +261,11 @@ AC_CHECK_TYPE([socklen_t], ,[
# for the fake-rfc2553 stuff - straight from OpenSSH
AC_CACHE_CHECK([for struct sockaddr_storage], ac_cv_have_struct_sockaddr_storage, [
AC_TRY_COMPILE(
[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
],
[ struct sockaddr_storage s; ],
]],
[[ struct sockaddr_storage s; ]])],
[ ac_cv_have_struct_sockaddr_storage="yes" ],
[ ac_cv_have_struct_sockaddr_storage="no" ]
)
@@ -274,12 +275,11 @@ if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
fi
AC_CACHE_CHECK([for struct sockaddr_in6], ac_cv_have_struct_sockaddr_in6, [
AC_TRY_COMPILE(
[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
],
[ struct sockaddr_in6 s; s.sin6_family = 0; ],
]],
[[ struct sockaddr_in6 s; s.sin6_family = 0; ]])],
[ ac_cv_have_struct_sockaddr_in6="yes" ],
[ ac_cv_have_struct_sockaddr_in6="no" ]
)
@@ -289,12 +289,11 @@ if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
fi
AC_CACHE_CHECK([for struct in6_addr], ac_cv_have_struct_in6_addr, [
AC_TRY_COMPILE(
[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <netinet/in.h>
],
[ struct in6_addr s; s.s6_addr[0] = 0; ],
]],
[[ struct in6_addr s; s.s6_addr[0] = 0; ]])],
[ ac_cv_have_struct_in6_addr="yes" ],
[ ac_cv_have_struct_in6_addr="no" ]
)
@@ -304,13 +303,12 @@ if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
fi
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
AC_TRY_COMPILE(
[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
],
[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ],
]],
[[ struct addrinfo s; s.ai_flags = AI_PASSIVE; ]])],
[ ac_cv_have_struct_addrinfo="yes" ],
[ ac_cv_have_struct_addrinfo="no" ]
)
@@ -323,15 +321,15 @@ fi
# IRIX has a const char return value for gai_strerror()
AC_CHECK_FUNCS(gai_strerror,[
AC_DEFINE(HAVE_GAI_STRERROR)
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
const char *gai_strerror(int);],[
const char *gai_strerror(int);]],[[
char *str;
str = gai_strerror(0);],[
str = gai_strerror(0);]])],[
AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
[Define if gai_strerror() returns const char *])])])
@@ -363,16 +361,30 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
AC_CHECK_FUNCS(setutxent utmpxname)
AC_CHECK_FUNCS(logout updwtmp logwtmp)
# OS X monotonic time
AC_CHECK_HEADERS([mach/mach_time.h])
AC_CHECK_FUNCS(mach_absolute_time)
AC_ARG_ENABLE(bundled-libtom,
[ --enable-bundled-libtom Use bundled libtomcrypt/libtommath even if a system version exists],
[
BUNDLED_LIBTOM=1
AC_MSG_NOTICE(Forcing 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.],
[
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="$LIBTOM_LIBS -ltommath",
[AC_MSG_ERROR([Missing system libtommath and --disable-bundled-libtom was specified])] )
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt",
[AC_MSG_ERROR([Missing system libtomcrypt and --disable-bundled-libtom was specified])] )
fi
],
[
BUNDLED_LIBTOM=0
AC_CHECK_LIB(tomcrypt, register_cipher, , BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tommath, mp_exptmod, , BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tommath, mp_exptmod, LIBTOM_LIBS="$LIBTOM_LIBS -ltommath", BUNDLED_LIBTOM=1)
AC_CHECK_LIB(tomcrypt, register_cipher, LIBTOM_LIBS="$LIBTOM_LIBS -ltomcrypt", BUNDLED_LIBTOM=1)
]
)
@@ -380,6 +392,7 @@ if test $BUNDLED_LIBTOM = 1 ; then
AC_DEFINE(BUNDLED_LIBTOM,,Use bundled libtom)
fi
AC_SUBST(LIBTOM_LIBS)
AC_SUBST(BUNDLED_LIBTOM)
dnl Added from OpenSSH 3.6.1p2's configure.ac
@@ -443,7 +456,7 @@ dnl lastlog and [uw]tmp are subject to a file search if all else fails
dnl lastlog detection
dnl NOTE: the code itself will detect if lastlog is a directory
AC_MSG_CHECKING([if your system defines LASTLOG_FILE])
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
@@ -455,13 +468,13 @@ AC_TRY_COMPILE([
#ifdef HAVE_LOGIN_H
# include <login.h>
#endif
],
[ char *lastlog = LASTLOG_FILE; ],
]],
[[ char *lastlog = LASTLOG_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[
AC_MSG_RESULT(no)
AC_MSG_CHECKING([if your system defines _PATH_LASTLOG])
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
@@ -470,8 +483,8 @@ AC_TRY_COMPILE([
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
],
[ char *lastlog = _PATH_LASTLOG; ],
]],
[[ char *lastlog = _PATH_LASTLOG; ]])],
[ AC_MSG_RESULT(yes) ],
[
AC_MSG_RESULT(no)
@@ -500,14 +513,14 @@ fi
dnl utmp detection
AC_MSG_CHECKING([if your system defines UTMP_FILE])
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
],
[ char *utmp = UTMP_FILE; ],
]],
[[ char *utmp = UTMP_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_utmp_path=no ]
@@ -530,14 +543,16 @@ fi
dnl wtmp detection
AC_MSG_CHECKING([if your system defines WTMP_FILE])
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
],
[ char *wtmp = WTMP_FILE; ],
]],
[[ char *wtmp = WTMP_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_wtmp_path=no ]
@@ -563,7 +578,7 @@ dnl utmpx detection - I don't know any system so perverse as to require
dnl utmpx, but not define UTMPX_FILE (ditto wtmpx.) No doubt it's out
dnl there, though.
AC_MSG_CHECKING([if your system defines UTMPX_FILE])
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMPX_H
@@ -572,8 +587,8 @@ AC_TRY_COMPILE([
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
],
[ char *utmpx = UTMPX_FILE; ],
]],
[[ char *utmpx = UTMPX_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_utmpx_path=no ]
@@ -588,17 +603,19 @@ fi
dnl wtmpx detection
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
AC_TRY_COMPILE([
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#ifdef HAVE_UTMPX_H
#include <utmpx.h>
# include <utmpx.h>
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
],
[ char *wtmpx = WTMPX_FILE; ],
]],
[[ char *wtmpx = WTMPX_FILE; ]])],
[ AC_MSG_RESULT(yes) ],
[ AC_MSG_RESULT(no)
system_wtmpx_path=no ]
@@ -615,15 +632,16 @@ fi
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_TYPE_SIGNAL
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork])
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
# Solaris needs ptmx
if test -z "$no_ptmx_check" ; then
if test x"$cross_compiling" = x"no" ; then
AC_CHECK_FILE("/dev/ptmx", AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx))
if test -e /dev/ptmx ; then
AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx)
fi
else
AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
fi
@@ -631,7 +649,9 @@ fi
if test -z "$no_ptc_check" ; then
if test x"$cross_compiling" = x"no" ; then
AC_CHECK_FILE("/dev/ptc", AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts))
if test -e /dev/ptc ; then
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts)
fi
else
AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
fi
@@ -640,6 +660,7 @@ fi
AC_EXEEXT
# XXX there must be a nicer way to do this
if test $BUNDLED_LIBTOM = 1 ; then
AS_MKDIR_P(libtomcrypt/src/ciphers/aes)
AS_MKDIR_P(libtomcrypt/src/ciphers/safer)
AS_MKDIR_P(libtomcrypt/src/ciphers/twofish)
@@ -671,6 +692,7 @@ AS_MKDIR_P(libtomcrypt/src/modes/ofb)
AS_MKDIR_P(libtomcrypt/src/modes/f8)
AS_MKDIR_P(libtomcrypt/src/modes/lrw)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/bit)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/boolean)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/choice)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/ia5)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/integer)
@@ -678,18 +700,22 @@ AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/object_identifier)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/octet)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/printable_string)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/sequence)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/set)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/short_integer)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utctime)
AS_MKDIR_P(libtomcrypt/src/pk/asn1/der/utf8)
AS_MKDIR_P(libtomcrypt/src/pk/dh)
AS_MKDIR_P(libtomcrypt/src/pk/dsa)
AS_MKDIR_P(libtomcrypt/src/pk/ecc)
AS_MKDIR_P(libtomcrypt/src/pk/katja)
AS_MKDIR_P(libtomcrypt/src/pk/pkcs1)
AS_MKDIR_P(libtomcrypt/src/pk/rsa)
AS_MKDIR_P(libtomcrypt/src/prng)
AS_MKDIR_P(libtomcrypt/src/prngs)
LIBTOM_FILES="libtomcrypt/Makefile libtommath/Makefile"
fi
AC_CONFIG_HEADER(config.h)
AC_OUTPUT(Makefile)
AC_OUTPUT(libtomcrypt/Makefile)
AC_OUTPUT(libtommath/Makefile)
AC_CONFIG_FILES(Makefile $LIBTOM_FILES)
AC_OUTPUT
AC_MSG_NOTICE()
if test $BUNDLED_LIBTOM = 1 ; then

75
crypto_desc.c Normal file
View File

@@ -0,0 +1,75 @@
#include "includes.h"
#include "dbutil.h"
#include "crypto_desc.h"
#include "ltc_prng.h"
#include "ecc.h"
#ifdef DROPBEAR_LTC_PRNG
int dropbear_ltc_prng = -1;
#endif
/* Register the compiled in ciphers.
* This should be run before using any of the ciphers/hashes */
void crypto_init() {
const struct ltc_cipher_descriptor *regciphers[] = {
#ifdef DROPBEAR_AES
&aes_desc,
#endif
#ifdef DROPBEAR_BLOWFISH
&blowfish_desc,
#endif
#ifdef DROPBEAR_TWOFISH
&twofish_desc,
#endif
#ifdef DROPBEAR_3DES
&des3_desc,
#endif
NULL
};
const struct ltc_hash_descriptor *reghashes[] = {
/* we need sha1 for hostkey stuff regardless */
&sha1_desc,
#ifdef DROPBEAR_MD5_HMAC
&md5_desc,
#endif
#ifdef DROPBEAR_SHA256
&sha256_desc,
#endif
#ifdef DROPBEAR_SHA384
&sha384_desc,
#endif
#ifdef DROPBEAR_SHA512
&sha512_desc,
#endif
NULL
};
int i;
for (i = 0; regciphers[i] != NULL; i++) {
if (register_cipher(regciphers[i]) == -1) {
dropbear_exit("Error registering crypto");
}
}
for (i = 0; reghashes[i] != NULL; i++) {
if (register_hash(reghashes[i]) == -1) {
dropbear_exit("Error registering crypto");
}
}
#ifdef DROPBEAR_LTC_PRNG
dropbear_ltc_prng = register_prng(&dropbear_prng_desc);
if (dropbear_ltc_prng == -1) {
dropbear_exit("Error registering crypto");
}
#endif
#ifdef DROPBEAR_ECC
ltc_mp = ltm_desc;
dropbear_ecc_fill_dp();
#endif
}

9
crypto_desc.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef _CRYPTO_DESC_H
#define _CRYPTO_DESC_H
void crypto_init();
extern int dropbear_ltc_prng;
#endif /* _CRYPTO_DESC_H */

734
curve25519-donna.c Normal file
View File

@@ -0,0 +1,734 @@
/* 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.
*/
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. */
static void freduce_degree(limb *output) {
/* Each of these shifts and adds ends up multiplying the value by 19. */
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. */
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. */
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;
}
static inline s32
div_s32_by_2_25(const s32 v)
{
const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;
return (v + roundoff) >> 25;
}
/* Reduce all coefficients of the short form input so that |x| < 2^26.
*
* On entry: |output[i]| < 2^62
*/
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]);
output[i] -= over << 26;
output[i+1] += over;
over = div_by_2_25(output[i+1]);
output[i+1] -= over << 25;
output[i+2] += over;
}
/* Now |output[10]| < 2 ^ 38 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 * 2^38
* So |over| will be no more than 77825 */
{
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 + 77825
* So |over| will be no more than 1. */
{
/* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */
s32 over32 = div_s32_by_2_25((s32) output[1]);
output[1] -= over32 << 25;
output[2] += over32;
}
/* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":
* we have |output[2]| <= 2^26. This is good enough for all of our math,
* but it will require an extra freduce_coefficients before fcontract. */
}
/* A helpful wrapper around fproduct: output = in * in2.
*
* output must be distinct to both inputs. The output is reduced degree and
* reduced coefficient.
*/
static void
fmul(limb *output, const limb *in, const limb *in2) {
limb t[19];
fproduct(t, in, in2);
freduce_degree(t);
freduce_coefficients(t);
memcpy(output, t, sizeof(limb) * 10);
}
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]);
}
static void
fsquare(limb *output, const limb *in) {
limb t[19];
fsquare_inner(t, in);
freduce_degree(t);
freduce_coefficients(t);
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, 0x3ffffff);
#undef F
}
#if (-32 >> 1) != -16
#error "This code only works when >> does sign-extension on negative numbers"
#endif
/* Take a fully reduced polynomial form number and contract it into a
* little-endian, 32-byte array
*/
static void
fcontract(u8 *output, limb *input) {
int i;
int j;
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] positive
by borrowing from the next-larger limb.
*/
const s32 mask = (s32)(input[i]) >> 31;
const s32 carry = -(((s32)(input[i]) & mask) >> 25);
input[i] = (s32)(input[i]) + (carry << 25);
input[i+1] = (s32)(input[i+1]) - carry;
} else {
const s32 mask = (s32)(input[i]) >> 31;
const s32 carry = -(((s32)(input[i]) & mask) >> 26);
input[i] = (s32)(input[i]) + (carry << 26);
input[i+1] = (s32)(input[i+1]) - carry;
}
}
{
const s32 mask = (s32)(input[9]) >> 31;
const s32 carry = -(((s32)(input[9]) & mask) >> 25);
input[9] = (s32)(input[9]) + (carry << 25);
input[0] = (s32)(input[0]) - (carry * 19);
}
}
/* The first borrow-propagation pass above ended with every limb
except (possibly) input[0] non-negative.
Since each input limb except input[0] is decreased by at most 1
by a borrow-propagation pass, 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 = (s32)(input[0]) >> 31;
const s32 carry = -(((s32)(input[0]) & mask) >> 26);
input[0] = (s32)(input[0]) + (carry << 26);
input[1] = (s32)(input[1]) - carry;
}
/* Both passes through the above loop, plus the last 0-to-1 step, are
necessary: if input[9] is -1 and input[0] through input[8] are 0,
negative values will remain in the array until the end.
*/
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
*/
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);
fdifference(z, origx); // does x - z
memcpy(origxprime, xprime, sizeof(limb) * 10);
fsum(xprime, zprime);
fdifference(zprime, origxprime);
fproduct(xxprime, xprime, z);
fproduct(zzprime, x, zprime);
freduce_degree(xxprime);
freduce_coefficients(xxprime);
freduce_degree(zzprime);
freduce_coefficients(zzprime);
memcpy(origxprime, xxprime, sizeof(limb) * 10);
fsum(xxprime, zzprime);
fdifference(zzprime, origxprime);
fsquare(xxxprime, xxprime);
fsquare(zzzprime, zzprime);
fproduct(zzprime, zzzprime, qmqp);
freduce_degree(zzprime);
freduce_coefficients(zzprime);
memcpy(x3, xxxprime, sizeof(limb) * 10);
memcpy(z3, zzprime, sizeof(limb) * 10);
fsquare(xx, x);
fsquare(zz, z);
fproduct(x2, xx, zz);
freduce_degree(x2);
freduce_coefficients(x2);
fdifference(zz, xx); // does zz = xx - zz
memset(zzz + 10, 0, sizeof(limb) * 9);
fscalar_product(zzz, zz, 121665);
/* No need to call freduce_degree here:
fscalar_product doesn't increase the degree of its input. */
freduce_coefficients(zzz);
fsum(zzz, xx);
fproduct(z2, zz, zzz);
freduce_degree(z2);
freduce_coefficients(z2);
}
/* 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 *, const u8 *, const u8 *);
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);
freduce_coefficients(z);
fcontract(mypublic, z);
return 0;
}

View File

@@ -1,6 +1,6 @@
.TH dbclient 1
.SH NAME
dbclient \- lightweight SSH2 client
dbclient \- lightweight SSH client
.SH SYNOPSIS
.B dbclient
[\-Tt] [\-p
@@ -15,26 +15,25 @@ dbclient \- lightweight SSH2 client
.B dbclient
[
.I args ]
.I [user1]@host1[/port1],[user2]@host2[/port2],...
.I [user1]@host1[^port1],[user2]@host2[^port2],...
.SH DESCRIPTION
.B dbclient
is a SSH 2 client designed to be small enough to be used in small memory
environments, while still being functional and secure enough for general use.
is a small SSH client
.SH OPTIONS
.TP
.B \-p \fIport
Remote port.
Connect to port
Connect to
.I port
on the remote host.
on the remote host. Alternatively a port can be specified as hostname^port.
Default is 22.
.TP
.B \-i \fIidfile
Identity file.
Read the identity from file
Read the identity key from file
.I idfile
(multiple allowed).
(multiple allowed). This file is created with dropbearkey(1) or converted
from OpenSSH with dropbearconvert(1). The default path ~/.ssh/id_dropbear is used
.TP
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
Local port forwarding.
@@ -61,10 +60,10 @@ Login as
on the remote host.
.TP
.B \-t
Allocate a pty.
Allocate a PTY.
.TP
.B \-T
Don't allocate a pty.
Don't allocate a PTY.
.TP
.B \-N
Don't request a remote shell or run any commands. Any command arguments are ignored.
@@ -80,7 +79,8 @@ by the ssh server.
.TP
.B \-y
Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the
connection will abort as normal.
connection will abort as normal. If specified a second time no host key checking
is performed at all, this is usually undesirable.
.TP
.B \-A
Forward agent connections to the remote host. dbclient will use any
@@ -97,7 +97,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 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.
@@ -120,13 +120,16 @@ Specify a comma separated list of authentication MACs to enable. Use \fI-m help\
.TP
.B \-s
The specified command will be requested as a subsystem, used for sftp. Dropbear doesn't implement sftp itself but the OpenSSH sftp client can be used eg \fIsftp -S dbclient user@host\fR
.TP
.B \-V
Print the version
.SH MULTI-HOP
Dropbear will also allow multiple "hops" to be specified, separated by commas. In
this case a connection will be made to the first host, then a TCP forwarded
connection will be made through that to the second host, and so on. Hosts other than
the final destination will not see anything other than the encrypted SSH stream.
A port for a host can be specified with a slash (eg matt@martello/44 ).
A port for a host can be specified with a hash (eg matt@martello^44 ).
This syntax can also be used with scp or rsync (specifying dbclient as the
ssh/rsh command). A file can be "bounced" through multiple SSH hops, eg
@@ -136,6 +139,11 @@ Note that hostnames are resolved by the prior hop (so "canyons" would be resolve
in the example above, the same way as other -L TCP forwarded hosts are. Host keys are
checked locally based on the given hostname.
.SH ESCAPE CHARACTERS
Typing a newline followed by the key sequence \fI~.\fR (tilde, dot) will terminate a connection.
The sequence \fI~^Z\fR (tilde, ctrl-z) will background the connection. This behaviour only
applies when a PTY is used.
.SH ENVIRONMENT
.TP
.B DROPBEAR_PASSWORD
@@ -156,6 +164,6 @@ Mihnea Stoenescu wrote initial Dropbear client support
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dropbearkey(8)
dropbear(8), dropbearkey(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -26,7 +26,8 @@
#include "buffer.h"
#include "dbutil.h"
#include "bignum.h"
#include "random.h"
#include "dbrandom.h"
/* this is used to generate unique output from the same hashpool */
static uint32_t counter = 0;
@@ -77,17 +78,20 @@ process_file(hash_state *hs, const char *filename,
while (len == 0 || readcount < len)
{
int readlen, wantread;
unsigned char readbuf[2048];
if (!already_blocked)
unsigned char readbuf[4096];
if (!already_blocked && !prngd)
{
int ret;
struct timeval timeout = { .tv_sec = 2, .tv_usec = 0};
int res;
struct timeval timeout;
fd_set read_fds;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
FD_ZERO(&read_fds);
FD_SET(readfd, &read_fds);
ret = select(readfd + 1, &read_fds, NULL, NULL, &timeout);
if (ret == 0)
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;
@@ -157,6 +161,9 @@ static void write_urandom()
/* This is opportunistic, don't worry about failure */
unsigned char buf[INIT_SEED_SIZE];
FILE *f = fopen(DROPBEAR_URANDOM_DEV, "w");
if (!f) {
return;
}
genrandom(buf, sizeof(buf));
fwrite(buf, sizeof(buf), 1, f);
fclose(f);
@@ -205,20 +212,21 @@ void seedrandom() {
process_file(&hs, "/proc/loadavg", 0, 0);
process_file(&hs, "/proc/sys/kernel/random/entropy_avail", 0, 0);
/* Mostly network visible but useful in some situations */
process_file(&hs, "/proc/net/netstat", 0, 0);
process_file(&hs, "/proc/net/dev", 0, 0);
process_file(&hs, "/proc/net/tcp", 0, 0);
/* Mostly network visible but useful in some situations.
* Limit size to avoid slowdowns on systems with lots of routes */
process_file(&hs, "/proc/net/netstat", 4096, 0);
process_file(&hs, "/proc/net/dev", 4096, 0);
process_file(&hs, "/proc/net/tcp", 4096, 0);
/* Also includes interface lo */
process_file(&hs, "/proc/net/rt_cache", 0, 0);
process_file(&hs, "/proc/net/rt_cache", 4096, 0);
process_file(&hs, "/proc/vmstat", 0, 0);
#endif
pid = getpid();
sha1_process(&hs, (void*)&pid, sizeof(pid));
// gettimeofday() doesn't completely fill out struct timeval on
// OS X (10.8.3), avoid valgrind warnings by clearing it first
/* gettimeofday() doesn't completely fill out struct timeval on
OS X (10.8.3), avoid valgrind warnings by clearing it first */
memset(&tv, 0x0, sizeof(tv));
gettimeofday(&tv, NULL);
sha1_process(&hs, (void*)&tv, sizeof(tv));

View File

@@ -25,7 +25,7 @@
#ifndef _RANDOM_H_
#define _RANDOM_H_
struct mp_int;
#include "includes.h"
void seedrandom();
void genrandom(unsigned char* buf, unsigned int len);

196
dbutil.c
View File

@@ -48,6 +48,19 @@
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#ifdef __linux__
#define _GNU_SOURCE
/* To call clock_gettime() directly */
#include <sys/syscall.h>
#endif /* __linux */
#ifdef HAVE_MACH_MACH_TIME_H
#include <mach/mach_time.h>
#include <mach/mach.h>
#endif
#include "includes.h"
#include "dbutil.h"
#include "buffer.h"
@@ -138,43 +151,90 @@ void dropbear_log(int priority, const char* format, ...) {
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...) {
va_list param;
struct timeval tv;
if (!debug_trace) {
return;
}
gettimeofday(&tv, NULL);
va_start(param, format);
fprintf(stderr, "TRACE (%d): ", getpid());
fprintf(stderr, "TRACE (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
void dropbear_trace2(const char* format, ...) {
static int trace_env = -1;
va_list param;
struct timeval tv;
if (trace_env == -1) {
trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
}
if (!(debug_trace && trace_env)) {
return;
}
gettimeofday(&tv, NULL);
va_start(param, format);
fprintf(stderr, "TRACE2 (%d) %d.%d: ", getpid(), (int)tv.tv_sec, (int)tv.tv_usec);
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
#endif /* DEBUG_TRACE */
static void set_sock_priority(int sock) {
void set_sock_nodelay(int sock) {
int val;
/* disable nagle */
val = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
}
void set_sock_priority(int sock, enum dropbear_prio prio) {
int iptos_val = 0, so_prio_val = 0, rc;
/* Don't log ENOTSOCK errors so that this can harmlessly be called
* on a client '-J' proxy pipe */
/* set the TOS bit for either ipv4 or ipv6 */
#ifdef IPTOS_LOWDELAY
val = IPTOS_LOWDELAY;
if (prio == DROPBEAR_PRIO_LOWDELAY) {
iptos_val = IPTOS_LOWDELAY;
} else if (prio == DROPBEAR_PRIO_BULK) {
iptos_val = IPTOS_THROUGHPUT;
}
#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0 && errno != ENOTSOCK) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
#endif
#ifdef SO_PRIORITY
/* linux specific, sets QoS class.
* 6 looks to be optimal for interactive traffic (see tc-prio(8) ). */
val = 6;
setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
if (prio == DROPBEAR_PRIO_LOWDELAY) {
so_prio_val = TC_PRIO_INTERACTIVE;
} else if (prio == DROPBEAR_PRIO_BULK) {
so_prio_val = TC_PRIO_BULK;
}
/* linux specific, sets QoS class. see tc-prio(8) */
rc = setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &so_prio_val, sizeof(so_prio_val));
if (rc < 0 && errno != ENOTSOCK)
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
strerror(errno));
#endif
}
@@ -266,7 +326,7 @@ int dropbear_listen(const char* address, const char* port,
}
#endif
set_sock_priority(sock);
set_sock_nodelay(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
@@ -275,7 +335,7 @@ int dropbear_listen(const char* address, const char* port,
continue;
}
if (listen(sock, 20) < 0) {
if (listen(sock, DROPBEAR_LISTEN_BACKLOG) < 0) {
err = errno;
close(sock);
TRACE(("listen() failed"))
@@ -405,7 +465,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
TRACE(("Error connecting: %s", strerror(err)))
} else {
/* Success */
set_sock_priority(sock);
set_sock_nodelay(sock);
}
freeaddrinfo(res0);
@@ -651,6 +711,14 @@ void printhex(const char * label, const unsigned char * buf, int len) {
}
fprintf(stderr, "\n");
}
void printmpint(const char *label, mp_int *mp) {
buffer *buf = buf_new(1000);
buf_putmpint(buf, mp);
printhex(label, buf->data, buf->len);
buf_free(buf);
}
#endif
/* Strip all control characters from text (a null-terminated string), except
@@ -725,8 +793,6 @@ int buf_getline(buffer * line, FILE * authfile) {
int c = EOF;
TRACE(("enter buf_getline"))
buf_setpos(line, 0);
buf_setlen(line, 0);
@@ -750,10 +816,8 @@ out:
/* if we didn't read anything before EOF or error, exit */
if (c == EOF && line->pos == 0) {
TRACE(("leave buf_getline: failure"))
return DROPBEAR_FAILURE;
} else {
TRACE(("leave buf_getline: success"))
buf_setpos(line, 0);
return DROPBEAR_SUCCESS;
}
@@ -764,6 +828,10 @@ out:
/* make sure that the socket closes */
void m_close(int fd) {
if (fd == -1) {
return;
}
int val;
do {
val = close(fd);
@@ -853,14 +921,100 @@ 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;
*val = strtoul(str, NULL, 10);
l = strtoul(str, NULL, 10);
/* The c99 spec doesn't actually seem to define EINVAL, but most platforms
* I've looked at mention it in their manpage */
if ((*val == 0 && errno == EINVAL)
|| (*val == ULONG_MAX && errno == ERANGE)) {
if ((l == 0 && errno == EINVAL)
|| (l == ULONG_MAX && errno == ERANGE)
|| (l > UINT_MAX)) {
return DROPBEAR_FAILURE;
} else {
*val = l;
return DROPBEAR_SUCCESS;
}
}
/* Returns malloced path. Only expands ~ in first character */
char * expand_tilde(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) + 1;
char *buf = m_malloc(len);
snprintf(buf, len, "%s/%s", pw->pw_dir, &inpath[1]);
return buf;
}
}
/* Fallback */
return m_strdup(inpath);
}
int constant_time_memcmp(const void* a, const void *b, size_t n)
{
const char *xa = a, *xb = b;
uint8_t c = 0;
size_t i;
for (i = 0; i < n; i++)
{
c |= (xa[i] ^ xb[i]);
}
return c;
}
#if defined(__linux__) && defined(SYS_clock_gettime)
/* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
reach userspace include headers */
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE 6
#endif
static clockid_t get_linux_clock_source() {
struct timespec ts;
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
return CLOCK_MONOTONIC_COARSE;
}
if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
return CLOCK_MONOTONIC;
}
return -1;
}
#endif
time_t monotonic_now() {
#if defined(__linux__) && defined(SYS_clock_gettime)
static clockid_t clock_source = -2;
if (clock_source == -2) {
/* First run, find out which one works.
-1 will fall back to time() */
clock_source = get_linux_clock_source();
}
if (clock_source >= 0) {
struct timespec ts;
if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
/* Intermittent clock failures should not happen */
dropbear_exit("Clock broke");
}
return ts.tv_sec;
}
#endif /* linux clock_gettime */
#if defined(HAVE_MACH_ABSOLUTE_TIME)
/* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
static mach_timebase_info_data_t timebase_info;
if (timebase_info.denom == 0) {
mach_timebase_info(&timebase_info);
}
return mach_absolute_time() * timebase_info.numer / timebase_info.denom
/ 1e9;
#endif /* osx mach_absolute_time */
/* Fallback for everything else - this will sometimes go backwards */
return time(NULL);
}

View File

@@ -35,14 +35,12 @@ void startsyslog();
#ifdef __GNUC__
#define ATTRIB_PRINTF(fmt,args) __attribute__((format(printf, fmt, args)))
#define ATTRIB_NORETURN __attribute__((noreturn))
#define ATTRIB_SENTINEL __attribute__((sentinel))
#else
#define ATTRIB_PRINTF(fmt,args)
#endif
#ifdef __GNUC__
#define ATTRIB_NORETURN __attribute__((noreturn))
#else
#define ATTRIB_NORETURN
#define ATTRIB_SENTINEL
#endif
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
@@ -57,15 +55,25 @@ void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
void printhex(const char * label, const unsigned char * buf, int len);
void printmpint(const char *label, mp_int *mp);
extern int debug_trace;
#endif
enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT = 10,
DROPBEAR_PRIO_LOWDELAY = 11,
DROPBEAR_PRIO_BULK = 12,
};
char * stripcontrol(const char * text);
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup);
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port, int host_lookup);
void set_sock_nodelay(int sock);
void set_sock_priority(int sock, enum dropbear_prio prio);
int dropbear_listen(const char* address, const char* port,
int *socks, unsigned int sockcount, char **errstring, int *maxfd);
int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
@@ -83,7 +91,7 @@ void m_close(int fd);
void * m_malloc(size_t size);
void * m_strdup(const char * str);
void * m_realloc(void* ptr, size_t size);
#define m_free(X) free(X); (X) = NULL;
#define m_free(X) do {free(X); (X) = NULL;} while (0);
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
void disallow_core();
@@ -95,4 +103,13 @@ int m_str_to_uint(const char* str, unsigned int *val);
/* Dropbear assertion */
#define dropbear_assert(X) do { if (!(X)) { fail_assert(#X, __FILE__, __LINE__); } } while (0)
/* Returns 0 if a and b have the same contents */
int constant_time_memcmp(const void* a, const void *b, size_t n);
/* Returns a time in seconds that doesn't go backwards - does not correspond to
a real-world clock */
time_t monotonic_now();
char * expand_tilde(const char *inpath);
#endif /* _DBUTIL_H_ */

61
debian/changelog vendored
View File

@@ -1,3 +1,64 @@
dropbear (2015.67-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 28 Jan 2015 22:53:59 +0800
dropbear (2014.66-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 23 Oct 2014 22:54:00 +0800
dropbear (2014.65-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Fri, 8 Aug 2014 22:54:00 +0800
dropbear (2014.64-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Sun, 27 Jul 2014 22:54:00 +0800
dropbear (2014.63-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Feb 2014 22:54:00 +0800
dropbear (2013.62) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Tue, 7 Dec 2013 22:54:00 +0800
dropbear (2013.60-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 16 Oct 2013 22:54:00 +0800
dropbear (2013.59-0.1) unstable; urgency=low
* New upstream release.
* Build with DEB_BUILD_MAINT_OPTIONS = hardening=+all
-- Matt Johnston <matt@ucc.asn.au> Fri, 4 Oct 2013 22:54:00 +0800
dropbear (2013.58-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 18 Apr 2013 22:54:00 +0800
dropbear (2013.57-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Mon, 15 Apr 2013 22:54:00 +0800
dropbear (2013.56-0.1) unstable; urgency=low
* New upstream release.

19
debian/rules vendored
View File

@@ -1,5 +1,9 @@
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk
#export DH_OPTIONS
DEB_HOST_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
@@ -9,13 +13,6 @@ ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
STRIP =: nostrip
endif
CFLAGS =-Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS +=-O0
else
CFLAGS +=-O2
endif
CONFFLAGS =
CC =gcc
ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
@@ -79,12 +76,12 @@ install: deb-checkdir deb-checkuid build-stamp
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
# man pages
install -d -m0755 '$(DIR)'/usr/share/man/man8
for i in dropbear.8 dropbearkey.8; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
install -d -m0755 '$(DIR)'/usr/share/man/man1
install -m644 dropbear.8 '$(DIR)'/usr/share/man/man8/
for i in dbclient.1 dropbearkey.1 dropbearconvert.1; do \
install -m644 $$i '$(DIR)'/usr/share/man/man1/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
install -d -m0755 '$(DIR)'/usr/share/man/man1
install -m644 dbclient.1 '$(DIR)'/usr/share/man/man1/
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
# copyright, changelog
cat debian/copyright.in LICENSE >debian/copyright

View File

@@ -39,7 +39,7 @@
* Caution: Don't use this in an unfriendly environment (ie unfirewalled),
* since the printing may not sanitise strings etc. This will add a reasonable
* amount to your executable size. */
/*#define DEBUG_TRACE */
/* #define DEBUG_TRACE */
/* All functions writing to the cleartext payload buffer call
* CHECKCLEARTOWRITE() before writing. This is only really useful if you're
@@ -63,8 +63,10 @@
/* you don't need to touch this block */
#ifdef DEBUG_TRACE
#define TRACE(X) dropbear_trace X;
#define TRACE2(X) dropbear_trace2 X;
#else /*DEBUG_TRACE*/
#define TRACE(X)
#define TRACE2(X)
#endif /*DEBUG_TRACE*/
/* To debug with GDB it is easier to run with no forking of child processes.

View File

@@ -1,17 +1,16 @@
.TH dropbear 8
.SH NAME
dropbear \- lightweight SSH2 server
dropbear \- lightweight SSH server
.SH SYNOPSIS
.B dropbear
[\-FEmwsgjki] [\-b
.I banner\fR] [\-d
.I dsskey\fR] [\-r
.I rsakey\fR] [\-p
[\-RFEmwsgjki] [\-b
.I banner\fR]
[\-r
.I hostkeyfile\fR] [\-p
.IR [address:]port ]
.SH DESCRIPTION
.B dropbear
is a SSH 2 server designed to be small enough to be used in small memory
environments, while still being functional and secure enough for general use.
is a small SSH server
.SH OPTIONS
.TP
.B \-b \fIbanner
@@ -20,24 +19,16 @@ Display the contents of the file
.I banner
before user login (default: none).
.TP
.B \-d \fIdsskey
dsskeyfile.
.B \-r \fIhostkey
Use the contents of the file
.I dsskey
for the DSS host key (default: /etc/dropbear/dropbear_dss_host_key).
Note that
some SSH implementations
use the term "DSA" rather than "DSS", they mean the same thing.
.I hostkey
for the SSH hostkey.
This file is generated with
.BR dropbearkey (8).
.BR dropbearkey (1)
or automatically with the '-R' option. See "Host Key Files" below.
.TP
.B \-r \fIrsakey
rsakeyfile.
Use the contents of the file
.I rsakey
for the rsa host key (default: /etc/dropbear/dropbear_rsa_host_key).
This file is generated with
.BR dropbearkey (8).
.B \-R
Generate hostkeys automatically. See "Host Key Files" below.
.TP
.B \-F
Don't fork into background.
@@ -96,10 +87,14 @@ 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 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.
.TP
.B \-V
Print the version
.SH FILES
.TP
@@ -143,9 +138,13 @@ key authentication.
Host Key Files
Host key files are read at startup from a standard location, by default
/etc/dropbear/dropbear_dss_host_key and /etc/dropbear/dropbear_rsa_host_key
or specified on the commandline with -d or -r. These are of the form generated
by dropbearkey.
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
/etc/dropbear/dropbear-ecdsa_host_key
or specified on the commandline with -r. These are of the form generated
by dropbearkey. The -R option can be used to automatically generate keys
in the default location - keys will be generated after startup when the first
connection is established. This had the benefit that the system /dev/urandom
random number source has a better chance of being securely seeded.
.TP
Message Of The Day
@@ -180,13 +179,14 @@ in this variable. If a shell was requested this is set to an empty value.
.B SSH_AUTH_SOCK
Set to a forwarded ssh-agent connection.
.SH NOTES
Dropbear only supports SSH protocol version 2.
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbearkey(8), dbclient(1)
dropbearkey(1), dbclient(1), dropbearconvert(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

50
dropbearconvert.1 Normal file
View File

@@ -0,0 +1,50 @@
.TH dropbearconvert 1
.SH NAME
dropbearconvert \- convert between Dropbear and OpenSSH private key formats
.SH SYNOPSIS
.B dropbearconvert
.I input_type
.I output_type
.I input_file
.I output_file
.SH DESCRIPTION
.B Dropbear
and
.B OpenSSH
SSH implementations have different private key formats.
.B dropbearconvert
can convert between the two.
.P
Dropbear uses the same SSH public key format as OpenSSH, it can be extracted
from a private key by using
.B dropbearkey \-y
.P
Encrypted private keys are not supported, use ssh-keygen(1) to decrypt them
first.
.SH OPTIONS
.TP
.B input type
Either
.I dropbear
or
.I openssh
.TP
.B output type
Either
.I dropbear
or
.I openssh
.TP
.B input file
An existing Dropbear or OpenSSH private key file
.TP
.B output file
The path to write the converted private key file. For client authentication ~/.ssh/id_dropbear is loaded by default
.SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/id_dropbear
.SH AUTHOR
Matt Johnston (matt@ucc.asn.au).
.SH SEE ALSO
dropbearkey(1), ssh-keygen(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -28,6 +28,8 @@
#include "buffer.h"
#include "dbutil.h"
#include "keyimport.h"
#include "crypto_desc.h"
#include "dbrandom.h"
static int do_convert(int intype, const char* infile, int outtype,
@@ -62,6 +64,9 @@ int main(int argc, char ** argv) {
const char* infile;
const char* outfile;
crypto_init();
seedrandom();
#ifdef DEBUG_TRACE
/* It's hard for it to get in the way _too_ much */
debug_trace = 1;
@@ -111,7 +116,7 @@ static int do_convert(int intype, const char* infile, int outtype,
const char* outfile) {
sign_key * key = NULL;
char * keytype = NULL;
const char * keytype = NULL;
int ret = 1;
key = import_read(infile, NULL, intype);
@@ -121,16 +126,7 @@ static int do_convert(int intype, const char* infile, int outtype,
goto out;
}
#ifdef DROPBEAR_RSA
if (key->rsakey != NULL) {
keytype = "RSA";
}
#endif
#ifdef DROPBEAR_DSS
if (key->dsskey != NULL) {
keytype = "DSS";
}
#endif
keytype = signkey_name_from_type(key->type, NULL);
fprintf(stderr, "Key is a %s key\n", keytype);

View File

@@ -1,6 +1,6 @@
.TH dropbearkey 8
.TH dropbearkey 1
.SH NAME
dropbearkey \- create private keys for the use with dropbear(8)
dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
.SH SYNOPSIS
.B dropbearkey
\-t
@@ -12,12 +12,12 @@ dropbearkey \- create private keys for the use with dropbear(8)
.SH DESCRIPTION
.B dropbearkey
generates a
.I RSA
.I RSA
.I DSS,
or
.I DSS
.I ECDSA
format SSH private key, and saves it to a file for the use with the
.BR dropbear (8)
SSH 2 server.
Dropbear client or server.
Note that
some SSH implementations
use the term "DSA" rather than "DSS", they mean the same thing.
@@ -27,17 +27,22 @@ use the term "DSA" rather than "DSS", they mean the same thing.
Type of key to generate.
Must be one of
.I rsa
.I ecdsa
or
.IR dss .
.TP
.B \-f \fIfile
Write the secret key to the file
.IR file .
.IR file . For client authentication ~/.ssh/id_dropbear is loaded by default
.TP
.B \-s \fIbits
Set the key size to
.I bits
bits, should be multiple of 8 (optional).
bits, should be multiple of 8 (optional).
.SH NOTES
The program dropbearconvert(1) can be used to convert between Dropbear and OpenSSH key formats.
.P
Dropbear does not support encrypted keys.
.SH EXAMPLE
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
.SH AUTHOR
@@ -45,6 +50,6 @@ Matt Johnston (matt@ucc.asn.au).
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dbclient(1)
dropbear(8), dbclient(1), dropbearconvert(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -51,15 +51,16 @@
#include "genrsa.h"
#include "gendss.h"
#include "ecdsa.h"
#include "crypto_desc.h"
#include "dbrandom.h"
#include "gensignkey.h"
static void printhelp(char * progname);
#define RSA_SIZE (1024/8) /* 1024 bit */
#define DSS_SIZE (1024/8) /* 1024 bit */
static void buf_writefile(buffer * buf, const char * filename);
static void printpubkey(sign_key * key, int keytype);
static void justprintpub(const char* filename);
static int printpubfile(const char* filename);
/* Print a help message */
static void printhelp(char * progname) {
@@ -72,9 +73,28 @@ static void printhelp(char * progname) {
#ifdef DROPBEAR_DSS
" dss\n"
#endif
"-f filename Use filename for the secret key\n"
#ifdef DROPBEAR_ECDSA
" ecdsa\n"
#endif
"-f filename Use filename for the secret key.\n"
" ~/.ssh/id_dropbear is recommended for client keys.\n"
"-s bits Key size in bits, should be a multiple of 8 (optional)\n"
" (DSS has a fixed size of 1024 bits)\n"
#ifdef DROPBEAR_DSS
" DSS has a fixed size of 1024 bits\n"
#endif
#ifdef DROPBEAR_ECDSA
" ECDSA has sizes "
#ifdef DROPBEAR_ECC_256
"256 "
#endif
#ifdef DROPBEAR_ECC_384
"384 "
#endif
#ifdef DROPBEAR_ECC_521
"521 "
#endif
"\n"
#endif
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
@@ -82,6 +102,30 @@ static void printhelp(char * progname) {
,progname);
}
/* fails fatally */
static void check_signkey_bits(enum signkey_type type, int bits)
{
switch (type) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8\n");
}
break;
#endif
#ifdef DROPEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
if (bits != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
}
#endif
default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */
}
}
#if defined(DBMULTI_dropbearkey) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dropbearkey) && defined(DROPBEAR_MULTI)
int dropbearkey_main(int argc, char ** argv) {
@@ -91,16 +135,16 @@ int main(int argc, char ** argv) {
int i;
char ** next = 0;
sign_key *key = NULL;
buffer *buf = NULL;
char * filename = NULL;
int keytype = -1;
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
char * typetext = NULL;
char * sizetext = NULL;
unsigned int bits;
unsigned int keysize;
unsigned int bits = 0;
int printpub = 0;
crypto_init();
seedrandom();
/* get the commandline options */
for (i = 1; i < argc; i++) {
if (argv[i] == NULL) {
@@ -151,8 +195,8 @@ int main(int argc, char ** argv) {
}
if (printpub) {
justprintpub(filename);
/* Not reached */
int ret = printpubfile(filename);
exit(ret);
}
/* check/parse args */
@@ -162,21 +206,26 @@ int main(int argc, char ** argv) {
exit(EXIT_FAILURE);
}
if (strlen(typetext) == 3) {
#ifdef DROPBEAR_RSA
if (strncmp(typetext, "rsa", 3) == 0) {
keytype = DROPBEAR_SIGNKEY_RSA;
TRACE(("type is rsa"))
}
if (strcmp(typetext, "rsa") == 0)
{
keytype = DROPBEAR_SIGNKEY_RSA;
}
#endif
#ifdef DROPBEAR_DSS
if (strncmp(typetext, "dss", 3) == 0) {
keytype = DROPBEAR_SIGNKEY_DSS;
TRACE(("type is dss"))
}
#endif
if (strcmp(typetext, "dss") == 0)
{
keytype = DROPBEAR_SIGNKEY_DSS;
}
if (keytype == -1) {
#endif
#ifdef DROPBEAR_ECDSA
if (strcmp(typetext, "ecdsa") == 0)
{
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
}
#endif
if (keytype == DROPBEAR_SIGNKEY_NONE) {
fprintf(stderr, "Unknown key type '%s'\n", typetext);
printhelp(argv[0]);
exit(EXIT_FAILURE);
@@ -188,75 +237,26 @@ int main(int argc, char ** argv) {
exit(EXIT_FAILURE);
}
if (keytype == DROPBEAR_SIGNKEY_DSS && bits != 1024) {
fprintf(stderr, "DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
} else if (bits < 512 || bits > 4096 || (bits % 8 != 0)) {
fprintf(stderr, "Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8\n");
exit(EXIT_FAILURE);
}
check_signkey_bits(keytype, bits);;
}
keysize = bits / 8;
} else {
if (keytype == DROPBEAR_SIGNKEY_DSS) {
keysize = DSS_SIZE;
} else if (keytype == DROPBEAR_SIGNKEY_RSA) {
keysize = RSA_SIZE;
} else {
exit(EXIT_FAILURE); /* not reached */
}
}
fprintf(stderr, "Will output %d bit %s secret key to '%s'\n", keysize*8,
typetext, filename);
/* don't want the file readable by others */
umask(077);
/* now we can generate the key */
key = new_sign_key();
fprintf(stderr, "Generating key, this may take a while...\n");
switch(keytype) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
key->rsakey = gen_rsa_priv_key(keysize); /* 128 bytes = 1024 bit */
break;
#endif
#ifdef DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
key->dsskey = gen_dss_priv_key(keysize); /* 128 bytes = 1024 bit */
break;
#endif
default:
fprintf(stderr, "Internal error, bad key type\n");
exit(EXIT_FAILURE);
}
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
{
dropbear_exit("Failed to generate key.\n");
}
buf = buf_new(MAX_PRIVKEY_SIZE);
buf_put_priv_key(buf, key, keytype);
buf_setpos(buf, 0);
buf_writefile(buf, filename);
buf_burn(buf);
buf_free(buf);
printpubkey(key, keytype);
sign_key_free(key);
printpubfile(filename);
return EXIT_SUCCESS;
}
#endif
static void justprintpub(const char* filename) {
static int printpubfile(const char* filename) {
buffer *buf = NULL;
sign_key *key = NULL;
int keytype;
enum signkey_type keytype;
int ret;
int err = DROPBEAR_FAILURE;
@@ -290,7 +290,7 @@ out:
sign_key_free(key);
key = NULL;
}
exit(err);
return err;
}
static void printpubkey(sign_key * key, int keytype) {
@@ -319,7 +319,7 @@ static void printpubkey(sign_key * key, int keytype) {
fprintf(stderr, "base64 failed");
}
typestring = signkey_name_from_type(keytype, &err);
typestring = signkey_name_from_type(keytype, NULL);
fp = sign_key_fingerprint(buf_getptr(buf, len), len);
@@ -339,35 +339,3 @@ static void printpubkey(sign_key * key, int keytype) {
m_free(fp);
buf_free(buf);
}
/* Write a buffer to a file specified, failing if the file exists */
static void buf_writefile(buffer * buf, const char * filename) {
int fd;
int len;
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
fprintf(stderr, "Couldn't create new file %s\n", filename);
perror("Reason");
buf_burn(buf);
exit(EXIT_FAILURE);
}
/* write the file now */
while (buf->pos != buf->len) {
len = write(fd, buf_getptr(buf, buf->len - buf->pos),
buf->len - buf->pos);
if (errno == EINTR) {
continue;
}
if (len <= 0) {
fprintf(stderr, "Failed writing file '%s'\n",filename);
perror("Reason");
exit(EXIT_FAILURE);
}
buf_incrpos(buf, len);
}
close(fd);
}

29
dss.c
View File

@@ -28,7 +28,7 @@
#include "dss.h"
#include "buffer.h"
#include "ssh.h"
#include "random.h"
#include "dbrandom.h"
/* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
* operations, such as key reading, signing, verification. Key generation
@@ -47,11 +47,7 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
TRACE(("enter buf_get_dss_pub_key"))
dropbear_assert(key != NULL);
key->p = m_malloc(sizeof(mp_int));
key->q = m_malloc(sizeof(mp_int));
key->g = m_malloc(sizeof(mp_int));
key->y = m_malloc(sizeof(mp_int));
m_mp_init_multi(key->p, key->q, key->g, key->y, NULL);
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
key->x = NULL;
buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
@@ -87,8 +83,7 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
return DROPBEAR_FAILURE;
}
key->x = m_malloc(sizeof(mp_int));
m_mp_init(key->x);
m_mp_alloc_init_multi(&key->x, NULL);
ret = buf_getmpint(buf, key->x);
if (ret == DROPBEAR_FAILURE) {
m_free(key->x);
@@ -101,9 +96,9 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
/* Clear and free the memory used by a public or private key */
void dss_key_free(dropbear_dss_key *key) {
TRACE(("enter dsa_key_free"))
TRACE2(("enter dsa_key_free"))
if (key == NULL) {
TRACE(("enter dsa_key_free: key == NULL"))
TRACE2(("enter dsa_key_free: key == NULL"))
return;
}
if (key->p) {
@@ -127,7 +122,7 @@ void dss_key_free(dropbear_dss_key *key) {
m_free(key->x);
}
m_free(key);
TRACE(("leave dsa_key_free"))
TRACE2(("leave dsa_key_free"))
}
/* put the dss public key into the buffer in the required format:
@@ -161,9 +156,7 @@ void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
#ifdef DROPBEAR_SIGNKEY_VERIFY
/* Verify a DSS signature (in buf) made on data by the key given.
* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len) {
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
unsigned char msghash[SHA1_HASH_SIZE];
hash_state hs;
int ret = DROPBEAR_FAILURE;
@@ -187,7 +180,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data
/* hash the data */
sha1_init(&hs);
sha1_process(&hs, data, len);
sha1_process(&hs, data_buf->data, data_buf->len);
sha1_done(&hs, msghash);
/* create the signature - s' and r' are the received signatures in buf */
@@ -260,9 +253,7 @@ out:
/* Sign the data presented with key, writing the signature contents
* to the buffer */
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len) {
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
unsigned char msghash[SHA1_HASH_SIZE];
unsigned int writelen;
unsigned int i;
@@ -279,7 +270,7 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* d
/* hash the data */
sha1_init(&hs);
sha1_process(&hs, data, len);
sha1_process(&hs, data_buf->data, data_buf->len);
sha1_done(&hs, msghash);
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,

8
dss.h
View File

@@ -30,8 +30,6 @@
#ifdef DROPBEAR_DSS
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
typedef struct {
mp_int* p;
@@ -43,11 +41,9 @@ typedef struct {
} dropbear_dss_key;
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len);
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
#ifdef DROPBEAR_SIGNKEY_VERIFY
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, const unsigned char* data,
unsigned int len);
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
#endif
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key);
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key);

275
ecc.c Normal file
View File

@@ -0,0 +1,275 @@
#include "includes.h"
#include "options.h"
#include "ecc.h"
#include "dbutil.h"
#include "bignum.h"
#ifdef DROPBEAR_ECC
/* .dp members are filled out by dropbear_ecc_fill_dp() at startup */
#ifdef DROPBEAR_ECC_256
struct dropbear_ecc_curve ecc_curve_nistp256 = {
32, /* .ltc_size */
NULL, /* .dp */
&sha256_desc, /* .hash_desc */
"nistp256" /* .name */
};
#endif
#ifdef DROPBEAR_ECC_384
struct dropbear_ecc_curve ecc_curve_nistp384 = {
48, /* .ltc_size */
NULL, /* .dp */
&sha384_desc, /* .hash_desc */
"nistp384" /* .name */
};
#endif
#ifdef DROPBEAR_ECC_521
struct dropbear_ecc_curve ecc_curve_nistp521 = {
66, /* .ltc_size */
NULL, /* .dp */
&sha512_desc, /* .hash_desc */
"nistp521" /* .name */
};
#endif
struct dropbear_ecc_curve *dropbear_ecc_curves[] = {
#ifdef DROPBEAR_ECC_256
&ecc_curve_nistp256,
#endif
#ifdef DROPBEAR_ECC_384
&ecc_curve_nistp384,
#endif
#ifdef DROPBEAR_ECC_521
&ecc_curve_nistp521,
#endif
NULL
};
void dropbear_ecc_fill_dp() {
struct dropbear_ecc_curve **curve;
/* libtomcrypt guarantees they're ordered by size */
const ltc_ecc_set_type *dp = ltc_ecc_sets;
for (curve = dropbear_ecc_curves; *curve; curve++) {
for (;dp->size > 0; dp++) {
if (dp->size == (*curve)->ltc_size) {
(*curve)->dp = dp;
break;
}
}
if (!(*curve)->dp) {
dropbear_exit("Missing ECC params %s", (*curve)->name);
}
}
}
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) {
struct dropbear_ecc_curve **curve = NULL;
for (curve = dropbear_ecc_curves; *curve; curve++) {
if ((*curve)->dp == dp) {
break;
}
}
assert(*curve);
return *curve;
}
ecc_key * new_ecc_key(void) {
ecc_key *key = m_malloc(sizeof(*key));
m_mp_alloc_init_multi((mp_int**)&key->pubkey.x, (mp_int**)&key->pubkey.y,
(mp_int**)&key->pubkey.z, (mp_int**)&key->k, NULL);
return key;
}
/* Copied from libtomcrypt ecc_import.c (version there is static), modified
for different mp_int pointer without LTC_SOURCE */
static int ecc_is_point(ecc_key *key)
{
mp_int *prime, *b, *t1, *t2;
int err;
prime = m_malloc(sizeof(mp_int));
b = m_malloc(sizeof(mp_int));
t1 = m_malloc(sizeof(mp_int));
t2 = m_malloc(sizeof(mp_int));
m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL);
/* load prime and b */
if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; }
if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; }
/* compute y^2 */
if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; }
/* compute x^3 */
if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) { goto error; }
if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) { goto error; }
if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) { goto error; }
/* compute y^2 - x^3 */
if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) { goto error; }
/* compute y^2 - x^3 + 3x */
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; }
if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) { goto error; }
while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) { goto error; }
}
while (mp_cmp(t1, prime) != LTC_MP_LT) {
if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) { goto error; }
}
/* compare to b */
if (mp_cmp(t1, b) != LTC_MP_EQ) {
err = CRYPT_INVALID_PACKET;
} else {
err = CRYPT_OK;
}
error:
mp_clear_multi(prime, b, t1, t2, NULL);
m_free(prime);
m_free(b);
m_free(t1);
m_free(t2);
return err;
}
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key) {
unsigned long len = key->dp->size*2 + 1;
int err;
buf_putint(buf, len);
err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len);
if (err != CRYPT_OK) {
dropbear_exit("ECC error");
}
buf_incrwritepos(buf, len);
}
/* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) {
ecc_key *key = NULL;
int ret = DROPBEAR_FAILURE;
const unsigned int size = curve->dp->size;
unsigned char first;
TRACE(("enter buf_get_ecc_raw_pubkey"))
buf_setpos(buf, 0);
first = buf_getbyte(buf);
if (first == 2 || first == 3) {
dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression");
return NULL;
}
if (first != 4 || buf->len != 1+2*size) {
TRACE(("leave, wrong size"))
return NULL;
}
key = new_ecc_key();
key->dp = curve->dp;
if (mp_read_unsigned_bin(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) {
TRACE(("failed to read y"))
goto out;
}
buf_incrpos(buf, size);
mp_set(key->pubkey.z, 1);
if (ecc_is_point(key) != CRYPT_OK) {
TRACE(("failed, not a point"))
goto out;
}
/* SEC1 3.2.3.1 Check that Q != 0 */
if (mp_cmp_d(key->pubkey.x, 0) == LTC_MP_EQ) {
TRACE(("failed, x == 0"))
goto out;
}
if (mp_cmp_d(key->pubkey.y, 0) == LTC_MP_EQ) {
TRACE(("failed, y == 0"))
goto out;
}
ret = DROPBEAR_SUCCESS;
out:
if (ret == DROPBEAR_FAILURE) {
if (key) {
ecc_free(key);
m_free(key);
key = NULL;
}
}
return key;
}
/* a modified version of libtomcrypt's "ecc_shared_secret" to output
a mp_int instead. */
mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, ecc_key *private_key)
{
ecc_point *result = NULL;
mp_int *prime = NULL, *shared_secret = NULL;
int err = DROPBEAR_FAILURE;
/* type valid? */
if (private_key->type != PK_PRIVATE) {
goto done;
}
if (private_key->dp != public_key->dp) {
goto done;
}
/* make new point */
result = ltc_ecc_new_point();
if (result == NULL) {
goto done;
}
prime = m_malloc(sizeof(*prime));
m_mp_init(prime);
if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) {
goto done;
}
if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) {
goto done;
}
err = DROPBEAR_SUCCESS;
done:
if (err == DROPBEAR_SUCCESS) {
shared_secret = m_malloc(sizeof(*shared_secret));
m_mp_init(shared_secret);
mp_copy(result->x, shared_secret);
}
if (prime) {
mp_clear(prime);
m_free(prime);
}
if (result)
{
ltc_ecc_del_point(result);
}
if (err == DROPBEAR_FAILURE) {
dropbear_exit("ECC error");
}
return shared_secret;
}
#endif

36
ecc.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef _DROPBEAR_ECC_H
#define _DROPBEAR_ECC_H
#include "includes.h"
#include "options.h"
#include "buffer.h"
#ifdef DROPBEAR_ECC
struct dropbear_ecc_curve {
int ltc_size; /* to match the byte sizes in ltc_ecc_sets[] */
const ltc_ecc_set_type *dp; /* curve domain parameters */
const struct ltc_hash_descriptor *hash_desc;
const unsigned char *name;
};
extern struct dropbear_ecc_curve ecc_curve_nistp256;
extern struct dropbear_ecc_curve ecc_curve_nistp384;
extern struct dropbear_ecc_curve ecc_curve_nistp521;
extern struct dropbear_ecc_curve *dropbear_ecc_curves[];
void dropbear_ecc_fill_dp();
struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp);
/* "pubkey" refers to a point, but LTC uses ecc_key structure for both public
and private keys */
void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key);
ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve);
int buf_get_ecc_privkey_string(buffer *buf, ecc_key *key);
mp_int * dropbear_ecc_shared_secret(ecc_key *pub_key, ecc_key *priv_key);
#endif
#endif /* _DROPBEAR_ECC_H */

421
ecdsa.c Normal file
View File

@@ -0,0 +1,421 @@
#include "options.h"
#include "includes.h"
#include "dbutil.h"
#include "crypto_desc.h"
#include "ecc.h"
#include "ecdsa.h"
#include "signkey.h"
#ifdef DROPBEAR_ECDSA
int signkey_is_ecdsa(enum signkey_type type)
{
return type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|| type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
}
enum signkey_type ecdsa_signkey_type(ecc_key * key) {
#ifdef DROPBEAR_ECC_256
if (key->dp == ecc_curve_nistp256.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
}
#endif
#ifdef DROPBEAR_ECC_384
if (key->dp == ecc_curve_nistp384.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
}
#endif
#ifdef DROPBEAR_ECC_521
if (key->dp == ecc_curve_nistp521.dp) {
return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
}
#endif
return DROPBEAR_SIGNKEY_NONE;
}
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
const ltc_ecc_set_type *dp = NULL; /* curve domain parameters */
ecc_key *new_key = NULL;
switch (bit_size) {
#ifdef DROPBEAR_ECC_256
case 256:
dp = ecc_curve_nistp256.dp;
break;
#endif
#ifdef DROPBEAR_ECC_384
case 384:
dp = ecc_curve_nistp384.dp;
break;
#endif
#ifdef DROPBEAR_ECC_521
case 521:
dp = ecc_curve_nistp521.dp;
break;
#endif
}
if (!dp) {
dropbear_exit("Key size %d isn't valid. Try "
#ifdef DROPBEAR_ECC_256
"256 "
#endif
#ifdef DROPBEAR_ECC_384
"384 "
#endif
#ifdef DROPBEAR_ECC_521
"521 "
#endif
, bit_size);
}
new_key = m_malloc(sizeof(*new_key));
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) {
dropbear_exit("ECC error");
}
return new_key;
}
ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
unsigned char *key_ident = NULL, *identifier = NULL;
unsigned int key_ident_len, identifier_len;
buffer *q_buf = NULL;
struct dropbear_ecc_curve **curve;
ecc_key *new_key = NULL;
/* string "ecdsa-sha2-[identifier]" */
key_ident = buf_getstring(buf, &key_ident_len);
/* string "[identifier]" */
identifier = 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;
}
for (curve = dropbear_ecc_curves; *curve; curve++) {
if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) {
break;
}
}
if (!*curve) {
TRACE(("couldn't match ecc curve"))
goto out;
}
/* string Q */
q_buf = buf_getstringbuf(buf);
new_key = buf_get_ecc_raw_pubkey(q_buf, *curve);
out:
m_free(key_ident);
m_free(identifier);
if (q_buf) {
buf_free(q_buf);
q_buf = NULL;
}
TRACE(("leave buf_get_ecdsa_pub_key"))
return new_key;
}
ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
ecc_key *new_key = NULL;
TRACE(("enter buf_get_ecdsa_priv_key"))
new_key = buf_get_ecdsa_pub_key(buf);
if (!new_key) {
return NULL;
}
if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
ecc_free(new_key);
m_free(new_key);
return NULL;
}
return new_key;
}
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
struct dropbear_ecc_curve *curve = NULL;
unsigned char key_ident[30];
curve = curve_for_dp(key->dp);
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
buf_putstring(buf, curve->name, strlen(curve->name));
buf_put_ecc_raw_pubkey_string(buf, key);
}
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
buf_put_ecdsa_pub_key(buf, key);
buf_putmpint(buf, key->k);
}
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) {
/* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
int err = DROPBEAR_FAILURE;
struct dropbear_ecc_curve *curve = NULL;
hash_state hs;
unsigned char hash[64];
void *e = NULL, *p = NULL, *s = NULL, *r;
unsigned char key_ident[30];
buffer *sigbuf = NULL;
TRACE(("buf_put_ecdsa_sign"))
curve = curve_for_dp(key->dp);
if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) {
goto out;
}
curve->hash_desc->init(&hs);
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
curve->hash_desc->done(&hs, hash);
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
goto out;
}
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
goto out;
}
for (;;) {
ecc_key R_key; /* ephemeral key */
if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) {
goto out;
}
if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) {
goto out;
}
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) {
/* try again */
ecc_free(&R_key);
continue;
}
/* k = 1/k */
if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) {
goto out;
}
/* s = xr */
if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) {
goto out;
}
/* s = e + xr */
if (ltc_mp.add(e, s, s) != CRYPT_OK) {
goto out;
}
if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) {
goto out;
}
/* s = (e + xr)/k */
if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) {
goto out;
}
ecc_free(&R_key);
if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) {
break;
}
}
snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
buf_putstring(buf, key_ident, strlen(key_ident));
/* enough for nistp521 */
sigbuf = buf_new(200);
buf_putmpint(sigbuf, (mp_int*)r);
buf_putmpint(sigbuf, (mp_int*)s);
buf_putbufstring(buf, sigbuf);
err = DROPBEAR_SUCCESS;
out:
if (r && s && p && e) {
ltc_deinit_multi(r, s, p, e, NULL);
}
if (sigbuf) {
buf_free(sigbuf);
}
if (err == DROPBEAR_FAILURE) {
dropbear_exit("ECC error");
}
}
/* returns values in s and r
returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int buf_get_ecdsa_verify_params(buffer *buf,
void *r, void* s) {
int ret = DROPBEAR_FAILURE;
unsigned int sig_len;
unsigned int sig_pos;
sig_len = buf_getint(buf);
sig_pos = buf->pos;
if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) {
goto out;
}
if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) {
goto out;
}
if (buf->pos - sig_pos != sig_len) {
goto out;
}
ret = DROPBEAR_SUCCESS;
out:
return ret;
}
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) {
/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
int ret = DROPBEAR_FAILURE;
hash_state hs;
struct dropbear_ecc_curve *curve = NULL;
unsigned char hash[64];
ecc_point *mG = NULL, *mQ = NULL;
void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL,
*e = NULL, *p = NULL, *m = NULL;
void *mp = NULL;
/* verify
*
* w = s^-1 mod n
* u1 = xw
* u2 = rw
* X = u1*G + u2*Q
* v = X_x1 mod n
* accept if v == r
*/
TRACE(("buf_ecdsa_verify"))
curve = curve_for_dp(key->dp);
mG = ltc_ecc_new_point();
mQ = ltc_ecc_new_point();
if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK
|| !mG
|| !mQ) {
dropbear_exit("ECC error");
}
if (buf_get_ecdsa_verify_params(buf, r, s) != DROPBEAR_SUCCESS) {
goto out;
}
curve->hash_desc->init(&hs);
curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
curve->hash_desc->done(&hs, hash);
if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
goto out;
}
/* get the order */
if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
goto out;
}
/* get the modulus */
if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) {
goto out;
}
/* check for zero */
if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ
|| ltc_mp.compare_d(s, 0) == LTC_MP_EQ
|| ltc_mp.compare(r, p) != LTC_MP_LT
|| ltc_mp.compare(s, p) != LTC_MP_LT) {
goto out;
}
/* w = s^-1 mod n */
if (ltc_mp.invmod(s, p, w) != CRYPT_OK) {
goto out;
}
/* u1 = ew */
if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) {
goto out;
}
/* u2 = rw */
if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) {
goto out;
}
/* find mG and mQ */
if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) {
goto out;
}
if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) {
goto out;
}
if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) {
goto out;
}
if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK
|| ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK
|| ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) {
goto out;
}
/* compute u1*mG + u2*mQ = mG */
if (ltc_mp.ecc_mul2add == NULL) {
if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) {
goto out;
}
if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) {
goto out;
}
/* find the montgomery mp */
if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) {
goto out;
}
/* add them */
if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) {
goto out;
}
/* reduce */
if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) {
goto out;
}
} else {
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) {
goto out;
}
}
/* v = X_x1 mod n */
if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) {
goto out;
}
/* does v == r */
if (ltc_mp.compare(v, r) == LTC_MP_EQ) {
ret = DROPBEAR_SUCCESS;
}
out:
ltc_ecc_del_point(mG);
ltc_ecc_del_point(mQ);
mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
if (mp != NULL) {
ltc_mp.montgomery_deinit(mp);
}
return ret;
}
#endif /* DROPBEAR_ECDSA */

35
ecdsa.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef _ECDSA_H_
#define _ECDSA_H_
#include "includes.h"
#include "buffer.h"
#include "signkey.h"
#ifdef DROPBEAR_ECDSA
/* Prefer the larger size - it's fast anyway */
#if defined(DROPBEAR_ECC_521)
#define ECDSA_DEFAULT_SIZE 521
#elif defined(DROPBEAR_ECC_384)
#define ECDSA_DEFAULT_SIZE 384
#elif defined(DROPBEAR_ECC_256)
#define ECDSA_DEFAULT_SIZE 256
#else
#define ECDSA_DEFAULT_SIZE 0
#endif
ecc_key *gen_ecdsa_priv_key(unsigned int bit_size);
ecc_key *buf_get_ecdsa_pub_key(buffer* buf);
ecc_key *buf_get_ecdsa_priv_key(buffer *buf);
void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key);
void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key);
enum signkey_type ecdsa_signkey_type(ecc_key * key);
void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf);
int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf);
/* Returns 1 on success */
int signkey_is_ecdsa(enum signkey_type type);
#endif
#endif /* _ECDSA_H_ */

View File

@@ -26,7 +26,7 @@
#include "dbutil.h"
#include "signkey.h"
#include "bignum.h"
#include "random.h"
#include "dbrandom.h"
#include "buffer.h"
#include "gendss.h"
#include "dss.h"
@@ -47,19 +47,16 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
dropbear_dss_key *key;
if (size != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits");
}
key = m_malloc(sizeof(*key));
key->p = (mp_int*)m_malloc(sizeof(mp_int));
key->q = (mp_int*)m_malloc(sizeof(mp_int));
key->g = (mp_int*)m_malloc(sizeof(mp_int));
key->y = (mp_int*)m_malloc(sizeof(mp_int));
key->x = (mp_int*)m_malloc(sizeof(mp_int));
m_mp_init_multi(key->p, key->q, key->g, key->y, key->x, NULL);
seedrandom();
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
getq(key);
getp(key, size);
getp(key, size/8);
getg(key);
getx(key);
gety(key);

View File

@@ -25,7 +25,7 @@
#include "includes.h"
#include "dbutil.h"
#include "bignum.h"
#include "random.h"
#include "dbrandom.h"
#include "rsa.h"
#include "genrsa.h"
@@ -34,7 +34,7 @@
#ifdef DROPBEAR_RSA
static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size);
mp_int* rsa_e, unsigned int size_bytes);
/* mostly taken from libtomcrypt's rsa key generation routine */
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
@@ -44,30 +44,32 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
DEF_MP_INT(qminus);
DEF_MP_INT(lcm);
if (size < 512 || size > 4096 || (size % 8 != 0)) {
dropbear_exit("Bits must satisfy 512 <= bits <= 4096, and be a"
" multiple of 8");
}
key = m_malloc(sizeof(*key));
key->e = (mp_int*)m_malloc(sizeof(mp_int));
key->n = (mp_int*)m_malloc(sizeof(mp_int));
key->d = (mp_int*)m_malloc(sizeof(mp_int));
key->p = (mp_int*)m_malloc(sizeof(mp_int));
key->q = (mp_int*)m_malloc(sizeof(mp_int));
m_mp_init_multi(key->e, key->n, key->d, key->p, key->q,
&pminus, &lcm, &qminus, NULL);
seedrandom();
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);
}
getrsaprime(key->p, &pminus, key->e, size/2);
getrsaprime(key->q, &qminus, key->e, size/2);
while (1) {
getrsaprime(key->p, &pminus, key->e, size/16);
getrsaprime(key->q, &qminus, key->e, size/16);
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
exit(1);
}
if ((unsigned int)mp_count_bits(key->n) == size) {
break;
}
}
/* lcm(p-1, q-1) */
@@ -90,21 +92,21 @@ dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
/* return a prime suitable for p or q */
static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size) {
mp_int* rsa_e, unsigned int size_bytes) {
unsigned char *buf;
DEF_MP_INT(temp_gcd);
buf = (unsigned char*)m_malloc(size+1);
buf = (unsigned char*)m_malloc(size_bytes);
m_mp_init(&temp_gcd);
do {
/* generate a random odd number with MSB set, then find the
the next prime above it */
genrandom(buf, size+1);
buf[0] |= 0x80; /* MSB set */
genrandom(buf, size_bytes);
buf[0] |= 0x80;
bytes_to_mp(prime, buf, size+1);
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) {
@@ -126,7 +128,7 @@ static void getrsaprime(mp_int* prime, mp_int *primeminus,
/* now we have a good value for result */
mp_clear(&temp_gcd);
m_burn(buf, size+1);
m_burn(buf, size_bytes);
m_free(buf);
}

135
gensignkey.c Normal file
View File

@@ -0,0 +1,135 @@
#include "includes.h"
#include "dbutil.h"
#include "buffer.h"
#include "ecdsa.h"
#include "genrsa.h"
#include "gendss.h"
#include "signkey.h"
#include "dbrandom.h"
#define RSA_DEFAULT_SIZE 2048
#define DSS_DEFAULT_SIZE 1024
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
static int buf_writefile(buffer * buf, const char * filename) {
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));
goto out;
}
/* write the file now */
while (buf->pos != buf->len) {
int len = write(fd, buf_getptr(buf, buf->len - buf->pos),
buf->len - buf->pos);
if (len == -1 && errno == EINTR) {
continue;
}
if (len <= 0) {
dropbear_log(LOG_ERR, "Failed writing file %s: %s",
filename, strerror(errno));
goto out;
}
buf_incrpos(buf, len);
}
ret = DROPBEAR_SUCCESS;
out:
if (fd >= 0) {
if (fsync(fd) != 0) {
dropbear_log(LOG_ERR, "fsync of %s failed: %s", filename, strerror(errno));
}
m_close(fd);
}
return ret;
}
/* returns 0 on failure */
static int get_default_bits(enum signkey_type keytype)
{
switch (keytype) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
return RSA_DEFAULT_SIZE;
#endif
#ifdef DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
return DSS_DEFAULT_SIZE;
#endif
#ifdef DROPBEAR_ECDSA
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
return ECDSA_DEFAULT_SIZE;
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
return 521;
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
return 384;
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return 256;
#endif
default:
return 0;
}
}
int signkey_generate(enum signkey_type keytype, int bits, const char* filename)
{
sign_key * key = NULL;
buffer *buf = NULL;
int ret = DROPBEAR_FAILURE;
if (bits == 0)
{
bits = get_default_bits(keytype);
}
/* now we can generate the key */
key = new_sign_key();
seedrandom();
switch(keytype) {
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
key->rsakey = gen_rsa_priv_key(bits);
break;
#endif
#ifdef DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
key->dsskey = gen_dss_priv_key(bits);
break;
#endif
#ifdef DROPBEAR_ECDSA
case DROPBEAR_SIGNKEY_ECDSA_KEYGEN:
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
{
ecc_key *ecckey = gen_ecdsa_priv_key(bits);
keytype = ecdsa_signkey_type(ecckey);
*signkey_key_ptr(key, keytype) = ecckey;
}
break;
#endif
default:
dropbear_exit("Internal error");
}
seedrandom();
buf = buf_new(MAX_PRIVKEY_SIZE);
buf_put_priv_key(buf, key, keytype);
sign_key_free(key);
key = NULL;
buf_setpos(buf, 0);
ret = buf_writefile(buf, filename);
buf_burn(buf);
buf_free(buf);
buf = NULL;
return ret;
}

8
gensignkey.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef _GENSIGNKEY_H
#define _GENSIGNKEY_H
#include "signkey.h"
int signkey_generate(enum signkey_type type, int bits, const char* filename);
#endif

View File

@@ -120,6 +120,10 @@
#include <libgen.h>
#endif
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#ifdef BUNDLED_LIBTOM
#include "libtomcrypt/src/headers/tomcrypt.h"
#include "libtommath/tommath.h"
@@ -130,15 +134,35 @@
#include "compat.h"
#include "fake-rfc2553.h"
#ifndef HAVE_UINT16_T
#ifndef HAVE_U_INT8_T
typedef unsigned char u_int8_t;
#endif /* HAVE_U_INT8_T */
#ifndef HAVE_UINT8_T
typedef u_int8_t uint8_t;
#endif /* HAVE_UINT8_T */
#ifndef HAVE_U_INT16_T
typedef unsigned short u_int16_t;
#endif /* HAVE_U_INT16_T */
#ifndef HAVE_UINT16_T
typedef u_int16_t uint16_t;
#endif /* HAVE_UINT16_T */
#ifndef HAVE_U_INT32_T
typedef unsigned int u_int32_t;
#endif /* HAVE_U_INT32_T */
#ifndef HAVE_UINT32_T
typedef u_int32_t uint32_t;
#endif /* HAVE_UINT32_T */
#ifdef SO_PRIORITY
#include <linux/types.h>
#include <linux/pkt_sched.h>
#endif
#include "fake-rfc2553.h"
#ifndef LOG_AUTHPRIV
#define LOG_AUTHPRIV LOG_AUTH
#endif

53
kex.h
View File

@@ -27,16 +27,33 @@
#include "includes.h"
#include "algo.h"
#include "signkey.h"
void send_msg_kexinit();
void recv_msg_kexinit();
void send_msg_newkeys();
void recv_msg_newkeys();
void kexfirstinitialise();
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv);
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
struct kex_dh_param *gen_kexdh_param();
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);
#ifdef DROPBEAR_ECDH
struct kex_ecdh_param *gen_kexecdh_param();
void free_kexecdh_param(struct kex_ecdh_param *param);
void kexecdh_comb_key(struct kex_ecdh_param *param, buffer *pub_them,
sign_key *hostkey);
#endif
#ifdef DROPBEAR_CURVE25519
struct kex_curve25519_param *gen_kexcurve25519_param();
void free_kexcurve25519_param(struct kex_curve25519_param *param);
void kexcurve25519_comb_key(struct kex_curve25519_param *param, buffer *pub_them,
sign_key *hostkey);
#endif
#ifndef DISABLE_ZLIB
int is_compress_trans();
int is_compress_recv();
@@ -51,19 +68,49 @@ struct KEXState {
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
unsigned recvkexinit : 1;
unsigned firstfollows : 1; /* true when first_kex_packet_follows is set */
unsigned them_firstfollows : 1; /* true when first_kex_packet_follows is set */
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,
ie the transport layer has been set up */
unsigned our_first_follows_matches : 1;
time_t lastkextime; /* time of the last kex */
unsigned int datatrans; /* data transmitted since last kex */
unsigned int datarecv; /* data received since last kex */
};
#define DH_P_1_LEN 128
extern const unsigned char dh_p_1[DH_P_1_LEN];
#define DH_P_14_LEN 256
extern const unsigned char dh_p_14[DH_P_14_LEN];
struct kex_dh_param {
mp_int pub; /* e */
mp_int priv; /* x */
};
#ifdef DROPBEAR_ECDH
struct kex_ecdh_param {
ecc_key key;
};
#endif
#ifdef DROPBEAR_CURVE25519
#define CURVE25519_LEN 32
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
#define MAX_KEXHASHBUF 2000
#endif /* _KEX_H_ */

View File

@@ -2,8 +2,6 @@
* Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com
* keyfiles.
*
* The horribleness of the code is probably mine (matt).
*
* Modifications copyright 2003 Matt Johnston
*
* PuTTY is copyright 1997-2003 Simon Tatham.
@@ -36,6 +34,11 @@
#include "bignum.h"
#include "buffer.h"
#include "dbutil.h"
#include "ecc.h"
static const unsigned char OID_SEC256R1_BLOB[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
static const unsigned char OID_SEC384R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
static const unsigned char OID_SEC521R1_BLOB[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
#define PUT_32BIT(cp, value) do { \
(cp)[3] = (unsigned char)(value); \
@@ -109,7 +112,7 @@ static sign_key *dropbear_read(const char* filename) {
buffer * buf = NULL;
sign_key *ret = NULL;
int type;
enum signkey_type type;
buf = buf_new(MAX_PRIVKEY_SIZE);
if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
@@ -125,6 +128,8 @@ static sign_key *dropbear_read(const char* filename) {
}
buf_free(buf);
ret->type = type;
return ret;
error:
@@ -140,25 +145,13 @@ error:
/* returns 0 on fail, 1 on success */
static int dropbear_write(const char*filename, sign_key * key) {
int keytype = -1;
buffer * buf;
FILE*fp;
int len;
int ret;
#ifdef DROPBEAR_RSA
if (key->rsakey != NULL) {
keytype = DROPBEAR_SIGNKEY_RSA;
}
#endif
#ifdef DROPBEAR_DSS
if (key->dsskey != NULL) {
keytype = DROPBEAR_SIGNKEY_DSS;
}
#endif
buf = buf_new(MAX_PRIVKEY_SIZE);
buf_put_priv_key(buf, key, keytype);
buf_put_priv_key(buf, key, key->type);
fp = fopen(filename, "w");
if (!fp) {
@@ -349,7 +342,7 @@ struct mpint_pos { void *start; int bytes; };
* Code to read and write OpenSSH private keys.
*/
enum { OSSH_DSA, OSSH_RSA };
enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
struct openssh_key {
int type;
int encrypted;
@@ -392,6 +385,8 @@ static struct openssh_key *load_openssh_key(const char *filename)
ret->type = OSSH_RSA;
else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
ret->type = OSSH_DSA;
else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n"))
ret->type = OSSH_EC;
else {
errmsg = "Unrecognised key type";
goto error;
@@ -506,7 +501,7 @@ static int openssh_encrypted(const char *filename)
return ret;
}
static sign_key *openssh_read(const char *filename, char *passphrase)
static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
{
struct openssh_key *key;
unsigned char *p;
@@ -516,11 +511,13 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
char *errmsg;
char *modptr = NULL;
int modlen = -9999;
int type;
enum signkey_type type;
sign_key *retkey;
buffer * blobbuf = NULL;
retkey = new_sign_key();
key = load_openssh_key(filename);
if (!key)
@@ -597,17 +594,26 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
num_integers = 9;
else if (key->type == OSSH_DSA)
num_integers = 6;
else if (key->type == OSSH_EC)
num_integers = 1;
/*
* Space to create key blob in.
*/
blobbuf = buf_new(3000);
#ifdef DROPBEAR_DSS
if (key->type == OSSH_DSA) {
buf_putstring(blobbuf, "ssh-dss", 7);
} else if (key->type == OSSH_RSA) {
retkey->type = DROPBEAR_SIGNKEY_DSS;
}
#endif
#ifdef DROPBEAR_RSA
if (key->type == OSSH_RSA) {
buf_putstring(blobbuf, "ssh-rsa", 7);
retkey->type = DROPBEAR_SIGNKEY_RSA;
}
#endif
for (i = 0; i < num_integers; i++) {
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
@@ -620,11 +626,18 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
}
if (i == 0) {
/*
* The first integer should be zero always (I think
* this is some sort of version indication).
*/
if (len != 1 || p[0] != 0) {
/* First integer is a version indicator */
int expected = -1;
switch (key->type) {
case OSSH_RSA:
case OSSH_DSA:
expected = 0;
break;
case OSSH_EC:
expected = 1;
break;
}
if (len != 1 || p[0] != expected) {
errmsg = "Version number mismatch";
goto error;
}
@@ -655,21 +668,136 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
p += len;
}
#ifdef DROPBEAR_ECDSA
if (key->type == OSSH_EC) {
unsigned char* private_key_bytes = NULL;
int private_key_len = 0;
unsigned char* public_key_bytes = NULL;
int public_key_len = 0;
ecc_key *ecc = NULL;
const struct dropbear_ecc_curve *curve = NULL;
/* See SEC1 v2, Appendix C.4 */
/* OpenSSL (so OpenSSH) seems to include the optional parts. */
/* privateKey OCTET STRING, */
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
&id, &len, &flags);
p += ret;
/* id==4 for octet string */
if (ret < 0 || id != 4 ||
key->keyblob+key->keyblob_len-p < len) {
errmsg = "ASN.1 decoding failure";
goto error;
}
private_key_bytes = p;
private_key_len = len;
p += len;
/* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, */
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
&id, &len, &flags);
p += ret;
/* id==0 */
if (ret < 0 || id != 0) {
errmsg = "ASN.1 decoding failure";
goto error;
}
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
&id, &len, &flags);
p += ret;
/* id==6 for object */
if (ret < 0 || id != 6 ||
key->keyblob+key->keyblob_len-p < len) {
errmsg = "ASN.1 decoding failure";
goto error;
}
if (0) {}
#ifdef DROPBEAR_ECC_256
else if (len == sizeof(OID_SEC256R1_BLOB)
&& memcmp(p, OID_SEC256R1_BLOB, len) == 0) {
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256;
curve = &ecc_curve_nistp256;
}
#endif
#ifdef DROPBEAR_ECC_384
else if (len == sizeof(OID_SEC384R1_BLOB)
&& memcmp(p, OID_SEC384R1_BLOB, len) == 0) {
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384;
curve = &ecc_curve_nistp384;
}
#endif
#ifdef DROPBEAR_ECC_521
else if (len == sizeof(OID_SEC521R1_BLOB)
&& memcmp(p, OID_SEC521R1_BLOB, len) == 0) {
retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521;
curve = &ecc_curve_nistp521;
}
#endif
else {
errmsg = "Unknown ECC key type";
goto error;
}
p += len;
/* publicKey [1] BIT STRING OPTIONAL */
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
&id, &len, &flags);
p += ret;
/* id==1 */
if (ret < 0 || id != 1) {
errmsg = "ASN.1 decoding failure";
goto error;
}
ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
&id, &len, &flags);
p += ret;
/* id==3 for bit string */
if (ret < 0 || id != 3 ||
key->keyblob+key->keyblob_len-p < len) {
errmsg = "ASN.1 decoding failure";
goto error;
}
public_key_bytes = p+1;
public_key_len = len-1;
p += len;
buf_putbytes(blobbuf, public_key_bytes, public_key_len);
ecc = buf_get_ecc_raw_pubkey(blobbuf, curve);
if (!ecc) {
errmsg = "Error parsing ECC key";
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)
!= MP_OKAY) {
errmsg = "Error parsing ECC key";
goto error;
}
*signkey_key_ptr(retkey, retkey->type) = ecc;
}
#endif /* DROPBEAR_ECDSA */
/*
* Now put together the actual key. Simplest way to do this is
* to assemble our own key blobs and feed them to the createkey
* functions; this is a bit faffy but it does mean we get all
* the sanity checks for free.
*/
retkey = new_sign_key();
buf_setpos(blobbuf, 0);
type = DROPBEAR_SIGNKEY_ANY;
if (buf_get_priv_key(blobbuf, retkey, &type)
!= DROPBEAR_SUCCESS) {
errmsg = "unable to create key structure";
sign_key_free(retkey);
retkey = NULL;
goto error;
if (key->type == OSSH_RSA || key->type == OSSH_DSA) {
buf_setpos(blobbuf, 0);
type = DROPBEAR_SIGNKEY_ANY;
if (buf_get_priv_key(blobbuf, retkey, &type)
!= DROPBEAR_SUCCESS) {
errmsg = "unable to create key structure";
sign_key_free(retkey);
retkey = NULL;
goto error;
}
}
errmsg = NULL; /* no error */
@@ -682,7 +810,7 @@ static sign_key *openssh_read(const char *filename, char *passphrase)
}
m_burn(key->keyblob, key->keyblob_size);
m_free(key->keyblob);
m_burn(key, sizeof(key));
m_burn(key, sizeof(*key));
m_free(key);
if (errmsg) {
fprintf(stderr, "Error: %s\n", errmsg);
@@ -698,207 +826,296 @@ static int openssh_write(const char *filename, sign_key *key,
unsigned char *outblob = NULL;
int outlen = -9999;
struct mpint_pos numbers[9];
int nnumbers = -1, pos, len, seqlen, i;
int nnumbers = -1, pos = 0, len = 0, seqlen, i;
char *header = NULL, *footer = NULL;
char zero[1];
int ret = 0;
FILE *fp;
int keytype = -1;
#ifdef DROPBEAR_RSA
mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
if (key->rsakey != NULL) {
keytype = DROPBEAR_SIGNKEY_RSA;
}
#endif
#ifdef DROPBEAR_DSS
if (key->dsskey != NULL) {
keytype = DROPBEAR_SIGNKEY_DSS;
}
#endif
dropbear_assert(keytype != -1);
/*
* Fetch the key blobs.
*/
keyblob = buf_new(3000);
buf_put_priv_key(keyblob, key, keytype);
buf_setpos(keyblob, 0);
/* skip the "ssh-rsa" or "ssh-dss" header */
buf_incrpos(keyblob, buf_getint(keyblob));
/*
* Find the sequence of integers to be encoded into the OpenSSH
* key blob, and also decide on the header line.
*/
numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
if (
#ifdef DROPBEAR_RSA
if (keytype == DROPBEAR_SIGNKEY_RSA) {
if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
goto error;
}
/* e */
numbers[2].bytes = buf_getint(keyblob);
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
buf_incrpos(keyblob, numbers[2].bytes);
/* n */
numbers[1].bytes = buf_getint(keyblob);
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
buf_incrpos(keyblob, numbers[1].bytes);
/* d */
numbers[3].bytes = buf_getint(keyblob);
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
buf_incrpos(keyblob, numbers[3].bytes);
/* p */
numbers[4].bytes = buf_getint(keyblob);
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
buf_incrpos(keyblob, numbers[4].bytes);
/* q */
numbers[5].bytes = buf_getint(keyblob);
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
buf_incrpos(keyblob, numbers[5].bytes);
/* now calculate some extra parameters: */
m_mp_init(&tmpval);
m_mp_init(&dmp1);
m_mp_init(&dmq1);
m_mp_init(&iqmp);
/* dmp1 = d mod (p-1) */
if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
fprintf(stderr, "Bignum error for p-1\n");
goto error;
}
if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
fprintf(stderr, "Bignum error for dmp1\n");
goto error;
}
/* dmq1 = d mod (q-1) */
if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
fprintf(stderr, "Bignum error for q-1\n");
goto error;
}
if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
fprintf(stderr, "Bignum error for dmq1\n");
goto error;
}
/* iqmp = (q^-1) mod p */
if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
fprintf(stderr, "Bignum error for iqmp\n");
goto error;
}
extrablob = buf_new(2000);
buf_putmpint(extrablob, &dmp1);
buf_putmpint(extrablob, &dmq1);
buf_putmpint(extrablob, &iqmp);
buf_setpos(extrablob, 0);
mp_clear(&dmp1);
mp_clear(&dmq1);
mp_clear(&iqmp);
mp_clear(&tmpval);
/* dmp1 */
numbers[6].bytes = buf_getint(extrablob);
numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
buf_incrpos(extrablob, numbers[6].bytes);
/* dmq1 */
numbers[7].bytes = buf_getint(extrablob);
numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
buf_incrpos(extrablob, numbers[7].bytes);
/* iqmp */
numbers[8].bytes = buf_getint(extrablob);
numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
buf_incrpos(extrablob, numbers[8].bytes);
nnumbers = 9;
header = "-----BEGIN RSA PRIVATE KEY-----\n";
footer = "-----END RSA PRIVATE KEY-----\n";
}
#endif /* DROPBEAR_RSA */
key->type == DROPBEAR_SIGNKEY_RSA ||
#endif
#ifdef DROPBEAR_DSS
if (keytype == DROPBEAR_SIGNKEY_DSS) {
key->type == DROPBEAR_SIGNKEY_DSS ||
#endif
0)
{
/*
* Fetch the key blobs.
*/
keyblob = buf_new(3000);
buf_put_priv_key(keyblob, key, key->type);
/* p */
numbers[1].bytes = buf_getint(keyblob);
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
buf_incrpos(keyblob, numbers[1].bytes);
buf_setpos(keyblob, 0);
/* skip the "ssh-rsa" or "ssh-dss" header */
buf_incrpos(keyblob, buf_getint(keyblob));
/* q */
numbers[2].bytes = buf_getint(keyblob);
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
buf_incrpos(keyblob, numbers[2].bytes);
/*
* Find the sequence of integers to be encoded into the OpenSSH
* key blob, and also decide on the header line.
*/
numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0';
/* g */
numbers[3].bytes = buf_getint(keyblob);
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
buf_incrpos(keyblob, numbers[3].bytes);
#ifdef DROPBEAR_RSA
if (key->type == DROPBEAR_SIGNKEY_RSA) {
/* y */
numbers[4].bytes = buf_getint(keyblob);
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
buf_incrpos(keyblob, numbers[4].bytes);
if (key->rsakey->p == NULL || key->rsakey->q == NULL) {
fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
goto error;
}
/* x */
numbers[5].bytes = buf_getint(keyblob);
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
buf_incrpos(keyblob, numbers[5].bytes);
/* e */
numbers[2].bytes = buf_getint(keyblob);
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
buf_incrpos(keyblob, numbers[2].bytes);
/* n */
numbers[1].bytes = buf_getint(keyblob);
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
buf_incrpos(keyblob, numbers[1].bytes);
/* d */
numbers[3].bytes = buf_getint(keyblob);
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
buf_incrpos(keyblob, numbers[3].bytes);
/* p */
numbers[4].bytes = buf_getint(keyblob);
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
buf_incrpos(keyblob, numbers[4].bytes);
/* q */
numbers[5].bytes = buf_getint(keyblob);
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
buf_incrpos(keyblob, numbers[5].bytes);
nnumbers = 6;
header = "-----BEGIN DSA PRIVATE KEY-----\n";
footer = "-----END DSA PRIVATE KEY-----\n";
}
#endif /* DROPBEAR_DSS */
/*
* Now count up the total size of the ASN.1 encoded integers,
* so as to determine the length of the containing SEQUENCE.
*/
len = 0;
for (i = 0; i < nnumbers; i++) {
len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
len += numbers[i].bytes;
}
seqlen = len;
/* Now add on the SEQUENCE header. */
len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
/* Round up to the cipher block size, ensuring we have at least one
* byte of padding (see below). */
outlen = len;
if (passphrase)
outlen = (outlen+8) &~ 7;
/*
* Now we know how big outblob needs to be. Allocate it.
*/
outblob = (unsigned char*)m_malloc(outlen);
/*
* And write the data into it.
*/
pos = 0;
pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
for (i = 0; i < nnumbers; i++) {
pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
pos += numbers[i].bytes;
/* now calculate some extra parameters: */
m_mp_init(&tmpval);
m_mp_init(&dmp1);
m_mp_init(&dmq1);
m_mp_init(&iqmp);
/* dmp1 = d mod (p-1) */
if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) {
fprintf(stderr, "Bignum error for p-1\n");
goto error;
}
if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) {
fprintf(stderr, "Bignum error for dmp1\n");
goto error;
}
/* dmq1 = d mod (q-1) */
if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) {
fprintf(stderr, "Bignum error for q-1\n");
goto error;
}
if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) {
fprintf(stderr, "Bignum error for dmq1\n");
goto error;
}
/* iqmp = (q^-1) mod p */
if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) {
fprintf(stderr, "Bignum error for iqmp\n");
goto error;
}
extrablob = buf_new(2000);
buf_putmpint(extrablob, &dmp1);
buf_putmpint(extrablob, &dmq1);
buf_putmpint(extrablob, &iqmp);
buf_setpos(extrablob, 0);
mp_clear(&dmp1);
mp_clear(&dmq1);
mp_clear(&iqmp);
mp_clear(&tmpval);
/* dmp1 */
numbers[6].bytes = buf_getint(extrablob);
numbers[6].start = buf_getptr(extrablob, numbers[6].bytes);
buf_incrpos(extrablob, numbers[6].bytes);
/* dmq1 */
numbers[7].bytes = buf_getint(extrablob);
numbers[7].start = buf_getptr(extrablob, numbers[7].bytes);
buf_incrpos(extrablob, numbers[7].bytes);
/* iqmp */
numbers[8].bytes = buf_getint(extrablob);
numbers[8].start = buf_getptr(extrablob, numbers[8].bytes);
buf_incrpos(extrablob, numbers[8].bytes);
nnumbers = 9;
header = "-----BEGIN RSA PRIVATE KEY-----\n";
footer = "-----END RSA PRIVATE KEY-----\n";
}
#endif /* DROPBEAR_RSA */
#ifdef DROPBEAR_DSS
if (key->type == DROPBEAR_SIGNKEY_DSS) {
/* p */
numbers[1].bytes = buf_getint(keyblob);
numbers[1].start = buf_getptr(keyblob, numbers[1].bytes);
buf_incrpos(keyblob, numbers[1].bytes);
/* q */
numbers[2].bytes = buf_getint(keyblob);
numbers[2].start = buf_getptr(keyblob, numbers[2].bytes);
buf_incrpos(keyblob, numbers[2].bytes);
/* g */
numbers[3].bytes = buf_getint(keyblob);
numbers[3].start = buf_getptr(keyblob, numbers[3].bytes);
buf_incrpos(keyblob, numbers[3].bytes);
/* y */
numbers[4].bytes = buf_getint(keyblob);
numbers[4].start = buf_getptr(keyblob, numbers[4].bytes);
buf_incrpos(keyblob, numbers[4].bytes);
/* x */
numbers[5].bytes = buf_getint(keyblob);
numbers[5].start = buf_getptr(keyblob, numbers[5].bytes);
buf_incrpos(keyblob, numbers[5].bytes);
nnumbers = 6;
header = "-----BEGIN DSA PRIVATE KEY-----\n";
footer = "-----END DSA PRIVATE KEY-----\n";
}
#endif /* DROPBEAR_DSS */
/*
* Now count up the total size of the ASN.1 encoded integers,
* so as to determine the length of the containing SEQUENCE.
*/
len = 0;
for (i = 0; i < nnumbers; i++) {
len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0);
len += numbers[i].bytes;
}
seqlen = len;
/* Now add on the SEQUENCE header. */
len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
/* Round up to the cipher block size, ensuring we have at least one
* byte of padding (see below). */
outlen = len;
if (passphrase)
outlen = (outlen+8) &~ 7;
/*
* Now we know how big outblob needs to be. Allocate it.
*/
outblob = (unsigned char*)m_malloc(outlen);
/*
* And write the data into it.
*/
pos = 0;
pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
for (i = 0; i < nnumbers; i++) {
pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0);
memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
pos += numbers[i].bytes;
}
} /* end RSA and DSS handling */
#ifdef DROPBEAR_ECDSA
if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
|| key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) {
/* SEC1 V2 appendix c.4
ECPrivateKey ::= SEQUENCE {
version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
privateKey OCTET STRING,
parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
publicKey [1] BIT STRING OPTIONAL
}
*/
buffer *seq_buf = buf_new(400);
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, key->type);
const long curve_size = (*eck)->dp->size;
int curve_oid_len = 0;
const void* curve_oid = NULL;
unsigned long pubkey_size = 2*curve_size+1;
unsigned int k_size;
/* version. less than 10 bytes */
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 2, 1, 0));
buf_putbyte(seq_buf, 1);
/* privateKey */
k_size = mp_unsigned_bin_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);
/* SECGCurveNames */
switch (key->type)
{
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
curve_oid_len = sizeof(OID_SEC256R1_BLOB);
curve_oid = OID_SEC256R1_BLOB;
break;
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
curve_oid_len = sizeof(OID_SEC384R1_BLOB);
curve_oid = OID_SEC384R1_BLOB;
break;
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
curve_oid_len = sizeof(OID_SEC521R1_BLOB);
curve_oid = OID_SEC521R1_BLOB;
break;
default:
dropbear_exit("Internal error");
}
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 0, 2+curve_oid_len, 0xa0));
/* object == 6 */
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 6, curve_oid_len, 0));
buf_putbytes(seq_buf, curve_oid, curve_oid_len);
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 1, 2+1+pubkey_size, 0xa0));
buf_incrwritepos(seq_buf,
ber_write_id_len(buf_getwriteptr(seq_buf, 10), 3, 1+pubkey_size, 0));
buf_putbyte(seq_buf, 0);
int err = ecc_ansi_x963_export(*eck, buf_getwriteptr(seq_buf, pubkey_size), &pubkey_size);
if (err != CRYPT_OK) {
dropbear_exit("ECC error");
}
buf_incrwritepos(seq_buf, pubkey_size);
buf_setpos(seq_buf, 0);
outblob = (unsigned char*)m_malloc(1000);
pos = 0;
pos += ber_write_id_len(outblob+pos, 16, seq_buf->len, ASN1_CONSTRUCTED);
memcpy(&outblob[pos], seq_buf->data, seq_buf->len);
pos += seq_buf->len;
len = pos;
outlen = len;
buf_burn(seq_buf);
buf_free(seq_buf);
seq_buf = NULL;
header = "-----BEGIN EC PRIVATE KEY-----\n";
footer = "-----END EC PRIVATE KEY-----\n";
}
#endif
/*
* Padding on OpenSSH keys is deterministic. The number of

View File

@@ -19,7 +19,7 @@ srcdir=@srcdir@
# Compilation flags. Note the += does not write over the user's CFLAGS!
# The rest of the flags come from the parent Dropbear makefile
CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../
CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../ -DLTC_SOURCE -I$(srcdir)/../libtommath/
# additional warnings (newer GCC 3.4 and higher)
ifdef GCC_34
@@ -157,7 +157,53 @@ src/modes/lrw/lrw_decrypt.o src/modes/lrw/lrw_done.o src/modes/lrw/lrw_encrypt.o
src/modes/lrw/lrw_getiv.o src/modes/lrw/lrw_process.o src/modes/lrw/lrw_setiv.o \
src/modes/lrw/lrw_start.o src/modes/lrw/lrw_test.o src/modes/ofb/ofb_decrypt.o src/modes/ofb/ofb_done.o \
src/modes/ofb/ofb_encrypt.o src/modes/ofb/ofb_getiv.o src/modes/ofb/ofb_setiv.o \
src/modes/ofb/ofb_start.o
src/modes/ofb/ofb_start.o src/pk/asn1/der/bit/der_decode_bit_string.o \
src/pk/asn1/der/bit/der_encode_bit_string.o src/pk/asn1/der/bit/der_length_bit_string.o \
src/pk/asn1/der/boolean/der_decode_boolean.o src/pk/asn1/der/boolean/der_encode_boolean.o \
src/pk/asn1/der/boolean/der_length_boolean.o src/pk/asn1/der/choice/der_decode_choice.o \
src/pk/asn1/der/ia5/der_decode_ia5_string.o src/pk/asn1/der/ia5/der_encode_ia5_string.o \
src/pk/asn1/der/ia5/der_length_ia5_string.o src/pk/asn1/der/integer/der_decode_integer.o \
src/pk/asn1/der/integer/der_encode_integer.o src/pk/asn1/der/integer/der_length_integer.o \
src/pk/asn1/der/object_identifier/der_decode_object_identifier.o \
src/pk/asn1/der/object_identifier/der_encode_object_identifier.o \
src/pk/asn1/der/object_identifier/der_length_object_identifier.o \
src/pk/asn1/der/octet/der_decode_octet_string.o src/pk/asn1/der/octet/der_encode_octet_string.o \
src/pk/asn1/der/octet/der_length_octet_string.o \
src/pk/asn1/der/printable_string/der_decode_printable_string.o \
src/pk/asn1/der/printable_string/der_encode_printable_string.o \
src/pk/asn1/der/printable_string/der_length_printable_string.o \
src/pk/asn1/der/sequence/der_decode_sequence_ex.o \
src/pk/asn1/der/sequence/der_decode_sequence_flexi.o \
src/pk/asn1/der/sequence/der_decode_sequence_multi.o \
src/pk/asn1/der/sequence/der_encode_sequence_ex.o \
src/pk/asn1/der/sequence/der_encode_sequence_multi.o src/pk/asn1/der/sequence/der_length_sequence.o \
src/pk/asn1/der/sequence/der_sequence_free.o src/pk/asn1/der/set/der_encode_set.o \
src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_short_integer.o \
src/pk/asn1/der/short_integer/der_encode_short_integer.o \
src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \
src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \
src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \
src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \
src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \
src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \
src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \
src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \
src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \
src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \
src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \
src/pk/katja/katja_make_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \
src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \
src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \
src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \
src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_import.o \
src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_sign_hash.o src/pk/rsa/rsa_verify_hash.o src/prngs/fortuna.o \
src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \
src/prngs/sprng.o src/prngs/yarrow.o
HEADERS=src/headers/tomcrypt_cfg.h src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h \
src/headers/tomcrypt_custom.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cipher.h \

View File

@@ -24,7 +24,7 @@ extern "C" {
/* descriptor table size */
/* Dropbear change - this should be smaller, saves some size */
#define TAB_SIZE 4
#define TAB_SIZE 5
/* error codes [will be expanded in future releases] */
enum {

View File

@@ -127,13 +127,32 @@
#ifdef DROPBEAR_SHA256
#define SHA256
#endif
#ifdef DROPBEAR_SHA384
#define SHA384
#endif
#ifdef DROPBEAR_SHA512
#define SHA512
#endif
#define LTC_HMAC
#ifdef DROPBEAR_ECC
#define MECC
#define LTC_ECC_SHAMIR
#define LTC_ECC_TIMING_RESISTANT
#define MPI
#define LTM_DESC
#ifdef DROPBEAR_ECC_256
#define ECC256
#endif
#ifdef DROPBEAR_ECC_384
#define ECC384
#endif
#ifdef DROPBEAR_ECC_521
#define ECC521
#endif
#endif
/* Various tidbits of modern neatoness */
#define BASE64

View File

@@ -11,12 +11,9 @@
typedef void ecc_point;
#endif
/* Dropbear has its own rsa_key. We just comment this out. */
#if 0
#ifndef MRSA
typedef void rsa_key;
#endif
#endif
/** math descriptor */
typedef struct {
@@ -389,8 +386,6 @@ typedef struct {
ecc_point *C,
void *modulus);
/* Dropbear has its own rsa code */
#if 0
/* ---- (optional) rsa optimized math (for internal CRT) ---- */
/** RSA Key Generation
@@ -416,7 +411,6 @@ typedef struct {
int (*rsa_me)(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int which,
rsa_key *key);
#endif
} ltc_math_descriptor;
extern ltc_math_descriptor ltc_mp;

View File

@@ -10,4 +10,4 @@
*/
#include "tomcrypt.h"
ltc_math_descriptor ltc_mp;
ltc_math_descriptor ltc_mp = {0};

View File

@@ -21,7 +21,7 @@
ECC Crypto, Tom St Denis
*/
#ifdef MECC
#if defined(MECC) && defined(LTC_DER)
/**
Decrypt an ECC encrypted key

View File

@@ -21,7 +21,7 @@
ECC Crypto, Tom St Denis
*/
#ifdef MECC
#if defined(MECC) && defined(LTC_DER)
/**
Encrypt a symmetric key with ECC

View File

@@ -21,7 +21,7 @@
ECC Crypto, Tom St Denis
*/
#ifdef MECC
#if defined(MECC) && defined(LTC_DER)
/**
Export an ECC key as a binary packet

View File

@@ -21,7 +21,7 @@
ECC Crypto, Tom St Denis
*/
#ifdef MECC
#if defined(MECC) && defined(LTC_DER)
static int is_point(ecc_key *key)
{

View File

@@ -21,7 +21,7 @@
ECC Crypto, Tom St Denis
*/
#ifdef MECC
#if defined(MECC) && defined(LTC_DER)
/**
Sign a message digest

View File

@@ -21,7 +21,7 @@
ECC Crypto, Tom St Denis
*/
#ifdef MECC
#if defined(MECC) && defined(LTC_DER)
/* verify
*

View File

@@ -329,8 +329,6 @@ login_write (struct logininfo *li)
{
#ifndef HAVE_CYGWIN
if ((int)geteuid() != 0) {
dropbear_log(LOG_WARNING,
"Attempt to write login records by non-root user (aborting)");
return 1;
}
#endif

View File

@@ -73,10 +73,10 @@
#else
/* Simply select your favourite login types. */
/* Can't do if-else because some systems use several... <sigh> */
# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
# if defined(HAVE_UTMPX_H) && defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
# define USE_UTMPX
# endif
# if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
# if defined(HAVE_UTMP_H) && defined(UTMP_FILE) && !defined(DISABLE_UTMP)
# define USE_UTMP
# endif
# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)

137
ltc_prng.c Normal file
View File

@@ -0,0 +1,137 @@
/* Copied from libtomcrypt/src/prngs/sprng.c and modified to
* use Dropbear's genrandom(). */
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
*/
#include "options.h"
#include "includes.h"
#include "dbrandom.h"
#include "ltc_prng.h"
/**
@file sprng.c
Secure PRNG, Tom St Denis
*/
/* A secure PRNG using the RNG functions. Basically this is a
* wrapper that allows you to use a secure RNG as a PRNG
* in the various other functions.
*/
#ifdef DROPBEAR_LTC_PRNG
/**
Start the PRNG
@param prng [out] The PRNG state to initialize
@return CRYPT_OK if successful
*/
int dropbear_prng_start(prng_state* UNUSED(prng))
{
return CRYPT_OK;
}
/**
Add entropy to the PRNG state
@param in The data to add
@param inlen Length of the data to add
@param prng PRNG state to update
@return CRYPT_OK if successful
*/
int dropbear_prng_add_entropy(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
{
return CRYPT_OK;
}
/**
Make the PRNG ready to read from
@param prng The PRNG to make active
@return CRYPT_OK if successful
*/
int dropbear_prng_ready(prng_state* UNUSED(prng))
{
return CRYPT_OK;
}
/**
Read from the PRNG
@param out Destination
@param outlen Length of output
@param prng The active PRNG to read from
@return Number of octets read
*/
unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* UNUSED(prng))
{
LTC_ARGCHK(out != NULL);
genrandom(out, outlen);
return outlen;
}
/**
Terminate the PRNG
@param prng The PRNG to terminate
@return CRYPT_OK if successful
*/
int dropbear_prng_done(prng_state* UNUSED(prng))
{
return CRYPT_OK;
}
/**
Export the PRNG state
@param out [out] Destination
@param outlen [in/out] Max size and resulting size of the state
@param prng The PRNG to export
@return CRYPT_OK if successful
*/
int dropbear_prng_export(unsigned char* UNUSED(out), unsigned long* outlen, prng_state* UNUSED(prng))
{
LTC_ARGCHK(outlen != NULL);
*outlen = 0;
return CRYPT_OK;
}
/**
Import a PRNG state
@param in The PRNG state
@param inlen Size of the state
@param prng The PRNG to import
@return CRYPT_OK if successful
*/
int dropbear_prng_import(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
{
return CRYPT_OK;
}
/**
PRNG self-test
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
*/
int dropbear_prng_test(void)
{
return CRYPT_OK;
}
const struct ltc_prng_descriptor dropbear_prng_desc =
{
"dropbear_prng", 0,
&dropbear_prng_start,
&dropbear_prng_add_entropy,
&dropbear_prng_ready,
&dropbear_prng_read,
&dropbear_prng_done,
&dropbear_prng_export,
&dropbear_prng_import,
&dropbear_prng_test
};
#endif /* DROPBEAR_LTC_PRNG */

13
ltc_prng.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef _LTC_PRNG_H_DROPBEAR
#define _LTC_PRNG_H_DROPBEAR
#include "options.h"
#include "includes.h"
#ifdef DROPBEAR_LTC_PRNG
extern const struct ltc_prng_descriptor dropbear_prng_desc;
#endif /* DROPBEAR_LTC_PRNG */
#endif /* _LTC_PRNG_H_DROPBEAR */

View File

@@ -5,10 +5,10 @@
#ifndef _OPTIONS_H_
#define _OPTIONS_H_
/******************************************************************
* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
******************************************************************/
/* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
* parts are to allow for commandline -DDROPBEAR_XXX options etc. */
/* IMPORTANT: Many options will require "make clean" after changes */
#ifndef DROPBEAR_DEFPORT
#define DROPBEAR_DEFPORT "22"
@@ -26,6 +26,9 @@
#ifndef RSA_PRIV_FILENAME
#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key"
#endif
#ifndef ECDSA_PRIV_FILENAME
#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key"
#endif
/* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens
* on chosen ports and keeps accepting connections. This is the default.
@@ -49,7 +52,7 @@
several kB in binary size however will make the symmetrical ciphers and hashes
slower, perhaps by 50%. Recommended for small systems that aren't doing
much traffic. */
/*#define DROPBEAR_SMALL_CODE*/
#define DROPBEAR_SMALL_CODE
/* Enable X11 Forwarding - server only */
#define ENABLE_X11FWD
@@ -92,8 +95,12 @@ much traffic. */
#define DROPBEAR_AES256
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
/*#define DROPBEAR_BLOWFISH*/
#define DROPBEAR_TWOFISH256
#define DROPBEAR_TWOFISH128
/*#define DROPBEAR_TWOFISH256*/
/*#define DROPBEAR_TWOFISH128*/
/* Enable CBC mode for ciphers. This has security issues though
* is the most compatible with older SSH implementations */
#define DROPBEAR_ENABLE_CBC_MODE
/* Enable "Counter Mode" for ciphers. This is more secure than normal
* CBC mode against certain attacks. This adds around 1kB to binary
@@ -120,13 +127,13 @@ much traffic. */
* which are not the standard form. */
#define DROPBEAR_SHA1_HMAC
#define DROPBEAR_SHA1_96_HMAC
/*#define DROPBEAR_SHA2_256_HMAC*/
/*#define DROPBEAR_SHA2_512_HMAC*/
#define DROPBEAR_SHA2_256_HMAC
#define DROPBEAR_SHA2_512_HMAC
#define DROPBEAR_MD5_HMAC
/* You can also disable integrity. Don't bother disabling this if you're
* still using a cipher, it's relatively cheap. If you disable this it's dead
* simple to run arbitrary commands on the remote host. Beware. */
* simple for an attacker to run arbitrary commands on the remote host. Beware. */
/* #define DROPBEAR_NONE_INTEGRITY */
/* Hostkey/public key algorithms - at least one required, these are used
@@ -135,11 +142,26 @@ much traffic. */
* SSH2 RFC Draft requires dss, recommends rsa */
#define DROPBEAR_RSA
#define DROPBEAR_DSS
/* ECDSA is significantly faster than RSA or DSS. Compiling in ECC
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64 */
#define DROPBEAR_ECDSA
/* RSA can be vulnerable to timing attacks which use the time required for
* signing to guess the private key. Blinding avoids this attack, though makes
* signing operations slightly slower. */
#define RSA_BLINDING
/* Generate hostkeys as-needed when the first connection using that key type occurs.
This avoids the need to otherwise run "dropbearkey" and avoids some problems
with badly seeded /dev/urandom when systems first boot.
This also requires a runtime flag "-R". This adds ~4kB to binary size (or hardly
anything if dropbearkey is linked in a "dropbearmulti" binary) */
#define DROPBEAR_DELAY_HOSTKEY
/* Enable Curve25519 for key exchange. This is another elliptic
* curve method with good security properties. Increases binary size
* by ~8kB on x86-64 */
#define DROPBEAR_CURVE25519
/* Enable elliptic curve Diffie Hellman key exchange, see note about
* ECDSA above */
#define DROPBEAR_ECDH
/* Control the memory/performance/compression tradeoff for zlib.
* Set windowBits=8 for least memory usage, see your system's
@@ -152,8 +174,13 @@ much traffic. */
#define DROPBEAR_ZLIB_WINDOW_BITS 15
#endif
/* Server won't allow zlib compression until after authentication. Prevents
flaws in the zlib library being unauthenticated exploitable flaws.
Some old ssh clients may not support the alternative zlib@openssh.com method */
#define DROPBEAR_SERVER_DELAY_ZLIB 1
/* Whether to do reverse DNS lookups. */
#define DO_HOST_LOOKUP
/*#define DO_HOST_LOOKUP */
/* Whether to print the message of the day (MOTD). This doesn't add much code
* size */
@@ -176,7 +203,7 @@ much traffic. */
#define ENABLE_SVR_PASSWORD_AUTH
/* PAM requires ./configure --enable-pam */
/*#define ENABLE_SVR_PAM_AUTH*/
/*#define ENABLE_SVR_PAM_AUTH */
#define ENABLE_SVR_PUBKEY_AUTH
/* Whether to take public key options in
@@ -189,6 +216,10 @@ much traffic. */
#define ENABLE_CLI_PUBKEY_AUTH
#define ENABLE_CLI_INTERACT_AUTH
/* A default argument for dbclient -i <privatekey>.
leading "~" is expanded */
#define DROPBEAR_DEFAULT_CLI_AUTHKEY "~/.ssh/id_dropbear"
/* This variable can be used to set a password for client
* authentication on the commandline. Beware of platforms
* that don't protect environment variables of processes etc. Also
@@ -204,6 +235,12 @@ much traffic. */
* return the password on standard output */
/*#define ENABLE_CLI_ASKPASS_HELPER*/
/* Save a network roundtrip by sendng a real auth request immediately after
* sending a query for the available methods. It is at the expense of < 100
* bytes of extra network traffic. This is not yet enabled by default since it
* could cause problems with non-compliant servers */
/* #define DROPBEAR_CLI_IMMEDIATE_AUTH */
/* Source for randomness. This must be able to provide hundreds of bytes per SSH
* connection without blocking. In addition /dev/random is used for seeding
* rsa/dss key generation */
@@ -240,7 +277,7 @@ much traffic. */
/* The command to invoke for xauth when using X11 forwarding.
* "-q" for quiet */
#ifndef XAUTH_COMMAND
#define XAUTH_COMMAND "/usr/bin/X11/xauth -q"
#define XAUTH_COMMAND "/usr/bin/xauth -q"
#endif
/* if you want to enable running an sftp server (such as the one included with
@@ -284,6 +321,11 @@ much traffic. */
be overridden at runtime with -K. 0 disables keepalives */
#define DEFAULT_KEEPALIVE 0
/* If this many KEEPALIVES are sent with no packets received from the
other side, exit. Not run-time configurable - if you have a need
for runtime configuration please mail the Dropbear list */
#define DEFAULT_KEEPALIVE_LIMIT 3
/* Ensure that data is received within IDLE_TIMEOUT seconds. This can
be overridden at runtime with -I. 0 disables idle timeouts */
#define DEFAULT_IDLE_TIMEOUT 0

179
packet.c
View File

@@ -30,7 +30,7 @@
#include "algo.h"
#include "buffer.h"
#include "kex.h"
#include "random.h"
#include "dbrandom.h"
#include "service.h"
#include "auth.h"
#include "channel.h"
@@ -41,8 +41,12 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
unsigned char *output_mac);
static int checkmac();
#define ZLIB_COMPRESS_INCR 100
#define ZLIB_DECOMPRESS_INCR 100
/* For exact details see http://www.zlib.net/zlib_tech.html
* 5 bytes per 16kB block, plus 6 bytes for the stream.
* We might allocate 5 unnecessary bytes here if it's an
* exact multiple. */
#define ZLIB_COMPRESS_EXPANSION (((RECV_MAX_PAYLOAD_LEN/16384)+1)*5 + 6)
#define ZLIB_DECOMPRESS_INCR 1024
#ifndef DISABLE_ZLIB
static buffer* buf_decompress(buffer* buf, unsigned int len);
static void buf_compress(buffer * dest, buffer * src, unsigned int len);
@@ -53,12 +57,76 @@ void write_packet() {
int len, written;
buffer * writebuf = NULL;
time_t now;
unsigned packet_type;
#ifdef HAVE_WRITEV
struct iovec *iov = NULL;
int i;
struct Link *l;
int iov_max_count;
#endif
TRACE(("enter write_packet"))
TRACE2(("enter write_packet"))
dropbear_assert(!isempty(&ses.writequeue));
#if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV))
#ifndef IOV_MAX
#define IOV_MAX UIO_MAXIOV
#endif
/* Make sure the size of the iov is below the maximum allowed by the OS. */
iov_max_count = ses.writequeue.count;
if (iov_max_count > IOV_MAX)
{
iov_max_count = IOV_MAX;
}
iov = m_malloc(sizeof(*iov) * iov_max_count);
for (l = ses.writequeue.head, i = 0; l; l = l->link, i++)
{
writebuf = (buffer*)l->item;
packet_type = writebuf->data[writebuf->len-1];
len = writebuf->len - 1 - writebuf->pos;
dropbear_assert(len > 0);
TRACE2(("write_packet writev #%d type %d len %d/%d", i, packet_type,
len, writebuf->len-1))
iov[i].iov_base = buf_getptr(writebuf, len);
iov[i].iov_len = len;
}
/* This may return EAGAIN. The main loop sometimes
calls write_packet() without bothering to test with select() since
it's likely to be necessary */
written = writev(ses.sock_out, iov, iov_max_count);
if (written < 0) {
if (errno == EINTR || errno == EAGAIN) {
m_free(iov);
TRACE2(("leave write_packet: EINTR"))
return;
} else {
dropbear_exit("Error writing: %s", strerror(errno));
}
}
if (written == 0) {
ses.remoteclosed();
}
while (written > 0) {
writebuf = (buffer*)examine(&ses.writequeue);
len = writebuf->len - 1 - writebuf->pos;
if (len > written) {
/* partial buffer write */
buf_incrpos(writebuf, written);
written = 0;
} else {
written -= len;
dequeue(&ses.writequeue);
buf_free(writebuf);
}
}
m_free(iov);
#else /* No writev () */
/* Get the next buffer in the queue of encrypted packets to write*/
writebuf = (buffer*)examine(&ses.writequeue);
@@ -71,20 +139,13 @@ void write_packet() {
written = write(ses.sock_out, buf_getptr(writebuf, len), len);
if (written < 0) {
if (errno == EINTR) {
TRACE(("leave writepacket: EINTR"))
if (errno == EINTR || errno == EAGAIN) {
TRACE2(("leave writepacket: EINTR"))
return;
} else {
dropbear_exit("Error writing");
dropbear_exit("Error writing: %s", strerror(errno));
}
}
now = time(NULL);
ses.last_trx_packet_time = now;
if (packet_type != SSH_MSG_IGNORE) {
ses.last_packet_time = now;
}
if (written == 0) {
ses.remoteclosed();
@@ -99,8 +160,9 @@ void write_packet() {
/* More packet left to write, leave it in the queue for later */
buf_incrpos(writebuf, written);
}
#endif /* writev */
TRACE(("leave write_packet"))
TRACE2(("leave write_packet"))
}
/* Non-blocking function reading available portion of a packet into the
@@ -112,7 +174,7 @@ void read_packet() {
unsigned int maxlen;
unsigned char blocksize;
TRACE(("enter read_packet"))
TRACE2(("enter read_packet"))
blocksize = ses.keys->recv.algo_crypt->blocksize;
if (ses.readbuf == NULL || ses.readbuf->len < blocksize) {
@@ -125,7 +187,7 @@ void read_packet() {
if (ret == DROPBEAR_FAILURE) {
/* didn't read enough to determine the length */
TRACE(("leave read_packet: packetinit done"))
TRACE2(("leave read_packet: packetinit done"))
return;
}
}
@@ -147,7 +209,7 @@ void read_packet() {
if (len < 0) {
if (errno == EINTR || errno == EAGAIN) {
TRACE(("leave read_packet: EINTR or EAGAIN"))
TRACE2(("leave read_packet: EINTR or EAGAIN"))
return;
} else {
dropbear_exit("Error reading: %s", strerror(errno));
@@ -163,7 +225,7 @@ void read_packet() {
/* The main select() loop process_packet() to
* handle the packet contents... */
}
TRACE(("leave read_packet"))
TRACE2(("leave read_packet"))
}
/* Function used to read the initial portion of a packet, and determine the
@@ -196,8 +258,8 @@ static int read_packet_init() {
ses.remoteclosed();
}
if (slen < 0) {
if (errno == EINTR) {
TRACE(("leave read_packet_init: EINTR"))
if (errno == EINTR || errno == EAGAIN) {
TRACE2(("leave read_packet_init: EINTR"))
return DROPBEAR_FAILURE;
}
dropbear_exit("Error reading: %s", strerror(errno));
@@ -221,14 +283,14 @@ static int read_packet_init() {
}
len = buf_getint(ses.readbuf) + 4 + macsize;
TRACE(("packet size is %d, block %d mac %d", len, blocksize, macsize))
TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
/* check packet length */
if ((len > RECV_MAX_PACKET_LEN) ||
(len < MIN_PACKET_LEN + macsize) ||
((len - macsize) % blocksize != 0)) {
dropbear_exit("Integrity error (bad packet size %d)", len);
dropbear_exit("Integrity error (bad packet size %u)", len);
}
if (len > ses.readbuf->size) {
@@ -247,7 +309,7 @@ void decrypt_packet() {
unsigned int padlen;
unsigned int len;
TRACE(("enter decrypt_packet"))
TRACE2(("enter decrypt_packet"))
blocksize = ses.keys->recv.algo_crypt->blocksize;
macsize = ses.keys->recv.algo_mac->hashsize;
@@ -279,8 +341,8 @@ void decrypt_packet() {
/* payload length */
/* - 4 - 1 is for LEN and PADLEN values */
len = ses.readbuf->len - padlen - 4 - 1 - macsize;
if ((len > RECV_MAX_PAYLOAD_LEN) || (len < 1)) {
dropbear_exit("Bad packet size %d", len);
if ((len > RECV_MAX_PAYLOAD_LEN+ZLIB_COMPRESS_EXPANSION) || (len < 1)) {
dropbear_exit("Bad packet size %u", len);
}
buf_setpos(ses.readbuf, PACKET_PAYLOAD_OFF);
@@ -304,7 +366,7 @@ void decrypt_packet() {
ses.recvseq++;
TRACE(("leave decrypt_packet"))
TRACE2(("leave decrypt_packet"))
}
/* Checks the mac at the end of a decrypted readbuf.
@@ -314,7 +376,7 @@ static int checkmac() {
unsigned char mac_bytes[MAX_MAC_LEN];
unsigned int mac_size, contents_len;
mac_size = ses.keys->trans.algo_mac->hashsize;
mac_size = ses.keys->recv.algo_mac->hashsize;
contents_len = ses.readbuf->len - mac_size;
buf_setpos(ses.readbuf, 0);
@@ -322,7 +384,7 @@ static int checkmac() {
/* compare the hash */
buf_setpos(ses.readbuf, contents_len);
if (memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
if (constant_time_memcmp(mac_bytes, buf_getptr(ses.readbuf, mac_size), mac_size) != 0) {
return DROPBEAR_FAILURE;
} else {
return DROPBEAR_SUCCESS;
@@ -366,7 +428,14 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
}
if (zstream->avail_out == 0) {
buf_resize(ret, ret->size + ZLIB_DECOMPRESS_INCR);
int new_size = 0;
if (ret->size >= RECV_MAX_PAYLOAD_LEN) {
/* Already been increased as large as it can go,
* yet didn't finish up the decompression */
dropbear_exit("bad packet, oversized decompressed");
}
new_size = MIN(RECV_MAX_PAYLOAD_LEN, ret->size + ZLIB_DECOMPRESS_INCR);
buf_resize(ret, new_size);
}
}
}
@@ -403,7 +472,6 @@ static void enqueue_reply_packet() {
ses.reply_queue_head = new_item;
}
ses.reply_queue_tail = new_item;
TRACE(("leave enqueue_reply_packet"))
}
void maybe_flush_reply_queue() {
@@ -439,25 +507,21 @@ void encrypt_packet() {
unsigned char packet_type;
unsigned int len, encrypt_buf_size;
unsigned char mac_bytes[MAX_MAC_LEN];
time_t now;
TRACE(("enter encrypt_packet()"))
TRACE2(("enter encrypt_packet()"))
buf_setpos(ses.writepayload, 0);
packet_type = buf_getbyte(ses.writepayload);
buf_setpos(ses.writepayload, 0);
TRACE(("encrypt_packet type is %d", packet_type))
TRACE2(("encrypt_packet type is %d", packet_type))
if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))
|| ses.kexstate.sentnewkeys) {
if ((!ses.dataallowed && !packet_is_okay_kex(packet_type))) {
/* During key exchange only particular packets are allowed.
Since this packet_type isn't OK we just enqueue it to send
after the KEX, see maybe_flush_reply_queue */
/* We also enqueue packets here when we have sent a MSG_NEWKEYS
* packet but are yet to received one. For simplicity we just switch
* over all the keys at once. This is the 'ses.kexstate.sentnewkeys'
* case. */
enqueue_reply_packet();
return;
}
@@ -474,7 +538,7 @@ void encrypt_packet() {
+ mac_size
#ifndef DISABLE_ZLIB
/* some extra in case 'compression' makes it larger */
+ ZLIB_COMPRESS_INCR
+ ZLIB_COMPRESS_EXPANSION
#endif
/* and an extra cleartext (stripped before transmission) byte for the
* packet type */
@@ -487,14 +551,7 @@ void encrypt_packet() {
#ifndef DISABLE_ZLIB
/* compression */
if (is_compress_trans()) {
int compress_delta;
buf_compress(writebuf, ses.writepayload, ses.writepayload->len);
compress_delta = (writebuf->len - PACKET_PAYLOAD_OFF) - ses.writepayload->len;
/* Handle the case where 'compress' increased the size. */
if (compress_delta > ZLIB_COMPRESS_INCR) {
buf_resize(writebuf, writebuf->size + compress_delta);
}
} else
#endif
{
@@ -559,7 +616,19 @@ void encrypt_packet() {
ses.kexstate.datatrans += writebuf->len;
ses.transseq++;
TRACE(("leave encrypt_packet()"))
now = monotonic_now();
ses.last_packet_time_any_sent = now;
/* idle timeout shouldn't be affected by responses to keepalives.
send_msg_keepalive() itself also does tricks with
ses.last_packet_idle_time - read that if modifying this code */
if (packet_type != SSH_MSG_REQUEST_FAILURE
&& packet_type != SSH_MSG_UNIMPLEMENTED
&& packet_type != SSH_MSG_IGNORE) {
ses.last_packet_time_idle = now;
}
TRACE2(("leave encrypt_packet()"))
}
@@ -572,8 +641,6 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
unsigned long bufsize;
hmac_state hmac;
TRACE(("enter writemac"))
if (key_state->algo_mac->hashsize > 0) {
/* calculate the mac */
if (hmac_init(&hmac,
@@ -602,7 +669,7 @@ static void make_mac(unsigned int seqno, const struct key_context_directional *
dropbear_exit("HMAC error");
}
}
TRACE(("leave writemac"))
TRACE2(("leave writemac"))
}
#ifndef DISABLE_ZLIB
@@ -613,7 +680,7 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
unsigned int endpos = src->pos + len;
int result;
TRACE(("enter buf_compress"))
TRACE2(("enter buf_compress"))
while (1) {
@@ -644,9 +711,9 @@ static void buf_compress(buffer * dest, buffer * src, unsigned int len) {
/* the buffer has been filled, we must extend. This only happens in
* unusual circumstances where the data grows in size after deflate(),
* but it is possible */
buf_resize(dest, dest->size + ZLIB_COMPRESS_INCR);
buf_resize(dest, dest->size + ZLIB_COMPRESS_EXPANSION);
}
TRACE(("leave buf_compress"))
TRACE2(("leave buf_compress"))
}
#endif

View File

@@ -30,7 +30,7 @@
#include "algo.h"
#include "buffer.h"
#include "kex.h"
#include "random.h"
#include "dbrandom.h"
#include "service.h"
#include "auth.h"
#include "channel.h"
@@ -44,15 +44,17 @@ void process_packet() {
unsigned char type;
unsigned int i;
time_t now;
TRACE(("enter process_packet"))
TRACE2(("enter process_packet"))
type = buf_getbyte(ses.payload);
TRACE(("process_packet: packet type = %d", type))
TRACE(("process_packet: packet type = %d, len %d", type, ses.payload->len))
ses.lastpacket = type;
ses.last_packet_time = time(NULL);
now = monotonic_now();
ses.last_packet_time_keepalive_recv = now;
/* These packets we can receive at any time */
switch(type) {
@@ -65,23 +67,49 @@ void process_packet() {
case SSH_MSG_UNIMPLEMENTED:
/* debugging XXX */
TRACE(("SSH_MSG_UNIMPLEMENTED"))
dropbear_exit("Received SSH_MSG_UNIMPLEMENTED");
goto out;
case SSH_MSG_DISCONNECT:
/* TODO cleanup? */
dropbear_close("Disconnect received");
}
/* Ignore these packet types so that keepalives don't interfere with
idle detection. This is slightly incorrect since a tcp forwarded
global request with failure won't trigger the idle timeout,
but that's probably acceptable */
if (!(type == SSH_MSG_GLOBAL_REQUEST || type == SSH_MSG_REQUEST_FAILURE)) {
ses.last_packet_time_idle = now;
}
/* This applies for KEX, where the spec says the next packet MUST be
* NEWKEYS */
if (ses.requirenext != 0) {
if (ses.requirenext != type) {
/* TODO send disconnect? */
dropbear_exit("Unexpected packet type %d, expected %d", type,
ses.requirenext);
} else {
if (ses.requirenext == type)
{
/* Got what we expected */
ses.requirenext = 0;
TRACE(("got expected packet %d during kexinit", type))
}
else
{
/* RFC4253 7.1 - various messages are allowed at this point.
The only ones we know about have already been handled though,
so just return "unimplemented" */
if (type >= 1 && type <= 49
&& type != SSH_MSG_SERVICE_REQUEST
&& type != SSH_MSG_SERVICE_ACCEPT
&& type != SSH_MSG_KEXINIT)
{
TRACE(("unknown allowed packet during kexinit"))
recv_unimplemented();
goto out;
}
else
{
TRACE(("disallowed packet during kexinit"))
dropbear_exit("Unexpected packet type %d, expected %d", type,
ses.requirenext);
}
}
}
@@ -93,6 +121,12 @@ void process_packet() {
goto out;
}
/* Only clear the flag after we have checked ignorenext */
if (ses.requirenext != 0 && ses.requirenext == type)
{
ses.requirenext = 0;
}
/* Kindly the protocol authors gave all the preauth packets type values
* less-than-or-equal-to 60 ( == MAX_UNAUTH_PACKET_TYPE ).
@@ -123,7 +157,7 @@ out:
buf_free(ses.payload);
ses.payload = NULL;
TRACE(("leave process_packet"))
TRACE2(("leave process_packet"))
}

View File

@@ -70,7 +70,6 @@ void enqueue(struct Queue* queue, void* item) {
struct Link* newlink;
TRACE(("enter enqueue"))
newlink = (struct Link*)m_malloc(sizeof(struct Link));
newlink->item = item;
@@ -85,5 +84,4 @@ void enqueue(struct Queue* queue, void* item) {
queue->head = newlink;
}
queue->count++;
TRACE(("leave enqueue"))
}

View File

@@ -36,7 +36,7 @@ struct Queue {
struct Link* head;
struct Link* tail;
unsigned int count; /* safety value */
unsigned int count;
};

40
release.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/sh
VERSION=$(echo '#include "sysoptions.h"\necho DROPBEAR_VERSION' | cpp - | sh)
echo Releasing version "$VERSION" ...
if ! head -n1 CHANGES | grep -q $VERSION ; then
echo "CHANGES needs updating"
exit 1
fi
if ! head -n1 debian/changelog | grep -q $VERSION ; then
echo "debian/changelog needs updating"
exit 1
fi
head -n1 CHANGES
#sleep 3
RELDIR=$PWD/../dropbear-$VERSION
ARCHIVE=${RELDIR}.tar.bz2
if test -e $RELDIR; then
echo "$RELDIR exists"
exit 1
fi
if test -e $ARCHIVE; then
echo "$ARCHIVE exists"
exit 1
fi
hg archive "$RELDIR" || exit 2
(cd "$RELDIR" && autoconf && autoheader) || exit 2
rm -r "$RELDIR/autom4te.cache" || exit 2
(cd $RELDIR/.. && tar cjf $ARCHIVE `basename "$RELDIR"`) || exit 2
ls -l $ARCHIVE
openssl sha1 $ARCHIVE
echo "Done to $ARCHIVE"

44
rsa.c
View File

@@ -34,13 +34,12 @@
#include "rsa.h"
#include "buffer.h"
#include "ssh.h"
#include "random.h"
#include "dbrandom.h"
#ifdef DROPBEAR_RSA
static void rsa_pad_em(dropbear_rsa_key * key,
const unsigned char * data, unsigned int len,
mp_int * rsa_em);
buffer *data_buf, mp_int * rsa_em);
/* Load a public rsa key from a buffer, initialising the values.
* The key will have the same format as buf_put_rsa_key.
@@ -51,9 +50,7 @@ int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key) {
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_rsa_pub_key"))
dropbear_assert(key != NULL);
key->e = m_malloc(sizeof(mp_int));
key->n = m_malloc(sizeof(mp_int));
m_mp_init_multi(key->e, key->n, NULL);
m_mp_alloc_init_multi(&key->e, &key->n, NULL);
key->d = NULL;
key->p = NULL;
key->q = NULL;
@@ -99,8 +96,7 @@ int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
key->p = NULL;
key->q = NULL;
key->d = m_malloc(sizeof(mp_int));
m_mp_init(key->d);
m_mp_alloc_init_multi(&key->d, NULL);
if (buf_getmpint(buf, key->d) == DROPBEAR_FAILURE) {
TRACE(("leave buf_get_rsa_priv_key: d: ret == DROPBEAR_FAILURE"))
goto out;
@@ -109,9 +105,7 @@ int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
if (buf->pos == buf->len) {
/* old Dropbear private keys didn't keep p and q, so we will ignore them*/
} else {
key->p = m_malloc(sizeof(mp_int));
key->q = m_malloc(sizeof(mp_int));
m_mp_init_multi(key->p, key->q, NULL);
m_mp_alloc_init_multi(&key->p, &key->q, NULL);
if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE) {
TRACE(("leave buf_get_rsa_priv_key: p: ret == DROPBEAR_FAILURE"))
@@ -139,10 +133,10 @@ out:
/* Clear and free the memory used by a public or private key */
void rsa_key_free(dropbear_rsa_key *key) {
TRACE(("enter rsa_key_free"))
TRACE2(("enter rsa_key_free"))
if (key == NULL) {
TRACE(("leave rsa_key_free: key == NULL"))
TRACE2(("leave rsa_key_free: key == NULL"))
return;
}
if (key->d) {
@@ -166,7 +160,7 @@ void rsa_key_free(dropbear_rsa_key *key) {
m_free(key->q);
}
m_free(key);
TRACE(("leave rsa_key_free"))
TRACE2(("leave rsa_key_free"))
}
/* Put the public rsa key into the buffer in the required format:
@@ -213,9 +207,7 @@ void buf_put_rsa_priv_key(buffer* buf, dropbear_rsa_key *key) {
#ifdef DROPBEAR_SIGNKEY_VERIFY
/* Verify a signature in buf, made on data by the key given.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len) {
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf) {
unsigned int slen;
DEF_MP_INT(rsa_s);
DEF_MP_INT(rsa_mdash);
@@ -247,7 +239,7 @@ int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* dat
}
/* create the magic PKCS padded value */
rsa_pad_em(key, data, len, &rsa_em);
rsa_pad_em(key, data_buf, &rsa_em);
if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
TRACE(("failed exptmod rsa_s"))
@@ -270,9 +262,7 @@ out:
/* Sign the data presented with key, writing the signature contents
* to the buffer */
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len) {
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf) {
unsigned int nsize, ssize;
unsigned int i;
DEF_MP_INT(rsa_s);
@@ -285,7 +275,7 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL);
rsa_pad_em(key, data, len, &rsa_tmp1);
rsa_pad_em(key, data_buf, &rsa_tmp1);
/* the actual signing of the padded data */
@@ -357,7 +347,9 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
mp_clear(&rsa_s);
#if defined(DEBUG_RSA) && defined(DEBUG_TRACE)
printhex("RSA sig", buf->data, buf->len);
if (!debug_trace) {
printhex("RSA sig", buf->data, buf->len);
}
#endif
@@ -377,8 +369,7 @@ void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* d
* rsa_em must be a pointer to an initialised mp_int.
*/
static void rsa_pad_em(dropbear_rsa_key * key,
const unsigned char * data, unsigned int len,
mp_int * rsa_em) {
buffer *data_buf, mp_int * rsa_em) {
/* ASN1 designator (including the 0x00 preceding) */
const unsigned char rsa_asn1_magic[] =
@@ -391,7 +382,6 @@ static void rsa_pad_em(dropbear_rsa_key * key,
unsigned int nsize;
dropbear_assert(key != NULL);
dropbear_assert(data != NULL);
nsize = mp_unsigned_bin_size(key->n);
rsa_EM = buf_new(nsize-1);
@@ -408,7 +398,7 @@ static void rsa_pad_em(dropbear_rsa_key * key,
/* The hash of the data */
sha1_init(&hs);
sha1_process(&hs, data, len);
sha1_process(&hs, data_buf->data, data_buf->len);
sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE));
buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE);

6
rsa.h
View File

@@ -43,11 +43,9 @@ typedef struct {
} dropbear_rsa_key;
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len);
void buf_put_rsa_sign(buffer* buf, dropbear_rsa_key *key, buffer *data_buf);
#ifdef DROPBEAR_SIGNKEY_VERIFY
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, const unsigned char* data,
unsigned int len);
int buf_rsa_verify(buffer * buf, dropbear_rsa_key *key, buffer *data_buf);
#endif
int buf_get_rsa_pub_key(buffer* buf, dropbear_rsa_key *key);
int buf_get_rsa_priv_key(buffer* buf, dropbear_rsa_key *key);

View File

@@ -37,14 +37,18 @@ typedef struct runopts {
int listen_fwd_all;
#endif
unsigned int recv_window;
time_t keepalive_secs;
time_t idle_timeout_secs;
time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
#ifndef DISABLE_ZLIB
/* TODO: add a commandline flag. Currently this is on by default if compression
* is compiled in, but disabled for a client's non-final multihop stages. (The
* intermediate stages are compressed streams, so are uncompressible. */
int enable_compress;
enum {
DROPBEAR_COMPRESS_DELAYED, /* Server only */
DROPBEAR_COMPRESS_ON,
DROPBEAR_COMPRESS_OFF,
} compress_mode;
#endif
#ifdef ENABLE_USER_ALGO_LIST
@@ -56,12 +60,12 @@ typedef struct runopts {
extern runopts opts;
int readhostkey(const char * filename, sign_key * hostkey, int *type);
int readhostkey(const char * filename, sign_key * hostkey,
enum signkey_type *type);
void load_all_hostkeys();
typedef struct svr_runopts {
char * rsakeyfile;
char * dsskeyfile;
char * bannerfile;
int forkbg;
@@ -99,6 +103,12 @@ typedef struct svr_runopts {
#endif
sign_key *hostkey;
int delay_hostkey;
char *hostkey_files[MAX_HOSTKEYS];
int num_hostkey_files;
buffer * banner;
char * pidfile;
@@ -121,6 +131,7 @@ typedef struct cli_runopts {
char *cmd;
int wantpty;
int always_accept_key;
int no_hostkey_check;
int no_cmd;
int backgrounded;
int is_subsystem;
@@ -157,4 +168,6 @@ void cli_getopts(int argc, char ** argv);
void parse_ciphers_macs();
#endif
void print_version(void);
#endif /* _RUNOPTS_H_ */

8
scp.c
View File

@@ -230,7 +230,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc)
close(pin[0]);
close(pout[1]);
#ifdef USE_VFORK
#ifndef USE_VFORK
arg_setup(host, remuser, cmd);
#endif
@@ -494,8 +494,8 @@ toremote(char *targ, int argc, char **argv)
if (verbose_mode)
addargs(&alist, "-v");
#if 0
// Disabled since dbclient won't understand them
// and scp works fine without them.
/* Disabled since dbclient won't understand them
and scp works fine without them. */
addargs(&alist, "-x");
addargs(&alist, "-oClearAllForwardings yes");
addargs(&alist, "-n");
@@ -1146,7 +1146,7 @@ usage(void)
{
(void) fprintf(stderr,
"usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
" [-l limit] [-o ssh_option] [-P port] [-S program]\n"
" [-l limit] [-P port] [-S program]\n"
" [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
exit(1);
}

View File

@@ -40,6 +40,7 @@
/*RCSID("OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp ");*/
#define _GNU_SOURCE
#include "includes.h"
#include "scpmisc.h"

View File

@@ -26,7 +26,5 @@
#define _SERVICE_H_
void recv_msg_service_request(); /* Server */
void send_msg_service_request(); /* Client */
void recv_msg_service_accept(); /* Client */
#endif /* _SERVICE_H_ */

View File

@@ -44,9 +44,12 @@ extern int exitflag;
void common_session_init(int sock_in, int sock_out);
void session_loop(void(*loophandler)());
void common_session_cleanup();
void session_identification();
void session_cleanup();
void send_session_identification();
void send_msg_ignore();
void ignore_recv_response();
void update_channel_prio();
const char* get_user_shell();
void fill_passwd(const char* username);
@@ -58,7 +61,6 @@ void svr_dropbear_log(int priority, const char* format, va_list param);
/* Client */
void cli_session(int sock_in, int sock_out);
void cli_session_cleanup();
void cleantext(unsigned char* dirtytext);
/* crypto parameters that are stored individually for transmit and receive */
@@ -67,7 +69,7 @@ struct key_context_directional {
const struct dropbear_cipher_mode *crypt_mode;
const struct dropbear_hash *algo_mac;
int hash_index; /* lookup for libtomcrypt */
char algo_comp; /* compression */
int algo_comp; /* compression */
#ifndef DISABLE_ZLIB
z_streamp zstream;
#endif
@@ -79,6 +81,7 @@ struct key_context_directional {
#endif
} cipher_state;
unsigned char mackey[MAX_MAC_LEN];
int valid;
};
struct key_context {
@@ -86,8 +89,8 @@ struct key_context {
struct key_context_directional recv;
struct key_context_directional trans;
char algo_kex;
char algo_hostkey;
const struct dropbear_kex *algo_kex;
int algo_hostkey;
int allow_compress; /* whether compression has started (useful in
zlib@openssh.com delayed compression case) */
@@ -104,14 +107,13 @@ struct sshsession {
/* Is it a client or server? */
unsigned char isserver;
time_t connect_time; /* time the connection was established
(cleared after auth once we're not
respecting AUTH_TIMEOUT any more) */
int sock_in;
int sock_out;
unsigned char *remoteident;
/* remotehost will be initially NULL as we delay
* reading the remote version string. it will be set
* by the time any recv_() packet methods are called */
unsigned char *remoteident;
int maxfd; /* the maximum file descriptor to check with select() */
@@ -132,8 +134,8 @@ struct sshsession {
unsigned dataallowed : 1; /* whether we can send data packets or we are in
the middle of a KEX or something */
unsigned char requirenext; /* byte indicating what packet we require next,
or 0x00 for any */
unsigned char requirenext; /* byte indicating what packets we require next,
or 0x00 for any. */
unsigned char ignorenext; /* whether to ignore the next packet,
used for kex_follows stuff */
@@ -143,21 +145,24 @@ struct sshsession {
int signal_pipe[2]; /* stores endpoints of a self-pipe used for
race-free signal handling */
time_t last_trx_packet_time; /* time of the last packet transmission, for
keepalive purposes */
/* time of the last packet send/receive, for keepalive. Not real-world clock */
time_t last_packet_time_keepalive_sent;
time_t last_packet_time_keepalive_recv;
time_t last_packet_time_any_sent;
time_t last_packet_time; /* time of the last packet transmission or receive, for
idle timeout purposes */
time_t last_packet_time_idle; /* time of the last packet transmission or receive, for
idle timeout purposes so ignores SSH_MSG_IGNORE
or responses to keepalives. Not real-world clock */
/* KEX/encryption related */
struct KEXState kexstate;
struct key_context *keys;
struct key_context *newkeys;
unsigned char *session_id; /* this is the hash from the first kex */
/* The below are used temorarily during kex, are freed after use */
buffer *session_id; /* this is the hash from the first kex */
/* The below are used temporarily during kex, are freed after use */
mp_int * dh_K; /* SSH_MSG_KEXDH_REPLY and sending SSH_MSH_NEWKEYS */
unsigned char hash[SHA1_HASH_SIZE]; /* the hash*/
buffer *hash; /* the session hash */
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
buffer* transkexinit; /* the kexinit packet we send should be kept so we
can add it to the hash when generating keys */
@@ -169,15 +174,11 @@ struct sshsession {
concluded (ie, while dataallowed was unset)*/
struct packetlist *reply_queue_head, *reply_queue_tail;
algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
int *goodguess); /* The function to use to choose which algorithm
to use from the ones presented by the remote
side. Is specific to the client/server mode,
hence the function-pointer callback.*/
void(*remoteclosed)(); /* A callback to handle closure of the
remote connection */
void(*extra_session_cleanup)(); /* client or server specific cleanup */
void(*send_kex_first_guess)();
struct AuthState authstate; /* Common amongst client and server, since most
struct elements are common */
@@ -187,8 +188,11 @@ struct sshsession {
unsigned int chansize; /* the number of Channel*s allocated for channels */
unsigned int chancount; /* the number of Channel*s in use */
const struct ChanType **chantypes; /* The valid channel types */
int channel_signal_pending; /* Flag set by sigchld handler */
/* TCP priority level for the main "port 22" tcp socket */
enum dropbear_prio socket_prio;
/* TCP forwarding - where manage listeners */
struct Listener ** listeners;
unsigned int listensize;
@@ -218,6 +222,11 @@ struct serversession {
/* The resolved remote address, used for lastlog etc */
char *remotehost;
time_t connect_time; /* time the connection was established
(cleared after auth once we're not
respecting AUTH_TIMEOUT any more).
A monotonic time, not realworld */
#ifdef USE_VFORK
pid_t server_pid;
#endif
@@ -233,10 +242,7 @@ typedef enum {
typedef enum {
STATE_NOTHING,
SERVICE_AUTH_REQ_SENT,
SERVICE_AUTH_ACCEPT_RCVD,
SERVICE_CONN_REQ_SENT,
SERVICE_CONN_ACCEPT_RCVD,
USERAUTH_WAIT,
USERAUTH_REQ_SENT,
USERAUTH_FAIL_RCVD,
USERAUTH_SUCCESS_RCVD,
@@ -245,7 +251,12 @@ typedef enum {
struct clientsession {
mp_int *dh_e, *dh_x; /* Used during KEX */
/* XXX - move these to kexstate? */
struct kex_dh_param *dh_param;
struct kex_ecdh_param *ecdh_param;
struct kex_curve25519_param *curve25519_param;
const struct dropbear_kex *param_kex_algo; /* KEX algorithm corresponding to current dh_e and dh_x */
cli_kex_state kex_state; /* Used for progressing KEX */
cli_state state; /* Used to progress auth/channelsession etc */
unsigned donefirstkex : 1; /* Set when we set sentnewkeys, never reset */
@@ -259,10 +270,14 @@ struct clientsession {
int stderrcopy;
int stderrflags;
/* for escape char handling */
int last_char;
int winchange; /* Set to 1 when a windowchange signal happens */
int lastauthtype; /* either AUTH_TYPE_PUBKEY or AUTH_TYPE_PASSWORD,
for the last type of auth we tried */
int ignore_next_auth_response;
#ifdef ENABLE_CLI_INTERACT_AUTH
int auth_interact_failed; /* flag whether interactive auth can still
be used */

280
signkey.c
View File

@@ -27,6 +27,21 @@
#include "signkey.h"
#include "buffer.h"
#include "ssh.h"
#include "ecdsa.h"
static const char *signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
#ifdef DROPBEAR_RSA
"ssh-rsa",
#endif
#ifdef DROPBEAR_DSS
"ssh-dss",
#endif
#ifdef DROPBEAR_ECDSA
"ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521"
#endif /* DROPBEAR_ECDSA */
};
/* malloc a new sign_key and set the dss and rsa keys to NULL */
sign_key * new_sign_key() {
@@ -34,71 +49,101 @@ sign_key * new_sign_key() {
sign_key * ret;
ret = (sign_key*)m_malloc(sizeof(sign_key));
#ifdef DROPBEAR_DSS
ret->dsskey = NULL;
#endif
#ifdef DROPBEAR_RSA
ret->rsakey = NULL;
#endif
ret->filename = NULL;
ret->type = DROPBEAR_SIGNKEY_NONE;
ret->source = SIGNKEY_SOURCE_INVALID;
return ret;
}
/* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
/* Returns key name corresponding to the type. Exits fatally
* if the type is invalid */
const char* signkey_name_from_type(int type, int *namelen) {
const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen) {
if (type >= DROPBEAR_SIGNKEY_NUM_NAMED) {
dropbear_exit("Bad key type %d", type);
}
#ifdef DROPBEAR_RSA
if (type == DROPBEAR_SIGNKEY_RSA) {
*namelen = SSH_SIGNKEY_RSA_LEN;
return SSH_SIGNKEY_RSA;
if (namelen) {
*namelen = strlen(signkey_names[type]);
}
#endif
#ifdef DROPBEAR_DSS
if (type == DROPBEAR_SIGNKEY_DSS) {
*namelen = SSH_SIGNKEY_DSS_LEN;
return SSH_SIGNKEY_DSS;
}
#endif
dropbear_exit("Bad key type %d", type);
return NULL; /* notreached */
return signkey_names[type];
}
/* Returns DROPBEAR_SIGNKEY_RSA, DROPBEAR_SIGNKEY_DSS,
* or DROPBEAR_SIGNKEY_NONE */
int signkey_type_from_name(const char* name, int namelen) {
/* Returns DROPBEAR_SIGNKEY_NONE if none match */
enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) {
int i;
for (i = 0; i < DROPBEAR_SIGNKEY_NUM_NAMED; i++) {
const char *fixed_name = signkey_names[i];
if (namelen == strlen(fixed_name)
&& memcmp(fixed_name, name, namelen) == 0) {
#ifdef DROPBEAR_RSA
if (namelen == SSH_SIGNKEY_RSA_LEN
&& memcmp(name, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN) == 0) {
return DROPBEAR_SIGNKEY_RSA;
}
#ifdef DROPBEAR_ECDSA
/* Some of the ECDSA key sizes are defined even if they're not compiled in */
if (0
#ifndef DROPBEAR_ECC_256
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP256
#endif
#ifdef DROPBEAR_DSS
if (namelen == SSH_SIGNKEY_DSS_LEN
&& memcmp(name, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN) == 0) {
return DROPBEAR_SIGNKEY_DSS;
}
#ifndef DROPBEAR_ECC_384
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP384
#endif
#ifndef DROPBEAR_ECC_521
|| i == DROPBEAR_SIGNKEY_ECDSA_NISTP521
#endif
) {
TRACE(("attempt to use ecdsa type %d not compiled in", i))
return DROPBEAR_SIGNKEY_NONE;
}
#endif
return i;
}
}
TRACE(("signkey_type_from_name unexpected key type."))
return DROPBEAR_SIGNKEY_NONE;
}
/* Returns a pointer to the key part specific to "type" */
void **
signkey_key_ptr(sign_key *key, enum signkey_type type) {
switch (type) {
#ifdef DROPBEAR_ECDSA
#ifdef DROPBEAR_ECC_256
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
return (void**)&key->ecckey256;
#endif
#ifdef DROPBEAR_ECC_384
case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
return (void**)&key->ecckey384;
#endif
#ifdef DROPBEAR_ECC_521
case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
return (void**)&key->ecckey521;
#endif
#endif /* DROPBEAR_ECDSA */
#ifdef DROPBEAR_RSA
case DROPBEAR_SIGNKEY_RSA:
return (void**)&key->rsakey;
#endif
#ifdef DROPBEAR_DSS
case DROPBEAR_SIGNKEY_DSS:
return (void**)&key->dsskey;
#endif
default:
return NULL;
}
}
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
* type should be set by the caller to specify the type to read, and
* on return is set to the type read (useful when type = _ANY) */
int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
unsigned char* ident;
unsigned int len;
int keytype;
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_pub_key"))
TRACE2(("enter buf_get_pub_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
@@ -109,7 +154,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
return DROPBEAR_FAILURE;
}
TRACE(("buf_get_pub_key keytype is %d", keytype))
TRACE2(("buf_get_pub_key keytype is %d", keytype))
*type = keytype;
@@ -136,8 +181,23 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
}
}
#endif
#ifdef DROPBEAR_ECDSA
if (signkey_is_ecdsa(keytype)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck) {
if (*eck) {
ecc_free(*eck);
*eck = NULL;
}
*eck = buf_get_ecdsa_pub_key(buf);
if (*eck) {
ret = DROPBEAR_SUCCESS;
}
}
}
#endif
TRACE(("leave buf_get_pub_key"))
TRACE2(("leave buf_get_pub_key"))
return ret;
@@ -146,14 +206,14 @@ int buf_get_pub_key(buffer *buf, sign_key *key, int *type) {
/* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
* type should be set by the caller to specify the type to read, and
* on return is set to the type read (useful when type = _ANY) */
int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
unsigned char* ident;
unsigned int len;
int keytype;
int ret = DROPBEAR_FAILURE;
TRACE(("enter buf_get_priv_key"))
TRACE2(("enter buf_get_priv_key"))
ident = buf_getstring(buf, &len);
keytype = signkey_type_from_name(ident, len);
@@ -189,19 +249,34 @@ int buf_get_priv_key(buffer *buf, sign_key *key, int *type) {
}
}
#endif
#ifdef DROPBEAR_ECDSA
if (signkey_is_ecdsa(keytype)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck) {
if (*eck) {
ecc_free(*eck);
*eck = NULL;
}
*eck = buf_get_ecdsa_priv_key(buf);
if (*eck) {
ret = DROPBEAR_SUCCESS;
}
}
}
#endif
TRACE(("leave buf_get_priv_key"))
TRACE2(("leave buf_get_priv_key"))
return ret;
}
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
buffer *pubkeys;
TRACE(("enter buf_put_pub_key"))
TRACE2(("enter buf_put_pub_key"))
pubkeys = buf_new(MAX_PUBKEY_SIZE);
#ifdef DROPBEAR_DSS
@@ -213,21 +288,26 @@ void buf_put_pub_key(buffer* buf, sign_key *key, int type) {
if (type == DROPBEAR_SIGNKEY_RSA) {
buf_put_rsa_pub_key(pubkeys, key->rsakey);
}
#endif
#ifdef DROPBEAR_ECDSA
if (signkey_is_ecdsa(type)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
if (eck) {
buf_put_ecdsa_pub_key(pubkeys, *eck);
}
}
#endif
if (pubkeys->len == 0) {
dropbear_exit("Bad key types in buf_put_pub_key");
}
buf_setpos(pubkeys, 0);
buf_putstring(buf, buf_getptr(pubkeys, pubkeys->len),
pubkeys->len);
buf_putbufstring(buf, pubkeys);
buf_free(pubkeys);
TRACE(("leave buf_put_pub_key"))
TRACE2(("leave buf_put_pub_key"))
}
/* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) {
TRACE(("enter buf_put_priv_key"))
TRACE(("type is %d", type))
@@ -245,13 +325,23 @@ void buf_put_priv_key(buffer* buf, sign_key *key, int type) {
TRACE(("leave buf_put_priv_key: rsa done"))
return;
}
#endif
#ifdef DROPBEAR_ECDSA
if (signkey_is_ecdsa(type)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
if (eck) {
buf_put_ecdsa_priv_key(buf, *eck);
TRACE(("leave buf_put_priv_key: ecdsa done"))
return;
}
}
#endif
dropbear_exit("Bad key types in put pub key");
}
void sign_key_free(sign_key *key) {
TRACE(("enter sign_key_free"))
TRACE2(("enter sign_key_free"))
#ifdef DROPBEAR_DSS
dss_key_free(key->dsskey);
@@ -260,16 +350,35 @@ void sign_key_free(sign_key *key) {
#ifdef DROPBEAR_RSA
rsa_key_free(key->rsakey);
key->rsakey = NULL;
#endif
#ifdef DROPBEAR_ECDSA
#ifdef DROPBEAR_ECC_256
if (key->ecckey256) {
ecc_free(key->ecckey256);
key->ecckey256 = NULL;
}
#endif
#ifdef DROPBEAR_ECC_384
if (key->ecckey384) {
ecc_free(key->ecckey384);
key->ecckey384 = NULL;
}
#endif
#ifdef DROPBEAR_ECC_521
if (key->ecckey521) {
ecc_free(key->ecckey521);
key->ecckey521 = NULL;
}
#endif
#endif
m_free(key->filename);
m_free(key);
TRACE(("leave sign_key_free"))
TRACE2(("leave sign_key_free"))
}
static char hexdig(unsigned char x) {
if (x > 0xf)
return 'X';
@@ -333,14 +442,14 @@ static char * sign_key_sha1_fingerprint(unsigned char* keyblob,
sha1_done(&hs, hash);
/* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 5 + 3*SHA1_HASH_SIZE;
/* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
buflen = 7 + 3*SHA1_HASH_SIZE;
ret = (char*)m_malloc(buflen);
strcpy(ret, "sha1 ");
strcpy(ret, "sha1!! ");
for (i = 0; i < SHA1_HASH_SIZE; i++) {
unsigned int pos = 5 + 3*i;
unsigned int pos = 7 + 3*i;
ret[pos] = hexdig(hash[i] >> 4);
ret[pos+1] = hexdig(hash[i] & 0x0f);
ret[pos+2] = ':';
@@ -363,29 +472,33 @@ char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen) {
#endif
}
void buf_put_sign(buffer* buf, sign_key *key, int type,
const unsigned char *data, unsigned int len) {
void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
buffer *data_buf) {
buffer *sigblob;
sigblob = buf_new(MAX_PUBKEY_SIZE);
#ifdef DROPBEAR_DSS
if (type == DROPBEAR_SIGNKEY_DSS) {
buf_put_dss_sign(sigblob, key->dsskey, data, len);
buf_put_dss_sign(sigblob, key->dsskey, data_buf);
}
#endif
#ifdef DROPBEAR_RSA
if (type == DROPBEAR_SIGNKEY_RSA) {
buf_put_rsa_sign(sigblob, key->rsakey, data, len);
buf_put_rsa_sign(sigblob, key->rsakey, data_buf);
}
#endif
#ifdef DROPBEAR_ECDSA
if (signkey_is_ecdsa(type)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
if (eck) {
buf_put_ecdsa_sign(sigblob, *eck, data_buf);
}
}
#endif
if (sigblob->len == 0) {
dropbear_exit("Non-matching signing type");
}
buf_setpos(sigblob, 0);
buf_putstring(buf, buf_getptr(sigblob, sigblob->len),
sigblob->len);
buf_putbufstring(buf, sigblob);
buf_free(sigblob);
}
@@ -395,40 +508,45 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
* If FAILURE is returned, the position of
* buf is undefined. If SUCCESS is returned, buf will be positioned after the
* signature blob */
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
unsigned int len) {
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
unsigned int bloblen;
unsigned char * ident = NULL;
unsigned int identlen = 0;
unsigned char * type_name = NULL;
unsigned int type_name_len = 0;
enum signkey_type type;
TRACE(("enter buf_verify"))
bloblen = buf_getint(buf);
ident = buf_getstring(buf, &identlen);
buf_getint(buf); /* blob length */
type_name = buf_getstring(buf, &type_name_len);
type = signkey_type_from_name(type_name, type_name_len);
m_free(type_name);
#ifdef DROPBEAR_DSS
if (bloblen == DSS_SIGNATURE_SIZE &&
memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) {
m_free(ident);
if (type == DROPBEAR_SIGNKEY_DSS) {
if (key->dsskey == NULL) {
dropbear_exit("No DSS key to verify signature");
}
return buf_dss_verify(buf, key->dsskey, data, len);
return buf_dss_verify(buf, key->dsskey, data_buf);
}
#endif
#ifdef DROPBEAR_RSA
if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) {
m_free(ident);
if (type == DROPBEAR_SIGNKEY_RSA) {
if (key->rsakey == NULL) {
dropbear_exit("No RSA key to verify signature");
}
return buf_rsa_verify(buf, key->rsakey, data, len);
return buf_rsa_verify(buf, key->rsakey, data_buf);
}
#endif
#ifdef DROPBEAR_ECDSA
if (signkey_is_ecdsa(type)) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
if (eck) {
return buf_ecdsa_verify(buf, *eck, data_buf);
}
}
#endif
m_free(ident);
dropbear_exit("Non-matching signing type");
return DROPBEAR_FAILURE;
}

View File

@@ -29,6 +29,24 @@
#include "dss.h"
#include "rsa.h"
enum signkey_type {
#ifdef DROPBEAR_RSA
DROPBEAR_SIGNKEY_RSA,
#endif
#ifdef DROPBEAR_DSS
DROPBEAR_SIGNKEY_DSS,
#endif
#ifdef DROPBEAR_ECDSA
DROPBEAR_SIGNKEY_ECDSA_NISTP256,
DROPBEAR_SIGNKEY_ECDSA_NISTP384,
DROPBEAR_SIGNKEY_ECDSA_NISTP521,
#endif /* DROPBEAR_ECDSA */
DROPBEAR_SIGNKEY_NUM_NAMED,
DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */
DROPBEAR_SIGNKEY_ANY = 80,
DROPBEAR_SIGNKEY_NONE = 90,
};
/* Sources for signing keys */
typedef enum {
@@ -39,11 +57,9 @@ typedef enum {
struct SIGN_key {
int type; /* The type of key (dss or rsa) */
enum signkey_type type;
signkey_source source;
char *filename;
/* the buffer? for encrypted keys, so we can later get
* the private key portion */
#ifdef DROPBEAR_DSS
dropbear_dss_key * dsskey;
@@ -51,27 +67,38 @@ struct SIGN_key {
#ifdef DROPBEAR_RSA
dropbear_rsa_key * rsakey;
#endif
#ifdef DROPBEAR_ECDSA
#ifdef DROPBEAR_ECC_256
ecc_key * ecckey256;
#endif
#ifdef DROPBEAR_ECC_384
ecc_key * ecckey384;
#endif
#ifdef DROPBEAR_ECC_521
ecc_key * ecckey521;
#endif
#endif
};
typedef struct SIGN_key sign_key;
sign_key * new_sign_key();
const char* signkey_name_from_type(int type, int *namelen);
int signkey_type_from_name(const char* name, int namelen);
int buf_get_pub_key(buffer *buf, sign_key *key, int *type);
int buf_get_priv_key(buffer* buf, sign_key *key, int *type);
void buf_put_pub_key(buffer* buf, sign_key *key, int type);
void buf_put_priv_key(buffer* buf, sign_key *key, int type);
const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen);
enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen);
int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type);
int buf_get_priv_key(buffer* buf, sign_key *key, enum signkey_type *type);
void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type);
void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type);
void sign_key_free(sign_key *key);
void buf_put_sign(buffer* buf, sign_key *key, int type,
const unsigned char *data, unsigned int len);
void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type, buffer *data_buf);
#ifdef DROPBEAR_SIGNKEY_VERIFY
int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
unsigned int len);
int buf_verify(buffer * buf, sign_key *key, buffer *data_buf);
char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen);
#endif
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
const unsigned char* algoname, unsigned int algolen,
buffer * line, char ** fingerprint);
void** signkey_key_ptr(sign_key *key, enum signkey_type type);
#endif /* _SIGNKEY_H_ */

View File

@@ -37,7 +37,7 @@
#include "channel.h"
#include "packet.h"
#include "buffer.h"
#include "random.h"
#include "dbrandom.h"
#include "listener.h"
#include "auth.h"

View File

@@ -1,100 +0,0 @@
/*
* Dropbear - a SSH2 server
* SSH client implementation
*
* Copyright (c) 2002,2003 Matt Johnston
* Copyright (c) 2004 by Mihnea Stoenescu
* 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 "algo.h"
#include "dbutil.h"
/* match the first algorithm in the comma-separated list in buf which is
* also in localalgos[], or return NULL on failure.
* (*goodguess) is set to 1 if the preferred client/server algos match,
* 0 otherwise. This is used for checking if the kexalgo/hostkeyalgos are
* guessed correctly */
algo_type * svr_buf_match_algo(buffer* buf, algo_type localalgos[],
int *goodguess)
{
unsigned char * algolist = NULL;
unsigned char * remotealgos[MAX_PROPOSED_ALGO];
unsigned int len;
unsigned int count, i, j;
algo_type * ret = NULL;
*goodguess = 0;
/* get the comma-separated list from the buffer ie "algo1,algo2,algo3" */
algolist = buf_getstring(buf, &len);
/* Debug this */
TRACE(("buf_match_algo: %s", algolist))
if (len > MAX_PROPOSED_ALGO*(MAX_NAME_LEN+1)) {
goto out; /* just a sanity check, no other use */
}
/* remotealgos will contain a list of the strings parsed out */
/* We will have at least one string (even if it's just "") */
remotealgos[0] = algolist;
count = 1;
/* Iterate through, replacing ','s with NULs, to split it into
* words. */
for (i = 0; i < len; i++) {
if (algolist[i] == '\0') {
/* someone is trying something strange */
goto out;
}
if (algolist[i] == ',') {
algolist[i] = '\0';
remotealgos[count] = &algolist[i+1];
count++;
}
if (count >= MAX_PROPOSED_ALGO) {
break;
}
}
/* iterate and find the first match */
for (i = 0; i < count; i++) {
len = strlen(remotealgos[i]);
for (j = 0; localalgos[j].name != NULL; j++) {
if (localalgos[j].usable) {
if (len == strlen(localalgos[j].name) &&
strncmp(localalgos[j].name, remotealgos[i], len) == 0) {
/* set if it was a good guess */
if (i == 0 && j == 0) {
*goodguess = 1;
}
/* set the algo to return */
ret = &localalgos[j];
goto out;
}
}
}
}
out:
m_free(algolist);
return ret;
}

View File

@@ -33,11 +33,10 @@
#include "packet.h"
#include "auth.h"
#include "runopts.h"
#include "random.h"
#include "dbrandom.h"
static void authclear();
static int checkusername(unsigned char *username, unsigned int userlen);
static void send_msg_userauth_banner();
/* initialise the first time for a session, resetting all parameters */
void svr_authinitialise() {
@@ -82,24 +81,17 @@ static void authclear() {
/* Send a banner message if specified to the client. The client might
* ignore this, but possibly serves as a legal "no trespassing" sign */
static void send_msg_userauth_banner() {
void send_msg_userauth_banner(buffer *banner) {
TRACE(("enter send_msg_userauth_banner"))
if (svr_opts.banner == NULL) {
TRACE(("leave send_msg_userauth_banner: banner is NULL"))
return;
}
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER);
buf_putstring(ses.writepayload, buf_getptr(svr_opts.banner,
svr_opts.banner->len), svr_opts.banner->len);
buf_putbufstring(ses.writepayload, banner);
buf_putstring(ses.writepayload, "en", 2);
encrypt_packet();
buf_free(svr_opts.banner);
svr_opts.banner = NULL;
TRACE(("leave send_msg_userauth_banner"))
}
@@ -110,6 +102,7 @@ void recv_msg_userauth_request() {
unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
unsigned int userlen, servicelen, methodlen;
int valid_user = 0;
TRACE(("enter recv_msg_userauth_request"))
@@ -121,10 +114,11 @@ void recv_msg_userauth_request() {
/* send the banner if it exists, it will only exist once */
if (svr_opts.banner) {
send_msg_userauth_banner();
send_msg_userauth_banner(svr_opts.banner);
buf_free(svr_opts.banner);
svr_opts.banner = NULL;
}
username = buf_getstring(ses.payload, &userlen);
servicename = buf_getstring(ses.payload, &servicelen);
methodname = buf_getstring(ses.payload, &methodlen);
@@ -141,12 +135,12 @@ void recv_msg_userauth_request() {
dropbear_exit("unknown service in auth");
}
/* check username is good before continuing */
if (checkusername(username, userlen) == DROPBEAR_FAILURE) {
/* username is invalid/no shell/etc - send failure */
TRACE(("sending checkusername failure"))
send_msg_userauth_failure(0, 1);
goto out;
/* check username is good before continuing.
* the 'incrfail' varies depending on the auth method to
* avoid giving away which users exist on the system through
* the time delay. */
if (checkusername(username, userlen) == DROPBEAR_SUCCESS) {
valid_user = 1;
}
/* user wants to know what methods are supported */
@@ -154,7 +148,8 @@ void recv_msg_userauth_request() {
strncmp(methodname, AUTH_METHOD_NONE,
AUTH_METHOD_NONE_LEN) == 0) {
TRACE(("recv_msg_userauth_request: 'none' request"))
if (svr_opts.allowblankpass
if (valid_user
&& svr_opts.allowblankpass
&& !svr_opts.noauthpass
&& !(svr_opts.norootpass && ses.authstate.pw_uid == 0)
&& ses.authstate.pw_passwd[0] == '\0')
@@ -168,6 +163,7 @@ void recv_msg_userauth_request() {
}
else
{
/* 'none' has no failure delay */
send_msg_userauth_failure(0, 0);
goto out;
}
@@ -180,8 +176,10 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
svr_auth_password();
goto out;
if (valid_user) {
svr_auth_password();
goto out;
}
}
}
#endif
@@ -193,8 +191,10 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
strncmp(methodname, AUTH_METHOD_PASSWORD,
AUTH_METHOD_PASSWORD_LEN) == 0) {
svr_auth_pam();
goto out;
if (valid_user) {
svr_auth_pam();
goto out;
}
}
}
#endif
@@ -204,12 +204,17 @@ void recv_msg_userauth_request() {
if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
strncmp(methodname, AUTH_METHOD_PUBKEY,
AUTH_METHOD_PUBKEY_LEN) == 0) {
svr_auth_pubkey();
if (valid_user) {
svr_auth_pubkey();
} else {
/* pubkey has no failure delay */
send_msg_userauth_failure(0, 0);
}
goto out;
}
#endif
/* nothing matched, we just fail */
/* nothing matched, we just fail with a delay */
send_msg_userauth_failure(0, 1);
out:
@@ -226,6 +231,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
char* listshell = NULL;
char* usershell = NULL;
uid_t uid;
TRACE(("enter checkusername"))
if (userlen > MAX_USERNAME_LEN) {
return DROPBEAR_FAILURE;
@@ -251,7 +257,17 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
dropbear_log(LOG_WARNING,
"Login attempt for nonexistent user from %s",
svr_ses.addrstring);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
}
/* check if we are running as non-root, and login user is different from the server */
uid = geteuid();
if (uid != 0 && uid != ses.authstate.pw_uid) {
TRACE(("running as nonroot, only server uid is allowed"))
dropbear_log(LOG_WARNING,
"Login attempt with wrong user %s from %s",
ses.authstate.pw_name,
svr_ses.addrstring);
return DROPBEAR_FAILURE;
}
@@ -259,7 +275,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) {
TRACE(("leave checkusername: root login disabled"))
dropbear_log(LOG_WARNING, "root login rejected");
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
}
@@ -288,7 +303,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
TRACE(("no matching shell"))
dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
ses.authstate.pw_name);
send_msg_userauth_failure(0, 1);
return DROPBEAR_FAILURE;
goodshell:
@@ -298,7 +312,6 @@ goodshell:
TRACE(("uid = %d", ses.authstate.pw_uid))
TRACE(("leave checkusername"))
return DROPBEAR_SUCCESS;
}
/* Send a failure message to the client, in responds to a userauth_request.
@@ -330,12 +343,10 @@ void send_msg_userauth_failure(int partial, int incrfail) {
buf_putbytes(typebuf, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN);
}
buf_setpos(typebuf, 0);
buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len),
typebuf->len);
buf_putbufstring(ses.writepayload, typebuf);
TRACE(("auth fail: methods %d, '%s'", ses.authstate.authtypes,
buf_getptr(typebuf, typebuf->len)));
TRACE(("auth fail: methods %d, '%.*s'", ses.authstate.authtypes,
typebuf->len, typebuf->data))
buf_free(typebuf);
@@ -345,8 +356,8 @@ void send_msg_userauth_failure(int partial, int incrfail) {
if (incrfail) {
unsigned int delay;
genrandom((unsigned char*)&delay, sizeof(delay));
/* We delay for 300ms +- 50ms, 0.1ms granularity */
delay = 250000 + (delay % 1000)*100;
/* We delay for 300ms +- 50ms */
delay = 250000 + (delay % 100000);
usleep(delay);
ses.authstate.failcount++;
}
@@ -381,8 +392,7 @@ void send_msg_userauth_success() {
/* authdone must be set after encrypt_packet() for
* delayed-zlib mode */
ses.authstate.authdone = 1;
ses.connect_time = 0;
svr_ses.connect_time = 0;
if (ses.authstate.pw_uid == 0) {
ses.allowprivport = 1;

View File

@@ -142,6 +142,22 @@ pamConvFunc(int num_msg,
(*respp) = resp;
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
if (msg_len > 0) {
buffer * pam_err = buf_new(msg_len + 4);
buf_setpos(pam_err, 0);
buf_putbytes(pam_err, "\r\n", 2);
buf_putbytes(pam_err, (*msg)->msg, msg_len);
buf_putbytes(pam_err, "\r\n", 2);
buf_setpos(pam_err, 0);
send_msg_userauth_banner(pam_err);
buf_free(pam_err);
}
break;
default:
TRACE(("Unknown message type"))
rc = PAM_CONV_ERR;
@@ -196,14 +212,14 @@ void svr_auth_pam() {
/* Init pam */
if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n",
dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s",
rc, pam_strerror(pamHandlep, rc));
goto cleanup;
}
/* just to set it to something */
if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) {
dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n",
dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s",
rc, pam_strerror(pamHandlep, rc));
goto cleanup;
}
@@ -216,7 +232,7 @@ void svr_auth_pam() {
/* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */
if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n",
dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s",
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"Bad PAM password attempt for '%s' from %s",
@@ -227,7 +243,7 @@ void svr_auth_pam() {
}
if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) {
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n",
dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s",
rc, pam_strerror(pamHandlep, rc));
dropbear_log(LOG_WARNING,
"Bad PAM password attempt for '%s' from %s",

View File

@@ -33,6 +33,17 @@
#ifdef ENABLE_SVR_PASSWORD_AUTH
static int constant_time_strcmp(const char* a, const char* b) {
size_t la = strlen(a);
size_t lb = strlen(b);
if (la != lb) {
return 1;
}
return constant_time_memcmp(a, b, la);
}
/* Process a password auth request, sending success or failure messages as
* appropriate */
void svr_auth_password() {
@@ -66,6 +77,14 @@ void svr_auth_password() {
m_burn(password, passwordlen);
m_free(password);
if (testcrypt == NULL) {
/* crypt() with an invalid salt like "!!" */
dropbear_log(LOG_WARNING, "User account '%s' is locked",
ses.authstate.pw_name);
send_msg_userauth_failure(0, 1);
return;
}
/* check for empty password */
if (passwdcrypt[0] == '\0') {
dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected",
@@ -74,7 +93,7 @@ void svr_auth_password() {
return;
}
if (strcmp(testcrypt, passwdcrypt) == 0) {
if (constant_time_strcmp(testcrypt, passwdcrypt) == 0) {
/* successful authentication */
dropbear_log(LOG_NOTICE,
"Password auth succeeded for '%s' from %s",

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