Compare commits

..

1 Commits

Author SHA1 Message Date
Matt Johnston
8deab76383 Import Maemo changes from 0.52-2
Taken from source tarball
http://maemo.org/packages/source/view/fremantle_extras-devel_free_source/dropbear/0.52-2/
2022-09-23 18:35:08 +08:00
137 changed files with 3659 additions and 8589 deletions

11
.hgsigs
View File

@@ -1,11 +0,0 @@
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

44
.hgtags
View File

@@ -1,44 +0,0 @@
03f65e461915a940939e4cc689fc89721ffc40de DROPBEAR_0.48.1
0f967bfef5cd0056b7ec60e2305d917e51cbf30d DROPBEAR_0.44
170329dc8ce5dfcf6298e1ad6699f109bf78e73d DROPBEAR_0.51
1dbd2473482f320ea59f76ce961385cb3a0150a9 DROPBEAR_0.46
2098857ab826dd42ae05a9a22c3ce2cc835b9844 DROPBEAR_0.45
36160290a1b27451178be36752ed038840f59cdd LTC_DB_0.46
39d5d58461d6e93337636e69d4cdf184a09c8d24 LTC_1.05
55a99934db873be2e63b5968fb6532e5d9bd02e4 DROPBEAR_0.48
59400faa4b44708c5d0b595e81193bc621e752d3 libtomcrypt-1.05
66087d87c3555c78b47cf01f32bb5a32054c3ceb DROPBEAR_0.44test4
677843bfa734238a67636b461a02c110c462ffaf DROPBEAR_0.44test1
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
8220862baae829ebc762587b99c662480d57bb23 DROPBEAR_0.53
86e0b50a9b588239c3fc9cc9cfe255ef586df17b ltm-0.30-orig
88e0a1ad951add46b795511dc2698e36b4aee922 DROPBEAR_0.44test3
8e94663164c6e106ccc5c9e997dedf6e04d77dd2 LTM_DB_0.44
91fbc376f01084037cd5f6a5bf2e2db4903e8e99 libtommath-0.35
97db060d0ef5f8cf8e67eb602ef037055a185ca9 libtommath-0.40
aa2f51a6b81d33de5e9898a7f27c792a173d9b26 DROPBEAR_0.53.1
ab370c629d363f8c9a3eca512bfa86e362034654 DROPBEAR_0.49
c2ac796b130eeb6fa840873d8c230544c8ec7e4b DROPBEAR_0.44test2
cd1143579f00b0248c79f63ca70efee4a35a57e8 LTC_DB_0.44
ce104c8b0be1ff3f2c2590b7cdc3fd6870c865cd DROPBEAR_0.52
d5faf4814ddbc5abd9e209409bb9e7a4686c8cd7 libtomcrypt-1.16
d7da3b1e15401eb234ec866d5eac992fc4cd5878 t:ltc-0.95-db-merge1
d8254fc979e99560c93ca2cece77a6df31927ea5 LTM_0.35
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.46
e109027b9edfb02f0bdf96ec45bb1cd9ad41e7da LTM_DB_0.47
e37b160c414cab6466622f63b0c4dcbf6ebc47a9 DROPBEAR_0.47
e430a26064ee86ab79aef372118d6d03b2441996 DROPBEAR_0.50
e5d119ea4c63656bc54ecfd865d04591ac2ed225 LTC_DB_0.47
3f12086c2ef2b9ffe36a822fdb3ff647fcec1831 DROPBEAR_2011.54
d354464b2aa6f6ba0bf44d43bcae5aa798435393 DROPBEAR_2012.55
7faae8f46238e23975430876547b8950b4e75481 t:ltc-0.95-orig
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

322
CHANGES
View File

@@ -1,313 +1,3 @@
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 Caralin 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
- Allow using 'none' cipher or MAC (off by default, use options.h). Encryption
is used during authentication then disabled, similar to OpenSSH HPN mode
- Allow a user in immediately if the account has a blank password and blank
passwords are enabled
- Include a few extra sources of entropy from /proc on Linux, hash private keys
as well. Dropbear will also write gathered entropy back into /dev/urandom
- Added hmac-sha2-256 and hmac-sha2-512 support (off by default, use options.h)
- Don't sent bad address "localhost" for -R forward connections,
reported by Denis Bider
- Add "-B" runtime option to allow blank passwords
- Allow using IPv6 bracket notation for addresses in server "-p" option, from Ben Jencks
- 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.
- Fix "make clean" for out of tree builds
- Fix compilation when ENABLE_{SVR,CLI}_AGENTFWD are unset
2012.55 - Wednesday 22 February 2012
- Security: Fix use-after-free bug that could be triggered if command="..."
authorized_keys restrictions are used. Could allow arbitrary code execution
or bypass of the command="..." restriction to an authenticated user.
This bug affects releases 0.52 onwards. Ref CVE-2012-0920.
Thanks to Danny Fullerton of Mantor Organization for reporting
the bug.
- Compile fix, only apply IPV6 socket options if they are available in headers
Thanks to Gustavo Zacarias for the patch
- Overwrite session key memory on exit
- Fix minor memory leak in unusual PAM authentication configurations.
Thanks to Stathis Voukelatos
- Other small code cleanups
2011.54 - Tuesday 8 November 2011
- Building statically works again, broke in 0.53 and 0.53.1
- Fix crash when forwarding with -R
- Fixed various leaks found by Klocwork analysis software, thanks to them for
running it
- Set IPTOS_LOWDELAY for IPv6, thanks to Dave Taht
- Bind to sockets with IPV6_V6ONLY so that it works properly on systems
regardless of the system-wide setting
- Added ALLOW_BLANK_PASSWORD option. Dropbear also now allows public key logins
to accounts with a blank password. Thanks to Rob Landley
- Fixed case where "-K 1" keepalive for dbclient would cause a SSH_MSG_IGNORE
packet to be sent
- Avoid some memory allocations in big number maths routines, improves
performance slightly
- Fix symlink target for installdropbearmulti with DESTDIR set, thanks to
Scottie Shore
- When requesting server allocated remote ports (-R 0:host:port) print a
message informing what the port is, thanks to Ali Onur Uyar.
- New version numbering scheme.
Source repository has now migrated to Mercurial at
https://secure.ucc.asn.au/hg/dropbear/graph/default
0.53.1 - Wednesday 2 March 2011
- -lcrypt needs to be before object files for static linking
- Compile fix when both client and agent forwarding are disabled
- Fix DROPBEAR_PRNGD_SOCKET mode
- Don't allow setting zlib memLevel since it seems buggy
0.53 - Thurs 24 February 2011
- Various performance/memory use improvements
- Client agent forwarding now works, using OpenSSH's ssh-agent
- Improve robustness of client multihop mode
- Fix a prime generation bug in bundled libtommath. This is unlikely to have
generated any bad keys in the wild.
See
https://bugzilla.redhat.com/show_bug.cgi?id=615088
http://bugs.gentoo.org/show_bug.cgi?id=328383
http://bugs.gentoo.org/show_bug.cgi?id=328409
- Attempt to build against system libtomcrypt/libtommath if available. This
can be disabled with ./configure --enable-bundled-libtom
- Make -K (keepalive) and -I (idle timeout) work together sensibly in the client.
The idle timeout is no longer reset by SSH_MSG_IGNORE packets.
- Add diffie-hellman-group14-sha1 key exchange method
- Compile fix if ENABLE_CLI_PROXYCMD is disabled
- /usr/bin/X11/xauth is now the default path
- Client remote forward (-L/-R) arguments now accept a listen address
- In uClinux avoid trashing the parent process when a session exits
- Blowfish is now disabled by default since it has large memory usage
- Add option to change zlib windowbits/memlevel. Use less memory by default
- DROPBEAR_SMALL_CODE is now disabled by default
- SSH_ORIGINAL_COMMAND environment variable is set by the server when an
authorized_keys command is specified.
- Set SSH_TTY and SSH_CONNECTION environment variables in the server
- Client banner is now printed to standard error rather than standard output
- Capitalisation in many log messages has been made consistent. This may affect
scripts that parse logfiles.
0.52 - Wed 12 November 2008
- Add "netcat-alike" option (-B) to dbclient, allowing Dropbear to tunnel
@@ -404,7 +94,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. CVE-2007-1099
exit upon a mismatch.
- Compile fixes, make sure that all variable definitions are at the start
of a scope.
@@ -466,7 +156,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) CVE-2006-1206
(after some poking from Pablo Fernandez)
- Exit gracefully if trying to connect to as SSH v1 server
(reported by Rushi Lala)
@@ -487,7 +177,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). CVE-2005-4178
Dropbear webpage).
- Fix channel handling code so that redirecting to /dev/null doesn't use
100% CPU.
@@ -694,7 +384,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. CVE-2004-2486
upgrade.
- Clean up agent forwarding socket files correctly, patch from Gerrit Pape.
@@ -818,7 +508,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
@@ -937,7 +627,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-2013 Matt Johnston
Copyright (c) 2002-2008 Matt Johnston
Portions copyright (c) 2004 Mihnea Stoenescu
All rights reserved.
@@ -87,55 +87,3 @@ 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,3 +20,7 @@ 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,54 +13,43 @@ ifndef PROGRAMS
PROGRAMS=dropbear dbclient dropbearkey dropbearconvert
endif
STATIC_LTC=libtomcrypt/libtomcrypt.a
STATIC_LTM=libtommath/libtommath.a
LIBTOM_LIBS=@LIBTOM_LIBS@
ifeq (@BUNDLED_LIBTOM@, 1)
LIBTOM_DEPS=$(STATIC_LTC) $(STATIC_LTM)
CFLAGS+=-I$(srcdir)/libtomcrypt/src/headers/
LIBTOM_LIBS=$(STATIC_LTC) $(STATIC_LTM)
endif
LTC=libtomcrypt/libtomcrypt.a
LTM=libtommath/libtommath.a
COMMONOBJS=dbutil.o buffer.o \
dss.o bignum.o \
signkey.o rsa.o dbrandom.o \
signkey.o rsa.o random.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
gensignkey.o gendss.o genrsa.o
atomicio.o compat.o fake-rfc2553.o
SVROBJS=svr-kex.o svr-auth.o sshpty.o \
SVROBJS=svr-kex.o svr-algo.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
svr-tcpfwd.o svr-authpam.o @CRYPTLIB@
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
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 \
cli-authpubkey.o cli-tcpfwd.o cli-channel.o cli-authinteract.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 curve25519-donna.o
common-runopts.o circbuffer.o
KEYOBJS=dropbearkey.o
KEYOBJS=dropbearkey.o gendss.o genrsa.o
CONVERTOBJS=dropbearconvert.o keyimport.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.o compat.o
SCPOBJS=scp.o progressmeter.o atomicio.o scpmisc.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 dbrandom.h service.h auth.h \
dss.h bignum.h signkey.h rsa.h random.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 ecc.h ecdsa.h
listener.h fake-rfc2553.h
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
dropbearkeyobjs=$(COMMONOBJS) $(KEYOBJS)
dropbearconvertobjs=$(COMMONOBJS) $(CONVERTOBJS)
@@ -70,11 +59,9 @@ VPATH=@srcdir@
srcdir=@srcdir@
prefix=@prefix@
exec_prefix=@exec_prefix@
datarootdir = @datarootdir@
bindir=@bindir@
sbindir=@sbindir@
mandir=@mandir@
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
sbindir=${exec_prefix}/sbin
CC=@CC@
AR=@AR@
@@ -82,8 +69,8 @@ RANLIB=@RANLIB@
STRIP=@STRIP@
INSTALL=@INSTALL@
CPPFLAGS=@CPPFLAGS@
CFLAGS+=-I. -I$(srcdir) $(CPPFLAGS) @CFLAGS@
LIBS+=@LIBS@
CFLAGS=-I. -I$(srcdir) -I$(srcdir)/libtomcrypt/src/headers/ $(CPPFLAGS) @CFLAGS@
LIBS=$(LTC) $(LTM) @LIBS@
LDFLAGS=@LDFLAGS@
EXEEXT=@EXEEXT@
@@ -119,6 +106,10 @@ ifeq ($(SCPPROGRESS), 1)
CFLAGS+=-DPROGRESS_METER
endif
#%: $(HEADERS)
#%: $(HEADERS) Makefile
# TODO
all: $(TARGETS)
strip: $(TARGETS)
@@ -126,34 +117,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 $(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 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(sbindir)/dropbear$(EXEEXT)
insmulti%: dropbearmulti
$(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
-ln -s $(DESTDIR)$(bindir)/dropbearmulti$(EXEEXT) $(DESTDIR)$(bindir)/$*$(EXEEXT)
# dropbear should go in sbin, so it needs a seperate rule
inst_dropbear: dropbear
$(INSTALL) -d $(DESTDIR)$(sbindir)
$(INSTALL) dropbear$(EXEEXT) $(DESTDIR)$(sbindir)
$(INSTALL) -d $(DESTDIR)$(mandir)/man8
$(INSTALL) -m 644 dropbear.8 $(DESTDIR)$(mandir)/man8/dropbear.8
$(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)
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))
$(INSTALL) -d -m 755 $(DESTDIR)$(bindir)
$(INSTALL) -m 755 $*$(EXEEXT) $(DESTDIR)$(bindir)
-chown root $(DESTDIR)$(bindir)/$*$(EXEEXT)
-chgrp 0 $(DESTDIR)$(bindir)/$*$(EXEEXT)
# for some reason the rule further down doesn't like $($@objs) as a prereq.
@@ -162,14 +153,9 @@ dbclient: $(dbclientobjs)
dropbearkey: $(dropbearkeyobjs)
dropbearconvert: $(dropbearconvertobjs)
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)
dropbear dbclient dropbearkey dropbearconvert: $(HEADERS) $(LTC) $(LTM) \
Makefile
$(CC) $(LDFLAGS) -o $@$(EXEEXT) $($@objs) $(LIBS)
# scp doesn't use the libs so is special.
scp: $(SCPOBJS) $(HEADERS) Makefile
@@ -183,10 +169,10 @@ ifeq ($(MULTI),1)
CFLAGS+=$(addprefix -DDBMULTI_, $(PROGRAMS)) -DDROPBEAR_MULTI
endif
dropbearmulti$(EXEEXT): $(HEADERS) $(MULTIOBJS) $(LIBTOM_DEPS) Makefile
$(CC) $(LDFLAGS) -o $@ $(MULTIOBJS) $(LIBTOM_LIBS) $(LIBS) @CRYPTLIB@
dropbearmulti: multilink
multibinary: dropbearmulti$(EXEEXT)
multibinary: $(HEADERS) $(MULTIOBJS) $(LTC) $(LTM) Makefile
$(CC) $(LDFLAGS) -o dropbearmulti$(EXEEXT) $(MULTIOBJS) $(LIBS)
multilink: multibinary $(addprefix link, $(PROGRAMS))
@@ -194,10 +180,10 @@ link%:
-rm -f $*$(EXEEXT)
-ln -s dropbearmulti$(EXEEXT) $*$(EXEEXT)
$(STATIC_LTC): options.h
cd libtomcrypt && $(MAKE)
$(LTC): options.h
cd libtomcrypt && $(MAKE) clean && $(MAKE)
$(STATIC_LTM): options.h
$(LTM): options.h
cd libtommath && $(MAKE)
.PHONY : clean sizes thisclean distclean tidy ltc-clean ltm-clean

16
README
View File

@@ -1,5 +1,4 @@
This is Dropbear, a smallish SSH server and client.
https://matt.ucc.asn.au/dropbear/dropbear.html
This is Dropbear, a smallish SSH 2 server and client.
INSTALL has compilation instructions.
@@ -28,7 +27,8 @@ ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwVa6M6cGVmUcLl2cFzkxEoJd06Ub4bVDsYrWvXhvUV+Z
You must make sure that ~/.ssh, and the key file, are only writable by the
user. Beware of editors that split the key into multiple lines.
Dropbear supports some options for authorized_keys entries, see the manpage.
NOTE: Dropbear ignores authorized_keys options such as those described in the
OpenSSH sshd manpage, and will not allow a login for these keys.
============================================================================
@@ -42,7 +42,8 @@ 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>
Dropbear does not support encrypted hostkeys though can connect to ssh-agent.
Currently encrypted keys aren't supported, neither is agent forwarding. At some
stage both hopefully will be.
============================================================================
@@ -51,18 +52,13 @@ dropbearkey's '-y' option.
============================================================================
To run the server, you need to server keys, this is one-off:
To run the server, you need to generate server keys, this is one-off:
./dropbearkey -t rsa -f dropbear_rsa_host_key
./dropbearkey -t dss -f dropbear_dss_host_key
./dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
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

@@ -23,41 +23,21 @@
* SOFTWARE. */
#ifndef _AGENTFWD_H_
#define _AGENTFWD_H_
#ifndef DISABLE_AGENTFWD
#include "includes.h"
#include "chansession.h"
#include "channel.h"
#include "auth.h"
#include "list.h"
#ifdef ENABLE_CLI_AGENTFWD
/* An agent reply can be reasonably large, as it can
* contain a list of all public keys held by the agent.
* 10000 is arbitrary */
#define MAX_AGENT_REPLY 10000
/* client functions */
void cli_load_agent_keys(m_list * ret_list);
void agent_buf_sign(buffer *sigblob, sign_key *key,
buffer *data_buf);
void cli_setup_agent(struct Channel *channel);
int agentreq(struct ChanSess * chansess);
void agentsetauth(struct ChanSess *chansess);
void agentcleanup(struct ChanSess * chansess);
void agentset(struct ChanSess *chansess);
#ifdef __hpux
#define seteuid(a) setresuid(-1, (a), -1)
#define setegid(a) setresgid(-1, (a), -1)
#endif
extern const struct ChanType cli_chan_agent;
#endif /* ENABLE_CLI_AGENTFWD */
#ifdef ENABLE_SVR_AGENTFWD
int svr_agentreq(struct ChanSess * chansess);
void svr_agentcleanup(struct ChanSess * chansess);
void svr_agentset(struct ChanSess *chansess);
#endif /* ENABLE_SVR_AGENTFWD */
#endif /* DROPBEAR_AGENTFWD */
#endif /* _AGENTFWD_H_ */

70
algo.h
View File

@@ -35,7 +35,7 @@
struct Algo_Type {
const unsigned char *name; /* identifying name */
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 */
@@ -50,8 +50,7 @@ extern algo_type sshkex[];
extern algo_type sshhostkey[];
extern algo_type sshciphers[];
extern algo_type sshhashes[];
extern algo_type ssh_compress[];
extern algo_type ssh_nocompress[];
extern algo_type sshcompress[];
extern const struct dropbear_cipher dropbear_nocipher;
extern const struct dropbear_cipher_mode dropbear_mode_none;
@@ -59,8 +58,8 @@ extern const struct dropbear_hash dropbear_nohash;
struct dropbear_cipher {
const struct ltc_cipher_descriptor *cipherdesc;
const unsigned long keysize;
const unsigned char blocksize;
unsigned long keysize;
unsigned char blocksize;
};
struct dropbear_cipher_mode {
@@ -74,63 +73,18 @@ struct dropbear_cipher_mode {
};
struct dropbear_hash {
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;
const struct ltc_hash_descriptor *hashdesc;
unsigned long keysize;
unsigned char hashsize;
};
void crypto_init();
int have_algo(char* algo, size_t algolen, algo_type algos[]);
void buf_put_algolist(buffer * buf, algo_type localalgos[]);
enum kexguess2_used {
KEXGUESS2_LOOK,
KEXGUESS2_NO,
KEXGUESS2_YES,
};
#define KEXGUESS2_ALGO_NAME "kexguess2@matt.ucc.asn.au"
#define KEXGUESS2_ALGO_ID 99
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,
const char *algo_desc);
char * algolist_string(algo_type algos[]);
#endif
enum {
DROPBEAR_COMP_NONE,
DROPBEAR_COMP_ZLIB,
DROPBEAR_COMP_ZLIB_DELAY,
};
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);
#endif /* _ALGO_H_ */

20
auth.h
View File

