Compare commits

...

274 Commits

Author SHA1 Message Date
Andreas Schneider
9e99408dba Bump version to 0.6.5
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-04-29 12:24:33 +02:00
Andreas Schneider
6b49863bb0 Update Changelog
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-04-29 12:23:50 +02:00
Aris Adamantiadis
e9d16bd343 buffers: Fix a possible null pointer dereference
This is an addition to CVE-2015-3146 to fix the null pointer
dereference. The patch is not required to fix the CVE but prevents
issues in future.

Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 3091025472)
2015-04-23 10:34:13 +02:00
Aris Adamantiadis
94f6955fba CVE-2015-3146: Fix state validation in packet handlers
The state validation in the packet handlers for SSH_MSG_NEWKEYS and
SSH_MSG_KEXDH_REPLY had a bug which did not raise an error.

The issue has been found and reported by Mariusz Ziule.

Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit bf0c7ae0ae)
2015-04-23 10:34:12 +02:00
Kevin Fan
d2a990a68e Fix leak of sftp->ext when sftp_new() fails
Signed-off-by: Kevin Fan <kevinfan@google.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit b5dc8197f7)
2015-04-14 20:57:17 +02:00
Andreas Schneider
584ab49b7b cmake: Detect network function correctly on Windows
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 195f25cfbd)
2015-04-10 14:32:53 +02:00
Andreas Schneider
dc30183d8a cmake: Detect __func__ and __FUNCTION__ during configure step
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-04-02 13:42:12 +02:00
Andreas Schneider
396f5e2110 include: We should use __func__ which is C99
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-04-02 10:57:18 +02:00
Seb Boving
6b18f0b4b0 Locally restart ssh_poll() upon EINTR.
BUG: https://red.libssh.org/issues/186

Reviewed-by: Aris Adamantiadis <aris@0xbadc0de.be>
Signed-off-by: Sebastien Boving <seb@google.com>
2015-02-23 22:06:34 +01:00
xjoaalm
8f2eee6509 Sending EOF on Socket that received a Broken Pipe makes call to poll to hang
Reviewed-by: Aris Adamantiadis <aris@0xbadc0de.be>
Signed-off-by: Joao Pedro Almeida Pereira <joao.almeida@blue-tc.com>
2015-02-23 22:02:35 +01:00
Aris Adamantiadis
4bd704295c examples: cast arguments of connect(2)
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2015-02-14 22:20:45 +01:00
Aris Adamantiadis
be2f5399dd torture: fix includes for freebsd10 2015-02-14 22:13:58 +01:00
Aris Adamantiadis
a672b3e7bb tests: torture-misc: check for NULL return codes
Use the LOGNAME environment variable if USER is not set, as it sometimes
happens in cron jobs.
2015-02-12 11:39:53 +01:00
Aris Adamantiadis
ddc3f987a7 tests: workaround for compiling with older cmocka 2015-02-12 11:39:45 +01:00
Aris Adamantiadis
e9ad0c3c69 sftp: fix endianess issue 2015-02-11 21:35:02 +01:00
Andreas Schneider
2ccab05cba connect: Fix mingw build.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a198193723)
2015-01-26 17:10:19 +01:00
Andreas Schneider
58348fcc57 sftp: Fix sftp_get_new_id().
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-01-21 08:44:34 +01:00
Léo Peltier
0579b7d8b2 cmake: Add libsshpp.hpp to the distributed headers list.
BUG: https://red.libssh.org/issues/163

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8db4520d89)
2015-01-20 19:33:16 +01:00
Andreas Schneider
915d28ffa5 pki: Make sure sig is not used unintialized.
BUG: https://red.libssh.org/issues/167

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 9a7d450098)
2015-01-20 19:31:29 +01:00
Andreas Schneider
884bff5bdc sftp: Fix sftp endianess bugs.
BUG: https://red.libssh.org/issues/179

This is a backport of 6019cf1bed.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2015-01-20 19:17:02 +01:00
Andreas Schneider
08c33d6aeb threads: Fix building with POSIX threads in MinGW.
BUG: https://red.libssh.org/issues/181

Originally written by Patrick von Reth <vonreth () kde ! org>.

This patch is part of the larger patch:
https://projects.kde.org/projects/kdesupport/emerge/repository/revisions/master/changes/portage/win32libs/libssh/0002-add-a-way-to-test-ssh-connections-on-windows.patch

MinGW (in particular, the MinGW-w64 fork) can use either posix threads
or win32 threads. This patch fixes the MinGW build when using posix
threads.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 433f8fd550)
2015-01-20 19:03:08 +01:00
Yanis Kurganov
fa4740bdf5 channels1: Fix pty request state
Signed-off-by: Yanis Kurganov <YKurganov@ptsecurity.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c6590bd189)
2015-01-20 18:59:01 +01:00
Andreas Schneider
da91ca43c0 connect: Fix a memory leak.
CID: #1238618

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Aris Adamantiadis <aris@0xbadc0de.be>
(cherry picked from commit 06a0d8ff1c)
2015-01-14 15:21:41 +01:00
Andreas Schneider
4de6a708ad sftp: Fix a possible integer overflow.
CID: #1238630

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Aris Adamantiadis <aris@0xbadc0de.be>
(cherry picked from commit af0dd3fb02)
2015-01-14 15:21:40 +01:00
Andreas Schneider
fd3b1f63a1 sftp: Use a declared variable for data len.
CID: #1238632

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Aris Adamantiadis <aris@0xbadc0de.be>
(cherry picked from commit ce02f6576a)
2015-01-14 15:21:36 +01:00
Andreas Schneider
914f8abde8 cmake: Fix ntohll and htonll macro detection.
BUG: https://red.libssh.org/issues/164

Thanks to Ryan Schmidt!

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8536cd9808)
2015-01-13 08:55:07 +01:00
Aris Adamantiadis
3880a8ed80 Fix the dh.c build with libgcrypt
Fixes bug reported by gentoo at https://bugs.gentoo.org/show_bug.cgi?id=533424
The function was only used by EDCSA backend which are not supported by the libgcrypt code anyway.
2014-12-29 16:06:33 +01:00
Andreas Schneider
0e969e0316 connect: Check that errno is 0 to fix Windows build.
Thanks to Viktor Butskih.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit e051135a05)
2014-12-25 12:35:24 +01:00
Andreas Schneider
a45dd8e000 options: Fix setting the port.
Make sure we correctly read the port from the config file.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit bb18442fe8)
2014-12-25 12:35:21 +01:00
Andreas Schneider
319129399d Bump version to 0.6.4. 2014-12-17 19:45:23 +01:00
Jon Simons
87ae95eb3c CVE-2014-8132: Fixup error path in ssh_packet_kexinit()
Before this change, dangling pointers can be unintentionally left in the
respective next_crypto kex methods slots.  Ensure to set all slots to
NULL in the error-out path.

Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 2ced24ddd67a261dc364ad4d8958c068c1671ae7)
2014-12-17 19:45:23 +01:00
Andreas Schneider
055f102601 libcrypto: Fix Windows build with ssh_reseed().
gettimeofday() is not available on Windows and we need it only in case
of forking.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit b7b535816d)
2014-12-17 19:40:57 +01:00
Andreas Schneider
2d6862ddb9 cmake: Fix the build on Windows.
(cherry picked from commit a738507ad2)
2014-12-17 19:31:32 +01:00
Andreas Schneider
22aa60d506 cmake: Fix config variable names.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit d8e691b58a)
2014-12-17 10:40:31 +01:00
Andreas Schneider
4b02bbbd32 cmake: Fix libssh cmake-config files.
(cherry picked from commit 142b2e4ede)
2014-12-17 10:40:25 +01:00
William Orr
31ded2070e config: Also tokenize on equal sign.
The ssh config specifies it as a valid separator.

BUG: https://red.libssh.org/issues/166

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 52968b1a11)
2014-12-17 10:35:17 +01:00
Davide \"FunkyAss\" Del Zompo
df3d53e561 doc: clarify tutorial error section
Signed-off-by: Davide "FunkyAss" Del Zompo <davide.delzompo@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit bb197de75d)
2014-12-05 11:09:34 +01:00
Hani Benhabiles
f28c3099da Set the correct error in ssh_options_set().
Signed-off-by: Hani Benhabiles <hani@linux.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 03095f1516)
2014-12-05 11:04:35 +01:00
Andreas Schneider
32a106c70d messages: Fix a possible double free.
Thanks to Ramana Gampa.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2014-12-05 10:59:41 +01:00
Jon Simons
5d75090d9f pki_crypto.c: plug ecdsa_sig->[r,s] bignum leaks
Per ecdsa(3ssl), ECDSA_SIG_new does allocate its 'r' and 's' bignum fields.
Fix a bug where the initial 'r' and 's' bignums were being overwritten with
newly-allocated bignums, resulting in a memory leak.

BUG: https://red.libssh.org/issues/175

Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>

(cherry picked from commit 4745d652b5)
2014-12-05 10:46:31 +01:00
Andreas Schneider
32a3cfe661 connect: Do not fail if the connect is in progress.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a48711ae7e)
2014-10-28 10:33:47 +01:00
Stef Walter
1c59844dfe gssapi: ssh_gssapi_set_creds() is a client side function
It should not be guarded by the WITH_SERVER #ifdef

Signed-off-by: Stef Walter <stefw@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit cd2dc3770a)
2014-10-12 15:47:13 +02:00
William Orr
f071954a76 Check return code of connect(2).
Signed-off-by: William Orr <will@worrbase.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 250f506487)
2014-10-12 15:47:12 +02:00
Artyom V. Poptsov
a033b93c61 pki_gcrypt: Initialize 'type_c' in 'pki_do_sign_sessionid'
Add missing initialization of 'type_c' field of a SSH signature in
'pki_do_sign_sessionid' procedure.

If libssh is compiled with GCrypt, 'dh_handshake_server' fails with
"Could not sign the session id" error.  The change fixes that.

Signed-off-by: Artyom V. Poptsov <poptsov.artyom@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit aaae6cd97d)
2014-10-02 08:30:30 +02:00
Jon Simons
b7856780a9 crypto: check malloc return in ssh_mac_ctx_init
Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit af25c5e668)
2014-10-02 08:26:08 +02:00
Jon Simons
8b3425865a wrapper: fix z_stream leak
Ensure to free the z_stream structures as allocated from
the gzip.c initcompress, initdecompress functions.

Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 092fe0b727)
2014-10-02 08:25:27 +02:00
Andreas Schneider
a30e234c03 string: Correctly burn the string buffer.
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Aris Adamantiadis <aris@0xbadc0de.be>
(cherry picked from commit 1ddb99c46f)
2014-09-15 20:46:06 +02:00
Jon Simons
bbf172a79c session: fix ssh_session->srv.ecdsa_key leak
Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-05-28 10:24:01 +02:00
Andreas Schneider
f28748578d pki: Fix build without ECC support.
Signed-off-by: Andreas Schneider <asn@samba.org>
2014-05-09 08:56:10 +02:00
Andreas Schneider
36f7d1a614 pki: Add missing semi-colon. 2014-05-07 09:36:11 +02:00
Andreas Schneider
71241ca68c pki: Move ssh_pki_key_ecdsa_name() to the correct file. 2014-05-07 09:35:49 +02:00
Andreas Schneider
bfbf9283d0 cmake: Fix doxygen. 2014-05-07 09:35:34 +02:00
Andreas Schneider
d75573e665 cmake: Update doxygen module. 2014-05-07 09:35:34 +02:00
Jon Simons
8fe36e3d07 pki crypto: expose new ssh_pki_key_ecdsa_name API
Enable retrieving the "ecdsa-sha2-nistpNNN" name of ECDSA keys with a
new 'ssh_pki_key_ecdsa_name' API.  This gives more information than the
'ssh_key_type_to_char' API, which yields "ssh-ecdsa" for ECDSA keys.
The motivation is that this info is useful to have in a server context.

The torture_pki unit test is updated to include the new API, and a few
more passes are added to additionally test 384 and 521-bit keys.

Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-05-07 09:35:06 +02:00
Alan Dunn
f2e9ce68e7 messages: Add missing ntohl on X11 request screen number
BUG: https://red.libssh.org/issues/160

Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-05-06 08:56:55 +02:00
Andreas Schneider
cfb4d27c47 pki: Correctly update the ECDSA keytype.
(cherry picked from commit 2884bbf5b1)
2014-05-06 08:54:11 +02:00
Andreas Schneider
d366e289f3 pki: Move ssh_pki_key_ecdsa_name() to the correct file.
(cherry picked from commit f48a99b97c)
2014-05-06 08:54:06 +02:00
Andreas Schneider
2fc8347504 pki: Make pki_key_ecdsa_nid_to_name() a shared function.
(cherry picked from commit 11cfb2903e)
2014-05-06 08:54:00 +02:00
Andreas Schneider
2691ed595e cmake: Install cmake config files to the correct directory.
(cherry picked from commit 291312c5e4)
2014-04-22 09:10:05 +02:00
Andreas Schneider
7b133cf9f5 doc: Improve docs for ssh_channel_get_exit_status().
BUG: https://red.libssh.org/issues/154
(cherry picked from commit adf23533e0)
2014-04-22 09:09:57 +02:00
Andreas Schneider
9b59f1a222 channels: Fix exit-signal request.
BUG: https://red.libssh.org/issues/153
(cherry picked from commit 927cd90dc1)
2014-04-22 09:09:56 +02:00
Andreas Schneider
8f21f879d3 session: Fix a memory leak with custom banner.
BUG: https://red.libssh.org/issues/152
(cherry picked from commit b5efbe75cd)
2014-04-22 09:09:39 +02:00
Andreas Schneider
67752dabfc cmake: Enable creation of the compile command database by default.
(cherry picked from commit 437a39c798)
2014-04-22 09:09:28 +02:00
Jon Simons
34ac4e4248 packet: elide two buffer_prepend calls into one
In packet_send2, rather than issue two separate buffer_prepend_data calls
(each of which may entail realloc + memmove + memcpy), elide the prepend
work into a single buffer_prepend_data: the header information is computed
locally, and a single 5 byte prepend operation is now done instead of
prepending 1, then 4 bytes.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit aa05248ca8)

Conflicts:
	src/packet.c
2014-03-27 11:25:15 +01:00
Andreas Schneider
1928fb6a85 doc: Fix ssh_userauth_none() function signature.
Thanks to David Tibbe!

BUG: https://red.libssh.org/issues/151
(cherry picked from commit 04543c9dbc)
2014-03-27 11:16:23 +01:00
Alan Dunn
5b1678f197 doc: Improve and consolidate ssh_bind_options_set docs
Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 47bd0b6d1f)
2014-03-27 11:15:39 +01:00
Petar Koretic
8aff91dfcb libssh: libhpp: overload read function to support timeout parameter
Signed-off-by: Petar Koretic <petar.koretic@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8e2590b535)
2014-03-27 11:15:39 +01:00
Petar Koretic
c0cc12d582 libssh: libhpp: avoid unnecessary call to ssh_channel_read
ssh_channel_read is a wrapper for ssh_channel_read_timeout with timeout
-1 (infinite) so we call that directly.

Signed-off-by: Petar Koretic <petar.koretic@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c51f42a566)
2014-03-27 11:15:39 +01:00
Petar Koretic
a162071f9a libssh: libhpp: fix multiple definitions for acceptForward function
Defining a non inlined class function in a header will cause multiple
definitions when header is included in more that one file since for each
file function will get defined.

Signed-off-by: Petar Koretic <petar.koretic@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 00d4fbe753)

Conflicts:
	include/libssh/libsshpp.hpp
2014-03-27 11:15:19 +01:00
Jon Simons
2091dab273 channel: check for closed state in waitwindow loops
Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit dee8e5688b)
2014-03-27 11:14:25 +01:00
Jon Simons
7f18ec4620 kex: enable more ECDSA hostkey algos
Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 40d81bb7ca)
2014-03-27 11:14:25 +01:00
Jon Simons
8e698382db pki_crypto: guard against NULL pubkey->rsa in signature extraction
Signed-off-by: Jon Simons <jon@jonsimons.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 10bc5ac203)
2014-03-27 11:14:25 +01:00
Luka Perkov
ce10d40325 session: fix comment typo
Signed-off-by: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8ba9402282)
2014-03-27 11:14:25 +01:00
Luka Perkov
3fed9a5aff messages: use predefined macro for clearing sensitive data
Signed-off-by: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a2fe341da5)
2014-03-27 11:14:25 +01:00
Luka Perkov
da0c77fdb1 client: fix corner case when sockets are manually created
If the sockets are created manually and passed to libssh the internal session
state is set to SSH_SESSION_STATE_SOCKET_CONNECTED. Result of this fix can be
verified by running torture_connect test (torture_connect_socket) with -vvvv
flags.

Signed-off-by: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit dbb2de272b)
2014-03-27 11:14:25 +01:00
Luka Perkov
818c80baed tests: torture_connect: add test for user provided socket
Signed-off-by: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 9423a3a065)
2014-03-27 11:14:25 +01:00
Luka Perkov
bb55bb2daf tests: torture_connect: fix coding style
Signed-off-by: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 0c5d4954a7)
2014-03-27 11:14:25 +01:00
Petar Koretic
fdced9d544 pki_crypto: Replace deprecated RSA_generate_key() with RSA_generate_key_ex()
On Mar 16, 09:41, Aris Adamantiadis wrote:
> Hi Petar,
> I agree with the principle, but I don't think this code can work...
> RSA_generate_key takes an RSA* as parameter and in our code we probably
> have key->rsa==NULL. (if we don't then the old code had a memory leak).
>
> Does the test case work ?
>
> Aris
>

Yes, you are right. This works, tested with tests/unittests/torture_pki

Signed-off-by: Petar Koretic <petar.koretic@sartura.hr>
(cherry picked from commit 0b8d24f800)
2014-03-27 11:14:25 +01:00
Luka Perkov
96db44ff17 update gitignore file
The libssh library by default does not allow in-source build (with cmake
MacroEnsureOutOfSourceBuild macro). The INSTALL file (implicitly) suggests
creating a build directory. So lets add build to list of git ignore files to
avoid complaints from git.

Signed-off-by: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 48354f56ec)
2014-03-27 11:14:25 +01:00
Alan Dunn
70dbbfa320 doc: Add ECDSA keys to docs, make key docs consistent
Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit f6276fe739)
2014-03-27 11:13:15 +01:00
Alan Dunn
1118fc2adf options: Allow use of host ECDSA key
Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 2a1089d607)
2014-03-27 11:13:15 +01:00
Andreas Schneider
257449a0b6 tests: Check the the ecdsa_nid is the same.
(cherry picked from commit fbf73ede1e)
2014-03-27 11:13:15 +01:00
Alan Dunn
8752460df4 tests: Add test case for bug #147
Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 577840d7f7)
2014-03-27 11:13:15 +01:00
Alan Dunn
6f089a098b pki_crypto: Always copy ecdsa_nid into duplicated ECDSA keys
BUG: https://red.libssh.org/issues/147

Signed-off-by: Alan Dunn <amdunn@gmail.com>
2014-03-12 14:16:43 +01:00
Alan Dunn
8b3be050c9 pki: Use SHA-2 for session ID signing with ECDSA keys
Previously, SHA-1 was used always.

BUG: https://red.libssh.org/issues/148

Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-03-12 14:16:35 +01:00
Luka Perkov
ade33474be server: silence build warning
The commit fixes this build warning:

====
src/server.c:223:8: warning: ‘privkey’ may be used uninitialized in this function [-Wmaybe-uninitialized]
     rc = ssh_pki_export_privkey_to_pubkey(*privkey, &pubkey);
        ^
src/server.c:243:11: note: ‘privkey’ was declared here
   ssh_key privkey;
====

Signed-off-by: Luka Perkov <luka.perkov@sartura.hr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-03-12 14:16:33 +01:00
Jon Simons
dbf7749696 packet: log disconnect code in host byte order
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-03-12 14:16:30 +01:00
Jon Simons
2db45dd547 bind: only set bindfd after successful listen
In 'ssh_bind_listen', move setting of 'sshbind->bindfd' to only happen after
the listen call: otherwise 'bindfd' can be set to a bogus descriptor for the
case that listen fails.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-03-12 14:16:28 +01:00
Andreas Schneider
87145387aa Prepare libssh-0.6.3.
We messed up some thing, so we release 0.6.3.
2014-03-04 13:20:52 +01:00
Aris Adamantiadis
d027460792 bump version to 0.6.2 2014-03-04 11:34:36 +01:00
Aris Adamantiadis
3fdd82f2a8 security: fix for vulnerability CVE-2014-0017
When accepting a new connection, a forking server based on libssh forks
and the child process handles the request. The RAND_bytes() function of
openssl doesn't reset its state after the fork, but simply adds the
current process id (getpid) to the PRNG state, which is not guaranteed
to be unique.
This can cause several children to end up with same PRNG state which is
a security issue.
2014-03-04 09:55:02 +01:00
Andreas Schneider
6cd94a63ff pki: Fix the build on OpenSolaris. 2014-02-12 09:40:09 +01:00
Andreas Schneider
e85b20ba82 pki: Fix memory leak with ecdsa signatures. 2014-02-11 10:31:51 +01:00
Andreas Schneider
78d5d64b38 Update ChangeLog. 2014-02-10 10:17:43 +01:00
Andreas Schneider
f73a44c223 cpack: Ignore obj directory. 2014-02-10 10:17:43 +01:00
Andreas Schneider
1cccfdf8a0 packet: Improve readablity of packet decrypt.
After discussion with Aris and it was not obvious enough to understand
the issue we decided to refactor it.

Reviewd-by: Aris Adamantiadis <aris@0xbadc0de.be>
2014-02-06 20:32:05 +01:00
Alan Dunn
abe4ed0e75 packet_crypt: Make packet_{en,de}crypt fail consistently on len == 0
Right now the behavior of packet_{en,de}crypt on len == 0 depends on
the behavior of malloc.  Instead, make these consistently fail based
on what I assume the desired behavior is due to the first error
message in each.

Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-06 19:40:29 +01:00
Alan Dunn
e7f831f0a3 packet: Do not decrypt zero length rest of buffer
If we receive a packet of length exactly blocksize, then
packet_decrypt gets called on a buffer of size 0.  The check at the
beginning of packet_decrypt indicates that the function should be
called on buffers of at least one blocksize, though the check allows
through zero length.  As is packet_decrypt can return -1 when len is 0
because malloc can return NULL in this case: according to the ISO C
standard, malloc is free to return NULL or a pointer that can be freed
when size == 0, and uclibc by default will return NULL here (in
"non-glibc-compatible" mode).  The net result is that when using
uclibc connections with libssh can anomalously fail.

Alternatively, packet_decrypt (and probably packet_encrypt for
consistency) could be made to always succeed on len == 0 without
depending on the behavior of malloc.

Thanks to Josh Berlin for bringing conneciton failures with uclibc to
my attention.

Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-06 19:40:09 +01:00
Raphael Kubo da Costa
4ea4e12df2 build: Use Threads_FOUND to decide whether to build ssh_threads.
Follow-up to 4e04ec8, which caused a regression on OS X.

Checking the value of CMAKE_THREAD_LIBS_INIT to decide whether any threading
library is present on a system turns out to be wrong -- in OS X, for
example, usage of pthreads does not depend on any additional linker or
compiler flags, so CMAKE_THREAD_LIBS_INIT is empty and our check in
src/CMakeLists.txt failed (it used to work before 4e04ec8 because
CMAKE_HAVE_THREADS_LIBRARY is set).

Instead, just look for Threads_FOUND, which FindThreads sets just like any
other Find module when it has found what it was looking for.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-06 11:13:23 +01:00
Jon Simons
fb49e194df session: skip timestamp init for non-blocking case
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-06 11:13:22 +01:00
Jon Simons
13f4e31ad1 session: add getters for session cipher names
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-06 11:13:20 +01:00
Aris Adamantiadis
da5fa4ef66 Revert f2c2687ca6
Fix bug #142
The mode does need to be an octal numeric string. Mode 0600 now gets sent on the wire as 0384, triggering a "scp: protocol error: bad mode" response, and an "scp status code 1d not valid" message from libssh.
2014-02-05 22:30:10 +01:00
Aris Adamantiadis
dca415a38e knownhosts: resolve leaks found by coverity 2014-02-05 08:08:31 +01:00
Aris Adamantiadis
56f86cd4a1 knownhosts: detect variations of ecdsa 2014-02-05 08:08:31 +01:00
Aris Adamantiadis
f265afacfb tests: lines lost during last cherry-pick merge 2014-02-04 16:20:20 +01:00
Aris Adamantiadis
99f8b2b803 Kex: fix coverity warning + edge case 2014-02-04 16:04:45 +01:00
Audrius Butkevicius
22edaf43ee server: use custom server banners
Value of session->serverbanner never gets used