@@ -26,7 +26,6 @@
#define _AUTH_H_
#include "includes.h"
#include "signkey.h"
#include "chansession.h"
void svr_authinitialise();
@@ -36,7 +35,6 @@ 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();
@@ -68,14 +66,13 @@ void recv_msg_userauth_pk_ok();
void recv_msg_userauth_info_request();
void cli_get_user();
void cli_auth_getmethods();
int cli_auth_try();
void cli_auth_try();
void recv_msg_userauth_banner();
void cli_pubkeyfail();
void cli_auth_password();
int cli_auth_pubkey();
void cli_auth_interactive();
char* getpass_or_cancel(char* prompt);
void cli_auth_pubkey_cleanup();
#define MAX_USERNAME_LEN 25 /* arbitrary for the moment */
@@ -100,6 +97,7 @@ void cli_auth_pubkey_cleanup();
* relatively little extraneous bits when used for the client rather than the
* server */
struct AuthState {
char *username; /* This is the username the client presents to check. It
is updated each run through, used for auth checking */
unsigned char authtypes; /* Flags indicating which auth types are still
@@ -122,6 +120,19 @@ struct AuthState {
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
struct PubKeyOptions* pubkey_options;
#endif
};
struct SignKeyList;
/* A singly linked list of signing keys */
struct SignKeyList {
sign_key *key;
int type; /* The type of key */
struct SignKeyList *next;
/* filename? or the buffer? for encrypted keys, so we can later get
* the private key portion */
};
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
@@ -134,6 +145,7 @@ struct PubKeyOptions {
int no_pty_flag;
/* "command=" option. */
unsigned char * forced_command;
};
#endif

View File

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

View File

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

View File

@@ -106,7 +106,7 @@ buffer* buf_newcopy(buffer* buf) {
/* Set the length of the buffer */
void buf_setlen(buffer* buf, unsigned int len) {
if (len > buf->size) {
dropbear_exit("Bad buf_setlen");
dropbear_exit("bad buf_setlen");
}
buf->len = len;
}
@@ -114,7 +114,7 @@ void buf_setlen(buffer* buf, unsigned int len) {
/* Increment the length of the buffer */
void buf_incrlen(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->len + incr > buf->size) {
dropbear_exit("Bad buf_incrlen");
dropbear_exit("bad buf_incrlen");
}
buf->len += incr;
}
@@ -122,7 +122,7 @@ void buf_incrlen(buffer* buf, unsigned int incr) {
void buf_setpos(buffer* buf, unsigned int pos) {
if (pos > buf->len) {
dropbear_exit("Bad buf_setpos");
dropbear_exit("bad buf_setpos");
}
buf->pos = pos;
}
@@ -130,7 +130,7 @@ void buf_setpos(buffer* buf, unsigned int pos) {
/* increment the postion by incr, increasing the buffer length if required */
void buf_incrwritepos(buffer* buf, unsigned int incr) {
if (incr > BUF_MAX_INCR || buf->pos + incr > buf->size) {
dropbear_exit("Bad buf_incrwritepos");
dropbear_exit("bad buf_incrwritepos");
}
buf->pos += incr;
if (buf->pos > buf->len) {
@@ -144,7 +144,7 @@ void buf_incrpos(buffer* buf, int incr) {
if (incr > BUF_MAX_INCR ||
(unsigned int)((int)buf->pos + incr) > buf->len
|| ((int)buf->pos + incr) < 0) {
dropbear_exit("Bad buf_incrpos");
dropbear_exit("bad buf_incrpos");
}
buf->pos += incr;
}
@@ -155,7 +155,7 @@ unsigned char buf_getbyte(buffer* buf) {
/* This check is really just ==, but the >= allows us to check for the
* bad case of pos > len, which should _never_ happen. */
if (buf->pos >= buf->len) {
dropbear_exit("Bad buf_getbyte");
dropbear_exit("bad buf_getbyte");
}
return buf->data[buf->pos++];
}
@@ -185,7 +185,7 @@ void buf_putbyte(buffer* buf, unsigned char val) {
unsigned char* buf_getptr(buffer* buf, unsigned int len) {
if (buf->pos + len > buf->len) {
dropbear_exit("Bad buf_getptr");
dropbear_exit("bad buf_getptr");
}
return &buf->data[buf->pos];
}
@@ -195,7 +195,7 @@ unsigned char* buf_getptr(buffer* buf, unsigned int len) {
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) {
if (buf->pos + len > buf->size) {
dropbear_exit("Bad buf_getwriteptr");
dropbear_exit("bad buf_getwriteptr");
}
return &buf->data[buf->pos];
}
@@ -209,7 +209,7 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
unsigned char* ret;
len = buf_getint(buf);
if (len > MAX_STRING_LEN) {
dropbear_exit("String too long");
dropbear_exit("string too long");
}
if (retlen != NULL) {
@@ -223,20 +223,6 @@ unsigned char* buf_getstring(buffer* buf, unsigned int *retlen) {
return ret;
}
/* Return a string as a newly allocated buffer */
buffer * buf_getstringbuf(buffer *buf) {
buffer *ret;
unsigned char* str;
unsigned int len;
str = buf_getstring(buf, &len);
ret = m_malloc(sizeof(*ret));
ret->data = str;
ret->len = len;
ret->size = len;
ret->pos = 0;
return ret;
}
/* Just increment the buffer position the same as if we'd used buf_getstring,
* but don't bother copying/malloc()ing for it */
void buf_eatstring(buffer *buf) {
@@ -269,11 +255,6 @@ 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) {
@@ -287,7 +268,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;
TRACE2(("enter buf_putmpint"))
TRACE(("enter buf_putmpint"))
dropbear_assert(mp != NULL);
@@ -323,7 +304,7 @@ void buf_putmpint(buffer* buf, mp_int * mp) {
buf_incrwritepos(buf, len-pad);
}
TRACE2(("leave buf_putmpint"))
TRACE(("leave buf_putmpint"))
}
/* Retrieve an mp_int from the buffer.

View File

@@ -55,11 +55,9 @@ void buf_putbyte(buffer* buf, unsigned char val);
unsigned char* buf_getptr(buffer* buf, unsigned int len);
unsigned char* buf_getwriteptr(buffer* buf, unsigned int len);
unsigned char* buf_getstring(buffer* buf, unsigned int *retlen);
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

@@ -58,11 +58,10 @@ struct Channel {
unsigned int recvmaxpacket, transmaxpacket;
void* typedata; /* a pointer to type specific data */
int writefd; /* read from wire, written to insecure side */
int readfd; /* read from insecure side, written to wire */
int readfd; /* read from insecure size, written to wire */
int errfd; /* used like writefd or readfd, depending if it's client or server.
Doesn't exactly belong here, but is cleaner here */
circbuffer *writebuf; /* data from the wire, for local consumption. Can be
initially NULL */
circbuffer *writebuf; /* data from the wire, for local consumption */
circbuffer *extrabuf; /* extended-data for the program - used like writebuf
but for stderr */
@@ -70,10 +69,6 @@ struct Channel {
int sent_close, recv_close;
int recv_eof, sent_eof;
/* Set after running the ChanType-specific close hander
* to ensure we don't run it twice (nor type->checkclose()). */
int close_handler_done;
int initconn; /* used for TCP forwarding, whether the channel has been
fully initialised */
@@ -83,10 +78,8 @@ 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;
};
struct ChanType {
@@ -105,6 +98,9 @@ void chancleanup();
void setchannelfds(fd_set *readfd, fd_set *writefd);
void channelio(fd_set *readfd, fd_set *writefd);
struct Channel* getchannel();
struct Channel* newchannel(unsigned int remotechan,
const struct ChanType *type,
unsigned int transwindow, unsigned int transmaxpacket);
void recv_msg_channel_open();
void recv_msg_channel_request();

View File

@@ -50,10 +50,6 @@ struct ChanSess {
/* exit details */
struct exitinfo exit;
/* Used to set $SSH_CONNECTION in the child session.
Is only set temporarily before forking */
char *connection_string;
#ifndef DISABLE_X11FWD
struct Listener * x11listener;
@@ -64,15 +60,11 @@ struct ChanSess {
unsigned char x11singleconn;
#endif
#ifdef ENABLE_SVR_AGENTFWD
#ifndef DISABLE_AGENTFWD
struct Listener * agentlistener;
char * agentfile;
char * agentdir;
#endif
#ifdef ENABLE_SVR_PUBKEY_OPTIONS
char *original_command;
#endif
};
struct ChildPid {
@@ -89,7 +81,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

@@ -33,13 +33,11 @@ circbuffer * cbuf_new(unsigned int size) {
circbuffer *cbuf = NULL;
if (size > MAX_CBUF_SIZE) {
dropbear_exit("Bad cbuf size");
dropbear_exit("bad cbuf size");
}
cbuf = (circbuffer*)m_malloc(sizeof(circbuffer));
if (size > 0) {
cbuf->data = (unsigned char*)m_malloc(size);
}
cbuf->data = (unsigned char*)m_malloc(size);
cbuf->used = 0;
cbuf->readpos = 0;
cbuf->writepos = 0;
@@ -50,7 +48,6 @@ circbuffer * cbuf_new(unsigned int size) {
void cbuf_free(circbuffer * cbuf) {
m_burn(cbuf->data, cbuf->size);
m_free(cbuf->data);
m_free(cbuf);
}
@@ -104,7 +101,7 @@ unsigned int cbuf_writelen(circbuffer *cbuf) {
unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
dropbear_exit("bad cbuf read");
}
return &cbuf->data[cbuf->readpos];
@@ -113,7 +110,7 @@ unsigned char* cbuf_readptr(circbuffer *cbuf, unsigned int len) {
unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("Bad cbuf write");
dropbear_exit("bad cbuf write");
}
return &cbuf->data[cbuf->writepos];
@@ -121,7 +118,7 @@ unsigned char* cbuf_writeptr(circbuffer *cbuf, unsigned int len) {
void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_writelen(cbuf)) {
dropbear_exit("Bad cbuf write");
dropbear_exit("bad cbuf write");
}
cbuf->used += len;
@@ -132,7 +129,7 @@ void cbuf_incrwrite(circbuffer *cbuf, unsigned int len) {
void cbuf_incrread(circbuffer *cbuf, unsigned int len) {
if (len > cbuf_readlen(cbuf)) {
dropbear_exit("Bad cbuf read");
dropbear_exit("bad cbuf read");
}
dropbear_assert(cbuf->used >= len);

View File

@@ -1,308 +0,0 @@
/*
* Dropbear - a SSH2 server
*
* Copyright (c) 2005 Matt Johnston
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */
#include "includes.h"
#ifdef ENABLE_CLI_AGENTFWD
#include "agentfwd.h"
#include "session.h"
#include "ssh.h"
#include "dbutil.h"
#include "chansession.h"
#include "channel.h"
#include "packet.h"
#include "buffer.h"
#include "dbrandom.h"
#include "listener.h"
#include "runopts.h"
#include "atomicio.h"
#include "signkey.h"
#include "auth.h"
/* The protocol implemented to talk to OpenSSH's SSH2 agent is documented in
PROTOCOL.agent in recent OpenSSH source distributions (5.1p1 has it). */
static int new_agent_chan(struct Channel * channel);
const struct ChanType cli_chan_agent = {
0, /* sepfds */
"auth-agent@openssh.com",
new_agent_chan,
NULL,
NULL,
NULL
};
static int connect_agent() {
int fd = -1;
char* agent_sock = NULL;
agent_sock = getenv("SSH_AUTH_SOCK");
if (agent_sock == NULL)
return -1;
fd = connect_unix(agent_sock);
if (fd < 0) {
dropbear_log(LOG_INFO, "Failed to connect to agent");
}
return fd;
}
/* 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;
if (!cli_opts.agent_fwd)
return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
fd = connect_agent();
if (fd < 0) {
return SSH_OPEN_CONNECT_FAILED;
}
setnonblocking(fd);
ses.maxfd = MAX(ses.maxfd, fd);
channel->readfd = fd;
channel->writefd = fd;
return 0;
}
/* Sends a request to the agent, returning a newly allocated buffer
* with the response */
/* This function will block waiting for a response - it will
* only be used by client authentication (not for forwarded requests)
* won't cause problems for interactivity. */
/* Packet format (from draft-ylonen)
4 bytes Length, msb first. Does not include length itself.
1 byte Packet type. The value 255 is reserved for future extensions.
data Any data, depending on packet type. Encoding as in the ssh packet
protocol.
*/
static buffer * agent_request(unsigned char type, buffer *data) {
buffer * payload = NULL;
buffer * inbuf = NULL;
size_t readlen = 0;
ssize_t ret;
const int fd = cli_opts.agent_fd;
unsigned int data_len = 0;
if (data)
{
data_len = data->len;
}
payload = buf_new(4 + 1 + data_len);
buf_putint(payload, 1 + data_len);
buf_putbyte(payload, type);
if (data) {
buf_putbytes(payload, data->data, data->len);
}
buf_setpos(payload, 0);
ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
if ((size_t)ret != payload->len) {
TRACE(("write failed fd %d for agent_request, %s", fd, strerror(errno)))
goto out;
}
buf_free(payload);
payload = NULL;
TRACE(("Wrote out bytes for agent_request"))
/* Now we read the response */
inbuf = buf_new(4);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, 4), 4);
if (ret != 4) {
TRACE(("read of length failed for agent_request"))
goto out;
}
buf_setpos(inbuf, 0);
buf_setlen(inbuf, ret);
readlen = buf_getint(inbuf);
if (readlen > MAX_AGENT_REPLY) {
TRACE(("agent reply is too big"));
goto out;
}
buf_resize(inbuf, readlen);
buf_setpos(inbuf, 0);
ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
if ((size_t)ret != readlen) {
TRACE(("read of data failed for agent_request"))
goto out;
}
buf_incrwritepos(inbuf, readlen);
buf_setpos(inbuf, 0);
out:
if (payload)
buf_free(payload);
return inbuf;
}
static void agent_get_key_list(m_list * ret_list)
{
buffer * inbuf = NULL;
unsigned int num = 0;
unsigned char packet_type;
unsigned int i;
int ret;
inbuf = agent_request(SSH2_AGENTC_REQUEST_IDENTITIES, NULL);
if (!inbuf) {
TRACE(("agent_request failed returning identities"))
goto out;
}
/* The reply has a format of:
byte SSH2_AGENT_IDENTITIES_ANSWER
uint32 num_keys
Followed by zero or more consecutive keys, encoded as:
string key_blob
string key_comment
*/
packet_type = buf_getbyte(inbuf);
if (packet_type != SSH2_AGENT_IDENTITIES_ANSWER) {
goto out;
}
num = buf_getint(inbuf);
for (i = 0; i < num; i++) {
sign_key * pubkey = NULL;
enum signkey_type key_type = DROPBEAR_SIGNKEY_ANY;
buffer * key_buf;
/* each public key is encoded as a string */
key_buf = buf_getstringbuf(inbuf);
pubkey = new_sign_key();
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;
list_append(ret_list, pubkey);
/* We'll ignore the comment for now. might want it later.*/
buf_eatstring(inbuf);
}
out:
if (inbuf) {
buf_free(inbuf);
inbuf = NULL;
}
}
void cli_setup_agent(struct Channel *channel) {
if (!getenv("SSH_AUTH_SOCK")) {
return;
}
cli_start_send_channel_request(channel, "auth-agent-req@openssh.com");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
encrypt_packet();
}
/* Returned keys are prepended to ret_list, which will
be updated. */
void cli_load_agent_keys(m_list *ret_list) {
/* agent_fd will be closed after successful auth */
cli_opts.agent_fd = connect_agent();
if (cli_opts.agent_fd < 0) {
return;
}
agent_get_key_list(ret_list);
}
void agent_buf_sign(buffer *sigblob, sign_key *key,
buffer *data_buf) {
buffer *request_data = NULL;
buffer *response = NULL;
unsigned int siglen;
int packet_type;
/* Request format
byte SSH2_AGENTC_SIGN_REQUEST
string key_blob
string data
uint32 flags
*/
request_data = buf_new(MAX_PUBKEY_SIZE + data_buf->len + 12);
buf_put_pub_key(request_data, key, key->type);
buf_putbufstring(request_data, data_buf);
buf_putint(request_data, 0);
response = agent_request(SSH2_AGENTC_SIGN_REQUEST, request_data);
if (!response) {
goto fail;
}
packet_type = buf_getbyte(response);
if (packet_type != SSH2_AGENT_SIGN_RESPONSE) {
goto fail;
}
/* Response format
byte SSH2_AGENT_SIGN_RESPONSE
string signature_blob
*/
siglen = buf_getint(response);
buf_putbytes(sigblob, buf_getptr(response, siglen), siglen);
goto cleanup;
fail:
/* XXX don't fail badly here. instead propagate a failure code back up to
the cli auth pubkey code, and just remove this key from the list of
ones to try. */
dropbear_exit("Agent failed signing key");
cleanup:
if (request_data) {
buf_free(request_data);
}
if (response) {
buf_free(response);
}
}
#endif

99
cli-algo.c Normal file
View File

@@ -0,0 +1,99 @@
/*
* 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,8 +40,11 @@ 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));
@@ -50,27 +53,8 @@ void cli_auth_getmethods() {
buf_putstring(ses.writepayload, "none", 4); /* 'none' method */
encrypt_packet();
#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() {
@@ -107,7 +91,7 @@ void recv_msg_userauth_banner() {
}
}
fprintf(stderr, "%s\n", banner);
printf("%s\n", banner);
out:
m_free(banner);
@@ -160,46 +144,31 @@ 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) {
TRACE(("ignore next response, state set to USERAUTH_REQ_SENT"))
cli_ses.state = USERAUTH_REQ_SENT;
} else {
cli_ses.state = USERAUTH_FAIL_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
#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;
}
#endif
/* 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.ignore_next_auth_response = 0;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
methods = buf_getstring(ses.payload, &methlen);
@@ -252,27 +221,22 @@ 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 */
ses.authstate.authdone = 1;
cli_ses.state = USERAUTH_SUCCESS_RCVD;
cli_ses.lastauthtype = AUTH_TYPE_NONE;
#ifdef ENABLE_CLI_PUBKEY_AUTH
cli_auth_pubkey_cleanup();
#endif
}
int cli_auth_try() {
void cli_auth_try() {
int finished = 0;
TRACE(("enter cli_auth_try"))
@@ -288,40 +252,33 @@ int cli_auth_try() {
}
#endif
#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");
#ifdef ENABLE_CLI_INTERACT_AUTH
if (!finished && ses.authstate.authtypes & AUTH_TYPE_INTERACT) {
if (cli_ses.auth_interact_failed) {
finished = 0;
} else {
cli_auth_password();
cli_auth_interactive();
cli_ses.lastauthtype = AUTH_TYPE_INTERACT;
finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
}
}
#endif
#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;
}
}
#ifdef ENABLE_CLI_PASSWORD_AUTH
if (!finished && ses.authstate.authtypes & AUTH_TYPE_PASSWORD) {
cli_auth_password();
finished = 1;
cli_ses.lastauthtype = AUTH_TYPE_PASSWORD;
}
#endif
TRACE(("cli_auth_try lastauthtype %d", cli_ses.lastauthtype))
if (finished) {
TRACE(("leave cli_auth_try success"))
return DROPBEAR_SUCCESS;
if (!finished) {
dropbear_exit("No auth methods could be used.");
}
TRACE(("leave cli_auth_try failure"))
return DROPBEAR_FAILURE;
TRACE(("leave cli_auth_try"))
}
/* A helper for getpass() that exits if the user cancels. The returned

View File

@@ -131,7 +131,6 @@ void recv_msg_userauth_info_request() {
response_len = strlen(response);
buf_putstring(ses.writepayload, response, response_len);
m_burn(response, response_len);
m_free(prompt);
m_free(response);
}

View File

@@ -30,7 +30,6 @@
#include "ssh.h"
#include "runopts.h"
#include "auth.h"
#include "agentfwd.h"
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
@@ -38,23 +37,30 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
/* Called when we receive a SSH_MSG_USERAUTH_FAILURE for a pubkey request.
* We use it to remove the key we tried from the list */
void cli_pubkeyfail() {
m_list_elem *iter;
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
sign_key *iter_key = (sign_key*)iter->item;
if (iter_key == cli_ses.lastprivkey)
{
/* found the failing key */
list_remove(iter);
sign_key_free(iter_key);
cli_ses.lastprivkey = NULL;
return;
struct SignKeyList *keyitem;
struct SignKeyList **previtem;
TRACE(("enter cli_pubkeyfail"))
previtem = &cli_opts.privkeys;
/* Find the key we failed with, and remove it */
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
if (keyitem == cli_ses.lastprivkey) {
*previtem = keyitem->next;
}
previtem = &keyitem;
}
sign_key_free(cli_ses.lastprivkey->key); /* It won't be used again */
m_free(cli_ses.lastprivkey);
TRACE(("leave cli_pubkeyfail"))
}
void recv_msg_userauth_pk_ok() {
m_list_elem *iter;
struct SignKeyList *keyitem = NULL;
buffer* keybuf = NULL;
char* algotype = NULL;
unsigned int algolen;
@@ -74,9 +80,9 @@ void recv_msg_userauth_pk_ok() {
/* Iterate through our keys, find which one it was that matched, and
* send a real request with that key */
for (iter = cli_opts.privkeys->first; iter; iter = iter->next) {
sign_key *key = (sign_key*)iter->item;
if (key->type != keytype) {
for (keyitem = cli_opts.privkeys; keyitem != NULL; keyitem = keyitem->next) {
if (keyitem->type != keytype) {
/* Types differed */
TRACE(("types differed"))
continue;
@@ -84,7 +90,7 @@ void recv_msg_userauth_pk_ok() {
/* Now we compare the contents of the key */
keybuf->pos = keybuf->len = 0;
buf_put_pub_key(keybuf, key, keytype);
buf_put_pub_key(keybuf, keyitem->key, keytype);
buf_setpos(keybuf, 0);
buf_incrpos(keybuf, 4); /* first int is the length of the remainder (ie
remotelen) which has already been taken from
@@ -108,11 +114,11 @@ void recv_msg_userauth_pk_ok() {
}
buf_free(keybuf);
if (iter != NULL) {
if (keyitem != NULL) {
TRACE(("matching key"))
/* XXX TODO: if it's an encrypted key, here we ask for their
* password */
send_msg_userauth_pubkey((sign_key*)iter->item, keytype, 1);
send_msg_userauth_pubkey(keyitem->key, keytype, 1);
} else {
TRACE(("That was whacky. We got told that a key was valid, but it didn't match our list. Sounds like dodgy code on Dropbear's part"))
}
@@ -120,23 +126,6 @@ void recv_msg_userauth_pk_ok() {
TRACE(("leave recv_msg_userauth_pk_ok"))
}
void cli_buf_put_sign(buffer* buf, sign_key *key, int type,
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_buf);
buf_putbufstring(buf, sigblob);
buf_free(sigblob);
} else
#endif /* ENABLE_CLI_AGENTFWD */
{
buf_put_sign(buf, key, type, data_buf);
}
}
/* TODO: make it take an agent reference to use as well */
static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
@@ -169,10 +158,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 + ses.session_id->len + ses.writepayload->len);
buf_putbufstring(sigbuf, ses.session_id);
sigbuf = buf_new(4 + SHA1_HASH_SIZE + ses.writepayload->len);
buf_putstring(sigbuf, ses.session_id, SHA1_HASH_SIZE);
buf_putbytes(sigbuf, ses.writepayload->data, ses.writepayload->len);
cli_buf_put_sign(ses.writepayload, key, type, sigbuf);
buf_put_sign(ses.writepayload, key, type, sigbuf->data, sigbuf->len);
buf_free(sigbuf); /* Nothing confidential in the buffer */
}
@@ -180,43 +169,20 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign) {
TRACE(("leave send_msg_userauth_pubkey"))
}
/* Returns 1 if a key was tried */
int cli_auth_pubkey() {
TRACE(("enter cli_auth_pubkey"))
#ifdef ENABLE_CLI_AGENTFWD
if (!cli_opts.agent_keys_loaded) {
/* get the list of available keys from the agent */
cli_load_agent_keys(cli_opts.privkeys);
cli_opts.agent_keys_loaded = 1;
}
#endif
if (cli_opts.privkeys->first) {
sign_key * key = (sign_key*)cli_opts.privkeys->first->item;
if (cli_opts.privkeys != NULL) {
/* Send a trial request */
send_msg_userauth_pubkey(key, key->type, 0);
cli_ses.lastprivkey = key;
send_msg_userauth_pubkey(cli_opts.privkeys->key,
cli_opts.privkeys->type, 0);
cli_ses.lastprivkey = cli_opts.privkeys;
TRACE(("leave cli_auth_pubkey-success"))
return 1;
} else {
/* no more keys left */
TRACE(("leave cli_auth_pubkey-failure"))
return 0;
}
}
void cli_auth_pubkey_cleanup() {
#ifdef ENABLE_CLI_AGENTFWD
m_close(cli_opts.agent_fd);
cli_opts.agent_fd = -1;
#endif
while (cli_opts.privkeys->first) {
sign_key * key = list_remove(cli_opts.privkeys->first);
sign_key_free(key);
}
}
#endif /* Pubkey auth */

View File

@@ -33,15 +33,15 @@
#include "runopts.h"
#include "termcodes.h"
#include "chansession.h"
#include "agentfwd.h"
static void cli_closechansess(struct Channel *channel);
static int cli_initchansess(struct Channel *channel);
static void cli_chansessreq(struct Channel *channel);
static void start_channel_request(struct Channel *channel, unsigned char *type);
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 void cli_tty_setup();
@@ -71,9 +71,7 @@ static void cli_chansessreq(struct Channel *channel) {
TRACE(("got exit-signal, ignoring it"))
} else {
TRACE(("unknown request '%s'", type))
if (wantreply) {
send_msg_channel_failure(channel);
}
send_msg_channel_failure(channel);
goto out;
}
@@ -84,15 +82,17 @@ 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,
static void start_channel_request(struct Channel *channel,
unsigned char *type) {
CHECKCLEARTOWRITE();
@@ -287,7 +287,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_channel_request(channel, "pty-req");
/* Don't want replies */
buf_putbyte(ses.writepayload, 0);
@@ -309,7 +309,7 @@ static void send_chansess_pty_req(struct Channel *channel) {
/* Set up a window-change handler */
if (signal(SIGWINCH, sigwinch_handler) == SIG_ERR) {
dropbear_exit("Signal error");
dropbear_exit("signal error");
}
TRACE(("leave send_chansess_pty_req"))
}
@@ -330,7 +330,7 @@ static void send_chansess_shell_req(struct Channel *channel) {
reqtype = "shell";
}
cli_start_send_channel_request(channel, reqtype);
start_channel_request(channel, reqtype);
/* XXX TODO */
buf_putbyte(ses.writepayload, 0); /* Don't want replies */
@@ -361,46 +361,35 @@ static int cli_initchansess(struct Channel *channel) {
cli_init_stdpipe_sess(channel);
#ifdef ENABLE_CLI_AGENTFWD
if (cli_opts.agent_fwd) {
cli_setup_agent(channel);
}
#endif
if (cli_opts.wantpty) {
send_chansess_pty_req(channel);
} else {
set_sock_priority(ses.sock_out, DROPBEAR_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 */
}
#ifdef ENABLE_CLI_NETCAT
static const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_stdpipe_sess, /* inithandler */
NULL,
NULL,
cli_closechansess
};
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"))
const struct ChanType cli_chan_netcat = {
0, /* sepfds */
"direct-tcpip",
cli_init_stdpipe_sess, /* inithandler */
NULL,
NULL,
cli_closechansess
};
cli_opts.wantpty = 0;
if (send_msg_channel_open_init(STDIN_FILENO, &cli_chan_netcat)
@@ -417,7 +406,7 @@ void cli_send_netcat_request() {
buf_putint(ses.writepayload, source_port);
encrypt_packet();
TRACE(("leave cli_send_netcat_request"))
TRACE(("leave cli_send_chansess_request"))
}
#endif
@@ -436,58 +425,15 @@ void 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;
}
}
#if 0
while (cli_opts.localfwds != NULL) {
ret = cli_localtcp(cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
if (ret == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
#endif

142
cli-kex.c
View File

@@ -33,73 +33,44 @@
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
#include "dbrandom.h"
#include "random.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() {
TRACE(("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);
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_INIT);
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;
buf_putmpint(ses.writepayload, cli_ses.dh_e);
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))
@@ -117,59 +88,19 @@ void recv_msg_kexdh_reply() {
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;
if (buf_getmpint(ses.payload, &dh_f) != DROPBEAR_SUCCESS) {
TRACE(("failed getting mpint"))
dropbear_exit("Bad KEX packet");
}
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
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);
cli_ses.param_kex_algo = NULL;
if (buf_verify(ses.payload, hostkey, ses.hash) != DROPBEAR_SUCCESS) {
if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
!= DROPBEAR_SUCCESS) {
dropbear_exit("Bad hostkey signature");
}
@@ -181,8 +112,7 @@ void recv_msg_kexdh_reply() {
TRACE(("leave recv_msg_kexdh_init"))
}
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen,
const char* algoname) {
static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
char* fp = NULL;
FILE *tty = NULL;
@@ -190,16 +120,14 @@ 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(%s fingerprint %s)\n",
fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(fingerprint %s)\n",
cli_opts.remotehost,
algoname,
fp);
m_free(fp);
return;
}
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(%s fingerprint %s)\nDo you want to continue connecting? (y/n) ",
fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n) ",
cli_opts.remotehost,
algoname,
fp);
m_free(fp);
@@ -289,22 +217,16 @@ 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, algoname);
ask_to_confirm(keyblob, keybloblen);
/* 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) {
@@ -324,6 +246,7 @@ 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;
}
@@ -357,18 +280,17 @@ 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\n%s host key mismatch for %s !\n"
dropbear_exit("\n\nHost 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, algoname);
ask_to_confirm(keyblob, keybloblen);
/* If we get here, they said yes */
@@ -382,11 +304,12 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */
buf_setpos(line, 0);
buf_setlen(line, 0);
buf_putbytes(line, cli_opts.remotehost, hostlen);
buf_putbytes(line, ses.remotehost, hostlen);
buf_putbyte(line, ' ');
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);
@@ -404,5 +327,4 @@ out:
if (line != NULL) {
buf_free(line);
}
m_free(fingerprint);
}

View File

@@ -28,15 +28,11 @@
#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_exit(int exitcode, const char* format, va_list param);
static void cli_dropbear_log(int priority, const char* format, va_list param);
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out);
#endif
#if defined(DBMULTI_dbclient) || !defined(DROPBEAR_MULTI)
#if defined(DBMULTI_dbclient) && defined(DROPBEAR_MULTI)
@@ -47,15 +43,14 @@ int main(int argc, char ** argv) {
int sock_in, sock_out;
char* error = NULL;
char* hostandport;
int len;
_dropbear_exit = cli_dropbear_exit;
_dropbear_log = cli_dropbear_log;
disallow_core();
seedrandom();
crypto_init();
cli_getopts(argc, argv);
TRACE(("user='%s' host='%s' port='%s'", cli_opts.username,
@@ -68,23 +63,26 @@ int main(int argc, char ** argv) {
#ifdef ENABLE_CLI_PROXYCMD
if (cli_opts.proxycmd) {
cli_proxy_cmd(&sock_in, &sock_out);
m_free(cli_opts.proxycmd);
} else
#endif
{
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error);
sock_in = sock_out = sock;
if (cli_opts.wantpty) {
set_sock_priority(sock, DROPBEAR_PRIO_LOWDELAY);
}
}
if (sock_in < 0) {
dropbear_exit("%s", error);
}
cli_session(sock_in, sock_out);
/* Set up the host:port log */
len = strlen(cli_opts.remotehost);
len += 10; /* 16 bit port and leeway*/
hostandport = (char*)m_malloc(len);
snprintf(hostandport, len, "%s:%s",
cli_opts.remotehost, cli_opts.remoteport);
cli_session(sock_in, sock_out, hostandport);
/* not reached */
return -1;
@@ -96,17 +94,18 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) {
char fmtbuf[300];
if (!sessinitdone) {
snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s",
snprintf(fmtbuf, sizeof(fmtbuf), "exited: %s",
format);
} else {
snprintf(fmtbuf, sizeof(fmtbuf),
"Connection to %s@%s:%s exited: %s",
"connection to %s@%s:%s exited: %s",
cli_opts.username, cli_opts.remotehost,
cli_opts.remoteport, format);
}
/* Do the cleanup first, since then the terminal will be reset */
session_cleanup();
cli_session_cleanup();
common_session_cleanup();
_dropbear_log(LOG_INFO, fmtbuf, param);
@@ -133,7 +132,6 @@ static void exec_proxy_cmd(void *user_data_cmd) {
dropbear_exit("Failed to run '%s'\n", cmd);
}
#ifdef ENABLE_CLI_PROXYCMD
static void cli_proxy_cmd(int *sock_in, int *sock_out) {
int ret;
@@ -146,4 +144,3 @@ static void cli_proxy_cmd(int *sock_in, int *sock_out) {
*sock_in = *sock_out = -1;
}
}
#endif /* ENABLE_CLI_PROXYCMD */

View File

@@ -29,7 +29,6 @@
#include "dbutil.h"
#include "algo.h"
#include "tcpfwd.h"
#include "list.h"
cli_runopts cli_opts; /* GLOBAL */
@@ -41,7 +40,7 @@ static void fill_own_user();
static void loadidentityfile(const char* filename);
#endif
#ifdef ENABLE_CLI_ANYTCPFWD
static void addforward(const char* str, m_list *fwdlist);
static void addforward(const char* str, struct TCPFwdList** fwdlist);
#endif
#ifdef ENABLE_CLI_NETCAT
static void add_netcat(const char *str);
@@ -49,12 +48,13 @@ static void add_netcat(const char *str);
static void printhelp() {
fprintf(stderr, "Dropbear SSH client v%s https://matt.ucc.asn.au/dropbear/dropbear.html\n"
fprintf(stderr, "Dropbear client v%s\n"
#ifdef ENABLE_CLI_MULTIHOP
"Usage: %s [options] [user@]host[/port][,[user@]host/port],...] [command]\n"
#else
"Usage: %s [options] [user@]host[/port] [command]\n"
#endif
"Options are:\n"
"-p <remoteport>\n"
"-l <username>\n"
"-t Allocate a pty\n"
@@ -62,20 +62,16 @@ 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"
"-s Request a subsystem (use for sftp)\n"
#ifdef ENABLE_CLI_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)\n"
#endif
#ifdef ENABLE_CLI_AGENTFWD
"-A Enable agent auth forwarding\n"
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
"-L <[listenaddress:]listenport:remotehost:remoteport> Local port forwarding\n"
"-L <listenport:remotehost:remoteport> Local port forwarding\n"
"-g Allow remote hosts to connect to forwarded ports\n"
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
"-R <[listenaddress:]listenport:remotehost:remoteport> Remote port forwarding\n"
"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
#endif
"-W <receive_window_buffer> (default %d, larger may be faster, max 1MB)\n"
"-K <keepalive> (0 is never, default %d)\n"
@@ -86,10 +82,6 @@ static void printhelp() {
#ifdef ENABLE_CLI_PROXYCMD
"-J <proxy_program> Use program pipe rather than TCP connection\n"
#endif
#ifdef ENABLE_USER_ALGO_LIST
"-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
#ifdef DEBUG_TRACE
"-v verbose (compiled with DEBUG_TRACE)\n"
#endif
@@ -99,6 +91,7 @@ static void printhelp() {
}
void cli_getopts(int argc, char ** argv) {
unsigned int i, j;
char ** next = 0;
unsigned int cmdlen;
@@ -119,7 +112,6 @@ void cli_getopts(int argc, char ** argv) {
char* recv_window_arg = NULL;
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char *host_arg = NULL;
/* see printhelp() for options */
cli_opts.progname = argv[0];
@@ -131,32 +123,19 @@ 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();
cli_opts.privkeys = NULL;
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
cli_opts.localfwds = list_new();
cli_opts.localfwds = NULL;
opts.listen_fwd_all = 0;
#endif
#ifdef ENABLE_CLI_REMOTETCPFWD
cli_opts.remotefwds = list_new();
#endif
#ifdef ENABLE_CLI_AGENTFWD
cli_opts.agent_fwd = 0;
cli_opts.agent_fd = -1;
cli_opts.agent_keys_loaded = 0;
cli_opts.remotefwds = NULL;
#endif
#ifdef ENABLE_CLI_PROXYCMD
cli_opts.proxycmd = NULL;
#endif
#ifndef DISABLE_ZLIB
opts.enable_compress = 1;
#endif
#ifdef ENABLE_USER_ALGO_LIST
opts.cipher_list = NULL;
opts.mac_list = NULL;
#endif
/* not yet
opts.ipv4 = 1;
@@ -179,7 +158,7 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_REMOTETCPFWD
if (nextisremote) {
TRACE(("nextisremote true"))
addforward(argv[i], cli_opts.remotefwds);
addforward(argv[i], &cli_opts.remotefwds);
nextisremote = 0;
continue;
}
@@ -187,7 +166,7 @@ void cli_getopts(int argc, char ** argv) {
#ifdef ENABLE_CLI_LOCALTCPFWD
if (nextislocal) {
TRACE(("nextislocal true"))
addforward(argv[i], cli_opts.localfwds);
addforward(argv[i], &cli_opts.localfwds);
nextislocal = 0;
continue;
}
@@ -215,10 +194,6 @@ 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 */
@@ -291,19 +266,6 @@ void cli_getopts(int argc, char ** argv) {
case 'I':
next = &idle_timeout_arg;
break;
#ifdef ENABLE_CLI_AGENTFWD
case 'A':
cli_opts.agent_fwd = 1;
break;
#endif
#ifdef ENABLE_USER_ALGO_LIST
case 'c':
next = &opts.cipher_list;
break;
case 'm':
next = &opts.mac_list;
break;
#endif
#ifdef DEBUG_TRACE
case 'v':
debug_trace = 1;
@@ -311,10 +273,8 @@ void cli_getopts(int argc, char ** argv) {
#endif
case 'F':
case 'e':
#ifndef ENABLE_USER_ALGO_LIST
case 'c':
case 'm':
#endif
case 'D':
#ifndef ENABLE_CLI_REMOTETCPFWD
case 'R':
@@ -344,8 +304,12 @@ void cli_getopts(int argc, char ** argv) {
/* Either the hostname or commands */
if (host_arg == NULL) {
host_arg = argv[i];
if (cli_opts.remotehost == NULL) {
#ifdef ENABLE_CLI_MULTIHOP
parse_multihop_hostname(argv[i], argv[0]);
#else
parse_hostname(argv[i]);
#endif
} else {
/* this is part of the commands to send - after this we
@@ -374,22 +338,11 @@ void cli_getopts(int argc, char ** argv) {
/* And now a few sanity checks and setup */
#ifdef ENABLE_USER_ALGO_LIST
parse_ciphers_macs();
#endif
if (host_arg == NULL) {
if (cli_opts.remotehost == NULL) {
printhelp();
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";
}
@@ -406,7 +359,7 @@ void cli_getopts(int argc, char ** argv) {
if (cli_opts.backgrounded && cli_opts.cmd == NULL
&& cli_opts.no_cmd == 0) {
dropbear_exit("Command required for -f");
dropbear_exit("command required for -f");
}
if (recv_window_arg) {
@@ -416,19 +369,15 @@ void cli_getopts(int argc, char ** argv) {
}
}
if (keepalive_arg) {
unsigned int val;
if (m_str_to_uint(keepalive_arg, &val) == DROPBEAR_FAILURE) {
if (m_str_to_uint(keepalive_arg, &opts.keepalive_secs) == DROPBEAR_FAILURE) {
dropbear_exit("Bad keepalive '%s'", keepalive_arg);
}
opts.keepalive_secs = val;
}
if (idle_timeout_arg) {
unsigned int val;
if (m_str_to_uint(idle_timeout_arg, &val) == DROPBEAR_FAILURE) {
if (m_str_to_uint(idle_timeout_arg, &opts.idle_timeout_secs) == DROPBEAR_FAILURE) {
dropbear_exit("Bad idle_timeout '%s'", idle_timeout_arg);
}
opts.idle_timeout_secs = val;
}
#ifdef ENABLE_CLI_NETCAT
@@ -436,90 +385,36 @@ void cli_getopts(int argc, char ** argv) {
dropbear_log(LOG_INFO, "Ignoring command '%s' in netcat mode", cli_opts.cmd);
}
#endif
/* The hostname gets set up last, since
* in multi-hop mode it will require knowledge
* of other flags such as -i */
#ifdef ENABLE_CLI_MULTIHOP
parse_multihop_hostname(host_arg, argv[0]);
#else
parse_hostname(host_arg);
#endif
}
#ifdef ENABLE_CLI_PUBKEY_AUTH
static void loadidentityfile(const char* filename) {
struct SignKeyList * nextkey;
sign_key *key;
enum signkey_type keytype;
int keytype;
key = new_sign_key();
keytype = DROPBEAR_SIGNKEY_ANY;
if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
sign_key_free(key);
} else {
key->type = keytype;
key->source = SIGNKEY_SOURCE_RAW_FILE;
key->filename = m_strdup(filename);
list_append(cli_opts.privkeys, key);
nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
nextkey->key = key;
nextkey->next = cli_opts.privkeys;
nextkey->type = keytype;
cli_opts.privkeys = nextkey;
}
}
#endif
#ifdef ENABLE_CLI_MULTIHOP
static char*
multihop_passthrough_args() {
char *ret;
int total;
unsigned int len = 0;
m_list_elem *iter;
/* 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 += 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);
total += written;
}
for (iter = cli_opts.privkeys->first; iter; iter = iter->next)
{
sign_key * key = (sign_key*)iter->item;
const size_t size = len - total;
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;
}
/* Sets up 'onion-forwarding' connections. This will spawn
* a separate dbclient process for each hop.
* As an example, if the cmdline is
@@ -534,8 +429,7 @@ multihop_passthrough_args() {
*/
static void parse_multihop_hostname(const char* orighostarg, const char* argv0) {
char *userhostarg = NULL;
char *hostbuf = NULL;
char *last_hop = NULL;
char *last_hop = NULL;;
char *remainder = NULL;
/* both scp and rsync parse a user@host argument
@@ -547,12 +441,11 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
&& strchr(cli_opts.username, ',')
&& strchr(cli_opts.username, '@')) {
unsigned int len = strlen(orighostarg) + strlen(cli_opts.username) + 2;
hostbuf = m_malloc(len);
snprintf(hostbuf, len, "%s@%s", cli_opts.username, orighostarg);
userhostarg = m_malloc(len);
snprintf(userhostarg, len, "%s@%s", cli_opts.username, orighostarg);
} else {
hostbuf = m_strdup(orighostarg);
userhostarg = m_strdup(orighostarg);
}
userhostarg = hostbuf;
last_hop = strrchr(userhostarg, ',');
if (last_hop) {
@@ -570,28 +463,19 @@ static void parse_multihop_hostname(const char* orighostarg, const char* argv0)
if (last_hop) {
/* Set up the proxycmd */
unsigned int cmd_len = 0;
char *passthrough_args = multihop_passthrough_args();
if (cli_opts.proxycmd) {
dropbear_exit("-J can't be used with multihop mode");
}
if (cli_opts.remoteport == NULL) {
cli_opts.remoteport = "22";
}
cmd_len = strlen(argv0) + strlen(remainder)
cmd_len = strlen(remainder)
+ strlen(cli_opts.remotehost) + strlen(cli_opts.remoteport)
+ strlen(passthrough_args)
+ 30;
+ strlen(argv0) + 30;
cli_opts.proxycmd = m_malloc(cmd_len);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport,
passthrough_args, remainder);
#ifndef DISABLE_ZLIB
/* The stream will be incompressible since it's encrypted. */
opts.enable_compress = 0;
#endif
m_free(passthrough_args);
snprintf(cli_opts.proxycmd, cmd_len, "%s -B %s:%s %s",
argv0, cli_opts.remotehost, cli_opts.remoteport, remainder);
}
m_free(hostbuf);
}
#endif /* !ENABLE_CLI_MULTIHOP */
@@ -617,11 +501,7 @@ static void parse_hostname(const char* orighostarg) {
cli_opts.username = m_strdup(cli_opts.own_user);
}
port = strchr(cli_opts.remotehost, '^');
if (!port) {
/* legacy separator */
port = strchr(cli_opts.remotehost, '/');
}
port = strchr(cli_opts.remotehost, '/');
if (port) {
*port = '\0';
cli_opts.remoteport = port+1;
@@ -684,16 +564,14 @@ static void fill_own_user() {
}
#ifdef ENABLE_CLI_ANYTCPFWD
/* Turn a "[listenaddr:]listenport:remoteaddr:remoteport" string into into a forwarding
/* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
* set, and add it to the forwarding list */
static void addforward(const char* origstr, m_list *fwdlist) {
static void addforward(const char* origstr, struct TCPFwdList** fwdlist) {
char *part1 = NULL, *part2 = NULL, *part3 = NULL, *part4 = NULL;
char * listenaddr = NULL;
char * listenport = NULL;
char * connectaddr = NULL;
char * connectport = NULL;
struct TCPFwdEntry* newfwd = NULL;
char * connectaddr = NULL;
struct TCPFwdList* newfwd = NULL;
char * str = NULL;
TRACE(("enter addforward"))
@@ -702,43 +580,25 @@ static void addforward(const char* origstr, m_list *fwdlist) {
is never free()d. */
str = m_strdup(origstr);
part1 = str;
listenport = str;
part2 = strchr(str, ':');
if (part2 == NULL) {
TRACE(("part2 == NULL"))
connectaddr = strchr(str, ':');
if (connectaddr == NULL) {
TRACE(("connectaddr == NULL"))
goto fail;
}
*part2 = '\0';
part2++;
*connectaddr = '\0';
connectaddr++;
part3 = strchr(part2, ':');
if (part3 == NULL) {
TRACE(("part3 == NULL"))
connectport = strchr(connectaddr, ':');
if (connectport == NULL) {
TRACE(("connectport == NULL"))
goto fail;
}
*part3 = '\0';
part3++;
*connectport = '\0';
connectport++;
part4 = strchr(part3, ':');
if (part4) {
*part4 = '\0';
part4++;
}
if (part4) {
listenaddr = part1;
listenport = part2;
connectaddr = part3;
connectport = part4;
} else {
listenaddr = NULL;
listenport = part1;
connectaddr = part2;
connectport = part3;
}
newfwd = m_malloc(sizeof(struct TCPFwdEntry));
newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList));
/* Now we check the ports - note that the port ints are unsigned,
* the check later only checks for >= MAX_PORT */
@@ -752,7 +612,6 @@ static void addforward(const char* origstr, m_list *fwdlist) {
goto fail;
}
newfwd->listenaddr = listenaddr;
newfwd->connectaddr = connectaddr;
if (newfwd->listenport > 65535) {
@@ -766,7 +625,8 @@ static void addforward(const char* origstr, m_list *fwdlist) {
}
newfwd->have_reply = 0;
list_append(fwdlist, newfwd);
newfwd->next = *fwdlist;
*fwdlist = newfwd;
TRACE(("leave addforward: done"))
return;

85
cli-service.c Normal file
View File

@@ -0,0 +1,85 @@
/*
* 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,19 +31,15 @@
#include "packet.h"
#include "tcpfwd.h"
#include "channel.h"
#include "dbrandom.h"
#include "random.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);
struct clientsession cli_ses; /* GLOBAL */
@@ -78,16 +74,17 @@ static const packettype cli_packettypes[] = {
static const struct ChanType *cli_chantypes[] = {
#ifdef ENABLE_CLI_REMOTETCPFWD
&cli_chan_tcpremote,
#endif
#ifdef ENABLE_CLI_AGENTFWD
&cli_chan_agent,
#endif
NULL /* Null termination */
};
void cli_session(int sock_in, int sock_out) {
void cli_session(int sock_in, int sock_out, char* remotehost) {
common_session_init(sock_in, sock_out);
seedrandom();
crypto_init();
common_session_init(sock_in, sock_out, remotehost);
chaninitialise(cli_chantypes);
@@ -98,7 +95,7 @@ void cli_session(int sock_in, int sock_out) {
sessinitdone = 1;
/* Exchange identification */
send_session_identification();
session_identification();
send_msg_kexinit();
@@ -108,12 +105,6 @@ 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;
@@ -138,70 +129,39 @@ static void cli_session_init() {
cli_ses.lastprivkey = NULL;
cli_ses.lastauthtype = 0;
#ifdef DROPBEAR_NONE_CIPHER
cli_ses.cipher_none_after_auth = get_algo_usable(sshciphers, "none");
set_algo_usable(sshciphers, "none", 0);
#else
cli_ses.cipher_none_after_auth = 0;
#endif
/* For printing "remote host closed" for the user */
ses.remoteclosed = cli_remoteclosed;
ses.extra_session_cleanup = cli_session_cleanup;
ses.buf_match_algo = cli_buf_match_algo;
/* 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() {
TRACE2(("enter cli_sessionloop"))
if (ses.lastpacket == 0) {
TRACE2(("exit cli_sessionloop: no real packets yet"))
return;
}
TRACE(("enter cli_sessionloop"))
if (ses.lastpacket == SSH_MSG_KEXINIT && cli_ses.kex_state == KEX_NOTHING) {
cli_ses.kex_state = KEXINIT_RCVD;
}
if (cli_ses.kex_state == KEXINIT_RCVD) {
/* We initiate the KEXDH. If DH wasn't the correct type, the KEXINIT
* negotiation would have failed. */
if (!ses.kexstate.our_first_follows_matches) {
send_msg_kexdh_init();
}
cli_ses.kex_state = KEXDH_INIT_SENT;
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.sentnewkeys) {
if (cli_ses.kex_state != KEX_NOTHING && ses.kexstate.recvkexinit == 0
&& ses.kexstate.sentkexinit == 0) {
cli_ses.kex_state = KEX_NOTHING;
}
@@ -211,10 +171,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) {
/* We might reach here if we have partial packet reads or have
* received SSG_MSG_IGNORE etc. Just skip it */
TRACE2(("donefirstkex false\n"))
TRACE(("XXX XXX might be bad! leave cli_sessionloop: haven't donefirstkex"))
return;
}
@@ -224,40 +184,32 @@ 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:
if (cli_auth_try() == DROPBEAR_FAILURE) {
dropbear_exit("No auth methods could be used.");
}
cli_auth_try();
cli_ses.state = USERAUTH_REQ_SENT;
TRACE(("leave cli_sessionloop: cli_auth_try"))
return;
case USERAUTH_SUCCESS_RCVD:
#ifdef DROPBEAR_NONE_CIPHER
if (cli_ses.cipher_none_after_auth)
{
set_algo_usable(sshciphers, "none", 1);
send_msg_kexinit();
}
#endif
if (cli_opts.backgrounded) {
int devnull;
/* keeping stdin open steals input from the terminal and
is confusing, though stdout/stderr could be useful. */
devnull = open(_PATH_DEVNULL, O_RDONLY);
if (devnull < 0) {
dropbear_exit("Opening /dev/null: %d %s",
dropbear_exit("opening /dev/null: %d %s",
errno, strerror(errno));
}
dup2(devnull, STDIN_FILENO);
@@ -267,15 +219,6 @@ static void cli_sessionloop() {
}
}
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.netcat_host) {
cli_send_netcat_request();
} else
#endif
if (!cli_opts.no_cmd) {
cli_send_chansess_request();
}
#ifdef ENABLE_CLI_LOCALTCPFWD
setup_localtcp();
#endif
@@ -283,6 +226,14 @@ static void cli_sessionloop() {
setup_remotetcp();
#endif
#ifdef ENABLE_CLI_NETCAT
if (cli_opts.netcat_host) {
cli_send_netcat_request();
} else
#endif
if (!cli_opts.no_cmd) {
cli_send_chansess_request();
}
TRACE(("leave cli_sessionloop: running"))
cli_ses.state = SESSION_RUNNING;
return;
@@ -304,11 +255,11 @@ static void cli_sessionloop() {
break;
}
TRACE2(("leave cli_sessionloop: fell out"))
TRACE(("leave cli_sessionloop: fell out"))
}
static void cli_session_cleanup(void) {
void cli_session_cleanup() {
if (!sessinitdone) {
return;
@@ -326,7 +277,8 @@ static void cli_session_cleanup(void) {
static void cli_finished() {
session_cleanup();
cli_session_cleanup();
common_session_cleanup();
fprintf(stderr, "Connection to %s@%s:%s closed.\n", cli_opts.username,
cli_opts.remotehost, cli_opts.remoteport);
exit(cli_ses.retval);
@@ -342,7 +294,7 @@ static void cli_remoteclosed() {
m_close(ses.sock_out);
ses.sock_in = -1;
ses.sock_out = -1;
dropbear_exit("Remote closed the connection");
dropbear_exit("remote closed the connection");
}
/* Operates in-place turning dirty (untrusted potentially containing control

View File

@@ -45,9 +45,7 @@ const struct ChanType cli_chan_tcpremote = {
#endif
#ifdef ENABLE_CLI_LOCALTCPFWD
static int cli_localtcp(const char* listenaddr,
unsigned int listenport,
const char* remoteaddr,
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
unsigned int remoteport);
static const struct ChanType cli_chan_tcplocal = {
1, /* sepfds */
@@ -61,33 +59,33 @@ static const struct ChanType cli_chan_tcplocal = {
#ifdef ENABLE_CLI_LOCALTCPFWD
void setup_localtcp() {
m_list_elem *iter;
int ret;
TRACE(("enter setup_localtcp"))
for (iter = cli_opts.localfwds->first; iter; iter = iter->next) {
struct TCPFwdEntry * fwd = (struct TCPFwdEntry*)iter->item;
ret = cli_localtcp(
fwd->listenaddr,
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
if (cli_opts.localfwds == NULL) {
TRACE(("cli_opts.localfwds == NULL"))
}
while (cli_opts.localfwds != NULL) {
ret = cli_localtcp(cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
if (ret == DROPBEAR_FAILURE) {
dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d",
fwd->listenaddr,
fwd->listenport,
fwd->connectaddr,
fwd->connectport);
}
dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
cli_opts.localfwds->listenport,
cli_opts.localfwds->connectaddr,
cli_opts.localfwds->connectport);
}
cli_opts.localfwds = cli_opts.localfwds->next;
}
TRACE(("leave setup_localtcp"))
}
static int cli_localtcp(const char* listenaddr,
unsigned int listenport,
const char* remoteaddr,
static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
unsigned int remoteport) {
struct TCPListener* tcpinfo = NULL;
@@ -101,17 +99,10 @@ static int cli_localtcp(const char* listenaddr,
tcpinfo->sendaddr = m_strdup(remoteaddr);
tcpinfo->sendport = remoteport;
if (listenaddr)
{
tcpinfo->listenaddr = m_strdup(listenaddr);
}
else
{
if (opts.listen_fwd_all) {
tcpinfo->listenaddr = m_strdup("");
} else {
tcpinfo->listenaddr = m_strdup("localhost");
}
if (opts.listen_fwd_all) {
tcpinfo->listenaddr = m_strdup("");
} else {
tcpinfo->listenaddr = m_strdup("localhost");
}
tcpinfo->listenport = listenport;
@@ -129,15 +120,22 @@ static int cli_localtcp(const char* listenaddr,
#endif /* ENABLE_CLI_LOCALTCPFWD */
#ifdef ENABLE_CLI_REMOTETCPFWD
static void send_msg_global_request_remotetcp(const char *addr, int port) {
static void send_msg_global_request_remotetcp(int port) {
char* listenspec = NULL;
TRACE(("enter send_msg_global_request_remotetcp"))
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
buf_putstring(ses.writepayload, "tcpip-forward", 13);
buf_putbyte(ses.writepayload, 1); /* want_reply */
buf_putstring(ses.writepayload, addr, strlen(addr));
if (opts.listen_fwd_all) {
listenspec = "";
} else {
listenspec = "localhost";
}
/* TODO: IPv6? */;
buf_putstring(ses.writepayload, listenspec, strlen(listenspec));
buf_putint(ses.writepayload, port);
encrypt_packet();
@@ -148,113 +146,90 @@ static void send_msg_global_request_remotetcp(const char *addr, int port) {
/* The only global success/failure messages are for remotetcp.
* Since there isn't any identifier in these messages, we have to rely on them
* being in the same order as we sent the requests. This is the ordering
* of the cli_opts.remotefwds list.
* If the requested remote port is 0 the listen port will be
* dynamically allocated by the server and the port number will be returned
* to client and the port number reported to the user. */
* of the cli_opts.remotefwds list */
void cli_recv_msg_request_success() {
/* We just mark off that we have received the reply,
/* Nothing in the packet. We just mark off that we have received the reply,
* so that we can report failure for later ones. */
m_list_elem * iter = NULL;
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->have_reply) {
fwd->have_reply = 1;
if (fwd->listenport == 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);
}
}
struct TCPFwdList * iter = NULL;
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (!iter->have_reply)
{
iter->have_reply = 1;
return;
}
iter = iter->next;
}
}
void cli_recv_msg_request_failure() {
m_list_elem *iter;
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
if (!fwd->have_reply) {
fwd->have_reply = 1;
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", fwd->listenport, fwd->connectaddr, fwd->connectport);
struct TCPFwdList * iter = NULL;
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (!iter->have_reply)
{
iter->have_reply = 1;
dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", iter->listenport, iter->connectaddr, iter->connectport);
return;
}
iter = iter->next;
}
}
void setup_remotetcp() {
m_list_elem *iter;
struct TCPFwdList * iter = NULL;
TRACE(("enter setup_remotetcp"))
for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
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 */
if (opts.listen_fwd_all) {
fwd->listenaddr = m_strdup("");
} else {
fwd->listenaddr = m_strdup("localhost");
}
}
send_msg_global_request_remotetcp(fwd->listenaddr, fwd->listenport);
if (cli_opts.remotefwds == NULL) {
TRACE(("cli_opts.remotefwds == NULL"))
}
iter = cli_opts.remotefwds;
while (iter != NULL) {
send_msg_global_request_remotetcp(iter->listenport);
iter = iter->next;
}
TRACE(("leave setup_remotetcp"))
}
static int newtcpforwarded(struct Channel * channel) {
char *origaddr = NULL;
unsigned int origport;
m_list_elem * iter = NULL;
struct TCPFwdEntry *fwd;
struct TCPFwdList * iter = NULL;
char portstring[NI_MAXSERV];
int sock;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
origaddr = buf_getstring(ses.payload, NULL);
/* We don't care what address they connected to */
buf_eatstring(ses.payload);
origport = buf_getint(ses.payload);
/* 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) {
/* Find which port corresponds */
iter = cli_opts.remotefwds;
while (iter != NULL) {
if (origport == iter->listenport) {
break;
}
iter = iter->next;
}
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);
dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
origaddr, origport);
dropbear_log(LOG_INFO, "Server send unrequested port, from port %d",
origport);
goto out;
}
snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
if (sock < 0) {
TRACE(("leave newtcpdirect: sock failed"))
err = SSH_OPEN_CONNECT_FAILED;
@@ -271,7 +246,6 @@ static int newtcpforwarded(struct Channel * channel) {
err = SSH_OPEN_IN_PROGRESS;
out:
m_free(origaddr);
TRACE(("leave newtcpdirect: err %d", err))
return err;
}

View File

@@ -23,35 +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* UNUSED(cipher_state)) {
if (in != out) {
memmove(out, in, len);
}
unsigned long len, void *cipher_state) {
memcpy(out, in, len);
return CRYPT_OK;
}
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)) {
static int void_start(int cipher, const unsigned char *IV,
const unsigned char *key,
int keylen, int num_rounds, void *cipher_state) {
return CRYPT_OK;
}
/* Mappings for ciphers, parameters are
{&cipher_desc, keysize, blocksize} */
/* Remember to add new ciphers/hashes to regciphers/reghashes too */
/* NOTE: if keysize > 2*SHA1_HASH_SIZE, code such as hashkeys()
needs revisiting */
#ifdef DROPBEAR_AES256
static const struct dropbear_cipher dropbear_aes256 =
@@ -111,14 +104,6 @@ static const struct dropbear_hash dropbear_sha1 =
static const struct dropbear_hash dropbear_sha1_96 =
{&sha1_desc, 20, 12};
#endif
#ifdef DROPBEAR_SHA2_256_HMAC
static const struct dropbear_hash dropbear_sha2_256 =
{&sha256_desc, 32, 32};
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
static const struct dropbear_hash dropbear_sha2_512 =
{&sha512_desc, 64, 64};
#endif
#ifdef DROPBEAR_MD5_HMAC
static const struct dropbear_hash dropbear_md5 =
{&md5_desc, 16, 16};
@@ -164,20 +149,11 @@ algo_type sshciphers[] = {
#endif
#ifdef DROPBEAR_BLOWFISH
{"blowfish-cbc", 0, &dropbear_blowfish, 1, &dropbear_mode_cbc},
#endif
#ifdef DROPBEAR_NONE_CIPHER
{"none", 0, (void*)&dropbear_nocipher, 1, &dropbear_mode_none},
#endif
{NULL, 0, NULL, 0, NULL}
};
algo_type sshhashes[] = {
#ifdef DROPBEAR_SHA2_256_HMAC
{"hmac-sha2-256", 0, &dropbear_sha2_256, 1, NULL},
#endif
#ifdef DROPBEAR_SHA2_512_HMAC
{"hmac-sha2-512", 0, &dropbear_sha2_512, 1, NULL},
#endif
#ifdef DROPBEAR_SHA1_96_HMAC
{"hmac-sha1-96", 0, &dropbear_sha1_96, 1, NULL},
#endif
@@ -185,40 +161,21 @@ algo_type sshhashes[] = {
{"hmac-sha1", 0, &dropbear_sha1, 1, NULL},
#endif
#ifdef DROPBEAR_MD5_HMAC
{"hmac-md5", 0, (void*)&dropbear_md5, 1, NULL},
#endif
#ifdef DROPBEAR_NONE_INTEGRITY
{"none", 0, (void*)&dropbear_nohash, 1, NULL},
{"hmac-md5", 0, &dropbear_md5, 1, NULL},
#endif
{NULL, 0, NULL, 0, NULL}
};
algo_type sshcompress[] = {
#ifndef DISABLE_ZLIB
algo_type ssh_compress[] = {
{"zlib", DROPBEAR_COMP_ZLIB, NULL, 1, NULL},
{"zlib@openssh.com", DROPBEAR_COMP_ZLIB_DELAY, NULL, 1, NULL},
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
#endif
algo_type ssh_nocompress[] = {
{"none", DROPBEAR_COMP_NONE, NULL, 1, NULL},
{NULL, 0, NULL, 0, NULL}
};
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
@@ -228,51 +185,55 @@ 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[] = {
#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-group1-sha1", 0, &kex_dh_group1, 1, NULL},
{"diffie-hellman-group14-sha1", 0, &kex_dh_group14, 1, NULL},
#ifdef USE_KEXGUESS2
{KEXGUESS2_ALGO_NAME, KEXGUESS2_ALGO_ID, NULL, 1, NULL},
#endif
{"diffie-hellman-group1-sha1", DROPBEAR_KEX_DH_GROUP1, NULL, 1, NULL},
{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
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
@@ -291,6 +252,8 @@ int have_algo(char* algo, size_t algolen, algo_type algos[]) {
return DROPBEAR_FAILURE;
}
/* Output a comma separated list of algorithms to a buffer */
void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
@@ -298,7 +261,7 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
unsigned int donefirst = 0;
buffer *algolist = NULL;
algolist = buf_new(200);
algolist = buf_new(160);
for (i = 0; localalgos[i].name != NULL; i++) {
if (localalgos[i].usable) {
if (donefirst)
@@ -311,232 +274,3 @@ void buf_put_algolist(buffer * buf, algo_type localalgos[]) {
buf_putstring(buf, algolist->data, algolist->len);
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
set_algo_usable(algo_type algos[], const char * algo_name, int usable)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
a->usable = usable;
return;
}
}
}
int
get_algo_usable(algo_type algos[], const char * algo_name)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
return a->usable;
}
}
return 0;
}
#endif /* DROPBEAR_NONE_CIPHER */
#ifdef ENABLE_USER_ALGO_LIST
char *
algolist_string(algo_type algos[])
{
char *ret_list;
buffer *b = buf_new(200);
buf_put_algolist(b, algos);
buf_setpos(b, b->len);
buf_putbyte(b, '\0');
buf_setpos(b, 4);
ret_list = m_strdup(buf_getptr(b, b->len - b->pos));
buf_free(b);
return ret_list;
}
static algo_type*
check_algo(const char* algo_name, algo_type *algos)
{
algo_type *a;
for (a = algos; a->name != NULL; a++)
{
if (strcmp(a->name, algo_name) == 0)
{
return a;
}
}
return NULL;
}
static void
try_add_algo(const char *algo_name, algo_type *algos,
const char *algo_desc, algo_type * new_algos, int *num_ret)
{
algo_type *match_algo = check_algo(algo_name, algos);
if (!match_algo)
{
dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc);
return;
}
new_algos[*num_ret] = *match_algo;
(*num_ret)++;
}
/* Checks a user provided comma-separated algorithm list for available
* options. Any that are not acceptable are removed in-place. Returns the
* number of valid algorithms. */
int
check_user_algos(const char* user_algo_list, algo_type * algos,
const char *algo_desc)
{
algo_type new_algos[MAX_PROPOSED_ALGO];
/* this has two passes. first we sweep through the given list of
* algorithms and mark them as usable=2 in the algo_type[] array... */
int num_ret = 0;
char *work_list = m_strdup(user_algo_list);
char *last_name = work_list;
char *c;
for (c = work_list; *c; c++)
{
if (*c == ',')
{
*c = '\0';
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
c++;
last_name = c;
}
}
try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret);
m_free(work_list);
new_algos[num_ret].name = NULL;
/* Copy one more as a blank delimiter */
memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1));
return num_ret;
}
#endif /* ENABLE_USER_ALGO_LIST */

View File

@@ -48,6 +48,7 @@ static void send_msg_channel_data(struct Channel *channel, int isextended);
static void send_msg_channel_eof(struct Channel *channel);
static void send_msg_channel_close(struct Channel *channel);
static void remove_channel(struct Channel *channel);
static void delete_channel(struct Channel *channel);
static void check_in_progress(struct Channel *channel);
static unsigned int write_pending(struct Channel * channel);
static void check_close(struct Channel *channel);
@@ -92,20 +93,11 @@ void chancleanup() {
TRACE(("leave chancleanup"))
}
static void
chan_initwritebuf(struct Channel *channel)
{
dropbear_assert(channel->writebuf->size == 0 && channel->recvwindow == 0);
cbuf_free(channel->writebuf);
channel->writebuf = cbuf_new(opts.recv_window);
channel->recvwindow = opts.recv_window;
}
/* Create a new channel entry, send a reply confirm or failure */
/* If remotechan, transwindow and transmaxpacket are not know (for a new
* outgoing connection, with them to be filled on confirmation), they should
* all be set to 0 */
static struct Channel* newchannel(unsigned int remotechan,
struct Channel* newchannel(unsigned int remotechan,
const struct ChanType *type,
unsigned int transwindow, unsigned int transmaxpacket) {
@@ -146,7 +138,6 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->index = i;
newchan->sent_close = newchan->recv_close = 0;
newchan->sent_eof = newchan->recv_eof = 0;
newchan->close_handler_done = 0;
newchan->remotechan = remotechan;
newchan->transwindow = transwindow;
@@ -160,10 +151,9 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->await_open = 0;
newchan->flushing = 0;
newchan->writebuf = cbuf_new(0); /* resized later by chan_initwritebuf */
newchan->recvwindow = 0;
newchan->writebuf = cbuf_new(opts.recv_window);
newchan->extrabuf = NULL; /* The user code can set it up */
newchan->recvwindow = opts.recv_window;
newchan->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN;
@@ -273,16 +263,14 @@ static unsigned int write_pending(struct Channel * channel) {
static void check_close(struct Channel *channel) {
int close_allowed = 0;
TRACE2(("check_close: writefd %d, readfd %d, errfd %d, sent_close %d, recv_close %d",
TRACE(("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))
TRACE2(("writebuf size %d extrabuf size %d",
channel->writebuf ? cbuf_getused(channel->writebuf) : 0,
TRACE(("writebuf size %d extrabuf size %d",
cbuf_getused(channel->writebuf),
channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0))
if (!channel->flushing
&& !channel->close_handler_done
&& channel->type->check_close
if (!channel->flushing && channel->type->check_close
&& channel->type->check_close(channel))
{
channel->flushing = 1;
@@ -293,8 +281,7 @@ static void check_close(struct Channel *channel) {
channel, to ensure that the shell has exited (and the exit status
retrieved) before we close things up. */
if (!channel->type->check_close
|| channel->close_handler_done
|| channel->type->check_close(channel)) {
|| channel->type->check_close(channel)) {
close_allowed = 1;
}
@@ -307,9 +294,7 @@ static void check_close(struct Channel *channel) {
return;
}
if ((channel->recv_eof && !write_pending(channel))
/* have a server "session" and child has exited */
|| (channel->type->check_close && close_allowed)) {
if (channel->recv_eof && !write_pending(channel)) {
close_chan_fd(channel, channel->writefd, SHUT_WR);
}
@@ -338,7 +323,6 @@ 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
@@ -364,10 +348,9 @@ static void check_in_progress(struct Channel *channel) {
send_msg_channel_open_failure(channel->remotechan,
SSH_OPEN_CONNECT_FAILED, "", "");
close(channel->writefd);
remove_channel(channel);
delete_channel(channel);
TRACE(("leave check_in_progress: fail"))
} else {
chan_initwritebuf(channel);
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
channel->readfd = channel->writefd;
@@ -380,11 +363,9 @@ static void check_in_progress(struct Channel *channel) {
/* Send the close message and set the channel as closed */
static void send_msg_channel_close(struct Channel *channel) {
TRACE(("enter send_msg_channel_close %p", channel))
if (channel->type->closehandler
&& !channel->close_handler_done) {
TRACE(("enter send_msg_channel_close"))
if (channel->type->closehandler) {
channel->type->closehandler(channel);
channel->close_handler_done = 1;
}
CHECKCLEARTOWRITE();
@@ -474,13 +455,8 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
continue;
}
/* 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)) {
/* Stuff to put over the wire */
if (channel->transwindow > 0) {
if (channel->readfd >= 0) {
FD_SET(channel->readfd, readfds);
@@ -492,13 +468,13 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
}
/* Stuff from the wire */
if (channel->initconn
||(channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0)) {
if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
|| channel->initconn) {
FD_SET(channel->writefd, writefds);
}
if (ERRFD_IS_WRITE(channel) && channel->errfd >= 0
&& cbuf_getused(channel->extrabuf) > 0) {
&& cbuf_getused(channel->extrabuf) > 0 ) {
FD_SET(channel->errfd, writefds);
}
@@ -569,36 +545,39 @@ static void remove_channel(struct Channel * channel) {
TRACE(("CLOSE errfd %d", channel->errfd))
close(channel->errfd);
if (!channel->close_handler_done
&& channel->type->closehandler) {
channel->type->closehandler(channel);
channel->close_handler_done = 1;
}
channel->typedata = NULL;
delete_channel(channel);
TRACE(("leave remove_channel"))
}
/* Remove a channel entry */
static void delete_channel(struct Channel *channel) {
ses.channels[channel->index] = NULL;
m_free(channel);
ses.chancount--;
TRACE(("leave remove_channel"))
}
/* Handle channel specific requests, passing off to corresponding handlers
* such as chansession or x11fwd */
void recv_msg_channel_request() {
struct Channel *channel;
TRACE(("enter recv_msg_channel_request"))
channel = getchannel();
TRACE(("enter recv_msg_channel_request %p", channel))
if (channel->sent_close) {
TRACE(("leave recv_msg_channel_request: already closed channel"))
return;
}
if (channel->type->reqhandler
&& !channel->close_handler_done) {
if (channel->type->reqhandler) {
channel->type->reqhandler(channel);
} else {
send_msg_channel_failure(channel);
@@ -637,7 +616,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 %zd", maxlen))
TRACE(("maxlen %d", maxlen))
if (maxlen == 0) {
TRACE(("leave send_msg_channel_data: no window"))
return;
@@ -655,7 +634,6 @@ 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
@@ -663,23 +641,11 @@ 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);
}
buf_setpos(ses.writepayload, 0);
buf_setlen(ses.writepayload, 0);
ses.writepayload->len = ses.writepayload->pos = 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 */
buf_setpos(ses.writepayload, size_pos);
@@ -722,10 +688,10 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd,
TRACE(("enter recv_msg_channel_data"))
if (channel->recv_eof) {
dropbear_exit("Received data after eof");
dropbear_exit("received data after eof");
}
if (fd < 0 || !cbuf) {
if (fd < 0) {
/* If we have encountered failed write, the far side might still
* be sending data without having yet received our close notification.
* We just drop the data. */
@@ -863,14 +829,12 @@ void recv_msg_channel_open() {
}
if (ret > 0) {
errtype = ret;
remove_channel(channel);
delete_channel(channel);
TRACE(("inithandler returned failure %d", ret))
goto failure;
}
}
chan_initwritebuf(channel);
/* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
@@ -1009,10 +973,6 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) {
return DROPBEAR_FAILURE;
}
/* Outbound opened channels don't make use of in-progress connections,
* we can set it up straight away */
chan_initwritebuf(chan);
/* set fd non-blocking */
setnonblocking(fd);
@@ -1046,7 +1006,7 @@ void recv_msg_channel_open_confirmation() {
channel = getchannel();
if (!channel->await_open) {
dropbear_exit("Unexpected channel reply");
dropbear_exit("unexpected channel reply");
}
channel->await_open = 0;
@@ -1078,7 +1038,7 @@ void recv_msg_channel_open_failure() {
channel = getchannel();
if (!channel->await_open) {
dropbear_exit("Unexpected channel reply");
dropbear_exit("unexpected channel reply");
}
channel->await_open = 0;

View File

@@ -32,13 +32,10 @@
#include "ssh.h"
#include "packet.h"
#include "bignum.h"
#include "dbrandom.h"
#include "runopts.h"
#include "ecc.h"
#include "crypto_desc.h"
#include "random.h"
/* diffie-hellman-group1-sha1 value for p */
const unsigned char dh_p_1[DH_P_1_LEN] = {
static const unsigned char dh_p_val[] = {
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,
@@ -50,46 +47,19 @@ const unsigned char dh_p_1[DH_P_1_LEN] = {
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#define DH_P_LEN sizeof(dh_p_val)
/* diffie-hellman-group14-sha1 value for p */
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,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2,
0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
/* Same for group1 and group14 */
static const int DH_G_VAL = 2;
static void kexinitialise();
static void gen_new_keys();
void gen_new_keys();
#ifndef DISABLE_ZLIB
static void gen_new_zstream_recv();
static void gen_new_zstream_trans();
static void gen_new_zstreams();
#endif
static void read_kex_algos();
/* helper function for gen_new_keys */
static void hashkeys(unsigned char *out, unsigned int outlen,
const hash_state * hs, const unsigned char X);
static void finish_kexhashbuf(void);
static void hashkeys(unsigned char *out, int outlen,
const hash_state * hs, unsigned const char X);
/* Send our list of algorithms we can use */
@@ -120,12 +90,11 @@ void send_msg_kexinit() {
/* mac_algorithms_server_to_client */
buf_put_algolist(ses.writepayload, sshhashes);
/* compression_algorithms_client_to_server */
buf_put_algolist(ses.writepayload, ses.compress_algos);
buf_put_algolist(ses.writepayload, sshcompress);
/* compression_algorithms_server_to_client */
buf_put_algolist(ses.writepayload, ses.compress_algos);
buf_put_algolist(ses.writepayload, sshcompress);
/* languages_client_to_server */
buf_putstring(ses.writepayload, "", 0);
@@ -133,8 +102,8 @@ void send_msg_kexinit() {
/* languages_server_to_client */
buf_putstring(ses.writepayload, "", 0);
/* first_kex_packet_follows */
buf_putbyte(ses.writepayload, (ses.send_kex_first_guess != NULL));
/* first_kex_packet_follows - unimplemented for now */
buf_putbyte(ses.writepayload, 0x00);
/* reserved unit32 */
buf_putint(ses.writepayload, 0);
@@ -146,60 +115,16 @@ 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;
}
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"))
}
/* *** 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.
*/
/* Bring new keys into use after a key exchange, and let the client know*/
void send_msg_newkeys() {
@@ -210,25 +135,44 @@ void send_msg_newkeys() {
CHECKCLEARTOWRITE();
buf_putbyte(ses.writepayload, SSH_MSG_NEWKEYS);
encrypt_packet();
/* set up our state */
ses.kexstate.sentnewkeys = 1;
ses.kexstate.donefirstkex = 1;
ses.dataallowed = 1; /* we can send other packets again now */
gen_new_keys();
switch_keys();
/* 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"))
}
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"))
ses.kexstate.recvnewkeys = 1;
switch_keys();
/* 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;
}
TRACE(("leave recv_msg_newkeys"))
}
@@ -236,16 +180,8 @@ void recv_msg_newkeys() {
/* Set up the kex for the first time */
void kexfirstinitialise() {
ses.kexstate.donefirstkex = 0;
#ifndef DISABLE_ZLIB
if (opts.enable_compress) {
ses.compress_algos = ssh_compress;
} else
#endif
{
ses.compress_algos = ssh_nocompress;
}
ses.kexstate.donefirstkex = 0;
kexinitialise();
}
@@ -263,13 +199,11 @@ static void kexinitialise() {
ses.kexstate.sentnewkeys = 0;
/* first_packet_follows */
ses.kexstate.them_firstfollows = 0;
ses.kexstate.firstfollows = 0;
ses.kexstate.datatrans = 0;
ses.kexstate.datarecv = 0;
ses.kexstate.our_first_follows_matches = 0;
ses.kexstate.lastkextime = time(NULL);
}
@@ -278,42 +212,38 @@ static void kexinitialise() {
* already initialised hash_state hs, which should already have processed
* the dh_K and hash, since these are common. X is the letter 'A', 'B' etc.
* out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated.
* The output will only be expanded once, as we are assured that
* outlen <= 2*SHA1_HASH_SIZE for all known hashes.
*
* See Section 7.2 of rfc4253 (ssh transport) for details */
static void hashkeys(unsigned char *out, unsigned int outlen,
static void hashkeys(unsigned char *out, 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;
unsigned int offset;
unsigned char tmpout[MAX_HASH_SIZE];
unsigned char k2[SHA1_HASH_SIZE]; /* used to extending */
memcpy(&hs2, hs, sizeof(hash_state));
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 += hash_desc->hashsize)
{
sha1_process(&hs2, &X, 1);
sha1_process(&hs2, ses.session_id, SHA1_HASH_SIZE);
sha1_done(&hs2, out);
if (SHA1_HASH_SIZE < outlen) {
/* need to extend */
memcpy(&hs2, hs, sizeof(hash_state));
hash_desc->process(&hs2, out, offset);
hash_desc->done(&hs2, tmpout);
memcpy(&out[offset], tmpout, MIN(outlen - offset, hash_desc->hashsize));
sha1_process(&hs2, out, SHA1_HASH_SIZE);
sha1_done(&hs2, k2);
memcpy(&out[SHA1_HASH_SIZE], k2, outlen - SHA1_HASH_SIZE);
}
}
/* Generate the actual encryption/integrity keys, using the results of the
* key exchange, as specified in section 7.2 of the transport rfc 4253.
* This occurs after the DH key-exchange.
* key exchange, as specified in section 5.2 of the IETF secsh-transport
* draft. This occurs after the DH key-exchange.
*
* 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 */
static void gen_new_keys() {
/* Originally from kex.c, generalized for cli/svr mode --mihnea */
void gen_new_keys() {
unsigned char C2S_IV[MAX_IV_LEN];
unsigned char C2S_key[MAX_KEY_LEN];
@@ -323,26 +253,27 @@ static void gen_new_keys() {
unsigned char *trans_IV, *trans_key, *recv_IV, *recv_key;
hash_state hs;
const struct ltc_hash_descriptor *hash_desc = ses.newkeys->algo_kex->hash_desc;
unsigned int C2S_keysize, S2C_keysize;
char mactransletter, macrecvletter; /* Client or server specific */
int recv_cipher = 0, trans_cipher = 0;
TRACE(("enter gen_new_keys"))
/* the dh_K and hash are the start of all hashes, we make use of that */
hash_desc->init(&hs);
hash_process_mp(hash_desc, &hs, ses.dh_K);
sha1_init(&hs);
sha1_process_mp(&hs, ses.dh_K);
mp_clear(ses.dh_K);
m_free(ses.dh_K);
hash_desc->process(&hs, ses.hash->data, ses.hash->len);
buf_burn(ses.hash);
buf_free(ses.hash);
ses.hash = NULL;
sha1_process(&hs, ses.hash, SHA1_HASH_SIZE);
m_burn(ses.hash, SHA1_HASH_SIZE);
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 {
@@ -350,59 +281,52 @@ static 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, 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');
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');
if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
if (recv_cipher < 0)
dropbear_exit("Crypto error");
if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
recv_IV, recv_key,
ses.newkeys->recv.algo_crypt->keysize, 0,
&ses.newkeys->recv.cipher_state) != CRYPT_OK) {
dropbear_exit("Crypto error");
}
recv_cipher = find_cipher(ses.newkeys->recv_algo_crypt->cipherdesc->name);
if (recv_cipher < 0)
dropbear_exit("crypto error");
if (ses.newkeys->recv_crypt_mode->start(recv_cipher,
recv_IV, recv_key,
ses.newkeys->recv_algo_crypt->keysize, 0,
&ses.newkeys->recv_cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error");
}
if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
if (trans_cipher < 0)
dropbear_exit("Crypto error");
if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
trans_IV, trans_key,
ses.newkeys->trans.algo_crypt->keysize, 0,
&ses.newkeys->trans.cipher_state) != CRYPT_OK) {
dropbear_exit("Crypto error");
}
trans_cipher = find_cipher(ses.newkeys->trans_algo_crypt->cipherdesc->name);
if (trans_cipher < 0)
dropbear_exit("crypto error");
if (ses.newkeys->trans_crypt_mode->start(trans_cipher,
trans_IV, trans_key,
ses.newkeys->trans_algo_crypt->keysize, 0,
&ses.newkeys->trans_cipher_state) != CRYPT_OK) {
dropbear_exit("crypto error");
}
/* MAC keys */
hashkeys(ses.newkeys->transmackey,
ses.newkeys->trans_algo_mac->keysize, &hs, mactransletter);
hashkeys(ses.newkeys->recvmackey,
ses.newkeys->recv_algo_mac->keysize, &hs, macrecvletter);
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->hash_desc->name);
}
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->hash_desc->name);
}
/* 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));
#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;
TRACE(("leave gen_new_keys"))
}
@@ -410,68 +334,63 @@ static void gen_new_keys() {
#ifndef DISABLE_ZLIB
int is_compress_trans() {
return ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB
return ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone
&& ses.keys->trans.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
&& ses.keys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
}
int is_compress_recv() {
return ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB
return ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB
|| (ses.authstate.authdone
&& ses.keys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
&& ses.keys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY);
}
/* Set up new zlib compression streams, close the old ones. Only
* called from gen_new_keys() */
static void gen_new_zstream_recv() {
static void gen_new_zstreams() {
/* create new zstreams */
if (ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv.algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv.zstream->zalloc = Z_NULL;
ses.newkeys->recv.zstream->zfree = Z_NULL;
if (ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->recv_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->recv_zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->recv_zstream->zalloc = Z_NULL;
ses.newkeys->recv_zstream->zfree = Z_NULL;
if (inflateInit(ses.newkeys->recv.zstream) != Z_OK) {
if (inflateInit(ses.newkeys->recv_zstream) != Z_OK) {
dropbear_exit("zlib error");
}
} else {
ses.newkeys->recv.zstream = NULL;
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) {
ses.newkeys->trans.zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans.zstream->zalloc = Z_NULL;
ses.newkeys->trans.zstream->zfree = Z_NULL;
if (ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB
|| ses.newkeys->trans_algo_comp == DROPBEAR_COMP_ZLIB_DELAY) {
ses.newkeys->trans_zstream = (z_streamp)m_malloc(sizeof(z_stream));
ses.newkeys->trans_zstream->zalloc = Z_NULL;
ses.newkeys->trans_zstream->zfree = Z_NULL;
if (deflateInit2(ses.newkeys->trans.zstream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, DROPBEAR_ZLIB_WINDOW_BITS,
DROPBEAR_ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY)
if (deflateInit(ses.newkeys->trans_zstream, Z_DEFAULT_COMPRESSION)
!= Z_OK) {
dropbear_exit("zlib error");
}
} else {
ses.newkeys->trans.zstream = NULL;
ses.newkeys->trans_zstream = NULL;
}
if (ses.keys->trans.zstream != NULL) {
if (deflateEnd(ses.keys->trans.zstream) == Z_STREAM_ERROR) {
/* 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");
dropbear_exit("crypto error");
}
m_free(ses.keys->trans.zstream);
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 */
dropbear_exit("crypto error");
}
m_free(ses.keys->trans_zstream);
}
}
#endif /* DISABLE_ZLIB */
@@ -483,6 +402,9 @@ static void gen_new_zstream_trans() {
* 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;
@@ -525,7 +447,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 */
@@ -557,29 +479,21 @@ void recv_msg_kexinit() {
TRACE(("leave recv_msg_kexinit"))
}
static void load_dh_p(mp_int * dh_p)
{
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 */
* See the ietf-secsh-transport draft, section 6, for details */
/* dh_pub and dh_priv MUST be already initialised */
struct kex_dh_param *gen_kexdh_param() {
struct kex_dh_param *param = NULL;
void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
DEF_MP_INT(dh_p);
DEF_MP_INT(dh_q);
DEF_MP_INT(dh_g);
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);
TRACE(("enter send_msg_kexdh_reply"))
m_mp_init_multi(&dh_g, &dh_p, &dh_q, NULL);
/* read the prime and generator*/
load_dh_p(&dh_p);
bytes_to_mp(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN);
if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
@@ -587,43 +501,37 @@ struct kex_dh_param *gen_kexdh_param() {
/* calculate q = (p-1)/2 */
/* dh_priv is just a temp var here */
if (mp_sub_d(&dh_p, 1, &param->priv) != MP_OKAY) {
if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
if (mp_div_2(&param->priv, &dh_q) != MP_OKAY) {
if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
dropbear_exit("Diffie-Hellman error");
}
/* Generate a private portion 0 < dh_priv < dh_q */
gen_random_mpint(&dh_q, &param->priv);
gen_random_mpint(&dh_q, dh_priv);
/* f = g^y mod p */
if (mp_exptmod(&dh_g, &param->priv, &dh_p, &param->pub) != MP_OKAY) {
if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_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(struct kex_dh_param *param, mp_int *dh_pub_them,
void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, 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);
load_dh_p(&dh_p);
bytes_to_mp(&dh_p, dh_p_val, DH_P_LEN);
/* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
@@ -632,8 +540,9 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
}
/* K = e^y mod p = f^x mod p */
m_mp_alloc_init_multi(&ses.dh_K, NULL);
if (mp_exptmod(dh_pub_them, &param->priv, &dh_p, ses.dh_K) != MP_OKAY) {
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) {
dropbear_exit("Diffie-Hellman error");
}
@@ -643,11 +552,11 @@ void kexdh_comb_key(struct kex_dh_param *param, 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 = &param->pub;
dh_e = dh_pub_us;
dh_f = dh_pub_them;
} else {
dh_e = dh_pub_them;
dh_f = &param->pub;
dh_f = dh_pub_us;
}
/* Create the remainder of the hash buffer, to generate the exchange hash */
@@ -661,138 +570,11 @@ void kexdh_comb_key(struct kex_dh_param *param, mp_int *dh_pub_them,
buf_putmpint(ses.kexhashbuf, ses.dh_K);
/* calculate the hash H to sign */
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);
sha1_init(&hs);
buf_setpos(ses.kexhashbuf, 0);
hash_desc->process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
ses.kexhashbuf->len);
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);
#ifdef DEBUG_KEXHASH
printhex("kexhashbuf", ses.kexhashbuf->data, ses.kexhashbuf->len);
printhex("kexhash", ses.hash->data, ses.hash->len);
#endif
sha1_done(&hs, ses.hash);
buf_burn(ses.kexhashbuf);
buf_free(ses.kexhashbuf);
@@ -801,9 +583,9 @@ static void finish_kexhashbuf(void) {
/* 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 = buf_newcopy(ses.hash);
ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
}
}
/* read the other side's algo list. buf_match_algo is a callback to match
@@ -827,29 +609,22 @@ 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 */
memset(ses.newkeys, 0x0, sizeof(*ses.newkeys));
ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
/* kex_algorithms */
algo = buf_match_algo(ses.payload, sshkex, &kexguess2, &goodguess);
algo = ses.buf_match_algo(ses.payload, sshkex, &goodguess);
allgood &= goodguess;
if (algo == NULL || algo->val == KEXGUESS2_ALGO_ID) {
if (algo == NULL) {
erralgo = "kex";
goto error;
}
TRACE(("kexguess2 %d", kexguess2))
TRACE(("kex algo %s", algo->name))
ses.newkeys->algo_kex = algo->data;
ses.newkeys->algo_kex = algo->val;
/* server_host_key_algorithms */
algo = buf_match_algo(ses.payload, sshhostkey, &kexguess2, &goodguess);
algo = ses.buf_match_algo(ses.payload, sshhostkey, &goodguess);
allgood &= goodguess;
if (algo == NULL) {
erralgo = "hostkey";
@@ -859,7 +634,7 @@ static void read_kex_algos() {
ses.newkeys->algo_hostkey = algo->val;
/* encryption_algorithms_client_to_server */
c2s_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
c2s_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (c2s_cipher_algo == NULL) {
erralgo = "enc c->s";
goto error;
@@ -867,7 +642,7 @@ static void read_kex_algos() {
TRACE(("enc c2s is %s", c2s_cipher_algo->name))
/* encryption_algorithms_server_to_client */
s2c_cipher_algo = buf_match_algo(ses.payload, sshciphers, NULL, NULL);
s2c_cipher_algo = ses.buf_match_algo(ses.payload, sshciphers, &goodguess);
if (s2c_cipher_algo == NULL) {
erralgo = "enc s->c";
goto error;
@@ -875,7 +650,7 @@ static void read_kex_algos() {
TRACE(("enc s2c is %s", s2c_cipher_algo->name))
/* mac_algorithms_client_to_server */
c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
c2s_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (c2s_hash_algo == NULL) {
erralgo = "mac c->s";
goto error;
@@ -883,7 +658,7 @@ static void read_kex_algos() {
TRACE(("hash c2s is %s", c2s_hash_algo->name))
/* mac_algorithms_server_to_client */
s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
s2c_hash_algo = ses.buf_match_algo(ses.payload, sshhashes, &goodguess);
if (s2c_hash_algo == NULL) {
erralgo = "mac s->c";
goto error;
@@ -891,7 +666,7 @@ static void read_kex_algos() {
TRACE(("hash s2c is %s", s2c_hash_algo->name))
/* compression_algorithms_client_to_server */
c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
c2s_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (c2s_comp_algo == NULL) {
erralgo = "comp c->s";
goto error;
@@ -899,7 +674,7 @@ static void read_kex_algos() {
TRACE(("hash c2s is %s", c2s_comp_algo->name))
/* compression_algorithms_server_to_client */
s2c_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
s2c_comp_algo = ses.buf_match_algo(ses.payload, sshcompress, &goodguess);
if (s2c_comp_algo == NULL) {
erralgo = "comp s->c";
goto error;
@@ -912,10 +687,9 @@ static void read_kex_algos() {
/* languages_server_to_client */
buf_eatstring(ses.payload);
/* their first_kex_packet_follows */
/* first_kex_packet_follows */
if (buf_getbool(ses.payload)) {
TRACE(("them kex firstfollows. allgood %d", allgood))
ses.kexstate.them_firstfollows = 1;
ses.kexstate.firstfollows = 1;
/* if the guess wasn't good, we ignore the packet sent */
if (!allgood) {
ses.ignorenext = 1;
@@ -924,47 +698,42 @@ static void read_kex_algos() {
/* Handle the asymmetry */
if (IS_DROPBEAR_CLIENT) {
ses.newkeys->recv.algo_crypt =
ses.newkeys->recv_algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->trans.algo_crypt =
ses.newkeys->trans_algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->recv.crypt_mode =
ses.newkeys->recv_crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->trans.crypt_mode =
ses.newkeys->trans_crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->recv.algo_mac =
ses.newkeys->recv_algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->trans.algo_mac =
ses.newkeys->trans_algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
ses.newkeys->recv_algo_comp = s2c_comp_algo->val;
ses.newkeys->trans_algo_comp = c2s_comp_algo->val;
} else {
/* SERVER */
ses.newkeys->recv.algo_crypt =
ses.newkeys->recv_algo_crypt =
(struct dropbear_cipher*)c2s_cipher_algo->data;
ses.newkeys->trans.algo_crypt =
ses.newkeys->trans_algo_crypt =
(struct dropbear_cipher*)s2c_cipher_algo->data;
ses.newkeys->recv.crypt_mode =
ses.newkeys->recv_crypt_mode =
(struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
ses.newkeys->trans.crypt_mode =
ses.newkeys->trans_crypt_mode =
(struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
ses.newkeys->recv.algo_mac =
ses.newkeys->recv_algo_mac =
(struct dropbear_hash*)c2s_hash_algo->data;
ses.newkeys->trans.algo_mac =
ses.newkeys->trans_algo_mac =
(struct dropbear_hash*)s2c_hash_algo->data;
ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
ses.newkeys->recv_algo_comp = c2s_comp_algo->val;
ses.newkeys->trans_algo_comp = s2c_comp_algo->val;
}
/* 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:
dropbear_exit("No matching algo %s", erralgo);
dropbear_exit("no matching algo %s", erralgo);
}

View File

@@ -28,15 +28,12 @@
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
#include "algo.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,
enum signkey_type *type) {
int readhostkey(const char * filename, sign_key * hostkey, int *type) {
int ret = DROPBEAR_FAILURE;
buffer *buf;
@@ -47,9 +44,6 @@ int readhostkey(const char * filename, sign_key * hostkey,
goto out;
}
buf_setpos(buf, 0);
addrandom(buf_getptr(buf, buf->len), buf->len);
if (buf_get_priv_key(buf, hostkey, type) == DROPBEAR_FAILURE) {
goto out;
}
@@ -61,48 +55,3 @@ out:
buf_free(buf);
return ret;
}
#ifdef ENABLE_USER_ALGO_LIST
void
parse_ciphers_macs()
{
if (opts.cipher_list)
{
if (strcmp(opts.cipher_list, "help") == 0)
{
char *ciphers = algolist_string(sshciphers);
dropbear_log(LOG_INFO, "Available ciphers:\n%s\n", ciphers);
m_free(ciphers);
dropbear_exit(".");
}
if (strcmp(opts.cipher_list, "none") == 0)
{
/* Encryption is required during authentication */
opts.cipher_list = "none,aes128-ctr";
}
if (check_user_algos(opts.cipher_list, sshciphers, "cipher") == 0)
{
dropbear_exit("No valid ciphers specified for '-c'");
}
}
if (opts.mac_list)
{
if (strcmp(opts.mac_list, "help") == 0)
{
char *macs = algolist_string(sshhashes);
dropbear_log(LOG_INFO, "Available MACs:\n%s\n", macs);
m_free(macs);
dropbear_exit(".");
}
if (check_user_algos(opts.mac_list, sshhashes, "MAC") == 0)
{
dropbear_exit("No valid MACs specified for '-m'");
}
}
}
#endif

View File

@@ -30,15 +30,15 @@
#include "buffer.h"
#include "dss.h"
#include "ssh.h"
#include "dbrandom.h"
#include "random.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,11 +49,15 @@ 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) {
void common_session_init(int sock_in, int sock_out, char* remotehost) {
TRACE(("enter session_init"))
ses.remotehost = remotehost;
ses.sock_in = sock_in;
ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out);
@@ -63,13 +67,10 @@ void common_session_init(int sock_in, int sock_out) {
ses.last_packet_time = 0;
if (pipe(ses.signal_pipe) < 0) {
dropbear_exit("Signal pipe failed");
dropbear_exit("signal pipe failed");
}
setnonblocking(ses.signal_pipe[0]);
setnonblocking(ses.signal_pipe[1]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[0]);
ses.maxfd = MAX(ses.maxfd, ses.signal_pipe[1]);
kexfirstinitialise(); /* initialise the kex state */
@@ -77,6 +78,7 @@ void common_session_init(int sock_in, int sock_out) {
ses.transseq = 0;
ses.readbuf = NULL;
ses.decryptreadbuf = NULL;
ses.payload = NULL;
ses.recvseq = 0;
@@ -93,22 +95,22 @@ void common_session_init(int sock_in, int sock_out) {
/* set all the algos to none */
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
ses.newkeys = NULL;
ses.keys->recv.algo_crypt = &dropbear_nocipher;
ses.keys->trans.algo_crypt = &dropbear_nocipher;
ses.keys->recv.crypt_mode = &dropbear_mode_none;
ses.keys->trans.crypt_mode = &dropbear_mode_none;
ses.keys->recv_algo_crypt = &dropbear_nocipher;
ses.keys->trans_algo_crypt = &dropbear_nocipher;
ses.keys->recv_crypt_mode = &dropbear_mode_none;
ses.keys->trans_crypt_mode = &dropbear_mode_none;
ses.keys->recv.algo_mac = &dropbear_nohash;
ses.keys->trans.algo_mac = &dropbear_nohash;
ses.keys->recv_algo_mac = &dropbear_nohash;
ses.keys->trans_algo_mac = &dropbear_nohash;
ses.keys->algo_kex = NULL;
ses.keys->algo_kex = -1;
ses.keys->algo_hostkey = -1;
ses.keys->recv.algo_comp = DROPBEAR_COMP_NONE;
ses.keys->trans.algo_comp = DROPBEAR_COMP_NONE;
ses.keys->recv_algo_comp = DROPBEAR_COMP_NONE;
ses.keys->trans_algo_comp = DROPBEAR_COMP_NONE;
#ifndef DISABLE_ZLIB
ses.keys->recv.zstream = NULL;
ses.keys->trans.zstream = NULL;
ses.keys->recv_zstream = NULL;
ses.keys->trans_zstream = NULL;
#endif
/* key exchange buffers */
@@ -139,10 +141,7 @@ void session_loop(void(*loophandler)()) {
FD_ZERO(&writefd);
FD_ZERO(&readfd);
dropbear_assert(ses.payload == NULL);
/* 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))) {
if (ses.sock_in != -1) {
FD_SET(ses.sock_in, &readfd);
}
if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
@@ -153,9 +152,10 @@ 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 can be read/written */
setchannelfds(&readfd, &writefd);
/* set up for channels which require reading/writing */
if (ses.dataallowed) {
setchannelfds(&readfd, &writefd);
}
val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);
if (exitflag) {
@@ -195,12 +195,7 @@ void session_loop(void(*loophandler)()) {
if (ses.sock_in != -1) {
if (FD_ISSET(ses.sock_in, &readfd)) {
if (!ses.remoteident) {
/* blocking read of the version string */
read_session_identification();
} else {
read_packet();
}
read_packet();
}
/* Process the decrypted packet. After this, the read buffer
@@ -216,7 +211,9 @@ void session_loop(void(*loophandler)()) {
/* process pipes etc for the channels, ses.dataallowed == 0
* during rekeying ) */
channelio(&readfd, &writefd);
if (ses.dataallowed) {
channelio(&readfd, &writefd);
}
if (loophandler) {
loophandler();
@@ -228,7 +225,7 @@ void session_loop(void(*loophandler)()) {
}
/* clean up a session on exit */
void session_cleanup() {
void common_session_cleanup() {
TRACE(("enter session_cleanup"))
@@ -237,45 +234,31 @@ void session_cleanup() {
TRACE(("leave session_cleanup: !sessinitdone"))
return;
}
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_free(ses.session_id);
m_burn(ses.keys, sizeof(struct key_context));
m_free(ses.keys);
chancleanup();
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);
}
static void read_session_identification() {
void 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));
@@ -470,20 +453,6 @@ void fill_passwd(const char* username) {
ses.authstate.pw_name = m_strdup(pw->pw_name);
ses.authstate.pw_dir = m_strdup(pw->pw_dir);
ses.authstate.pw_shell = m_strdup(pw->pw_shell);
{
char *passwd_crypt = pw->pw_passwd;
#ifdef HAVE_SHADOW_H
/* get the shadow password if possible */
struct spwd *spasswd = getspnam(ses.authstate.pw_name);
if (spasswd && spasswd->sp_pwdp) {
passwd_crypt = spasswd->sp_pwdp;
}
#endif
if (!passwd_crypt) {
/* android supposedly returns NULL */
passwd_crypt = "!!";
}
ses.authstate.pw_passwd = m_strdup(passwd_crypt);
}
ses.authstate.pw_passwd = m_strdup(pw->pw_passwd);
}

View File

@@ -193,10 +193,6 @@ int daemon(int nochdir, int noclose) {
char *basename(const char *path) {
char *foo = strrchr(path, '/');
if (!foo)
{
return path;
}
return ++foo;
}

647
config.guess vendored
View File

@@ -1,12 +1,14 @@
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2013 Free Software Foundation, Inc.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
# Inc.
timestamp='2013-06-10'
timestamp='2007-01-15'
# 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
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -15,23 +17,27 @@ timestamp='2013-06-10'
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# 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. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
# Originally written by Per Bothner.
#
# 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.
# 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.
#
# 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.
#
# The plan is that this can be called by configure scripts if you
# don't specify an explicit build system type.
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
@@ -50,7 +56,8 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
Copyright 1992-2013 Free Software Foundation, Inc.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
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."
@@ -132,33 +139,12 @@ 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 tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
@@ -184,7 +170,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 -q __ELF__
| grep __ELF__ >/dev/null
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
@@ -194,7 +180,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
fi
;;
*)
os=netbsd
os=netbsd
;;
esac
# The OS release
@@ -215,10 +201,6 @@ 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}
@@ -241,7 +223,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
@@ -287,10 +269,7 @@ 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'`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
exit $exitcode ;;
exit ;;
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
@@ -316,12 +295,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:*:*)
@@ -345,33 +324,14 @@ 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: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/[^.]*//'`
i86pc:SunOS:5.*:*)
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
@@ -415,23 +375,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 ;;
@@ -501,8 +461,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 ] || \
@@ -515,7 +475,7 @@ EOF
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
exit ;;
exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit ;;
@@ -572,7 +532,7 @@ EOF
echo rs6000-ibm-aix3.2
fi
exit ;;
*:AIX:*:[4567])
*:AIX:*:[45])
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
@@ -615,52 +575,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
@@ -680,7 +640,7 @@ EOF
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
grep __LP64__ >/dev/null
then
HP_ARCH="hppa2.0w"
else
@@ -751,22 +711,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 ;;
@@ -790,14 +750,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}
@@ -809,51 +769,37 @@ EOF
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
case ${UNAME_PROCESSOR} in
case ${UNAME_MACHINE} in
pc98)
echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
amd64)
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
echo ${UNAME_MACHINE}-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 ;;
*: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 ;;
x86:Interix*:[3456]*)
echo i586-pc-interix${UNAME_RELEASE}
exit ;;
EM64T:Interix*:[3456]* | authenticamd:Interix*:[3456]*)
echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;;
[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
@@ -874,21 +820,93 @@ EOF
exit ;;
*:GNU:*:*)
# the GNU system
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`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/[-(].*//'`-${LIBC}
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
aarch64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
arm*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
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
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -899,132 +917,106 @@ EOF
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
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}
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}
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-${LIBC} ;;
PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
*) echo hppa-unknown-linux-${LIBC} ;;
PA7*) echo hppa1.1-unknown-linux-gnu ;;
PA8*) echo hppa2.0-unknown-linux-gnu ;;
*) echo hppa-unknown-linux-gnu ;;
esac
exit ;;
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}
parisc64:Linux:*:* | hppa64:Linux:*:*)
echo hppa64-unknown-linux-gnu
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
echo ${UNAME_MACHINE}-ibm-linux
exit ;;
sh64*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
tile*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
echo ${UNAME_MACHINE}-dec-linux-gnu
exit ;;
x86_64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
echo x86_64-unknown-linux-gnu
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
xtensa:Linux:*:*)
echo xtensa-unknown-linux-gnu
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
@@ -1032,11 +1024,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:*:*)
@@ -1053,7 +1045,7 @@ EOF
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;;
i*86:*DOS:*:*)
@@ -1068,7 +1060,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 ;;
@@ -1096,13 +1088,10 @@ 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 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 ;;
# 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 ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit ;;
@@ -1137,18 +1126,8 @@ 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; } ;;
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; } ;;
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;;
@@ -1161,7 +1140,7 @@ EOF
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;;
SM[BE]S:UNIX_SV:*:*)
@@ -1181,10 +1160,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
@@ -1210,11 +1189,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 ;;
@@ -1224,12 +1203,6 @@ 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 ;;
@@ -1256,21 +1229,9 @@ EOF
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
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
case $UNAME_PROCESSOR in
unknown) UNAME_PROCESSOR=powerpc ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
@@ -1284,10 +1245,7 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
NEO-?:NONSTOP_KERNEL:*:*)
echo neo-tandem-nsk${UNAME_RELEASE}
exit ;;
NSE-*:NONSTOP_KERNEL:*:*)
NSE-?:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
NSR-?:NONSTOP_KERNEL:*:*)
@@ -1332,13 +1290,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 ;;
@@ -1353,14 +1311,11 @@ 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_
@@ -1378,11 +1333,11 @@ main ()
#include <sys/param.h>
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
"4"
"4"
#else
""
""
#endif
); exit (0);
); exit (0);
#endif
#endif
@@ -1516,9 +1471,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://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
and
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
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,40 +1,44 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2013 Free Software Foundation, Inc.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
# Inc.
timestamp='2013-10-01'
timestamp='2007-01-18'
# 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
# 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
# (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, see <http://www.gnu.org/licenses/>.
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# 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. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
# the same distribution terms that you use for the rest of that program.
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
# Please send patches to <config-patches@gnu.org>. Submit a context
# diff and a properly formatted ChangeLog entry.
#
# 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.
@@ -68,7 +72,8 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright 1992-2013 Free Software Foundation, Inc.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
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."
@@ -115,18 +120,12 @@ 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-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-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 ]
@@ -149,13 +148,10 @@ 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 | -microblaze*)
-apple | -axis | -knuth | -cray)
os=
basic_machine=$1
;;
-bluegene*)
os=-cnk
;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
@@ -170,10 +166,10 @@ case $os in
os=-chorusos
basic_machine=$1
;;
-chorusrdb)
os=-chorusrdb
-chorusrdb)
os=-chorusrdb
basic_machine=$1
;;
;;
-hiux*)
os=-hiuxwe2
;;
@@ -218,12 +214,6 @@ 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
;;
@@ -248,35 +238,24 @@ 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 | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
| be32 | be64 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
| bfin \
| c4x | c8051 | clipper \
| c4x | 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 | microblazeel | mcore | mep | metag \
| maxq | mb | microblaze | mcore | mep \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
| mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \
| mips64r5900 | mips64r5900el \
| mips64vr | mips64vrel \
| mips64orion | mips64orionel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
@@ -287,45 +266,31 @@ case $basic_machine in
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| moxie \
| mt \
| msp430 \
| nds32 | nds32le | nds32be \
| nios | nios2 | nios2eb | nios2el \
| nios | nios2 \
| ns16k | ns32k \
| open8 \
| or1k | or32 \
| or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| rl78 | rx \
| score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh | sh[1234] | sh[24]a | 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 \
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| spu | strongarm \
| tahoe | thumb | tic4x | tic80 | tron \
| v850 | v850e \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
| z8k)
basic_machine=$basic_machine-unknown
;;
c54x)
basic_machine=tic54x-unknown
;;
c55x)
basic_machine=tic55x-unknown
;;
c6x)
basic_machine=tic6x-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
m6811 | m68hc11 | m6812 | m68hc12)
# Motorola 68HC11/12.
basic_machine=$basic_machine-unknown
os=-none
;;
@@ -335,21 +300,6 @@ 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.
@@ -364,38 +314,29 @@ 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-* | arceb-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
| 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-* | metag-* \
| microblaze-* | microblazeel-* \
| m88110-* | m88k-* | maxq-* | mcore-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
| mips64octeon-* | mips64octeonel-* \
| mips64orion-* | mips64orionel-* \
| mips64r5900-* | mips64r5900el-* \
| mips64vr-* | mips64vrel-* \
| mips64orion-* | mips64orionel-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
@@ -406,41 +347,31 @@ case $basic_machine in
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipsr5900-* | mipsr5900el-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nds32-* | nds32le-* | nds32be-* \
| nios-* | nios2-* | nios2eb-* | nios2el-* \
| nios-* | nios2-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| open8-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| romp-* | rs6000-* \
| sh-* | sh[1234]-* | sh[24]a-* | 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-* | sv1-* | sx?-* \
| tahoe-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
| tahoe-* | thumb-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
| tron-* \
| ubicom32-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| v850-* | v850e-* | vax-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
| xstormy16-* | xtensa-* \
| ymp-* \
| z8k-* | z80-*)
;;
# Recognize the basic CPU types without company name, with glob match.
xtensa*)
basic_machine=$basic_machine-unknown
| z8k-*)
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -458,7 +389,7 @@ case $basic_machine in
basic_machine=a29k-amd
os=-udi
;;
abacus)
abacus)
basic_machine=abacus-unknown
;;
adobe68k)
@@ -504,10 +435,6 @@ case $basic_machine in
basic_machine=m68k-apollo
os=-bsd
;;
aros)
basic_machine=i386-pc
os=-aros
;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -516,35 +443,10 @@ 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
@@ -573,8 +475,8 @@ case $basic_machine in
basic_machine=craynv-cray
os=-unicosmp
;;
cr16 | cr16-*)
basic_machine=cr16-unknown
cr16c)
basic_machine=cr16c-unknown
os=-elf
;;
crds | unos)
@@ -612,10 +514,6 @@ case $basic_machine in
basic_machine=m88k-motorola
os=-sysv3
;;
dicos)
basic_machine=i686-pc
os=-dicos
;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
@@ -731,6 +629,7 @@ 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
@@ -769,14 +668,6 @@ 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
;;
@@ -788,21 +679,10 @@ 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=i686-pc
basic_machine=i386-pc
os=-mingw32
;;
mingw32ce)
basic_machine=arm-unknown
os=-mingw32ce
;;
miniframe)
basic_machine=m68000-convergent
;;
@@ -831,18 +711,10 @@ 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
@@ -907,12 +779,6 @@ 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
;;
@@ -943,14 +809,6 @@ 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
;;
@@ -995,10 +853,9 @@ case $basic_machine in
;;
power) basic_machine=power-ibm
;;
ppc | ppcbe) basic_machine=powerpc-unknown
ppc) basic_machine=powerpc-unknown
;;
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
@@ -1023,11 +880,7 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
rdos | rdos64)
basic_machine=x86_64-pc
os=-rdos
;;
rdos32)
rdos)
basic_machine=i386-pc
os=-rdos
;;
@@ -1096,9 +949,6 @@ 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
;;
@@ -1155,9 +1005,17 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
tile*)
basic_machine=$basic_machine-unknown
os=-linux-gnu
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tic55x | c55x*)
basic_machine=tic55x-unknown
os=-coff
;;
tic6x | c6x*)
basic_machine=tic6x-unknown
os=-coff
;;
tx39)
basic_machine=mipstx39-unknown
@@ -1226,9 +1084,6 @@ 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
@@ -1237,10 +1092,6 @@ 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
@@ -1279,7 +1130,7 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
@@ -1326,12 +1177,9 @@ 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|'`
;;
@@ -1352,23 +1200,21 @@ 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* | -cnk* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* | -aros* \
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -bitrig* | -openbsd* | -solidbsd* \
| -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* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
@@ -1376,7 +1222,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* | -es*)
| -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1415,7 +1261,7 @@ case $os in
-opened*)
os=-openedition
;;
-os400*)
-os400*)
os=-os400
;;
-wince*)
@@ -1464,7 +1310,7 @@ case $os in
-sinix*)
os=-sysv4
;;
-tpf*)
-tpf*)
os=-tpf
;;
-triton*)
@@ -1500,14 +1346,12 @@ case $os in
-aros*)
os=-aros
;;
-kaos*)
os=-kaos
;;
-zvmoe)
os=-zvmoe
;;
-dicos*)
os=-dicos
;;
-nacl*)
;;
-none)
;;
*)
@@ -1530,10 +1374,10 @@ else
# system, and we'll never get to this point.
case $basic_machine in
score-*)
score-*)
os=-elf
;;
spu-*)
spu-*)
os=-elf
;;
*-acorn)
@@ -1545,23 +1389,8 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
c4x-* | tic4x-*)
os=-coff
;;
c8051-*)
os=-elf
;;
hexagon-*)
os=-elf
;;
tic54x-*)
os=-coff
;;
tic55x-*)
os=-coff
;;
tic6x-*)
os=-coff
c4x-* | tic4x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
@@ -1581,11 +1410,14 @@ 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)
@@ -1594,9 +1426,6 @@ case $basic_machine in
mips*-*)
os=-elf
;;
or1k-*)
os=-elf
;;
or32-*)
os=-coff
;;
@@ -1615,7 +1444,7 @@ case $basic_machine in
*-ibm)
os=-aix
;;
*-knuth)
*-knuth)
os=-mmixware
;;
*-wec)
@@ -1720,7 +1549,7 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
-cnk*|-aix*)
-aix*)
vendor=ibm
;;
-beos*)

View File

@@ -5,9 +5,8 @@
# of the platform checks have been taken straight from OpenSSH's configure.ac
# Huge thanks to them for dealing with the horrible platform-specifics :)
AC_PREREQ(2.59)
AC_INIT
AC_CONFIG_SRCDIR(buffer.c)
AC_PREREQ(2.50)
AC_INIT(buffer.c)
OLDCFLAGS=$CFLAGS
# Checks for programs.
@@ -21,7 +20,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 -Wno-pointer-sign"
CFLAGS="-Os -W -Wall"
fi
# large file support is useful for scp
@@ -147,7 +146,6 @@ AC_ARG_ENABLE(pam,
if test "x$enableval" = "xyes"; then
AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***]))
AC_MSG_NOTICE(Enabling PAM)
AC_CHECK_FUNCS(pam_fail_delay)
else
AC_DEFINE(DISABLE_PAM,, Use PAM)
AC_MSG_NOTICE(Disabling PAM)
@@ -212,7 +210,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 sys/uio.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])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
@@ -222,8 +220,7 @@ AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_CHECK_TYPES([uint8_t, u_int8_t, uint16_t, u_int16_t, uint32_t, u_int32_t])
AC_CHECK_TYPES([struct sockaddr_storage])
AC_CHECK_TYPES([uint16_t, u_int16_t, struct sockaddr_storage])
AC_CHECK_TYPE([socklen_t], ,[
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
@@ -233,15 +230,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_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <sys/socket.h>
AC_TRY_COMPILE([
#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
])
@@ -261,11 +258,12 @@ 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE(
[
#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" ]
)
@@ -275,11 +273,12 @@ 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE(
[
#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,11 +288,12 @@ 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE(
[
#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" ]
)
@@ -303,12 +303,13 @@ if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
fi
AC_CACHE_CHECK([for struct addrinfo], ac_cv_have_struct_addrinfo, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE(
[
#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" ]
)
@@ -321,15 +322,15 @@ fi
# IRIX has a const char return value for gai_strerror()
AC_CHECK_FUNCS(gai_strerror,[
AC_DEFINE(HAVE_GAI_STRERROR)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE([
#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 *])])])
@@ -361,36 +362,6 @@ AC_CHECK_FUNCS(endutxent getutxent getutxid getutxline pututxline )
AC_CHECK_FUNCS(setutxent utmpxname)
AC_CHECK_FUNCS(logout updwtmp logwtmp)
AC_ARG_ENABLE(bundled-libtom,
[ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists.
--disable-bundled-libtom Force using system libtomcrypt/libtommath, fail if it does not exist.
Default is to use system if available, otherwise bundled.],
[
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(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)
]
)
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
dnl allow user to disable some login recording features
@@ -452,7 +423,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_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE([
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
@@ -464,13 +435,13 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#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_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE([
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_LASTLOG_H
@@ -479,8 +450,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
]],
[[ char *lastlog = _PATH_LASTLOG; ]])],
],
[ char *lastlog = _PATH_LASTLOG; ],
[ AC_MSG_RESULT(yes) ],
[
AC_MSG_RESULT(no)
@@ -509,14 +480,14 @@ fi
dnl utmp detection
AC_MSG_CHECKING([if your system defines UTMP_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE([
#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 ]
@@ -539,16 +510,14 @@ fi
dnl wtmp detection
AC_MSG_CHECKING([if your system defines WTMP_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE([
#include <sys/types.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#include <utmp.h>
#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 ]
@@ -574,7 +543,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_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE([
#include <sys/types.h>
#include <utmp.h>
#ifdef HAVE_UTMPX_H
@@ -583,8 +552,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#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 ]
@@ -599,19 +568,17 @@ fi
dnl wtmpx detection
AC_MSG_CHECKING([if your system defines WTMPX_FILE])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_TRY_COMPILE([
#include <sys/types.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
#include <utmp.h>
#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 ]
@@ -628,16 +595,15 @@ fi
AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo fork writev])
AC_TYPE_SIGNAL
AC_CHECK_FUNCS([dup2 getspnam getusershell memset putenv select socket strdup clearenv strlcpy strlcat daemon basename _getpty getaddrinfo freeaddrinfo getnameinfo])
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
if test -e /dev/ptmx ; then
AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx)
fi
AC_CHECK_FILE("/dev/ptmx", AC_DEFINE(USE_DEV_PTMX,,Use /dev/ptmx))
else
AC_MSG_NOTICE([Not checking for /dev/ptmx, we're cross-compiling])
fi
@@ -645,9 +611,7 @@ fi
if test -z "$no_ptc_check" ; then
if test x"$cross_compiling" = x"no" ; then
if test -e /dev/ptc ; then
AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts)
fi
AC_CHECK_FILE("/dev/ptc", AC_DEFINE(HAVE_DEV_PTS_AND_PTC,,Use /dev/ptc & /dev/pts))
else
AC_MSG_NOTICE([Not checking for /dev/ptc & /dev/pts since we're cross-compiling])
fi
@@ -687,7 +651,6 @@ 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)
@@ -695,27 +658,17 @@ 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/prngs)
AS_MKDIR_P(libtomcrypt/src/prng)
AC_CONFIG_HEADER(config.h)
AC_CONFIG_FILES(Makefile libtomcrypt/Makefile libtommath/Makefile)
AC_OUTPUT
AC_MSG_NOTICE()
if test $BUNDLED_LIBTOM = 1 ; then
AC_MSG_NOTICE(Using bundled libtomcrypt and libtommath)
else
AC_MSG_NOTICE(Using system libtomcrypt and libtommath)
fi
AC_OUTPUT(Makefile)
AC_OUTPUT(libtomcrypt/Makefile)
AC_OUTPUT(libtommath/Makefile)
AC_MSG_NOTICE()
AC_MSG_NOTICE(Now edit options.h to choose features.)

View File

@@ -1,75 +0,0 @@
#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
}

View File

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

View File

@@ -1,734 +0,0 @@
/* Copyright 2008, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* curve25519-donna: Curve25519 elliptic curve, public key function
*
* http://code.google.com/p/curve25519-donna/
*
* Adam Langley <agl@imperialviolet.org>
*
* Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
*
* More information about curve25519 can be found here
* http://cr.yp.to/ecdh.html
*
* djb's sample implementation of curve25519 is written in a special assembly
* language called qhasm and uses the floating point registers.
*
* This is, almost, a clean room reimplementation from the curve25519 paper. It
* uses many of the tricks described therein. Only the crecip function is taken
* from the sample implementation.
*/
#include <string.h>
#include <stdint.h>
#ifdef _MSC_VER
#define inline __inline
#endif
typedef uint8_t u8;
typedef int32_t s32;
typedef int64_t limb;
/* Field element representation:
*
* Field elements are written as an array of signed, 64-bit limbs, least
* significant first. The value of the field element is:
* x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...
*
* i.e. the limbs are 26, 25, 26, 25, ... bits wide.
*/
/* Sum two numbers: output += in */
static void fsum(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; i += 2) {
output[0+i] = (output[0+i] + in[0+i]);
output[1+i] = (output[1+i] + in[1+i]);
}
}
/* Find the difference of two numbers: output = in - output
* (note the order of the arguments!)
*/
static void fdifference(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = (in[i] - output[i]);
}
}
/* Multiply a number by a scalar: output = in * scalar */
static void fscalar_product(limb *output, const limb *in, const limb scalar) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] * scalar;
}
}
/* Multiply two numbers: output = in2 * in
*
* output must be distinct to both inputs. The inputs are reduced coefficient
* form, the output is not.
*/
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 SSH client
dbclient \- lightweight SSH2 client
.SH SYNOPSIS
.B dbclient
[\-Tt] [\-p
@@ -15,28 +15,28 @@ dbclient \- lightweight SSH 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 client designed to be small enough to be used in small memory
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.
.SH OPTIONS
.TP
.B \-p \fIport
Connect to
Remote port.
Connect to port
.I port
on the remote host. Alternatively a port can be specified as hostname^port.
on the remote host.
Default is 22.
.TP
.B \-i \fIidfile
Identity file.
Read the identity key from file
Read the identity from file
.I idfile
(multiple allowed). This file is created with dropbearkey(1) or converted
from OpenSSH with dropbearconvert(1).
(multiple allowed).
.TP
.B \-L [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-L \fIlistenport\fR:\fIhost\fR:\fIport\fR
Local port forwarding.
Forward the port
.I listenport
@@ -45,7 +45,7 @@ on the local host through the SSH connection to port
on the host
.IR host .
.TP
.B \-R [\fIlistenaddress\fR]:\fIlistenport\fR:\fIhost\fR:\fIport\fR
.B \-R \fIlistenport\fR:\fIhost\fR:\fIport\fR
Remote port forwarding.
Forward the port
.I listenport
@@ -61,10 +61,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,13 +80,7 @@ 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. 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
OpenSSH-style agent program if available ($SSH_AUTH_SOCK will be set) for
public key authentication. Forwarding is only enabled if -A is specified.
connection will abort as normal.
.TP
.B \-W \fIwindowsize
Specify the per-channel receive window buffer size. Increasing this
@@ -112,22 +106,12 @@ comparing saved hostkeys.
"Netcat-alike" mode, where Dropbear will connect to the given host, then create a
forwarded connection to \fIendhost\fR. This will then be presented as dbclient's
standard input/output.
.TP
.B \-c \fIcipherlist
Specify a comma separated list of ciphers to enable. Use \fI-c help\fR to list possibilities.
.TP
.B \-m \fIMAClist
Specify a comma separated list of authentication MACs to enable. Use \fI-m help\fR to list possibilities.
.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
.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 hash (eg matt@martello^44 ).
A port for a host can be specified with a slash (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
@@ -137,11 +121,6 @@ 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
@@ -162,6 +141,6 @@ Mihnea Stoenescu wrote initial Dropbear client support
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dropbearkey(1)
dropbear(8), dropbearkey(8)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html
http://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -66,7 +66,7 @@ int main(int argc, char ** argv) {
#endif
}
fprintf(stderr, "Dropbear SSH multi-purpose v%s\n"
fprintf(stderr, "Dropbear multi-purpose version %s\n"
"Make a symlink pointing at this binary with one of the following names:\n"
#ifdef DBMULTI_dropbear
"'dropbear' - the Dropbear server\n"

285
dbutil.c
View File

@@ -57,11 +57,11 @@
#define MAX_FMT 100
static void generic_dropbear_exit(int exitcode, const char* format,
va_list param) ATTRIB_NORETURN;
va_list param);
static void generic_dropbear_log(int priority, const char* format,
va_list param);
void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN
void (*_dropbear_exit)(int exitcode, const char* format, va_list param)
= generic_dropbear_exit;
void (*_dropbear_log)(int priority, const char* format, va_list param)
= generic_dropbear_log;
@@ -111,7 +111,7 @@ static void generic_dropbear_exit(int exitcode, const char* format,
}
void fail_assert(const char* expr, const char* file, int line) {
dropbear_exit("Failed assertion (%s:%d): `%s'", file, line, expr);
dropbear_exit("failed assertion (%s:%d): `%s'", file, line, expr);
}
static void generic_dropbear_log(int UNUSED(priority), const char* format,
@@ -138,87 +138,41 @@ 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) %d.%d: ", getpid(), tv.tv_sec, 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(), tv.tv_sec, tv.tv_usec);
fprintf(stderr, "TRACE (%d): ", getpid());
vfprintf(stderr, format, param);
fprintf(stderr, "\n");
va_end(param);
}
#endif /* DEBUG_TRACE */
void set_sock_nodelay(int sock) {
static void set_sock_priority(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;
/* set the TOS bit for either ipv4 or ipv6 */
/* set the TOS bit. note that this will fail for ipv6, I can't find any
* equivalent. */
#ifdef 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)
rc = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0) {
TRACE(("Couldn't set IPV6_TCLASS (%s)", strerror(errno)));
}
#endif
rc = setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&iptos_val, sizeof(iptos_val));
if (rc < 0) {
TRACE(("Couldn't set IP_TOS (%s)", strerror(errno)));
}
val = IPTOS_LOWDELAY;
setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
#endif
#ifdef SO_PRIORITY
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)
dropbear_log(LOG_WARNING, "Couldn't set SO_PRIORITY (%s)",
strerror(errno));
/* 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));
#endif
}
@@ -300,17 +254,7 @@ int dropbear_listen(const char* address, const char* port,
linger.l_linger = 5;
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
int on = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
&on, sizeof(on)) == -1) {
dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY");
}
}
#endif
set_sock_nodelay(sock);
set_sock_priority(sock);
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
err = errno;
@@ -351,29 +295,6 @@ int dropbear_listen(const char* address, const char* port,
return nsock;
}
/* Connect to a given unix socket. The socket is blocking */
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* path) {
struct sockaddr_un addr;
int fd = -1;
memset((void*)&addr, 0x0, sizeof(addr));
addr.sun_family = AF_UNIX;
strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
TRACE(("Failed to open unix socket"))
return -1;
}
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
TRACE(("Failed to connect to '%s' socket", path))
m_close(fd);
return -1;
}
return fd;
}
#endif
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
* return immediately if nonblocking is set. On failure, if errstring
* wasn't null, it will be a newly malloced error message */
@@ -420,7 +341,15 @@ int connect_remote(const char* remotehost, const char* remoteport,
}
if (nonblocking) {
setnonblocking(sock);
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
close(sock);
sock = -1;
if (errstring != NULL && *errstring == NULL) {
*errstring = m_strdup("Failed non-blocking");
}
TRACE(("Failed non-blocking: %s", strerror(errno)))
continue;
}
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
@@ -449,7 +378,7 @@ int connect_remote(const char* remotehost, const char* remoteport,
TRACE(("Error connecting: %s", strerror(err)))
} else {
/* Success */
set_sock_nodelay(sock);
set_sock_priority(sock);
}
freeaddrinfo(res0);
@@ -487,7 +416,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
return DROPBEAR_FAILURE;
}
#ifdef USE_VFORK
#ifdef __uClinux__
pid = vfork();
#else
pid = fork();
@@ -512,7 +441,7 @@ int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
(dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
(ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
TRACE(("leave noptycommand: error redirecting FDs"))
dropbear_exit("Child dup2() failure");
dropbear_exit("child dup2() failure");
}
close(infds[FDOUT]);
@@ -596,47 +525,14 @@ void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
execv(usershell, argv);
}
void get_socket_address(int fd, char **local_host, char **local_port,
char **remote_host, char **remote_port, int host_lookup)
{
struct sockaddr_storage addr;
socklen_t addrlen;
if (local_host || local_port) {
addrlen = sizeof(addr);
if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, local_host, local_port, host_lookup);
}
if (remote_host || remote_port) {
addrlen = sizeof(addr);
if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
dropbear_exit("Failed socket address: %s", strerror(errno));
}
getaddrstring(&addr, remote_host, remote_port, host_lookup);
}
}
/* Return a string representation of the socket address passed. The return
* value is allocated with malloc() */
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port,
int host_lookup) {
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
unsigned int len;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
char *retstring = NULL;
int ret;
int flags = NI_NUMERICSERV | NI_NUMERICHOST;
#ifndef DO_HOST_LOOKUP
host_lookup = 0;
#endif
if (host_lookup) {
flags = NI_NUMERICSERV;
}
unsigned int len;
len = sizeof(struct sockaddr_storage);
/* Some platforms such as Solaris 8 require that len is the length
@@ -654,28 +550,67 @@ void getaddrstring(struct sockaddr_storage* addr,
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
serv, sizeof(serv)-1, flags);
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
if (ret != 0) {
if (host_lookup) {
/* On some systems (Darwin does it) we get EINTR from getnameinfo
* somehow. Eew. So we'll just return the IP, since that doesn't seem
* to exhibit that behaviour. */
getaddrstring(addr, ret_host, ret_port, 0);
return;
} else {
/* if we can't do a numeric lookup, something's gone terribly wrong */
dropbear_exit("Failed lookup: %s", gai_strerror(ret));
}
/* This is a fairly bad failure - it'll fallback to IP if it
* just can't resolve */
dropbear_exit("failed lookup (%d, %d)", ret, errno);
}
if (ret_host) {
*ret_host = m_strdup(host);
if (withport) {
len = strlen(hbuf) + 2 + strlen(sbuf);
retstring = (char*)m_malloc(len);
snprintf(retstring, len, "%s:%s", hbuf, sbuf);
} else {
retstring = m_strdup(hbuf);
}
if (ret_port) {
*ret_port = m_strdup(serv);
return retstring;
}
/* Get the hostname corresponding to the address addr. On failure, the IP
* address is returned. The return value is allocated with strdup() */
char* getaddrhostname(struct sockaddr_storage * addr) {
char hbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
int ret;
unsigned int len;
#ifdef DO_HOST_LOOKUP
const int flags = NI_NUMERICSERV;
#else
const int flags = NI_NUMERICHOST | NI_NUMERICSERV;
#endif
len = sizeof(struct sockaddr_storage);
/* Some platforms such as Solaris 8 require that len is the length
* of the specific structure. */
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
if (addr->ss_family == AF_INET) {
len = sizeof(struct sockaddr_in);
}
#ifdef AF_INET6
if (addr->ss_family == AF_INET6) {
len = sizeof(struct sockaddr_in6);
}
#endif
#endif
ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), flags);
if (ret != 0) {
/* On some systems (Darwin does it) we get EINTR from getnameinfo
* somehow. Eew. So we'll just return the IP, since that doesn't seem
* to exhibit that behaviour. */
return getaddrstring(addr, 0);
}
return m_strdup(hbuf);
}
#ifdef DEBUG_TRACE
@@ -695,14 +630,6 @@ 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
@@ -777,6 +704,8 @@ int buf_getline(buffer * line, FILE * authfile) {
int c = EOF;
TRACE(("enter buf_getline"))
buf_setpos(line, 0);
buf_setlen(line, 0);
@@ -800,8 +729,10 @@ 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;
}
@@ -812,10 +743,6 @@ out:
/* make sure that the socket closes */
void m_close(int fd) {
if (fd == -1) {
return;
}
int val;
do {
val = close(fd);
@@ -852,6 +779,12 @@ void * m_strdup(const char * str) {
return ret;
}
void __m_free(void* ptr) {
if (ptr != NULL) {
free(ptr);
}
}
void * m_realloc(void* ptr, size_t size) {
void *ret;
@@ -876,7 +809,7 @@ void m_burn(void *data, unsigned int len) {
if (data == NULL)
return;
while (len--) {
*p++ = 0x0;
*p++ = 0x66;
}
}
@@ -905,30 +838,14 @@ void disallow_core() {
/* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
int m_str_to_uint(const char* str, unsigned int *val) {
unsigned long l;
errno = 0;
l = strtoul(str, NULL, 10);
*val = strtoul(str, NULL, 10);
/* The c99 spec doesn't actually seem to define EINVAL, but most platforms
* I've looked at mention it in their manpage */
if ((l == 0 && errno == EINVAL)
|| (l == ULONG_MAX && errno == ERANGE)
|| (l > UINT_MAX)) {
if ((*val == 0 && errno == EINVAL)
|| (*val == ULONG_MAX && errno == ERANGE)) {
return DROPBEAR_FAILURE;
} else {
*val = l;
return DROPBEAR_SUCCESS;
}
}
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;
}

View File

@@ -33,57 +33,28 @@
void startsyslog();
#endif
#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)
#define ATTRIB_NORETURN
#define ATTRIB_SENTINEL
#endif
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN;
extern void (*_dropbear_exit)(int exitcode, const char* format, va_list param);
extern void (*_dropbear_log)(int priority, const char* format, va_list param);
void dropbear_exit(const char* format, ...) ATTRIB_PRINTF(1,2) ATTRIB_NORETURN;
void dropbear_close(const char* format, ...) ATTRIB_PRINTF(1,2) ;
void dropbear_log(int priority, const char* format, ...) ATTRIB_PRINTF(2,3) ;
void fail_assert(const char* expr, const char* file, int line) ATTRIB_NORETURN;
void dropbear_exit(const char* format, ...);
void dropbear_close(const char* format, ...);
void dropbear_log(int priority, const char* format, ...);
void fail_assert(const char* expr, const char* file, int line);
#ifdef DEBUG_TRACE
void dropbear_trace(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace2(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace(const char* format, ...);
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,
DROPBEAR_PRIO_LOWDELAY,
DROPBEAR_PRIO_BULK,
};
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);
unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
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,
int *writefd, int *readfd, int *errfd, pid_t *pid);
void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell);
#ifdef ENABLE_CONNECT_UNIX
int connect_unix(const char* addr);
#endif
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring);
char* getaddrhostname(struct sockaddr_storage * addr);
int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile);
@@ -91,7 +62,8 @@ 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) __m_free(X); (X) = NULL;
void __m_free(void* ptr);
void m_burn(void* data, unsigned int len);
void setnonblocking(int fd);
void disallow_core();
@@ -103,7 +75,4 @@ 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);
#endif /* _DBUTIL_H_ */

73
debian/changelog vendored
View File

@@ -1,69 +1,20 @@
dropbear (2014.63-0.1) unstable; urgency=low
dropbear (0.52-2) unstable; urgency=low
* New upstream release.
* Make key utils part of dropbear-server package (since it's
required anyway, single binary saves space), rename -common to
-keyutils
* Don't make clean between builds, just rm *.o since only
top-level files change
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Feb 2014 22:54:00 +0800
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Nov 2008 21:54:00 +0900
dropbear (2013.62) unstable; urgency=low
dropbear (0.52-1) unstable; urgency=low
* New upstream release.
* Maemo port, split into 5 packages
(dropbear, dropbear-server, dropbear-client, dropbear-common, dropbear-scp).
This avoids conflicts with openssh package.
-- 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.
-- Matt Johnston <matt@ucc.asn.au> Thu, 21 Mar 2013 22:54:00 +0800
dropbear (2012.55-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 22 Feb 2012 22:54:00 +0800
dropbear (2011.54-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Tues, 8 Nov 2011 22:54:00 +0800
dropbear (0.53.1-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Wed, 2 Mar 2011 22:54:00 +0900
dropbear (0.53-0.1) unstable; urgency=low
* New upstream release.
-- Matt Johnston <matt@ucc.asn.au> Thu, 24 Feb 2011 22:54:00 +0900
-- Matt Johnston <matt@ucc.asn.au> Wed, 19 Nov 2008 20:54:00 +0900
dropbear (0.52-0.1) unstable; urgency=low

79
debian/control vendored
View File

@@ -1,7 +1,7 @@
Source: dropbear
Section: net
Section: user/network
Priority: optional
Maintainer: Gerrit Pape <pape@smarden.org>
Maintainer: Matt Johnston <matt@ucc.asn.au>
Build-Depends: libz-dev
Standards-Version: 3.7.3.0
@@ -9,6 +9,9 @@ Package: dropbear
Architecture: any
Depends: ${shlibs:Depends}
Suggests: openssh-client, runit
Section: user/network
Conflicts: dropbear-server, dropbear-client, dropbear-keyutils, dropbear-scp
XB-Maemo-Display-Name: Dropbear SSH Client and Server
Description: lightweight SSH2 server and client
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
@@ -17,4 +20,76 @@ Description: lightweight SSH2 server and client
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides Dropbear client and server as a single binary,
as well as key utilities and SCP.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-server
Architecture: any
Depends: ${shlibs:Depends}
Section: user/network
Conflicts: dropbear, dropbear-keyutils
Provides: dropbear-keyutils
Recommends: dropbear-scp
XB-Maemo-Display-Name: Dropbear SSH Server
Description: lightweight SSH2 server
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides only the Dropbear server.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-client
Architecture: any
Conflicts: dropbear
Section: user/network
Depends: ${shlibs:Depends}
Recommends: dropbear-scp
Suggests: dropbear-keyutils
XB-Maemo-Display-Name: Dropbear SSH Client
Description: lightweight SSH2 client
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
It implements most required features of the SSH 2 protocol, and other
features such as X11 and authentication agent forwarding.
.
This package provides only the Dropbear client.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-keyutils
Architecture: any
Conflicts: dropbear, dropbear-server
Section: user/network
XB-Maemo-Display-Name: Dropbear SSH Key Utils
Depends: ${shlibs:Depends}
Description: lightweight SSH2, key management utilities
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
This package provides dropbearkey and dropbearconvert programs,
for generating keys and converting to/from OpenSSH keys.
.
See http://matt.ucc.asn.au/dropbear/dropbear.html
Package: dropbear-scp
Architecture: any
Section: user/network
Conflicts: dropbear
XB-Maemo-Display-Name: Dropbear SCP
Depends: ${shlibs:Depends}
Description: lightweight SSH2 scp
dropbear is a SSH 2 server and client designed to be small enough to
be used in small memory environments, while still being functional and
secure enough for general use.
.
This dropbear-scp package provides /usr/bin/scp.

3
debian/dropbear-server.conffiles vendored Normal file
View File

@@ -0,0 +1,3 @@
/etc/init.d/dropbear
/etc/dropbear/run
/etc/dropbear/log/run

79
debian/dropbear-server.postinst vendored Normal file
View File

@@ -0,0 +1,79 @@
#!/bin/sh
set -e
test "$1" = 'configure' || exit 0
if test ! -e /etc/dropbear/dropbear_rsa_host_key; then
if test -f /etc/ssh/ssh_host_rsa_key; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/lib/dropbear/dropbearconvert openssh dropbear \
/etc/ssh/ssh_host_rsa_key /etc/dropbear/dropbear_rsa_host_key
else
echo "Generating Dropbear RSA key. Please wait."
dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
fi
fi
if test ! -e /etc/dropbear/dropbear_dss_host_key; then
if test -f /etc/ssh/ssh_host_dsa_key; then
echo "Converting existing OpenSSH RSA host key to Dropbear format."
/usr/lib/dropbear/dropbearconvert openssh dropbear \
/etc/ssh/ssh_host_dsa_key /etc/dropbear/dropbear_dss_host_key
else
echo "Generating Dropbear DSS key. Please wait."
dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key
fi
fi
if test ! -s /etc/default/dropbear; then
# check whether OpenSSH seems to be installed.
if test -x /usr/sbin/sshd; then
cat <<EOT
OpenSSH appears to be installed. Setting /etc/default/dropbear so that
Dropbear will not start by default. Edit this file to change this behaviour.
EOT
cat >>/etc/default/dropbear <<EOT
# disabled because OpenSSH is installed
# change to NO_START=0 to enable Dropbear
NO_START=1
EOT
fi
cat >>/etc/default/dropbear <<EOT
# the TCP port that Dropbear listens on
DROPBEAR_PORT=22
# any additional arguments for Dropbear
DROPBEAR_EXTRA_ARGS=
# specify an optional banner file containing a message to be
# sent to clients before they connect, such as "/etc/issue.net"
DROPBEAR_BANNER=""
# RSA hostkey file (default: /etc/dropbear/dropbear_rsa_host_key)
#DROPBEAR_RSAKEY="/etc/dropbear/dropbear_rsa_host_key"
# DSS hostkey file (default: /etc/dropbear/dropbear_dss_host_key)
#DROPBEAR_DSSKEY="/etc/dropbear/dropbear_dss_host_key"
# Receive window size - this is a tradeoff between memory and
# network performance
DROPBEAR_RECEIVE_WINDOW=65536
EOT
fi
if test -x /etc/init.d/dropbear; then
update-rc.d dropbear defaults >/dev/null
if test -x /usr/sbin/invoke-rc.d; then
invoke-rc.d dropbear restart
else
/etc/init.d/dropbear restart
fi
fi
if test -n "$2" && dpkg --compare-versions "$2" lt '0.50-4' &&
update-service --check dropbear 2>/dev/null; then
update-service --remove /etc/dropbear 2>/dev/null || :
sleep 6
rm -rf /var/run/dropbear /var/run/dropbear.log
update-service --add /etc/dropbear || :
fi

12
debian/dropbear-server.postrm vendored Normal file
View File

@@ -0,0 +1,12 @@
#! /bin/sh
set -e
test "$1" = 'purge' || exit 0
if test -e /etc/dropbear; then
rm -f /etc/dropbear/dropbear_rsa_host_key
rm -f /etc/dropbear/dropbear_dss_host_key
rmdir --ignore-fail-on-non-empty /etc/dropbear
fi
update-rc.d dropbear remove >/dev/null
rm -f /etc/default/dropbear
rm -rf /etc/dropbear/supervise /etc/dropbear/log/supervise

11
debian/dropbear-server.prerm vendored Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
set -e
test "$1" = 'remove' || test "$1" = 'deconfigure' || exit 0
if test -x /etc/init.d/dropbear; then
if test -x /usr/sbin/invoke-rc.d; then
invoke-rc.d dropbear stop
else
/etc/init.d/dropbear stop
fi
fi

View File

@@ -38,7 +38,7 @@ test -n "$DROPBEAR_RECEIVE_WINDOW" || \
case "$1" in
start)
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
test "$NO_START" = "0" || cancel '/etc/default/dropbear NO_START is set, Dropbear will not run.'
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/"$NAME".pid \
--exec "$DAEMON" -- -d "$DROPBEAR_DSSKEY" -r "$DROPBEAR_RSAKEY" \
@@ -51,7 +51,7 @@ case "$1" in
echo "$NAME."
;;
restart|force-reload)
test "$NO_START" = "0" || cancel 'NO_START is not set to zero.'
test "$NO_START" = "0" || cancel '/etc/default/dropbear NO_START is set, Dropbear will not run.'
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/"$NAME".pid
sleep 1

165
debian/rules vendored
View File

@@ -1,9 +1,5 @@
#!/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)
@@ -13,6 +9,13 @@ ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
STRIP =: nostrip
endif
CFLAGS =-Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS +=-O0
else
CFLAGS +=-Os
endif
CONFFLAGS =
CC =gcc
ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
@@ -20,8 +23,6 @@ ifneq (,$(findstring diet,$(DEB_BUILD_OPTIONS)))
CC =diet -v -Os gcc -nostdinc
endif
DIR =$(shell pwd)/debian/dropbear
patch: deb-checkdir patch-stamp
patch-stamp:
for i in `ls -1 debian/diff/*.diff || :`; do \
@@ -36,13 +37,15 @@ config.status: patch-stamp configure
--build='$(DEB_BUILD_GNU_TYPE)' --prefix=/usr \
--mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info \
$(CONFFLAGS)
$(MAKE) clean
build: deb-checkdir build-stamp
build-stamp: config.status
$(MAKE) CC='$(CC)' LD='$(CC)'
touch build-stamp
clean: deb-checkdir deb-checkuid
clean: DIR=$(shell pwd)/debian/dropbear
clean: deb-checkdir deb-checkuid
test ! -r Makefile || $(MAKE) distclean
rm -f libtomcrypt/Makefile libtommath/Makefile
test ! -e patch-stamp || \
@@ -51,22 +54,27 @@ clean: deb-checkdir deb-checkuid
done
rm -f patch-stamp build-stamp config.log config.status
rm -rf '$(DIR)'
rm -rf '$(DIR)'-client
rm -rf '$(DIR)'-server
rm -rf '$(DIR)'-keyutils
rm -rf '$(DIR)'-scp
rm -f debian/files debian/substvars debian/copyright changelog
install: deb-checkdir deb-checkuid build-stamp
rm -rf '$(DIR)'
install-server: DIR=$(shell pwd)/debian/dropbear-server
install-server: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbear dropbearkey dropbearconvert" MULTI=1
install -d -m0755 '$(DIR)'/etc/dropbear
# programs
install -d -m0755 '$(DIR)'/usr/sbin
install -m0755 dropbear '$(DIR)'/usr/sbin/dropbear
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 dbclient '$(DIR)'/usr/bin/dbclient
install -m0755 dropbearkey '$(DIR)'/usr/bin/dropbearkey
install -d -m0755 '$(DIR)'/usr/sbin
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearconvert \
'$(DIR)'/usr/lib/dropbear/dropbearconvert
$(STRIP) -R .comment -R .note '$(DIR)'/usr/sbin/* \
'$(DIR)'/usr/bin/* '$(DIR)'/usr/lib/dropbear/*
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/sbin/dropbear
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
# init and run scripts
install -d -m0755 '$(DIR)'/etc/init.d
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
@@ -74,27 +82,124 @@ install: deb-checkdir deb-checkuid build-stamp
install -d -m0755 '$(DIR)'/etc/dropbear/log
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
# man pages
install -d -m0755 '$(DIR)'/usr/share/man/man8
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; \
for i in dropbear.8 ; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
gzip -9 '$(DIR)'/usr/share/man/man1/*.1
# copyright, changelog
cat debian/copyright.in LICENSE >debian/copyright
cat debian/copyright.in LICENSE > debian/copyright
test -r changelog || ln -s CHANGES changelog
$(STRIP) -R .comment -R .note '$(DIR)'/usr/lib/dropbear/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install-client: DIR=$(shell pwd)/debian/dropbear-client
install-client: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS=dbclient dbclient
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 dbclient '$(DIR)'/usr/bin/dbclient
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
$(STRIP) -R .comment -R .note '$(DIR)'/usr/bin/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/bin/*
install-keyutils: DIR=$(shell pwd)/debian/dropbear-keyutils
install-keyutils: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbearkey dropbearconvert" MULTI=1
install -d -m0755 '$(DIR)'/usr/bin
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
install -d -m0755 '$(DIR)'/usr/share/man/man8
for i in dropbearkey.8; do \
install -m644 $$i '$(DIR)'/usr/share/man/man8/ || exit 1; \
done
gzip -9 '$(DIR)'/usr/share/man/man8/*.8
$(STRIP) -R .comment -R .note \
'$(DIR)'/usr/lib/dropbear/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install-scp: DIR=$(shell pwd)/debian/dropbear-scp
install-scp: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="scp" scp
install -d -m0755 '$(DIR)'/usr/bin
install -m0755 scp '$(DIR)'/usr/bin/scp
$(STRIP) -R .comment -R .note '$(DIR)'/usr/bin/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/bin/*
install-multi: DIR=$(shell pwd)/debian/dropbear
install-multi: deb-checkdir deb-checkuid config.status
rm -f '$(DIR)'
rm *.o
$(MAKE) CC='$(CC)' LD='$(LD)' PROGRAMS="dropbearkey dropbearconvert scp dropbear dbclient" MULTI=1
install -d -m0755 '$(DIR)'/etc/dropbear
# programs
install -d -m0755 '$(DIR)'/usr/bin
install -d -m0755 '$(DIR)'/usr/sbin
install -d -m0755 '$(DIR)'/usr/lib/dropbear
install -m0755 dropbearmulti \
'$(DIR)'/usr/lib/dropbear/dropbearmulti
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dropbearkey
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/dbclient
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/bin/scp
ln -s ../lib/dropbear/dropbearmulti '$(DIR)'/usr/sbin/dropbear
ln -s dropbearmulti '$(DIR)'/usr/lib/dropbear/dropbearconvert
# init and run scripts
install -d -m0755 '$(DIR)'/etc/init.d
install -m0755 debian/dropbear.init '$(DIR)'/etc/init.d/dropbear
install -m0755 debian/service/run '$(DIR)'/etc/dropbear/run
install -d -m0755 '$(DIR)'/etc/dropbear/log
install -m0755 debian/service/log '$(DIR)'/etc/dropbear/log/run
ln -s /var/log/dropbear '$(DIR)'/etc/dropbear/log/main
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; \
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
$(STRIP) -R .comment -R .note '$(DIR)'/usr/lib/dropbear/*
install -d -m0755 '$(DIR)'/DEBIAN
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/lib/dropbear/*
install: install-client install-server install-keyutils install-multi install-scp
binary-indep:
binary-arch: install dropbear.deb
test '$(CC)' != 'gcc' || \
dpkg-shlibdeps '$(DIR)'/usr/sbin/* '$(DIR)'/usr/bin/* \
'$(DIR)'/usr/lib/dropbear/*
dpkg-gencontrol -isp -pdropbear -P'$(DIR)'
dpkg -b '$(DIR)' ..
binary-arch: install dropbear.deb dropbear-server.deb dropbear-keyutils.deb dropbear-scp.deb dropbear-client.deb
dpkg-gencontrol -isp -pdropbear -P'$(shell pwd)/debian'/dropbear
dpkg-gencontrol -isp -pdropbear-server -P'$(shell pwd)/debian'/dropbear-server
dpkg-gencontrol -isp -pdropbear-client -P'$(shell pwd)/debian'/dropbear-client
dpkg-gencontrol -isp -pdropbear-keyutils -P'$(shell pwd)/debian'/dropbear-keyutils
dpkg-gencontrol -isp -pdropbear-scp -P'$(shell pwd)/debian'/dropbear-scp
dpkg -b '$(shell pwd)/debian'/dropbear ..
dpkg -b '$(shell pwd)/debian'/dropbear-server ..
dpkg -b '$(shell pwd)/debian'/dropbear-keyutils ..
dpkg -b '$(shell pwd)/debian'/dropbear-scp ..
dpkg -b '$(shell pwd)/debian'/dropbear-client ..
binary: binary-arch binary-indep

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,10 +63,8 @@
/* 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,16 +1,16 @@
.TH dropbear 8
.SH NAME
dropbear \- lightweight SSH server
dropbear \- lightweight SSH2 server
.SH SYNOPSIS
.B dropbear
[\-RFEmwsgjki] [\-b
.I banner\fR]
[\-r
.I hostkeyfile\fR] [\-p
.IR [address:]port ]
[\-FEmwsgjki] [\-b
.I banner\fR] [\-d
.I dsskey\fR] [\-r
.I rsakey\fR] [\-p
.IR port ]
.SH DESCRIPTION
.B dropbear
is a SSH server designed to be small enough to be used in small memory
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.
.SH OPTIONS
.TP
@@ -20,16 +20,24 @@ Display the contents of the file
.I banner
before user login (default: none).
.TP
.B \-r \fIhostkey
.B \-d \fIdsskey
dsskeyfile.
Use the contents of the file
.I hostkey
for the SSH hostkey.
.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.
This file is generated with
.BR dropbearkey (1)
or automatically with the '-R' option. See "Host Key Files" below.
.BR dropbearkey (8).
.TP
.B \-R
Generate hostkeys automatically. See "Host Key Files" below.
.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).
.TP
.B \-F
Don't fork into background.
@@ -135,13 +143,9 @@ key authentication.
Host Key Files
Host key files are read at startup from a standard location, by default
/etc/dropbear/dropbear_dss_host_key, /etc/dropbear/dropbear_rsa_host_key, and
/etc/dropbear/dropbear-ecdsa_host_key
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.
/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.
.TP
Message Of The Day
@@ -150,40 +154,11 @@ By default the file /etc/motd will be printed for any login shell (unless
disabled at compile-time). This can also be disabled per-user
by creating a file ~/.hushlogin .
.SH ENVIRONMENT VARIABLES
Dropbear sets the standard variables USER, LOGNAME, HOME, SHELL, PATH, and TERM.
The variables below are set for sessions as appropriate.
.TP
.B SSH_TTY
This is set to the allocated TTY if a PTY was used.
.TP
.B SSH_CONNECTION
Contains "<remote_ip> <remote_port> <local_ip> <local_port>".
.TP
.B DISPLAY
Set X11 forwarding is used.
.TP
.B SSH_ORIGINAL_COMMAND
If a 'command=' authorized_keys option was used, the original command is specified
in this variable. If a shell was requested this is set to an empty value.
.TP
.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(1), dbclient(1), dropbearconvert(1)
dropbearkey(8), dbclient(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html
http://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -1,50 +0,0 @@
.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
.SH EXAMPLE
# dropbearconvert openssh dropbear ~/.ssh/id_rsa ~/.ssh/dropbear_priv
.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,8 +28,6 @@
#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,
@@ -64,9 +62,6 @@ 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;
@@ -116,7 +111,7 @@ static int do_convert(int intype, const char* infile, int outtype,
const char* outfile) {
sign_key * key = NULL;
const char * keytype = NULL;
char * keytype = NULL;
int ret = 1;
key = import_read(infile, NULL, intype);
@@ -126,7 +121,16 @@ static int do_convert(int intype, const char* infile, int outtype,
goto out;
}
keytype = signkey_name_from_type(key->type, NULL);
#ifdef DROPBEAR_RSA
if (key->rsakey != NULL) {
keytype = "RSA";
}
#endif
#ifdef DROPBEAR_DSS
if (key->dsskey != NULL) {
keytype = "DSS";
}
#endif
fprintf(stderr, "Key is a %s key\n", keytype);

View File

@@ -1,6 +1,6 @@
.TH dropbearkey 1
.TH dropbearkey 8
.SH NAME
dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
dropbearkey \- create private keys for the use with dropbear(8)
.SH SYNOPSIS
.B dropbearkey
\-t
@@ -12,12 +12,12 @@ dropbearkey \- create private keys for the use with dropbear(8) or dbclient(1)
.SH DESCRIPTION
.B dropbearkey
generates a
.I RSA
.I DSS,
.I RSA
or
.I ECDSA
.I DSS
format SSH private key, and saves it to a file for the use with the
Dropbear client or server.
.BR dropbear (8)
SSH 2 server.
Note that
some SSH implementations
use the term "DSA" rather than "DSS", they mean the same thing.
@@ -27,7 +27,6 @@ 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
@@ -38,11 +37,7 @@ Write the secret key to the file
.B \-s \fIbits
Set the key size to
.I bits
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.
bits, should be multiple of 8 (optional).
.SH EXAMPLE
# dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
.SH AUTHOR
@@ -50,6 +45,6 @@ Matt Johnston (matt@ucc.asn.au).
.br
Gerrit Pape (pape@smarden.org) wrote this manual page.
.SH SEE ALSO
dropbear(8), dbclient(1), dropbearconvert(1)
dropbear(8), dbclient(1)
.P
https://matt.ucc.asn.au/dropbear/dropbear.html
http://matt.ucc.asn.au/dropbear/dropbear.html

View File

@@ -23,7 +23,7 @@
* SOFTWARE. */
/* The format of the keyfiles is basically a raw dump of the buffer. Data types
* are specified in the transport rfc 4253 - string is a 32-bit len then the
* are specified in the transport draft - string is a 32-bit len then the
* non-null-terminated string, mp_int is a 32-bit len then the bignum data.
* The actual functions are buf_put_rsa_priv_key() and buf_put_dss_priv_key()
@@ -51,49 +51,31 @@
#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 int printpubfile(const char* filename);
static void justprintpub(const char* filename);
/* Print a help message */
static void printhelp(char * progname) {
fprintf(stderr, "Usage: %s -t <type> -f <filename> [-s bits]\n"
"Options are:\n"
"-t type Type of key to generate. One of:\n"
#ifdef DROPBEAR_RSA
" rsa\n"
#endif
#ifdef DROPBEAR_DSS
" dss\n"
#endif
#ifdef DROPBEAR_ECDSA
" ecdsa\n"
#endif
"-f filename Use filename for the secret key\n"
"-s bits Key size in bits, should be a multiple of 8 (optional)\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
" (DSS has a fixed size of 1024 bits)\n"
"-y Just print the publickey and fingerprint for the\n private key in <filename>.\n"
#ifdef DEBUG_TRACE
"-v verbose\n"
@@ -101,30 +83,6 @@ 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) {
@@ -134,16 +92,16 @@ int main(int argc, char ** argv) {
int i;
char ** next = 0;
sign_key *key = NULL;
buffer *buf = NULL;
char * filename = NULL;
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
int keytype = -1;
char * typetext = NULL;
char * sizetext = NULL;
unsigned int bits = 0;
unsigned int bits;
unsigned int keysize;
int printpub = 0;
crypto_init();
seedrandom();
/* get the commandline options */
for (i = 1; i < argc; i++) {
if (argv[i] == NULL) {
@@ -194,8 +152,8 @@ int main(int argc, char ** argv) {
}
if (printpub) {
int ret = printpubfile(filename);
exit(ret);
justprintpub(filename);
/* Not reached */
}
/* check/parse args */
@@ -205,26 +163,21 @@ int main(int argc, char ** argv) {
exit(EXIT_FAILURE);
}
if (strlen(typetext) == 3) {
#ifdef DROPBEAR_RSA
if (strcmp(typetext, "rsa") == 0)
{
keytype = DROPBEAR_SIGNKEY_RSA;
}
if (strncmp(typetext, "rsa", 3) == 0) {
keytype = DROPBEAR_SIGNKEY_RSA;
TRACE(("type is rsa"))
}
#endif
#ifdef DROPBEAR_DSS
if (strcmp(typetext, "dss") == 0)
{
keytype = DROPBEAR_SIGNKEY_DSS;
}
if (strncmp(typetext, "dss", 3) == 0) {
keytype = DROPBEAR_SIGNKEY_DSS;
TRACE(("type is dss"))
}
#endif
#ifdef DROPBEAR_ECDSA
if (strcmp(typetext, "ecdsa") == 0)
{
keytype = DROPBEAR_SIGNKEY_ECDSA_KEYGEN;
}
#endif
if (keytype == DROPBEAR_SIGNKEY_NONE) {
if (keytype == -1) {
fprintf(stderr, "Unknown key type '%s'\n", typetext);
printhelp(argv[0]);
exit(EXIT_FAILURE);
@@ -236,26 +189,75 @@ int main(int argc, char ** argv) {
exit(EXIT_FAILURE);
}
check_signkey_bits(keytype, bits);;
}
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);
}
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");
if (signkey_generate(keytype, bits, filename) == DROPBEAR_FAILURE)
{
dropbear_exit("Failed to generate key.\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);
}
printpubfile(filename);
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);
return EXIT_SUCCESS;
}
#endif
static int printpubfile(const char* filename) {
static void justprintpub(const char* filename) {
buffer *buf = NULL;
sign_key *key = NULL;
enum signkey_type keytype;
int keytype;
int ret;
int err = DROPBEAR_FAILURE;
@@ -289,7 +291,7 @@ out:
sign_key_free(key);
key = NULL;
}
return err;
exit(err);
}
static void printpubkey(sign_key * key, int keytype) {
@@ -318,7 +320,7 @@ static void printpubkey(sign_key * key, int keytype) {
fprintf(stderr, "base64 failed");
}
typestring = signkey_name_from_type(keytype, NULL);
typestring = signkey_name_from_type(keytype, &err);
fp = sign_key_fingerprint(buf_getptr(buf, len), len);
@@ -338,3 +340,35 @@ 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);
}

123
dss.c
View File

@@ -28,7 +28,7 @@
#include "dss.h"
#include "buffer.h"
#include "ssh.h"
#include "dbrandom.h"
#include "random.h"
/* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
* operations, such as key reading, signing, verification. Key generation
@@ -43,11 +43,15 @@
* The key will have the same format as buf_put_dss_key.
* These should be freed with dss_key_free.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
TRACE(("enter buf_get_dss_pub_key"))
dropbear_assert(key != NULL);
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, 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);
key->x = NULL;
buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
@@ -72,7 +76,7 @@ int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
/* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
* Loads a private dss key from a buffer
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
int ret = DROPBEAR_FAILURE;
@@ -83,7 +87,8 @@ int buf_get_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
return DROPBEAR_FAILURE;
}
m_mp_alloc_init_multi(&key->x, NULL);
key->x = m_malloc(sizeof(mp_int));
m_mp_init(key->x);
ret = buf_getmpint(buf, key->x);
if (ret == DROPBEAR_FAILURE) {
m_free(key->x);
@@ -94,11 +99,11 @@ 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) {
void dss_key_free(dss_key *key) {
TRACE2(("enter dsa_key_free"))
TRACE(("enter dsa_key_free"))
if (key == NULL) {
TRACE2(("enter dsa_key_free: key == NULL"))
TRACE(("enter dsa_key_free: key == NULL"))
return;
}
if (key->p) {
@@ -122,7 +127,7 @@ void dss_key_free(dropbear_dss_key *key) {
m_free(key->x);
}
m_free(key);
TRACE2(("leave dsa_key_free"))
TRACE(("leave dsa_key_free"))
}
/* put the dss public key into the buffer in the required format:
@@ -133,7 +138,7 @@ void dss_key_free(dropbear_dss_key *key) {
* mpint g
* mpint y
*/
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
dropbear_assert(key != NULL);
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
@@ -145,7 +150,7 @@ void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
}
/* Same as buf_put_dss_pub_key, but with the private "x" key appended */
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
dropbear_assert(key != NULL);
buf_put_dss_pub_key(buf, key);
@@ -156,7 +161,9 @@ 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, buffer *data_buf) {
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
unsigned int len) {
unsigned char msghash[SHA1_HASH_SIZE];
hash_state hs;
int ret = DROPBEAR_FAILURE;
@@ -180,7 +187,7 @@ int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* hash the data */
sha1_init(&hs);
sha1_process(&hs, data_buf->data, data_buf->len);
sha1_process(&hs, data, len);
sha1_done(&hs, msghash);
/* create the signature - s' and r' are the received signatures in buf */
@@ -251,12 +258,52 @@ out:
}
#endif /* DROPBEAR_SIGNKEY_VERIFY */
#ifdef DSS_PROTOK
/* convert an unsigned mp into an array of bytes, malloced.
* This array must be freed after use, len contains the length of the array,
* if len != NULL */
static unsigned char* mptobytes(mp_int *mp, int *len) {
unsigned char* ret;
int size;
size = mp_unsigned_bin_size(mp);
ret = m_malloc(size);
if (mp_to_unsigned_bin(mp, ret) != MP_OKAY) {
dropbear_exit("mem alloc error");
}
if (len != NULL) {
*len = size;
}
return ret;
}
#endif
/* Sign the data presented with key, writing the signature contents
* to the buffer */
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
* to the buffer
*
* When DSS_PROTOK is #defined:
* The alternate k generation method is based on the method used in PuTTY.
* In particular to avoid being vulnerable to attacks using flaws in random
* generation of k, we use the following:
*
* proto_k = SHA512 ( SHA512(x) || SHA160(message) )
* k = proto_k mod q
*
* Now we aren't relying on the random number generation to protect the private
* key x, which is a long term secret */
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
unsigned int len) {
unsigned char msghash[SHA1_HASH_SIZE];
unsigned int writelen;
unsigned int i;
#ifdef DSS_PROTOK
unsigned char privkeyhash[SHA512_HASH_SIZE];
unsigned char *privkeytmp;
unsigned char proto_k[SHA512_HASH_SIZE];
DEF_MP_INT(dss_protok);
#endif
DEF_MP_INT(dss_k);
DEF_MP_INT(dss_m);
DEF_MP_INT(dss_temp1);
@@ -270,44 +317,68 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
/* hash the data */
sha1_init(&hs);
sha1_process(&hs, data_buf->data, data_buf->len);
sha1_process(&hs, data, len);
sha1_done(&hs, msghash);
m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
&dss_m, NULL);
/* the random number generator's input has included the private key which
* avoids DSS's problem of private key exposure due to low entropy */
#ifdef DSS_PROTOK
/* hash the privkey */
privkeytmp = mptobytes(key->x, &i);
sha512_init(&hs);
sha512_process(&hs, "the quick brown fox jumped over the lazy dog", 44);
sha512_process(&hs, privkeytmp, i);
sha512_done(&hs, privkeyhash);
m_burn(privkeytmp, i);
m_free(privkeytmp);
/* calculate proto_k */
sha512_init(&hs);
sha512_process(&hs, privkeyhash, SHA512_HASH_SIZE);
sha512_process(&hs, msghash, SHA1_HASH_SIZE);
sha512_done(&hs, proto_k);
/* generate k */
m_mp_init(&dss_protok);
bytes_to_mp(&dss_protok, proto_k, SHA512_HASH_SIZE);
if (mp_mod(&dss_protok, key->q, &dss_k) != MP_OKAY) {
dropbear_exit("dss error");
}
mp_clear(&dss_protok);
m_burn(proto_k, SHA512_HASH_SIZE);
#else /* DSS_PROTOK not defined*/
gen_random_mpint(key->q, &dss_k);
#endif
/* now generate the actual signature */
bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
/* g^k mod p */
if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
/* r = (g^k mod p) mod q */
if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
/* x*r mod q */
if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
/* (SHA1(M) + xr) mod q) */
if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
/* (k^-1) mod q */
if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
/* s = (k^-1(SHA1(M) + xr)) mod q */
if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
@@ -321,7 +392,7 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
}
if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
!= MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
mp_clear(&dss_r);
buf_incrwritepos(buf, writelen);
@@ -334,7 +405,7 @@ void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
}
if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
!= MP_OKAY) {
dropbear_exit("DSS error");
dropbear_exit("dss error");
}
mp_clear(&dss_s);
buf_incrwritepos(buf, writelen);