Signed-off-by: Audrius Butkevicius <audrius.butkevicius@gmail.com>
2014-02-04 16:04:26 +01:00
Aris Adamantiadis
497bd31364 server: allow custom server banners (bug #83) 2014-02-04 16:04:26 +01:00
Aris Adamantiadis
8ed0c0b3c8 Knownhosts: implement hostkey with knownhosts heuristic 2014-02-04 16:01:37 +01:00
Aris Adamantiadis
ce39d2fa73 knownhosts: add test case for bug #138 2014-02-04 16:01:37 +01:00
Aris Adamantiadis
90d3768f0f known_hosts: add ssh_knownhosts_algorithms()
Goal of that function is to test the preferred key exchange methods
based on what's available in the known_hosts file

Conflicts:
	tests/client/torture_knownhosts.c
2014-02-04 16:01:02 +01:00
Aris Adamantiadis
6f66032209 build: remove OSX deprecated warnings for openssl 2014-02-04 15:55:37 +01:00
Raphael Kubo da Costa
c571cd8402 threads: Be less strict when deciding whether to build libssh_threads.
As mentioned in the previous commit, there are cases where
CMAKE_HAVE_THREADS_LIBRARY is not set and pthreads _is_ being used: one can
pass -DTHREADS_HAVE_PTHREAD_ARG=1 to CMake directly so that it just passes
-pthread to the compiler/linker and does not set CMAKE_HAVE_THREADS_LIBRARY.

Since we are only interested in knowing whether any threading library has
been found, we should use CMAKE_THREAD_LIBS_INIT instead (Threads_FOUND
would also work).

Note that, at the moment, there is only a pthreads backend available in
threads/, so if it is not found configuration will fail because CMake will
try to create a library from an empty set of source files.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-03 14:39:15 +01:00
Raphael Kubo da Costa
b049e12652 ConfigureChecks: Stop checking for CMAKE_HAVE_THREADS_LIBRARY.
libssh is primarily interested in whether pthreads is present and can be
used. Checking for CMAKE_HAVE_THREADS_LIBRARY is not the same thing, as
there are cases where pthread exists but CMAKE_HAVE_THREADS_LIBRARY is not
set (for example, FreeBSD passes -DTHREADS_HAVE_PTHREAD_ARG=1 to CMake by
default as a way to skip the checks for -lpthread, -lpthreads and others and
tell the build system that -pthread is the one expected to be used).

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-03 14:39:14 +01:00
Jon Simons
785682ac28 socket: fix read of non-connected socket
Ensure to check whether the socket at hand is indeed still connected
throughout POLLIN processing in ssh_socket_pollcallback.

Before this change, the POLLIN block in ssh_socket_pollcallback is
predicated against the condition (s->state == SSH_SOCKET_CONNECTED).
Once entered, data from the socket is consumed through the data
callback in this loop:

  do {
    r = s->callbacks->data(buffer_get_rest(s->in_buffer),
                           buffer_get_rest_len(s->in_buffer),
                           s->callbacks->userdata);
    buffer_pass_bytes(s->in_buffer,r);
  } while (r > 0);

However, it is possible for the socket data callback to change the
state of the socket (closing it, for example).  Fix the loop to only
continue so long as the socket remains connected: this also entails
setting the ssh_socket state to SSH_SOCKET_CLOSED upon close.

The bug can be observed before the change by sending a bogus banner
to the server: 'echo -e "A\r\nB\r\n" | nc localhost 22'.  Each of
'A' and 'B' will be processed by 'callback_receive_banner', even
though the client socket is closed after rejection of 'A'.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-02 22:21:07 +01:00
Jon Simons
f29f10876a doc: correct ssh_channel_read_timeout units
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-02 22:21:07 +01:00
Audrius Butkevicius
45d28c7682 doc: Document expected return value of channel data callback
Signed-off-by: Audrius Butkevicius <audrius.butkevicius@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-02 22:21:07 +01:00
Audrius Butkevicius
2786565e77 src: Fix argument order in ssh_channel_pty_window_change_callback
So that it would match ssh_channel_pty_request_callback as well as the documentation

Signed-off-by: Audrius Butkevicius <audrius.butkevicius@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-02 22:21:07 +01:00
Joseph Southwell
96ad690c80 src: Define MAX_BUF_SIZE globally and use it.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-02 22:21:07 +01:00
Joseph Southwell
0d82186503 client: Fix EOF session error reporting.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-02 22:21:07 +01:00
Oleksandr Shneyder
5157d96958 Make function ssh_channel_accept() nonblocking if timeout is 0.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-02-02 22:21:07 +01:00
Andreas Schneider
6a0787a366 pki_crypto: Fix memory leak with EC_KEY_set_public_key().
BUG: https://red.libssh.org/issues/146
2014-01-28 12:01:35 +01:00
Andreas Schneider
709e921942 doc: Document the unit for ssh_select() timeout.
BUG: https://red.libssh.org/issues/143
2014-01-23 11:29:58 +01:00
Rod Vagg
43a69b0a65 dh: Fix NULL check for p_group14.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-23 11:22:22 +01:00
Jon Simons
18506f697c pki_crypto: fix DSA signature extraction
Fix the DSA portion of 'pki_signature_to_blob': before this change, it
is possible to sometimes observe DSA signature validation failure when
testing with OpenSSH clients.  The problem ended up being the following
snippet which did not account for the case when 'ssh_string_len(x)' may
be less than 20:

  r = make_bignum_string(sig->dsa_sig->r);
  ...
  memcpy(buffer,
         ((char *) ssh_string_data(r)) + ssh_string_len(r) - 20,
         20);

Above consider the case that ssh_string_len(r) is 19; in that case the
memcpy unintentionally starts in the wrong place.  The same situation
can happen for value 's' in this code.

To fix, adjust the offsets used for the input and output pointers, taking
into account that the lengths of 'r' and 's' can be less than 20.  With
the fix I am no longer able to reproduce the original failure mode.

BUG: https://red.libssh.org/issues/144

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-23 11:17:45 +01:00
Alan Dunn
15bede0c0e doc: Fix description of error parameter for ssh_get_error*
ssh_get_error can actually work on anything with an ssh_common_struct
as its first member.  It is already used in examples in the
distribution with ssh_sessions and ssh_binds.

Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-22 09:46:00 +01:00
Jon Simons
92dde09a37 pki_crypto: pad RSA signature blobs
Pad RSA signature blobs to the expected RSA signature length
when processing via 'pki_signature_to_blob'.

Some clients, notably PuTTY, may send unpadded RSA signatures
during the public key exchange: before this change, one can
sometimes observe failure in signature validation when using
PuTTY's 'plink' client, along these lines:

   ssh_packet_process: ssh_packet_process: Dispatching handler for packet type 50
   ssh_packet_userauth_request: ssh_packet_userauth_request: Auth request for service ssh-connection, method publickey for user 'foo'
   ssh_pki_signature_verify_blob: ssh_pki_signature_verify_blob: Going to verify a ssh-rsa type signature
   pki_signature_verify: pki_signature_verify: RSA error: error:04091077:rsa routines:INT_RSA_VERIFY:wrong signature length
   ssh_packet_userauth_request: ssh_packet_userauth_request: Received an invalid  signature from peer

For cross-reference this issue once also existed between
PuTTY and OpenSSH:

  http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/rsa-verify-failed.html

  http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/ssh-rsa.c?rev=1.19;content-type=text%2Fx-cvsweb-markup

With the fix I am unable to reproduce the above failure mode when
testing with 'plink'.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-21 16:12:00 +01:00
Alan Dunn
809d76cbf2 Test change to ssh_bind_accept_fd
Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-21 16:08:12 +01:00
Alan Dunn
f78a74c160 Import keys during ssh_bind_accept_fd
Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-21 16:08:12 +01:00
Alan Dunn
b3b3045a81 Separate out key import functionality from ssh_bind_listen
Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-21 16:08:11 +01:00
Andreas Schneider
72fd3a73df doc: Fix channel documentation. 2014-01-17 11:09:07 +01:00
Jon Simons
cf19770ede bind: fix possible double-frees in ssh_bind_free
Make sure to explicitly set key pointers to NULL following the use
of 'ssh_key_free' throughout bind.c.

Before this change, a double free can happen via 'ssh_bind_free'
as in this example callpath:

  // create an ssh_bind
  ssh_bind b = ssh_bind_new();

  // provide a path to a wrong key-type
  ssh_bind_options_set(b, SSH_BIND_OPTIONS_DSAKEY, path_to_rsa_key);

  // initialize set key-type
  ssh_bind_listen(b);

    -> error path "The DSA host key has the wrong type: %d",

       ssh_key_free(sshbind->dsa)

         -> ssh_key_clean(key) // OK

         -> SAFE_FREE(key)     // OK, but, sshbind->dsa is *not* set to NULL

  // ssh_bind_listen failed, so clean up ssh_bind
  ssh_bind_free(b);

    -> ssh_key_free(sshbind->dsa)  // double-free here

To fix, set pointers to NULL that have been free'd with 'ssh_key_free'.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-16 09:27:55 +01:00
Andreas Schneider
7f42f5a3c9 cmake: Increase version numbers for 0.6.1. 2014-01-16 09:16:11 +01:00
Andreas Schneider
6223e05b23 doc: Use ssh_channel_accept_forward() in documentation. 2014-01-16 09:14:52 +01:00
Oleksandr Shneyder
634671db11 channel: Add ssh_channel_accept_forward().
This works same way as ssh_forward_accept() but can return a destination
port of the channel (useful if SSH connection forwarding several TCP/IP
ports).

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2014-01-16 09:13:57 +01:00
Aris Adamantiadis
1f689261ec threads: support libgcrypt 1.6 hack
Not 100% satisfied of this patch, but the way libgcrypt handles
threading in 1.6 is not compatible with custom handlers. The
new code basicaly uses pthreads in every case. This will probably
not work on windows.
2014-01-08 22:06:38 +01:00
Andreas Schneider
4919771f0f ChangeLog: Set release date. 2014-01-08 11:17:12 +01:00
Andreas Schneider
8aad24c062 include: Remove warning cause VSC doesn't know about it. 2014-01-08 10:55:39 +01:00
Andreas Schneider
0e5510bb99 include: Fix building if we do not have asm volatile. 2014-01-08 10:52:57 +01:00
Andreas Schneider
de464cb74e src: Update my mail address. 2014-01-07 16:09:04 +01:00
Andreas Schneider
c41f32bcca cmake: Remove unused macro modules. 2014-01-07 16:09:02 +01:00
Aris Adamantiadis
61e701caaa update copyright information 2014-01-07 15:18:44 +01:00
Aris Adamantiadis
1c36642fed tests: avoid reading uninitialized bytes 2014-01-07 14:43:01 +01:00
Aris Adamantiadis
ad287371fb pki: fix gcrypt signature process 2014-01-07 14:21:15 +01:00
Andreas Schneider
ebfdfd9a14 examples: Make sure buffer is initialized. 2014-01-07 09:19:30 +01:00
Andreas Schneider
c9a1be5a85 example: Add missing include for forkpty(). 2014-01-07 09:04:06 +01:00
Aris Adamantiadis
fc0db4d982 test: fixed torture_auth_none condition 2014-01-06 22:10:23 +01:00
Aris Adamantiadis
8f1a350b6e test: test case for async auth_none
This test currently fails
2014-01-06 16:52:35 +01:00
Aris Adamantiadis
15ed51cf20 tests: auth_agent_nonblocking should run in nonblocking 2014-01-06 16:52:35 +01:00
Andreas Schneider
7b2e07ecbc session: Fix a possible memory leak. 2014-01-06 16:18:06 +01:00
Aris Adamantiadis
0404d45c29 poll: fix poll_handles ownerships 2014-01-06 16:18:06 +01:00
Aris Adamantiadis
f2215d14de socket: don't attempt reading a non-connected socket 2014-01-06 16:18:06 +01:00
Aris Adamantiadis
ebbf7988b9 tests: use LC_LIBSSH instead of LANG for env tests.
LANG is stripped and replaced on many distros and LC_* is accepted
by default on debian
2014-01-06 16:17:38 +01:00
Andreas Schneider
ec307d9862 examples: Fix building samplesshd-tty on FreeBSD. 2013-12-26 16:38:38 +01:00
Andreas Schneider
2068973ff3 poll: Correctly free ssh_event_fd_wrapper.
This is allocated by ssh_event_add_fd.
2013-12-22 22:26:51 +01:00
Andreas Schneider
6eea08a9ef config: Support expansion in the Host variable too.
BUG: https://red.libssh.org/issues/127
2013-12-21 14:37:55 +01:00
Andreas Schneider
3ba2e7ace7 tests: Fix non-blocking auth tests.
The ssh_userauth_none() call should already be non-blocking. However
this this function is broken in non-blocking mode. It should reveal the
existing bug.
2013-12-15 21:04:46 +01:00
Andreas Schneider
15c64b2981 tests: Use new auth API in the torture_session test. 2013-12-15 20:30:48 +01:00
Andreas Schneider
ce5d421753 tests: Use new auth API in the torture_auth test. 2013-12-15 20:26:59 +01:00
Andreas Schneider
fd77439a12 tests: Fix pki test with gcrypt. 2013-12-11 21:12:12 +01:00
Jon Simons
a633deb985 channel: fix setting of channel->flags
Fix the setting of 'channel->flags' to use '|='.  Before this
change, one bug symptom can be that channels are never fully
free'd via ssh_channel_free, resulting in memory leaks.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-12-11 21:03:45 +01:00
Jon Simons
50b9a182f5 client: use ssh_channel_do_free in ssh_disconnect
Ensure to use 'ssh_channel_do_free' in 'ssh_disconnect', when removing and
free'ing up a session's channels.  This matches the behavior in 'ssh_free',
and is necessary to fully free any channel which may not have been closed
completely (see usage of flags SSH_CHANNEL_FLAG_CLOSED_REMOTE,
SSH_CHANNEL_FLAG_FREED_LOCAL).

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-12-11 21:03:43 +01:00
Andreas Schneider
bb88b637a9 bind: Correctly free all memory in ssh_bind_free().
Thanks to Jacob Baines.
2013-12-09 19:50:52 +01:00
Jon Simons
60d5824760 session: Add ssh_get_clientbanner(). 2013-12-07 16:24:53 +01:00
Andreas Schneider
397be918cd channels: Add a ssh_channel_read_timeout function. 2013-12-04 20:34:52 +01:00
Andreas Schneider
880fdb4b52 tests: Try to fix torture_forward. 2013-12-04 16:27:19 +01:00
Andreas Schneider
6a74677cef tests: Fix memory leaks. 2013-12-04 16:27:18 +01:00
Andreas Schneider
2c66eeaf75 pki: Fix a memory leak.
CID #1132819
2013-11-28 11:44:34 +01:00
Andreas Schneider
91edc0ee21 tests: Add torture_pki_write_privkey_ecdsa test. 2013-11-27 22:54:40 +01:00
Andreas Schneider
46bda45d95 tests: Add torture_pki_write_privkey_dsa test. 2013-11-27 22:54:40 +01:00
Andreas Schneider
9773c0852a tests: Add torture_pki_write_privkey_rsa test. 2013-11-27 22:54:40 +01:00
Andreas Schneider
f1c56e4309 pki: Add ssh_pki_import_privkey_file(). 2013-11-27 22:54:40 +01:00
Andreas Schneider
1fdc1025a8 pki_crypto: Add pki_private_key_to_pem(). 2013-11-27 22:54:40 +01:00
Andreas Schneider
a375b6c996 pki_gcrypt: Add pki_private_key_to_pem() stub. 2013-11-27 22:54:40 +01:00
Andreas Schneider
ecb01e05a2 curve25519: Fix memory leaks in ssh_server_curve25519_init().
CID #1125255
2013-11-27 22:53:53 +01:00
Andreas Schneider
b3911d0fa2 curve25519: Do not leak q_s_string.
CID #1125256
2013-11-27 22:53:53 +01:00
Andreas Schneider
1ee687ea6f curve25519: Fix a memory leak.
CID #1125257
2013-11-27 22:53:53 +01:00
Andreas Schneider
73e1f2691f examples: Fix else branch.
CID #1127816
2013-11-27 22:53:53 +01:00
Andreas Schneider
84e29f9c06 packet: Remove logically dead code.
CID #1128796
2013-11-27 22:53:53 +01:00
Andreas Schneider
23837b2080 tests: Try to fix valgrind warnings. 2013-11-27 22:53:53 +01:00
Andreas Schneider
4884f1d6fc tests: Fix a valgrind warning. 2013-11-27 22:53:53 +01:00
Andreas Schneider
ead1c4b168 ecdh: Check if we have ECC support. 2013-11-27 22:53:53 +01:00
Andreas Schneider
3e11cb8071 ecdh: Use bignum_bin2bn. 2013-11-27 22:53:48 +01:00
Nicolas Viennot
78e78642e7 server: Add a ssh_send_keepalive() function.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-24 23:21:39 +01:00
Jon Simons
7ab0e3fe62 channel: fix infinite loop in channel_write_common
BUG: https://red.libssh.org/issues/130

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-22 10:34:49 +01:00
Andreas Schneider
5da02d6de2 Update ChangeLog. 2013-11-19 10:29:59 +01:00
Rod Vagg
94db978218 flush channel after EOF and CLOSE 2013-11-18 17:23:52 +01:00
Aris Adamantiadis
78ea8608b0 logging: fix server-side logging 2013-11-18 15:28:59 +01:00
Aris Adamantiadis
7d9940d6eb gssapi: fix logging 2013-11-18 15:10:56 +01:00
Aris Adamantiadis
9f4fa22250 sockets: null pointer check 2013-11-18 14:42:06 +01:00
Simo Sorce
330f6c73f6 gssapi: Fix support of delegated credentials
In a previous refactoring patch, the code underpinning the
ssh_gssapi_set_creds() API was inadvertently removed. This patch
fixes the problem.

Also clarify what variable holds which credentials and insure that
credentials created within the library are propelry freed.

Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-17 11:43:52 +01:00
Simo Sorce
4a3934da48 gssapi: Add support for GSSAPIDelegateCredentials config option.
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-17 11:43:52 +01:00
Simo Sorce
68b996bdbf options: Add SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS option.
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-17 11:43:50 +01:00
Andreas Schneider
d364374422 gssapi: Add error checks and cleanup the code in ssh_gssapi_auth_mic(). 2013-11-15 16:29:49 +01:00
Simo Sorce
00af5bd582 gssapi: Use GSSAPIClientIdentity to acquire creds
Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-15 16:29:49 +01:00
Andreas Schneider
1ab5abf0e6 gssapi: Add support for GSSAPIClientIdentity config option. 2013-11-15 16:29:49 +01:00
Andreas Schneider
f5d1d813fb options: Add SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY option. 2013-11-15 16:29:49 +01:00
Andreas Schneider
92928a7d8d gssapi: Add support for GSSAPIServerIdentity config option. 2013-11-15 16:29:49 +01:00
Andreas Schneider
651c173e72 gssapi: Add suppport to set GSSAPI server identity. 2013-11-15 16:29:49 +01:00
Simo Sorce
f76cd8b6d5 Fix gssapi credential handling.
- Properly acquire and inquitre credentials to get the list of available
credentials.
- Avoid enforcing a specific username it breaks some use cases (k5login).
- Remove confusing references to delegated credentials as there is no code
that actually uses delegated credentials in the initialization case.

Signed-off-by: Siom Sorce <simo@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-15 16:29:49 +01:00
Andreas Schneider
2bbeebd505 socket: Fix connect if we pass in a fd.
BUG: https://red.libssh.org/issues/106

Thanks to Saju Panikulam.
2013-11-15 08:54:18 +01:00
Andreas Schneider
fef32b4c14 packet: Remove dead code. 2013-11-14 11:44:12 +01:00
Andreas Schneider
2eaff2b363 packet: Set the packet to the processed data position.
Else we could end up with packet - current_macsize if to_be_read is 0.
2013-11-14 11:44:11 +01:00
Andreas Schneider
2b3e69fd5f dh: Fix wrong assignment.
Ups, sorry.
2013-11-14 08:09:42 +01:00
Andreas Schneider
cd992a90fb poll: Fix realloc in ssh_poll_ctx_resize(). 2013-11-13 16:29:41 +01:00
Andreas Schneider
6ea111fd8a dh: Avoid possible memory leaks with realloc. 2013-11-13 16:29:41 +01:00
Andreas Schneider
cda641176d packet: Refactor ssh_packet_socket_callback().
Make error checking more readable and add additional NULL checks.
2013-11-13 16:29:41 +01:00
Andreas Schneider
5581645500 server: Fix malloc call. 2013-11-13 16:29:41 +01:00
Colin Walters
3e64ef3bf5 session: Always request POLLIN
The assumption is that if libssh functions are being invoked, we want
to read data.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-09 12:29:26 +01:00
Colin Walters
7372cd837a Add ssh_get_poll_flags()
For integration with an external mainloop, we need to know how to
replicate libssh's internal poll() calls.  We originally through
ssh_get_status() was that API, but it's not really - those flags only
get updated from the *result* of a poll(), where what we really need
is to know how libssh would *start* a poll().

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-09 12:29:25 +01:00
Colin Walters
1ecf7003f6 client: If we have a pre-connected FD, set state to SOCKET_CONNECTED
Otherwise applications providing their own fd end up tripping an
assertion, since the session is just in _CONNECTING.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-09 12:29:24 +01:00
Andreas Schneider
70c54d9445 example: Use ssh_get_publickey_hash(). 2013-11-06 17:11:26 +01:00
Andreas Schneider
e52ff2c8ff dh: Move ssh_get_hexa() and ssh_print_hexa() down.
This way they are in the documentation block for the session and we get
documentation for them.
2013-11-06 17:11:25 +01:00
Andreas Schneider
9bf9d52e21 dh: Add new ssh_get_publickey_hash() function. 2013-11-06 17:11:24 +01:00
Andreas Schneider
965000129e doc: Fix doxygen warnings. 2013-11-04 21:55:58 +01:00
Aris Adamantiadis
0940c6f1b0 Fix cast warnings on 64bits 2013-11-04 10:51:17 +01:00
Aris Adamantiadis
2e6dbe8d3d remove warnings on OSX (workaround) 2013-11-04 10:51:09 +01:00
Aris Adamantiadis
8bf6907c1d curve25519: include reference implementation 2013-11-03 14:58:47 +01:00
Aris Adamantiadis
6e9e13cc24 examples: fix forktty() warning on OSX 2013-11-03 14:09:28 +01:00
Aris Adamantiadis
5bc32bfd88 Fix examples compilation on OSX (libargp) 2013-11-03 13:51:03 +01:00
Aris Adamantiadis
7c8a793b0a socket: Fix check for pending data.
BUG: https://red.libssh.org/issues/119

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-03 12:48:12 +01:00
Nicolas Viennot
e9b0a8210d server: Fix ssh_execute_server_callbacks() client execution
When the public key auth handler is executed and returns SSH_OK,
ssh_execute_server_callbacks() still runs some client callbacks,
which may set rc to SSH_AGAIN, which triggers a default reply on
auth, denying auth.

Signed-off-by: Nicolas Viennot <nicolas@viennot.biz>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-03 10:53:44 +01:00
Nicolas Viennot
fb63887c16 server kex: enable delayed compression
The code is careful to reenable compression when rekeying.

Signed-off-by: Nicolas Viennot <nicolas@viennot.biz>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-03 10:53:42 +01:00
Andreas Schneider
b113b78dfc session: Make sure we correctly burn the buffer. 2013-11-03 10:53:41 +01:00
Andreas Schneider
646112b4e4 wrapper: Make sure we really burn the buffer. 2013-11-03 10:53:40 +01:00
Andreas Schneider
ba4346f089 priv: Fix brackets of burn macros. 2013-11-03 10:53:38 +01:00
Jon Simons
401865d725 server: fix pubkey reply for key probes
Per RFC 4252, it is required to send back only one of either
SSH_MSG_USERAUTH_PK_OK or SSH_MSG_USERAUTH_FAILURE for public
key probes.

Update the handling of 'auth_pubkey_function' to send back PK_OK
instead of SSH_MSG_USERAUTH_SUCCESS for the case that the state
of the message at hand is SSH_PUBLICKEY_STATE_NONE.

With this change, it is now possible to process an initial key probe
and then subsequent signature validation using the server callbacks.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-02 21:03:20 +01:00
William Orr
d312af1ed5 ssh_options_get can now return ProxyCommand
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-11-02 21:03:19 +01:00
Jon Simons
3cfd8a126b connect: fix memory leak in ssh_select
Balance 'ssh_event_add_fd' with 'ssh_event_remove_fd' in 'ssh_select'.

BUG: https://red.libssh.org/issues/128

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-10-31 12:48:56 +01:00
Andreas Schneider
24ebbb8b39 tests: Add a test for ssh_channel(). 2013-10-31 12:48:55 +01:00
Jon Simons
447ee309b0 poll: fix leak in ssh_poll_ctx_free
Fix a memory leak in 'ssh_poll_ctx_free': issue 'ssh_poll_free'
to remove the poll handle from its context and free it.

BUG: https://red.libssh.org/issues/128

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-10-31 11:55:27 +01:00
Alan Dunn
6c213c913b SSH_AUTH_OK -> SSH_AUTH_SUCCESS in comments
A few callback descriptions refer to a non-existent value SSH_AUTH_OK,
which should be SSH_AUTH_SUCCESS.  This commit fixes these.

Signed-off-by: Alan Dunn <amdunn@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-10-31 08:19:35 +01:00
Andreas Schneider
f8f6eb0ce6 cmake: Check for isblank(). 2013-10-30 17:33:32 +01:00
Jon Simons
54f89af6d3 bind: fix leak in ssh_bind_accept error path
Use 'ssh_socket_free' to cleanup if 'ssh_bind_accept_fd'
fails, to be sure to free the ssh_socket in/out buffers.
2013-10-24 10:37:59 +02:00
Andreas Schneider
0e4a1b1f66 tests: Add a sftp_read blocking test. 2013-10-23 15:54:40 +02:00
Colin Walters
5eeadf533f auth: docs: Fix typo optoins -> options
I'm just getting my feet wet with this codebase.

Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-10-23 09:55:39 +02:00
Andreas Schneider
a4e2e01d3e doc: Improve sftp_read_sync() example. 2013-10-23 09:55:38 +02:00
Andreas Schneider
3911046f7e include: Fix build on platforms without ECC. 2013-10-21 07:16:26 +02:00
Andreas Schneider
2727af0fe6 tests: Add a test for ssh_channel_request_env(). 2013-10-20 17:06:23 +02:00
Andreas Schneider
c42da23348 tests: We can't test the accept right now. 2013-10-20 17:06:22 +02:00
Andreas Schneider
e0adcea90d tests: Fix torture_forward. 2013-10-20 17:06:21 +02:00
Andreas Schneider
a62399fcd5 channel: Reinit the buffer and reset the state on error.
BUG: https://red.libssh.org/issues/126
2013-10-20 12:47:17 +02:00
Andreas Schneider
0ee68ac2a1 channel: Fix ssh_global_request_termination().
BUG: https://red.libssh.org/issues/126
2013-10-20 12:47:16 +02:00
Andreas Schneider
796d285eaf tests: Add torture forward test. 2013-10-20 12:47:16 +02:00
Andreas Schneider
b5f71f35a3 pki: Don't leak a buffer. 2013-10-19 10:42:18 +02:00
Andreas Schneider
b98ea81903 wrapper: Fix compilation with gcrypt. 2013-10-19 10:39:44 +02:00
Andreas Schneider
beeca3c650 pki_crpypto: Fix ecdsa signature to blob.
BUG: https://red.libssh.org/issues/118
2013-10-18 23:50:09 +02:00
Andreas Schneider
9f5abdb526 pki: Add support for ECDSA private key signing. 2013-10-18 23:50:08 +02:00
Andreas Schneider
02f80eb288 pki: Add the type as a char pointer. 2013-10-18 23:50:08 +02:00
Andreas Schneider
5b7f07b484 wrapper: Add more evp functions. 2013-10-18 23:50:06 +02:00
Andreas Schneider
ec5278e34d client: Fix the build. 2013-10-18 21:19:33 +02:00
Oliver Stöneberg
e554f0dc0d scp: Fixed result of ssh_scp_string_mode() to get SCP working.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-10-18 14:59:01 +02:00
Oliver Stöneberg
e8e1916d2e client: Added a missing NULL pointer check.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2013-10-18 14:58:59 +02:00
Andreas Schneider
58893352b0 doc: Make sure we have the defines to build all docs. 2013-10-14 15:40:18 +02:00
Aris Adamantiadis
cdcc92e344 Compile libssh with nacl if possible
Conflicts:
	DefineOptions.cmake
2013-10-06 17:43:53 +02:00
Andreas Schneider
29b3a94032 channel: Fix packets termination timeout in global_request().
BUG: https://red.libssh.org/issues/126
2013-10-01 14:51:55 +02:00
Andreas Schneider
8f2b26a837 session: Try the ecdsa default key first. 2013-10-01 14:48:20 +02:00
Andreas Schneider
42c07f379d channels: Correctly handle timeouts in channel functions. 2013-10-01 14:47:58 +02:00
Andreas Schneider
f79c4fd7a3 channel: Use the correct timeout option in channel_open().
BUG: https://red.libssh.org/issues/124
2013-10-01 14:47:58 +02:00
Andreas Schneider
7b2aee90f0 callbacks: Improve the documentation of ssh_threads_set_callbacks().
BUG: https://red.libssh.org/issues/123
2013-10-01 14:47:58 +02:00
Andreas Schneider
aaacd18031 callbacks: Improve the documentation of ssh_threads_get_noop().
BUG: https://red.libssh.org/issues/123
2013-10-01 14:47:58 +02:00
Andreas Schneider
9f60352497 session: Document return value of ssh_get_serverbanner().
BUG: https://red.libssh.org/issues/122
2013-10-01 14:47:58 +02:00
Andreas Schneider
70c796e8b8 session: Remove obsolete status variables.
BUG: https://red.libssh.org/issues/121
2013-10-01 14:47:57 +02:00
Andreas Schneider
5b7a696cf2 client: Add example code for ssh_get_openssh_version().
BUG: https://red.libssh.org/issues/120
2013-10-01 14:47:57 +02:00
Andreas Schneider
c59568c3c1 channels: Correctly decrement timeout value in ssh_channel_accept().
BUG: https://red.libssh.org/issues/116
2013-10-01 14:47:57 +02:00
Andreas Schneider
6f10422685 channel: Document SSH_AGAIN in ssh_channel_read().
BUG: https://red.libssh.org/issues/115
2013-10-01 14:47:57 +02:00
Andreas Schneider
44f851d287 cmake: Allow to build without examples.
BUG: https://red.libssh.org/issues/114
2013-10-01 14:47:57 +02:00
Andreas Schneider
3d158fffa0 doc: Improve the PKI documentation a bit. 2013-10-01 14:47:57 +02:00
Andreas Schneider
c8be0201c6 doc: Update documentation of ssh_set_blocking().
This should work correctly in libssh 0.6.0. If not then you hit a bug.
2013-10-01 14:47:57 +02:00
Tristan CACQUERAY
a8969c4be6 callbacks: add support for auth_none_function 2013-09-27 16:06:09 +02:00
Aris Adamantiadis
8ec8d35e1a doc: Documentation of curve25519-sha256@libssh.org 2013-09-27 16:06:09 +02:00
Aris Adamantiadis
666db37e21 kex: implement curve25519-sha256@libssh.org 2013-09-27 16:06:09 +02:00
Andreas Schneider
391bd88355 scp: Document more scp functionts. 2013-08-12 11:25:15 +02:00
Andreas Schneider
5f90b77a1b cmake: Update libssh version. 2013-08-07 17:33:03 +02:00
111 changed files with 4945 additions and 2938 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@
build
cscope.*
tags
build

View File

@@ -1,7 +1,7 @@
Author(s):
Aris Adamantiadis <aris@0xbadc0de.be> (project initiator)
Andreas Schneider <mail@cynapses.org> (developer)
Andreas Schneider <asn@cryptomilk.org> (developer)
Nick Zitzmann <seiryu (at) comcast (dot) net> (mostly client SFTP stuff)

View File

@@ -7,8 +7,8 @@ cmake_minimum_required(VERSION 2.6.0)
set(APPLICATION_NAME ${PROJECT_NAME})
set(APPLICATION_VERSION_MAJOR "0")
set(APPLICATION_VERSION_MINOR "5")
set(APPLICATION_VERSION_PATCH "90")
set(APPLICATION_VERSION_MINOR "6")
set(APPLICATION_VERSION_PATCH "5")
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
@@ -19,7 +19,7 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO
# Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes:
# Increment REVISION.
set(LIBRARY_VERSION "4.3.0")
set(LIBRARY_VERSION "4.5.1")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
@@ -39,10 +39,6 @@ include(CPackConfig.cmake)
include(MacroEnsureOutOfSourceBuild)
macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there.")
# add macros
include(MacroAddPlugin)
include(MacroCopyFile)
# search for libraries
if (WITH_ZLIB)
find_package(ZLIB REQUIRED)
@@ -71,6 +67,13 @@ if (WITH_GSSAPI)
find_package(GSSAPI)
endif (WITH_GSSAPI)
if (WITH_NACL)
find_package(NaCl)
if (NOT NACL_FOUND)
set(WITH_NACL OFF)
endif (NOT NACL_FOUND)
endif (WITH_NACL)
# config.h checks
include(ConfigureChecks.cmake)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
@@ -94,22 +97,28 @@ install(
)
# cmake config files
configure_file(libssh-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libssh-config.cmake @ONLY)
configure_file(libssh-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libssh-config-version.cmake @ONLY)
set(LIBSSH_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
set(LIBSSH_THREADS_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}ssh${CMAKE_SHARED_LIBRARY_SUFFIX})
configure_file(${PROJECT_NAME}-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake @ONLY)
configure_file(${PROJECT_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake @ONLY)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/libssh-config-version.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
DESTINATION
${CMAKE_INSTALL_DIR}
${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
COMPONENT
devel
)
# in tree build settings
configure_file(libssh-build-tree-settings.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libssh-build-tree-settings.cmake @ONLY)
add_subdirectory(examples)
if (WITH_EXAMPLES)
add_subdirectory(examples)
endif (WITH_EXAMPLES)
if (WITH_TESTING)
find_package(CMocka REQUIRED)
@@ -123,6 +132,7 @@ message(STATUS "********** ${PROJECT_NAME} build options : **********")
message(STATUS "zlib support: ${WITH_ZLIB}")
message(STATUS "libgcrypt support: ${WITH_GCRYPT}")
message(STATUS "libnacl support: ${WITH_NACL}")
message(STATUS "SSH-1 support: ${WITH_SSH1}")
message(STATUS "SFTP support: ${WITH_SFTP}")
message(STATUS "Server support : ${WITH_SERVER}")

View File

@@ -11,15 +11,15 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
### versions
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "5")
set(CPACK_PACKAGE_VERSION_PATCH "90")
set(CPACK_PACKAGE_VERSION_MAJOR ${APPLICATION_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${APPLICATION_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${APPLICATION_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
### source generator
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;tags;cscope.*")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]svn/;/[.]git/;.gitignore;/build/;/obj/;tags;cscope.*")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
if (WIN32)

View File

@@ -1,16 +1,68 @@
ChangeLog
==========
version 0.6.0 (released 2013-XX-XX)
version 0.6.5 (released 2015-04-29)
* Fixed CVE-2015-3146
* Fixed port handling in config file
* Fixed the build with libgcrypt
* Fixed SFTP endian issues (rlo #179)
* Fixed uninitilized sig variable (rlo #167)
* Fixed polling issues which could result in a hang
* Fixed handling of EINTR in ssh_poll() (rlo #186)
* Fixed C99 issues with __func__
* Fixed some memory leaks
* Improved macro detection on Windows
version 0.6.4 (released 2014-12-19)
* Fixed CVE-2014-8132.
* Added SHA-2 for session ID signing with ECDSA keys.
* Added support for ECDSA host keys.
* Added support for more ECDSA hostkey algorithms.
* Added ssh_pki_key_ecdsa_name() API.
* Fixed setting the bindfd only after successful listen.
* Fixed issues with user created sockets.
* Fixed several issues in libssh C++ wrapper.
* Fixed several documentation issues.
* Fixed channel exit-signal request.
* Fixed X11 request screen number in messages.
* Fixed several memory leaks.
version 0.6.3 (released 2014-03-04)
* Fixed CVE-2014-0017.
* Fixed memory leak with ecdsa signatures.
version 0.6.2 (released 2014-03-04)
* security: fix for vulnerability CVE-2014-0017
version 0.6.1 (released 2014-02-08)
* Added support for libgcrypt 1.6.
* Added ssh_channel_accept_forward().
* Added known_hosts heuristic during connection (#138).
* Added getters for session cipher names.
* Fixed decrypt of zero length buffer.
* Fixed padding in RSA signature blobs.
* Fixed DSA signature extraction.
* Fixed some memory leaks.
* Fixed read of non-connected socket.
* Fixed thread dectection.
version 0.6.0 (released 2014-01-08)
* Added new publicy key API.
* Added new userauth API.
* Added ssh_get_publickey_hash() function.
* Added ssh_get_poll_flags() function.
* Added gssapi-mic userauth.
* Added GSSAPIServerIdentity option.
* Added GSSAPIClientIdentity option.
* Added GSSAPIDelegateCredentials option.
* Added new callback based server API.
* Added Elliptic Curve DSA (ECDSA) support (with OpenSSL).
* Added Elliptic Curve Diffie Hellman (ECDH) support.
* Added Curve25519 for ECDH key exchange.
* Added improved logging system.
* Added SSH-agent forwarding.
* Added key-reexchange.
* Added more unit tests.
* Improved documentation.
* Fixed timeout handling.

View File

@@ -50,6 +50,8 @@ check_include_file(argp.h HAVE_ARGP_H)
check_include_file(pty.h HAVE_PTY_H)
check_include_file(termios.h HAVE_TERMIOS_H)
check_include_file(unistd.h HAVE_UNISTD_H)
check_include_file(util.h HAVE_UTIL_H)
check_include_file(sys/time.h HAVE_SYS_TIME_H)
if (WIN32)
check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H)
@@ -93,14 +95,10 @@ endif (NOT WITH_GCRYPT)
# FUNCTIONS
check_function_exists(isblank HAVE_ISBLANK)
check_function_exists(strncpy HAVE_STRNCPY)
check_function_exists(vsnprintf HAVE_VSNPRINTF)
check_function_exists(snprintf HAVE_SNPRINTF)
check_function_exists(poll HAVE_POLL)
check_function_exists(select HAVE_SELECT)
check_function_exists(getaddrinfo HAVE_GETADDRINFO)
check_function_exists(ntohll HAVE_NTOHLL)
check_function_exists(htonll HAVE_HTONLL)
if (WIN32)
check_function_exists(_strtoui64 HAVE__STRTOUI64)
@@ -111,17 +109,28 @@ if (WIN32)
check_function_exists(_snprintf_s HAVE__SNPRINTF_S)
if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
set(HAVE_GETADDRINFO TRUE)
set(HAVE_GETHOSTBYNAME TRUE)
if (MSVC)
set(HAVE_NTOHLL TRUE)
set(HAVE_HTONLL TRUE)
endif (MSVC)
check_symbol_exists(ntohll winsock2.h HAVE_NTOHLL)
check_symbol_exists(htonll winsock2.h HAVE_HTONLL)
set(CMAKE_REQUIRED_LIBRARIES ws2_32)
check_symbol_exists(select "winsock2.h;ws2tcpip.h" HAVE_SELECT)
check_symbol_exists(poll "winsock2.h;ws2tcpip.h" HAVE_SELECT)
# The getaddrinfo function is defined to the WspiapiGetAddrInfo inline function
check_symbol_exists(getaddrinfo "winsock2.h;ws2tcpip.h" HAVE_GETADDRINFO)
set(CMAKE_REQUIRED_LIBRARIES)
endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
set(HAVE_SELECT TRUE)
else (WIN32)
check_function_exists(poll HAVE_POLL)
check_function_exists(select HAVE_SELECT)
check_function_exists(getaddrinfo HAVE_GETADDRINFO)
check_symbol_exists(ntohll arpa/inet.h HAVE_NTOHLL)
check_symbol_exists(htonll arpa/inet.h HAVE_HTONLL)
endif (WIN32)
if (UNIX)
if (NOT LINUX)
# libsocket (Solaris)
@@ -167,11 +176,9 @@ if (GCRYPT_FOUND)
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
endif (GCRYPT_FOUND)
if (CMAKE_HAVE_THREADS_LIBRARY)
if (CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif (CMAKE_USE_PTHREADS_INIT)
endif (CMAKE_HAVE_THREADS_LIBRARY)
if (CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif (CMAKE_USE_PTHREADS_INIT)
# OPTIONS
check_c_source_compiles("
@@ -200,6 +207,20 @@ int main(void)
return 0;
}" HAVE_GCC_VOLATILE_MEMORY_PROTECTION)
check_c_source_compiles("
#include <stdio.h>
int main(void) {
printf(\"%s\", __func__);
return 0;
}" HAVE_COMPILER__FUNC__)
check_c_source_compiles("
#include <stdio.h>
int main(void) {
printf(\"%s\", __FUNCTION__);
return 0;
}" HAVE_COMPILER__FUNCTION__)
if (WITH_DEBUG_CRYPTO)
set(DEBUG_CRYPTO 1)
endif (WITH_DEBUG_CRYPTO)

View File

@@ -12,7 +12,8 @@ option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
option(WITH_TESTING "Build with unit tests" OFF)
option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF)
option(WITH_BENCHMARKS "Build benchmarks tools" OFF)
option(WITH_EXAMPLES "Build examples" ON)
option(WITH_NACL "Build with libnacl (curve25519" ON)
if (WITH_ZLIB)
set(WITH_LIBZ ON)
else (WITH_ZLIB)
@@ -26,3 +27,7 @@ endif(WITH_BENCHMARKS)
if (WITH_TESTING)
set(WITH_STATIC_LIB ON)
endif (WITH_TESTING)
if (WITH_NACL)
set(WITH_NACL ON)
endif (WITH_NACL)

View File

@@ -4,7 +4,7 @@
#
# Script to build libssh on UNIX.
#
# Copyright (c) 2006-2007 Andreas Schneider <mail@cynapses.org>
# Copyright (c) 2006-2007 Andreas Schneider <asn@cryptomilk.org>
#
SOURCE_DIR=".."

View File

@@ -1,7 +1,7 @@
# - ADD_CHECK_TEST(test_name test_source linklib1 ... linklibN)
# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
# Copyright (c) 2007-2010 Andreas Schneider <asn@cynapses.org>
# Copyright (c) 2007-2010 Andreas Schneider <asn@cryptomilk.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.

View File

@@ -25,3 +25,6 @@ if (NOT CMAKE_BUILD_TYPE)
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
)
endif (NOT CMAKE_BUILD_TYPE)
# Create the compile command database for clang by default
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

View File

@@ -75,3 +75,10 @@ if (MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
endif (MSVC)
# This removes this annoying warning
# "warning: 'BN_CTX_free' is deprecated: first deprecated in OS X 10.7 [-Wdeprecated-declarations]"
if (OSX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
endif (OSX)

View File

@@ -26,3 +26,7 @@ endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
if (CMAKE_SYSTEM_NAME MATCHES "OS2")
set(OS2 TRUE)
endif (CMAKE_SYSTEM_NAME MATCHES "OS2")
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
set (OSX TRUE)
endif (CMAKE_SYSTEM_NAME MATCHES "Darwin")

View File

@@ -6,7 +6,7 @@
# ARGP_LIBRARIES - Link these to use Argp
# ARGP_DEFINITIONS - Compiler switches required for using Argp
#
# Copyright (c) 2010 Andreas Schneider <asn@cynapses.org>
# Copyright (c) 2010 Andreas Schneider <asn@cryptomilk.org>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.

View File

@@ -0,0 +1,61 @@
# - Try to find NaCl
# Once done this will define
#
# NACL_FOUND - system has NaCl
# NACL_INCLUDE_DIRS - the NaCl include directory
# NACL_LIBRARIES - Link these to use NaCl
# NACL_DEFINITIONS - Compiler switches required for using NaCl
#
# Copyright (c) 2010 Andreas Schneider <asn@cryptomilk.org>
# Copyright (c) 2013 Aris Adamantiadis <aris@badcode.be>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
if (NACL_LIBRARIES AND NACL_INCLUDE_DIRS)
# in cache already
set(NACL_FOUND TRUE)
else (NACL_LIBRARIES AND NACL_INCLUDE_DIRS)
find_path(NACL_INCLUDE_DIR
NAMES
nacl/crypto_box_curve25519xsalsa20poly1305.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
)
find_library(NACL_LIBRARY
NAMES
nacl
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
)
set(NACL_INCLUDE_DIRS
${NACL_INCLUDE_DIR}
)
if (NACL_LIBRARY)
set(NACL_LIBRARIES
${NACL_LIBRARIES}
${NACL_LIBRARY}
)
endif (NACL_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(NaCl DEFAULT_MSG NACL_LIBRARIES NACL_INCLUDE_DIRS)
# show the NACL_INCLUDE_DIRS and NACL_LIBRARIES variables only in the advanced view
mark_as_advanced(NACL_INCLUDE_DIRS NACL_LIBRARIES)
endif (NACL_LIBRARIES AND NACL_INCLUDE_DIRS)

View File

@@ -1,21 +0,0 @@
# - MACRO_ADD_COMPILE_FLAGS(target_name flag1 ... flagN)
# Copyright (c) 2006, Oswald Buddenhagen, <ossi@kde.org>
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
macro (MACRO_ADD_COMPILE_FLAGS _target)
get_target_property(_flags ${_target} COMPILE_FLAGS)
if (_flags)
set(_flags ${_flags} ${ARGN})
else (_flags)
set(_flags ${ARGN})
endif (_flags)
set_target_properties(${_target} PROPERTIES COMPILE_FLAGS ${_flags})
endmacro (MACRO_ADD_COMPILE_FLAGS)

View File

@@ -1,20 +0,0 @@
# - MACRO_ADD_LINK_FLAGS(target_name flag1 ... flagN)
# Copyright (c) 2006, Oswald Buddenhagen, <ossi@kde.org>
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
macro (MACRO_ADD_LINK_FLAGS _target)
get_target_property(_flags ${_target} LINK_FLAGS)
if (_flags)
set(_flags "${_flags} ${ARGN}")
else (_flags)
set(_flags "${ARGN}")
endif (_flags)
set_target_properties(${_target} PROPERTIES LINK_FLAGS "${_flags}")
endmacro (MACRO_ADD_LINK_FLAGS)

View File

@@ -1,30 +0,0 @@
# - MACRO_ADD_PLUGIN(name [WITH_PREFIX] file1 .. fileN)
#
# Create a plugin from the given source files.
# If WITH_PREFIX is given, the resulting plugin will have the
# prefix "lib", otherwise it won't.
#
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
# Copyright (c) 2006, Andreas Schneider, <mail@cynapses.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
macro (MACRO_ADD_PLUGIN _target_NAME _with_PREFIX)
if (${_with_PREFIX} STREQUAL "WITH_PREFIX")
set(_first_SRC)
else (${_with_PREFIX} STREQUAL "WITH_PREFIX")
set(_first_SRC ${_with_PREFIX})
endif (${_with_PREFIX} STREQUAL "WITH_PREFIX")
add_library(${_target_NAME} MODULE ${_first_SRC} ${ARGN})
if (_first_SRC)
set_target_properties(${_target_NAME} PROPERTIES PREFIX "")
endif (_first_SRC)
endmacro (MACRO_ADD_PLUGIN _name _sources)

View File

@@ -1,33 +0,0 @@
# - macro_copy_file(_src _dst)
# Copies a file to ${_dst} only if ${_src} is different (newer) than ${_dst}
#
# Example:
# macro_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/icon.png ${CMAKE_CURRENT_BINARY_DIR}/.)
# Copies file icon.png to ${CMAKE_CURRENT_BINARY_DIR} directory
#
# Copyright (c) 2006-2007 Wengo
# Copyright (c) 2006-2008 Andreas Schneider <mail@cynapses.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING file.
macro (macro_copy_file _src _dst)
# Removes all path containing .svn or CVS or CMakeLists.txt during the copy
if (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
if (CMAKE_VERBOSE_MAKEFILE)
message(STATUS "Copy file from ${_src} to ${_dst}")
endif (CMAKE_VERBOSE_MAKEFILE)
# Creates directory if necessary
get_filename_component(_path ${_dst} PATH)
file(MAKE_DIRECTORY ${_path})
execute_process(
COMMAND
${CMAKE_COMMAND} -E copy_if_different ${_src} ${_dst}
OUTPUT_QUIET
)
endif (NOT ${_src} MATCHES ".*\\.svn|CVS|CMakeLists\\.txt.*")
endmacro (macro_copy_file)

View File

@@ -2,10 +2,18 @@
#
# Adds a doxygen target that runs doxygen to generate the html
# and optionally the LaTeX API documentation.
# The doxygen target is added to the doc target as dependency.
# The doxygen target is added to the doc target as a dependency.
# i.e.: the API documentation is built with:
# make doc
#
# USAGE: GLOBAL INSTALL
#
# Install it with:
# cmake ./ && sudo make install
# Add the following to the CMakeLists.txt of your project:
# include(UseDoxygen OPTIONAL)
# Optionally copy Doxyfile.in in the directory of CMakeLists.txt and edit it.
#
# USAGE: INCLUDE IN PROJECT
#
# set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
@@ -13,88 +21,120 @@
# Add the Doxyfile.in and UseDoxygen.cmake files to the projects source directory.
#
#
# CONFIGURATION
#
# To configure Doxygen you can edit Doxyfile.in and set some variables in cmake.
# Variables you may define are:
# DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored. Defaults to "doc".
#
# DOXYFILE_LATEX_DIR - Directory where the Doxygen LaTeX output is stored. Defaults to "latex".
#
# DOXYFILE_HTML_DIR - Directory where the Doxygen html output is stored. Defaults to "html".
# DOXYFILE_SOURCE_DIR - Path where the Doxygen input files are.
# Defaults to the current source directory.
# DOXYFILE_EXTRA_SOURCES - Additional source diretories/files for Doxygen to scan.
# The Paths should be in double quotes and separated by space. e.g.:
# "${CMAKE_CURRENT_BINARY_DIR}/foo.c" "${CMAKE_CURRENT_BINARY_DIR}/bar/"
#
# DOXYFILE_OUTPUT_DIR - Path where the Doxygen output is stored.
# Defaults to "${CMAKE_CURRENT_BINARY_DIR}/doc".
#
# DOXYFILE_LATEX - ON/OFF; Set to "ON" if you want the LaTeX documentation
# to be built.
# DOXYFILE_LATEX_DIR - Directory relative to DOXYFILE_OUTPUT_DIR where
# the Doxygen LaTeX output is stored. Defaults to "latex".
#
# DOXYFILE_HTML_DIR - Directory relative to DOXYFILE_OUTPUT_DIR where
# the Doxygen html output is stored. Defaults to "html".
#
#
# Copyright (c) 2009-2010 Tobias Rautenkranz <tobias@rautenkranz.ch>
# Copyright (c) 2010 Andreas Schneider <mail@cynapses.org>
# Copyright (c) 2009, 2010, 2011 Tobias Rautenkranz <tobias@rautenkranz.ch>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
macro(usedoxygen_set_default name value)
if(NOT DEFINED "${name}")
set("${name}" "${value}")
endif()
macro(usedoxygen_set_default name value type docstring)
if(NOT DEFINED "${name}")
set("${name}" "${value}" CACHE "${type}" "${docstring}")
endif()
endmacro()
find_package(Doxygen)
if(DOXYGEN_FOUND)
find_file(DOXYFILE_IN
NAMES
doxy.config.in
PATHS
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_ROOT}/Modules/
NO_DEFAULT_PATH)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DOXYFILE_IN DEFAULT_MSG "DOXYFILE_IN")
find_file(DOXYFILE_IN "Doxyfile.in"
PATHS "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_ROOT}/Modules/"
NO_DEFAULT_PATH
DOC "Path to the doxygen configuration template file")
set(DOXYFILE "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DOXYFILE_IN DEFAULT_MSG "DOXYFILE_IN")
endif()
if(DOXYGEN_FOUND AND DOXYFILE_IN_FOUND)
add_custom_target(doxygen ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config)
usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/doc"
PATH "Doxygen output directory")
usedoxygen_set_default(DOXYFILE_HTML_DIR "html"
STRING "Doxygen HTML output directory")
usedoxygen_set_default(DOXYFILE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
PATH "Input files source directory")
usedoxygen_set_default(DOXYFILE_EXTRA_SOURCE_DIRS ""
STRING "Additional source files/directories separated by space")
set(DOXYFILE_SOURCE_DIRS "\"${DOXYFILE_SOURCE_DIR}\" ${DOXYFILE_EXTRA_SOURCES}")
usedoxygen_set_default(DOXYFILE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
usedoxygen_set_default(DOXYFILE_HTML_DIR "html")
usedoxygen_set_default(DOXYFILE_LATEX YES BOOL "Generate LaTeX API documentation" OFF)
usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex" STRING "LaTex output directory")
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR}")
mark_as_advanced(DOXYFILE_OUTPUT_DIR DOXYFILE_HTML_DIR DOXYFILE_LATEX_DIR
DOXYFILE_SOURCE_DIR DOXYFILE_EXTRA_SOURCE_DIRS DOXYFILE_IN)
set(DOXYFILE_LATEX FALSE)
set(DOXYFILE_PDFLATEX FALSE)
set(DOXYFILE_DOT FALSE)
#find_package(LATEX)
#if(LATEX_COMPILER AND MAKEINDEX_COMPILER)
# set(DOXYFILE_LATEX TRUE)
# usedoxygen_set_default(DOXYFILE_LATEX_DIR "latex")
#
# set_property(DIRECTORY APPEND PROPERTY
# ADDITIONAL_MAKE_CLEAN_FILES
# "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
#
# if(PDFLATEX_COMPILER)
# set(DOXYFILE_PDFLATEX TRUE)
# endif()
# if(DOXYGEN_DOT_EXECUTABLE)
# set(DOXYFILE_DOT TRUE)
# endif()
#
# add_custom_command(TARGET doxygen
# POST_BUILD
# COMMAND ${CMAKE_MAKE_PROGRAM}
# WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
#endif()
set_property(DIRECTORY
APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_HTML_DIR}")
configure_file(${DOXYFILE_IN} ${CMAKE_CURRENT_BINARY_DIR}/doxy.config ESCAPE_QUOTES IMMEDIATE @ONLY)
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxy.trac.in ${CMAKE_CURRENT_BINARY_DIR}/doxy.trac ESCAPE_QUOTES IMMEDIATE @ONLY)
add_custom_target(doxygen-trac ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.trac)
endif()
add_custom_target(doxygen
COMMAND "${DOXYGEN_EXECUTABLE}"
"${DOXYFILE}"
COMMENT "Writing documentation to ${DOXYFILE_OUTPUT_DIR}..."
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
get_target_property(DOC_TARGET doc TYPE)
if(NOT DOC_TARGET)
add_custom_target(doc)
endif()
set(DOXYFILE_DOT "NO")
if(DOXYGEN_DOT_EXECUTABLE)
set(DOXYFILE_DOT "YES")
endif()
add_dependencies(doc doxygen)
## LaTeX
set(DOXYFILE_PDFLATEX "NO")
set_property(DIRECTORY APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
"${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
if(DOXYFILE_LATEX STREQUAL "ON")
set(DOXYFILE_GENERATE_LATEX "YES")
find_package(LATEX)
find_program(DOXYFILE_MAKE make)
mark_as_advanced(DOXYFILE_MAKE)
if(LATEX_COMPILER AND MAKEINDEX_COMPILER AND DOXYFILE_MAKE)
if(PDFLATEX_COMPILER)
set(DOXYFILE_PDFLATEX "YES")
endif()
add_custom_command(TARGET doxygen
POST_BUILD
COMMAND "${DOXYFILE_MAKE}"
COMMENT "Running LaTeX for Doxygen documentation in ${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}..."
WORKING_DIRECTORY "${DOXYFILE_OUTPUT_DIR}/${DOXYFILE_LATEX_DIR}")
else()
set(DOXYGEN_LATEX "NO")
endif()
else()
set(DOXYFILE_GENERATE_LATEX "NO")
endif()
configure_file("${DOXYFILE_IN}" "${DOXYFILE}" @ONLY)
add_custom_target(doc)
add_dependencies(doc doxygen)
endif()

View File

@@ -20,6 +20,12 @@
/* Define to 1 if you have the <pty.h> header file. */
#cmakedefine HAVE_PTY_H 1
/* Define to 1 if you have the <util.h> header file. */
#cmakedefine HAVE_UTIL_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <termios.h> header file. */
#cmakedefine HAVE_TERMIOS_H 1
@@ -79,6 +85,9 @@
/* Define to 1 if you have the `_vsnprintf_s' function. */
#cmakedefine HAVE__VSNPRINTF_S 1
/* Define to 1 if you have the `isblank' function. */
#cmakedefine HAVE_ISBLANK 1
/* Define to 1 if you have the `strncpy' function. */
#cmakedefine HAVE_STRNCPY 1
@@ -123,7 +132,6 @@
/* Define to 1 if you have the `pthread' library (-lpthread). */
#cmakedefine HAVE_PTHREAD 1
/**************************** OPTIONS ****************************/
#cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1
@@ -131,6 +139,9 @@
#cmakedefine HAVE_GCC_VOLATILE_MEMORY_PROTECTION 1
#cmakedefine HAVE_COMPILER__FUNC__ 1
#cmakedefine HAVE_COMPILER__FUNCTION__ 1
/* Define to 1 if you want to enable GSSAPI */
#cmakedefine WITH_GSSAPI 1
@@ -155,6 +166,9 @@
/* Define to 1 if you want to enable calltrace debug output */
#cmakedefine DEBUG_CALLTRACE 1
/* Define to 1 if you want to enable NaCl support */
#cmakedefine WITH_NACL 1
/*************************** ENDIAN *****************************/
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most

View File

@@ -1628,7 +1628,7 @@ INCLUDE_FILE_PATTERNS =
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
PREDEFINED =
PREDEFINED = WITH_SERVER WITH_SFTP WITH_PCAP
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.

View File

@@ -285,7 +285,7 @@ int authenticate_kbdint(ssh_session session)
{
int rc;
rc = ssh_userauth_none(session, NULL, NULL);
rc = ssh_userauth_none(session, NULL);
return rc;
}
@endcode
@@ -304,7 +304,7 @@ int test_several_auth_methods(ssh_session session)
{
int method, rc;
rc = ssh_userauth_none(session, NULL, NULL);
rc = ssh_userauth_none(session, NULL);
if (rc != SSH_AUTH_SUCCESS) {
return rc;
}

View File

@@ -0,0 +1,119 @@
curve25519-sha256@libssh.org.txt Aris Adamantiadis <aris@badcode.be>
21/9/2013
1. Introduction
This document describes the key exchange methode curve25519-sha256@libssh.org
for SSH version 2 protocol. It is provided as an alternative to the existing
key exchange mechanisms based on either Diffie-Hellman or Elliptic Curve Diffie-
Hellman [RFC5656].
The reason is the following : During summer of 2013, revelations from ex-
consultant at NSA Edward Snowden gave proof that NSA willingly inserts backdoors
into softwares, hardware components and published standards. While it is still
believed that the mathematics behind ECC cryptography are still sound and solid,
some people (including Bruce Schneier [SCHNEIER]), showed their lack of confidence
in NIST-published curves such as nistp256, nistp384, nistp521, for which constant
parameters (including the generator point) are defined without explanation. It
is also believed that NSA had a word to say in their definition. These curves
are not the most secure or fastest possible for their key sizes [DJB], and
researchers think it is possible that NSA have ways of cracking NIST curves.
It is also interesting to note that SSH belongs to the list of protocols the NSA
claims to be able to eavesdrop. Having a secure replacement would make passive
attacks much harder if such a backdoor exists.
However an alternative exists in the form of Curve25519. This algorithm has been
proposed in 2006 by DJB [Curve25519]. Its main stengths are its speed, its
constant-time run time (and resistance against side-channel attacks), and its
lack of nebulous hard-coded constants.
The reference version being used in this document is the one described in
[Curve25519] as implemented in the library NaCl [NaCl].
This document does not attempts to provide alternatives to the ecdsa-sha1-*
authentication keys.
2. Key exchange
The key exchange procedure is very similar to the one described chapter 4 of
[RFC5656]. Public ephemeral keys are transmitted over SSH encapsulated into
standard SSH strings.
The following is an overview of the key exchange process:
Client Server
------ ------
Generate ephemeral key pair.
SSH_MSG_KEX_ECDH_INIT -------->
Verify that client public key
length is 32 bytes.
Generate ephemeral key pair.
Compute shared secret.
Generate and sign exchange hash.
<-------- SSH_MSG_KEX_ECDH_REPLY
Verify that server public key length is 32 bytes.
* Verify host keys belong to server.
Compute shared secret.
Generate exchange hash.
Verify server's signature.
* Optional but strongly recommanded as this protects against MITM attacks.
This is implemented using the same messages as described in RFC5656 chapter 4
3. Method Name
The name of this key exchange method is "curve25519-sha256@libssh.org".
4. Implementation considerations
The whole method is based on the curve25519 scalar multiplication. In this
method, a private key is a scalar of 256 bits, and a public key is a point
of 256 bits.
4.1. Private key generation
A 32 bytes private key should be generated for each new connection,
using a secure PRNG. The following actions must be done on the private key:
mysecret[0] &= 248;
mysecret[31] &= 127;
mysecret[31] |= 64;
In order to keep the key valid. However, many cryptographic libraries will do
this automatically.
It should be noted that, in opposition to NIST curves, no special validation
should be done to ensure the result is a valid and secure private key.
4.2 Public key generation
The 32 bytes public key of either a client or a server must be generated using
the 32 bytes private key and a common generator base. This base is defined as 9
followed by all zeroes:
const unsigned char basepoint[32] = {9};
The public key is calculated using the cryptographic scalar multiplication:
const unsigned char privkey[32];
unsigned char pubkey[32];
crypto_scalarmult (pubkey, privkey, basepoint);
However some cryptographic libraries may provide a combined function:
crypto_scalarmult_base (pubkey, privkey);
It should be noted that, in opposition to NIST curves, no special validation
should be done to ensure the received public keys are valid curves point. The
Curve25519 algorithm ensure that every possible public key maps to a valid
ECC Point.
4.3 Shared secret generation
The shared secret, k, is defined in SSH specifications to be a big integer.
This number is calculated using the following procedure:
X is the 32 bytes point obtained by the scalar multiplication of the other
side's public key and the local private key scalar.
The whole 32 bytes of the number X are then converted into a big integer k.
This conversion follows the network byte order. This step differs from
RFC5656.
[RFC5656] http://tools.ietf.org/html/rfc5656
[SCHNEIER] https://www.schneier.com/blog/archives/2013/09/the_nsa_is_brea.html#c1675929
[DJB] http://cr.yp.to/talks/2013.05.31/slides-dan+tanja-20130531-4x3.pdf
[Curve25519] "Curve25519: new Diffie-Hellman speed records."
http://cr.yp.to/ecdh/curve25519-20060209.pdf

File diff suppressed because it is too large Load Diff

View File

@@ -145,7 +145,7 @@ or whatever use you have for it.
@subsection libssh_reverse Doing reverse port forwarding with libssh
To do reverse port forwarding, call ssh_forward_listen(),
then ssh_forward_accept().
then ssh_channel_accept_forward().
When you call ssh_forward_listen(), you can let the remote server
chose the non-priviledged port it should listen to. Otherwise, you can chose
@@ -164,6 +164,7 @@ int web_server(ssh_session session)
ssh_channel channel;
char buffer[256];
int nbytes, nwritten;
int port;
char *helloworld = ""
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
@@ -186,7 +187,7 @@ int web_server(ssh_session session)
return rc;
}
channel = ssh_forward_accept(session, 60000);
channel = ssh_channel_accept_forward(session, 60000, &port);
if (channel == NULL)
{
fprintf(stderr, "Error waiting for incoming connection: %s\n",

View File

@@ -443,11 +443,10 @@ Most of time, the error returned are SSH_FATAL, but some functions
(generaly the ssh_request_xxx ones) may fail because of server denying request.
In these cases, SSH_REQUEST_DENIED is returned.
ssh_get_error() and ssh_get_error_code() take a ssh_session as a parameter.
That's for thread safety, error messages that can be attached to a session
aren't static anymore. Any error that happens during ssh_options_xxx()
or ssh_connect() (i.e., outside of any session) can be retrieved by
giving NULL as argument.
For thread safety, errors are bound to ssh_session objects.
As long as your ssh_session object is not NULL, you can retrieve the last error
message and error code from the ssh_session using ssh_get_error() and
ssh_get_error_code() respectively.
The SFTP subsystem has its own error codes, in addition to libssh ones.

View File

@@ -210,52 +210,63 @@ results to come.
Synchronous read is done with sftp_read().
The following example prints the contents of remote file "/etc/profile". For
each 1024 bytes of information read, it waits until the end of the read operation:
Files are normally transferred in chunks. A good chunk size is 16 KB. The following
example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
request, sftp_read blocks till the data has been received:
@code
// Good chunk size
#define MAX_XFER_BUF_SIZE 16384
int sftp_read_sync(ssh_session session, sftp_session sftp)
{
int access_type;
sftp_file file;
char buffer[1024];
int nbytes, rc;
char buffer[MAX_XFER_BUF_SIZE];
int nbytes, nwritten, rc;
int fd;
access_type = O_RDONLY;
file = sftp_open(sftp, "/etc/profile",
access_type, 0);
if (file == NULL)
{
fprintf(stderr, "Can't open file for reading: %s\n",
ssh_get_error(session));
return SSH_ERROR;
}
nbytes = sftp_read(file, buffer, sizeof(buffer));
while (nbytes > 0)
{
if (write(1, buffer, nbytes) != nbytes)
{
sftp_close(file);
if (file == NULL) {
fprintf(stderr, "Can't open file for reading: %s\n",
ssh_get_error(session));
return SSH_ERROR;
}
nbytes = sftp_read(file, buffer, sizeof(buffer));
}
if (nbytes < 0)
{
fprintf(stderr, "Error while reading file: %s\n",
ssh_get_error(session));
sftp_close(file);
return SSH_ERROR;
fd = open("/path/to/profile", O_CREAT);
if (fd < 0) {
fprintf(stderr, "Can't open file for writing: %s\n",
strerror(errno));
return SSH_ERROR;
}
for (;;) {
nbytes = sftp_read(file, buffer, sizeof(buffer));
if (nbytes == 0) {
break; // EOF
} else if (nbytes < 0) {
fprintf(stderr, "Error while reading file: %s\n",
ssh_get_error(session));
sftp_close(file);
return SSH_ERROR;
}
nwritten = write(fd, buf, nbytes);
if (nwritten != nbytes) {
fprintf(stderr, "Error writing: %s\n",
strerror(errno));
sftp_close(file);
return SSH_ERROR;
}
}
rc = sftp_close(file);
if (rc != SSH_OK)
{
fprintf(stderr, "Can't close the read file: %s\n",
ssh_get_error(session));
return rc;
if (rc != SSH_OK) {
fprintf(stderr, "Can't close the read file: %s\n",
ssh_get_error(session));
return rc;
}
return SSH_OK;
@@ -274,11 +285,14 @@ The example below reads a very big file in asynchronous, nonblocking, mode. Each
time the data are not ready yet, a counter is incrementer.
@code
// Good chunk size
#define MAX_XFER_BUF_SIZE 16384
int sftp_read_async(ssh_session session, sftp_session sftp)
{
int access_type;
sftp_file file;
char buffer[1024];
char buffer[MAX_XFER_BUF_SIZE];
int async_request;
int nbytes;
long counter;
@@ -287,8 +301,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
access_type = O_RDONLY;
file = sftp_open(sftp, "some_very_big_file",
access_type, 0);
if (file == NULL)
{
if (file == NULL) {
fprintf(stderr, "Can't open file for reading: %s\n",
ssh_get_error(session));
return SSH_ERROR;
@@ -298,27 +311,31 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
async_request = sftp_async_read_begin(file, sizeof(buffer));
counter = 0L;
usleep(10000);
if (async_request >= 0)
if (async_request >= 0) {
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
async_request);
else nbytes = -1;
while (nbytes > 0 || nbytes == SSH_AGAIN)
{
if (nbytes > 0)
{
write(1, buffer, nbytes);
async_request = sftp_async_read_begin(file, sizeof(buffer));
}
else counter++;
usleep(10000);
if (async_request >= 0)
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
async_request);
else nbytes = -1;
} else {
nbytes = -1;
}
if (nbytes < 0)
{
while (nbytes > 0 || nbytes == SSH_AGAIN) {
if (nbytes > 0) {
write(1, buffer, nbytes);
async_request = sftp_async_read_begin(file, sizeof(buffer));
} else {
counter++;
}
usleep(10000);
if (async_request >= 0) {
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
async_request);
} else {
nbytes = -1;
}
}
if (nbytes < 0) {
fprintf(stderr, "Error while reading file: %s\n",
ssh_get_error(session));
sftp_close(file);
@@ -328,8 +345,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
printf("The counter has reached value: %ld\n", counter);
rc = sftp_close(file);
if (rc != SSH_OK)
{
if (rc != SSH_OK) {
fprintf(stderr, "Can't close the read file: %s\n",
ssh_get_error(session));
return rc;

View File

@@ -61,5 +61,6 @@ implement the following methods :
- mutex_destroy
- thread_id
libgcrypt 1.6 and bigger backend does not support custom callback. Using anything else than pthreads (ssh_threads_get_pthread()) here will fail.
Good luck !
*/

View File

@@ -11,9 +11,9 @@ include_directories(
${CMAKE_BINARY_DIR}
)
if (BSD OR SOLARIS)
if (BSD OR SOLARIS OR OSX)
find_package(Argp)
endif (BSD OR SOLARIS)
endif (BSD OR SOLARIS OR OSX)
if (UNIX AND NOT WIN32)
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
@@ -28,7 +28,7 @@ if (UNIX AND NOT WIN32)
if (WITH_SERVER)
if (HAVE_LIBUTIL)
add_executable(samplesshd-tty samplesshd-tty.c)
target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} util)
target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES} util)
endif (HAVE_LIBUTIL)
endif (WITH_SERVER)

View File

@@ -34,14 +34,26 @@ int verify_knownhost(ssh_session session){
int state;
char buf[10];
unsigned char *hash = NULL;
int hlen;
size_t hlen;
ssh_key srv_pubkey;
int rc;
state=ssh_is_server_known(session);
hlen = ssh_get_pubkey_hash(session, &hash);
if (hlen < 0) {
return -1;
rc = ssh_get_publickey(session, &srv_pubkey);
if (rc < 0) {
return -1;
}
rc = ssh_get_publickey_hash(srv_pubkey,
SSH_PUBLICKEY_HASH_SHA1,
&hash,
&hlen);
ssh_key_free(srv_pubkey);
if (rc < 0) {
return -1;
}
switch(state){
case SSH_SERVER_KNOWN_OK:
break; /* ok */

View File

@@ -25,8 +25,15 @@ clients must be made or how a client should react.
#include <string.h>
#include <stdio.h>
#include <poll.h>
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#define SSHD_USER "libssh"
#define SSHD_PASSWORD "libssh"
@@ -38,6 +45,8 @@ clients must be made or how a client should react.
#endif
#endif
static int port = 22;
#ifdef WITH_PCAP
const char *pcap_file="debug.server.pcap";
ssh_pcap_file pcap;
@@ -80,8 +89,6 @@ static char doc[] = "libssh -- a Secure Shell protocol implementation";
/* A description of the arguments we accept. */
static char args_doc[] = "BINDADDR";
static int port = 22;
/* The options we understand. */
static struct argp_option options[] = {
{

View File

@@ -143,13 +143,14 @@ static void select_loop(ssh_session session,ssh_channel channel){
if(lus==0){
channel_free(channel);
channel=channels[0]=NULL;
} else
} else {
ret = write(2, buffer, lus);
if (ret < 0) {
fprintf(stderr, "Error writing to stderr: %s",
strerror(errno));
return;
}
}
}
}
if(channel && channel_is_closed(channel)){

View File

@@ -5,6 +5,7 @@ set(libssh_HDRS
libssh.h
ssh2.h
legacy.h
libsshpp.hpp
)
if (WITH_SFTP)

View File

@@ -166,7 +166,7 @@ typedef struct ssh_callbacks_struct *ssh_callbacks;
* @param user User that wants to authenticate
* @param password Password used for authentication
* @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted.
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed.
*/
@@ -179,7 +179,7 @@ typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user
* @param session Current session handler
* @param user User that wants to authenticate
* @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted.
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed.
*/
@@ -191,7 +191,7 @@ typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, vo
* @param user Username of the user (can be spoofed)
* @param principal Authenticated principal of the user, including realm.
* @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted.
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed.
* @warning Implementations should verify that parameter user matches in some way the principal.
@@ -209,7 +209,7 @@ typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *us
* SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be
* replied with a SSH_AUTH_DENIED.
* @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted.
* @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed.
*/
@@ -495,6 +495,8 @@ LIBSSH_API int ssh_set_callbacks(ssh_session session, ssh_callbacks cb);
* @param len the length of the data
* @param is_stderr is 0 for stdout or 1 for stderr
* @param userdata Userdata to be passed to the callback function.
* @returns number of bytes processed by the callee. The remaining bytes will
* be sent in the next callback message, when more data is available.
*/
typedef int (*ssh_channel_data_callback) (ssh_session session,
ssh_channel channel,
@@ -788,14 +790,21 @@ struct ssh_threads_callbacks_struct {
};
/**
* @brief sets the thread callbacks necessary if your program is using
* libssh in a multithreaded fashion. This function must be called first,
* outside of any threading context (in your main() for instance), before
* ssh_init().
* @param cb pointer to a ssh_threads_callbacks_struct structure, which contains
* the different callbacks to be set.
* @brief Set the thread callbacks structure.
*
* This is necessary if your program is using libssh in a multithreaded fashion.
* This function must be called first, outside of any threading context (in your
* main() function for instance), before you call ssh_init().
*
* @param[in] cb A pointer to a ssh_threads_callbacks_struct structure, which
* contains the different callbacks to be set.
*
* @returns Always returns SSH_OK.
*
* @see ssh_threads_callbacks_struct
* @see SSH_THREADS_PTHREAD
* @bug libgcrypt 1.6 and bigger backend does not support custom callback.
* Using anything else than pthreads here will fail.
*/
LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
*cb);
@@ -809,9 +818,13 @@ LIBSSH_API int ssh_threads_set_callbacks(struct ssh_threads_callbacks_struct
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_pthread(void);
/**
* @brief returns a pointer on the noop threads callbacks, to be used with
* ssh_threads_set_callbacks. These callbacks do nothing and are being used by
* default.
* @brief Get the noop threads callbacks structure
*
* This can be used with ssh_threads_set_callbacks. These callbacks do nothing
* and are being used by default.
*
* @return Always returns a valid pointer to the noop callbacks structure.
*
* @see ssh_threads_set_callbacks
*/
LIBSSH_API struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void);

View File

@@ -44,6 +44,7 @@
#endif
#include "libssh/ecdh.h"
#include "libssh/kex.h"
#include "libssh/curve25519.h"
enum ssh_key_exchange_e {
/* diffie-hellman-group1-sha1 */
@@ -51,7 +52,9 @@ enum ssh_key_exchange_e {
/* diffie-hellman-group14-sha1 */
SSH_KEX_DH_GROUP14_SHA1,
/* ecdh-sha2-nistp256 */
SSH_KEX_ECDH_SHA2_NISTP256
SSH_KEX_ECDH_SHA2_NISTP256,
/* curve25519-sha256@libssh.org */
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG
};
struct ssh_crypto_struct {
@@ -60,6 +63,11 @@ struct ssh_crypto_struct {
EC_KEY *ecdh_privkey;
ssh_string ecdh_client_pubkey;
ssh_string ecdh_server_pubkey;
#endif
#ifdef HAVE_CURVE25519
ssh_curve25519_privkey curve25519_privkey;
ssh_curve25519_pubkey curve25519_client_pubkey;
ssh_curve25519_pubkey curve25519_server_pubkey;
#endif
ssh_string dh_server_signature; /* information used by dh_handshake. */
size_t digest_len; /* len of all the fields below */

View File

@@ -0,0 +1,57 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CURVE25519_H_
#define CURVE25519_H_
#include "config.h"
#include "libssh.h"
#ifdef WITH_NACL
#include <nacl/crypto_scalarmult_curve25519.h>
#define CURVE25519_PUBKEY_SIZE crypto_scalarmult_curve25519_BYTES
#define CURVE25519_PRIVKEY_SIZE crypto_scalarmult_curve25519_SCALARBYTES
#define crypto_scalarmult_base crypto_scalarmult_curve25519_base
#define crypto_scalarmult crypto_scalarmult_curve25519
#else
#define CURVE25519_PUBKEY_SIZE 32
#define CURVE25519_PRIVKEY_SIZE 32
int crypto_scalarmult_base(unsigned char *q, const unsigned char *n);
int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
#endif /* WITH_NACL */
#ifdef HAVE_ECC
#define HAVE_CURVE25519 1
#endif
typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE];
typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
int ssh_client_curve25519_init(ssh_session session);
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet);
#ifdef WITH_SERVER
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet);
#endif /* WITH_SERVER */
#endif /* CURVE25519_H_ */

View File

@@ -49,7 +49,9 @@ int hashbufin_add_cookie(ssh_session session, unsigned char *cookie);
int hashbufout_add_cookie(ssh_session session);
int generate_session_keys(ssh_session session);
bignum make_string_bn(ssh_string string);
#ifdef HAVE_LIBCRYPTO
void make_string_bn_inplace(ssh_string string, bignum bnout);
#endif /* HAVE_LIBCRYPTO */
ssh_string make_bignum_string(bignum num);
#endif /* DH_H_ */

View File

@@ -26,7 +26,9 @@
#ifdef HAVE_LIBCRYPTO
#ifdef HAVE_OPENSSL_ECDH_H
#define HAVE_ECDH
#ifdef HAVE_ECC
#define HAVE_ECDH 1
#endif
#endif /* HAVE_OPENSSL_ECDH_H */
#endif /* HAVE_LIBCRYPTO */

View File

@@ -0,0 +1,27 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 20014 by Aris Adamantiadis <aris@badcode.be>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef KNOWNHOSTS_H_
#define KNOWNHOSTS_H_
char **ssh_knownhosts_algorithms(ssh_session session);
#endif /* KNOWNHOSTS_H_ */

View File

@@ -38,6 +38,11 @@ typedef SHA_CTX* SHACTX;
typedef SHA256_CTX* SHA256CTX;
typedef MD5_CTX* MD5CTX;
typedef HMAC_CTX* HMACCTX;
#ifdef HAVE_ECC
typedef EVP_MD_CTX *EVPCTX;
#else
typedef void *EVPCTX;
#endif
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#ifdef MD5_DIGEST_LEN

View File

@@ -29,6 +29,7 @@
typedef gcry_md_hd_t SHACTX;
typedef gcry_md_hd_t MD5CTX;
typedef gcry_md_hd_t HMACCTX;
typedef void *EVPCTX;
#define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define MD5_DIGEST_LEN 16

View File

@@ -78,7 +78,7 @@
/* libssh version */
#define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 6
#define LIBSSH_VERSION_MICRO 0
#define LIBSSH_VERSION_MICRO 5
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \
@@ -208,10 +208,14 @@ enum ssh_publickey_state_e {
SSH_PUBLICKEY_STATE_WRONG=2
};
/* status flags */
/* Status flags */
/** Socket is closed */
#define SSH_CLOSED 0x01
/** Reading to socket won't block */
#define SSH_READ_PENDING 0x02
/** Session was closed due to an error */
#define SSH_CLOSED_ERROR 0x04
/** Output buffer not empty */
#define SSH_WRITE_PENDING 0x08
enum ssh_server_known_e {
@@ -327,7 +331,10 @@ enum ssh_options_e {
SSH_OPTIONS_COMPRESSION,
SSH_OPTIONS_COMPRESSION_LEVEL,
SSH_OPTIONS_KEY_EXCHANGE,
SSH_OPTIONS_HOSTKEYS
SSH_OPTIONS_HOSTKEYS,
SSH_OPTIONS_GSSAPI_SERVER_IDENTITY,
SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY,
SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
};
enum {
@@ -370,6 +377,7 @@ LIBSSH_API int ssh_channel_open_x11(ssh_channel channel, const char *orig_addr,
LIBSSH_API int ssh_channel_poll(ssh_channel channel, int is_stderr);
LIBSSH_API int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr);
LIBSSH_API int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr);
LIBSSH_API int ssh_channel_read_timeout(ssh_channel channel, void *dest, uint32_t count, int is_stderr, int timeout_ms);
LIBSSH_API int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
int is_stderr);
LIBSSH_API int ssh_channel_request_env(ssh_channel channel, const char *name, const char *value);
@@ -398,6 +406,7 @@ LIBSSH_API void ssh_disconnect(ssh_session session);
LIBSSH_API char *ssh_dirname (const char *path);
LIBSSH_API int ssh_finalize(void);
LIBSSH_API ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms);
LIBSSH_API ssh_channel ssh_channel_accept_forward(ssh_session session, int timeout_ms, int *destination_port);
LIBSSH_API int ssh_forward_cancel(ssh_session session, const char *address, int port);
LIBSSH_API int ssh_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
LIBSSH_API void ssh_free(ssh_session session);
@@ -408,11 +417,24 @@ LIBSSH_API socket_t ssh_get_fd(ssh_session session);
LIBSSH_API char *ssh_get_hexa(const unsigned char *what, size_t len);
LIBSSH_API char *ssh_get_issue_banner(ssh_session session);
LIBSSH_API int ssh_get_openssh_version(ssh_session session);
LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key);
LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash);
enum ssh_publickey_hash_type {
SSH_PUBLICKEY_HASH_SHA1,
SSH_PUBLICKEY_HASH_MD5
};
LIBSSH_API int ssh_get_publickey_hash(const ssh_key key,
enum ssh_publickey_hash_type type,
unsigned char **hash,
size_t *hlen);
SSH_DEPRECATED LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash);
LIBSSH_API int ssh_get_random(void *where,int len,int strong);
LIBSSH_API int ssh_get_version(ssh_session session);
LIBSSH_API int ssh_get_status(ssh_session session);
LIBSSH_API int ssh_get_poll_flags(ssh_session session);
LIBSSH_API int ssh_init(void);
LIBSSH_API int ssh_is_blocking(ssh_session session);
LIBSSH_API int ssh_is_connected(ssh_session session);
@@ -493,6 +515,11 @@ LIBSSH_API int ssh_pki_import_privkey_file(const char *filename,
ssh_auth_callback auth_fn,
void *auth_data,
ssh_key *pkey);
LIBSSH_API int ssh_pki_export_privkey_file(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
const char *filename);
LIBSSH_API int ssh_pki_import_pubkey_base64(const char *b64_key,
enum ssh_keytypes_e type,
@@ -507,6 +534,8 @@ LIBSSH_API int ssh_pki_export_pubkey_base64(const ssh_key key,
LIBSSH_API int ssh_pki_export_pubkey_file(const ssh_key key,
const char *filename);
LIBSSH_API const char *ssh_pki_key_ecdsa_name(const ssh_key key);
LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len);
LIBSSH_API int ssh_send_ignore (ssh_session session, const char *data);
LIBSSH_API int ssh_send_debug (ssh_session session, const char *message, int always_display);
@@ -599,7 +628,10 @@ LIBSSH_API int ssh_event_dopoll(ssh_event event, int timeout);
LIBSSH_API int ssh_event_remove_fd(ssh_event event, socket_t fd);
LIBSSH_API int ssh_event_remove_session(ssh_event event, ssh_session session);
LIBSSH_API void ssh_event_free(ssh_event event);
LIBSSH_API const char* ssh_get_clientbanner(ssh_session session);
LIBSSH_API const char* ssh_get_serverbanner(ssh_session session);
LIBSSH_API const char* ssh_get_cipher_in(ssh_session session);
LIBSSH_API const char* ssh_get_cipher_out(ssh_session session);
#ifndef LIBSSH_LEGACY_0_4
#include "libssh/legacy.h"

View File

@@ -361,8 +361,8 @@ public:
* @see ssh_channel_forward_accept
* @see Session::listenForward
*/
Channel *acceptForward(int timeout_ms);
/* acceptForward is implemented later in this file */
inline Channel *acceptForward(int timeout_ms);
/* implemented outside the class due Channel references */
void_throwable cancelForward(const char *address, int port){
int err=ssh_forward_cancel(c_session, address, port);
@@ -480,12 +480,30 @@ public:
ssh_throw(err);
return err;
}
int read(void *dest, size_t count, bool is_stderr=false){
int read(void *dest, size_t count, bool is_stderr){
int err;
/* handle int overflow */
if(count > 0x7fffffff)
count = 0x7fffffff;
err=ssh_channel_read(channel,dest,count,is_stderr);
err=ssh_channel_read_timeout(channel,dest,count,is_stderr,-1);
ssh_throw(err);
return err;
}
int read(void *dest, size_t count, int timeout){
int err;
/* handle int overflow */
if(count > 0x7fffffff)
count = 0x7fffffff;
err=ssh_channel_read_timeout(channel,dest,count,false,timeout);
ssh_throw(err);
return err;
}
int read(void *dest, size_t count, bool is_stderr=false, int timeout=-1){
int err;
/* handle int overflow */
if(count > 0x7fffffff)
count = 0x7fffffff;
err=ssh_channel_read_timeout(channel,dest,count,is_stderr,timeout);
ssh_throw(err);
return err;
}

View File

@@ -60,6 +60,7 @@ struct ssh_key_struct {
struct ssh_signature_struct {
enum ssh_keytypes_e type;
const char *type_c;
#ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa_sig;
gcry_sexp_t rsa_sig;

View File

@@ -29,11 +29,12 @@
#define ECDSA_HEADER_END "-----END EC PRIVATE KEY-----"
#define ssh_pki_log(...) \
_ssh_pki_log(__FUNCTION__, __VA_ARGS__)
_ssh_log(SSH_LOG_FUNCTIONS, __func__, __VA_ARGS__)
void _ssh_pki_log(const char *function,
const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
int pki_key_ecdsa_nid_from_name(const char *name);
const char *pki_key_ecdsa_nid_to_name(int nid);
/* SSH Key Functions */
ssh_key pki_key_dup(const ssh_key key, int demote);
@@ -51,6 +52,11 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
ssh_auth_callback auth_fn,
void *auth_data);
ssh_string pki_private_key_to_pem(const ssh_key key,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data);
/* SSH Public Key Functions */
int pki_pubkey_build_dss(ssh_key key,
ssh_string p,

View File

@@ -67,7 +67,9 @@
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
# if ! defined(HAVE_ISBLANK)
# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
# endif
# define usleep(X) Sleep(((X)+1000)/1000)
@@ -118,16 +120,31 @@ int gettimeofday(struct timeval *__p, void *__t);
#include "libssh/callbacks.h"
/* some constants */
#ifndef MAX_PACKAT_LEN
#define MAX_PACKET_LEN 262144
#define ERROR_BUFFERLEN 1024
#define CLIENTBANNER1 "SSH-1.5-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
#ifndef __FUNCTION__
#if defined(__SUNPRO_C)
#define __FUNCTION__ __func__
#endif
#ifndef ERROR_BUFFERLEN
#define ERROR_BUFFERLEN 1024
#endif
#ifndef CLIENTBANNER1
#define CLIENTBANNER1 "SSH-1.5-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
#endif
#ifndef CLIENTBANNER2
#define CLIENTBANNER2 "SSH-2.0-libssh-" SSH_STRINGIFY(LIBSSH_VERSION)
#endif
#ifndef KBDINT_MAX_PROMPT
#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
#endif
#ifndef MAX_BUF_SIZE
#define MAX_BUF_SIZE 4096
#endif
#ifndef HAVE_COMPILER__FUNC__
# ifdef HAVE_COMPILER__FUNCTION__
# define __func__ __FUNCTION__
# else
# error "Your system must provide a __func__ macro"
# endif
#endif
#if defined(HAVE_GCC_THREAD_LOCAL_STORAGE)
@@ -164,7 +181,7 @@ void ssh_log_function(int verbosity,
const char *function,
const char *buffer);
#define SSH_LOG(priority, ...) \
_ssh_log(priority, __FUNCTION__, __VA_ARGS__)
_ssh_log(priority, __func__, __VA_ARGS__)
/* LEGACY */
void ssh_log_common(struct ssh_common_struct *common,
@@ -182,18 +199,18 @@ struct error_struct {
};
#define ssh_set_error(error, code, ...) \
_ssh_set_error(error, code, __FUNCTION__, __VA_ARGS__)
_ssh_set_error(error, code, __func__, __VA_ARGS__)
void _ssh_set_error(void *error,
int code,
const char *function,
const char *descr, ...) PRINTF_ATTRIBUTE(4, 5);
#define ssh_set_error_oom(error) \
_ssh_set_error_oom(error, __FUNCTION__)
_ssh_set_error_oom(error, __func__)
void _ssh_set_error_oom(void *error, const char *function);
#define ssh_set_error_invalid(error) \
_ssh_set_error_invalid(error, __FUNCTION__)
_ssh_set_error_invalid(error, __func__)
void _ssh_set_error_invalid(void *error, const char *function);
@@ -251,7 +268,7 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
/** Overwrite the buffer with '\0' */
# define BURN_BUFFER(x, size) do { \
if ((x) != NULL) \
memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
memset((x), '\0', (size)); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
} while(0)
#else /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */
/** Overwrite a string with '\0' */
@@ -262,7 +279,7 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
/** Overwrite the buffer with '\0' */
# define BURN_BUFFER(x, size) do { \
if ((x) != NULL) \
memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \
memset((x), '\0', (size)); \
} while(0)
#endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */

View File

@@ -44,7 +44,8 @@ enum ssh_bind_options_e {
SSH_BIND_OPTIONS_RSAKEY,
SSH_BIND_OPTIONS_BANNER,
SSH_BIND_OPTIONS_LOG_VERBOSITY,
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR
SSH_BIND_OPTIONS_LOG_VERBOSITY_STR,
SSH_BIND_OPTIONS_ECDSAKEY
};
typedef struct ssh_bind_struct* ssh_bind;
@@ -80,69 +81,6 @@ typedef struct ssh_bind_callbacks_struct *ssh_bind_callbacks;
*/
LIBSSH_API ssh_bind ssh_bind_new(void);
/**
* @brief Set the options for the current SSH server bind.
*
* @param sshbind The ssh server bind to configure.
*
* @param type The option type to set. This could be one of the
* following:
*
* - SSH_BIND_OPTIONS_BINDADDR
* The ip address to bind (const char *).
*
* - SSH_BIND_OPTIONS_BINDPORT
* The port to bind (unsigned int).
*
* - SSH_BIND_OPTIONS_BINDPORT_STR
* The port to bind (const char *).
*
* - SSH_BIND_OPTIONS_HOSTKEY
* This specifies the file containing the private host key used
* by SSHv1. (const char *).
*
* - SSH_BIND_OPTIONS_DSAKEY
* This specifies the file containing the private host dsa key
* used by SSHv2. (const char *).
*
* - SSH_BIND_OPTIONS_RSAKEY
* This specifies the file containing the private host dsa key
* used by SSHv2. (const char *).
*
* - SSH_BIND_OPTIONS_BANNER
* That the server banner (version string) for SSH.
* (const char *).
*
* - SSH_BIND_OPTIONS_LOG_VERBOSITY
* Set the session logging verbosity (int).\n
* \n
* The verbosity of the messages. Every log smaller or
* equal to verbosity will be shown.
* - SSH_LOG_NOLOG: No logging
* - SSH_LOG_RARE: Rare conditions or warnings
* - SSH_LOG_ENTRY: API-accessible entrypoints
* - SSH_LOG_PACKET: Packet id and size
* - SSH_LOG_FUNCTIONS: Function entering and leaving
*
* - SSH_BIND_OPTIONS_LOG_VERBOSITY_STR
* Set the session logging verbosity (const char *).\n
* \n
* The verbosity of the messages. Every log smaller or
* equal to verbosity will be shown.
* - SSH_LOG_NOLOG: No logging
* - SSH_LOG_RARE: Rare conditions or warnings
* - SSH_LOG_ENTRY: API-accessible entrypoints
* - SSH_LOG_PACKET: Packet id and size
* - SSH_LOG_FUNCTIONS: Function entering and leaving
* \n
* See the corresponding numbers in libssh.h.
*
* @param value The value to set. This is a generic pointer and the
* datatype which is used should be set according to the
* type set.
*
* @returns SSH_OK on success, SSH_ERROR on invalid option or parameter.
*/
LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind,
enum ssh_bind_options_e type, const void *value);
@@ -382,6 +320,8 @@ LIBSSH_API int ssh_channel_write_stderr(ssh_channel channel,
const void *data,
uint32_t len);
LIBSSH_API int ssh_send_keepalive(ssh_session session);
/* deprecated functions */
SSH_DEPRECATED LIBSSH_API int ssh_accept(ssh_session session);
SSH_DEPRECATED LIBSSH_API int channel_write_stderr(ssh_channel channel,

View File

@@ -97,9 +97,6 @@ struct ssh_session_struct {
int openssh;
uint32_t send_seq;
uint32_t recv_seq;
/* status flags */
int closed;
int closed_by_except;
int connected;
/* !=0 when the user got a session handle */
@@ -178,6 +175,7 @@ struct ssh_session_struct {
char *knownhosts;
char *wanted_methods[10];
char *ProxyCommand;
char *custombanner;
unsigned long timeout; /* seconds */
unsigned long timeout_usec;
unsigned int port;
@@ -186,6 +184,9 @@ struct ssh_session_struct {
int ssh2;
int ssh1;
char compressionlevel;
char *gss_server_identity;
char *gss_client_identity;
int gss_delegate_creds;
} opts;
};

View File

@@ -52,6 +52,7 @@ void ssh_socket_set_write_wontblock(ssh_socket s);
void ssh_socket_set_read_wontblock(ssh_socket s);
void ssh_socket_set_except(ssh_socket s);
int ssh_socket_get_status(ssh_socket s);
int ssh_socket_get_poll_flags(ssh_socket s);
int ssh_socket_buffered_write_bytes(ssh_socket s);
int ssh_socket_data_available(ssh_socket s);
int ssh_socket_data_writable(ssh_socket s);

View File

@@ -53,6 +53,9 @@ void sha1(unsigned char *digest,int len,unsigned char *hash);
void sha256(unsigned char *digest, int len, unsigned char *hash);
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen);
EVPCTX evp_init(int nid);
void evp_update(EVPCTX ctx, const void *data, unsigned long len);
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen);
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type);
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len);
@@ -67,5 +70,6 @@ int crypt_set_algorithms_server(ssh_session session);
struct ssh_crypto_struct *crypto_new(void);
void crypto_free(struct ssh_crypto_struct *crypto);
void ssh_reseed(void);
#endif /* WRAPPER_H_ */

View File

@@ -7,5 +7,7 @@ else()
set(LIBSSH_INCLUDE_DIR @INCLUDE_INSTALL_DIR@)
endif()
set(LIBSSH_LIRBARY @LIB_INSTALL_DIR@/libssh.so)
set(LIBSSH_LIRBARIES @LIB_INSTALL_DIR@/libssh.so)
set(LIBSSH_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
set(LIBSSH_LIBRARIES @LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@)
set(LIBSSH_THREADS_LIBRARY @LIB_INSTALL_DIR@/@LIBSSH_THREADS_LIBRARY_NAME@)

View File

@@ -76,6 +76,18 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (WITH_NACL AND NACL_FOUND)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
${NACL_INCLUDE_DIR}
)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
${NACL_LIBRARY}
)
endif (WITH_NACL AND NACL_FOUND)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
CACHE INTERNAL "libssh link libraries"
@@ -103,6 +115,7 @@ set(libssh_SRCS
client.c
config.c
connect.c
curve25519.c
dh.c
ecdh.c
error.c
@@ -192,6 +205,13 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (NOT WITH_NACL)
set(libssh_SRCS
${libssh_SRCS}
curve25519_ref.c
)
endif (NOT WITH_NACL)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${LIBSSH_PRIVATE_INCLUDE_DIRS}
@@ -268,6 +288,6 @@ if (WITH_STATIC_LIB)
)
endif (WITH_STATIC_LIB)
if (CMAKE_HAVE_THREADS_LIBRARY)
if (Threads_FOUND)
add_subdirectory(threads)
endif (CMAKE_HAVE_THREADS_LIBRARY)
endif (Threads_FOUND)

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2008-2009 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View File

@@ -3,8 +3,8 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2011 by Aris Adamantiadis <aris@0xbadc0de.be>
* Copyright (c) 2008-2011 Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2003-2013 by Aris Adamantiadis <aris@0xbadc0de.be>
* Copyright (c) 2008-2013 Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -355,7 +355,7 @@ int ssh_userauth_list(ssh_session session, const char *username)
* later.
*
* @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only
* authentication. The username should only be set with ssh_options_set() only
* before you connect to the server.
*/
int ssh_userauth_none(ssh_session session, const char *username) {
@@ -478,7 +478,7 @@ fail:
* later.
*
* @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only
* authentication. The username should only be set with ssh_options_set() only
* before you connect to the server.
*/
int ssh_userauth_try_publickey(ssh_session session,
@@ -640,7 +640,7 @@ fail:
* later.
*
* @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only
* authentication. The username should only be set with ssh_options_set() only
* before you connect to the server.
*/
int ssh_userauth_publickey(ssh_session session,
@@ -961,7 +961,7 @@ struct ssh_agent_state_struct {
* later.
*
* @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only
* authentication. The username should only be set with ssh_options_set() only
* before you connect to the server.
*/
int ssh_userauth_agent(ssh_session session,
@@ -1083,7 +1083,7 @@ struct ssh_auth_auto_state_struct {
* later.
*
* @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only
* authentication. The username should only be set with ssh_options_set() only
* before you connect to the server.
*/
int ssh_userauth_publickey_auto(ssh_session session,
@@ -1297,7 +1297,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
* later.
*
* @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only
* authentication. The username should only be set with ssh_options_set() only
* before you connect to the server.
*
* @see ssh_userauth_none()
@@ -1907,7 +1907,7 @@ int ssh_userauth_kbdint(ssh_session session, const char *user,
* This should not happen
*/
rc = SSH_AUTH_ERROR;
ssh_set_error(session,SSH_FATAL,"Invalid state in %s", __FUNCTION__);
ssh_set_error(session, SSH_FATAL, "Invalid state in %s", __func__);
}
return rc;
}

View File

@@ -144,26 +144,19 @@ ssh_bind ssh_bind_new(void) {
return ptr;
}
int ssh_bind_listen(ssh_bind sshbind) {
const char *host;
socket_t fd;
static int ssh_bind_import_keys(ssh_bind sshbind) {
int rc;
if (ssh_init() < 0) {
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
return -1;
}
if (sshbind->ecdsakey == NULL &&
sshbind->dsakey == NULL &&
sshbind->rsakey == NULL) {
ssh_set_error(sshbind, SSH_FATAL,
"DSA or RSA host key file must be set before listen()");
"ECDSA, DSA, or RSA host key file must be set");
return SSH_ERROR;
}
#ifdef HAVE_ECC
if (sshbind->ecdsakey) {
if (sshbind->ecdsa == NULL && sshbind->ecdsakey != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->ecdsakey,
NULL,
NULL,
@@ -179,12 +172,13 @@ int ssh_bind_listen(ssh_bind sshbind) {
ssh_set_error(sshbind, SSH_FATAL,
"The ECDSA host key has the wrong type");
ssh_key_free(sshbind->ecdsa);
sshbind->ecdsa = NULL;
return SSH_ERROR;
}
}
#endif
if (sshbind->dsakey) {
if (sshbind->dsa == NULL && sshbind->dsakey != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->dsakey,
NULL,
NULL,
@@ -201,11 +195,12 @@ int ssh_bind_listen(ssh_bind sshbind) {
"The DSA host key has the wrong type: %d",
ssh_key_type(sshbind->dsa));
ssh_key_free(sshbind->dsa);
sshbind->dsa = NULL;
return SSH_ERROR;
}
}
if (sshbind->rsakey) {
if (sshbind->rsa == NULL && sshbind->rsakey != NULL) {
rc = ssh_pki_import_privkey_file(sshbind->rsakey,
NULL,
NULL,
@@ -222,10 +217,29 @@ int ssh_bind_listen(ssh_bind sshbind) {
ssh_set_error(sshbind, SSH_FATAL,
"The RSA host key has the wrong type");
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
return SSH_ERROR;
}
}
return SSH_OK;
}
int ssh_bind_listen(ssh_bind sshbind) {
const char *host;
socket_t fd;
int rc;
if (ssh_init() < 0) {
ssh_set_error(sshbind, SSH_FATAL, "ssh_init() failed");
return -1;
}
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
}
if (sshbind->bindfd == SSH_INVALID_SOCKET) {
host = sshbind->bindaddr;
if (host == NULL) {
@@ -235,10 +249,11 @@ int ssh_bind_listen(ssh_bind sshbind) {
fd = bind_socket(sshbind, host, sshbind->bindport);
if (fd == SSH_INVALID_SOCKET) {
ssh_key_free(sshbind->dsa);
sshbind->dsa = NULL;
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
return -1;
}
sshbind->bindfd = fd;
if (listen(fd, 10) < 0) {
ssh_set_error(sshbind, SSH_FATAL,
@@ -246,9 +261,13 @@ int ssh_bind_listen(ssh_bind sshbind) {
fd, strerror(errno));
close(fd);
ssh_key_free(sshbind->dsa);
sshbind->dsa = NULL;
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
return -1;
}
sshbind->bindfd = fd;
} else {
SSH_LOG(SSH_LOG_INFO, "Using app-provided bind socket");
}
@@ -341,11 +360,18 @@ void ssh_bind_free(ssh_bind sshbind){
/* options */
SAFE_FREE(sshbind->banner);
SAFE_FREE(sshbind->bindaddr);
SAFE_FREE(sshbind->dsakey);
SAFE_FREE(sshbind->rsakey);
SAFE_FREE(sshbind->dsa);
SAFE_FREE(sshbind->rsa);
SAFE_FREE(sshbind->bindaddr);
SAFE_FREE(sshbind->ecdsakey);
ssh_key_free(sshbind->dsa);
sshbind->dsa = NULL;
ssh_key_free(sshbind->rsa);
sshbind->rsa = NULL;
ssh_key_free(sshbind->ecdsa);
sshbind->ecdsa = NULL;
for (i = 0; i < 10; i++) {
if (sshbind->wanted_methods[i]) {
@@ -357,7 +383,7 @@ void ssh_bind_free(ssh_bind sshbind){
}
int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
int i;
int i, rc;
if (session == NULL){
ssh_set_error(sshbind, SSH_FATAL,"session is null");
@@ -388,7 +414,8 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
}
session->common.log_verbosity = sshbind->common.log_verbosity;
if(sshbind->banner != NULL)
session->opts.custombanner = strdup(sshbind->banner);
ssh_socket_free(session->socket);
session->socket = ssh_socket_new(session);
if (session->socket == NULL) {
@@ -399,6 +426,16 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
ssh_socket_set_fd(session->socket, fd);
ssh_socket_get_poll_handle_out(session->socket);
/* We must try to import any keys that could be imported in case
* we are not using ssh_bind_listen (which is the other place
* where keys can be imported) on this ssh_bind and are instead
* only using ssh_bind_accept_fd to manage sockets ourselves.
*/
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
}
#ifdef HAVE_ECC
if (sshbind->ecdsa) {
session->srv.ecdsa_key = ssh_key_dup(sshbind->ecdsa);
@@ -422,6 +459,8 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
return SSH_ERROR;
}
}
/* force PRNG to change state in case we fork after ssh_bind_accept */
ssh_reseed();
return SSH_OK;
}
@@ -454,8 +493,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
#else
close(fd);
#endif
if (session->socket)
ssh_socket_close(session->socket);
ssh_socket_free(session->socket);
}
return rc;
}

View File

@@ -188,6 +188,10 @@ int buffer_reinit(struct ssh_buffer_struct *buffer) {
int buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) {
buffer_verify(buffer);
if (data == NULL) {
return -1;
}
if (buffer->used + len < len) {
return -1;
}
@@ -221,6 +225,10 @@ int buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
struct ssh_string_struct *string) {
uint32_t len = 0;
if (string == NULL) {
return -1;
}
len = ssh_string_len(string);
if (buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
return -1;

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by

View File

@@ -3,8 +3,8 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2003-2013 by Aris Adamantiadis
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -177,7 +177,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){
(long unsigned int) channel->remote_maxpacket);
channel->state = SSH_CHANNEL_STATE_OPEN;
channel->flags = channel->flags & ~SSH_CHANNEL_FLAG_NOT_BOUND;
channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND;
return SSH_PACKET_USED;
}
@@ -312,7 +312,11 @@ static int channel_open(ssh_channel channel, const char *type_c, int window,
type_c, channel->local_channel);
pending:
/* wait until channel is opened by server */
err = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, ssh_channel_open_termination, channel);
err = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_open_termination,
channel);
if (session->session_state == SSH_SESSION_STATE_ERROR)
err = SSH_ERROR;
end:
@@ -631,7 +635,7 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
channel,
channel->callbacks->userdata);
}
channel->flags &= SSH_CHANNEL_FLAG_CLOSED_REMOTE;
channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE;
if(channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL)
ssh_channel_do_free(channel);
@@ -912,10 +916,10 @@ int channel_default_bufferize(ssh_channel channel, void *data, int len,
* SSH_AGAIN if in nonblocking mode and call has
* to be done again.
*
* @see channel_open_forward()
* @see channel_request_env()
* @see channel_request_shell()
* @see channel_request_exec()
* @see ssh_channel_open_forward()
* @see ssh_channel_request_env()
* @see ssh_channel_request_shell()
* @see ssh_channel_request_exec()
*/
int ssh_channel_open_session(ssh_channel channel) {
if(channel == NULL) {
@@ -948,7 +952,7 @@ int ssh_channel_open_session(ssh_channel channel) {
* SSH_AGAIN if in nonblocking mode and call has
* to be done again.
*
* @see channel_open_forward()
* @see ssh_channel_open_forward()
*/
int ssh_channel_open_auth_agent(ssh_channel channel){
if(channel == NULL) {
@@ -1074,7 +1078,7 @@ void ssh_channel_free(ssh_channel channel) {
if (session->alive && channel->state == SSH_CHANNEL_STATE_OPEN) {
ssh_channel_close(channel);
}
channel->flags &= SSH_CHANNEL_FLAG_FREED_LOCAL;
channel->flags |= SSH_CHANNEL_FLAG_FREED_LOCAL;
/* The idea behind the flags is the following : it is well possible
* that a client closes a channel that stills exists on the server side.
@@ -1116,8 +1120,24 @@ void ssh_channel_do_free(ssh_channel channel){
*
* @return SSH_OK on success, SSH_ERROR if an error occurred.
*
* @see channel_close()
* @see channel_free()
* Example:
@code
rc = ssh_channel_send_eof(channel);
if (rc == SSH_ERROR) {
return -1;
}
while(!ssh_channel_is_eof(channel)) {
rc = ssh_channel_read(channel, buf, sizeof(buf), 0);
if (rc == SSH_ERROR) {
return -1;
}
}
ssh_channel_close(channel);
@endcode
*
* @see ssh_channel_close()
* @see ssh_channel_free()
* @see ssh_channel_is_eof()
*/
int ssh_channel_send_eof(ssh_channel channel){
ssh_session session;
@@ -1143,6 +1163,10 @@ int ssh_channel_send_eof(ssh_channel channel){
channel->local_channel,
channel->remote_channel);
rc = ssh_channel_flush(channel);
if(rc == SSH_ERROR)
goto error;
channel->local_eof = 1;
return rc;
@@ -1162,8 +1186,8 @@ error:
*
* @return SSH_OK on success, SSH_ERROR if an error occurred.
*
* @see channel_free()
* @see channel_eof()
* @see ssh_channel_free()
* @see ssh_channel_is_eof()
*/
int ssh_channel_close(ssh_channel channel){
ssh_session session;
@@ -1199,6 +1223,10 @@ int ssh_channel_close(ssh_channel channel){
channel->state=SSH_CHANNEL_STATE_CLOSED;
}
rc = ssh_channel_flush(channel);
if(rc == SSH_ERROR)
goto error;
return rc;
error:
buffer_reinit(session->out_buffer);
@@ -1210,7 +1238,8 @@ error:
static int ssh_channel_waitwindow_termination(void *c){
ssh_channel channel = (ssh_channel) c;
if (channel->remote_window > 0 ||
channel->session->session_state == SSH_SESSION_STATE_ERROR)
channel->session->session_state == SSH_SESSION_STATE_ERROR ||
channel->state == SSH_CHANNEL_STATE_CLOSED)
return 1;
else
return 0;
@@ -1315,7 +1344,10 @@ int channel_write_common(ssh_channel channel, const void *data,
"Wait for a growing window message...");
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT,
ssh_channel_waitwindow_termination,channel);
if (rc == SSH_ERROR || !ssh_channel_waitwindow_termination(channel))
if (rc == SSH_ERROR ||
!ssh_channel_waitwindow_termination(channel) ||
channel->session->session_state == SSH_SESSION_STATE_ERROR ||
channel->state == SSH_CHANNEL_STATE_CLOSED)
goto out;
continue;
}
@@ -1383,7 +1415,7 @@ uint32_t ssh_channel_window_size(ssh_channel channel) {
*
* @return The number of bytes written, SSH_ERROR on error.
*
* @see channel_read()
* @see ssh_channel_read()
*/
int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) {
return channel_write_common(channel, data, len, 0);
@@ -1396,7 +1428,7 @@ int ssh_channel_write(ssh_channel channel, const void *data, uint32_t len) {
*
* @return 0 if channel is closed, nonzero otherwise.
*
* @see channel_is_closed()
* @see ssh_channel_is_closed()
*/
int ssh_channel_is_open(ssh_channel channel) {
if(channel == NULL) {
@@ -1412,7 +1444,7 @@ int ssh_channel_is_open(ssh_channel channel) {
*
* @return 0 if channel is opened, nonzero otherwise.
*
* @see channel_is_open()
* @see ssh_channel_is_open()
*/
int ssh_channel_is_closed(ssh_channel channel) {
if(channel == NULL) {
@@ -1582,7 +1614,11 @@ static int channel_request(ssh_channel channel, const char *request,
return SSH_OK;
}
pending:
rc = ssh_handle_packets_termination(session,SSH_TIMEOUT_USER, ssh_channel_request_termination, channel);
rc = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_request_termination,
channel);
if(session->session_state == SSH_SESSION_STATE_ERROR || rc == SSH_ERROR) {
channel->request_state = SSH_CHANNEL_REQ_STATE_ERROR;
}
@@ -1707,7 +1743,7 @@ error:
* SSH_AGAIN if in nonblocking mode and call has
* to be done again.
*
* @see channel_request_pty_size()
* @see ssh_channel_request_pty_size()
*/
int ssh_channel_request_pty(ssh_channel channel) {
return ssh_channel_request_pty_size(channel, "xterm", 80, 24);
@@ -1946,7 +1982,7 @@ error:
}
static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
int timeout_ms) {
int timeout_ms, int *destination_port) {
#ifndef _WIN32
static const struct timespec ts = {
.tv_sec = 0,
@@ -1958,9 +1994,16 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
struct ssh_iterator *iterator;
int t;
for (t = timeout_ms; t >= 0; t -= 50)
{
ssh_handle_packets(session, 50);
/*
* We sleep for 50 ms in ssh_handle_packets() and later sleep for
* 50 ms. So we need to decrement by 100 ms.
*/
for (t = timeout_ms; t >= 0; t -= 100) {
if (timeout_ms == 0) {
ssh_handle_packets(session, 0);
} else {
ssh_handle_packets(session, 50);
}
if (session->ssh_message_list) {
iterator = ssh_list_get_iterator(session->ssh_message_list);
@@ -1970,6 +2013,10 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
ssh_message_subtype(msg) == channeltype) {
ssh_list_remove(session->ssh_message_list, iterator);
channel = ssh_message_channel_request_open_reply_accept(msg);
if(destination_port) {
*destination_port=msg->channel_request_open.destination_port;
}
ssh_message_free(msg);
return channel;
}
@@ -2000,7 +2047,7 @@ static ssh_channel ssh_channel_accept(ssh_session session, int channeltype,
* the server.
*/
ssh_channel ssh_channel_accept_x11(ssh_channel channel, int timeout_ms) {
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms);
return ssh_channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms, NULL);
}
/**
@@ -2053,7 +2100,7 @@ SSH_PACKET_CALLBACK(ssh_request_denied){
static int ssh_global_request_termination(void *s){
ssh_session session = (ssh_session) s;
if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING ||
session->session_state != SSH_SESSION_STATE_ERROR)
session->session_state == SSH_SESSION_STATE_ERROR)
return 1;
else
return 0;
@@ -2081,47 +2128,73 @@ static int ssh_global_request_termination(void *s){
static int global_request(ssh_session session, const char *request,
ssh_buffer buffer, int reply) {
ssh_string req = NULL;
int rc = SSH_ERROR;
int rc;
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE)
switch (session->global_req_state) {
case SSH_CHANNEL_REQ_STATE_NONE:
break;
default:
goto pending;
}
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST);
if (rc < 0) {
goto error;
}
req = ssh_string_from_char(request);
if (req == NULL) {
ssh_set_error_oom(session);
goto error;
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 ||
buffer_add_ssh_string(session->out_buffer, req) < 0 ||
buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
ssh_set_error_oom(session);
goto error;
}
rc = buffer_add_ssh_string(session->out_buffer, req);
ssh_string_free(req);
req=NULL;
if (rc < 0) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
rc = buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1);
if (rc < 0) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
if (buffer != NULL) {
if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer),
buffer_get_rest_len(buffer)) < 0) {
ssh_set_error_oom(session);
goto error;
}
rc = buffer_add_data(session->out_buffer,
buffer_get_rest(buffer),
buffer_get_rest_len(buffer));
if (rc < 0) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
}
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
if (packet_send(session) == SSH_ERROR) {
return rc;
rc = packet_send(session);
if (rc == SSH_ERROR) {
return rc;
}
SSH_LOG(SSH_LOG_PACKET,
"Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
if (reply == 0) {
session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE;
return SSH_OK;
if (reply == 0) {
session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
return SSH_OK;
}
pending:
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
ssh_global_request_termination, session);
rc = ssh_handle_packets_termination(session,
SSH_TIMEOUT_DEFAULT,
ssh_global_request_termination,
session);
if(rc==SSH_ERROR || session->session_state == SSH_SESSION_STATE_ERROR){
session->global_req_state = SSH_CHANNEL_REQ_STATE_ERROR;
}
@@ -2139,16 +2212,16 @@ pending:
break;
case SSH_CHANNEL_REQ_STATE_ERROR:
case SSH_CHANNEL_REQ_STATE_NONE:
rc=SSH_ERROR;
rc = SSH_ERROR;
break;
case SSH_CHANNEL_REQ_STATE_PENDING:
rc=SSH_AGAIN;
break;
return SSH_AGAIN;
}
session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
return rc;
error:
ssh_string_free(req);
buffer_reinit(session->out_buffer);
return rc;
}
@@ -2228,7 +2301,23 @@ error:
* the server
*/
ssh_channel ssh_forward_accept(ssh_session session, int timeout_ms) {
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms);
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, NULL);
}
/**
* @brief Accept an incoming TCP/IP forwarding channel and get information
* about incomming connection
* @param[in] session The ssh session to use.
*
* @param[in] timeout_ms A timeout in milliseconds.
*
* @param[in] destination_port A pointer to destination port or NULL.
*
* @return Newly created channel, or NULL if no incoming channel request from
* the server
*/
ssh_channel ssh_channel_accept_forward(ssh_session session, int timeout_ms, int* destination_port) {
return ssh_channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms, destination_port);
}
/**
@@ -2364,20 +2453,22 @@ error:
* SSH_ERROR if an error occurred,
* SSH_AGAIN if in nonblocking mode and call has
* to be done again.
* @code
* rc = channel_request_exec(channel, "ps aux");
* if (rc > 0) {
* return -1;
* }
*
* while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
* if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
* return -1;
* }
* }
* @endcode
* Example:
@code
rc = channel_request_exec(channel, "ps aux");
if (rc > 0) {
return -1;
}
while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
return -1;
}
}
@endcode
*
* @see channel_request_shell()
* @see ssh_channel_request_shell()
*/
int ssh_channel_request_exec(ssh_channel channel, const char *cmd) {
ssh_buffer buffer = NULL;
@@ -2615,15 +2706,48 @@ static int ssh_channel_read_termination(void *s){
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR
* on error. Can return 0 if nothing is available in nonblocking
* mode.
* on error. In nonblocking mode it Can return 0 if no data
* is available or SSH_AGAIN.
*
* @warning This function may return less than count bytes of data, and won't
* block until count bytes have been read.
* @warning The read function using a buffer has been renamed to
* channel_read_buffer().
*/
int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr) {
int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr)
{
return ssh_channel_read_timeout(channel, dest, count, is_stderr, -1);
}
/**
* @brief Reads data from a channel.
*
* @param[in] channel The channel to read from.
*
* @param[in] dest The destination buffer which will get the data.
*
* @param[in] count The count of bytes to be read.
*
* @param[in] is_stderr A boolean value to mark reading from the stderr flow.
*
* @param[in] timeout_ms A timeout in milliseconds. A value of -1 means
* infinite timeout.
*
* @return The number of bytes read, 0 on end of file or SSH_ERROR
* on error. In nonblocking mode it Can return 0 if no data
* is available or SSH_AGAIN.
*
* @warning This function may return less than count bytes of data, and won't
* block until count bytes have been read.
* @warning The read function using a buffer has been renamed to
* channel_read_buffer().
*/
int ssh_channel_read_timeout(ssh_channel channel,
void *dest,
uint32_t count,
int is_stderr,
int timeout)
{
ssh_session session;
ssh_buffer stdbuf;
uint32_t len;
@@ -2671,8 +2795,15 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
ctx.channel = channel;
ctx.buffer = stdbuf;
ctx.count = 1;
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT,
ssh_channel_read_termination, &ctx);
if (timeout < 0) {
timeout = SSH_TIMEOUT_DEFAULT;
}
rc = ssh_handle_packets_termination(session,
timeout,
ssh_channel_read_termination,
&ctx);
if (rc == SSH_ERROR){
return rc;
}
@@ -2716,7 +2847,7 @@ int ssh_channel_read(ssh_channel channel, void *dest, uint32_t count, int is_std
*
* @warning Don't forget to check for EOF as it would return 0 here.
*
* @see channel_is_eof()
* @see ssh_channel_is_eof()
*/
int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count,
int is_stderr) {
@@ -2768,7 +2899,7 @@ int ssh_channel_read_nonblocking(ssh_channel channel, void *dest, uint32_t count
*
* @warning When the channel is in EOF state, the function returns SSH_EOF.
*
* @see channel_is_eof()
* @see ssh_channel_is_eof()
*/
int ssh_channel_poll(ssh_channel channel, int is_stderr){
ssh_buffer stdbuf;
@@ -2820,7 +2951,7 @@ int ssh_channel_poll(ssh_channel channel, int is_stderr){
*
* @warning When the channel is in EOF state, the function returns SSH_EOF.
*
* @see channel_is_eof()
* @see ssh_channel_is_eof()
*/
int ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr){
ssh_session session;
@@ -2893,14 +3024,21 @@ static int ssh_channel_exit_status_termination(void *c){
* (yet).
* @warning This function may block until a timeout (or never)
* if the other side is not willing to close the channel.
*
* If you're looking for an async handling of this register a callback for the
* exit status.
*
* @see ssh_channel_exit_status_callback
*/
int ssh_channel_get_exit_status(ssh_channel channel) {
int rc;
if(channel == NULL) {
return SSH_ERROR;
}
rc = ssh_handle_packets_termination(channel->session, SSH_TIMEOUT_USER,
ssh_channel_exit_status_termination, channel);
rc = ssh_handle_packets_termination(channel->session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_exit_status_termination,
channel);
if (rc == SSH_ERROR || channel->session->session_state ==
SSH_SESSION_STATE_ERROR)
return SSH_ERROR;
@@ -3123,7 +3261,7 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
*
* @return The number of bytes written, SSH_ERROR on error.
*
* @see channel_read()
* @see ssh_channel_read()
*/
int ssh_channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) {
return channel_write_common(channel, data, len, 1);
@@ -3284,17 +3422,18 @@ error:
}
/**
* @brief Send the exit status to the remote process (as described in RFC 4254, section 6.10).
* @brief Send the exit status to the remote process
*
* Sends the exit status to the remote process.
* Sends the exit status to the remote process (as described in RFC 4254,
* section 6.10).
* Only SSH-v2 is supported (I'm not sure about SSH-v1).
*
* @param[in] channel The channel to send exit status.
*
* @param[in] sig The exit status to send
* @param[in] exit_status The exit status to send
*
* @return SSH_OK on success, SSH_ERROR if an error occurred
* (including attempts to send exit status via SSH-v1 session).
* @return SSH_OK on success, SSH_ERROR if an error occurred.
* (including attempts to send exit status via SSH-v1 session).
*/
int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) {
ssh_buffer buffer = NULL;
@@ -3328,9 +3467,9 @@ error:
}
/**
* @brief Send an exit signal to remote process (as described in RFC 4254, section 6.10).
* @brief Send an exit signal to remote process (RFC 4254, section 6.10).
*
* Sends a signal 'sig' to the remote process.
* This sends the exit status of the remote process.
* Note, that remote system may not support signals concept.
* In such a case this request will be silently ignored.
* Only SSH-v2 is supported (I'm not sure about SSH-v1).
@@ -3408,7 +3547,7 @@ int ssh_channel_request_send_exit_signal(ssh_channel channel, const char *sig,
goto error;
}
rc = channel_request(channel, "signal", buffer, 0);
rc = channel_request(channel, "exit-signal", buffer, 0);
error:
ssh_buffer_free(buffer);
if(tmp)

View File

@@ -4,7 +4,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2009 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -101,7 +101,8 @@ int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col
}
session = channel->session;
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){
if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE &&
channel->request_state != SSH_CHANNEL_REQ_STATE_ACCEPTED){
ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state");
return SSH_ERROR;
}

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
* Copyright (c) 2003-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -60,12 +60,15 @@
static void socket_callback_connected(int code, int errno_code, void *user){
ssh_session session=(ssh_session)user;
if(session->session_state != SSH_SESSION_STATE_CONNECTING){
if (session->session_state != SSH_SESSION_STATE_CONNECTING &&
session->session_state != SSH_SESSION_STATE_SOCKET_CONNECTED)
{
ssh_set_error(session,SSH_FATAL, "Wrong state in socket_callback_connected : %d",
session->session_state);
return;
}
SSH_LOG(SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code);
if(code == SSH_SOCKET_CONNECTED_OK)
session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
@@ -105,14 +108,18 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
}
#endif
if(buffer[i]=='\r')
buffer[i]='\0';
if(buffer[i]=='\n'){
buffer[i]='\0';
str=strdup(buffer);
/* number of bytes read */
ret=i+1;
session->serverbanner=str;
if(buffer[i]=='\r') {
buffer[i]='\0';
}
if (buffer[i]=='\n') {
buffer[i] = '\0';
str = strdup(buffer);
if (str == NULL) {
return SSH_ERROR;
}
/* number of bytes read */
ret = i + 1;
session->serverbanner = str;
session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED;
SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str);
session->ssh_connection_callback(session);
@@ -148,19 +155,27 @@ int ssh_send_banner(ssh_session session, int server) {
banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2;
if (server) {
session->serverbanner = strdup(banner);
if(session->opts.custombanner == NULL){
session->serverbanner = strdup(banner);
} else {
session->serverbanner = malloc(strlen(session->opts.custombanner) + 9);
if(!session->serverbanner)
goto end;
strcpy(session->serverbanner, "SSH-2.0-");
strcat(session->serverbanner, session->opts.custombanner);
}
if (session->serverbanner == NULL) {
goto end;
}
snprintf(buffer, 128, "%s\n", session->serverbanner);
} else {
session->clientbanner = strdup(banner);
if (session->clientbanner == NULL) {
goto end;
}
snprintf(buffer, 128, "%s\n", session->clientbanner);
}
snprintf(buffer, 128, "%s\n", banner);
if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) {
goto end;
}
@@ -196,6 +211,11 @@ static int dh_handshake(ssh_session session) {
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_client_ecdh_init(session);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_init(session);
break;
#endif
default:
rc = SSH_ERROR;
@@ -495,6 +515,7 @@ int ssh_connect(ssh_session session) {
session->socket_callbacks.exception=ssh_socket_exception_callback;
session->socket_callbacks.userdata=session;
if (session->opts.fd != SSH_INVALID_SOCKET) {
session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED;
ssh_socket_set_fd(session->socket, session->opts.fd);
ret=SSH_OK;
#ifndef _WIN32
@@ -505,7 +526,7 @@ int ssh_connect(ssh_session session) {
} else {
ret=ssh_socket_connect(session->socket,
session->opts.host,
session->opts.port,
session->opts.port > 0 ? session->opts.port : 22,
session->opts.bindaddr);
}
if (ret == SSH_ERROR) {
@@ -526,7 +547,8 @@ pending:
}
SSH_LOG(SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout);
ret = ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session);
if (ret == SSH_ERROR || !ssh_connect_termination(session)) {
if (session->session_state != SSH_SESSION_STATE_ERROR &&
(ret == SSH_ERROR || !ssh_connect_termination(session))) {
ssh_set_error(session, SSH_FATAL,
"Timeout connecting to %s", session->opts.host);
session->session_state = SSH_SESSION_STATE_ERROR;
@@ -579,6 +601,14 @@ char *ssh_get_issue_banner(ssh_session session) {
* @param[in] session The SSH session to use.
*
* @return The version number if available, 0 otherwise.
*
* @code
* int openssh = ssh_get_openssh_version();
*
* if (openssh == SSH_INT_VERSION(6, 1, 0)) {
* printf("Version match!\m");
* }
* @endcode
*/
int ssh_get_openssh_version(ssh_session session) {
if (session == NULL) {
@@ -634,7 +664,7 @@ error:
session->session_state=SSH_SESSION_STATE_DISCONNECTED;
while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
ssh_channel_free(ssh_iterator_value(ssh_channel,it));
ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));
ssh_list_remove(session->channels, it);
}
if(session->current_crypto){
@@ -670,8 +700,8 @@ error:
}
const char *ssh_copyright(void) {
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2010 Aris Adamantiadis "
"(aris@0xbadc0de.be) Distributed under the LGPL, please refer to COPYING "
return SSH_STRINGIFY(LIBSSH_VERSION) " (c) 2003-2014 Aris Adamantiadis, Andreas Schneider, "
"and libssh contributors. Distributed under the LGPL, please refer to COPYING "
"file for information about your rights";
}
/** @} */

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -46,7 +46,10 @@ enum ssh_config_opcode_e {
SOC_PROTOCOL,
SOC_STRICTHOSTKEYCHECK,
SOC_KNOWNHOSTS,
SOC_PROXYCOMMAND
SOC_PROXYCOMMAND,
SOC_GSSAPISERVERIDENTITY,
SOC_GSSAPICLIENTIDENTITY,
SOC_GSSAPIDELEGATECREDENTIALS,
};
struct ssh_config_keyword_table_s {
@@ -67,6 +70,9 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ "stricthostkeychecking", SOC_STRICTHOSTKEYCHECK },
{ "userknownhostsfile", SOC_KNOWNHOSTS },
{ "proxycommand", SOC_PROXYCOMMAND },
{ "gssapiserveridentity", SOC_GSSAPISERVERIDENTITY },
{ "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
{ "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
{ NULL, SOC_UNSUPPORTED }
};
@@ -122,7 +128,7 @@ static char *ssh_config_get_token(char **str) {
c = ssh_config_get_cmd(str);
for (r = c; *c; c++) {
if (isblank(*c)) {
if (isblank(*c) || *c == '=') {
*c = '\0';
goto out;
}
@@ -213,16 +219,25 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
switch (opcode) {
case SOC_HOST:
*parsing = 0;
lowerhost = (session->opts.host) ? ssh_lowercase(session->opts.host) : NULL;
for (p = ssh_config_get_str_tok(&s, NULL); p && *p;
p = ssh_config_get_str_tok(&s, NULL)) {
if (match_hostname(lowerhost, p, strlen(p))) {
*parsing = 1;
*parsing = 0;
lowerhost = (session->opts.host) ? ssh_lowercase(session->opts.host) : NULL;
for (p = ssh_config_get_str_tok(&s, NULL);
p != NULL && p[0] != '\0';
p = ssh_config_get_str_tok(&s, NULL)) {
char *z = ssh_path_expand_escape(session, p);
int ok;
if (z == NULL) {
z = strdup(p);
}
ok = match_hostname(lowerhost, z, strlen(z));
if (ok) {
*parsing = 1;
}
free(z);
}
}
SAFE_FREE(lowerhost);
break;
SAFE_FREE(lowerhost);
break;
case SOC_HOSTNAME:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
@@ -230,7 +245,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
break;
case SOC_PORT:
if (session->opts.port == 22) {
if (session->opts.port == 0) {
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
@@ -323,6 +338,24 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, p);
}
break;
case SOC_GSSAPISERVERIDENTITY:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_GSSAPI_SERVER_IDENTITY, p);
}
break;
case SOC_GSSAPICLIENTIDENTITY:
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
ssh_options_set(session, SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY, p);
}
break;
case SOC_GSSAPIDELEGATECREDENTIALS:
i = ssh_config_get_yesno(&s, -1);
if (i >=0 && *parsing) {
ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
}
break;
case SOC_UNSUPPORTED:
SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d\n",
keyword, count);

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2009 by Aris Adamantiadis
* Copyright (c) 2003-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -64,6 +64,10 @@
#include <wspiapi.h>
#endif
#ifndef EINPROGRESS
#define EINPROGRESS WSAEINPROGRESS
#endif
#else /* _WIN32 */
#include <netdb.h>
@@ -285,6 +289,7 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
timeout, usec, s);
freeaddrinfo(ai);
return ret;
}
@@ -382,7 +387,16 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
continue;
}
connect(s, itr->ai_addr, itr->ai_addrlen);
errno = 0;
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
ssh_set_error(session, SSH_FATAL,
"Failed to connect: %s", strerror(errno));
ssh_connect_socket_close(s);
s = -1;
continue;
}
break;
}
@@ -421,7 +435,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
* @param[in] readfds A fd_set of file descriptors to be select'ed for
* reading.
*
* @param[in] timeout A timeout for the select.
* @param[in] timeout The timeout in milliseconds.
*
* @return SSH_OK on success,
* SSH_ERROR on error,
@@ -436,6 +450,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
*/
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
fd_set *readfds, struct timeval *timeout) {
fd_set origfds;
socket_t fd;
int i,j;
int rc;
@@ -449,9 +464,11 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
ssh_event_add_session(event, channels[i]->session);
}
FD_ZERO(&origfds);
for (fd = 0; fd < maxfd ; fd++) {
if (FD_ISSET(fd, readfds)) {
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
FD_SET(fd, &origfds);
}
}
outchannels[0] = NULL;
@@ -485,13 +502,17 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
/* since there's nothing, let's fire the polling */
rc = ssh_event_dopoll(event,tm);
if (rc == SSH_ERROR){
ssh_event_free(event);
return SSH_ERROR;
goto out;
}
tm = ssh_timeout_update(&ts, base_tm);
firstround=0;
} while (1);
out:
for (fd = 0; fd < maxfd; fd++) {
if (FD_ISSET(fd, &origfds)) {
ssh_event_remove_fd(event, fd);
}
}
ssh_event_free(event);
return SSH_OK;
}

292
src/curve25519.c Normal file
View File

@@ -0,0 +1,292 @@
/*
* curve25519.c - Curve25519 ECDH functions for key exchange
* curve25519-sha256@libssh.org
*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/curve25519.h"
#ifdef HAVE_CURVE25519
#ifdef WITH_NACL
#include "nacl/crypto_scalarmult_curve25519.h"
#endif
#include "libssh/ssh2.h"
#include "libssh/buffer.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/crypto.h"
#include "libssh/dh.h"
#include "libssh/pki.h"
/** @internal
* @brief Starts curve25519-sha256@libssh.org key exchange
*/
int ssh_client_curve25519_init(ssh_session session){
ssh_string client_pubkey;
int rc;
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT);
if (rc < 0) {
return SSH_ERROR;
}
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
session->next_crypto->curve25519_privkey);
client_pubkey = ssh_string_new(CURVE25519_PUBKEY_SIZE);
if (client_pubkey == NULL) {
return SSH_ERROR;
}
ssh_string_fill(client_pubkey, session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
rc = buffer_add_ssh_string(session->out_buffer,client_pubkey);
ssh_string_free(client_pubkey);
if (rc < 0) {
return SSH_ERROR;
}
rc = packet_send(session);
return rc;
}
static int ssh_curve25519_build_k(ssh_session session) {
ssh_curve25519_pubkey k;
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
return SSH_ERROR;
}
if (session->server)
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_client_pubkey);
else
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_server_pubkey);
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->k);
#endif
return 0;
}
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
*/
int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){
ssh_string q_s_string = NULL;
ssh_string pubkey = NULL;
ssh_string signature = NULL;
int rc;
pubkey = buffer_get_ssh_string(packet);
if (pubkey == NULL){
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
/* this is the server host key */
session->next_crypto->server_pubkey = pubkey;
pubkey = NULL;
q_s_string = buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
goto error;
}
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
(int)ssh_string_len(q_s_string));
ssh_string_free(q_s_string);
goto error;
}
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
ssh_string_free(q_s_string);
signature = buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature=NULL; /* ownership changed */
/* TODO: verify signature now instead of waiting for NEWKEYS */
if (ssh_curve25519_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* Send the MSG_NEWKEYS */
if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
error:
return SSH_ERROR;
}
#ifdef WITH_SERVER
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){
/* ECDH keys */
ssh_string q_c_string;
ssh_string q_s_string;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
ssh_string sig_blob = NULL;
int rc;
/* Extract the client pubkey from the init packet */
q_c_string = buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
return SSH_ERROR;
}
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
(int)ssh_string_len(q_c_string));
ssh_string_free(q_c_string);
return SSH_ERROR;
}
memcpy(session->next_crypto->curve25519_client_pubkey,
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
ssh_string_free(q_c_string);
/* Build server's keypair */
rc = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (rc == 0){
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
session->next_crypto->curve25519_privkey);
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
/* build k and session_id */
rc = ssh_curve25519_build_k(session);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
if (rc == SSH_ERROR) {
goto error;
}
rc = make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
goto error;
}
/* add host's public key */
rc = buffer_add_ssh_string(session->out_buffer,
session->next_crypto->server_pubkey);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
/* add ecdh public key */
q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE);
if (q_s_string == NULL) {
goto error;
}
ssh_string_fill(q_s_string,
session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
rc = buffer_add_ssh_string(session->out_buffer, q_s_string);
ssh_string_free(q_s_string);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
/* add signature blob */
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
goto error;
}
rc = buffer_add_ssh_string(session->out_buffer, sig_blob);
ssh_string_free(sig_blob);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent");
rc = packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
/* Send the MSG_NEWKEYS */
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
goto error;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return rc;
error:
buffer_reinit(session->out_buffer);
return SSH_ERROR;
}
#endif /* WITH_SERVER */
#endif /* HAVE_CURVE25519 */

272
src/curve25519_ref.c Normal file
View File

@@ -0,0 +1,272 @@
/*
version 20081011
Matthew Dempsky
Public domain.
Derived from public domain code by D. J. Bernstein.
*/
#include "libssh/curve25519.h"
static const unsigned char base[32] = {9};
int crypto_scalarmult_base(unsigned char *q,
const unsigned char *n)
{
return crypto_scalarmult(q,n,base);
}
static void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
{
unsigned int j;
unsigned int u;
u = 0;
for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
u += a[31] + b[31]; out[31] = u;
}
static void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
{
unsigned int j;
unsigned int u;
u = 218;
for (j = 0;j < 31;++j) {
u += a[j] + 65280 - b[j];
out[j] = u & 255;
u >>= 8;
}
u += a[31] - b[31];
out[31] = u;
}
static void squeeze(unsigned int a[32])
{
unsigned int j;
unsigned int u;
u = 0;
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
u += a[31]; a[31] = u & 127;
u = 19 * (u >> 7);
for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
u += a[31]; a[31] = u;
}
static const unsigned int minusp[32] = {
19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128
} ;
static void freeze(unsigned int a[32])
{
unsigned int aorig[32];
unsigned int j;
unsigned int negative;
for (j = 0;j < 32;++j) aorig[j] = a[j];
add(a,a,minusp);
negative = -((a[31] >> 7) & 1);
for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]);
}
static void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
{
unsigned int i;
unsigned int j;
unsigned int u;
for (i = 0;i < 32;++i) {
u = 0;
for (j = 0;j <= i;++j) u += a[j] * b[i - j];
for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j];
out[i] = u;
}
squeeze(out);
}
static void mult121665(unsigned int out[32],const unsigned int a[32])
{
unsigned int j;
unsigned int u;
u = 0;
for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; }
u += 121665 * a[31]; out[31] = u & 127;
u = 19 * (u >> 7);
for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; }
u += out[j]; out[j] = u;
}
static void square(unsigned int out[32],const unsigned int a[32])
{
unsigned int i;
unsigned int j;
unsigned int u;
for (i = 0;i < 32;++i) {
u = 0;
for (j = 0;j < i - j;++j) u += a[j] * a[i - j];
for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j];
u *= 2;
if ((i & 1) == 0) {
u += a[i / 2] * a[i / 2];
u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
}
out[i] = u;
}
squeeze(out);
}
static void c_select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b)
{
unsigned int j;
unsigned int t;
unsigned int bminus1;
bminus1 = b - 1;
for (j = 0;j < 64;++j) {
t = bminus1 & (r[j] ^ s[j]);
p[j] = s[j] ^ t;
q[j] = r[j] ^ t;
}
}
static void mainloop(unsigned int work[64],const unsigned char e[32])
{
unsigned int xzm1[64];
unsigned int xzm[64];
unsigned int xzmb[64];
unsigned int xzm1b[64];
unsigned int xznb[64];
unsigned int xzn1b[64];
unsigned int a0[64];
unsigned int a1[64];
unsigned int b0[64];
unsigned int b1[64];
unsigned int c1[64];
unsigned int r[32];
unsigned int s[32];
unsigned int t[32];
unsigned int u[32];
unsigned int j;
unsigned int b;
int pos;
for (j = 0;j < 32;++j) xzm1[j] = work[j];
xzm1[32] = 1;
for (j = 33;j < 64;++j) xzm1[j] = 0;
xzm[0] = 1;
for (j = 1;j < 64;++j) xzm[j] = 0;
for (pos = 254;pos >= 0;--pos) {
b = e[pos / 8] >> (pos & 7);
b &= 1;
c_select(xzmb,xzm1b,xzm,xzm1,b);
add(a0,xzmb,xzmb + 32);
sub(a0 + 32,xzmb,xzmb + 32);
add(a1,xzm1b,xzm1b + 32);
sub(a1 + 32,xzm1b,xzm1b + 32);
square(b0,a0);
square(b0 + 32,a0 + 32);
mult(b1,a1,a0 + 32);
mult(b1 + 32,a1 + 32,a0);
add(c1,b1,b1 + 32);
sub(c1 + 32,b1,b1 + 32);
square(r,c1 + 32);
sub(s,b0,b0 + 32);
mult121665(t,s);
add(u,t,b0);
mult(xznb,b0,b0 + 32);
mult(xznb + 32,s,u);
square(xzn1b,c1);
mult(xzn1b + 32,r,work);
c_select(xzm,xzm1,xznb,xzn1b,b);
}
for (j = 0;j < 64;++j) work[j] = xzm[j];
}
static void recip(unsigned int out[32],const unsigned int z[32])
{
unsigned int z2[32];
unsigned int z9[32];
unsigned int z11[32];
unsigned int z2_5_0[32];
unsigned int z2_10_0[32];
unsigned int z2_20_0[32];
unsigned int z2_50_0[32];
unsigned int z2_100_0[32];
unsigned int t0[32];
unsigned int t1[32];
int i;
/* 2 */ square(z2,z);
/* 4 */ square(t1,z2);
/* 8 */ square(t0,t1);
/* 9 */ mult(z9,t0,z);
/* 11 */ mult(z11,z9,z2);
/* 22 */ square(t0,z11);
/* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9);
/* 2^6 - 2^1 */ square(t0,z2_5_0);
/* 2^7 - 2^2 */ square(t1,t0);
/* 2^8 - 2^3 */ square(t0,t1);
/* 2^9 - 2^4 */ square(t1,t0);
/* 2^10 - 2^5 */ square(t0,t1);
/* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0);
/* 2^11 - 2^1 */ square(t0,z2_10_0);
/* 2^12 - 2^2 */ square(t1,t0);
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); }
/* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0);
/* 2^21 - 2^1 */ square(t0,z2_20_0);
/* 2^22 - 2^2 */ square(t1,t0);
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); }
/* 2^40 - 2^0 */ mult(t0,t1,z2_20_0);
/* 2^41 - 2^1 */ square(t1,t0);
/* 2^42 - 2^2 */ square(t0,t1);
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); }
/* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0);
/* 2^51 - 2^1 */ square(t0,z2_50_0);
/* 2^52 - 2^2 */ square(t1,t0);
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
/* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0);
/* 2^101 - 2^1 */ square(t1,z2_100_0);
/* 2^102 - 2^2 */ square(t0,t1);
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); }
/* 2^200 - 2^0 */ mult(t1,t0,z2_100_0);
/* 2^201 - 2^1 */ square(t0,t1);
/* 2^202 - 2^2 */ square(t1,t0);
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
/* 2^250 - 2^0 */ mult(t0,t1,z2_50_0);
/* 2^251 - 2^1 */ square(t1,t0);
/* 2^252 - 2^2 */ square(t0,t1);
/* 2^253 - 2^3 */ square(t1,t0);
/* 2^254 - 2^4 */ square(t0,t1);
/* 2^255 - 2^5 */ square(t1,t0);
/* 2^255 - 21 */ mult(out,t1,z11);
}
int crypto_scalarmult(unsigned char *q,
const unsigned char *n,
const unsigned char *p)
{
unsigned int work[96];
unsigned char e[32];
unsigned int i;
for (i = 0;i < 32;++i) e[i] = n[i];
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
for (i = 0;i < 32;++i) work[i] = p[i];
mainloop(work,e);
recip(work + 32,work + 32);
mult(work + 64,work,work + 32);
freeze(work + 64);
for (i = 0;i < 32;++i) q[i] = work[64 + i];
return 0;
}

283
src/dh.c
View File

@@ -3,8 +3,8 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2003-2013 by Aris Adamantiadis
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Dmitriy Kuznetsov <dk@yandex.ru>
*
* The SSH Library is free software; you can redistribute it and/or modify
@@ -170,7 +170,7 @@ int ssh_crypto_init(void) {
return -1;
}
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, &p_group14);
if (p_group1 == NULL) {
if (p_group14 == NULL) {
bignum_free(g);
bignum_free(p_group1);
g = NULL;
@@ -239,63 +239,6 @@ void ssh_print_bignum(const char *which, bignum num) {
SAFE_FREE(hex);
}
/**
* @brief Convert a buffer into a colon separated hex string.
* The caller has to free the memory.
*
* @param what What should be converted to a hex string.
*
* @param len Length of the buffer to convert.
*
* @return The hex string or NULL on error.
*
* @see ssh_string_free_char()
*/
char *ssh_get_hexa(const unsigned char *what, size_t len) {
const char h[] = "0123456789abcdef";
char *hexa;
size_t i;
size_t hlen = len * 3;
if (len > (UINT_MAX - 1) / 3) {
return NULL;
}
hexa = malloc(hlen + 1);
if (hexa == NULL) {
return NULL;
}
for (i = 0; i < len; i++) {
hexa[i * 3] = h[(what[i] >> 4) & 0xF];
hexa[i * 3 + 1] = h[what[i] & 0xF];
hexa[i * 3 + 2] = ':';
}
hexa[hlen - 1] = '\0';
return hexa;
}
/**
* @brief Print a buffer as colon separated hex string.
*
* @param descr Description printed in front of the hex string.
*
* @param what What should be converted to a hex string.
*
* @param len Length of the buffer to convert.
*/
void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
char *hexa = ssh_get_hexa(what, len);
if (hexa == NULL) {
return;
}
printf("%s: %s\n", descr, hexa);
free(hexa);
}
int dh_generate_x(ssh_session session) {
session->next_crypto->x = bignum_new();
if (session->next_crypto->x == NULL) {
@@ -464,6 +407,18 @@ bignum make_string_bn(ssh_string string){
return bn;
}
#ifdef HAVE_LIBCRYPTO
/** @internal
* @brief converts the content of a SSH string in an already allocated bignum
* @warning only available with OpenSSL builds
*/
void make_string_bn_inplace(ssh_string string, bignum bnout) {
unsigned int len = ssh_string_len(string);
bignum_bin2bn(string->data, len, bnout);
}
#endif /* HAVE_LIBCRYPTO */
ssh_string dh_get_e(ssh_session session) {
return make_bignum_string(session->next_crypto->e);
}
@@ -770,6 +725,18 @@ int make_sessionid(ssh_session session) {
if (rc < 0) {
goto error;
}
#endif
#ifdef HAVE_CURVE25519
} else if(session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG){
rc = buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
rc += buffer_add_data(buf, session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
rc += buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
rc += buffer_add_data(buf, session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
if (rc != SSH_OK) {
goto error;
}
#endif
}
num = make_bignum_string(session->next_crypto->k);
@@ -800,6 +767,7 @@ int make_sessionid(ssh_session session) {
session->next_crypto->secret_hash);
break;
case SSH_KEX_ECDH_SHA2_NISTP256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
@@ -913,6 +881,7 @@ int generate_session_keys(ssh_session session) {
ssh_string k_string = NULL;
ssh_mac_ctx ctx = NULL;
struct ssh_crypto_struct *crypto = session->next_crypto;
unsigned char *tmp;
int rc = -1;
k_string = make_bignum_string(crypto->k);
@@ -968,9 +937,12 @@ int generate_session_keys(ssh_session session) {
/* some ciphers need more than DIGEST_LEN bytes of input key */
if (crypto->out_cipher->keysize > crypto->digest_len * 8) {
crypto->encryptkey = realloc(crypto->encryptkey, crypto->digest_len * 2);
if(crypto->encryptkey == NULL)
goto error;
tmp = realloc(crypto->encryptkey, crypto->digest_len * 2);
if (tmp == NULL) {
goto error;
}
crypto->encryptkey = tmp;
ctx = ssh_mac_ctx_init(crypto->mac_type);
if (ctx == NULL) {
goto error;
@@ -983,7 +955,12 @@ int generate_session_keys(ssh_session session) {
}
if (crypto->in_cipher->keysize > crypto->digest_len * 8) {
crypto->decryptkey = realloc(crypto->decryptkey, crypto->digest_len *2);
tmp = realloc(crypto->decryptkey, crypto->digest_len *2);
if (tmp == NULL) {
goto error;
}
crypto->decryptkey = tmp;
if(crypto->decryptkey == NULL)
goto error;
ctx = ssh_mac_ctx_init(crypto->mac_type);
@@ -1034,25 +1011,7 @@ error:
*/
/**
* @brief Allocates a buffer with the MD5 hash of the server public key.
*
* This function allows you to get a MD5 hash of the public key. You can then
* print this hash in a human-readable form to the user so that he is able to
* verify it. Use ssh_get_hexa() or ssh_print_hexa() to display it.
*
* @param[in] session The SSH session to use.
*
* @param[in] hash The buffer to allocate.
*
* @return The bytes allocated or < 0 on error.
*
* @warning It is very important that you verify at some moment that the hash
* matches a known server. If you don't do it, cryptography wont help
* you at making things secure
*
* @see ssh_is_server_known()
* @see ssh_get_hexa()
* @see ssh_print_hexa()
* @deprecated Use ssh_get_publickey_hash()
*/
int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) {
ssh_string pubkey;
@@ -1129,6 +1088,164 @@ int ssh_get_publickey(ssh_session session, ssh_key *key)
key);
}
/**
* @brief Allocates a buffer with the hash of the public key.
*
* This function allows you to get a hash of the public key. You can then
* print this hash in a human-readable form to the user so that he is able to
* verify it. Use ssh_get_hexa() or ssh_print_hexa() to display it.
*
* @param[in] key The public key to create the hash for.
*
* @param[in] type The type of the hash you want.
*
* @param[in] hash A pointer to store the allocated buffer. It can be
* freed using ssh_clean_pubkey_hash().
*
* @param[in] hlen The length of the hash.
*
* @return 0 on success, -1 if an error occured.
*
* @warning It is very important that you verify at some moment that the hash
* matches a known server. If you don't do it, cryptography wont help
* you at making things secure.
* OpenSSH uses SHA1 to print public key digests.
*
* @see ssh_is_server_known()
* @see ssh_get_hexa()
* @see ssh_print_hexa()
* @see ssh_clean_pubkey_hash()
*/
int ssh_get_publickey_hash(const ssh_key key,
enum ssh_publickey_hash_type type,
unsigned char **hash,
size_t *hlen)
{
ssh_string blob;
unsigned char *h;
int rc;
rc = ssh_pki_export_pubkey_blob(key, &blob);
if (rc < 0) {
return rc;
}
switch (type) {
case SSH_PUBLICKEY_HASH_SHA1:
{
SHACTX ctx;
h = malloc(SHA_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = sha1_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
sha1_final(h, ctx);
*hlen = SHA_DIGEST_LEN;
}
break;
case SSH_PUBLICKEY_HASH_MD5:
{
MD5CTX ctx;
h = malloc(MD5_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = md5_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
md5_final(h, ctx);
*hlen = MD5_DIGEST_LEN;
}
break;
default:
rc = -1;
goto out;
}
*hash = h;
rc = 0;
out:
ssh_string_free(blob);
return rc;
}
/**
* @brief Convert a buffer into a colon separated hex string.
* The caller has to free the memory.
*
* @param what What should be converted to a hex string.
*
* @param len Length of the buffer to convert.
*
* @return The hex string or NULL on error.
*
* @see ssh_string_free_char()
*/
char *ssh_get_hexa(const unsigned char *what, size_t len) {
const char h[] = "0123456789abcdef";
char *hexa;
size_t i;
size_t hlen = len * 3;
if (len > (UINT_MAX - 1) / 3) {
return NULL;
}
hexa = malloc(hlen + 1);
if (hexa == NULL) {
return NULL;
}
for (i = 0; i < len; i++) {
hexa[i * 3] = h[(what[i] >> 4) & 0xF];
hexa[i * 3 + 1] = h[what[i] & 0xF];
hexa[i * 3 + 2] = ':';
}
hexa[hlen - 1] = '\0';
return hexa;
}
/**
* @brief Print a buffer as colon separated hex string.
*
* @param descr Description printed in front of the hex string.
*
* @param what What should be converted to a hex string.
*
* @param len Length of the buffer to convert.
*/
void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
char *hexa = ssh_get_hexa(what, len);
if (hexa == NULL) {
return;
}
printf("%s: %s\n", descr, hexa);
free(hexa);
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -1,7 +1,7 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2011 by Aris Adamantiadis
* Copyright (c) 2011-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -100,6 +100,7 @@ static int ecdh_build_k(ssh_session session) {
EC_POINT *pubkey;
void *buffer;
int len = (EC_GROUP_get_degree(group) + 7) / 8;
int rc;
bignum_CTX ctx = bignum_ctx_new();
if (ctx == NULL) {
return -1;
@@ -124,9 +125,23 @@ static int ecdh_build_k(ssh_session session) {
EC_POINT_oct2point(group,pubkey,ssh_string_data(session->next_crypto->ecdh_server_pubkey),
ssh_string_len(session->next_crypto->ecdh_server_pubkey),ctx);
buffer = malloc(len);
ECDH_compute_key(buffer,len,pubkey,session->next_crypto->ecdh_privkey,NULL);
EC_POINT_free(pubkey);
BN_bin2bn(buffer,len,session->next_crypto->k);
if (buffer == NULL) {
EC_POINT_clear_free(pubkey);
return -1;
}
rc = ECDH_compute_key(buffer,
len,
pubkey,
session->next_crypto->ecdh_privkey,
NULL);
EC_POINT_clear_free(pubkey);
if (rc <= 0) {
free(buffer);
return -1;
}
bignum_bin2bn(buffer, len, session->next_crypto->k);
free(buffer);
EC_KEY_free(session->next_crypto->ecdh_privkey);
session->next_crypto->ecdh_privkey=NULL;

View File

@@ -104,7 +104,7 @@ void _ssh_set_error_invalid(void *error, const char *function)
/**
* @brief Retrieve the error text message from the last error.
*
* @param error The SSH session pointer.
* @param error An ssh_session or ssh_bind.
*
* @return A static string describing the error.
*/
@@ -117,7 +117,7 @@ const char *ssh_get_error(void *error) {
/**
* @brief Retrieve the error code from the last error.
*
* @param error The SSH session pointer.
* @param error An ssh_session or ssh_bind.
*
* \return SSH_NO_ERROR No error occurred\n
* SSH_REQUEST_DENIED The last request was denied but situation is

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2011 by Andreas Schneider <mail@cryptomilk.org>
* Copyright (c) 2011-2013 by Andreas Schneider <mail@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by

View File

@@ -49,7 +49,7 @@ struct ssh_gssapi_struct{
enum ssh_gssapi_state_e state; /* current state */
struct gss_OID_desc_struct mech; /* mechanism being elected for auth */
gss_cred_id_t server_creds; /* credentials of server */
gss_cred_id_t client_creds; /* creds of the client */
gss_cred_id_t client_creds; /* creds delegated by the client */
gss_ctx_id_t ctx; /* the authentication context */
gss_name_t client_name; /* Identity of the client */
char *user; /* username of client */
@@ -57,7 +57,9 @@ struct ssh_gssapi_struct{
char *service; /* name of the service */
struct {
gss_name_t server_name; /* identity of server */
OM_uint32 flags; /* flags used for init context */
gss_OID oid; /* mech being used for authentication */
gss_cred_id_t creds; /* creds used to initialize context */
gss_cred_id_t client_deleg_creds; /* delegated creds (const, not freeable) */
} client;
};
@@ -89,12 +91,13 @@ static void ssh_gssapi_free(ssh_session session){
OM_uint32 min;
if (session->gssapi == NULL)
return;
if (session->gssapi->mech.elements)
SAFE_FREE(session->gssapi->mech.elements);
if (session->gssapi->user)
SAFE_FREE(session->gssapi->user);
if (session->gssapi->server_creds)
gss_release_cred(&min,&session->gssapi->server_creds);
SAFE_FREE(session->gssapi->user);
SAFE_FREE(session->gssapi->mech.elements);
gss_release_cred(&min,&session->gssapi->server_creds);
if (session->gssapi->client.creds !=
session->gssapi->client.client_deleg_creds) {
gss_release_cred(&min, &session->gssapi->client.creds);
}
SAFE_FREE(session->gssapi);
}
@@ -208,8 +211,8 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
maj_stat = gss_import_name(&min_stat, &name_buf,
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
if (maj_stat != GSS_S_COMPLETE) {
SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat);
ssh_gssapi_log_error(0, "importing name", maj_stat);
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat);
return -1;
}
@@ -220,13 +223,13 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
gss_release_oid_set(&min_stat, &both_supported);
if (maj_stat != GSS_S_COMPLETE) {
SSH_LOG(0, "error acquiring credentials %d, %d", maj_stat, min_stat);
ssh_gssapi_log_error(0, "acquiring creds", maj_stat);
SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat);
ssh_gssapi_log_error(SSH_LOG_WARNING, "acquiring creds", maj_stat);
ssh_auth_reply_default(session,0);
return SSH_ERROR;
}
SSH_LOG(0, "acquiring credentials %d, %d", maj_stat, min_stat);
SSH_LOG(SSH_LOG_PROTOCOL, "acquiring credentials %d, %d", maj_stat, min_stat);
/* finding which OID from client we selected */
for (i=0 ; i< n_oid ; ++i){
@@ -263,7 +266,7 @@ static char *ssh_gssapi_name_to_char(gss_name_t name){
OM_uint32 maj_stat, min_stat;
char *ptr;
maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
ssh_gssapi_log_error(0, "converting name", maj_stat);
ssh_gssapi_log_error(SSH_LOG_WARNING, "converting name", maj_stat);
ptr=malloc(buffer.length + 1);
memcpy(ptr, buffer.value, buffer.length);
ptr[buffer.length] = '\0';
@@ -335,14 +338,14 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds,
&input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags,
NULL /*time*/, &session->gssapi->client_creds);
ssh_gssapi_log_error(0, "accepting token", maj_stat);
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "accepting token", maj_stat);
ssh_string_free(token);
if (client_name != GSS_C_NO_NAME){
session->gssapi->client_name = client_name;
session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name);
}
if (GSS_ERROR(maj_stat)){
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "Gssapi error", maj_stat);
ssh_gssapi_log_error(SSH_LOG_WARNING, "Gssapi error", maj_stat);
ssh_auth_reply_default(session,0);
ssh_gssapi_free(session);
session->gssapi=NULL;
@@ -484,8 +487,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic)
mic_token_buf.value = ssh_string_data(mic_token);
maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL);
ssh_gssapi_log_error(0, "verifying MIC", maj_stat);
ssh_gssapi_log_error(0, "verifying MIC (min stat)", min_stat);
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "verifying MIC", maj_stat);
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "verifying MIC (min stat)", min_stat);
if (maj_stat == GSS_S_DEFECTIVE_TOKEN || GSS_ERROR(maj_stat)) {
goto error;
}
@@ -536,8 +539,12 @@ ssh_gssapi_creds ssh_gssapi_get_creds(ssh_session session){
return (ssh_gssapi_creds)session->gssapi->client_creds;
}
#endif /* SERVER */
/**
* @brief Set the forwadable ticket to be given to the server for authentication.
* Unlike ssh_gssapi_get_creds() this is called on the client side of an ssh
* connection.
*
* @param[in] creds gssapi credentials handle.
*/
@@ -556,8 +563,6 @@ void ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds)
session->gssapi->client.client_deleg_creds = (gss_cred_id_t)creds;
}
#endif /* SERVER */
static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, int n_oid){
ssh_string str;
int rc;
@@ -616,88 +621,75 @@ fail:
return SSH_ERROR;
}
/** @brief returns the OIDs of the mechs that work with both
* hostname and username
/** @brief returns the OIDs of the mechs that have usable credentials
*/
static int ssh_gssapi_match(ssh_session session, char *hostname, char *username, gss_OID_set *valid_oids, int deleg){
gss_buffer_desc host_namebuf, user_namebuf;
gss_name_t host_name, user_name;
OM_uint32 maj_stat, min_stat;
gss_OID_set supported;
static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
{
OM_uint32 maj_stat, min_stat, lifetime;
gss_OID_set actual_mechs;
gss_buffer_desc namebuf;
gss_name_t client_id = GSS_C_NO_NAME;
gss_OID oid;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL;
unsigned int i;
char *ptr;
char hostname_buf[256];
int ret;
if (session->gssapi->client.client_deleg_creds == NULL) {
if (session->opts.gss_client_identity != NULL) {
namebuf.value = (void *)session->opts.gss_client_identity;
namebuf.length = strlen(session->opts.gss_client_identity);
gss_create_empty_oid_set(&min_stat, valid_oids);
maj_stat = gss_indicate_mechs(&min_stat, &supported);
for (i=0; i < supported->count; ++i){
ptr=ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length);
SSH_LOG(SSH_LOG_DEBUG, "GSSAPI oid supported %d : %s\n",i, ptr);
SAFE_FREE(ptr);
}
user_namebuf.value = username;
user_namebuf.length = strlen(username) + 1;
maj_stat = gss_import_name(&min_stat, &user_namebuf,
(gss_OID) GSS_C_NT_USER_NAME, &user_name);
if (maj_stat != GSS_S_COMPLETE) {
SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat);
ssh_gssapi_log_error(SSH_LOG_DEBUG, "importing name", maj_stat);
return -1;
}
snprintf(hostname_buf, sizeof(hostname_buf),"host@%s", hostname);
host_namebuf.value = hostname_buf;
host_namebuf.length = strlen(hostname_buf) + 1;
maj_stat = gss_import_name(&min_stat, &host_namebuf,
(gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &host_name);
if (maj_stat != GSS_S_COMPLETE) {
SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat);
ssh_gssapi_log_error(0, "importing name", maj_stat);
return -1;
}
ssh_gssapi_init(session);
session->gssapi->client_name = user_name;
session->gssapi->client.server_name = host_name;
session->gssapi->user = strdup(username);
for (i=0; i<supported->count; ++i){
oid = &supported->elements[i];
maj_stat = gss_init_sec_context(&min_stat,
session->gssapi->client.client_deleg_creds, &ctx, host_name, oid,
GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0),
0, NULL, &input_token, NULL, &output_token, NULL, NULL);
if (!GSS_ERROR(maj_stat)){
gss_OID_set tmp;
if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL){
/* we know the oid is ok since init_sec_context worked */
gss_add_oid_set_member(&min_stat, oid, valid_oids);
SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server (with forwarding)", i);
} else {
gss_create_empty_oid_set(&min_stat, &tmp);
gss_add_oid_set_member(&min_stat, oid, &tmp);
maj_stat = gss_acquire_cred(&min_stat, user_name, 0,
tmp, GSS_C_INITIATE,
&client_creds, NULL, NULL);
gss_release_oid_set(&min_stat, &tmp);
if (!GSS_ERROR(maj_stat)){
gss_release_cred(&min_stat, &client_creds);
gss_add_oid_set_member(&min_stat,oid,valid_oids);
SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server", i);
}
maj_stat = gss_import_name(&min_stat, &namebuf,
GSS_C_NT_USER_NAME, &client_id);
if (GSS_ERROR(maj_stat)) {
ret = SSH_ERROR;
goto end;
}
}
gss_delete_sec_context(&min_stat,&ctx, &output_token);
ctx = GSS_C_NO_CONTEXT;
maj_stat = gss_acquire_cred(&min_stat, client_id, GSS_C_INDEFINITE,
GSS_C_NO_OID_SET, GSS_C_INITIATE,
&session->gssapi->client.creds,
&actual_mechs, NULL);
if (GSS_ERROR(maj_stat)) {
ret = SSH_ERROR;
goto end;
}
} else {
session->gssapi->client.creds =
session->gssapi->client.client_deleg_creds;
maj_stat = gss_inquire_cred(&min_stat, session->gssapi->client.creds,
&client_id, NULL, NULL, &actual_mechs);
if (GSS_ERROR(maj_stat)) {
ret = SSH_ERROR;
goto end;
}
}
return SSH_OK;
gss_create_empty_oid_set(&min_stat, valid_oids);
/* double check each single cred */
for (i = 0; i < actual_mechs->count; i++) {
/* check lifetime is not 0 or skip */
lifetime = 0;
oid = &actual_mechs->elements[i];
maj_stat = gss_inquire_cred_by_mech(&min_stat,
session->gssapi->client.creds,
oid, NULL, &lifetime, NULL, NULL);
if (maj_stat == GSS_S_COMPLETE && lifetime > 0) {
gss_add_oid_set_member(&min_stat, oid, valid_oids);
ptr = ssh_get_hexa(oid->elements, oid->length);
SSH_LOG(SSH_LOG_DEBUG, "GSSAPI valid oid %d : %s\n", i, ptr);
SAFE_FREE(ptr);
}
}
ret = SSH_OK;
end:
gss_release_name(&min_stat, &client_id);
return ret;
}
/**
@@ -713,21 +705,55 @@ int ssh_gssapi_auth_mic(ssh_session session){
ssh_string *oids;
int rc;
int n_oids = 0;
OM_uint32 maj_stat, min_stat;
char name_buf[256];
gss_buffer_desc hostname;
const char *gss_host = session->opts.host;
if (ssh_gssapi_init(session) == SSH_ERROR)
rc = ssh_gssapi_init(session);
if (rc == SSH_ERROR) {
return SSH_AUTH_ERROR;
}
if (session->opts.gss_server_identity != NULL) {
gss_host = session->opts.gss_server_identity;
}
/* import target host name */
snprintf(name_buf, sizeof(name_buf), "host@%s", gss_host);
hostname.value = name_buf;
hostname.length = strlen(name_buf) + 1;
maj_stat = gss_import_name(&min_stat, &hostname,
(gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
&session->gssapi->client.server_name);
if (maj_stat != GSS_S_COMPLETE) {
SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat);
ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat);
return SSH_PACKET_USED;
}
/* copy username */
session->gssapi->user = strdup(session->opts.username);
if (session->gssapi->user == NULL) {
ssh_set_error_oom(session);
return SSH_AUTH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi to host %s with user %s",
session->opts.host, session->opts.username);
rc = ssh_gssapi_match(session,session->opts.host, session->opts.username, &selected, 0);
if (rc == SSH_ERROR)
session->opts.host, session->gssapi->user);
rc = ssh_gssapi_match(session, &selected);
if (rc == SSH_ERROR) {
return SSH_AUTH_DENIED;
}
n_oids = selected->count;
SSH_LOG(SSH_LOG_PROTOCOL, "Sending %d oids", n_oids);
oids = calloc(n_oids, sizeof(ssh_string));
if (oids == NULL) {
ssh_set_error_oom(session);
return SSH_AUTH_ERROR;
}
for (i=0; i<n_oids; ++i){
oids[i] = ssh_string_new(selected->elements[i].length + 2);
@@ -769,15 +795,11 @@ static gss_OID ssh_gssapi_oid_from_string(ssh_string oid_s){
SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
ssh_string oid_s;
gss_OID oid;
gss_uint32 maj_stat, min_stat;
int deleg = 0;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_OID_set tmp;
char *hexa;
ssh_string token;
gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
(void)type;
(void)user;
@@ -791,31 +813,27 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
ssh_set_error(session, SSH_FATAL, "Missing OID");
return SSH_PACKET_USED;
}
oid = ssh_gssapi_oid_from_string(oid_s);
session->gssapi->client.oid = ssh_gssapi_oid_from_string(oid_s);
ssh_string_free(oid_s);
if (!oid) {
if (!session->gssapi->client.oid) {
ssh_set_error(session, SSH_FATAL, "Invalid OID");
return SSH_PACKET_USED;
}
if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL)
creds = session->gssapi->client.client_deleg_creds;
if (creds == GSS_C_NO_CREDENTIAL){
gss_create_empty_oid_set(&min_stat, &tmp);
gss_add_oid_set_member(&min_stat, oid, &tmp);
maj_stat = gss_acquire_cred(&min_stat, session->gssapi->client_name, 0,
tmp, GSS_C_INITIATE,
&session->gssapi->client_creds, NULL, NULL);
gss_release_oid_set(&min_stat, &tmp);
if (GSS_ERROR(maj_stat)){
ssh_gssapi_log_error(SSH_LOG_WARNING,"Error acquiring credentials",maj_stat);
return SSH_PACKET_USED;
}
session->gssapi->client.flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
if (session->opts.gss_delegate_creds) {
session->gssapi->client.flags |= GSS_C_DELEG_FLAG;
}
/* prepare the first TOKEN response */
maj_stat = gss_init_sec_context(&min_stat,
creds, &session->gssapi->ctx, session->gssapi->client.server_name, oid,
GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0),
0, NULL, &input_token, NULL, &output_token, NULL, NULL);
session->gssapi->client.creds,
&session->gssapi->ctx,
session->gssapi->client.server_name,
session->gssapi->client.oid,
session->gssapi->client.flags,
0, NULL, &input_token, NULL,
&output_token, NULL, NULL);
if(GSS_ERROR(maj_stat)){
ssh_gssapi_log_error(SSH_LOG_WARNING, "Initializing gssapi context", maj_stat);
return SSH_PACKET_USED;
@@ -832,7 +850,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
ssh_string_free(token);
session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN;
}
session->gssapi->client.oid = oid;
return SSH_PACKET_USED;
}
@@ -856,7 +873,7 @@ static int ssh_gssapi_send_mic(ssh_session session){
maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT, &mic_buf, &mic_token_buf);
if (GSS_ERROR(maj_stat)){
ssh_buffer_free(mic_buffer);
ssh_gssapi_log_error(0, "generating MIC", maj_stat);
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "generating MIC", maj_stat);
return SSH_ERROR;
}
@@ -889,8 +906,6 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
char *hexa;
OM_uint32 maj_stat, min_stat;
gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
int deleg = 0;
(void)user;
(void)type;
@@ -910,16 +925,16 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
SAFE_FREE(hexa);
input_token.length = ssh_string_len(token);
input_token.value = ssh_string_data(token);
if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL)
creds = session->gssapi->client.client_deleg_creds;
else
creds = session->gssapi->client_creds;
maj_stat = gss_init_sec_context(&min_stat,
creds, &session->gssapi->ctx, session->gssapi->client.server_name, session->gssapi->client.oid,
GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0),
0, NULL, &input_token, NULL, &output_token, NULL, NULL);
session->gssapi->client.creds,
&session->gssapi->ctx,
session->gssapi->client.server_name,
session->gssapi->client.oid,
session->gssapi->client.flags,
0, NULL, &input_token, NULL,
&output_token, NULL, NULL);
ssh_gssapi_log_error(0, "accepting token", maj_stat);
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "accepting token", maj_stat);
ssh_string_free(token);
if (GSS_ERROR(maj_stat)){
ssh_gssapi_log_error(SSH_LOG_PROTOCOL, "Gssapi error", maj_stat);

View File

@@ -4,7 +4,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2003 by Aris Adamantiadis
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2009 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by

View File

@@ -34,6 +34,8 @@
#include "libssh/session.h"
#include "libssh/ssh2.h"
#include "libssh/string.h"
#include "libssh/curve25519.h"
#include "libssh/knownhosts.h"
#ifdef HAVE_LIBGCRYPT
# define BLOWFISH "blowfish-cbc,"
@@ -63,14 +65,21 @@
#define ZLIB "none"
#endif
#ifdef HAVE_ECDH
#define KEY_EXCHANGE "ecdh-sha2-nistp256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define HOSTKEYS "ecdsa-sha2-nistp256,ssh-rsa,ssh-dss"
#ifdef HAVE_CURVE25519
#define CURVE25519 "curve25519-sha256@libssh.org,"
#else
#define KEY_EXCHANGE "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define HOSTKEYS "ssh-rsa,ssh-dss"
#define CURVE25519 ""
#endif
#ifdef HAVE_ECDH
#define ECDH "ecdh-sha2-nistp256,"
#define HOSTKEYS "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-rsa,ssh-dss"
#else
#define HOSTKEYS "ssh-rsa,ssh-dss"
#define ECDH ""
#endif
#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define KEX_METHODS_SIZE 10
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
@@ -306,7 +315,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
for (i = 0; i < KEX_METHODS_SIZE; i++) {
str = buffer_get_ssh_string(packet);
if (str == NULL) {
break;
goto error;
}
if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) {
@@ -341,6 +350,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
error:
ssh_string_free(str);
for (i = 0; i < SSH_KEX_METHODS; i++) {
if (server_kex) {
session->next_crypto->client_kex.methods[i] = NULL;
} else { /* client */
session->next_crypto->server_kex.methods[i] = NULL;
}
SAFE_FREE(strings[i]);
}
@@ -365,6 +379,53 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
}
}
/**
* @internal
* @brief selects the hostkey mechanisms to be chosen for the key exchange,
* as some hostkey mechanisms may be present in known_hosts file and preferred
* @returns a cstring containing a comma-separated list of hostkey methods.
* NULL if no method matches
*/
static char *ssh_client_select_hostkeys(ssh_session session){
char methods_buffer[128]={0};
static const char *preferred_hostkeys[]={"ecdsa-sha2-nistp521","ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp256", "ssh-rsa", "ssh-dss", "ssh-rsa1", NULL};
char **methods;
int i,j;
int needcoma=0;
methods = ssh_knownhosts_algorithms(session);
if (methods == NULL || methods[0] == NULL){
SAFE_FREE(methods);
return NULL;
}
for (i=0;preferred_hostkeys[i] != NULL; ++i){
for (j=0; methods[j] != NULL; ++j){
if(strcmp(preferred_hostkeys[i], methods[j]) == 0){
if (verify_existing_algo(SSH_HOSTKEYS, methods[j])){
if(needcoma)
strncat(methods_buffer,",",sizeof(methods_buffer)-strlen(methods_buffer)-1);
strncat(methods_buffer, methods[j], sizeof(methods_buffer)-strlen(methods_buffer)-1);
needcoma = 1;
}
}
}
}
for(i=0;methods[i]!= NULL; ++i){
SAFE_FREE(methods[i]);
}
SAFE_FREE(methods);
if(strlen(methods_buffer) > 0){
SSH_LOG(SSH_LOG_DEBUG, "Changing host key method to \"%s\"", methods_buffer);
return strdup(methods_buffer);
} else {
SSH_LOG(SSH_LOG_DEBUG, "No supported kex method for existing key in known_hosts file");
return NULL;
}
}
/**
* @brief sets the key exchange parameters to be sent to the server,
* in function of the options and available methods.
@@ -377,6 +438,13 @@ int set_client_kex(ssh_session session){
ssh_get_random(client->cookie, 16, 0);
memset(client->methods, 0, KEX_METHODS_SIZE * sizeof(char **));
/* first check if we have specific host key methods */
if(session->opts.wanted_methods[SSH_HOSTKEYS] == NULL){
/* Only if no override */
session->opts.wanted_methods[SSH_HOSTKEYS] =
ssh_client_select_hostkeys(session);
}
for (i = 0; i < KEX_METHODS_SIZE; i++) {
wanted = session->opts.wanted_methods[i];
if (wanted == NULL)
@@ -412,6 +480,8 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
}
return SSH_OK;

View File

@@ -4,7 +4,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2003-2009 by Aris Adamantiadis
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2009 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -34,7 +34,7 @@
#include "libssh/misc.h"
#include "libssh/pki.h"
#include "libssh/options.h"
#include "libssh/knownhosts.h"
/*todo: remove this include */
#include "libssh/string.h"
@@ -435,7 +435,7 @@ int ssh_is_server_known(ssh_session session) {
return SSH_SERVER_ERROR;
}
host = ssh_lowercase(session->opts.host);
hostport = ssh_hostport(host, session->opts.port);
hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
if (host == NULL || hostport == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(host);
@@ -542,7 +542,7 @@ int ssh_write_knownhost(ssh_session session) {
host = ssh_lowercase(session->opts.host);
/* If using a nonstandard port, save the host in the [host]:port format */
if(session->opts.port != 22) {
if (session->opts.port > 0 && session->opts.port != 22) {
hostport = ssh_hostport(host, session->opts.port);
SAFE_FREE(host);
if (hostport == NULL) {
@@ -647,6 +647,102 @@ int ssh_write_knownhost(ssh_session session) {
return 0;
}
#define KNOWNHOSTS_MAXTYPES 10
/**
* @internal
* @brief Check which kind of host keys should be preferred for connection
* by reading the known_hosts file.
*
* @param[in] session The SSH session to use.
*
* @returns array of supported key types
* NULL on error
*/
char **ssh_knownhosts_algorithms(ssh_session session) {
FILE *file = NULL;
char **tokens;
char *host;
char *hostport;
const char *type;
int match;
char **array;
int i=0, j;
if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Can't find a known_hosts file");
return NULL;
}
}
if (session->opts.host == NULL) {
return NULL;
}
host = ssh_lowercase(session->opts.host);
hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
array = malloc(sizeof(char *) * KNOWNHOSTS_MAXTYPES);
if (host == NULL || hostport == NULL || array == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(host);
SAFE_FREE(hostport);
SAFE_FREE(array);
return NULL;
}
do {
tokens = ssh_get_knownhost_line(&file,
session->opts.knownhosts, &type);
/* End of file, return the current state */
if (tokens == NULL) {
break;
}
match = match_hashed_host(host, tokens[0]);
if (match == 0){
match = match_hostname(hostport, tokens[0], strlen(tokens[0]));
}
if (match == 0) {
match = match_hostname(host, tokens[0], strlen(tokens[0]));
}
if (match == 0) {
match = match_hashed_host(hostport, tokens[0]);
}
if (match) {
/* We got a match. Now check the key type */
SSH_LOG(SSH_LOG_DEBUG, "server %s:%d has %s in known_hosts",
host, session->opts.port, type);
/* don't copy more than once */
for(j=0;j<i && match;++j){
if(strcmp(array[j], type)==0)
match=0;
}
if (match){
array[i] = strdup(type);
i++;
if(i>= KNOWNHOSTS_MAXTYPES-1){
tokens_free(tokens);
break;
}
}
}
tokens_free(tokens);
} while (1);
array[i]=NULL;
SAFE_FREE(host);
SAFE_FREE(hostport);
if (file != NULL) {
fclose(file);
}
/* Return the current state at end of file */
return array;
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -19,10 +19,14 @@
* MA 02111-1307, USA.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include "libssh/priv.h"
#include "libssh/session.h"
@@ -38,6 +42,8 @@
#include <openssl/rsa.h>
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
#include <openssl/rand.h>
#ifdef HAVE_OPENSSL_AES_H
#define HAS_AES
#include <openssl/aes.h>
@@ -74,6 +80,14 @@ static int alloc_key(struct ssh_cipher_struct *cipher) {
return 0;
}
void ssh_reseed(void){
#ifndef _WIN32
struct timeval tv;
gettimeofday(&tv, NULL);
RAND_add(&tv, sizeof(tv), 0.0);
#endif
}
SHACTX sha1_init(void) {
SHACTX c = malloc(sizeof(*c));
if (c == NULL) {
@@ -123,6 +137,30 @@ void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned
EVP_DigestUpdate(&md, digest, len);
EVP_DigestFinal(&md, hash, hlen);
}
EVPCTX evp_init(int nid)
{
const EVP_MD *evp_md = nid_to_evpmd(nid);
EVPCTX ctx = malloc(sizeof(EVP_MD_CTX));
if (ctx == NULL) {
return NULL;
}
EVP_DigestInit(ctx, evp_md);
return ctx;
}
void evp_update(EVPCTX ctx, const void *data, unsigned long len)
{
EVP_DigestUpdate(ctx, data, len);
}
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
{
EVP_DigestFinal(ctx, md, mdlen);
}
#endif
SHA256CTX sha256_init(void){
@@ -169,7 +207,11 @@ void md5_final(unsigned char *md, MD5CTX c) {
}
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
if (ctx == NULL) {
return NULL;
}
ctx->mac_type=type;
switch(type){
case SSH_MAC_SHA1:

View File

@@ -45,6 +45,9 @@ static int alloc_key(struct ssh_cipher_struct *cipher) {
return 0;
}
void ssh_reseed(void){
}
SHACTX sha1_init(void) {
SHACTX ctx = NULL;
gcry_md_open(&ctx, GCRY_MD_SHA1, 0);
@@ -88,7 +91,11 @@ void md5_final(unsigned char *md, MD5CTX c) {
}
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
ssh_mac_ctx ctx=malloc(sizeof(struct ssh_mac_ctx_struct));
ssh_mac_ctx ctx = malloc(sizeof(struct ssh_mac_ctx_struct));
if (ctx == NULL) {
return NULL;
}
ctx->mac_type=type;
switch(type){
case SSH_MAC_SHA1:

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2008 by Aris Adamantiadis
* Copyright (c) 2008-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -65,7 +65,7 @@ static int current_timestring(int hires, char *buf, size_t len)
if (hires) {
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
snprintf(buf, len, "%s.%06ld", tbuf, tv.tv_usec);
snprintf(buf, len, "%s.%06ld", tbuf, (long)tv.tv_usec);
} else {
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
snprintf(buf, len, "%s", tbuf);

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2009 by Aris Adamantiadis
* Copyright (c) 2003-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -120,13 +120,32 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
msg->auth_request.username, msg->auth_request.pubkey,
msg->auth_request.signature_state,
session->server_callbacks->userdata);
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
if (msg->auth_request.signature_state != SSH_PUBLICKEY_STATE_NONE) {
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
} else {
} else {
ssh_message_reply_default(msg);
}
} else {
if (rc == SSH_AUTH_SUCCESS) {
ssh_message_auth_reply_pk_ok_simple(msg);
} else {
ssh_message_reply_default(msg);
}
}
return SSH_OK;
} else if (msg->auth_request.method == SSH_AUTH_METHOD_NONE &&
ssh_callbacks_exists(session->server_callbacks, auth_none_function)) {
rc = session->server_callbacks->auth_none_function(session,
msg->auth_request.username, session->server_callbacks->userdata);
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){
ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
} else {
ssh_message_reply_default(msg);
}
return SSH_OK;
}
break;
case SSH_REQUEST_CHANNEL_OPEN:
@@ -189,8 +208,8 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
ssh_callbacks_exists(channel->callbacks, channel_pty_window_change_function)) {
rc = channel->callbacks->channel_pty_window_change_function(session,
channel,
msg->channel_request.height, msg->channel_request.width,
msg->channel_request.pxheight, msg->channel_request.pxwidth,
msg->channel_request.width, msg->channel_request.height,
msg->channel_request.pxwidth, msg->channel_request.pxheight,
channel->callbacks->userdata);
} else if (msg->channel_request.type == SSH_CHANNEL_REQUEST_EXEC &&
ssh_callbacks_exists(channel->callbacks, channel_exec_request_function)) {
@@ -290,10 +309,8 @@ static int ssh_execute_server_callbacks(ssh_session session, ssh_message msg){
if (session->server_callbacks != NULL){
rc = ssh_execute_server_request(session, msg);
}
/* This one is in fact a client callback... */
if (session->common.callbacks != NULL) {
} else if (session->common.callbacks != NULL) {
/* This one is in fact a client callback... */
rc = ssh_execute_client_request(session, msg);
}
@@ -491,8 +508,7 @@ void ssh_message_free(ssh_message msg){
case SSH_REQUEST_AUTH:
SAFE_FREE(msg->auth_request.username);
if (msg->auth_request.password) {
memset(msg->auth_request.password, 0,
strlen(msg->auth_request.password));
BURN_STRING(msg->auth_request.password);
SAFE_FREE(msg->auth_request.password);
}
ssh_key_free(msg->auth_request.pubkey);
@@ -1355,6 +1371,7 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel,
msg->channel_request.pxheight = ntohl(msg->channel_request.pxheight);
msg->channel_request.modes = buffer_get_ssh_string(packet);
if (msg->channel_request.modes == NULL) {
msg->channel_request.TERM = NULL;
SAFE_FREE(term_c);
goto error;
}
@@ -1453,6 +1470,7 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel,
if (strcmp(request, "x11-req") == 0) {
ssh_string auth_protocol = NULL;
ssh_string auth_cookie = NULL;
uint32_t screen_number;
buffer_get_u8(packet, &msg->channel_request.x11_single_connection);
@@ -1480,7 +1498,8 @@ int ssh_message_handle_channel_request(ssh_session session, ssh_channel channel,
ssh_string_free(auth_protocol);
ssh_string_free(auth_cookie);
buffer_get_u32(packet, &msg->channel_request.x11_screen_number);
buffer_get_u32(packet, &screen_number);
msg->channel_request.x11_screen_number = ntohl(screen_number);
goto end;
}

View File

@@ -4,7 +4,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2003-2009 by Aris Adamantiadis
* Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2008-2009 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -697,7 +697,6 @@ char *ssh_path_expand_tilde(const char *d) {
}
char *ssh_path_expand_escape(ssh_session session, const char *s) {
#define MAX_BUF_SIZE 4096
char host[NI_MAXHOST];
char buf[MAX_BUF_SIZE];
char *r, *x = NULL;

View File

@@ -4,7 +4,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
* Copyright (c) 2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -367,6 +367,18 @@ int ssh_options_set_algo(ssh_session session, int algo,
* Set the command to be executed in order to connect to
* server (const char *).
*
* - SSH_OPTIONS_GSSAPI_SERVER_IDENTITY
* Set it to specify the GSSAPI server identity that libssh
* should expect when connecting to the server (const char *).
*
* - SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY
* Set it to specify the GSSAPI client identity that libssh
* should expect when connecting to the server (const char *).
*
* - SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS
* Set it to specify that GSSAPI should delegate credentials
* to the server (int, 0 = false).
*
* @param value The value to set. This is a generic pointer and the
* datatype which is used should be set according to the
* type set.
@@ -500,7 +512,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
}
session->opts.username = q;
} else if (v[0] == '\0') {
ssh_set_error_oom(session);
ssh_set_error_invalid(session);
return -1;
} else { /* username provided */
session->opts.username = strdup(value);
@@ -519,7 +531,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
return -1;
}
} else if (v[0] == '\0') {
ssh_set_error_oom(session);
ssh_set_error_invalid(session);
return -1;
} else {
session->opts.sshdir = ssh_path_expand_tilde(v);
@@ -661,6 +673,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
}
session->common.log_verbosity = i & 0xffff;
ssh_set_log_level(i & 0xffff);
}
break;
case SSH_OPTIONS_CIPHERS_C_S:
@@ -792,6 +805,45 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
}
}
break;
case SSH_OPTIONS_GSSAPI_SERVER_IDENTITY:
v = value;
if (v == NULL || v[0] == '\0') {
ssh_set_error_invalid(session);
return -1;
} else {
SAFE_FREE(session->opts.gss_server_identity);
session->opts.gss_server_identity = strdup(v);
if (session->opts.gss_server_identity == NULL) {
ssh_set_error_oom(session);
return -1;
}
}
break;
case SSH_OPTIONS_GSSAPI_CLIENT_IDENTITY:
v = value;
if (v == NULL || v[0] == '\0') {
ssh_set_error_invalid(session);
return -1;
} else {
SAFE_FREE(session->opts.gss_client_identity);
session->opts.gss_client_identity = strdup(v);
if (session->opts.gss_client_identity == NULL) {
ssh_set_error_oom(session);
return -1;
}
}
break;
case SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS:
if (value == NULL) {
ssh_set_error_invalid(session);
return -1;
} else {
int x = *(int *)value;
session->opts.gss_delegate_creds = (x & 0xff);
}
break;
default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return -1;
@@ -819,11 +871,14 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
if (session == NULL) {
return -1;
}
if (!session->opts.port) {
ssh_set_error_invalid(session);
return -1;
if (session->opts.port == 0) {
*port_target = 22;
return 0;
}
*port_target = session->opts.port;
return 0;
}
@@ -856,6 +911,11 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
* It may include "%s" which will be replaced by the
* user home directory.
*
* - SSH_OPTIONS_PROXYCOMMAND:
* Get the proxycommand necessary to log into the
* remote host. When not explicitly set, it will be read
* from the ~/.ssh/config file.
*
* @param value The value to get into. As a char**, space will be
* allocated by the function for the value, it is
* your responsibility to free the memory using
@@ -894,6 +954,10 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
src = ssh_iterator_value(char *, it);
break;
}
case SSH_OPTIONS_PROXYCOMMAND: {
src = session->opts.ProxyCommand;
break;
}
default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return SSH_ERROR;
@@ -1242,65 +1306,89 @@ static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo,
return 0;
}
static int ssh_bind_set_key(ssh_bind sshbind, char **key_loc,
const void *value) {
if (value == NULL) {
ssh_set_error_invalid(sshbind);
return -1;
} else {
SAFE_FREE(*key_loc);
*key_loc = strdup(value);
if (*key_loc == NULL) {
ssh_set_error_oom(sshbind);
return -1;
}
}
return 0;
}
/**
* @brief This function can set all possible ssh bind options.
* @brief Set options for an SSH server bind.
*
* @param session An allocated ssh option structure.
* @param sshbind The ssh server bind to configure.
*
* @param type The option type to set. This could be one of the
* @param type The option type to set. This should be one of the
* following:
*
* SSH_BIND_OPTIONS_LOG_VERBOSITY:
* Set the session logging verbosity (integer).
*
* The verbosity of the messages. Every log smaller or
* equal to verbosity will be shown.
* SSH_LOG_NOLOG: No logging
* SSH_LOG_RARE: Rare conditions or warnings
* SSH_LOG_ENTRY: API-accessible entrypoints
* SSH_LOG_PACKET: Packet id and size
* SSH_LOG_FUNCTIONS: Function entering and leaving
*
* SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
* Set the session logging verbosity (integer).
*
* The verbosity of the messages. Every log smaller or
* equal to verbosity will be shown.
* SSH_LOG_NOLOG: No logging
* SSH_LOG_RARE: Rare conditions or warnings
* SSH_LOG_ENTRY: API-accessible entrypoints
* SSH_LOG_PACKET: Packet id and size
* SSH_LOG_FUNCTIONS: Function entering and leaving
*
* SSH_BIND_OPTIONS_BINDADDR:
* Set the bind address.
*
* SSH_BIND_OPTIONS_BINDPORT:
* Set the bind port, default is 22.
*
* SSH_BIND_OPTIONS_HOSTKEY:
* - SSH_BIND_OPTIONS_HOSTKEY:
* Set the server public key type: ssh-rsa or ssh-dss
* (string).
* (const char *).
*
* SSH_BIND_OPTIONS_DSAKEY:
* Set the path to the dsa ssh host key (string).
* - SSH_BIND_OPTIONS_BINDADDR:
* Set the IP address to bind (const char *).
*
* SSH_BIND_OPTIONS_RSAKEY:
* Set the path to the ssh host rsa key (string).
* - SSH_BIND_OPTIONS_BINDPORT:
* Set the port to bind (unsigned int *).
*
* SSH_BIND_OPTIONS_BANNER:
* Set the server banner sent to clients (string).
* - SSH_BIND_OPTIONS_BINDPORT_STR:
* Set the port to bind (const char *).
*
* - SSH_BIND_OPTIONS_LOG_VERBOSITY:
* Set the session logging verbosity (int *).
* The logging verbosity should have one of the
* following values, which are listed in order
* of increasing verbosity. Every log message
* with verbosity less than or equal to the
* logging verbosity will be shown.
* - SSH_LOG_NOLOG: No logging
* - SSH_LOG_RARE: Rare conditions or warnings
* - SSH_LOG_ENTRY: API-accessible entrypoints
* - SSH_LOG_PACKET: Packet id and size
* - SSH_LOG_FUNCTIONS: Function entering and leaving
*
* - SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
* Set the session logging verbosity via a
* string that will be converted to a numerical
* value (e.g. "3") and interpreted according
* to the values of
* SSH_BIND_OPTIONS_LOG_VERBOSITY above (const
* char *).
*
* - SSH_BIND_OPTIONS_DSAKEY:
* Set the path to the ssh host dsa key, SSHv2
* only (const char *).
*
* - SSH_BIND_OPTIONS_RSAKEY:
* Set the path to the ssh host rsa key, SSHv2
* only (const char *).
*
* - SSH_BIND_OPTIONS_ECDSAKEY:
* Set the path to the ssh host ecdsa key,
* SSHv2 only (const char *).
*
* - SSH_BIND_OPTIONS_BANNER:
* Set the server banner sent to clients (const char *).
*
* @param value The value to set. This is a generic pointer and the
* datatype which is used should be set according to the
* type set.
* datatype which should be used is described at the
* corresponding value of type above.
*
* @return 0 on success, < 0 on error.
* @return 0 on success, < 0 on error, invalid option, or parameter.
*/
int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
const void *value) {
char *p, *q;
int i;
int i, rc;
if (sshbind == NULL) {
return -1;
@@ -1367,7 +1455,7 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
break;
case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
if (value == NULL) {
sshbind->common.log_verbosity = 0;
ssh_set_log_level(0);
} else {
q = strdup(value);
if (q == NULL) {
@@ -1380,35 +1468,27 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
}
SAFE_FREE(q);
sshbind->common.log_verbosity = i & 0xffff;
ssh_set_log_level(i & 0xffff);
}
break;
case SSH_BIND_OPTIONS_DSAKEY:
if (value == NULL) {
ssh_set_error_invalid(sshbind);
return -1;
} else {
SAFE_FREE(sshbind->dsakey);
sshbind->dsakey = strdup(value);
if (sshbind->dsakey == NULL) {
ssh_set_error_oom(sshbind);
return -1;
rc = ssh_bind_set_key(sshbind, &sshbind->dsakey, value);
if (rc < 0) {
return -1;
}
}
break;
break;
case SSH_BIND_OPTIONS_RSAKEY:
if (value == NULL) {
ssh_set_error_invalid(sshbind);
return -1;
} else {
SAFE_FREE(sshbind->rsakey);
sshbind->rsakey = strdup(value);
if (sshbind->rsakey == NULL) {
ssh_set_error_oom(sshbind);
return -1;
rc = ssh_bind_set_key(sshbind, &sshbind->rsakey, value);
if (rc < 0) {
return -1;
}
}
break;
break;
case SSH_BIND_OPTIONS_ECDSAKEY:
rc = ssh_bind_set_key(sshbind, &sshbind->ecdsakey, value);
if (rc < 0) {
return -1;
}
break;
case SSH_BIND_OPTIONS_BANNER:
if (value == NULL) {
ssh_set_error_invalid(sshbind);

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
* Copyright (c) 2003-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -141,174 +141,217 @@ static ssh_packet_callback default_packet_handlers[]= {
* @len length of data received. It might not be enough for a complete packet
* @returns number of bytes read and processed.
*/
int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user){
ssh_session session=(ssh_session) user;
unsigned int blocksize = (session->current_crypto ?
session->current_crypto->in_cipher->blocksize : 8);
int current_macsize = session->current_crypto ? MACSIZE : 0;
unsigned char mac[30] = {0};
char buffer[16] = {0};
const void *packet = NULL;
int to_be_read;
int rc;
uint32_t len, compsize, payloadsize;
uint8_t padding;
size_t processed=0; /* number of byte processed from the callback */
int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
{
ssh_session session= (ssh_session) user;
unsigned int blocksize = (session->current_crypto ?
session->current_crypto->in_cipher->blocksize : 8);
int current_macsize = session->current_crypto ? MACSIZE : 0;
unsigned char mac[30] = {0};
char buffer[16] = {0};
const uint8_t *packet;
int to_be_read;
int rc;
uint32_t len, compsize, payloadsize;
uint8_t padding;
size_t processed = 0; /* number of byte processed from the callback */
if (data == NULL) {
goto error;
}
if (session->session_state == SSH_SESSION_STATE_ERROR)
goto error;
switch(session->packet_state) {
case PACKET_STATE_INIT:
if(receivedlen < blocksize){
/* We didn't receive enough data to read at least one block size, give up */
return 0;
}
memset(&session->in_packet, 0, sizeof(PACKET));
if (session->in_buffer) {
if (buffer_reinit(session->in_buffer) < 0) {
goto error;
}
} else {
session->in_buffer = ssh_buffer_new();
if (session->in_buffer == NULL) {
goto error;
}
}
memcpy(buffer,data,blocksize);
processed += blocksize;
len = packet_decrypt_len(session, buffer);
if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) {
if (data == NULL) {
goto error;
}
}
if(len > MAX_PACKET_LEN) {
ssh_set_error(session, SSH_FATAL,
"read_packet(): Packet len too high(%u %.4x)", len, len);
if (session->session_state == SSH_SESSION_STATE_ERROR) {
goto error;
}
}
to_be_read = len - blocksize + sizeof(uint32_t);
if (to_be_read < 0) {
/* remote sshd sends invalid sizes? */
ssh_set_error(session, SSH_FATAL,
"given numbers of bytes left to be read < 0 (%d)!", to_be_read);
goto error;
}
switch(session->packet_state) {
case PACKET_STATE_INIT:
if (receivedlen < blocksize) {
/*
* We didn't receive enough data to read at least one
* block size, give up
*/
return 0;
}
/* saves the status of the current operations */
session->in_packet.len = len;
session->packet_state = PACKET_STATE_SIZEREAD;
/* FALL TROUGH */
case PACKET_STATE_SIZEREAD:
len = session->in_packet.len;
to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
/* if to_be_read is zero, the whole packet was blocksize bytes. */
if (to_be_read != 0) {
if(receivedlen - processed < (unsigned int)to_be_read){
/* give up, not enough data in buffer */
SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len);
return processed;
}
memset(&session->in_packet, 0, sizeof(PACKET));
packet = ((unsigned char *)data) + processed;
// ssh_socket_read(session->socket,packet,to_be_read-current_macsize);
if (session->in_buffer) {
rc = buffer_reinit(session->in_buffer);
if (rc < 0) {
goto error;
}
} else {
session->in_buffer = ssh_buffer_new();
if (session->in_buffer == NULL) {
goto error;
}
}
if (buffer_add_data(session->in_buffer, packet,
to_be_read - current_macsize) < 0) {
goto error;
}
processed += to_be_read - current_macsize;
}
memcpy(buffer, data, blocksize);
processed += blocksize;
len = packet_decrypt_len(session, buffer);
if (session->current_crypto) {
/*
* decrypt the rest of the packet (blocksize bytes already
* have been decrypted)
*/
if (packet_decrypt(session,
((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize),
buffer_get_rest_len(session->in_buffer) - blocksize) < 0) {
ssh_set_error(session, SSH_FATAL, "Decrypt error");
goto error;
}
/* copy the last part from the incoming buffer */
memcpy(mac,(unsigned char *)packet + to_be_read - current_macsize, MACSIZE);
rc = buffer_add_data(session->in_buffer, buffer, blocksize);
if (rc < 0) {
goto error;
}
if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
ssh_set_error(session, SSH_FATAL, "HMAC error");
goto error;
}
processed += current_macsize;
}
if (len > MAX_PACKET_LEN) {
ssh_set_error(session,
SSH_FATAL,
"read_packet(): Packet len too high(%u %.4x)",
len, len);
goto error;
}
/* skip the size field which has been processed before */
buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
to_be_read = len - blocksize + sizeof(uint32_t);
if (to_be_read < 0) {
/* remote sshd sends invalid sizes? */
ssh_set_error(session,
SSH_FATAL,
"Given numbers of bytes left to be read < 0 (%d)!",
to_be_read);
goto error;
}
if (buffer_get_u8(session->in_buffer, &padding) == 0) {
ssh_set_error(session, SSH_FATAL, "Packet too short to read padding");
goto error;
}
/* Saves the status of the current operations */
session->in_packet.len = len;
session->packet_state = PACKET_STATE_SIZEREAD;
/* FALL TROUGH */
case PACKET_STATE_SIZEREAD:
len = session->in_packet.len;
to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize;
/* if to_be_read is zero, the whole packet was blocksize bytes. */
if (to_be_read != 0) {
if (receivedlen - processed < (unsigned int)to_be_read) {
/* give up, not enough data in buffer */
SSH_LOG(SSH_LOG_PACKET,"packet: partial packet (read len) [len=%d]",len);
return processed;
}
if (padding > buffer_get_rest_len(session->in_buffer)) {
ssh_set_error(session, SSH_FATAL,
"Invalid padding: %d (%d left)",
padding,
buffer_get_rest_len(session->in_buffer));
goto error;
}
buffer_pass_bytes_end(session->in_buffer, padding);
compsize = buffer_get_rest_len(session->in_buffer);
packet = ((uint8_t*)data) + processed;
#if 0
ssh_socket_read(session->socket,
packet,
to_be_read - current_macsize);
#endif
rc = buffer_add_data(session->in_buffer,
packet,
to_be_read - current_macsize);
if (rc < 0) {
goto error;
}
processed += to_be_read - current_macsize;
}
if (session->current_crypto) {
/*
* Decrypt the rest of the packet (blocksize bytes already
* have been decrypted)
*/
uint32_t buffer_len = buffer_get_rest_len(session->in_buffer);
/* The following check avoids decrypting zero bytes */
if (buffer_len > blocksize) {
uint8_t *payload = ((uint8_t*)buffer_get_rest(session->in_buffer) + blocksize);
uint32_t plen = buffer_len - blocksize;
rc = packet_decrypt(session, payload, plen);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Decrypt error");
goto error;
}
}
/* copy the last part from the incoming buffer */
packet = ((uint8_t *)data) + processed;
memcpy(mac, packet, MACSIZE);
rc = packet_hmac_verify(session, session->in_buffer, mac);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "HMAC error");
goto error;
}
processed += current_macsize;
}
/* skip the size field which has been processed before */
buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
rc = buffer_get_u8(session->in_buffer, &padding);
if (rc == 0) {
ssh_set_error(session,
SSH_FATAL,
"Packet too short to read padding");
goto error;
}
if (padding > buffer_get_rest_len(session->in_buffer)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid padding: %d (%d left)",
padding,
buffer_get_rest_len(session->in_buffer));
goto error;
}
buffer_pass_bytes_end(session->in_buffer, padding);
compsize = buffer_get_rest_len(session->in_buffer);
#ifdef WITH_ZLIB
if (session->current_crypto
&& session->current_crypto->do_compress_in
&& buffer_get_rest_len(session->in_buffer)) {
if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
goto error;
}
}
if (session->current_crypto
&& session->current_crypto->do_compress_in
&& buffer_get_rest_len(session->in_buffer) > 0) {
rc = decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN);
if (rc < 0) {
goto error;
}
}
#endif /* WITH_ZLIB */
payloadsize=buffer_get_rest_len(session->in_buffer);
session->recv_seq++;
/* We don't want to rewrite a new packet while still executing the packet callbacks */
session->packet_state = PACKET_STATE_PROCESSING;
ssh_packet_parse_type(session);
SSH_LOG(SSH_LOG_PACKET,
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
session->in_packet.type, len, padding, compsize, payloadsize);
/* execute callbacks */
ssh_packet_process(session, session->in_packet.type);
session->packet_state = PACKET_STATE_INIT;
if(processed < receivedlen){
/* Handle a potential packet left in socket buffer */
SSH_LOG(SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
receivedlen-processed);
rc = ssh_packet_socket_callback(((unsigned char *)data) + processed,
receivedlen - processed,user);
processed += rc;
}
payloadsize = buffer_get_rest_len(session->in_buffer);
session->recv_seq++;
return processed;
case PACKET_STATE_PROCESSING:
SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying.");
return 0;
}
/*
* We don't want to rewrite a new packet while still executing the
* packet callbacks
*/
session->packet_state = PACKET_STATE_PROCESSING;
ssh_packet_parse_type(session);
SSH_LOG(SSH_LOG_PACKET,
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
session->in_packet.type, len, padding, compsize, payloadsize);
ssh_set_error(session, SSH_FATAL,
"Invalid state into packet_read2(): %d",
session->packet_state);
/* Execute callbacks */
ssh_packet_process(session, session->in_packet.type);
session->packet_state = PACKET_STATE_INIT;
if (processed < receivedlen) {
/* Handle a potential packet left in socket buffer */
SSH_LOG(SSH_LOG_PACKET,
"Processing %" PRIdS " bytes left in socket buffer",
receivedlen-processed);
packet = ((uint8_t*)data) + processed;
rc = ssh_packet_socket_callback(packet, receivedlen - processed,user);
processed += rc;
}
return processed;
case PACKET_STATE_PROCESSING:
SSH_LOG(SSH_LOG_RARE, "Nested packet processing. Delaying.");
return 0;
}
ssh_set_error(session,
SSH_FATAL,
"Invalid state into packet_read2(): %d",
session->packet_state);
error:
session->session_state= SSH_SESSION_STATE_ERROR;
session->session_state= SSH_SESSION_STATE_ERROR;
return processed;
return processed;
}
void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){
@@ -461,11 +504,13 @@ static int packet_send2(ssh_session session) {
session->current_crypto->out_cipher->blocksize : 8);
uint32_t currentlen = buffer_get_rest_len(session->out_buffer);
unsigned char *hmac = NULL;
char padstring[32] = {0};
char padstring[32] = { 0 };
int rc = SSH_ERROR;
uint32_t finallen,payloadsize,compsize;
uint8_t padding;
uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 };
payloadsize = currentlen;
#ifdef WITH_ZLIB
if (session->current_crypto
@@ -485,19 +530,18 @@ static int packet_send2(ssh_session session) {
if (session->current_crypto) {
ssh_get_random(padstring, padding, 0);
} else {
memset(padstring,0,padding);
}
finallen = htonl(currentlen + padding + 1);
if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) {
memcpy(&header[0], &finallen, sizeof(finallen));
header[sizeof(finallen)] = padding;
rc = buffer_prepend_data(session->out_buffer, &header, sizeof(header));
if (rc < 0) {
goto error;
}
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
goto error;
}
if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
rc = buffer_add_data(session->out_buffer, padstring, padding);
if (rc < 0) {
goto error;
}
#ifdef WITH_PCAP

View File

@@ -106,7 +106,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user
size_t processed=0;
uint32_t padding;
uint32_t crc;
uint32_t len;
uint32_t len, buffer_len;
ssh_session session=(ssh_session)user;
switch (session->packet_state){
@@ -168,11 +168,16 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user
* We decrypt everything, missing the lenght part (which was
* previously read, unencrypted, and is not part of the buffer
*/
if (packet_decrypt(session,
ssh_buffer_get_begin(session->in_buffer),
ssh_buffer_get_len(session->in_buffer)) < 0) {
ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
goto error;
buffer_len = ssh_buffer_get_len(session->in_buffer);
if (buffer_len > 0) {
int rc;
rc = packet_decrypt(session,
ssh_buffer_get_begin(session->in_buffer),
buffer_len);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Packet decrypt error");
goto error;
}
}
}
#ifdef DEBUG_CRYPTO
@@ -300,6 +305,8 @@ int packet_send1(ssh_session session) {
ssh_buffer_get_len(session->out_buffer));
#endif
/* session->out_buffer should have more than sizeof(uint32_t) bytes
in it as required for packet_encrypt */
packet_encrypt(session, (unsigned char *)ssh_buffer_get_begin(session->out_buffer) + sizeof(uint32_t),
ssh_buffer_get_len(session->out_buffer) - sizeof(uint32_t));

View File

@@ -35,6 +35,7 @@
#include "libssh/session.h"
#include "libssh/socket.h"
#include "libssh/ssh2.h"
#include "libssh/curve25519.h"
/**
* @internal
@@ -42,29 +43,35 @@
* @brief Handle a SSH_DISCONNECT packet.
*/
SSH_PACKET_CALLBACK(ssh_packet_disconnect_callback){
uint32_t code;
char *error=NULL;
ssh_string error_s;
(void)user;
(void)type;
buffer_get_u32(packet, &code);
int rc;
uint32_t code = 0;
char *error = NULL;
ssh_string error_s;
(void)user;
(void)type;
rc = buffer_get_u32(packet, &code);
if (rc != 0) {
code = ntohl(code);
}
error_s = buffer_get_ssh_string(packet);
if (error_s != NULL) {
error = ssh_string_to_char(error_s);
ssh_string_free(error_s);
}
SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",code,
error != NULL ? error : "no error");
SSH_LOG(SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT %d:%s",
code, error != NULL ? error : "no error");
ssh_set_error(session, SSH_FATAL,
"Received SSH_MSG_DISCONNECT: %d:%s",code,
error != NULL ? error : "no error");
"Received SSH_MSG_DISCONNECT: %d:%s",
code, error != NULL ? error : "no error");
SAFE_FREE(error);
ssh_socket_close(session->socket);
session->alive = 0;
session->session_state= SSH_SESSION_STATE_ERROR;
/* TODO: handle a graceful disconnect */
return SSH_PACKET_USED;
session->session_state = SSH_SESSION_STATE_ERROR;
/* TODO: handle a graceful disconnect */
return SSH_PACKET_USED;
}
/**
@@ -87,7 +94,7 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
(void)type;
(void)user;
SSH_LOG(SSH_LOG_PROTOCOL,"Received SSH_KEXDH_REPLY");
if(session->session_state!= SSH_SESSION_STATE_DH &&
if (session->session_state != SSH_SESSION_STATE_DH ||
session->dh_handshake_state != DH_STATE_INIT_SENT){
ssh_set_error(session,SSH_FATAL,"ssh_packet_dh_reply called in wrong state : %d:%d",
session->session_state,session->dh_handshake_state);
@@ -102,6 +109,11 @@ SSH_PACKET_CALLBACK(ssh_packet_dh_reply){
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_client_ecdh_reply(session, packet);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_reply(session, packet);
break;
#endif
default:
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_dh_reply");
@@ -123,12 +135,16 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
(void)user;
(void)type;
SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_NEWKEYS");
if(session->session_state!= SSH_SESSION_STATE_DH &&
session->dh_handshake_state != DH_STATE_NEWKEYS_SENT){
ssh_set_error(session,SSH_FATAL,"ssh_packet_newkeys called in wrong state : %d:%d",
session->session_state,session->dh_handshake_state);
goto error;
if (session->session_state != SSH_SESSION_STATE_DH ||
session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) {
ssh_set_error(session,
SSH_FATAL,
"ssh_packet_newkeys called in wrong state : %d:%d",
session->session_state,session->dh_handshake_state);
goto error;
}
if(session->server){
/* server things are done in server.c */
session->dh_handshake_state=DH_STATE_FINISHED;

View File

@@ -22,6 +22,7 @@
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -59,6 +60,9 @@ uint32_t packet_decrypt_len(ssh_session session, char *crypted){
int packet_decrypt(ssh_session session, void *data,uint32_t len) {
struct ssh_cipher_struct *crypto = session->current_crypto->in_cipher;
char *out = NULL;
assert(len);
if(len % session->current_crypto->in_cipher->blocksize != 0){
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
return SSH_ERROR;
@@ -89,6 +93,8 @@ unsigned char *packet_encrypt(ssh_session session, void *data, uint32_t len) {
unsigned int finallen;
uint32_t seq;
assert(len);
if (!session->current_crypto) {
return NULL; /* nothing to do here */
}

231
src/pki.c
View File

@@ -3,7 +3,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2010 by Aris Adamantiadis
* Copyright (c) 2011-2012 Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2011-2013 Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -98,6 +98,25 @@ enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey) {
return SSH_KEYTYPE_UNKNOWN;
}
/**
* @brief returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
*
* @param[in] key the ssh_key whose ECDSA name to get
*
* @returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
*
* @returns "unknown" if the ECDSA key name is not known
*/
const char *ssh_pki_key_ecdsa_name(const ssh_key key)
{
#ifdef HAVE_OPENSSL_ECC /* FIXME Better ECC check needed */
return pki_key_ecdsa_nid_to_name(key->ecdsa_nid);
#else
(void) key; /* unused */
return NULL;
#endif
}
/**
* @brief creates a new empty SSH key
* @returns an empty ssh_key handle, or NULL on error.
@@ -331,6 +350,10 @@ void ssh_signature_free(ssh_signature sig)
#endif
break;
case SSH_KEYTYPE_ECDSA:
#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_ECC)
ECDSA_SIG_free(sig->ecdsa_sig);
#endif
break;
case SSH_KEYTYPE_UNKNOWN:
break;
}
@@ -349,8 +372,8 @@ void ssh_signature_free(ssh_signature sig)
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_ERROR in case of error, SSH_OK otherwise.
*
@@ -397,8 +420,8 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[out] pkey A pointer to store the ssh_key. You need to free the
* key.
* @param[out] pkey A pointer to store the allocated ssh_key. You need to
* free the key.
*
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
* denied, SSH_ERROR otherwise.
@@ -476,6 +499,65 @@ int ssh_pki_import_privkey_file(const char *filename,
return SSH_OK;
}
/**
* @brief Export a private key to a pam file on disk.
*
* @param[in] privkey The private key to export.
*
* @param[in] passphrase The passphrase to use to encrypt the key with or
* NULL. An empty string means no passphrase.
*
* @param[in] auth_fn An auth function you may want to use or NULL.
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[in] filename The path where to store the pem file.
*
* @return SSH_OK on success, SSH_ERROR on error.
*/
int ssh_pki_export_privkey_file(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
const char *filename)
{
ssh_string blob;
FILE *fp;
int rc;
if (privkey == NULL || !ssh_key_is_private(privkey)) {
return SSH_ERROR;
}
fp = fopen(filename, "wb");
if (fp == NULL) {
SSH_LOG(SSH_LOG_FUNCTIONS, "Error opening %s: %s",
filename, strerror(errno));
return SSH_EOF;
}
blob = pki_private_key_to_pem(privkey,
passphrase,
auth_fn,
auth_data);
if (blob == NULL) {
fclose(fp);
return -1;
}
rc = fwrite(ssh_string_data(blob), ssh_string_len(blob), 1, fp);
ssh_string_free(blob);
if (rc != 1 || ferror(fp)) {
fclose(fp);
unlink(filename);
return SSH_ERROR;
}
fclose(fp);
return SSH_OK;
}
/* temporary function to migrate seemlessly to ssh_key */
ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key) {
ssh_public_key pub;
@@ -661,6 +743,9 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
if (rc < 0) {
goto fail;
}
/* Update key type */
key->type_c = ssh_pki_key_ecdsa_name(key);
}
break;
#endif
@@ -684,8 +769,8 @@ fail:
*
* @param[in] type The type of the key to format.
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
@@ -728,8 +813,8 @@ int ssh_pki_import_pubkey_base64(const char *b64_key,
* @param[in] key_blob The key blob to import as specified in RFC 4253 section
* 6.6 "Public Key Algorithms".
*
* @param[out] pkey A pointer where the key can be stored. You need
* to free the memory.
* @param[out] pkey A pointer where the allocated key can be stored. You
* need to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
@@ -789,8 +874,8 @@ fail:
*
* @param[in] filename The path to the public key.
*
* @param[out] pkey A pointer to store the public key. You need to free the
* memory.
* @param[out] pkey A pointer to store the allocated public key. You need to
* free the memory.
*
* @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
* denied, SSH_ERROR otherwise.
@@ -875,17 +960,20 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
/**
* @brief Generates a keypair.
*
* @param[in] type Type of key to create
*
* @param[in] parameter Parameter to the creation of key:
* rsa : length of the key in bits (e.g. 1024, 2048, 4096)
* dsa : length of the key in bits (e.g. 1024, 2048, 3072)
* ecdsa : bits of the key (e.g. 256, 384, 512)
* @param[out] pkey A pointer to store the private key. You need to free the
* memory.
* @param[out] pkey A pointer to store the allocated private key. You need
* to free the memory.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
* @warning Generating a key pair may take some time.
*/
int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
ssh_key *pkey){
int rc;
@@ -914,8 +1002,12 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
rc = pki_key_generate_ecdsa(key, parameter);
if(rc == SSH_ERROR)
if (rc == SSH_ERROR) {
goto error;
}
/* Update key type */
key->type_c = ssh_pki_key_ecdsa_name(key);
break;
#endif
case SSH_KEYTYPE_UNKNOWN:
@@ -1000,7 +1092,8 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
*
* @param[in] key The key to hash
*
* @param[out] b64_key A pointer to store the base64 hased key.
* @param[out] b64_key A pointer to store the allocated base64 hashed key. You
* need to free the buffer.
*
* @return SSH_OK on success, SSH_ERROR on error.
*
@@ -1114,7 +1207,7 @@ int ssh_pki_export_signature_blob(const ssh_signature sig,
return SSH_ERROR;
}
str = ssh_string_from_char(ssh_key_type_to_char(sig->type));
str = ssh_string_from_char(sig->type_c);
if (str == NULL) {
ssh_buffer_free(buf);
return SSH_ERROR;
@@ -1232,6 +1325,11 @@ int ssh_pki_signature_verify_blob(ssh_session session,
evp(key->ecdsa_nid, digest, dlen, ehash, &elen);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Hash to be verified with ecdsa",
ehash, elen);
#endif
rc = pki_signature_verify(session,
sig,
key,
@@ -1267,11 +1365,9 @@ ssh_string ssh_pki_do_sign(ssh_session session,
struct ssh_crypto_struct *crypto =
session->current_crypto ? session->current_crypto :
session->next_crypto;
unsigned char hash[SHA_DIGEST_LEN] = {0};
ssh_signature sig;
ssh_signature sig = NULL;
ssh_string sig_blob;
ssh_string session_id;
SHACTX ctx;
int rc;
if (privkey == NULL || !ssh_key_is_private(privkey)) {
@@ -1283,24 +1379,50 @@ ssh_string ssh_pki_do_sign(ssh_session session,
return NULL;
}
ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);
/* TODO: change when supporting ECDSA keys */
ctx = sha1_init();
if (ctx == NULL) {
ssh_string_free(session_id);
return NULL;
}
sha1_update(ctx, session_id, ssh_string_len(session_id) + 4);
ssh_string_free(session_id);
if (privkey->type == SSH_KEYTYPE_ECDSA) {
#ifdef HAVE_ECC
unsigned char ehash[EVP_DIGEST_LEN] = {0};
uint32_t elen;
EVPCTX ctx;
sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
sha1_final(hash, ctx);
ctx = evp_init(privkey->ecdsa_nid);
if (ctx == NULL) {
ssh_string_free(session_id);
return NULL;
}
evp_update(ctx, session_id, ssh_string_len(session_id) + 4);
evp_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
evp_final(ctx, ehash, &elen);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
ssh_print_hexa("Hash being signed", ehash, elen);
#endif
sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN);
sig = pki_do_sign(privkey, ehash, elen);
#endif
} else {
unsigned char hash[SHA_DIGEST_LEN] = {0};
SHACTX ctx;
ctx = sha1_init();
if (ctx == NULL) {
ssh_string_free(session_id);
return NULL;
}
sha1_update(ctx, session_id, ssh_string_len(session_id) + 4);
sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
sha1_final(hash, ctx);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
#endif
sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN);
}
ssh_string_free(session_id);
if (sig == NULL) {
return NULL;
}
@@ -1371,10 +1493,8 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
const ssh_key privkey)
{
struct ssh_crypto_struct *crypto;
unsigned char hash[SHA_DIGEST_LEN] = {0};
ssh_signature sig;
ssh_string sig_blob;
SHACTX ctx;
int rc;
if (session == NULL || privkey == NULL || !ssh_key_is_private(privkey)) {
@@ -1383,24 +1503,47 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
crypto = session->next_crypto ? session->next_crypto :
session->current_crypto;
ctx = sha1_init();
if (ctx == NULL) {
return NULL;
}
if (crypto->secret_hash == NULL){
ssh_set_error(session,SSH_FATAL,"Missing secret_hash");
return NULL;
}
sha1_update(ctx, crypto->secret_hash, crypto->digest_len);
sha1_final(hash, ctx);
if (privkey->type == SSH_KEYTYPE_ECDSA) {
#ifdef HAVE_ECC
unsigned char ehash[EVP_DIGEST_LEN] = {0};
uint32_t elen;
evp(privkey->ecdsa_nid, crypto->secret_hash, crypto->digest_len,
ehash, &elen);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
ssh_print_hexa("Hash being signed", ehash, elen);
#endif
sig = pki_do_sign_sessionid(privkey, hash, SHA_DIGEST_LEN);
if (sig == NULL) {
return NULL;
sig = pki_do_sign_sessionid(privkey, ehash, elen);
if (sig == NULL) {
return NULL;
}
#endif
} else {
unsigned char hash[SHA_DIGEST_LEN] = {0};
SHACTX ctx;
ctx = sha1_init();
if (ctx == NULL) {
return NULL;
}
sha1_update(ctx, crypto->secret_hash, crypto->digest_len);
sha1_final(hash, ctx);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
#endif
sig = pki_do_sign_sessionid(privkey, hash, SHA_DIGEST_LEN);
if (sig == NULL) {
return NULL;
}
}
rc = ssh_pki_export_signature_blob(sig, &sig_blob);

View File

@@ -4,7 +4,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2003-2009 by Aris Adamantiadis
* Copyright (c) 2009-2012 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -25,6 +25,8 @@
#ifndef _PKI_CRYPTO_H
#define _PKI_CRYPTO_H
#include "libssh/priv.h"
#include <openssl/pem.h>
#include <openssl/dsa.h>
#include <openssl/err.h>
@@ -37,8 +39,6 @@
#include <openssl/ecdsa.h>
#endif
#include "libssh/priv.h"
#include "libssh/libssh.h"
#include "libssh/buffer.h"
#include "libssh/session.h"
@@ -89,7 +89,7 @@ static int pki_key_ecdsa_to_nid(EC_KEY *k)
return -1;
}
static const char *pki_key_ecdsa_nid_to_name(int nid)
const char *pki_key_ecdsa_nid_to_name(int nid)
{
switch (nid) {
case NID_X9_62_prime256v1:
@@ -200,9 +200,11 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
return -1;
}
/* EC_KEY_set_public_key duplicates p */
ok = EC_KEY_set_public_key(key->ecdsa, p);
EC_POINT_free(p);
if (!ok) {
EC_POINT_free(p);
return -1;
}
return 0;
@@ -343,13 +345,13 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_OPENSSL_ECC
new->ecdsa_nid = key->ecdsa_nid;
/* privkey -> pubkey */
if (demote && ssh_key_is_private(key)) {
const EC_POINT *p;
int ok;
new->ecdsa_nid = key->ecdsa_nid;
new->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
if (new->ecdsa == NULL) {
goto fail;
@@ -381,10 +383,20 @@ fail:
}
int pki_key_generate_rsa(ssh_key key, int parameter){
key->rsa = RSA_generate_key(parameter, 65537, NULL, NULL);
if(key->rsa == NULL)
return SSH_ERROR;
return SSH_OK;
BIGNUM *e;
int rc;
e = BN_new();
key->rsa = RSA_new();
BN_set_word(e, 65537);
rc = RSA_generate_key_ex(key->rsa, parameter, e, NULL);
BN_free(e);
if (rc == -1 || key->rsa == NULL)
return SSH_ERROR;
return SSH_OK;
}
int pki_key_generate_dss(ssh_key key, int parameter){
@@ -528,6 +540,124 @@ int pki_key_compare(const ssh_key k1,
return 0;
}
ssh_string pki_private_key_to_pem(const ssh_key key,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data)
{
ssh_string blob;
BUF_MEM *buf;
BIO *mem;
int rc;
/* needed for openssl initialization */
if (ssh_init() < 0) {
return NULL;
}
mem = BIO_new(BIO_s_mem());
if (mem == NULL) {
return NULL;
}
switch (key->type) {
case SSH_KEYTYPE_DSS:
if (passphrase == NULL) {
struct pem_get_password_struct pgp = { auth_fn, auth_data };
rc = PEM_write_bio_DSAPrivateKey(mem,
key->dsa,
NULL, /* cipher */
NULL, /* kstr */
0, /* klen */
pem_get_password,
&pgp);
} else {
rc = PEM_write_bio_DSAPrivateKey(mem,
key->dsa,
NULL, /* cipher */
NULL, /* kstr */
0, /* klen */
NULL, /* auth_fn */
(void*) passphrase);
}
if (rc != 1) {
goto err;
}
break;
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
if (passphrase == NULL) {
struct pem_get_password_struct pgp = { auth_fn, auth_data };
rc = PEM_write_bio_RSAPrivateKey(mem,
key->rsa,
NULL, /* cipher */
NULL, /* kstr */
0, /* klen */
pem_get_password,
&pgp);
} else {
rc = PEM_write_bio_RSAPrivateKey(mem,
key->rsa,
NULL, /* cipher */
NULL, /* kstr */
0, /* klen */
NULL, /* auth_fn */
(void*) passphrase);
}
if (rc != 1) {
goto err;
}
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_ECC
if (passphrase == NULL) {
struct pem_get_password_struct pgp = { auth_fn, auth_data };
rc = PEM_write_bio_ECPrivateKey(mem,
key->ecdsa,
NULL, /* cipher */
NULL, /* kstr */
0, /* klen */
pem_get_password,
&pgp);
} else {
rc = PEM_write_bio_ECPrivateKey(mem,
key->ecdsa,
NULL, /* cipher */
NULL, /* kstr */
0, /* klen */
NULL, /* auth_fn */
(void*) passphrase);
}
if (rc != 1) {
goto err;
}
break;
#endif
case SSH_KEYTYPE_UNKNOWN:
BIO_free(mem);
ssh_pki_log("Unkown or invalid private key type %d", key->type);
return NULL;
}
BIO_get_mem_ptr(mem, &buf);
blob = ssh_string_new(buf->length);
if (blob == NULL) {
goto err;
}
ssh_string_fill(blob, buf->data, buf->length);
BIO_free(mem);
return blob;
err:
BIO_free(mem);
return NULL;
}
ssh_key pki_private_key_from_base64(const char *b64_key,
const char *passphrase,
ssh_auth_callback auth_fn,
@@ -976,41 +1106,65 @@ static ssh_string _RSA_do_sign(const unsigned char *digest,
return sig_blob;
}
static ssh_string pki_dsa_signature_to_blob(const ssh_signature sig)
{
char buffer[40] = { 0 };
ssh_string sig_blob = NULL;
ssh_string r;
int r_len, r_offset_in, r_offset_out;
ssh_string s;
int s_len, s_offset_in, s_offset_out;
r = make_bignum_string(sig->dsa_sig->r);
if (r == NULL) {
return NULL;
}
s = make_bignum_string(sig->dsa_sig->s);
if (s == NULL) {
ssh_string_free(r);
return NULL;
}
r_len = ssh_string_len(r);
r_offset_in = (r_len > 20) ? (r_len - 20) : 0;
r_offset_out = (r_len < 20) ? (20 - r_len) : 0;
s_len = ssh_string_len(s);
s_offset_in = (s_len > 20) ? (s_len - 20) : 0;
s_offset_out = (s_len < 20) ? (20 - s_len) : 0;
memcpy(buffer + r_offset_out,
((char *)ssh_string_data(r)) + r_offset_in,
r_len - r_offset_in);
memcpy(buffer + 20 + s_offset_out,
((char *)ssh_string_data(s)) + s_offset_in,
s_len - s_offset_in);
ssh_string_free(r);
ssh_string_free(s);
sig_blob = ssh_string_new(40);
if (sig_blob == NULL) {
return NULL;
}
ssh_string_fill(sig_blob, buffer, 40);
return sig_blob;
}
ssh_string pki_signature_to_blob(const ssh_signature sig)
{
char buffer[40] = {0};
ssh_string sig_blob = NULL;
ssh_string r;
ssh_string s;
ssh_string sig_blob = NULL;
switch(sig->type) {
case SSH_KEYTYPE_DSS:
r = make_bignum_string(sig->dsa_sig->r);
if (r == NULL) {
return NULL;
}
s = make_bignum_string(sig->dsa_sig->s);
if (s == NULL) {
ssh_string_free(r);
return NULL;
}
memcpy(buffer,
((char *)ssh_string_data(r)) + ssh_string_len(r) - 20,
20);
memcpy(buffer + 20,
((char *)ssh_string_data(s)) + ssh_string_len(s) - 20,
20);
ssh_string_free(r);
ssh_string_free(s);
sig_blob = ssh_string_new(40);
if (sig_blob == NULL) {
return NULL;
}
ssh_string_fill(sig_blob, buffer, 40);
sig_blob = pki_dsa_signature_to_blob(sig);
break;
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
@@ -1018,42 +1172,119 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_OPENSSL_ECC
{
ssh_buffer b;
int rc;
b = ssh_buffer_new();
if (b == NULL) {
return NULL;
}
r = make_bignum_string(sig->ecdsa_sig->r);
if (r == NULL) {
ssh_buffer_free(b);
return NULL;
}
rc = buffer_add_ssh_string(b, r);
ssh_string_free(r);
if (rc < 0) {
ssh_buffer_free(b);
return NULL;
}
s = make_bignum_string(sig->ecdsa_sig->s);
if (s == NULL) {
ssh_string_free(r);
ssh_buffer_free(b);
return NULL;
}
memcpy(buffer,
((char *)ssh_string_data(r)) + ssh_string_len(r) - 20,
20);
memcpy(buffer + 20,
((char *)ssh_string_data(s)) + ssh_string_len(s) - 20,
20);
ssh_string_free(r);
rc = buffer_add_ssh_string(b, s);
ssh_string_free(s);
sig_blob = ssh_string_new(40);
if (sig_blob == NULL) {
if (rc < 0) {
ssh_buffer_free(b);
return NULL;
}
ssh_string_fill(sig_blob, buffer, 40);
sig_blob = ssh_string_new(buffer_get_rest_len(b));
if (sig_blob == NULL) {
ssh_buffer_free(b);
return NULL;
}
ssh_string_fill(sig_blob, buffer_get_rest(b), buffer_get_rest_len(b));
ssh_buffer_free(b);
break;
}
#endif
case SSH_KEYTYPE_UNKNOWN:
ssh_pki_log("Unknown signature key type: %d", sig->type);
ssh_pki_log("Unknown signature key type: %s", sig->type_c);
return NULL;
}
return sig_blob;
}
static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey,
const ssh_string sig_blob,
ssh_signature sig)
{
uint32_t pad_len = 0;
char *blob_orig;
char *blob_padded_data;
ssh_string sig_blob_padded;
size_t rsalen = 0;
size_t len = ssh_string_len(sig_blob);
if (pubkey->rsa == NULL) {
ssh_pki_log("Pubkey RSA field NULL");
goto errout;
}
rsalen = RSA_size(pubkey->rsa);
if (len > rsalen) {
ssh_pki_log("Signature is too big: %lu > %lu",
(unsigned long)len, (unsigned long)rsalen);
goto errout;
}
#ifdef DEBUG_CRYPTO
ssh_pki_log("RSA signature len: %lu", (unsigned long)len);
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
#endif
if (len == rsalen) {
sig->rsa_sig = ssh_string_copy(sig_blob);
} else {
/* pad the blob to the expected rsalen size */
ssh_pki_log("RSA signature len %lu < %lu",
(unsigned long)len, (unsigned long)rsalen);
pad_len = rsalen - len;
sig_blob_padded = ssh_string_new(rsalen);
if (sig_blob_padded == NULL) {
goto errout;
}
blob_padded_data = (char *) ssh_string_data(sig_blob_padded);
blob_orig = (char *) ssh_string_data(sig_blob);
/* front-pad the buffer with zeroes */
BURN_BUFFER(blob_padded_data, pad_len);
/* fill the rest with the actual signature blob */
memcpy(blob_padded_data + pad_len, blob_orig, len);
sig->rsa_sig = sig_blob_padded;
}
return sig;
errout:
ssh_signature_free(sig);
return NULL;
}
ssh_signature pki_signature_from_blob(const ssh_key pubkey,
const ssh_string sig_blob,
enum ssh_keytypes_e type)
@@ -1062,7 +1293,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
ssh_string r;
ssh_string s;
size_t len;
size_t rsalen;
sig = ssh_signature_new();
if (sig == NULL) {
@@ -1070,6 +1300,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
sig->type = type;
sig->type_c = ssh_key_type_to_char(type);
len = ssh_string_len(sig_blob);
@@ -1125,29 +1356,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
break;
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
rsalen = RSA_size(pubkey->rsa);
if (len > rsalen) {
ssh_pki_log("Signature is to big size: %lu",
(unsigned long)len);
ssh_signature_free(sig);
return NULL;
}
if (len < rsalen) {
ssh_pki_log("RSA signature len %lu < %lu",
(unsigned long)len, (unsigned long)rsalen);
}
#ifdef DEBUG_CRYPTO
ssh_pki_log("RSA signature len: %lu", (unsigned long)len);
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
#endif
sig->rsa_sig = ssh_string_copy(sig_blob);
if (sig->rsa_sig == NULL) {
ssh_signature_free(sig);
return NULL;
}
sig = pki_signature_from_rsa_blob(pubkey, sig_blob, sig);
break;
case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_OPENSSL_ECC
@@ -1188,7 +1397,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
#endif
sig->ecdsa_sig->r = make_string_bn(r);
make_string_bn_inplace(r, sig->ecdsa_sig->r);
ssh_string_burn(r);
ssh_string_free(r);
if (sig->ecdsa_sig->r == NULL) {
@@ -1209,7 +1418,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
#endif
sig->ecdsa_sig->s = make_string_bn(s);
make_string_bn_inplace(s, sig->ecdsa_sig->s);
ssh_string_burn(s);
ssh_string_free(s);
if (sig->ecdsa_sig->s == NULL) {
@@ -1309,6 +1518,7 @@ ssh_signature pki_do_sign(const ssh_key privkey,
}
sig->type = privkey->type;
sig->type_c = privkey->type_c;
switch(privkey->type) {
case SSH_KEYTYPE_DSS:
@@ -1368,6 +1578,7 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
return NULL;
}
sig->type = key->type;
sig->type_c = key->type_c;
switch(key->type) {
case SSH_KEYTYPE_DSS:

View File

@@ -591,6 +591,19 @@ int pki_key_ecdsa_nid_from_name(const char *name)
}
#endif
ssh_string pki_private_key_to_pem(const ssh_key key,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data)
{
(void) key;
(void) passphrase;
(void) auth_fn;
(void) auth_data;
return NULL;
}
ssh_key pki_private_key_from_base64(const char *b64_key,
const char *passphrase,
ssh_auth_callback auth_fn,
@@ -1577,7 +1590,7 @@ ssh_signature pki_do_sign(const ssh_key privkey,
return NULL;
}
sig->type = privkey->type;
sig->type_c = privkey->type_c;
switch (privkey->type) {
case SSH_KEYTYPE_DSS:
/* That is to mark the number as positive */
@@ -1644,6 +1657,7 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
return NULL;
}
sig->type = key->type;
sig->type_c = key->type_c;
switch(key->type) {
case SSH_KEYTYPE_DSS:

View File

@@ -3,8 +3,8 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2003-2009 by Aris Adamantiadis
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2003-2013 by Aris Adamantiadis
* Copyright (c) 2009 Aleksandar Kanchev
*
* The SSH Library is free software; you can redistribute it and/or modify
@@ -64,6 +64,7 @@
struct ssh_poll_handle_struct {
ssh_poll_ctx ctx;
ssh_session session;
union {
socket_t fd;
size_t idx;
@@ -450,7 +451,11 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
if (ctx->polls_allocated > 0) {
while (ctx->polls_used > 0){
ssh_poll_handle p = ctx->pollptrs[0];
ssh_poll_ctx_remove(ctx, p);
/*
* The free function calls ssh_poll_ctx_remove() and decrements
* ctx->polls_used
*/
ssh_poll_free(p);
}
SAFE_FREE(ctx->pollptrs);
@@ -468,14 +473,18 @@ static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size) {
if (pollptrs == NULL) {
return -1;
}
ctx->pollptrs = pollptrs;
pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
if (pollfds == NULL) {
ctx->pollptrs = realloc(pollptrs, sizeof(ssh_poll_handle) * ctx->polls_allocated);
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * ctx->polls_allocated);
if (pollptrs == NULL) {
return -1;
}
ctx->pollptrs = pollptrs;
return -1;
}
ctx->pollptrs = pollptrs;
ctx->pollfds = pollfds;
ctx->polls_allocated = new_size;
@@ -588,11 +597,17 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout) {
ssh_poll_handle p;
socket_t fd;
int revents;
struct ssh_timestamp ts;
if (!ctx->polls_used)
return SSH_ERROR;
rc = ssh_poll(ctx->pollfds, ctx->polls_used, timeout);
ssh_timestamp_init(&ts);
do {
int tm = ssh_timeout_update(&ts, timeout);
rc = ssh_poll(ctx->pollfds, ctx->polls_used, tm);
} while (rc == -1 && errno == EINTR);
if(rc < 0)
return SSH_ERROR;
if (rc == 0)
@@ -782,6 +797,10 @@ int ssh_event_add_session(ssh_event event, ssh_session session) {
p = session->default_poll_ctx->pollptrs[i];
ssh_poll_ctx_remove(session->default_poll_ctx, p);
ssh_poll_ctx_add(event->ctx, p);
/* associate the pollhandler with a session so we can put it back
* at ssh_event_free()
*/
p->session = session;
}
#ifdef WITH_SERVER
iterator = ssh_list_get_iterator(event->sessions);
@@ -844,12 +863,22 @@ int ssh_event_remove_fd(ssh_event event, socket_t fd) {
for (i = 0; i < used; i++) {
if(fd == event->ctx->pollfds[i].fd) {
ssh_poll_handle p = event->ctx->pollptrs[i];
struct ssh_event_fd_wrapper *pw = p->cb_data;
if (p->session != NULL){
/* we cannot free that handle, it's owned by its session */
continue;
}
if (p->cb == ssh_event_fd_wrapper_callback) {
struct ssh_event_fd_wrapper *pw = p->cb_data;
SAFE_FREE(pw);
}
ssh_poll_ctx_remove(event->ctx, p);
free(pw);
/*
* The free function calls ssh_poll_ctx_remove() and decrements
* event->ctx->polls_used.
*/
ssh_poll_free(p);
rc = SSH_OK;
/* restart the loop */
used = event->ctx->polls_used;
i = 0;
@@ -872,7 +901,6 @@ int ssh_event_remove_session(ssh_event event, ssh_session session) {
ssh_poll_handle p;
register size_t i, used;
int rc = SSH_ERROR;
socket_t session_fd;
#ifdef WITH_SERVER
struct ssh_iterator *iterator;
#endif
@@ -881,14 +909,15 @@ int ssh_event_remove_session(ssh_event event, ssh_session session) {
return SSH_ERROR;
}
session_fd = ssh_get_fd(session);
used = event->ctx->polls_used;
for(i = 0; i < used; i++) {
if(session_fd == event->ctx->pollfds[i].fd) {
p = event->ctx->pollptrs[i];
p = event->ctx->pollptrs[i];
if(p->session == session){
ssh_poll_ctx_remove(event->ctx, p);
p->session = NULL;
ssh_poll_ctx_add(session->default_poll_ctx, p);
rc = SSH_OK;
used = 0;
}
}
#ifdef WITH_SERVER
@@ -915,10 +944,23 @@ int ssh_event_remove_session(ssh_event event, ssh_session session) {
*
*/
void ssh_event_free(ssh_event event) {
if(event == NULL) {
int used, i;
ssh_poll_handle p;
if(event == NULL) {
return;
}
if(event->ctx != NULL) {
used = event->ctx->polls_used;
for(i = 0; i < used; i++) {
p = event->ctx->pollptrs[i];
if(p->session != NULL){
ssh_poll_ctx_remove(event->ctx, p);
ssh_poll_ctx_add(p->session->default_poll_ctx, p);
p->session = NULL;
used = 0;
}
}
ssh_poll_ctx_free(event->ctx);
}
#ifdef WITH_SERVER

View File

@@ -83,7 +83,17 @@ ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
return scp;
}
int ssh_scp_init(ssh_scp scp){
/**
* @brief Initialize the scp channel.
*
* @param[in] scp The scp context to initialize.
*
* @return SSH_OK on success or an SSH error code.
*
* @see ssh_scp_new()
*/
int ssh_scp_init(ssh_scp scp)
{
int r;
char execbuffer[1024];
uint8_t code;
@@ -139,7 +149,17 @@ int ssh_scp_init(ssh_scp scp){
return SSH_OK;
}
int ssh_scp_close(ssh_scp scp){
/**
* @brief Close the scp channel.
*
* @param[in] scp The scp context to close.
*
* @return SSH_OK on success or an SSH error code.
*
* @see ssh_scp_init()
*/
int ssh_scp_close(ssh_scp scp)
{
char buffer[128];
int err;
if(scp==NULL)
@@ -169,7 +189,15 @@ int ssh_scp_close(ssh_scp scp){
return SSH_OK;
}
void ssh_scp_free(ssh_scp scp){
/**
* @brief Free a scp context.
*
* @param[in] scp The context to free.
*
* @see ssh_scp_new()
*/
void ssh_scp_free(ssh_scp scp)
{
if(scp==NULL)
return;
if(scp->state != SSH_SCP_NEW)
@@ -517,7 +545,7 @@ int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
* @see ssh_scp_request_get_warning()
*/
int ssh_scp_pull_request(ssh_scp scp){
char buffer[4096] = {0};
char buffer[MAX_BUF_SIZE] = {0};
char *mode=NULL;
char *p,*tmp;
uint64_t size;
@@ -614,7 +642,7 @@ int ssh_scp_pull_request(ssh_scp scp){
* the message failed, or sending it in a bad state.
*/
int ssh_scp_deny_request(ssh_scp scp, const char *reason){
char buffer[4096];
char buffer[MAX_BUF_SIZE];
int err;
if(scp==NULL)
return SSH_ERROR;

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2004-2005 by Aris Adamantiadis
* Copyright (c) 2004-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -58,6 +58,7 @@
#include "libssh/dh.h"
#include "libssh/messages.h"
#include "libssh/options.h"
#include "libssh/curve25519.h"
#define set_status(session, status) do {\
if (session->common.callbacks && session->common.callbacks->connect_status_function) \
@@ -164,7 +165,7 @@ static int ssh_server_kexdh_init(ssh_session session, ssh_buffer packet){
}
SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
int rc;
int rc = SSH_ERROR;
(void)type;
(void)user;
@@ -182,14 +183,21 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_server_ecdh_init(session, packet);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_server_curve25519_init(session, packet);
break;
#endif
default:
ssh_set_error(session,SSH_FATAL,"Wrong kex type in ssh_packet_kexdh_init");
rc = SSH_ERROR;
}
if (rc == SSH_ERROR)
error:
if (rc == SSH_ERROR) {
session->session_state = SSH_SESSION_STATE_ERROR;
error:
}
return SSH_PACKET_USED;
}
@@ -211,6 +219,7 @@ int ssh_get_key_params(ssh_session session, ssh_key *privkey){
*privkey = session->srv.ecdsa_key;
break;
case SSH_KEYTYPE_UNKNOWN:
default:
*privkey = NULL;
}
@@ -988,7 +997,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name,
msg->session->kbdint = NULL;
return SSH_ERROR;
}
msg->session->kbdint->echo = malloc(num_prompts * sizeof(char));
msg->session->kbdint->echo = malloc(num_prompts * sizeof(unsigned char));
if (msg->session->kbdint->echo == NULL) {
ssh_set_error_oom(msg->session);
ssh_kbdint_free(msg->session->kbdint);
@@ -1215,6 +1224,47 @@ int ssh_execute_message_callbacks(ssh_session session){
return SSH_OK;
}
int ssh_send_keepalive(ssh_session session)
{
struct ssh_string_struct *req;
int rc;
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST);
if (rc < 0) {
goto err;
}
req = ssh_string_from_char("keepalive@openssh.com");
if (req == NULL) {
goto err;
}
rc = buffer_add_ssh_string(session->out_buffer, req);
ssh_string_free(req);
if (rc < 0) {
goto err;
}
rc = buffer_add_u8(session->out_buffer, 1);
if (rc < 0) {
goto err;
}
if (packet_send(session) == SSH_ERROR) {
goto err;
}
ssh_handle_packets(session, 0);
SSH_LOG(SSH_LOG_PACKET, "Sent a keepalive");
return SSH_OK;
err:
ssh_set_error_oom(session);
buffer_reinit(session->out_buffer);
return SSH_ERROR;
}
/** @} */
/* vim: set ts=4 sw=4 et cindent: */

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2005-2008 by Aris Adamantiadis
* Copyright (c) 2005-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -100,7 +100,7 @@ ssh_session ssh_new(void) {
/* OPTIONS */
session->opts.StrictHostKeyChecking = 1;
session->opts.port = 22;
session->opts.port = 0;
session->opts.fd = -1;
session->opts.ssh2 = 1;
session->opts.compressionlevel=7;
@@ -115,6 +115,17 @@ ssh_session ssh_new(void) {
goto err;
}
#ifdef HAVE_ECC
id = strdup("%d/id_ecdsa");
if (id == NULL) {
goto err;
}
rc = ssh_list_append(session->opts.identity, id);
if (rc == SSH_ERROR) {
goto err;
}
#endif
id = strdup("%d/id_rsa");
if (id == NULL) {
goto err;
@@ -215,7 +226,11 @@ void ssh_free(ssh_session session) {
#endif /* _WIN32 */
ssh_key_free(session->srv.dsa_key);
session->srv.dsa_key = NULL;
ssh_key_free(session->srv.rsa_key);
session->srv.rsa_key = NULL;
ssh_key_free(session->srv.ecdsa_key);
session->srv.ecdsa_key = NULL;
if (session->ssh_message_list) {
ssh_message msg;
@@ -244,16 +259,20 @@ void ssh_free(ssh_session session) {
ssh_list_free(session->opts.identity);
}
SAFE_FREE(session->auth_auto_state);
SAFE_FREE(session->serverbanner);
SAFE_FREE(session->clientbanner);
SAFE_FREE(session->banner);
SAFE_FREE(session->opts.bindaddr);
SAFE_FREE(session->opts.custombanner);
SAFE_FREE(session->opts.username);
SAFE_FREE(session->opts.host);
SAFE_FREE(session->opts.sshdir);
SAFE_FREE(session->opts.knownhosts);
SAFE_FREE(session->opts.ProxyCommand);
SAFE_FREE(session->opts.gss_server_identity);
SAFE_FREE(session->opts.gss_client_identity);
for (i = 0; i < 10; i++) {
if (session->opts.wanted_methods[i]) {
@@ -261,14 +280,32 @@ void ssh_free(ssh_session session) {
}
}
/* burn connection, it could hang sensitive datas */
ZERO_STRUCTP(session);
/* burn connection, it could contain sensitive data */
BURN_BUFFER(session, sizeof(struct ssh_session_struct));
SAFE_FREE(session);
}
/**
* @brief get the server banner
* @brief get the client banner
*
* @param[in] session The SSH session
*
* @return Returns the client banner string or NULL.
*/
const char* ssh_get_clientbanner(ssh_session session) {
if (session == NULL) {
return NULL;
}
return session->clientbanner;
}
/**
* @brief get the server banner
*
* @param[in] session The SSH session
*
* @return Returns the server banner string or NULL.
*/
const char* ssh_get_serverbanner(ssh_session session) {
if(!session) {
@@ -277,6 +314,38 @@ const char* ssh_get_serverbanner(ssh_session session) {
return session->serverbanner;
}
/**
* @brief get the name of the input for the given session.
*
* @param[in] session The SSH session.
*
* @return Returns cipher name or NULL.
*/
const char* ssh_get_cipher_in(ssh_session session) {
if ((session != NULL) &&
(session->current_crypto != NULL) &&
(session->current_crypto->in_cipher != NULL)) {
return session->current_crypto->in_cipher->name;
}
return NULL;
}
/**
* @brief get the name of the output cipher for the given session.
*
* @param[in] session The SSH session.
*
* @return Returns cipher name or NULL.
*/
const char* ssh_get_cipher_out(ssh_session session) {
if ((session != NULL) &&
(session->current_crypto != NULL) &&
(session->current_crypto->out_cipher != NULL)) {
return session->current_crypto->out_cipher->name;
}
return NULL;
}
/**
* @brief Disconnect impolitely from a remote host by closing the socket.
*
@@ -300,8 +369,6 @@ void ssh_silent_disconnect(ssh_session session) {
* @param[in] session The ssh session to change.
*
* @param[in] blocking Zero for nonblocking mode.
*
* \bug nonblocking code is in development and won't work as expected
*/
void ssh_set_blocking(ssh_session session, int blocking) {
if (session == NULL) {
@@ -464,9 +531,7 @@ int ssh_handle_packets(ssh_session session, int timeout) {
spoll_in = ssh_socket_get_poll_handle_in(session->socket);
spoll_out = ssh_socket_get_poll_handle_out(session->socket);
if (session->server) {
ssh_poll_add_events(spoll_in, POLLIN);
}
ssh_poll_add_events(spoll_in, POLLIN);
ctx = ssh_poll_get_ctx(spoll_in);
if (!ctx) {
@@ -539,7 +604,11 @@ int ssh_handle_packets_termination(ssh_session session,
}
}
ssh_timestamp_init(&ts);
/* avoid unnecessary syscall for the SSH_TIMEOUT_NONBLOCKING case */
if (timeout != SSH_TIMEOUT_NONBLOCKING) {
ssh_timestamp_init(&ts);
}
tm = timeout;
while(!fct(user)) {
ret = ssh_handle_packets(session, tm);
@@ -577,7 +646,7 @@ int ssh_get_status(ssh_session session) {
socketstate = ssh_socket_get_status(session->socket);
if (session->closed) {
if (session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
r |= SSH_CLOSED;
}
if (socketstate & SSH_READ_PENDING) {
@@ -586,7 +655,8 @@ int ssh_get_status(ssh_session session) {
if (socketstate & SSH_WRITE_PENDING) {
r |= SSH_WRITE_PENDING;
}
if ((session->closed && (socketstate & SSH_CLOSED_ERROR)) ||
if ((session->session_state == SSH_SESSION_STATE_DISCONNECTED &&
(socketstate & SSH_CLOSED_ERROR)) ||
session->session_state == SSH_SESSION_STATE_ERROR) {
r |= SSH_CLOSED_ERROR;
}
@@ -594,6 +664,25 @@ int ssh_get_status(ssh_session session) {
return r;
}
/**
* @brief Get poll flags for an external mainloop
*
* @param session The ssh session to use.
*
* @returns A bitmask including SSH_READ_PENDING or SSH_WRITE_PENDING.
* For SSH_READ_PENDING, your invocation of poll() should include
* POLLIN. For SSH_WRITE_PENDING, your invocation of poll() should
* include POLLOUT.
*/
int ssh_get_poll_flags(ssh_session session)
{
if (session == NULL) {
return 0;
}
return ssh_socket_get_poll_flags (session->socket);
}
/**
* @brief Get the disconnect message from the server.
*
@@ -610,12 +699,9 @@ const char *ssh_get_disconnect_message(ssh_session session) {
return NULL;
}
if (!session->closed) {
if (session->session_state != SSH_SESSION_STATE_DISCONNECTED) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Connection not closed yet");
} else if(session->closed_by_except) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Connection closed by socket error");
} else if(!session->discon_msg) {
ssh_set_error(session, SSH_FATAL,
"Connection correctly closed but no disconnect message");
@@ -650,8 +736,13 @@ void ssh_socket_exception_callback(int code, int errno_code, void *user){
ssh_session session=(ssh_session)user;
SSH_LOG(SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code);
session->session_state=SSH_SESSION_STATE_ERROR;
ssh_set_error(session,SSH_FATAL,"Socket error: %s",strerror(errno_code));
session->session_state = SSH_SESSION_STATE_ERROR;
if (errno_code == 0 && code == SSH_SOCKET_EXCEPTION_EOF) {
ssh_set_error(session, SSH_FATAL, "Socket error: disconnected");
} else {
ssh_set_error(session, SSH_FATAL, "Socket error: %s", strerror(errno_code));
}
session->ssh_connection_callback(session);
}

View File

@@ -4,7 +4,7 @@
* This file is part of the SSH Library
*
* Copyright (c) 2005-2008 by Aris Adamantiadis
* Copyright (c) 2008-2009 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2008-2009 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -126,6 +126,7 @@ sftp_session sftp_new(ssh_session session){
sftp->session = session;
sftp->channel = ssh_channel_new(session);
if (sftp->channel == NULL) {
sftp_ext_free(sftp->ext);
SAFE_FREE(sftp);
return NULL;
@@ -133,6 +134,7 @@ sftp_session sftp_new(ssh_session session){
if (ssh_channel_open_session(sftp->channel)) {
ssh_channel_free(sftp->channel);
sftp_ext_free(sftp->ext);
SAFE_FREE(sftp);
return NULL;
@@ -308,7 +310,7 @@ int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload){
}
sftp_packet sftp_packet_read(sftp_session sftp) {
unsigned char buffer[4096];
unsigned char buffer[MAX_BUF_SIZE];
sftp_packet packet = NULL;
uint32_t size;
int r;
@@ -340,7 +342,6 @@ sftp_packet sftp_packet_read(sftp_session sftp) {
return NULL;
}
size = ntohl(size);
r=ssh_channel_read(sftp->channel, buffer, 1, 0);
if (r <= 0) {
/* TODO: check if there are cases where an error needs to be set here */
@@ -350,7 +351,12 @@ sftp_packet sftp_packet_read(sftp_session sftp) {
}
buffer_add_data(packet->payload, buffer, r);
buffer_get_u8(packet->payload, &packet->type);
size=size-1;
size = ntohl(size);
if (size == 0) {
return packet;
}
size--;
while (size>0){
r=ssh_channel_read(sftp->channel,buffer,
sizeof(buffer)>size ? size:sizeof(buffer),0);
@@ -445,6 +451,7 @@ static sftp_message sftp_get_message(sftp_packet packet) {
sftp_message_free(msg);
return NULL;
}
msg->id = ntohl(msg->id);
SSH_LOG(SSH_LOG_PACKET,
"Packet with id %d type %d",
@@ -886,7 +893,7 @@ sftp_dir sftp_opendir(sftp_session sftp, const char *path){
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(payload, id) < 0 ||
if (buffer_add_u32(payload, htonl(id)) < 0 ||
buffer_add_ssh_string(payload, path_s) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(payload);
@@ -1433,7 +1440,7 @@ sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(payload, id) < 0 ||
if (buffer_add_u32(payload, htonl(id)) < 0 ||
buffer_add_ssh_string(payload, dir->handle) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(payload);
@@ -1557,7 +1564,7 @@ static int sftp_handle_close(sftp_session sftp, ssh_string handle) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, handle) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
@@ -1681,7 +1688,7 @@ sftp_file sftp_open(sftp_session sftp, const char *file, int flags,
sftp_flags |= SSH_FXF_EXCL;
SSH_LOG(SSH_LOG_PACKET,"Opening file %s with sftp flags %x",file,sftp_flags);
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, filename) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
@@ -1749,6 +1756,7 @@ ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
sftp_message msg = NULL;
sftp_status_message status;
ssh_string datastring;
size_t datalen;
ssh_buffer buffer;
int id;
@@ -1762,7 +1770,7 @@ ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
return -1;
}
id = sftp_get_new_id(handle->sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, handle->handle) < 0 ||
buffer_add_u64(buffer, htonll(handle->offset)) < 0 ||
buffer_add_u32(buffer,htonl(count)) < 0) {
@@ -1819,19 +1827,19 @@ ssize_t sftp_read(sftp_file handle, void *buf, size_t count) {
return -1;
}
if (ssh_string_len(datastring) > count) {
datalen = ssh_string_len(datastring);
if (datalen > count) {
ssh_set_error(sftp->session, SSH_FATAL,
"Received a too big DATA packet from sftp server: "
"%" PRIdS " and asked for %" PRIdS,
ssh_string_len(datastring), count);
datalen, count);
ssh_string_free(datastring);
return -1;
}
count = ssh_string_len(datastring);
handle->offset += count;
memcpy(buf, ssh_string_data(datastring), count);
handle->offset += (uint64_t)datalen;
memcpy(buf, ssh_string_data(datastring), datalen);
ssh_string_free(datastring);
return count;
return datalen;
default:
ssh_set_error(sftp->session, SSH_FATAL,
"Received message %d during read!", msg->packet_type);
@@ -1855,7 +1863,7 @@ int sftp_async_read_begin(sftp_file file, uint32_t len){
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0 ||
buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
buffer_add_u32(buffer, htonl(len)) < 0) {
@@ -1982,7 +1990,7 @@ ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
ssh_string_fill(datastring, buf, count);
id = sftp_get_new_id(file->sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0 ||
buffer_add_u64(buffer, htonll(file->offset)) < 0 ||
buffer_add_ssh_string(buffer, datastring) < 0) {
@@ -2101,7 +2109,7 @@ int sftp_unlink(sftp_session sftp, const char *file) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, filename) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
@@ -2178,7 +2186,7 @@ int sftp_rmdir(sftp_session sftp, const char *directory) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, filename) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
@@ -2258,7 +2266,7 @@ int sftp_mkdir(sftp_session sftp, const char *directory, mode_t mode) {
attr.flags = SSH_FILEXFER_ATTR_PERMISSIONS;
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, path) < 0 ||
buffer_add_attributes(buffer, &attr) < 0 ||
sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer) < 0) {
@@ -2353,7 +2361,7 @@ int sftp_rename(sftp_session sftp, const char *original, const char *newname) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, oldpath) < 0 ||
buffer_add_ssh_string(buffer, newpath) < 0 ||
/* POSIX rename atomically replaces newpath, we should do the same
@@ -2438,7 +2446,7 @@ int sftp_setstat(sftp_session sftp, const char *file, sftp_attributes attr) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, path) < 0 ||
buffer_add_attributes(buffer, attr) < 0) {
ssh_set_error_oom(sftp->session);
@@ -2571,7 +2579,7 @@ int sftp_symlink(sftp_session sftp, const char *target, const char *dest) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0) {
if (buffer_add_u32(buffer, htonl(id)) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
ssh_string_free(dest_s);
@@ -2682,7 +2690,7 @@ char *sftp_readlink(sftp_session sftp, const char *path) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, path_s) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
@@ -2869,7 +2877,7 @@ sftp_statvfs_t sftp_statvfs(sftp_session sftp, const char *path) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, ext) < 0 ||
buffer_add_ssh_string(buffer, pathstr) < 0) {
ssh_set_error_oom(sftp->session);
@@ -2948,7 +2956,7 @@ sftp_statvfs_t sftp_fstatvfs(sftp_file file) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, ext) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0) {
ssh_set_error_oom(sftp->session);
@@ -3037,7 +3045,7 @@ char *sftp_canonicalize_path(sftp_session sftp, const char *path) {
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, pathstr) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
@@ -3115,7 +3123,7 @@ static sftp_attributes sftp_xstat(sftp_session sftp, const char *path,
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, pathstr) < 0) {
ssh_set_error_oom(sftp->session);
ssh_buffer_free(buffer);
@@ -3182,7 +3190,7 @@ sftp_attributes sftp_fstat(sftp_file file) {
}
id = sftp_get_new_id(file->sftp);
if (buffer_add_u32(buffer, id) < 0 ||
if (buffer_add_u32(buffer, htonl(id)) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0) {
ssh_set_error_oom(file->sftp->session);
ssh_buffer_free(buffer);

View File

@@ -218,7 +218,7 @@ void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){
*/
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_s){
ssh_socket s=(ssh_socket )v_s;
char buffer[4096];
char buffer[MAX_BUF_SIZE];
int r;
int err=0;
socklen_t errlen=sizeof(err);
@@ -245,7 +245,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
/* force a read to get an explanation */
revents |= POLLIN;
}
if(revents & POLLIN){
if((revents & POLLIN) && s->state == SSH_SOCKET_CONNECTED){
s->read_wontblock=1;
r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
if(r<0){
@@ -291,7 +291,7 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
buffer_get_rest_len(s->in_buffer),
s->callbacks->userdata);
buffer_pass_bytes(s->in_buffer,r);
} while (r > 0);
} while ((r > 0) && (s->state == SSH_SOCKET_CONNECTED));
/* p may have been freed, so don't use it
* anymore in this function */
p = NULL;
@@ -307,11 +307,13 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r
if(s->state == SSH_SOCKET_CONNECTING){
SSH_LOG(SSH_LOG_PACKET,"Received POLLOUT in connecting state");
s->state = SSH_SOCKET_CONNECTED;
ssh_poll_set_events(p,POLLOUT | POLLIN);
r = ssh_socket_set_blocking(ssh_socket_get_fd_in(s));
if (r < 0) {
return -1;
}
if (p != NULL) {
ssh_poll_set_events(p,POLLOUT | POLLIN);
}
r = ssh_socket_set_blocking(ssh_socket_get_fd_in(s));
if (r < 0) {
return -1;
}
if(s->callbacks && s->callbacks->connected)
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
return 0;
@@ -438,6 +440,8 @@ void ssh_socket_close(ssh_socket s){
ssh_poll_free(s->poll_out);
s->poll_out=NULL;
}
s->state = SSH_SOCKET_CLOSED;
}
/**
@@ -449,9 +453,19 @@ void ssh_socket_close(ssh_socket s){
* file descriptors
*/
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
s->fd_in = s->fd_out = fd;
if(s->poll_in)
ssh_poll_set_fd(s->poll_in,fd);
s->fd_in = s->fd_out = fd;
if (s->poll_in) {
ssh_poll_set_fd(s->poll_in,fd);
} else {
s->state = SSH_SOCKET_CONNECTING;
/* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s), POLLOUT);
#ifdef _WIN32
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s), POLLWRNORM);
#endif
}
}
/**
@@ -616,10 +630,15 @@ int ssh_socket_nonblocking_flush(ssh_socket s) {
if (!ssh_socket_is_open(s)) {
session->alive = 0;
/* FIXME use ssh_socket_get_errno */
ssh_set_error(session, SSH_FATAL,
"Writing packet: error on socket (or connection closed): %s",
strerror(s->last_errno));
if(s->callbacks && s->callbacks->exception){
s->callbacks->exception(
SSH_SOCKET_EXCEPTION_ERROR,
s->last_errno,s->callbacks->userdata);
}else{
ssh_set_error(session, SSH_FATAL,
"Writing packet: error on socket (or connection closed): %s",
strerror(s->last_errno));
}
return SSH_ERROR;
}
@@ -636,12 +655,16 @@ int ssh_socket_nonblocking_flush(ssh_socket s) {
if (w < 0) {
session->alive = 0;
ssh_socket_close(s);
/* FIXME use ssh_socket_get_errno() */
/* FIXME use callback for errors */
ssh_set_error(session, SSH_FATAL,
"Writing packet: error on socket (or connection closed): %s",
strerror(s->last_errno));
if(s->callbacks && s->callbacks->exception){
s->callbacks->exception(
SSH_SOCKET_EXCEPTION_ERROR,
s->last_errno,s->callbacks->userdata);
}else{
ssh_set_error(session, SSH_FATAL,
"Writing packet: error on socket (or connection closed): %s",
strerror(s->last_errno));
}
return SSH_ERROR;
}
buffer_pass_bytes(s->out_buffer, w);
@@ -695,11 +718,11 @@ int ssh_socket_buffered_write_bytes(ssh_socket s){
int ssh_socket_get_status(ssh_socket s) {
int r = 0;
if (s->read_wontblock) {
r |= SSH_READ_PENDING;
if (buffer_get_len(s->in_buffer) > 0) {
r |= SSH_READ_PENDING;
}
if (s->write_wontblock) {
if (buffer_get_len(s->out_buffer) > 0) {
r |= SSH_WRITE_PENDING;
}
@@ -710,6 +733,17 @@ int ssh_socket_get_status(ssh_socket s) {
return r;
}
int ssh_socket_get_poll_flags(ssh_socket s) {
int r = 0;
if (s->poll_in != NULL && (ssh_poll_get_events (s->poll_in) & POLLIN) > 0) {
r |= SSH_READ_PENDING;
}
if (s->poll_out != NULL && (ssh_poll_get_events (s->poll_out) & POLLOUT) > 0) {
r |= SSH_WRITE_PENDING;
}
return r;
}
#ifdef _WIN32
int ssh_socket_set_nonblocking(socket_t fd) {
u_long nonblocking = 1;
@@ -759,12 +793,6 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
if(fd == SSH_INVALID_SOCKET)
return SSH_ERROR;
ssh_socket_set_fd(s,fd);
s->state=SSH_SOCKET_CONNECTING;
/* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle_in(s),POLLOUT);
#ifdef _WIN32
ssh_poll_add_events(ssh_socket_get_poll_handle_in(s),POLLWRNORM);
#endif
return SSH_OK;
}

View File

@@ -235,10 +235,11 @@ struct ssh_string_struct *ssh_string_copy(struct ssh_string_struct *s) {
* @param[in] s The string to burn.
*/
void ssh_string_burn(struct ssh_string_struct *s) {
if (s == NULL) {
return;
}
memset(s->data, 'X', ssh_string_len(s));
if (s == NULL || s->size == 0) {
return;
}
BURN_BUFFER(s->data, ssh_string_len(s));
}
/**

View File

@@ -59,8 +59,28 @@ struct ssh_threads_callbacks_struct *ssh_threads_get_noop(void) {
static struct ssh_threads_callbacks_struct *user_callbacks =&ssh_threads_noop;
#ifdef HAVE_LIBGCRYPT
#if (GCRYPT_VERSION_NUMBER >= 0x010600)
/* libgcrypt >= 1.6 does not support custom callbacks */
GCRY_THREAD_OPTION_PTHREAD_IMPL;
/* Libgcrypt specific way of handling thread callbacks */
static int libgcrypt_thread_init(void){
if(user_callbacks == NULL)
return SSH_ERROR;
if(user_callbacks == &ssh_threads_noop)
return SSH_OK;
if (strcmp(user_callbacks->type, "threads_pthread") == 0){
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
return SSH_OK;
} else {
/* not supported */
SSH_LOG(SSH_LOG_WARN, "Custom thread handlers not supported with libgcrypt >=1.6, using pthreads");
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
return SSH_OK;
}
}
#else
/* Libgcrypt < 1.6 specific way of handling thread callbacks */
static struct gcry_thread_cbs gcrypt_threads_callbacks;
@@ -79,7 +99,8 @@ static int libgcrypt_thread_init(void){
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcrypt_threads_callbacks);
return SSH_OK;
}
#else
#endif /* GCRYPT_VERSION_NUMBER */
#else /* HAVE_LIBGCRYPT */
/* Libcrypto specific stuff */

View File

@@ -53,73 +53,75 @@ include_directories(
${LIBSSH_THREADS_PRIVATE_INCLUDE_DIRS}
)
add_library(${LIBSSH_THREADS_SHARED_LIBRARY} SHARED ${libssh_threads_SRCS})
if (libssh_threads_SRCS)
add_library(${LIBSSH_THREADS_SHARED_LIBRARY} SHARED ${libssh_threads_SRCS})
target_link_libraries(${LIBSSH_THREADS_SHARED_LIBRARY} ${LIBSSH_THREADS_LINK_LIBRARIES})
target_link_libraries(${LIBSSH_THREADS_SHARED_LIBRARY} ${LIBSSH_THREADS_LINK_LIBRARIES})
set_target_properties(
${LIBSSH_THREADS_SHARED_LIBRARY}
PROPERTIES
VERSION
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh_threads
DEFINE_SYMBOL
LIBSSH_EXPORTS
)
if (WITH_VISIBILITY_HIDDEN)
set_target_properties(${LIBSSH_THREADS_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
endif (WITH_VISIBILITY_HIDDEN)
install(
TARGETS
${LIBSSH_THREADS_SHARED_LIBRARY}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
COMPONENT libraries
)
if (WITH_STATIC_LIB)
add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
VERSION
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh_threads
ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
)
if (WIN32)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
COMPILE_FLAGS
"-DLIBSSH_STATIC"
)
endif (WIN32)
${LIBSSH_THREADS_SHARED_LIBRARY}
PROPERTIES
VERSION
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh_threads
DEFINE_SYMBOL
LIBSSH_EXPORTS
)
install(
TARGETS
${LIBSSH_THREADS_STATIC_LIBRARY}
DESTINATION
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT
libraries
)
endif (WITH_STATIC_LIB)
if (WITH_VISIBILITY_HIDDEN)
set_target_properties(${LIBSSH_THREADS_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
endif (WITH_VISIBILITY_HIDDEN)
install(
TARGETS
${LIBSSH_THREADS_SHARED_LIBRARY}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
COMPONENT libraries
)
if (WITH_STATIC_LIB)
add_library(${LIBSSH_THREADS_STATIC_LIBRARY} STATIC ${libssh_threads_SRCS})
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
VERSION
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh_threads
ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_SUFFIX}
)
if (WIN32)
set_target_properties(
${LIBSSH_THREADS_STATIC_LIBRARY}
PROPERTIES
COMPILE_FLAGS
"-DLIBSSH_STATIC"
)
endif (WIN32)
install(
TARGETS
${LIBSSH_THREADS_STATIC_LIBRARY}
DESTINATION
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT
libraries
)
endif (WITH_STATIC_LIB)
endif (libssh_threads_SRCS)

View File

@@ -75,7 +75,7 @@ static int ssh_pthread_mutex_unlock (void **lock){
}
static unsigned long ssh_pthread_thread_id (void){
#if _WIN32
#if defined(_WIN32) && !defined(__WINPTHREADS_VERSION)
return (unsigned long) pthread_self().p;
#else
return (unsigned long) pthread_self();

View File

@@ -3,7 +3,7 @@
*
* This file is part of the SSH Library
*
* Copyright (c) 2003 by Aris Adamantiadis
* Copyright (c) 2003-2013 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -130,10 +130,13 @@ void crypto_free(struct ssh_crypto_struct *crypto){
(deflateEnd(crypto->compress_out_ctx) != 0)) {
inflateEnd(crypto->compress_out_ctx);
}
SAFE_FREE(crypto->compress_out_ctx);
if (crypto->compress_in_ctx &&
(deflateEnd(crypto->compress_in_ctx) != 0)) {
inflateEnd(crypto->compress_in_ctx);
}
SAFE_FREE(crypto->compress_in_ctx);
#endif /* WITH_ZLIB */
if(crypto->encryptIV)
SAFE_FREE(crypto->encryptIV);
@@ -158,7 +161,7 @@ void crypto_free(struct ssh_crypto_struct *crypto){
SAFE_FREE(crypto->kex_methods[i]);
}
memset(crypto,0,sizeof(*crypto));
BURN_BUFFER(crypto, sizeof(struct ssh_crypto_struct));
SAFE_FREE(crypto);
}
@@ -317,8 +320,13 @@ int crypt_set_algorithms_server(ssh_session session){
session->next_crypto->do_compress_in=1;
}
if(strcmp(method,"zlib@openssh.com") == 0){
ssh_set_error(session,SSH_FATAL,"zlib@openssh.com not supported");
return SSH_ERROR;
SSH_LOG(SSH_LOG_PACKET,"enabling C->S delayed compression");
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
session->next_crypto->do_compress_in = 1;
} else {
session->next_crypto->delayed_compress_in = 1;
}
}
method = session->next_crypto->kex_methods[SSH_COMP_S_C];
@@ -327,8 +335,13 @@ int crypt_set_algorithms_server(ssh_session session){
session->next_crypto->do_compress_out=1;
}
if(strcmp(method,"zlib@openssh.com") == 0){
ssh_set_error(session,SSH_FATAL,"zlib@openssh.com not supported");
return SSH_ERROR;
SSH_LOG(SSH_LOG_PACKET,"enabling S->C delayed compression\n");
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
session->next_crypto->do_compress_out = 1;
} else {
session->next_crypto->delayed_compress_out = 1;
}
}
method = session->next_crypto->kex_methods[SSH_HOSTKEYS];

View File

@@ -6,7 +6,10 @@ add_cmocka_test(torture_connect torture_connect.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_knownhosts torture_knownhosts.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_session torture_session.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_forward torture_forward.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_request_env torture_request_env.c ${TORTURE_LIBRARY})
if (WITH_SFTP)
add_cmocka_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_sftp_read torture_sftp_read.c ${TORTURE_LIBRARY})
endif (WITH_SFTP)

View File

@@ -64,9 +64,10 @@ static void torture_auth_autopubkey(void **state) {
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
rc = ssh_userauth_autopubkey(session, NULL);
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
assert_true(rc == SSH_AUTH_SUCCESS);
}
@@ -87,16 +88,21 @@ static void torture_auth_autopubkey_nonblocking(void **state) {
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
rc = ssh_userauth_none(session,NULL);
ssh_set_blocking(session,0);
do {
rc = ssh_userauth_none(session, NULL);
} while (rc == SSH_AUTH_AGAIN);
/* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
ssh_set_blocking(session, 0);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
do {
rc = ssh_userauth_autopubkey(session, NULL);
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
} while (rc == SSH_AUTH_AGAIN);
assert_true(rc == SSH_AUTH_SUCCESS);
}
@@ -130,7 +136,8 @@ static void torture_auth_kbdint(void **state) {
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_INTERACTIVE);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_INTERACTIVE);
rc = ssh_userauth_kbdint(session, NULL, NULL);
assert_true(rc == SSH_AUTH_INFO);
@@ -172,13 +179,18 @@ static void torture_auth_kbdint_nonblocking(void **state) {
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
rc = ssh_userauth_none(session,NULL);
ssh_set_blocking(session,0);
do {
rc = ssh_userauth_none(session, NULL);
} while (rc == SSH_AUTH_AGAIN);
/* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_INTERACTIVE);
ssh_set_blocking(session,0);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_INTERACTIVE);
do {
rc = ssh_userauth_kbdint(session, NULL, NULL);
} while (rc == SSH_AUTH_AGAIN);
@@ -231,7 +243,8 @@ static void torture_auth_password(void **state) {
if (rc == SSH_AUTH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PASSWORD);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PASSWORD);
rc = ssh_userauth_password(session, NULL, password);
assert_true(rc == SSH_AUTH_SUCCESS);
@@ -260,17 +273,19 @@ static void torture_auth_password_nonblocking(void **state) {
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
ssh_set_blocking(session,0);
ssh_set_blocking(session,0);
do {
rc = ssh_userauth_none(session, NULL);
} while (rc==SSH_AUTH_AGAIN);
} while (rc == SSH_AUTH_AGAIN);
/* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_AUTH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PASSWORD);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PASSWORD);
do {
rc = ssh_userauth_password(session, NULL, password);
@@ -304,7 +319,8 @@ static void torture_auth_agent(void **state) {
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
rc = ssh_userauth_agent(session, NULL);
assert_true(rc == SSH_AUTH_SUCCESS);
@@ -335,14 +351,74 @@ static void torture_auth_agent_nonblocking(void **state) {
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
assert_true(ssh_auth_list(session) & SSH_AUTH_METHOD_PUBLICKEY);
ssh_set_blocking(session, 0);
rc = ssh_userauth_list(session, NULL);
assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
ssh_set_blocking(session,0);
do {
rc = ssh_userauth_agent(session, NULL);
} while (rc == SSH_AUTH_AGAIN);
assert_true(rc == SSH_AUTH_SUCCESS);
}
static void torture_auth_none(void **state) {
ssh_session session = *state;
char *user = getenv("TORTURE_USER");
int rc;
if (user == NULL) {
print_message("*** Please set the environment variable TORTURE_USER"
" to enable this test!!\n");
return;
}
rc = ssh_options_set(session, SSH_OPTIONS_USER, user);
assert_true(rc == SSH_OK);
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
rc = ssh_userauth_none(session,NULL);
assert_true(rc == SSH_AUTH_DENIED);
/* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
}
static void torture_auth_none_nonblocking(void **state) {
ssh_session session = *state;
char *user = getenv("TORTURE_USER");
int rc;
if (user == NULL) {
print_message("*** Please set the environment variable TORTURE_USER"
" to enable this test!!\n");
return;
}
rc = ssh_options_set(session, SSH_OPTIONS_USER, user);
assert_true(rc == SSH_OK);
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
/* This request should return a SSH_REQUEST_DENIED error */
if (rc == SSH_ERROR) {
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
ssh_set_blocking(session,0);
do {
rc = ssh_userauth_none(session,NULL);
} while (rc == SSH_AUTH_AGAIN);
assert_true(rc == SSH_AUTH_DENIED);
assert_true(ssh_get_error_code(session) == SSH_REQUEST_DENIED);
}
int torture_run_tests(void) {
int rc;
const UnitTest tests[] = {
@@ -354,6 +430,8 @@ int torture_run_tests(void) {
unit_test_setup_teardown(torture_auth_autopubkey_nonblocking, setup, teardown),
unit_test_setup_teardown(torture_auth_agent, setup, teardown),
unit_test_setup_teardown(torture_auth_agent_nonblocking, setup, teardown),
unit_test_setup_teardown(torture_auth_none, setup, teardown),
unit_test_setup_teardown(torture_auth_none_nonblocking, setup, teardown),
};
ssh_init();

View File

@@ -24,7 +24,10 @@
#include "torture.h"
#include <libssh/libssh.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#define HOST "localhost"
/* Should work until Apnic decides to assign it :) */
#define BLACKHOLE "1.1.1.1"
@@ -54,12 +57,11 @@ static void torture_connect_nonblocking(void **state) {
ssh_set_blocking(session,0);
do {
rc = ssh_connect(session);
assert_true(rc != SSH_ERROR);
rc = ssh_connect(session);
assert_true(rc != SSH_ERROR);
} while(rc == SSH_AGAIN);
assert_true(rc==SSH_OK);
assert_true(rc == SSH_OK);
}
static void torture_connect_timeout(void **state) {
@@ -84,9 +86,9 @@ static void torture_connect_timeout(void **state) {
sec = after.tv_sec - before.tv_sec;
usec = after.tv_usec - before.tv_usec;
/* Borrow a second for the missing usecs, but don't bother calculating */
if(usec < 0)
if (usec < 0)
sec--;
assert_in_range(sec,1,3);
assert_in_range(sec, 1, 3);
}
static void torture_connect_double(void **state) {
@@ -102,10 +104,9 @@ static void torture_connect_double(void **state) {
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
}
static void torture_connect_failure(void **state){
static void torture_connect_failure(void **state) {
/*
* The intent of this test is to check that a fresh
* ssh_new/ssh_disconnect/ssh_free sequence doesn't crash/leak
@@ -114,6 +115,30 @@ static void torture_connect_failure(void **state){
ssh_session session = *state;
ssh_disconnect(session);
}
static void torture_connect_socket(void **state) {
ssh_session session = *state;
int rc;
int sock_fd = 0;
struct sockaddr_in server_addr;
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
assert_true(sock_fd > 0);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(22);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
rc = connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
assert_true(rc == 0);
ssh_options_set(session, SSH_OPTIONS_FD, &sock_fd);
rc = ssh_connect(session);
assert_true(rc == SSH_OK);
}
int torture_run_tests(void) {
int rc;
const UnitTest tests[] = {
@@ -121,6 +146,7 @@ int torture_run_tests(void) {
unit_test_setup_teardown(torture_connect_double, setup, teardown),
unit_test_setup_teardown(torture_connect_failure, setup, teardown),
unit_test_setup_teardown(torture_connect_timeout, setup, teardown),
unit_test_setup_teardown(torture_connect_socket, setup, teardown),
};
ssh_init();

View File

@@ -0,0 +1,94 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Andreas Schneider <asn@cryptomilk.org>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#define LIBSSH_STATIC
#include "torture.h"
#include <libssh/libssh.h>
static void setup(void **state)
{
ssh_session session;
const char *host;
const char *user;
const char *password;
host = getenv("TORTURE_HOST");
if (host == NULL) {
host = "localhost";
}
user = getenv("TORTURE_USER");
password = getenv("TORTURE_PASSWORD");
session = torture_ssh_session(host, user, password);
assert_non_null(session);
*state = session;
}
static void teardown(void **state)
{
ssh_session session = (ssh_session) *state;
assert_non_null(session);
if (ssh_is_connected(session)) {
ssh_disconnect(session);
}
ssh_free(session);
}
static void torture_ssh_forward(void **state)
{
ssh_session session = (ssh_session) *state;
#if 0
ssh_channel c;
#endif
int bound_port;
int rc;
rc = ssh_forward_listen(session, "127.0.0.1", 8080, &bound_port);
assert_int_equal(rc, SSH_OK);
#if 0
c = ssh_forward_accept(session, 60000);
assert_non_null(c);
ssh_channel_send_eof(c);
ssh_channel_close(c);
#endif
}
int torture_run_tests(void) {
int rc;
const UnitTest tests[] = {
unit_test_setup_teardown(torture_ssh_forward, setup, teardown),
};
ssh_init();
rc = run_tests(tests);
ssh_finalize();
return rc;
}

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