25
dss.h
View File

@@ -30,26 +30,31 @@
#ifdef DROPBEAR_DSS
typedef struct {
#define DSS_SIGNATURE_SIZE 4+SSH_SIGNKEY_DSS_LEN+4+2*SHA1_HASH_SIZE
struct DSS_key {
mp_int* p;
mp_int* q;
mp_int* g;
mp_int* y;
/* x is the private part */
mp_int* x;
} dropbear_dss_key;
};
void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
typedef struct DSS_key dss_key;
void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
unsigned int len);
#ifdef DROPBEAR_SIGNKEY_VERIFY
int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf);
int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
unsigned int len);
#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);
void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key);
void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key);
void dss_key_free(dropbear_dss_key *key);
int buf_get_dss_pub_key(buffer* buf, dss_key *key);
int buf_get_dss_priv_key(buffer* buf, dss_key *key);
void buf_put_dss_pub_key(buffer* buf, dss_key *key);
void buf_put_dss_priv_key(buffer* buf, dss_key *key);
void dss_key_free(dss_key *key);
#endif /* DROPBEAR_DSS */

275
ecc.c
View File

@@ -1,275 +0,0 @@
#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
View File

@@ -1,36 +0,0 @@
#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 */

420
ecdsa.c
View File

@@ -1,420 +0,0 @@
#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);
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
View File

@@ -1,35 +0,0 @@
#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

@@ -1,6 +1,7 @@
/* Taken for Dropbear from OpenSSH 5.5p1 */
/*
*
* Taken from OpenSSH 3.8.1p1
*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
* Copyright (C) 1999 WIDE Project. All rights reserved.
*
@@ -39,11 +40,7 @@
#include "includes.h"
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* RCSID("$.Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $");*/
#ifndef HAVE_GETNAMEINFO
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
@@ -53,8 +50,6 @@ int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
struct hostent *hp;
char tmpserv[16];
if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
return (EAI_FAMILY);
if (serv != NULL) {
snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
if (strlcpy(serv, tmpserv, servlen) >= servlen)
@@ -99,8 +94,6 @@ gai_strerror(int err)
return ("memory allocation failure.");
case EAI_NONAME:
return ("nodename nor servname provided, or not known");
case EAI_FAMILY:
return ("ai_family not supported");
default:
return ("unknown/invalid error.");
}
@@ -165,9 +158,6 @@ getaddrinfo(const char *hostname, const char *servname,
u_long addr;
port = 0;
if (hints && hints->ai_family != AF_UNSPEC &&
hints->ai_family != AF_INET)
return (EAI_FAMILY);
if (servname != NULL) {
char *cp;

View File

@@ -1,6 +1,6 @@
/* Taken for Dropbear from OpenSSH 5.5p1 */
/* Taken from OpenSSH 3.8.1p1 */
/* $Id: fake-rfc2553.h,v 1.16 2008/07/14 11:37:37 djm Exp $ */
/* $.Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */
/*
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
@@ -43,10 +43,6 @@
#define _FAKE_RFC2553_H
#include "includes.h"
#include <sys/types.h>
#if defined(HAVE_NETDB_H)
# include <netdb.h>
#endif
/*
* First, socket and INET6 related definitions
@@ -79,7 +75,6 @@ struct sockaddr_in6 {
u_int16_t sin6_port;
u_int32_t sin6_flowinfo;
struct in6_addr sin6_addr;
u_int32_t sin6_scope_id;
};
#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
@@ -120,19 +115,9 @@ struct sockaddr_in6 {
#endif /* !NI_MAXHOST */
#ifndef EAI_NODATA
# define EAI_NODATA (INT_MAX - 1)
#endif
#ifndef EAI_MEMORY
# define EAI_MEMORY (INT_MAX - 2)
#endif
#ifndef EAI_NONAME
# define EAI_NONAME (INT_MAX - 3)
#endif
#ifndef EAI_SYSTEM
# define EAI_SYSTEM (INT_MAX - 4)
#endif
#ifndef EAI_FAMILY
# define EAI_FAMILY (INT_MAX - 5)
# define EAI_NODATA 1
# define EAI_MEMORY 2
# define EAI_NONAME 3
#endif
#ifndef HAVE_STRUCT_ADDRINFO
@@ -158,7 +143,7 @@ int getaddrinfo(const char *, const char *,
#endif /* !HAVE_GETADDRINFO */
#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
#define gai_strerror(a) (_ssh_compat_gai_strerror(a))
#define gai_strerror(a) (ssh_gai_strerror(a))
char *gai_strerror(int);
#endif /* !HAVE_GAI_STRERROR */

View File

@@ -26,7 +26,7 @@
#include "dbutil.h"
#include "signkey.h"
#include "bignum.h"
#include "dbrandom.h"
#include "random.h"
#include "buffer.h"
#include "gendss.h"
#include "dss.h"
@@ -37,26 +37,29 @@
#ifdef DROPBEAR_DSS
static void getq(dropbear_dss_key *key);
static void getp(dropbear_dss_key *key, unsigned int size);
static void getg(dropbear_dss_key *key);
static void getx(dropbear_dss_key *key);
static void gety(dropbear_dss_key *key);
static void getq(dss_key *key);
static void getp(dss_key *key, unsigned int size);
static void getg(dss_key *key);
static void getx(dss_key *key);
static void gety(dss_key *key);
dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
dss_key * gen_dss_priv_key(unsigned int size) {
dropbear_dss_key *key;
dss_key *key;
if (size != 1024) {
dropbear_exit("DSS keys have a fixed size of 1024 bits");
}
key = (dss_key*)m_malloc(sizeof(dss_key));
key = m_malloc(sizeof(*key));
m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
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();
getq(key);
getp(key, size/8);
getp(key, size);
getg(key);
getx(key);
gety(key);
@@ -65,7 +68,7 @@ dropbear_dss_key * gen_dss_priv_key(unsigned int size) {
}
static void getq(dropbear_dss_key *key) {
static void getq(dss_key *key) {
char buf[QSIZE];
@@ -78,12 +81,12 @@ static void getq(dropbear_dss_key *key) {
/* 18 rounds are required according to HAC */
if (mp_prime_next_prime(key->q, 18, 0) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
}
static void getp(dropbear_dss_key *key, unsigned int size) {
static void getp(dss_key *key, unsigned int size) {
DEF_MP_INT(tempX);
DEF_MP_INT(tempC);
@@ -97,7 +100,7 @@ static void getp(dropbear_dss_key *key, unsigned int size) {
/* 2*q */
if (mp_mul_d(key->q, 2, &temp2q) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
@@ -114,25 +117,25 @@ static void getp(dropbear_dss_key *key, unsigned int size) {
/* C = X mod 2q */
if (mp_mod(&tempX, &temp2q, &tempC) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
/* P = X - (C - 1) = X - C + 1*/
if (mp_sub(&tempX, &tempC, &tempP) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
if (mp_add_d(&tempP, 1, key->p) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
/* now check for prime, 5 rounds is enough according to HAC */
/* result == 1 => p is prime */
if (mp_prime_is_prime(key->p, 5, &result) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
} while (!result);
@@ -142,7 +145,7 @@ static void getp(dropbear_dss_key *key, unsigned int size) {
m_free(buf);
}
static void getg(dropbear_dss_key * key) {
static void getg(dss_key * key) {
DEF_MP_INT(div);
DEF_MP_INT(h);
@@ -152,11 +155,11 @@ static void getg(dropbear_dss_key * key) {
/* get div=(p-1)/q */
if (mp_sub_d(key->p, 1, &val) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
if (mp_div(&val, key->q, &div, NULL) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
@@ -165,12 +168,12 @@ static void getg(dropbear_dss_key * key) {
do {
/* now keep going with g=h^div mod p, until g > 1 */
if (mp_exptmod(&h, &div, key->p, key->g) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
if (mp_add_d(&h, 1, &h) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
@@ -179,15 +182,15 @@ static void getg(dropbear_dss_key * key) {
mp_clear_multi(&div, &h, &val, NULL);
}
static void getx(dropbear_dss_key *key) {
static void getx(dss_key *key) {
gen_random_mpint(key->q, key->x);
}
static void gety(dropbear_dss_key *key) {
static void gety(dss_key *key) {
if (mp_exptmod(key->g, key->x, key->p, key->y) != MP_OKAY) {
fprintf(stderr, "DSS key generation failed\n");
fprintf(stderr, "dss key generation failed\n");
exit(1);
}
}

View File

@@ -29,7 +29,7 @@
#ifdef DROPBEAR_DSS
dropbear_dss_key * gen_dss_priv_key(unsigned int size);
dss_key * gen_dss_priv_key(unsigned int size);
#endif /* DROPBEAR_DSS */

View File

@@ -25,7 +25,7 @@
#include "includes.h"
#include "dbutil.h"
#include "bignum.h"
#include "dbrandom.h"
#include "random.h"
#include "rsa.h"
#include "genrsa.h"
@@ -34,54 +34,52 @@
#ifdef DROPBEAR_RSA
static void getrsaprime(mp_int* prime, mp_int *primeminus,
mp_int* rsa_e, unsigned int size_bytes);
mp_int* rsa_e, unsigned int size);
/* mostly taken from libtomcrypt's rsa key generation routine */
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
rsa_key * gen_rsa_priv_key(unsigned int size) {
dropbear_rsa_key * key;
rsa_key * key;
DEF_MP_INT(pminus);
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 = (rsa_key*)m_malloc(sizeof(rsa_key));
key = m_malloc(sizeof(*key));
m_mp_alloc_init_multi(&key->e, &key->n, &key->d, &key->p, &key->q, NULL);
m_mp_init_multi(&pminus, &lcm, &qminus, NULL);
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();
if (mp_set_int(key->e, RSA_E) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
fprintf(stderr, "rsa generation failed\n");
exit(1);
}
while (1) {
getrsaprime(key->p, &pminus, key->e, size/16);
getrsaprime(key->q, &qminus, key->e, size/16);
getrsaprime(key->p, &pminus, key->e, size/2);
getrsaprime(key->q, &qminus, key->e, size/2);
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;
}
if (mp_mul(key->p, key->q, key->n) != MP_OKAY) {
fprintf(stderr, "rsa generation failed\n");
exit(1);
}
/* lcm(p-1, q-1) */
if (mp_lcm(&pminus, &qminus, &lcm) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
fprintf(stderr, "rsa generation failed\n");
exit(1);
}
/* de = 1 mod lcm(p-1,q-1) */
/* therefore d = (e^-1) mod lcm(p-1,q-1) */
if (mp_invmod(key->e, &lcm, key->d) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
fprintf(stderr, "rsa generation failed\n");
exit(1);
}
@@ -92,43 +90,43 @@ 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_bytes) {
mp_int* rsa_e, unsigned int size) {
unsigned char *buf;
DEF_MP_INT(temp_gcd);
buf = (unsigned char*)m_malloc(size_bytes);
buf = (unsigned char*)m_malloc(size+1);
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_bytes);
buf[0] |= 0x80;
genrandom(buf, size+1);
buf[0] |= 0x80; /* MSB set */
bytes_to_mp(prime, buf, size_bytes);
bytes_to_mp(prime, buf, size+1);
/* find the next integer which is prime, 8 round of miller-rabin */
if (mp_prime_next_prime(prime, 8, 0) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
fprintf(stderr, "rsa generation failed\n");
exit(1);
}
/* subtract one to get p-1 */
if (mp_sub_d(prime, 1, primeminus) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
fprintf(stderr, "rsa generation failed\n");
exit(1);
}
/* check relative primality to e */
if (mp_gcd(primeminus, rsa_e, &temp_gcd) != MP_OKAY) {
fprintf(stderr, "RSA generation failed\n");
fprintf(stderr, "rsa generation failed\n");
exit(1);
}
} while (mp_cmp_d(&temp_gcd, 1) != MP_EQ); /* while gcd(p-1, e) != 1 */
/* now we have a good value for result */
mp_clear(&temp_gcd);
m_burn(buf, size_bytes);
m_burn(buf, size+1);
m_free(buf);
}

View File

@@ -29,7 +29,7 @@
#ifdef DROPBEAR_RSA
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size);
rsa_key * gen_rsa_priv_key(unsigned int size);
#endif /* DROPBEAR_RSA */

View File

@@ -1,132 +0,0 @@
#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) {
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;
}

View File

@@ -1,8 +0,0 @@
#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,49 +120,19 @@
#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"
#else
#include <tomcrypt.h>
#include <tommath.h>
#endif
#include "compat.h"
#include "fake-rfc2553.h"
#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_UINT16_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

57
kex.h
View File

@@ -27,33 +27,16 @@
#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();
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,
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,
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();
@@ -68,49 +51,19 @@ struct KEXState {
unsigned sentkexinit : 1; /*set when we've sent/recv kexinit packet */
unsigned recvkexinit : 1;
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 firstfollows : 1; /* true when first_kex_packet_follows is set */
unsigned sentnewkeys : 1; /* set once we've send/recv'ed MSG_NEWKEYS*/
unsigned recvnewkeys : 1;
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,6 +2,8 @@
* 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.
@@ -34,11 +36,6 @@
#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); \
@@ -112,7 +109,7 @@ static sign_key *dropbear_read(const char* filename) {
buffer * buf = NULL;
sign_key *ret = NULL;
enum signkey_type type;
int type;
buf = buf_new(MAX_PRIVKEY_SIZE);
if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) {
@@ -128,8 +125,6 @@ static sign_key *dropbear_read(const char* filename) {
}
buf_free(buf);
ret->type = type;
return ret;
error:
@@ -145,13 +140,25 @@ 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, key->type);
buf_put_priv_key(buf, key, keytype);
fp = fopen(filename, "w");
if (!fp) {
@@ -342,7 +349,7 @@ struct mpint_pos { void *start; int bytes; };
* Code to read and write OpenSSH private keys.
*/
enum { OSSH_DSA, OSSH_RSA, OSSH_EC };
enum { OSSH_DSA, OSSH_RSA };
struct openssh_key {
int type;
int encrypted;
@@ -385,8 +392,6 @@ 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;
@@ -501,7 +506,7 @@ static int openssh_encrypted(const char *filename)
return ret;
}
static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
static sign_key *openssh_read(const char *filename, char *passphrase)
{
struct openssh_key *key;
unsigned char *p;
@@ -511,13 +516,11 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
char *errmsg;
char *modptr = NULL;
int modlen = -9999;
enum signkey_type type;
int type;
sign_key *retkey;
buffer * blobbuf = NULL;
retkey = new_sign_key();
key = load_openssh_key(filename);
if (!key)
@@ -594,8 +597,6 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(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.
@@ -604,10 +605,8 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
if (key->type == OSSH_DSA) {
buf_putstring(blobbuf, "ssh-dss", 7);
retkey->type = DROPBEAR_SIGNKEY_DSS;
} else if (key->type == OSSH_RSA) {
buf_putstring(blobbuf, "ssh-rsa", 7);
retkey->type = DROPBEAR_SIGNKEY_RSA;
}
for (i = 0; i < num_integers; i++) {
@@ -621,18 +620,11 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase))
}
if (i == 0) {
/* First integer is a version indicator */
int expected;
switch (key->type) {
case OSSH_RSA:
case OSSH_DSA:
expected = 0;
break;
case OSSH_EC:
expected = 1;
break;
}
if (len != 1 || p[0] != expected) {
/*
* The first integer should be zero always (I think
* this is some sort of version indication).
*/
if (len != 1 || p[0] != 0) {
errmsg = "Version number mismatch";
goto error;
}
@@ -663,136 +655,21 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(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.
*/
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;
}
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;
}
errmsg = NULL; /* no error */
@@ -826,284 +703,202 @@ static int openssh_write(const char *filename, sign_key *key,
char zero[1];
int ret = 0;
FILE *fp;
int keytype = -1;
#ifdef DROPBEAR_RSA
mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */
#endif
if (key->type == DROPBEAR_SIGNKEY_RSA || key->type == DROPBEAR_SIGNKEY_DSS)
{
/*
* Fetch the key blobs.
*/
keyblob = buf_new(3000);
buf_put_priv_key(keyblob, key, key->type);
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';
#ifdef DROPBEAR_RSA
if (key->type == 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 */
#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";
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';
#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 */
#ifdef DROPBEAR_DSS
if (keytype == 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;
}
/*
* 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)/../ -DLTC_SOURCE -I$(srcdir)/../libtommath/
CFLAGS += -c -I$(srcdir)/src/headers/ -I$(srcdir)/../
# additional warnings (newer GCC 3.4 and higher)
ifdef GCC_34
@@ -157,53 +157,7 @@ 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/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
src/modes/ofb/ofb_start.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 5
#define TAB_SIZE 4
/* error codes [will be expanded in future releases] */
enum {

View File

@@ -78,7 +78,7 @@
/* #define LTC_CLEAN_STACK */
/* disable all file related functions */
#define LTC_NO_FILE
/* #define LTC_NO_FILE */
/* disable all forms of ASM */
/* #define LTC_NO_ASM */
@@ -118,41 +118,18 @@
#define LTC_CTR_MODE
#endif
#define SHA1
#ifdef DROPBEAR_MD5
#define MD5
#endif
#ifdef DROPBEAR_SHA256
#define SHA256
#endif
#ifdef DROPBEAR_SHA384
#define SHA384
#endif
#ifdef DROPBEAR_SHA512
#if defined(DROPBEAR_DSS) && defined(DSS_PROTOK)
#define SHA512
#endif
#define LTC_HMAC
#define SHA1
#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
#ifdef DROPBEAR_MD5_HMAC
#define MD5
#endif
#define LTC_HMAC
/* Various tidbits of modern neatoness */
#define BASE64

View File

@@ -11,9 +11,12 @@
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 {
@@ -386,6 +389,8 @@ 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
@@ -411,6 +416,7 @@ 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 = {0};
ltc_math_descriptor ltc_mp;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -170,8 +170,8 @@ clean:
rm -f *.bat *.pdf *.o *.a *.obj *.lib *.exe *.dll etclib/*.o demo/demo.o test ltmtest mpitest mtest/mtest mtest/mtest.exe \
*.idx *.toc *.log *.aux *.dvi *.lof *.ind *.ilg *.ps *.log *.s mpi.c *.da *.dyn *.dpi tommath.tex `find . -type f | grep [~] | xargs` *.lo *.la
rm -rf .libs
-cd etc && MAKE=${MAKE} ${MAKE} clean
-cd pics && MAKE=${MAKE} ${MAKE} clean
cd etc ; MAKE=${MAKE} ${MAKE} clean
cd pics ; MAKE=${MAKE} ${MAKE} clean
#zipup the project (take that!)
no_oops: clean

View File

@@ -67,13 +67,13 @@ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode
/* init M array */
/* init first cell */
if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) {
if ((err = mp_init(&M[1])) != MP_OKAY) {
return err;
}
/* now init the second half of the array */
for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) {
if ((err = mp_init(&M[x])) != MP_OKAY) {
for (y = 1<<(winsize-1); y < x; y++) {
mp_clear (&M[y]);
}
@@ -133,7 +133,7 @@ int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode
}
/* setup result */
if ((err = mp_init_size (&res, P->alloc)) != MP_OKAY) {
if ((err = mp_init (&res)) != MP_OKAY) {
goto LBL_M;
}

View File

@@ -20,7 +20,7 @@ int mp_init_copy (mp_int * a, mp_int * b)
{
int res;
if ((res = mp_init_size (a, b->used)) != MP_OKAY) {
if ((res = mp_init (a)) != MP_OKAY) {
return res;
}
return mp_copy (b, a);

View File

@@ -22,7 +22,7 @@ mp_mod (mp_int * a, mp_int * b, mp_int * c)
mp_int t;
int res;
if ((res = mp_init_size (&t, b->used)) != MP_OKAY) {
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}

View File

@@ -21,7 +21,7 @@ int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
int res;
mp_int t;
if ((res = mp_init_size (&t, c->used)) != MP_OKAY) {
if ((res = mp_init (&t)) != MP_OKAY) {
return res;
}

View File

@@ -143,7 +143,7 @@ int mp_prime_next_prime(mp_int *a, int t, int bbs_style)
/* is this prime? */
for (x = 0; x < t; x++) {
mp_set(&b, ltm_prime_tab[x]);
mp_set(&b, ltm_prime_tab[t]);
if ((err = mp_prime_miller_rabin(a, &b, &res)) != MP_OKAY) {
goto LBL_ERR;
}

49
list.c
View File

@@ -1,49 +0,0 @@
#include "options.h"
#include "dbutil.h"
#include "list.h"
void list_append(m_list *list, void *item) {
m_list_elem *elem;
elem = m_malloc(sizeof(*elem));
elem->item = item;
elem->list = list;
elem->next = NULL;
if (!list->first) {
list->first = elem;
elem->prev = NULL;
} else {
elem->prev = list->last;
list->last->next = elem;
}
list->last = elem;
}
m_list * list_new() {
m_list *ret = m_malloc(sizeof(m_list));
ret->first = ret->last = NULL;
return ret;
}
void * list_remove(m_list_elem *elem) {
void *item = elem->item;
m_list *list = elem->list;
if (list->first == elem)
{
list->first = elem->next;
}
if (list->last == elem)
{
list->last = elem->prev;
}
if (elem->prev)
{
elem->prev->next = elem->next;
}
if (elem->next)
{
elem->next->prev = elem->prev;
}
m_free(elem);
return item;
}

28
list.h
View File

@@ -1,28 +0,0 @@
#ifndef _DROPBEAR_LIST_H
#define _DROPBEAR_LIST_H
struct _m_list;
struct _m_list_elem {
void *item;
struct _m_list_elem *next;
struct _m_list_elem *prev;
struct _m_list *list;
};
typedef struct _m_list_elem m_list_elem;
struct _m_list {
m_list_elem *first;
m_list_elem *last;
};
typedef struct _m_list m_list;
m_list * list_new();
void list_append(m_list *list, void *item);
/* returns the item for the element removed */
void * list_remove(m_list_elem *elem);
#endif /* _DROPBEAR_LIST_H */

View File

@@ -329,6 +329,8 @@ 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,16 +73,16 @@
#else
/* Simply select your favourite login types. */
/* Can't do if-else because some systems use several... <sigh> */
# if defined(HAVE_UTMPX_H) && defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX)
# define USE_UTMPX
# endif
# if defined(HAVE_UTMP_H) && defined(UTMP_FILE) && !defined(DISABLE_UTMP)
# if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
# define USE_UTMP
# endif
# if defined(HAVE_WTMPX_H) && defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
# define USE_WTMPX
# endif
# if defined(HAVE_WTMP_H) && defined(WTMP_FILE) && !defined(DISABLE_WTMP)
# if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
# define USE_WTMP
# endif

View File

@@ -1,137 +0,0 @@
/* 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 */

View File

@@ -1,13 +0,0 @@
#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 */

128
options.h
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. */
/* IMPORTANT: Many options will require "make clean" after changes */
/******************************************************************
* Define compile-time options below - the "#ifndef DROPBEAR_XXX .... #endif"
* parts are to allow for commandline -DDROPBEAR_XXX options etc.
******************************************************************/
#ifndef DROPBEAR_DEFPORT
#define DROPBEAR_DEFPORT "22"
@@ -26,9 +26,6 @@
#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,9 +46,8 @@
/*#define NO_FAST_EXPTMOD*/
/* Set this if you want to use the DROPBEAR_SMALL_CODE option. This can save
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. */
several kB in binary size, however will make the symmetrical ciphers (AES, DES
etc) slower (perhaps by 50%). Recommended for most small systems. */
#define DROPBEAR_SMALL_CODE
/* Enable X11 Forwarding - server only */
@@ -67,9 +63,8 @@ much traffic. */
#define ENABLE_SVR_LOCALTCPFWD
#define ENABLE_SVR_REMOTETCPFWD
/* Enable Authentication Agent Forwarding */
#define ENABLE_SVR_AGENTFWD
#define ENABLE_CLI_AGENTFWD
/* Enable Authentication Agent Forwarding - server only for now */
#define ENABLE_AGENTFWD
/* Note: Both ENABLE_CLI_PROXYCMD and ENABLE_CLI_NETCAT must be set to
@@ -83,9 +78,6 @@ much traffic. */
* to a remote TCP-forwarded connection */
#define ENABLE_CLI_NETCAT
/* Whether to support "-c" and "-m" flags to choose ciphers/MACs at runtime */
#define ENABLE_USER_ALGO_LIST
/* Encryption - at least one required.
* Protocol RFC requires 3DES and recommends AES128 for interoperability.
* Including multiple keysize variants the same cipher
@@ -93,8 +85,7 @@ much traffic. */
#define DROPBEAR_AES128
#define DROPBEAR_3DES
#define DROPBEAR_AES256
/* Compiling in Blowfish will add ~6kB to runtime heap memory usage */
/*#define DROPBEAR_BLOWFISH*/
#define DROPBEAR_BLOWFISH
#define DROPBEAR_TWOFISH256
#define DROPBEAR_TWOFISH128
@@ -103,18 +94,12 @@ much traffic. */
* size and is recommended for most cases */
#define DROPBEAR_ENABLE_CTR_MODE
/* You can compile with no encryption if you want. In some circumstances
* this could be safe security-wise, though make sure you know what
* you're doing. Anyone can see everything that goes over the wire, so
* the only safe auth method is public key. */
/* #define DROPBEAR_NONE_CIPHER */
/* Message Integrity - at least one required.
* Protocol RFC requires sha1 and recommends sha1-96.
* sha1-96 is of use for slow links as it has a smaller overhead.
* sha1-96 may be of use for slow links, as it has a smaller overhead.
*
* There's no reason to disable sha1 or sha1-96 to save space since it's
* used for the random number generator and public-key cryptography anyway.
* Note: there's no point disabling sha1 to save space, since it's used
* for the random number generator and public-key cryptography anyway.
* Disabling it here will just stop it from being used as the integrity portion
* of the ssh protocol.
*
@@ -123,55 +108,28 @@ 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_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 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
* for hostkey as well as for verifying signatures with pubkey auth.
* Removing either of these won't save very much space.
* 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
/* 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
/* 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
/* 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
* zlib.h for full details.
* Default settings (windowBits=15) will use 256kB for compression
* windowBits=8 will use 129kB for compression.
* Both modes will use ~35kB for decompression (using windowBits=15 for
* interoperability) */
#ifndef DROPBEAR_ZLIB_WINDOW_BITS
#define DROPBEAR_ZLIB_WINDOW_BITS 15
#endif
/* Define DSS_PROTOK to use PuTTY's method of generating the value k for dss,
* rather than just from the random byte source. Undefining this will save you
* ~4k in binary size with static uclibc, but your DSS hostkey could be exposed
* if the random number source isn't good. In general this isn't required */
/* #define DSS_PROTOK */
/* 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 */
@@ -185,20 +143,18 @@ much traffic. */
/* Authentication Types - at least one required.
RFC Draft requires pubkey auth, and recommends password */
/* Note: PAM auth is quite simple and only works for PAM modules which just do
/* Note: PAM auth is quite simple, and only works for PAM modules which just do
* a simple "Login: " "Password: " (you can edit the strings in svr-authpam.c).
* It's useful for systems like OS X where standard password crypts don't work
* but there's an interface via a PAM module. It won't work for more complex
* PAM challenge/response.
* It's useful for systems like OS X where standard password crypts don't work,
* but there's an interface via a PAM module - don't bother using it otherwise.
* You can't enable both PASSWORD and PAM. */
#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
* authorized_keys file into account */
/* Wether to ake public key options in authorized_keys file into account */
#ifdef ENABLE_SVR_PUBKEY_AUTH
#define ENABLE_SVR_PUBKEY_OPTIONS
#endif
@@ -222,21 +178,21 @@ 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 */
/* Random device to use - define either DROPBEAR_RANDOM_DEV or
* DROPBEAR_PRNGD_SOCKET.
* DROPBEAR_RANDOM_DEV is recommended on hosts with a good /dev/(u)random,
* otherwise use run prngd (or egd if you want), specifying the socket.
* The device will be queried for a few dozen bytes of seed a couple of times
* per session (or more for very long-lived sessions). */
/* 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 */
#define DROPBEAR_URANDOM_DEV "/dev/urandom"
/* We'll use /dev/urandom by default, since /dev/random is too much hassle.
* If system developers aren't keeping seeds between boots nor getting
* any entropy from somewhere it's their own fault. */
#define DROPBEAR_RANDOM_DEV "/dev/urandom"
/* Set this to use PRNGD or EGD instead of /dev/urandom or /dev/random */
/* prngd must be manually set up to produce output */
/*#define DROPBEAR_PRNGD_SOCKET "/var/run/dropbear-rng"*/
/* Specify the number of clients we will allow to be connected but
* not yet authenticated. After this limit, connections are rejected */
/* The first setting is per-IP, to avoid denial of service */
@@ -264,7 +220,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/X11R6/bin/xauth -q"
#endif
/* if you want to enable running an sftp server (such as the one included with
@@ -290,19 +246,13 @@ much traffic. */
significant difference to network performance. 24kB was empirically
chosen for a 100mbit ethernet network. The value can be altered at
runtime with the -W argument. */
#ifndef DEFAULT_RECV_WINDOW
#define DEFAULT_RECV_WINDOW 24576
#endif
/* Maximum size of a received SSH data packet - this _MUST_ be >= 32768
in order to interoperate with other implementations */
#ifndef RECV_MAX_PAYLOAD_LEN
#define RECV_MAX_PAYLOAD_LEN 32768
#endif
/* Maximum size of a transmitted data packet - this can be any value,
though increasing it may not make a significant difference. */
#ifndef TRANS_MAX_PAYLOAD_LEN
#define TRANS_MAX_PAYLOAD_LEN 16384
#endif
/* Ensure that data is transmitted every KEEPALIVE seconds. This can
be overridden at runtime with -K. 0 disables keepalives */

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