Compare commits

...

120 Commits

Author SHA1 Message Date
Andreas Schneider
389efc234b src: Add missing ABI files
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2019-11-07 16:19:45 +01:00
Andreas Schneider
f1e44a79a9 Bump version to 0.9.2
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2019-11-07 16:19:00 +01:00
Jakub Jelen
54cf7b92ed server: Use really the negotiated signature type
Generally, when the extension negotiation is enabled and client supports
SHA2 algorithms for RSA, they are supposed to be prioritized against the
old SHA1. If it is not (ssh-rsa is listed in front of rsa-sha2-* hostkey
algorithms during negotiation), the server wrongly tries to provide the
new typo of signature, ignoring the negotiated algirithm

This commit propagates the digest algorithm from negotiation to the actual
signature functions, which were previously responsible for decision
about the hash algorithm based just on the negotiated extensions.

Fixes T191

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 1ebf506913)
2019-11-07 16:14:46 +01:00
Andreas Schneider
f0b676a9f0 gitlab-ci: Disable client testing as pam_wrapper is broken on TW
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit fbc2912dde)
2019-11-07 16:14:46 +01:00
Andreas Schneider
cc190b21b2 cmake: Fix setting up cwrap for server testing
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit ea4f71721f)
2019-11-07 16:14:46 +01:00
Andreas Schneider
a775324c35 cmake: Do not use cached LIBSSH_PUBLIC_INCLUDE_DIRS
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 4ab0fb2b48)
2019-11-07 16:14:46 +01:00
Andreas Schneider
5de765ebd5 cmake: Rename static library
This is only compiled for tests and fuzzers!

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 8c36a865f2)
2019-11-07 16:14:46 +01:00
Andreas Schneider
9de970160d cmake: Create ssh library directly as libssh
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 82c57c1f36)
2019-11-07 16:14:46 +01:00
Andreas Schneider
8a7abf2480 cmake: Add option to build shared libs
See https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit c2c3545391)
2019-11-07 16:14:46 +01:00
Andreas Schneider
920c08eaf8 cmake: Remove WITH_STATIC_LIB
We will honor BUILD_SHARED_LIBS from cmake next.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 729c92606c)
2019-11-07 16:14:46 +01:00
Andreas Schneider
c0fa85a43d cmake: Don't cache LIBSSH_LINK_LIBRARIES
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 498b63949e)
2019-11-07 16:14:46 +01:00
Andreas Schneider
be16481be2 cmake:pkd: Don't use LIBSSH_LINK_LIBRARIES
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 39f7ddaa06)
2019-11-07 16:14:46 +01:00
Andreas Schneider
c4ac076607 cmake: Remove libsocket
This is already part of LIBSSH_REQUIRED_LIBRARIES

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 2fcc15c5dc)
2019-11-07 16:14:46 +01:00
Andreas Schneider
ff534bc2fe cmake: Use target_include_directories()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 5e2788d4c5)
2019-11-07 16:14:46 +01:00
Anderson Toshiyuki Sasaki
27096c3c0f cmake: Only use OpenSSL Ed25519 implementation when possible
It is possible for OpenSSL to have the type EVP_PKEY_ED25519 in
openssl/evp.h, but not the single shot functions EVP_DigestSign() and
EVP_DigestVerify() which are required to generate Ed25519 signatures.

Only switch to use OpenSSL Ed25519 implementation when OpenSSL have all
required types and functions.

Fixes: T197

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 21655e396c)
2019-11-07 16:14:46 +01:00
Andreas Schneider
8a6ddc0a48 gitlab-ci: Mips is dead
Debian removed the cross compiling toolchain. So lets drop it.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit d02c06268e)
2019-11-04 09:48:40 +01:00
Andreas Schneider
0c951b9f27 channel: Document ssh_channel_request_sftp()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit e5767bf0b7)
2019-11-04 09:48:38 +01:00
Andreas Schneider
37529f16a8 auth: Add missing include for explicit_bzero()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 4a113159b2)
2019-11-04 09:48:36 +01:00
Andreas Schneider
e89106b9f7 cpack: Ignore compule_database.json and clangd dir
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit a4b95268ee)
2019-10-25 17:29:55 +02:00
Andreas Schneider
67c0ce3d21 cmake: Bump version to 0.9.1
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2019-10-25 16:11:17 +02:00
Andreas Schneider
f618689c82 cmake: Bump library version
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2019-10-25 16:11:17 +02:00
Andreas Schneider
aaeaca8c6e cmake: Link compile database to source dir for clangd
See
https://github.com/ycm-core/YouCompleteMe
https://github.com/abingham/emacs-ycmd

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit d4328069652635a431e13db0d7c8cbe02af21082)
2019-10-25 16:11:17 +02:00
Jakub Jelen
58c26f4823 packet: On failure, do not use uninitialized crypto
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit e9e8292370)
2019-10-25 16:11:17 +02:00
Jakub Jelen
c888d9c690 packet_crypt: Avoid out of bounds access in debug functions
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 5a0177def0)
2019-10-25 16:11:17 +02:00
Anderson Toshiyuki Sasaki
07df7bb4e6 tests: Do not parse global config in torture_ssh_session()
Do not parse global config file in sessions created by
torture_ssh_session().

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 8a50dbc6ba)
2019-10-25 16:11:17 +02:00
Anderson Toshiyuki Sasaki
5aecfb5a96 tests: Do not parse global configuration when testing server
This removes the tests which uses external configuration files.  This
makes the tests no not change behaviour depending on the environment
they are being executed.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 85239c8ea0)
2019-10-25 16:11:17 +02:00
Anderson Toshiyuki Sasaki
50b37f2991 tests: Do not process server config during tests
In pkd tests, avoid processing the global server configuration file.
This is to allow testing with algorithms not allowed in the global
server configuration.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 040aa0edfe)
2019-10-25 16:11:17 +02:00
Anderson Toshiyuki Sasaki
a47a291303 tests: Do not process config when reinitializing session
Do not process system-wide configuration when reinitializing a session
during testing.  This could lead to different settings set from the
expected one (which was initialized during test setup).

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit f97a8b4e3f)
2019-10-25 16:11:17 +02:00
Anderson Toshiyuki Sasaki
f199bd4879 tests: Use temporary file for known_hosts
Previously, the tests were sharing the same file path to create the
known_hosts file, which can create a race condition if the tests run in
parallel.  Such file was deleted between tests.

By using different different files for each test, the risk of race
conditions is eliminated. Moreover, it makes unnecessary to destroy the
file between tests.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit d4fe8e1f62)
2019-10-25 16:11:17 +02:00
Anderson Toshiyuki Sasaki
4f7cb6076a pki_crypto: Support Ed25519 keys in PEM files
This adds support for Ed25519 keys from files in PEM format when using
OpenSSL with Ed25519 support.  The default encoding for the PEM file is
expected to be PKCS#8.  Encrypted files are supported.

For the lack of an API, it is not possible to export keys in PEM format,
only in OpenSSH format.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit a3a0529b41)
2019-09-30 16:58:07 +02:00
Anderson Toshiyuki Sasaki
3f6820694e cmake: Do not build internal ed25519 when unnecessary
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 61e6b6cc59)
2019-09-30 16:57:59 +02:00
Anderson Toshiyuki Sasaki
0da6597fe4 curve25519: Use OpenSSL X25519 implementation
If supported, use OpenSSL X25519 implementation for the curve25519 key
exchange.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit d463f67aba)
2019-09-30 16:57:48 +02:00
Anderson Toshiyuki Sasaki
0a13045f68 cmake: Detect OpenSSL X25519 support
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 0b7f7d2cf7)
2019-09-30 16:57:39 +02:00
Anderson Toshiyuki Sasaki
b56ffd8424 pki: Remove unused function pki_signature_verify()
This removes unused function pki_signature_verify()
from pki_{crypto, mbedcrypto, gcrypt}.  The function was also removed
from include/libssh/pki_priv.h.  The function ssh_pki_signature_verify()
was changed to receive a const unsigned char *input.

All tests calling pki_signature_verify() were changed to call
ssh_pki_signature_verify() instead.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 55cd04fbee)
2019-09-30 16:57:31 +02:00
Anderson Toshiyuki Sasaki
c60ac3fe02 pki_crypto: Use OpenSSL for Ed25519 signatures
Use OpenSSL to generate and verify Ed25519 signatures, if supported.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 2a2c1c98bf)
2019-09-30 16:57:23 +02:00
Anderson Toshiyuki Sasaki
84eab65edc pki: Move common Ed25519 functions to pki_ed25519_common.c
This is a preparation to use the Ed25519 implementation from OpenSSL.

The function pki_ed25519_sig_to_blob() was renamed to
pki_ed25519_signature_to_blob() and pki_ed25519_sig_from_blob() was
renamed to pki_signature_from_ed25519_blob() to follow the naming for
other algorithms.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit bdcaf55b90)
2019-09-30 16:57:16 +02:00
Anderson Toshiyuki Sasaki
7c3e37bf4c cmake: Detect OpenSSL support for Ed25519
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit a0b84a8cd5)
2019-09-30 16:57:07 +02:00
Anderson Toshiyuki Sasaki
ab9921ee6a pki_mbedcrypto: Do not treat Ed25519 as a special case
Generate and verify Ed25519 signatures along with the other signature
types.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 97adbfe087)
2019-09-30 16:56:59 +02:00
Anderson Toshiyuki Sasaki
9296bcd4bb pki_gcrypt: Do not treat Ed25519 as a special case
Verify the Ed25519 signature in pki_verify_data_signature() along with
the other signature types.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 38ede2e225)
2019-09-30 16:56:50 +02:00
Anderson Toshiyuki Sasaki
24f39761f3 pki_crypto: Use EVP_DigestSign* and EVP_DigestVerify*
Use the newer APIs EVP_DigestSign{Init}() and EVP_DigestVerify{Init}()
to generate and verify signatures instead of the older EVP_Sign{Init,
Update, Final} and EVP_Verify{Init, Update, Final} if supported.

Also use the single shot signature/verification if supported as all the
input is provided at once.

This is a preparation to use Ed25519 implementation from OpenSSL.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 90944a3651)
2019-09-30 16:56:39 +02:00
Anderson Toshiyuki Sasaki
49e8a4ef19 torture_pki_ed25519: Use public key to verify signatures
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 7452f0ded8)
2019-09-30 16:56:24 +02:00
Anderson Toshiyuki Sasaki
d7e1141c1e gitlab-ci: Move cmake from prep to build command in csbuild
This is required to avoid csbuild scan failures when a commit removes
source files.  The command prep is run only once before all the builds,
making csbuild to try to compile the old files using the configuration
files generated for the newest version.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 7ffa3c358d)
2019-09-30 16:54:43 +02:00
Andreas Schneider
fd5c598477 gitlab-ci: Turn DEBUG_CRYPTO on for standard crypto lib builds
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 4799915a36)
2019-09-30 16:54:27 +02:00
Jakub Jelen
de4034bfe0 buffer: Simplify handling of the return codes
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit e72429f205)
2019-09-30 16:00:30 +02:00
Jakub Jelen
6ccd84bae9 buffer: Avoid use of uninitialized values
Fixes the following oss-fuzz bug:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=17565

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit aff7c500d5)
2019-09-30 16:00:19 +02:00
Jakub Jelen
e4c281c7ce dh-gex: Correctly free modulus and generator with openssl
Fixes T176

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit aac682f60e)
2019-09-30 16:00:09 +02:00
Jakub Jelen
93541fe150 channels: Correctly reports failed channels opening
Fixes T75

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 2f05243a4a)
2019-09-30 15:59:53 +02:00
Jakub Jelen
e6ba98a0aa Reformat channel_open()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 89a9eb8811)
2019-09-30 15:59:37 +02:00
Jakub Jelen
6dcb960501 channels: Do not use deprecated functions in the example code
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 3cf2b41f5e)
2019-09-30 15:59:27 +02:00
Jakub Jelen
fcacc7fe8c options: Do not attempt to expand percents in PKCS#11 URIs
With the old token parser, the data was simply broken on the = sign even
if the uri was in quotes and ignored.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 223cc96239)
2019-09-30 15:59:17 +02:00
Jakub Jelen
f078f53911 tests: Verify the localuser match works
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 61b1e0e7e9)
2019-09-30 15:59:07 +02:00
Jakub Jelen
27f5bfd129 config: Support match localuser
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 6500134259)
2019-09-30 15:58:57 +02:00
Jakub Jelen
4a0cbe396d config: Make the matching case sensitive as documented in ssh_config manual pages
> note that keywords are case-insensitive and arguments are case-sensitive

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 9b8b312b88)
2019-09-30 15:58:46 +02:00
Jakub Jelen
a1812e9ac1 Skip the proxycommand test in case the netcat is not avaliable
Fixes: T142

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 4900ab6ca9)
2019-09-30 15:58:36 +02:00
Jakub Jelen
0e3dbd6c69 sftp: Improve the documentation of sftp_init() and sftp_new()
Fixes: T137

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 618b858e49)
2019-09-30 15:53:44 +02:00
Jakub Jelen
d2af62624d known_hosts: Avoid using deprecated functions (even from deprecated functions)
Fixes: T165

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 83fa060cec)
2019-09-30 15:42:26 +02:00
Richard W.M. Jones
93113ccfb9 misc: Allow %% to escape a single % in paths.
For example "%d/config%%1" is expanded to "~/.ssh/config%1".

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 3737e5f0e7)
2019-08-08 10:36:50 +02:00
Andreas Schneider
9ffaa12012 dh: Add ssh_dh_debug_crypto()
We should call it where we have access to the crypto structure.

Pair-Programmed-With: Jakub Jelen <jjelen@redhat.com>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 92d3efec81)
2019-08-08 09:45:38 +02:00
Andreas Schneider
ae5146f7ba bignum: Pass const to ssh_print_bignum()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 4e25ee6124)
2019-08-08 09:45:36 +02:00
Andreas Schneider
dd554ebb32 pki_mbedcrypto: Add missing misc.h header file
For ssh_log_hexdump().

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 89ab7b23f8)
2019-08-08 09:45:14 +02:00
Anderson Toshiyuki Sasaki
fae61f1d09 tests: Skip testing 1024 bits key generation in FIPS mode
In torture_threads_pki_rsa, skip the test which generates 1024 bits RSA
key pair when in FIPS mode.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 3a61cd34a9)
2019-08-08 09:45:10 +02:00
Anderson Toshiyuki Sasaki
9e8e5f5cb2 knownhosts: Use ssh_mkdirs() instead of ssh_mkdir()
Previously, if the path to known_hosts file set through
SSH_OPTIONS_KNOWNHOSTS included missing directories,
ssh_session_update_known_hosts() would fail.  The added test case checks
that this is not the case anymore.

The logic of checking if the directory is accessible before creating it
was replaced by creating the directory if opening the file failed.  This
is to minimize the risk of TOCTOU race conditions.

Fixes: T166

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 5b18bcb0ac)
2019-08-08 09:45:08 +02:00
Anderson Toshiyuki Sasaki
80c1dbdb61 misc: Introduce internal function ssh_mkdirs()
If the given path includes missing directories, ssh_mkdirs() tries to
create them recursively.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 742918cb1c)
2019-08-08 09:45:06 +02:00
Anderson Toshiyuki Sasaki
4505c076b3 misc: Introduce internal function ssh_dir_writeable()
The introduced internal function checks if the provided path is for an
existing directory which is accessible for writing.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 7857cd1aa5)
2019-08-08 09:45:04 +02:00
Jakub Jelen
99dc2002b9 libcrypto: Avoid incompatible pointers
Fixes: T164

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit e42d44e48a)
2019-08-08 09:44:54 +02:00
Jakub Jelen
878d8320c1 pki_container_openssh: Avoid bogus newline in debug message
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 683096ae7e)
2019-08-08 09:44:47 +02:00
Jakub Jelen
80e729fe33 pki_container_openssh: Reformat whitespace
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 3811c73f8f)
2019-08-08 09:44:45 +02:00
Jakub Jelen
47945671af examples: Load ED25519 key when loading all keys
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit cc92e74309)
2019-08-08 09:44:43 +02:00
Anderson Toshiyuki Sasaki
b2e7ef6836 Replace ssh_print_hexa() with ssh_log_hexdump()
Replace all occurrences of the deprecated function ssh_print_hexa() with
the introduced ssh_log_hexdump().

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 68baebbd62)
2019-08-08 09:44:18 +02:00
Anderson Toshiyuki Sasaki
651fea9f14 misc: Introduce ssh_log_hexdump()
The introduced internal function is intended to be a replacement for the
deprecated function ssh_print_hexa().

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 33927f3ae8)
2019-08-08 09:44:15 +02:00
Anderson Toshiyuki Sasaki
f10db964b5 tests: Try PEM files with leading white spaces
This adds a reproducer for T123.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c03c9b88d1)
2019-08-08 09:44:09 +02:00
Anderson Toshiyuki Sasaki
703f0a0f36 pki: Search OpenSSH header not only at the beginning
Try to find the OpenSSH private key header not only at the beginning of
the file.  This makes the parser to skip comments and white spaces.

Fixes: T76
Fixes: T123

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 88d777e678)
2019-08-08 09:42:47 +02:00
Andreas Schneider
7b8d57fbb6 tests: Use the correct assert function in test server
CID 1398983

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2019-07-08 18:39:47 +02:00
Andreas Schneider
8e793d930e tests: Fix #ifdef in torture_server_config
This should stop detecting it as dead code.

CID 1402934

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2019-07-08 18:39:44 +02:00
Andreas Schneider
cc2feabe73 examples: Fix freeing the channel in ssh_client
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
2019-07-08 18:39:41 +02:00
Andreas Schneider
4d57d73faf examples: Update header in ssh_client
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit b275045ac8)
2019-07-08 16:49:51 +02:00
Andreas Schneider
4bd9041afb exmples: Use SSH_CONNECTOR_STDINOUT in client example
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit b5a8547d91)
2019-07-08 16:49:48 +02:00
Andreas Schneider
74e084f76c include: Add define for SSH_CONNECTOR_STDINOUT
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 1a26c57af2)
2019-07-08 16:49:47 +02:00
Andreas Schneider
6c80718c0d cmake: Fix linking shared and static libraries
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 915c006a30)
2019-07-08 16:48:05 +02:00
Andreas Schneider
a330806e4b dh_crypto: Use size_t for loop variable
Also don't declare the variable in the loop.

Fixes #157

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 2884f97bc5)
2019-07-08 16:48:01 +02:00
Stefan Strogin
3b01c328ab libcrypto: fix compilation with LibreSSL
LibreSSL does not support FIPS mode, check for FIPS_mode() in
ConfigureChecks.cmake.

Signed-off-by: Stefan Strogin <steils@gentoo.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 0d4658740b)
2019-07-08 16:47:59 +02:00
Andreas Schneider
5b981a9e3d tests: Use C99 initilizer in test_server.c
This fixes a clang build warning.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit fed31c1ca3)
2019-07-04 16:32:46 +02:00
Andreas Schneider
36dc66da81 cmake: Write libssh-config.cmake using EXPORTS
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 68533147e2)
2019-07-04 16:29:32 +02:00
Andreas Schneider
2a3718de51 cmake: Use GNUInstallDirs for installation
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 24af712931)
2019-07-04 16:29:29 +02:00
Anderson Toshiyuki Sasaki
1fd68ec732 kex: Do not ignore keys in known_hosts files
Previously, if the SSH_OPTIONS_HOSTKEYS option was set by any mean,
including the client configuration file, the keys in known_hosts files
wouldn't be considered before advertising the list of wanted host keys.

This could result in the client requesting the server to provide a
signature using a key not present in the known_hosts files (e.g. when
the first wanted algorithm in SSH_OPTIONS_HOSTKEYS is not present in the
known_hosts files), causing a host key mismatch and possible key
rejection.

Now, the keys present in the known_hosts files are prioritized over the
other wanted keys.  This do not change the fact that only keys of types
present in the list set in SSH_OPTIONS_HOSTKEYS will be accepted and
prioritized following the order defined by such list.

The new wanted list of hostkeys is given by:
 - The keys present in known_hosts files, ordered by preference defined
   in SSH_OPTIONS_HOSTKEYS.  If the option is not set, a default order
   of preference is used.
 - The other keys present in the same option are appended without adding
   duplicates.  If the option is not set, the default list of keys is
   used.

Fixes: T156

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit f18a7cc17e)
2019-07-04 11:26:37 +02:00
Anderson Toshiyuki Sasaki
fa3caa61fd knownhosts: Introduced ssh_known_hosts_get_algorithms_names()
The added internal function obtain a newly allocated string containing a
list of the signature types that can be generated by the keys present in
the known_hosts files, separated by commas.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 65a38759ca)
2019-07-04 11:26:27 +02:00
Anderson Toshiyuki Sasaki
aaa978ad06 token: Added function to remove duplicates
Added a function to remove duplicates from lists.  This function is used
in a new provided function to append lists removing duplicates.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 548753b338)
2019-07-04 11:26:19 +02:00
Anderson Toshiyuki Sasaki
b9530cedbe knownhosts: Read knownhosts file only if found
Avoid trying to open the files if they are not accessible.  This was
already treated as a non-error, but with this we save one function call.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit e5a64a3d6b)
2019-07-04 11:26:10 +02:00
Anderson Toshiyuki Sasaki
7ff0af7543 tests: Check if known_hosts works with single unaccessible file
Make sure known hosts check works when local known_hosts file is
unaccessible, but the host is present in global known_hosts file.

Remove double return value check in previous existing test.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit ad68de7271)
2019-07-04 11:26:00 +02:00
Anderson Toshiyuki Sasaki
b040856ccf knownhosts: Fix possible memory leak
The memory allocated for host_port can leak if the global knownhosts
file is unaccessible.

Found by address sanitizer build in CI.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit fe248414fe)
2019-07-04 11:25:35 +02:00
Andreas Schneider
79900e5246 Bump version to 0.9.0
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2019-06-28 08:06:35 +02:00
Anderson Toshiyuki Sasaki
63b0399373 tests: Added a check for unaccessible global known_hosts
Verify that the check process will not fail if the global known_hosts
file is not accessible and the local known_hosts file contain the host.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 8e42ed8220)
2019-06-28 08:06:35 +02:00
Anderson Toshiyuki Sasaki
39665fd9c5 knownhosts: Fixed a typo
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 5617eaf0e2)
2019-06-28 08:06:35 +02:00
Anderson Toshiyuki Sasaki
83f0be1f04 knownhosts: Do not fail if global known_hosts file is inaccessible
Previously, if the global known_hosts file (default:
/etc/ssh/ssh_known_hosts) was inaccessible, the check for known hosts
failed.  This makes the check to fail if both files are inaccessible.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 4adb13d9e3)
2019-06-28 08:06:35 +02:00
Anderson Toshiyuki Sasaki
3bc5f88f77 connect: Code style formatting
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit da50b12051)
2019-06-27 10:37:46 +02:00
Anderson Toshiyuki Sasaki
466ca07626 connect: Removed unused code
The internal function ssh_connect_host() is not used.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a82993b320)
2019-06-27 10:37:44 +02:00
Anderson Toshiyuki Sasaki
b6e757d692 packet: Check return value when sending unimplemented
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 6a9185636f)
2019-06-27 10:37:43 +02:00
Anderson Toshiyuki Sasaki
3f2375e948 packet: Reformat ssh_packet_process()
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit a1ee22eb64)
2019-06-27 10:37:41 +02:00
Anderson Toshiyuki Sasaki
4d06c2f283 auth: Do not print error message for SSH_AGAIN
In non-blocking mode, it is expected SSH_AGAIN to be returned many
times.  Do not flood the log with error messages.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 1d54a3880d)
2019-06-27 10:37:40 +02:00
Anderson Toshiyuki Sasaki
0298bfbbf0 examples: Check ssh_event_dopoll() return value
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit b1ff11f416)
2019-06-27 10:37:39 +02:00
Anderson Toshiyuki Sasaki
2399a9f8de dh-gex: Check return code ssh_dh_keypair_get_keys()
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 25bb6eef96)
2019-06-27 10:37:37 +02:00
Anderson Toshiyuki Sasaki
79756c5c56 gitlab-ci: Re-enable client tests in CentOS7
The tests were disabled because of failures in torture_auth.  The server
tests are not enabled because the pkd tests are failing.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit d00ff451db)
2019-06-27 09:56:57 +02:00
Anderson Toshiyuki Sasaki
e8510043d2 pki: Add workarounds for old OpenSSH
When we are talking to old OpenSSH versions which does not support
rsa-sha2-{256,512}-cert-v01@openssh.com or SHA2 in certificates,
fallback to old supported values.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 4b7ce75e1f)
2019-06-27 09:56:55 +02:00
Anderson Toshiyuki Sasaki
1f7889f271 tests/pkd: Fix elif without expression
This was introduced during fixes to run pkd tests in FIPS mode.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit c8f49becfd)
2019-06-27 09:56:53 +02:00
Anderson Toshiyuki Sasaki
89efd56217 tests: Add a server test case for unknown global request
The test checks if the server handles unknown global requests properly.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit f64814b7be)
2019-06-27 09:56:52 +02:00
Anderson Toshiyuki Sasaki
e3fca31c59 tests: Introduce torture_client_global_requests
Added a test case where invalid global requests are sent to the server
which should reject them, but not stop working.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit abf5712160)
2019-06-27 09:56:50 +02:00
Anderson Toshiyuki Sasaki
d71a7976dd messages: Reject tcpip-forward requests as client
When the session is a client session, reject tcpip-forward requests.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 1aef599ab1)
2019-06-27 09:56:49 +02:00
Anderson Toshiyuki Sasaki
8fe8d13e29 messages: Consume unknown global requests messages
When an unknown global request is received, consume the message to avoid
sending UNIMPLEMENTED later.  Only report the failure if the request
wants a reply.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 3d7d3f303e)
2019-06-27 09:56:47 +02:00
Andreas Schneider
722f979790 Update ChangeLog to add FIPS
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 220f1e1435)
2019-06-24 16:05:05 +02:00
Jakub Jelen
2c60ef04d9 tests: Skip 1k RSA key generation in FIPS
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 17a531d2af)
2019-06-24 15:42:02 +02:00
Jakub Jelen
ec486d13db pki_crypto: Correct error checking after RSA key generation
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit a80547bdf9)
2019-06-24 15:42:01 +02:00
Jakub Jelen
ebfe46f6ad tests: Filter out bogus output from openssh in FIPS Mode
The OpenSSH in RHEL 8 in FIPS Mode outputs information about this on start
and it needs to be skipped for the version detection (and build) to pass:

$ ssh -V
FIPS mode initialized
OpenSSH_8.0p1, OpenSSL 1.1.1c FIPS  28 May 2019

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit a4fa514549)
2019-06-24 15:42:00 +02:00
Jakub Jelen
3c0897b975 tests: Add reproducer for T76
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit d5095a55b9)
2019-06-24 15:41:58 +02:00
Jakub Jelen
993e0df81e pki: Search for the PEM headers not only on the start of the key file
Fixes: T76 for gcrypt and mbedtls backends

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit d627cba476)
2019-06-24 15:41:57 +02:00
Jakub Jelen
551188d99b pki: Reformat pki_privatekey_type_from_string()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 23c837f4d0)
2019-06-24 15:41:56 +02:00
Jakub Jelen
cafafe8f5a tests: Reproducer for proxy command with stderr output (T130)
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit bd69ac63ca)
2019-06-24 15:41:54 +02:00
Jakub Jelen
c6c7856b51 socket: Do not process stderr of proxy commands (Fixes T130)
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 6c49c41c19)
2019-06-24 15:41:53 +02:00
Jakub Jelen
ea71af9c22 socket: Reformat the rest of the file
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit bd65568749)
2019-06-24 15:41:51 +02:00
Andreas Schneider
bb98413fc1 Bump version to 0.8.91
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2019-06-14 15:35:51 +02:00
Andreas Schneider
2a8cd81e8f Update ChangeLog
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2019-06-14 15:34:07 +02:00
100 changed files with 5337 additions and 2244 deletions

2
.gitignore vendored
View File

@@ -4,6 +4,8 @@
*.swp
*~$
cscope.*
compile_commands.json
/.clangd
tags
/build
/obj*

View File

@@ -4,9 +4,8 @@ variables:
CENTOS7_BUILD: buildenv-centos7
TUMBLEWEED_BUILD: buildenv-tumbleweed
MINGW_BUILD: buildenv-mingw
DEBIAN_CROSS_BUILD: buildenv-debian-cross
# torture_auth fails on centos7 docker images, so we don't use -DCLIENT_TESTING=ON
# pkd tests fail on CentOS7 docker images, so we don't use -DSERVER_TESTING=ON
centos7/openssl_1.0.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS7_BUILD
script:
@@ -14,7 +13,7 @@ centos7/openssl_1.0.x/x86_64:
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON .. &&
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
@@ -34,6 +33,7 @@ fedora/openssl_1.1.x/x86_64:
-DPICKY_DEVELOPER=ON
-DWITH_BLOWFISH_CIPHER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DWITH_DEBUG_CRYPTO=ON
-DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
@@ -168,8 +168,7 @@ fedora/csbuild:
- csbuild
--build-dir=obj-csbuild
--prep-cmd="rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@"
--build-cmd "make clean && make -j$(nproc)"
--build-cmd "rm -rf CMakeFiles CMakeCache.txt && cmake -DCMAKE_BUILD_TYPE=Debug -DPICKY_DEVELOPER=ON -DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DFUZZ_TESTING=ON @SRCDIR@ && make clean && make -j$(nproc)"
--git-commit-range $CI_COMMIT_RANGE
--color
--print-current --print-fixed
@@ -215,7 +214,7 @@ fedora/libgcrypt/x86_64:
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
-DWITH_GCRYPT=ON .. &&
-DWITH_GCRYPT=ON -DWITH_DEBUG_CRYPTO=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
@@ -235,7 +234,7 @@ fedora/mbedtls/x86_64:
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON
-DWITH_MBEDTLS=ON .. &&
-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
@@ -295,33 +294,6 @@ fedora/mingw32:
paths:
- obj/
.Debian.cross.template: &Debian_cross_template
stage: test
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$DEBIAN_CROSS_BUILD
script:
- build=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
- host="${CI_JOB_NAME#*.cross.}"
- mkdir -p obj && cd obj && cmake
-DCMAKE_C_COMPILER="$(which $host-gcc)"
-DCMAKE_CXX_COMPILER="$(which $host-g++)"
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DUNIT_TESTING=ON -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON
-DWITH_PCAP=ON .. &&
make -j$(nproc) &&
ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
.Debian.cross.mips-linux-gnu:
<<: *Debian_cross_template
tumbleweed/openssl_1.1.x/x86_64/gcc:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
script:
@@ -330,7 +302,7 @@ tumbleweed/openssl_1.1.x/x86_64/gcc:
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
@@ -371,7 +343,7 @@ tumbleweed/openssl_1.1.x/x86_64/gcc7:
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
@@ -413,7 +385,8 @@ tumbleweed/openssl_1.1.x/x86_64/clang:
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
-DUNIT_TESTING=ON
-DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
@@ -446,7 +419,7 @@ tumbleweed/undefined-sanitizer:
-DCMAKE_BUILD_TYPE=UndefinedSanitizer
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
@@ -468,7 +441,7 @@ tumbleweed/static-analysis:
-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
-DUNIT_TESTING=ON -DSERVER_TESTING=ON .. &&
scan-build --status-bugs -o scan make -j$(nproc)
tags:
- shared

View File

@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
include(DefineCMakeDefaults)
include(DefineCompilerFlags)
project(libssh VERSION 0.8.90 LANGUAGES C)
project(libssh VERSION 0.9.2 LANGUAGES C)
# global needed variable
set(APPLICATION_NAME ${PROJECT_NAME})
@@ -22,16 +22,16 @@ set(APPLICATION_NAME ${PROJECT_NAME})
# Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes:
# Increment REVISION.
set(LIBRARY_VERSION "4.8.1")
set(LIBRARY_VERSION "4.8.3")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
# add definitions
include(DefinePlatformDefaults)
include(DefineInstallationPaths)
include(DefineOptions.cmake)
include(CPackConfig.cmake)
include(GNUInstallDirs)
include(CompilerChecks.cmake)
@@ -117,7 +117,7 @@ install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/libssh.pc
DESTINATION
${LIB_INSTALL_DIR}/pkgconfig
${CMAKE_INSTALL_LIBDIR}/pkgconfig
COMPONENT
pkgconfig
)
@@ -133,21 +133,13 @@ write_basic_package_version_file(libssh-config-version.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion)
# libssh-config.cmake
configure_package_config_file(${PROJECT_NAME}-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
DESTINATION
${CMAKE_INSTALL_DIR}/${PROJECT_NAME}
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
COMPONENT
devel
)
devel)
if (WITH_EXAMPLES)
add_subdirectory(examples)
@@ -213,6 +205,11 @@ endif (WITH_SYMBOL_VERSIONING AND ABIMAP_FOUND)
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source DEPENDS ${_SYMBOL_TARGET})
# Link compile database for clangd
execute_process(COMMAND cmake -E create_symlink
"${CMAKE_BINARY_DIR}/compile_commands.json"
"${CMAKE_SOURCE_DIR}/compile_commands.json")
message(STATUS "********************************************")
message(STATUS "********** ${PROJECT_NAME} build options : **********")
@@ -225,7 +222,7 @@ message(STATUS "Server support : ${WITH_SERVER}")
message(STATUS "GSSAPI support : ${WITH_GSSAPI}")
message(STATUS "GEX support : ${WITH_GEX}")
message(STATUS "Pcap debugging support : ${WITH_PCAP}")
message(STATUS "With static library: ${WITH_STATIC_LIB}")
message(STATUS "Build shared library: ${BUILD_SHARED_LIBS}")
message(STATUS "Unit testing: ${UNIT_TESTING}")
message(STATUS "Client code testing: ${CLIENT_TESTING}")
message(STATUS "Blowfish cipher support: ${WITH_BLOWFISH_CIPHER}")

View File

@@ -10,7 +10,7 @@ set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
# SOURCE GENERATOR
set(CPACK_SOURCE_GENERATOR "TXZ")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;.gitignore;/build*;/obj*;tags;cscope.*")
set(CPACK_SOURCE_IGNORE_FILES "~$;[.]swp$;/[.]git/;/[.]clangd/;.gitignore;/build*;/obj*;tags;cscope.*;compile_commands.json")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
### NSIS INSTALLER

View File

@@ -1,7 +1,26 @@
ChangeLog
==========
version 0.9.0 (released 2019-02-xx)
version 0.9.2 (released 2019-11-07)
* Fixed libssh-config.cmake
* Fixed issues with rsa algorithm negotiation (T191)
* Fixed detection of OpenSSL ed25519 support (T197)
version 0.9.1 (released 2019-10-25)
* Added support for Ed25519 via OpenSSL
* Added support for X25519 via OpenSSL
* Added support for localuser in Match keyword
* Fixed Match keyword to be case sensitive
* Fixed compilation with LibreSSL
* Fixed error report of channel open (T75)
* Fixed sftp documentation (T137)
* Fixed known_hosts parsing (T156)
* Fixed build issue with MinGW (T157)
* Fixed build with gcc 9 (T164)
* Fixed deprecation issues (T165)
* Fixed known_hosts directory creation (T166)
version 0.9.0 (released 2019-06-28)
* Added support for AES-GCM
* Added improved rekeying support
* Added performance improvements
@@ -11,10 +30,76 @@ version 0.9.0 (released 2019-02-xx)
* Added support for Encrypt-then-MAC mode
* Added support for parsing server side configuration file
* Added support for ECDSA/Ed25519 certificates
* Added FIPS 140-2 compatibility
* Improved known_hosts parsing
* Improved documentation
* Improved OpenSSL API usage for KEX, DH, and signatures
version 0.8.7 (released 2019-02-25)
* Fixed handling extension flags in the server implementation
* Fixed exporting ed25519 private keys
* Fixed corner cases for rsa-sha2 signatures
* Fixed some issues with connector
version 0.8.6 (released 2018-12-24)
* Fixed compilation issues with different OpenSSL versions
* Fixed StrictHostKeyChecking in new knownhosts API
* Fixed ssh_send_keepalive() with packet filter
* Fixed possible crash with knownhosts options
* Fixed issus with rekeying
* Fixed strong ECDSA keys
* Fixed some issues with rsa-sha2 extentions
* Fixed access violation in ssh_init() (static linking)
* Fixed ssh_channel_close() handling
version 0.8.5 (released 2018-10-29)
* Added support to get known_hosts locations with ssh_options_get()
* Fixed preferred algorithm for known hosts negotiations
* Fixed KEX with some server implementations (e.g. Cisco)
* Fixed issues with MSVC
* Fixed keyboard-interactive auth in server mode
(regression from CVE-2018-10933)
* Fixed gssapi auth in server mode (regression from CVE-2018-10933)
* Fixed socket fd handling with proxy command
* Fixed a memory leak with OpenSSL
version 0.8.4 (released 2018-10-16)
* Fixed CVE-2018-10933
* Fixed building without globbing support
* Fixed possible memory leaks
* Avoid SIGPIPE on sockets
version 0.8.3 (released 2018-09-21)
* Added support for rsa-sha2
* Added support to parse private keys in openssh container format
(other than ed25519)
* Added support for diffie-hellman-group18-sha512 and
diffie-hellman-group16-sha512
* Added ssh_get_fingerprint_hash()
* Added ssh_pki_export_privkey_base64()
* Added support for Match keyword in config file
* Improved performance and reduced memory footprint for sftp
* Fixed ecdsa publickey auth
* Fixed reading a closed channel
* Added support to announce posix-rename@openssh.com and
hardlink@openssh.com in the sftp server
version 0.8.2 (released 2018-08-30)
* Added sha256 fingerprints for pubkeys
* Improved compiler flag detection
* Fixed race condition in reading sftp messages
* Fixed doxygen generation and added modern style
* Fixed library initialization on Windows
* Fixed __bounded__ attribute detection
* Fixed a bug in the options parser
* Fixed documentation for new knwon_hosts API
version 0.8.1 (released 2018-08-13)
* Fixed version number in the header
* Fixed version number in pkg-config and cmake config
* Fixed library initialization
* Fixed attribute detection
version 0.8.0 (released 2018-08-10)
* Removed support for deprecated SSHv1 protocol
* Added new connector API for clients

View File

@@ -9,10 +9,7 @@ include(TestBigEndian)
set(PACKAGE ${PROJECT_NAME})
set(VERSION ${PROJECT_VERSION})
set(DATADIR ${DATA_INSTALL_DIR})
set(LIBDIR ${LIB_INSTALL_DIR})
set(PLUGINDIR "${PLUGIN_INSTALL_DIR}-${LIBRARY_SOVERSION}")
set(SYSCONFDIR ${SYSCONF_INSTALL_DIR})
set(SYSCONFDIR ${CMAKE_INSTALL_SYSCONFDIR})
set(BINARYDIR ${CMAKE_BINARY_DIR})
set(SOURCEDIR ${CMAKE_SOURCE_DIR})
@@ -131,12 +128,37 @@ if (OPENSSL_FOUND)
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(EVP_KDF_CTX_new_id HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(FIPS_mode HAVE_OPENSSL_FIPS_MODE)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(RAND_priv_bytes HAVE_OPENSSL_RAND_PRIV_BYTES)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(EVP_DigestSign HAVE_OPENSSL_EVP_DIGESTSIGN)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_function_exists(EVP_DigestVerify HAVE_OPENSSL_EVP_DIGESTVERIFY)
check_function_exists(OPENSSL_ia32cap_loc HAVE_OPENSSL_IA32CAP_LOC)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_symbol_exists(EVP_PKEY_ED25519 "openssl/evp.h" FOUND_OPENSSL_ED25519)
if (HAVE_OPENSSL_EVP_DIGESTSIGN AND HAVE_OPENSSL_EVP_DIGESTVERIFY AND
FOUND_OPENSSL_ED25519)
set(HAVE_OPENSSL_ED25519 1)
endif()
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
check_symbol_exists(EVP_PKEY_X25519 "openssl/evp.h" HAVE_OPENSSL_X25519)
unset(CMAKE_REQUIRED_INCLUDES)
unset(CMAKE_REQUIRED_LIBRARIES)
endif()

View File

@@ -2,7 +2,6 @@ option(WITH_GSSAPI "Build with GSSAPI support" ON)
option(WITH_ZLIB "Build with ZLIB support" ON)
option(WITH_SFTP "Build with SFTP support" ON)
option(WITH_SERVER "Build with SSH server support" ON)
option(WITH_STATIC_LIB "Build with a static library" OFF)
option(WITH_DEBUG_CRYPTO "Build with cryto debug output" OFF)
option(WITH_DEBUG_PACKET "Build with packet debug output" OFF)
option(WITH_DEBUG_CALLTRACE "Build with calltrace debug output" ON)
@@ -11,6 +10,7 @@ option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
option(WITH_PCAP "Compile with Pcap generation support" ON)
option(WITH_INTERNAL_DOC "Compile doxygen internal documentation" OFF)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(UNIT_TESTING "Build with unit tests" OFF)
option(CLIENT_TESTING "Build with client tests; requires openssh" OFF)
option(SERVER_TESTING "Build with server tests; requires openssh and dropbear" OFF)
@@ -34,13 +34,9 @@ if (WITH_BENCHMARKS)
set(CLIENT_TESTING ON)
endif()
if (WITH_STATIC_LIB)
set(BUILD_STATIC_LIB ON)
endif (WITH_STATIC_LIB)
if (UNIT_TESTING)
if (UNIT_TESTING OR CLIENT_TESTING OR SERVER_TESTING)
set(BUILD_STATIC_LIB ON)
endif (UNIT_TESTING)
endif()
if (WITH_NACL)
set(WITH_NACL ON)

View File

@@ -1,109 +0,0 @@
if (UNIX OR OS2)
IF (NOT APPLICATION_NAME)
MESSAGE(STATUS "${PROJECT_NAME} is used as APPLICATION_NAME")
SET(APPLICATION_NAME ${PROJECT_NAME})
ENDIF (NOT APPLICATION_NAME)
# Suffix for Linux
SET(LIB_SUFFIX
CACHE STRING "Define suffix of directory name (32/64)"
)
SET(EXEC_INSTALL_PREFIX
"${CMAKE_INSTALL_PREFIX}"
CACHE PATH "Base directory for executables and libraries"
)
SET(SHARE_INSTALL_PREFIX
"${CMAKE_INSTALL_PREFIX}/share"
CACHE PATH "Base directory for files which go to share/"
)
SET(DATA_INSTALL_PREFIX
"${SHARE_INSTALL_PREFIX}/${APPLICATION_NAME}"
CACHE PATH "The parent directory where applications can install their data")
# The following are directories where stuff will be installed to
SET(BIN_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/bin"
CACHE PATH "The ${APPLICATION_NAME} binary install dir (default prefix/bin)"
)
SET(SBIN_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/sbin"
CACHE PATH "The ${APPLICATION_NAME} sbin install dir (default prefix/sbin)"
)
SET(LIB_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}"
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/lib)"
)
SET(LIBEXEC_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/libexec"
CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is prefix/libexec)"
)
SET(PLUGIN_INSTALL_DIR
"${LIB_INSTALL_DIR}/${APPLICATION_NAME}"
CACHE PATH "The subdirectory relative to the install prefix where plugins will be installed (default is prefix/lib/${APPLICATION_NAME})"
)
SET(INCLUDE_INSTALL_DIR
"${CMAKE_INSTALL_PREFIX}/include"
CACHE PATH "The subdirectory to the header prefix (default prefix/include)"
)
set(CMAKE_INSTALL_DIR
"${LIB_INSTALL_DIR}/cmake"
CACHE PATH "The subdirectory to install cmake config files")
SET(DATA_INSTALL_DIR
"${DATA_INSTALL_PREFIX}"
CACHE PATH "The parent directory where applications can install their data (default prefix/share/${APPLICATION_NAME})"
)
SET(HTML_INSTALL_DIR
"${DATA_INSTALL_PREFIX}/doc/HTML"
CACHE PATH "The HTML install dir for documentation (default data/doc/html)"
)
SET(ICON_INSTALL_DIR
"${DATA_INSTALL_PREFIX}/icons"
CACHE PATH "The icon install dir (default data/icons/)"
)
SET(SOUND_INSTALL_DIR
"${DATA_INSTALL_PREFIX}/sounds"
CACHE PATH "The install dir for sound files (default data/sounds)"
)
SET(LOCALE_INSTALL_DIR
"${SHARE_INSTALL_PREFIX}/locale"
CACHE PATH "The install dir for translations (default prefix/share/locale)"
)
SET(XDG_APPS_DIR
"${SHARE_INSTALL_PREFIX}/applications/"
CACHE PATH "The XDG apps dir"
)
SET(XDG_DIRECTORY_DIR
"${SHARE_INSTALL_PREFIX}/desktop-directories"
CACHE PATH "The XDG directory"
)
SET(SYSCONF_INSTALL_DIR
"${EXEC_INSTALL_PREFIX}/etc"
CACHE PATH "The ${APPLICATION_NAME} sysconfig install dir (default prefix/etc)"
)
SET(MAN_INSTALL_DIR
"${SHARE_INSTALL_PREFIX}/man"
CACHE PATH "The ${APPLICATION_NAME} man install dir (default prefix/man)"
)
SET(INFO_INSTALL_DIR
"${SHARE_INSTALL_PREFIX}/info"
CACHE PATH "The ${APPLICATION_NAME} info install dir (default prefix/info)"
)
else()
# Same same
set(BIN_INSTALL_DIR "bin" CACHE PATH "-")
set(SBIN_INSTALL_DIR "sbin" CACHE PATH "-")
set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "-")
set(INCLUDE_INSTALL_DIR "include" CACHE PATH "-")
set(CMAKE_INSTALL_DIR "CMake" CACHE PATH "-")
set(PLUGIN_INSTALL_DIR "plugins" CACHE PATH "-")
set(HTML_INSTALL_DIR "doc/HTML" CACHE PATH "-")
set(ICON_INSTALL_DIR "icons" CACHE PATH "-")
set(SOUND_INSTALL_DIR "soudns" CACHE PATH "-")
set(LOCALE_INSTALL_DIR "lang" CACHE PATH "-")
endif ()

View File

@@ -4,10 +4,6 @@
/* Version number of package */
#cmakedefine VERSION "${PROJECT_VERSION}"
#cmakedefine LOCALEDIR "${LOCALE_INSTALL_DIR}"
#cmakedefine DATADIR "${DATADIR}"
#cmakedefine LIBDIR "${LIBDIR}"
#cmakedefine PLUGINDIR "${PLUGINDIR}"
#cmakedefine SYSCONFDIR "${SYSCONFDIR}"
#cmakedefine BINARYDIR "${BINARYDIR}"
#cmakedefine SOURCEDIR "${SOURCEDIR}"
@@ -101,6 +97,12 @@
/* Define to 1 if you have gl_flags as a glob_t sturct member */
#cmakedefine HAVE_GLOB_GL_FLAGS_MEMBER 1
/* Define to 1 if you have OpenSSL with Ed25519 support */
#cmakedefine HAVE_OPENSSL_ED25519 1
/* Define to 1 if you have OpenSSL with X25519 support */
#cmakedefine HAVE_OPENSSL_X25519 1
/*************************** FUNCTIONS ***************************/
/* Define to 1 if you have the `EVP_aes128_ctr' function. */
@@ -124,6 +126,15 @@
/* Define to 1 if you have the `EVP_KDF_CTX_new_id' function. */
#cmakedefine HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID 1
/* Define to 1 if you have the `FIPS_mode' function. */
#cmakedefine HAVE_OPENSSL_FIPS_MODE 1
/* Define to 1 if you have the `EVP_DigestSign' function. */
#cmakedefine HAVE_OPENSSL_EVP_DIGESTSIGN 1
/* Define to 1 if you have the `EVP_DigestVerify' function. */
#cmakedefine HAVE_OPENSSL_EVP_DIGESTVERIFY 1
/* Define to 1 if you have the `OPENSSL_ia32cap_loc' function. */
#cmakedefine HAVE_OPENSSL_IA32CAP_LOC 1

View File

@@ -6,10 +6,7 @@ set(examples_SRCS
connect_ssh.c
)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}
)
include_directories(${libssh_BINARY_DIR})
if (ARGP_INCLUDE_DIR)
include_directories(${ARGP_INCLUDE_DIR})
@@ -18,68 +15,68 @@ endif()
if (UNIX AND NOT WIN32)
add_executable(libssh_scp libssh_scp.c ${examples_SRCS})
target_compile_options(libssh_scp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(libssh_scp ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(libssh_scp ssh::ssh)
add_executable(scp_download scp_download.c ${examples_SRCS})
target_compile_options(scp_download PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(scp_download ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(scp_download ssh::ssh)
add_executable(sshnetcat sshnetcat.c ${examples_SRCS})
target_compile_options(sshnetcat PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(sshnetcat ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(sshnetcat ssh::ssh)
if (WITH_SFTP)
add_executable(samplesftp samplesftp.c ${examples_SRCS})
target_compile_options(samplesftp PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(samplesftp ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(samplesftp ssh::ssh)
endif (WITH_SFTP)
add_executable(ssh-client ssh_client.c ${examples_SRCS})
target_compile_options(ssh-client PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(ssh-client ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(ssh-client ssh::ssh)
if (WITH_SERVER AND (ARGP_LIBRARY OR HAVE_ARGP_H))
if (HAVE_LIBUTIL)
add_executable(ssh_server_fork ssh_server_fork.c)
target_compile_options(ssh_server_fork PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(ssh_server_fork ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY} util)
target_link_libraries(ssh_server_fork ssh::ssh ${ARGP_LIBRARY} util)
endif (HAVE_LIBUTIL)
if (WITH_GSSAPI AND GSSAPI_FOUND)
add_executable(samplesshd-cb samplesshd-cb.c)
target_compile_options(samplesshd-cb PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(samplesshd-cb ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
target_link_libraries(samplesshd-cb ssh::ssh ${ARGP_LIBRARY})
add_executable(proxy proxy.c)
target_compile_options(proxy PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(proxy ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
target_link_libraries(proxy ssh::ssh ${ARGP_LIBRARY})
add_executable(sshd_direct-tcpip sshd_direct-tcpip.c)
target_compile_options(sshd_direct-tcpip PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(sshd_direct-tcpip ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
target_link_libraries(sshd_direct-tcpip ssh::ssh ${ARGP_LIBRARY})
endif (WITH_GSSAPI AND GSSAPI_FOUND)
add_executable(samplesshd-kbdint samplesshd-kbdint.c)
target_compile_options(samplesshd-kbdint PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(samplesshd-kbdint ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARY})
target_link_libraries(samplesshd-kbdint ssh::ssh ${ARGP_LIBRARY})
endif()
endif (UNIX AND NOT WIN32)
add_executable(exec exec.c ${examples_SRCS})
target_compile_options(exec PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(exec ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(exec ssh::ssh)
add_executable(senddata senddata.c ${examples_SRCS})
target_compile_options(senddata PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(senddata ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(senddata ssh::ssh)
add_executable(keygen keygen.c)
target_compile_options(keygen PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(keygen ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(keygen ssh::ssh)
add_executable(libsshpp libsshpp.cpp)
target_link_libraries(libsshpp ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(libsshpp ssh::ssh)
add_executable(libsshpp_noexcept libsshpp_noexcept.cpp)
target_link_libraries(libsshpp_noexcept ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(libsshpp_noexcept ssh::ssh)

View File

@@ -1,16 +1,17 @@
/* client.c */
/* ssh_client.c */
/*
Copyright 2003-2009 Aris Adamantiadis
This file is part of the SSH Library
You are free to copy this file, modify it in any way, consider it being public
domain. This does not apply to the rest of the library though, but it is
allowed to cut-and-paste working code from this file to any license of
program.
The goal is to show the API in action. It's not a reference on how terminal
clients must be made or how a client should react.
*/
* Copyright 2003-2015 Aris Adamantiadis
*
* This file is part of the SSH Library
*
* You are free to copy this file, modify it in any way, consider it being public
* domain. This does not apply to the rest of the library though, but it is
* allowed to cut-and-paste working code from this file to any license of
* program.
* The goal is to show the API in action. It's not a reference on how terminal
* clients must be made or how a client should react.
*/
#include "config.h"
#include <stdio.h>
@@ -197,19 +198,20 @@ static void sizechanged(void)
static void select_loop(ssh_session session,ssh_channel channel)
{
ssh_connector connector_in, connector_out, connector_err;
int rc;
ssh_event event = ssh_event_new();
/* stdin */
connector_in = ssh_connector_new(session);
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDOUT);
ssh_connector_set_out_channel(connector_in, channel, SSH_CONNECTOR_STDINOUT);
ssh_connector_set_in_fd(connector_in, 0);
ssh_event_add_connector(event, connector_in);
/* stdout */
connector_out = ssh_connector_new(session);
ssh_connector_set_out_fd(connector_out, 1);
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDOUT);
ssh_connector_set_in_channel(connector_out, channel, SSH_CONNECTOR_STDINOUT);
ssh_event_add_connector(event, connector_out);
/* stderr */
@@ -222,7 +224,11 @@ static void select_loop(ssh_session session,ssh_channel channel)
if (signal_delayed) {
sizechanged();
}
ssh_event_dopoll(event, 60000);
rc = ssh_event_dopoll(event, 60000);
if (rc == SSH_ERROR) {
fprintf(stderr, "Error in ssh_event_dopoll()\n");
break;
}
}
ssh_event_remove_connector(event, connector_in);
ssh_event_remove_connector(event, connector_out);
@@ -233,7 +239,6 @@ static void select_loop(ssh_session session,ssh_channel channel)
ssh_connector_free(connector_err);
ssh_event_free(event);
ssh_channel_free(channel);
}
static void shell(ssh_session session)
@@ -241,7 +246,11 @@ static void shell(ssh_session session)
ssh_channel channel;
struct termios terminal_local;
int interactive=isatty(0);
channel = ssh_channel_new(session);
if (channel == NULL) {
return;
}
if (interactive) {
tcgetattr(0, &terminal_local);
@@ -250,6 +259,7 @@ static void shell(ssh_session session)
if (ssh_channel_open_session(channel)) {
printf("Error opening channel : %s\n", ssh_get_error(session));
ssh_channel_free(channel);
return;
}
chan = channel;
@@ -260,6 +270,7 @@ static void shell(ssh_session session)
if (ssh_channel_request_shell(channel)) {
printf("Requesting shell : %s\n", ssh_get_error(session));
ssh_channel_free(channel);
return;
}
@@ -273,6 +284,7 @@ static void shell(ssh_session session)
if (interactive) {
do_cleanup(0);
}
ssh_channel_free(channel);
}
static void batch_shell(ssh_session session)
@@ -289,12 +301,18 @@ static void batch_shell(ssh_session session)
}
channel = ssh_channel_new(session);
if (channel == NULL) {
return;
}
ssh_channel_open_session(channel);
if (ssh_channel_request_exec(channel, buffer)) {
printf("Error executing '%s' : %s\n", buffer, ssh_get_error(session));
ssh_channel_free(channel);
return;
}
select_loop(session, channel);
ssh_channel_free(channel);
}
static int client(ssh_session session)

View File

@@ -70,6 +70,8 @@ static void set_default_keys(ssh_bind sshbind,
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY,
KEYS_FOLDER "ssh_host_ecdsa_key");
}
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY,
KEYS_FOLDER "ssh_host_ed25519_key");
}
#define DEF_STR_SIZE 1024
char authorizedkeys[DEF_STR_SIZE] = {0};

View File

@@ -26,7 +26,7 @@ install(
FILES
${libssh_HDRS}
DESTINATION
${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}
${CMAKE_INSTALL_INCLUDEDIR}/${APPLICATION_NAME}
COMPONENT
headers
)

View File

@@ -27,7 +27,7 @@
bignum ssh_make_string_bn(ssh_string string);
ssh_string ssh_make_bignum_string(bignum num);
void ssh_print_bignum(const char *which, const bignum num);
void ssh_print_bignum(const char *which, const_bignum num);
#endif /* BIGNUM_H_ */

View File

@@ -48,6 +48,8 @@ int ssh_dh_keypair_set_keys(struct dh_ctx *ctx, int peer,
int ssh_dh_compute_shared_secret(struct dh_ctx *ctx, int local, int remote,
bignum *dest);
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c);
/* common functions */
int ssh_dh_init(void);
void ssh_dh_finalize(void);

View File

@@ -23,6 +23,7 @@
#define SSH_KNOWNHOSTS_H_
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
char *ssh_known_hosts_get_algorithms_names(ssh_session session);
enum ssh_known_hosts_e
ssh_session_get_known_hosts_entry_file(ssh_session session,
const char *filename,

View File

@@ -112,7 +112,11 @@ typedef BN_CTX* bignum_CTX;
/* Returns true if the OpenSSL is operating in FIPS mode */
#ifdef HAVE_OPENSSL_FIPS_MODE
#define ssh_fips_mode() (FIPS_mode() != 0)
#else
#define ssh_fips_mode() false
#endif
#endif /* HAVE_LIBCRYPTO */

View File

@@ -78,7 +78,10 @@ int ssh_gcry_rand_range(bignum rnd, bignum max);
#define bignum_bin2bn(data,datalen,dest) gcry_mpi_scan(dest,GCRYMPI_FMT_USG,data,datalen,NULL)
#define bignum_bn2dec(num) ssh_gcry_bn2dec(num)
#define bignum_dec2bn(num, data) ssh_gcry_dec2bn(data, num)
#define bignum_bn2hex(num,data) gcry_mpi_aprint(GCRYMPI_FMT_HEX,data,NULL,num)
#define bignum_bn2hex(num, data) \
gcry_mpi_aprint(GCRYMPI_FMT_HEX, data, NULL, (const gcry_mpi_t)num)
#define bignum_hex2bn(data, num) (gcry_mpi_scan(num,GCRYMPI_FMT_HEX,data,0,NULL)==0?1:0)
#define bignum_rand(num,bits) 1,gcry_mpi_randomize(num,bits,GCRY_STRONG_RANDOM),gcry_mpi_set_bit(num,bits-1),gcry_mpi_set_bit(num,0)
#define bignum_mod_exp(dest,generator,exp,modulo, ctx) 1,gcry_mpi_powm(dest,generator,exp,modulo)

View File

@@ -75,7 +75,7 @@ struct mbedtls_ecdsa_sig {
bignum ssh_mbedcry_bn_new(void);
void ssh_mbedcry_bn_free(bignum num);
unsigned char *ssh_mbedcry_bn2num(bignum num, int radix);
unsigned char *ssh_mbedcry_bn2num(const_bignum num, int radix);
int ssh_mbedcry_rand(bignum rnd, int bits, int top, int bottom);
int ssh_mbedcry_is_bit_set(bignum num, size_t pos);
int ssh_mbedcry_rand_range(bignum dest, bignum max);

View File

@@ -78,8 +78,8 @@
/* libssh version */
#define LIBSSH_VERSION_MAJOR 0
#define LIBSSH_VERSION_MINOR 8
#define LIBSSH_VERSION_MICRO 90
#define LIBSSH_VERSION_MINOR 9
#define LIBSSH_VERSION_MICRO 2
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
LIBSSH_VERSION_MINOR, \
@@ -441,6 +441,7 @@ enum ssh_scp_request_types {
enum ssh_connector_flags_e {
/** Only the standard stream of the channel */
SSH_CONNECTOR_STDOUT = 1,
SSH_CONNECTOR_STDINOUT = 1,
/** Only the exception stream of the channel */
SSH_CONNECTOR_STDERR = 2,
/** Merge both standard and exception streams */

View File

@@ -26,6 +26,7 @@
char *ssh_get_user_home_dir(void);
char *ssh_get_local_username(void);
int ssh_file_readaccess_ok(const char *file);
int ssh_dir_writeable(const char *path);
char *ssh_path_expand_tilde(const char *d);
char *ssh_path_expand_escape(ssh_session session, const char *s);
@@ -83,4 +84,8 @@ int ssh_match_group(const char *group, const char *object);
void uint64_inc(unsigned char *counter);
void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len);
int ssh_mkdirs(const char *pathname, mode_t mode);
#endif /* MISC_H_ */

View File

@@ -30,7 +30,15 @@
#endif
#include "libssh/crypto.h"
#ifdef HAVE_OPENSSL_ED25519
/* If using OpenSSL implementation, define the signature lenght which would be
* defined in libssh/ed25519.h otherwise */
#define ED25519_SIG_LEN 64
#else
#include "libssh/ed25519.h"
#endif
/* This definition is used for both OpenSSL and internal implementations */
#define ED25519_KEY_LEN 32
#define MAX_PUBKEY_SIZE 0x100000 /* 1M */
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
@@ -61,8 +69,13 @@ struct ssh_key_struct {
void *ecdsa;
# endif /* HAVE_OPENSSL_EC_H */
#endif /* HAVE_LIBGCRYPT */
#ifdef HAVE_OPENSSL_ED25519
uint8_t *ed25519_pubkey;
uint8_t *ed25519_privkey;
#else
ed25519_pubkey *ed25519_pubkey;
ed25519_privkey *ed25519_privkey;
#endif
void *cert;
enum ssh_keytypes_e cert_type;
};
@@ -79,7 +92,9 @@ struct ssh_signature_struct {
ssh_string rsa_sig;
struct mbedtls_ecdsa_sig ecdsa_sig;
#endif /* HAVE_LIBGCRYPT */
#ifndef HAVE_OPENSSL_ED25519
ed25519_signature *ed25519_sig;
#endif
ssh_string raw_sig;
};
@@ -96,6 +111,7 @@ enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name);
enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type);
enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
enum ssh_keytypes_e type);
enum ssh_digest_e ssh_key_hash_from_name(const char *name);
#define is_ecdsa_key_type(t) \
((t) >= SSH_KEYTYPE_ECDSA_P256 && (t) <= SSH_KEYTYPE_ECDSA_P521)
@@ -118,7 +134,7 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob,
int ssh_pki_signature_verify(ssh_session session,
ssh_signature sig,
const ssh_key key,
unsigned char *digest,
const unsigned char *digest,
size_t dlen);
/* SSH Public Key Functions */
@@ -138,7 +154,8 @@ ssh_string ssh_pki_do_sign_agent(ssh_session session,
struct ssh_buffer_struct *buf,
const ssh_key pubkey);
ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
const ssh_key privkey);
const ssh_key privkey,
const enum ssh_digest_e digest);
/* Temporary functions, to be removed after migration to ssh_key */
ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key);

View File

@@ -124,11 +124,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
const ssh_string sig_blob,
enum ssh_keytypes_e type,
enum ssh_digest_e hash_type);
int pki_signature_verify(ssh_session session,
const ssh_signature sig,
const ssh_key key,
const unsigned char *input,
size_t input_len);
/* SSH Signing Functions */
ssh_signature pki_do_sign(const ssh_key privkey,
@@ -148,8 +143,8 @@ int pki_ed25519_key_cmp(const ssh_key k1,
enum ssh_keycmp_e what);
int pki_ed25519_key_dup(ssh_key new, const ssh_key key);
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
ssh_string pki_ed25519_sig_to_blob(ssh_signature sig);
int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob);
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig);
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey,
ssh_string privkey);

View File

@@ -221,7 +221,17 @@ int gettimeofday(struct timeval *__p, void *__t);
struct ssh_common_struct;
struct ssh_kex_struct;
int ssh_get_key_params(ssh_session session, ssh_key *privkey);
enum ssh_digest_e {
SSH_DIGEST_AUTO=0,
SSH_DIGEST_SHA1=1,
SSH_DIGEST_SHA256,
SSH_DIGEST_SHA384,
SSH_DIGEST_SHA512,
};
int ssh_get_key_params(ssh_session session,
ssh_key *privkey,
enum ssh_digest_e *digest);
/* LOGGING */
void ssh_log_function(int verbosity,
@@ -272,8 +282,6 @@ int ssh_auth_reply_success(ssh_session session, int partial);
int ssh_send_banner(ssh_session session, int is_server);
/* connect.c */
socket_t ssh_connect_host(ssh_session session, const char *host,const char
*bind_addr, int port, long timeout, long usec);
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
const char *bind_addr, int port);

View File

@@ -188,6 +188,7 @@ struct ssh_session_struct {
ssh_key ed25519_key;
/* The type of host key wanted by client */
enum ssh_keytypes_e hostkey;
enum ssh_digest_e hostkey_digest;
} srv;
/* auths accepted by server */

View File

@@ -201,13 +201,18 @@ struct sftp_statvfs_struct {
};
/**
* @brief Start a new sftp session.
* @brief Creates a new sftp session.
*
* This function creates a new sftp session and allocates a new sftp channel
* with the server inside of the provided ssh session. This function call is
* usually followed by the sftp_init(), which initializes SFTP protocol itself.
*
* @param session The ssh session to use.
*
* @return A new sftp session or NULL on error.
*
* @see sftp_free()
* @see sftp_init()
*/
LIBSSH_API sftp_session sftp_new(ssh_session session);
@@ -232,7 +237,10 @@ LIBSSH_API sftp_session sftp_new_channel(ssh_session session, ssh_channel channe
LIBSSH_API void sftp_free(sftp_session sftp);
/**
* @brief Initialize the sftp session with the server.
* @brief Initialize the sftp protocol with the server.
*
* This function involves the SFTP protocol initialization (as described
* in the SFTP specification), including the version and extensions negotiation.
*
* @param sftp The sftp session to initialize.
*

View File

@@ -38,7 +38,11 @@ void ssh_tokens_free(struct ssh_tokens_st *tokens);
char *ssh_find_matching(const char *available_d,
const char *preferred_d);
char *ssh_find_all_matching(const char *available_d,
const char *preferred_d);
char *ssh_remove_duplicates(const char *list);
char *ssh_append_without_duplicates(const char *list,
const char *appended_list);
#endif /* TOKEN_H_ */

View File

@@ -29,14 +29,6 @@
#include "libssh/libgcrypt.h"
#include "libssh/libmbedcrypto.h"
enum ssh_digest_e {
SSH_DIGEST_AUTO=0,
SSH_DIGEST_SHA1=1,
SSH_DIGEST_SHA256,
SSH_DIGEST_SHA384,
SSH_DIGEST_SHA512,
};
enum ssh_kdf_digest {
SSH_KDF_SHA1=1,
SSH_KDF_SHA256,

View File

@@ -1,15 +0,0 @@
@PACKAGE_INIT@
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/CMakeCache.txt")
# In tree build
set_and_check(LIBSSH_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}/include")
set_and_check(LIBSSH_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/lib/@LIBSSH_LIBRARY_NAME@")
else()
set_and_check(LIBSSH_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(LIBSSH_LIBRARIES "@PACKAGE_LIB_INSTALL_DIR@/@LIBSSH_LIBRARY_NAME@")
endif()
# For backward compatibility
set(LIBSSH_LIBRARY ${LIBSSH_LIBRARIES})
mark_as_advanced(LIBSSH_LIBRARIES LIBSSH_LIBRARY LIBSSH_INCLUDE_DIR)

View File

@@ -1,6 +1,6 @@
Name: ${PROJECT_NAME}
Description: The SSH Library
Version: ${PROJECT_VERSION}
Libs: -L${LIB_INSTALL_DIR} -lssh
Cflags: -I${INCLUDE_INSTALL_DIR}
Libs: -L${CMAKE_INSTALL_FULL_LIBDIR} -lssh
Cflags: -I${CMAKE_INSTALL_FULL_INCLUDEDIR}

View File

@@ -1,200 +0,0 @@
#!/bin/bash
#
# Last Change: 2008-06-18 14:13:46
#
# Script to build libssh on UNIX.
#
# Copyright (c) 2006-2007 Andreas Schneider <asn@cryptomilk.org>
#
SOURCE_DIR=".."
LANG=C
export LANG
SCRIPT="$0"
COUNT=0
while [ -L "${SCRIPT}" ]
do
SCRIPT=$(readlink ${SCRIPT})
COUNT=$(expr ${COUNT} + 1)
if [ ${COUNT} -gt 100 ]; then
echo "Too many symbolic links"
exit 1
fi
done
BUILDDIR=$(dirname ${SCRIPT})
cleanup_and_exit () {
if test "$1" = 0 -o -z "$1" ; then
exit 0
else
exit $1
fi
}
function configure() {
if [ -n "${CMAKEDIR}" ]; then
${CMAKEDIR}/bin/cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
else
cmake "$@" ${SOURCE_DIR} || cleanup_and_exit $?
fi
}
function compile() {
if [ -f /proc/cpuinfo ]; then
CPUCOUNT=$(grep -c processor /proc/cpuinfo)
elif test `uname` = "SunOS" ; then
CPUCOUNT=$(psrinfo -p)
else
CPUCOUNT="1"
fi
if [ "${CPUCOUNT}" -gt "1" ]; then
${MAKE} -j${CPUCOUNT} $1 || cleanup_and_exit $?
else
${MAKE} $1 || exit $?
fi
}
function clean_build_dir() {
find ! -path "*.svn*" ! -name "*.bat" ! -name "*.sh" ! -name "." -print0 | xargs -0 rm -rf
}
function usage () {
echo "Usage: `basename $0` [--prefix /install_prefix|--build [debug|final]|--clean|--verbose|--libsuffix (32|64)|--help|--clang|--cmakedir /directory|--make
(gmake|make)|--ccompiler(gcc|cc)|--withstaticlib|--unittesting|--clientunittesting|--withserver|--withoutsymbolversioning]"
cleanup_and_exit
}
cd ${BUILDDIR}
# the default CMake options:
OPTIONS="--graphviz=${BUILDDIR}/libssh.dot"
# the default 'make' utility:
MAKE="make"
while test -n "$1"; do
PARAM="$1"
ARG="$2"
shift
case ${PARAM} in
*-*=*)
ARG=${PARAM#*=}
PARAM=${PARAM%%=*}
set -- "----noarg=${PARAM}" "$@"
esac
case ${PARAM} in
*-help|-h)
#echo_help
usage
cleanup_and_exit
;;
*-build)
DOMAKE="1"
BUILD_TYPE="${ARG}"
test -n "${BUILD_TYPE}" && shift
;;
*-clean)
clean_build_dir
cleanup_and_exit
;;
*-clang)
OPTIONS="${OPTIONS} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
;;
*-verbose)
DOVERBOSE="1"
;;
*-memtest)
OPTIONS="${OPTIONS} -DMEM_NULL_TESTS=ON"
;;
*-libsuffix)
OPTIONS="${OPTIONS} -DLIB_SUFFIX=${ARG}"
shift
;;
*-prefix)
OPTIONS="${OPTIONS} -DCMAKE_INSTALL_PREFIX=${ARG}"
shift
;;
*-sysconfdir)
OPTIONS="${OPTIONS} -DSYSCONF_INSTALL_DIR=${ARG}"
shift
;;
*-cmakedir)
CMAKEDIR="${ARG}"
shift
;;
*-make)
MAKE="${ARG}"
shift
;;
*-ccompiler)
OPTIONS="${OPTIONS} -DCMAKE_C_COMPILER=${ARG}"
shift
;;
*-withstaticlib)
OPTIONS="${OPTIONS} -DWITH_STATIC_LIB=ON"
;;
*-unittesting)
OPTIONS="${OPTIONS} -DUNIT_TESTING=ON"
;;
*-clientunittesting)
OPTIONS="${OPTIONS} -DCLIENT_TESTING=ON"
;;
*-withserver)
OPTIONS="${OPTIONS} -DWITH_SERVER=ON"
;;
*-withoutsymbolversioning)
OPTIONS="${OPTIONS} -DWITH_SYMBOL_VERSIONING=OFF"
;;
*-finalrelease)
OPTIONS="${OPTIONS} -DWITH_FINAL=ON"
;;
----noarg)
echo "$ARG does not take an argument"
cleanup_and_exit
;;
-*)
echo Unknown Option "$PARAM". Exit.
cleanup_and_exit 1
;;
*)
usage
;;
esac
done
if [ "${DOMAKE}" == "1" ]; then
OPTIONS="${OPTIONS} -DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
fi
if [ -n "${DOVERBOSE}" ]; then
OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=1"
else
OPTIONS="${OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=0"
fi
test -f "${BUILDDIR}/.build.log" && rm -f ${BUILDDIR}/.build.log
touch ${BUILDDIR}/.build.log
# log everything from here to .build.log
exec 1> >(exec -a 'build logging tee' tee -a ${BUILDDIR}/.build.log) 2>&1
echo "${HOST} started build at $(date)."
echo
configure ${OPTIONS} "$@"
if [ -n "${DOMAKE}" ]; then
test -n "${DOVERBOSE}" && compile VERBOSE=1 || compile
fi
DOT=$(which dot 2>/dev/null)
if [ -n "${DOT}" ]; then
${DOT} -Tpng -o${BUILDDIR}/libssh.png ${BUILDDIR}/libssh.dot
${DOT} -Tsvg -o${BUILDDIR}/libssh.svg ${BUILDDIR}/libssh.dot
fi
exec >&0 2>&0 # so that the logging tee finishes
sleep 1 # wait till tee terminates
cleanup_and_exit 0

View File

@@ -1 +1 @@
4.8.1
4.8.3

View File

@@ -0,0 +1,421 @@
_ssh_log
buffer_free
buffer_get
buffer_get_len
buffer_new
channel_accept_x11
channel_change_pty_size
channel_close
channel_forward_accept
channel_forward_cancel
channel_forward_listen
channel_free
channel_get_exit_status
channel_get_session
channel_is_closed
channel_is_eof
channel_is_open
channel_new
channel_open_forward
channel_open_session
channel_poll
channel_read
channel_read_buffer
channel_read_nonblocking
channel_request_env
channel_request_exec
channel_request_pty
channel_request_pty_size
channel_request_send_signal
channel_request_sftp
channel_request_shell
channel_request_subsystem
channel_request_x11
channel_select
channel_send_eof
channel_set_blocking
channel_write
channel_write_stderr
privatekey_free
privatekey_from_file
publickey_free
publickey_from_file
publickey_from_privatekey
publickey_to_string
sftp_async_read
sftp_async_read_begin
sftp_attributes_free
sftp_canonicalize_path
sftp_chmod
sftp_chown
sftp_client_message_free
sftp_client_message_get_data
sftp_client_message_get_filename
sftp_client_message_get_flags
sftp_client_message_get_submessage
sftp_client_message_get_type
sftp_client_message_set_filename
sftp_close
sftp_closedir
sftp_dir_eof
sftp_extension_supported
sftp_extensions_get_count
sftp_extensions_get_data
sftp_extensions_get_name
sftp_file_set_blocking
sftp_file_set_nonblocking
sftp_free
sftp_fstat
sftp_fstatvfs
sftp_fsync
sftp_get_client_message
sftp_get_error
sftp_handle
sftp_handle_alloc
sftp_handle_remove
sftp_init
sftp_lstat
sftp_mkdir
sftp_new
sftp_new_channel
sftp_open
sftp_opendir
sftp_read
sftp_readdir
sftp_readlink
sftp_rename
sftp_reply_attr
sftp_reply_data
sftp_reply_handle
sftp_reply_name
sftp_reply_names
sftp_reply_names_add
sftp_reply_status
sftp_rewind
sftp_rmdir
sftp_seek
sftp_seek64
sftp_send_client_message
sftp_server_free
sftp_server_init
sftp_server_new
sftp_server_version
sftp_setstat
sftp_stat
sftp_statvfs
sftp_statvfs_free
sftp_symlink
sftp_tell
sftp_tell64
sftp_unlink
sftp_utimes
sftp_write
ssh_accept
ssh_add_channel_callbacks
ssh_auth_list
ssh_basename
ssh_bind_accept
ssh_bind_accept_fd
ssh_bind_fd_toaccept
ssh_bind_free
ssh_bind_get_fd
ssh_bind_listen
ssh_bind_new
ssh_bind_options_parse_config
ssh_bind_options_set
ssh_bind_set_blocking
ssh_bind_set_callbacks
ssh_bind_set_fd
ssh_blocking_flush
ssh_buffer_add_data
ssh_buffer_free
ssh_buffer_get
ssh_buffer_get_data
ssh_buffer_get_len
ssh_buffer_new
ssh_buffer_reinit
ssh_channel_accept_forward
ssh_channel_accept_x11
ssh_channel_cancel_forward
ssh_channel_change_pty_size
ssh_channel_close
ssh_channel_free
ssh_channel_get_exit_status
ssh_channel_get_session
ssh_channel_is_closed
ssh_channel_is_eof
ssh_channel_is_open
ssh_channel_listen_forward
ssh_channel_new
ssh_channel_open_auth_agent
ssh_channel_open_forward
ssh_channel_open_forward_unix
ssh_channel_open_reverse_forward
ssh_channel_open_session
ssh_channel_open_x11
ssh_channel_poll
ssh_channel_poll_timeout
ssh_channel_read
ssh_channel_read_nonblocking
ssh_channel_read_timeout
ssh_channel_request_auth_agent
ssh_channel_request_env
ssh_channel_request_exec
ssh_channel_request_pty
ssh_channel_request_pty_size
ssh_channel_request_send_break
ssh_channel_request_send_exit_signal
ssh_channel_request_send_exit_status
ssh_channel_request_send_signal
ssh_channel_request_sftp
ssh_channel_request_shell
ssh_channel_request_subsystem
ssh_channel_request_x11
ssh_channel_select
ssh_channel_send_eof
ssh_channel_set_blocking
ssh_channel_set_counter
ssh_channel_window_size
ssh_channel_write
ssh_channel_write_stderr
ssh_clean_pubkey_hash
ssh_connect
ssh_connector_free
ssh_connector_new
ssh_connector_set_in_channel
ssh_connector_set_in_fd
ssh_connector_set_out_channel
ssh_connector_set_out_fd
ssh_copyright
ssh_dirname
ssh_disconnect
ssh_dump_knownhost
ssh_event_add_connector
ssh_event_add_fd
ssh_event_add_session
ssh_event_dopoll
ssh_event_free
ssh_event_new
ssh_event_remove_connector
ssh_event_remove_fd
ssh_event_remove_session
ssh_execute_message_callbacks
ssh_finalize
ssh_forward_accept
ssh_forward_cancel
ssh_forward_listen
ssh_free
ssh_get_cipher_in
ssh_get_cipher_out
ssh_get_clientbanner
ssh_get_disconnect_message
ssh_get_error
ssh_get_error_code
ssh_get_fd
ssh_get_fingerprint_hash
ssh_get_hexa
ssh_get_hmac_in
ssh_get_hmac_out
ssh_get_issue_banner
ssh_get_kex_algo
ssh_get_log_callback
ssh_get_log_level
ssh_get_log_userdata
ssh_get_openssh_version
ssh_get_poll_flags
ssh_get_pubkey
ssh_get_pubkey_hash
ssh_get_publickey
ssh_get_publickey_hash
ssh_get_random
ssh_get_server_publickey
ssh_get_serverbanner
ssh_get_status
ssh_get_version
ssh_getpass
ssh_gssapi_get_creds
ssh_gssapi_set_creds
ssh_handle_key_exchange
ssh_init
ssh_is_blocking
ssh_is_connected
ssh_is_server_known
ssh_key_cmp
ssh_key_free
ssh_key_is_private
ssh_key_is_public
ssh_key_new
ssh_key_type
ssh_key_type_from_name
ssh_key_type_to_char
ssh_known_hosts_parse_line
ssh_knownhosts_entry_free
ssh_log
ssh_message_auth_interactive_request
ssh_message_auth_kbdint_is_response
ssh_message_auth_password
ssh_message_auth_pubkey
ssh_message_auth_publickey
ssh_message_auth_publickey_state
ssh_message_auth_reply_pk_ok
ssh_message_auth_reply_pk_ok_simple
ssh_message_auth_reply_success
ssh_message_auth_set_methods
ssh_message_auth_user
ssh_message_channel_request_channel
ssh_message_channel_request_command
ssh_message_channel_request_env_name
ssh_message_channel_request_env_value
ssh_message_channel_request_open_destination
ssh_message_channel_request_open_destination_port
ssh_message_channel_request_open_originator
ssh_message_channel_request_open_originator_port
ssh_message_channel_request_open_reply_accept
ssh_message_channel_request_open_reply_accept_channel
ssh_message_channel_request_pty_height
ssh_message_channel_request_pty_pxheight
ssh_message_channel_request_pty_pxwidth
ssh_message_channel_request_pty_term
ssh_message_channel_request_pty_width
ssh_message_channel_request_reply_success
ssh_message_channel_request_subsystem
ssh_message_channel_request_x11_auth_cookie
ssh_message_channel_request_x11_auth_protocol
ssh_message_channel_request_x11_screen_number
ssh_message_channel_request_x11_single_connection
ssh_message_free
ssh_message_get
ssh_message_global_request_address
ssh_message_global_request_port
ssh_message_global_request_reply_success
ssh_message_reply_default
ssh_message_retrieve
ssh_message_service_reply_success
ssh_message_service_service
ssh_message_subtype
ssh_message_type
ssh_mkdir
ssh_new
ssh_options_copy
ssh_options_get
ssh_options_get_port
ssh_options_getopt
ssh_options_parse_config
ssh_options_set
ssh_pcap_file_close
ssh_pcap_file_free
ssh_pcap_file_new
ssh_pcap_file_open
ssh_pki_copy_cert_to_privkey
ssh_pki_export_privkey_base64
ssh_pki_export_privkey_file
ssh_pki_export_privkey_to_pubkey
ssh_pki_export_pubkey_base64
ssh_pki_export_pubkey_file
ssh_pki_generate
ssh_pki_import_cert_base64
ssh_pki_import_cert_file
ssh_pki_import_privkey_base64
ssh_pki_import_privkey_file
ssh_pki_import_pubkey_base64
ssh_pki_import_pubkey_file
ssh_pki_key_ecdsa_name
ssh_print_hash
ssh_print_hexa
ssh_privatekey_type
ssh_publickey_to_file
ssh_remove_channel_callbacks
ssh_scp_accept_request
ssh_scp_close
ssh_scp_deny_request
ssh_scp_free
ssh_scp_init
ssh_scp_leave_directory
ssh_scp_new
ssh_scp_pull_request
ssh_scp_push_directory
ssh_scp_push_file
ssh_scp_push_file64
ssh_scp_read
ssh_scp_request_get_filename
ssh_scp_request_get_permissions
ssh_scp_request_get_size
ssh_scp_request_get_size64
ssh_scp_request_get_warning
ssh_scp_write
ssh_select
ssh_send_debug
ssh_send_ignore
ssh_send_keepalive
ssh_server_init_kex
ssh_service_request
ssh_session_export_known_hosts_entry
ssh_session_get_known_hosts_entry
ssh_session_has_known_hosts_entry
ssh_session_is_known_server
ssh_session_update_known_hosts
ssh_set_agent_channel
ssh_set_agent_socket
ssh_set_auth_methods
ssh_set_blocking
ssh_set_callbacks
ssh_set_channel_callbacks
ssh_set_counters
ssh_set_fd_except
ssh_set_fd_toread
ssh_set_fd_towrite
ssh_set_log_callback
ssh_set_log_level
ssh_set_log_userdata
ssh_set_message_callback
ssh_set_pcap_file
ssh_set_server_callbacks
ssh_silent_disconnect
ssh_string_burn
ssh_string_copy
ssh_string_data
ssh_string_fill
ssh_string_free
ssh_string_free_char
ssh_string_from_char
ssh_string_get_char
ssh_string_len
ssh_string_new
ssh_string_to_char
ssh_threads_get_default
ssh_threads_get_noop
ssh_threads_get_pthread
ssh_threads_set_callbacks
ssh_try_publickey_from_file
ssh_userauth_agent
ssh_userauth_agent_pubkey
ssh_userauth_autopubkey
ssh_userauth_gssapi
ssh_userauth_kbdint
ssh_userauth_kbdint_getanswer
ssh_userauth_kbdint_getinstruction
ssh_userauth_kbdint_getname
ssh_userauth_kbdint_getnanswers
ssh_userauth_kbdint_getnprompts
ssh_userauth_kbdint_getprompt
ssh_userauth_kbdint_setanswer
ssh_userauth_list
ssh_userauth_none
ssh_userauth_offer_pubkey
ssh_userauth_password
ssh_userauth_privatekey_file
ssh_userauth_pubkey
ssh_userauth_publickey
ssh_userauth_publickey_auto
ssh_userauth_try_publickey
ssh_version
ssh_write_knownhost
string_burn
string_copy
string_data
string_fill
string_free
string_from_char
string_len
string_new
string_to_char

View File

@@ -0,0 +1,421 @@
_ssh_log
buffer_free
buffer_get
buffer_get_len
buffer_new
channel_accept_x11
channel_change_pty_size
channel_close
channel_forward_accept
channel_forward_cancel
channel_forward_listen
channel_free
channel_get_exit_status
channel_get_session
channel_is_closed
channel_is_eof
channel_is_open
channel_new
channel_open_forward
channel_open_session
channel_poll
channel_read
channel_read_buffer
channel_read_nonblocking
channel_request_env
channel_request_exec
channel_request_pty
channel_request_pty_size
channel_request_send_signal
channel_request_sftp
channel_request_shell
channel_request_subsystem
channel_request_x11
channel_select
channel_send_eof
channel_set_blocking
channel_write
channel_write_stderr
privatekey_free
privatekey_from_file
publickey_free
publickey_from_file
publickey_from_privatekey
publickey_to_string
sftp_async_read
sftp_async_read_begin
sftp_attributes_free
sftp_canonicalize_path
sftp_chmod
sftp_chown
sftp_client_message_free
sftp_client_message_get_data
sftp_client_message_get_filename
sftp_client_message_get_flags
sftp_client_message_get_submessage
sftp_client_message_get_type
sftp_client_message_set_filename
sftp_close
sftp_closedir
sftp_dir_eof
sftp_extension_supported
sftp_extensions_get_count
sftp_extensions_get_data
sftp_extensions_get_name
sftp_file_set_blocking
sftp_file_set_nonblocking
sftp_free
sftp_fstat
sftp_fstatvfs
sftp_fsync
sftp_get_client_message
sftp_get_error
sftp_handle
sftp_handle_alloc
sftp_handle_remove
sftp_init
sftp_lstat
sftp_mkdir
sftp_new
sftp_new_channel
sftp_open
sftp_opendir
sftp_read
sftp_readdir
sftp_readlink
sftp_rename
sftp_reply_attr
sftp_reply_data
sftp_reply_handle
sftp_reply_name
sftp_reply_names
sftp_reply_names_add
sftp_reply_status
sftp_rewind
sftp_rmdir
sftp_seek
sftp_seek64
sftp_send_client_message
sftp_server_free
sftp_server_init
sftp_server_new
sftp_server_version
sftp_setstat
sftp_stat
sftp_statvfs
sftp_statvfs_free
sftp_symlink
sftp_tell
sftp_tell64
sftp_unlink
sftp_utimes
sftp_write
ssh_accept
ssh_add_channel_callbacks
ssh_auth_list
ssh_basename
ssh_bind_accept
ssh_bind_accept_fd
ssh_bind_fd_toaccept
ssh_bind_free
ssh_bind_get_fd
ssh_bind_listen
ssh_bind_new
ssh_bind_options_parse_config
ssh_bind_options_set
ssh_bind_set_blocking
ssh_bind_set_callbacks
ssh_bind_set_fd
ssh_blocking_flush
ssh_buffer_add_data
ssh_buffer_free
ssh_buffer_get
ssh_buffer_get_data
ssh_buffer_get_len
ssh_buffer_new
ssh_buffer_reinit
ssh_channel_accept_forward
ssh_channel_accept_x11
ssh_channel_cancel_forward
ssh_channel_change_pty_size
ssh_channel_close
ssh_channel_free
ssh_channel_get_exit_status
ssh_channel_get_session
ssh_channel_is_closed
ssh_channel_is_eof
ssh_channel_is_open
ssh_channel_listen_forward
ssh_channel_new
ssh_channel_open_auth_agent
ssh_channel_open_forward
ssh_channel_open_forward_unix
ssh_channel_open_reverse_forward
ssh_channel_open_session
ssh_channel_open_x11
ssh_channel_poll
ssh_channel_poll_timeout
ssh_channel_read
ssh_channel_read_nonblocking
ssh_channel_read_timeout
ssh_channel_request_auth_agent
ssh_channel_request_env
ssh_channel_request_exec
ssh_channel_request_pty
ssh_channel_request_pty_size
ssh_channel_request_send_break
ssh_channel_request_send_exit_signal
ssh_channel_request_send_exit_status
ssh_channel_request_send_signal
ssh_channel_request_sftp
ssh_channel_request_shell
ssh_channel_request_subsystem
ssh_channel_request_x11
ssh_channel_select
ssh_channel_send_eof
ssh_channel_set_blocking
ssh_channel_set_counter
ssh_channel_window_size
ssh_channel_write
ssh_channel_write_stderr
ssh_clean_pubkey_hash
ssh_connect
ssh_connector_free
ssh_connector_new
ssh_connector_set_in_channel
ssh_connector_set_in_fd
ssh_connector_set_out_channel
ssh_connector_set_out_fd
ssh_copyright
ssh_dirname
ssh_disconnect
ssh_dump_knownhost
ssh_event_add_connector
ssh_event_add_fd
ssh_event_add_session
ssh_event_dopoll
ssh_event_free
ssh_event_new
ssh_event_remove_connector
ssh_event_remove_fd
ssh_event_remove_session
ssh_execute_message_callbacks
ssh_finalize
ssh_forward_accept
ssh_forward_cancel
ssh_forward_listen
ssh_free
ssh_get_cipher_in
ssh_get_cipher_out
ssh_get_clientbanner
ssh_get_disconnect_message
ssh_get_error
ssh_get_error_code
ssh_get_fd
ssh_get_fingerprint_hash
ssh_get_hexa
ssh_get_hmac_in
ssh_get_hmac_out
ssh_get_issue_banner
ssh_get_kex_algo
ssh_get_log_callback
ssh_get_log_level
ssh_get_log_userdata
ssh_get_openssh_version
ssh_get_poll_flags
ssh_get_pubkey
ssh_get_pubkey_hash
ssh_get_publickey
ssh_get_publickey_hash
ssh_get_random
ssh_get_server_publickey
ssh_get_serverbanner
ssh_get_status
ssh_get_version
ssh_getpass
ssh_gssapi_get_creds
ssh_gssapi_set_creds
ssh_handle_key_exchange
ssh_init
ssh_is_blocking
ssh_is_connected
ssh_is_server_known
ssh_key_cmp
ssh_key_free
ssh_key_is_private
ssh_key_is_public
ssh_key_new
ssh_key_type
ssh_key_type_from_name
ssh_key_type_to_char
ssh_known_hosts_parse_line
ssh_knownhosts_entry_free
ssh_log
ssh_message_auth_interactive_request
ssh_message_auth_kbdint_is_response
ssh_message_auth_password
ssh_message_auth_pubkey
ssh_message_auth_publickey
ssh_message_auth_publickey_state
ssh_message_auth_reply_pk_ok
ssh_message_auth_reply_pk_ok_simple
ssh_message_auth_reply_success
ssh_message_auth_set_methods
ssh_message_auth_user
ssh_message_channel_request_channel
ssh_message_channel_request_command
ssh_message_channel_request_env_name
ssh_message_channel_request_env_value
ssh_message_channel_request_open_destination
ssh_message_channel_request_open_destination_port
ssh_message_channel_request_open_originator
ssh_message_channel_request_open_originator_port
ssh_message_channel_request_open_reply_accept
ssh_message_channel_request_open_reply_accept_channel
ssh_message_channel_request_pty_height
ssh_message_channel_request_pty_pxheight
ssh_message_channel_request_pty_pxwidth
ssh_message_channel_request_pty_term
ssh_message_channel_request_pty_width
ssh_message_channel_request_reply_success
ssh_message_channel_request_subsystem
ssh_message_channel_request_x11_auth_cookie
ssh_message_channel_request_x11_auth_protocol
ssh_message_channel_request_x11_screen_number
ssh_message_channel_request_x11_single_connection
ssh_message_free
ssh_message_get
ssh_message_global_request_address
ssh_message_global_request_port
ssh_message_global_request_reply_success
ssh_message_reply_default
ssh_message_retrieve
ssh_message_service_reply_success
ssh_message_service_service
ssh_message_subtype
ssh_message_type
ssh_mkdir
ssh_new
ssh_options_copy
ssh_options_get
ssh_options_get_port
ssh_options_getopt
ssh_options_parse_config
ssh_options_set
ssh_pcap_file_close
ssh_pcap_file_free
ssh_pcap_file_new
ssh_pcap_file_open
ssh_pki_copy_cert_to_privkey
ssh_pki_export_privkey_base64
ssh_pki_export_privkey_file
ssh_pki_export_privkey_to_pubkey
ssh_pki_export_pubkey_base64
ssh_pki_export_pubkey_file
ssh_pki_generate
ssh_pki_import_cert_base64
ssh_pki_import_cert_file
ssh_pki_import_privkey_base64
ssh_pki_import_privkey_file
ssh_pki_import_pubkey_base64
ssh_pki_import_pubkey_file
ssh_pki_key_ecdsa_name
ssh_print_hash
ssh_print_hexa
ssh_privatekey_type
ssh_publickey_to_file
ssh_remove_channel_callbacks
ssh_scp_accept_request
ssh_scp_close
ssh_scp_deny_request
ssh_scp_free
ssh_scp_init
ssh_scp_leave_directory
ssh_scp_new
ssh_scp_pull_request
ssh_scp_push_directory
ssh_scp_push_file
ssh_scp_push_file64
ssh_scp_read
ssh_scp_request_get_filename
ssh_scp_request_get_permissions
ssh_scp_request_get_size
ssh_scp_request_get_size64
ssh_scp_request_get_warning
ssh_scp_write
ssh_select
ssh_send_debug
ssh_send_ignore
ssh_send_keepalive
ssh_server_init_kex
ssh_service_request
ssh_session_export_known_hosts_entry
ssh_session_get_known_hosts_entry
ssh_session_has_known_hosts_entry
ssh_session_is_known_server
ssh_session_update_known_hosts
ssh_set_agent_channel
ssh_set_agent_socket
ssh_set_auth_methods
ssh_set_blocking
ssh_set_callbacks
ssh_set_channel_callbacks
ssh_set_counters
ssh_set_fd_except
ssh_set_fd_toread
ssh_set_fd_towrite
ssh_set_log_callback
ssh_set_log_level
ssh_set_log_userdata
ssh_set_message_callback
ssh_set_pcap_file
ssh_set_server_callbacks
ssh_silent_disconnect
ssh_string_burn
ssh_string_copy
ssh_string_data
ssh_string_fill
ssh_string_free
ssh_string_free_char
ssh_string_from_char
ssh_string_get_char
ssh_string_len
ssh_string_new
ssh_string_to_char
ssh_threads_get_default
ssh_threads_get_noop
ssh_threads_get_pthread
ssh_threads_set_callbacks
ssh_try_publickey_from_file
ssh_userauth_agent
ssh_userauth_agent_pubkey
ssh_userauth_autopubkey
ssh_userauth_gssapi
ssh_userauth_kbdint
ssh_userauth_kbdint_getanswer
ssh_userauth_kbdint_getinstruction
ssh_userauth_kbdint_getname
ssh_userauth_kbdint_getnanswers
ssh_userauth_kbdint_getnprompts
ssh_userauth_kbdint_getprompt
ssh_userauth_kbdint_setanswer
ssh_userauth_list
ssh_userauth_none
ssh_userauth_offer_pubkey
ssh_userauth_password
ssh_userauth_privatekey_file
ssh_userauth_pubkey
ssh_userauth_publickey
ssh_userauth_publickey_auto
ssh_userauth_try_publickey
ssh_version
ssh_write_knownhost
string_burn
string_copy
string_data
string_fill
string_free
string_from_char
string_len
string_new
string_to_char

View File

@@ -1,7 +1,4 @@
set(LIBSSH_PUBLIC_INCLUDE_DIRS
${libssh_SOURCE_DIR}/include
CACHE INTERNAL "libssh public include directories"
)
set(LIBSSH_PUBLIC_INCLUDE_DIRS ${libssh_SOURCE_DIR}/include)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${libssh_BINARY_DIR}
@@ -18,13 +15,6 @@ if (WIN32)
)
endif (WIN32)
if (HAVE_LIBSOCKET)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
socket
)
endif (HAVE_LIBSOCKET)
if (OPENSSL_CRYPTO_LIBRARY)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
@@ -95,16 +85,6 @@ if (WITH_NACL AND NACL_FOUND)
)
endif (WITH_NACL AND NACL_FOUND)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
CACHE INTERNAL "libssh link libraries"
)
set(LIBSSH_SHARED_LIBRARY
ssh_shared
CACHE INTERNAL "libssh shared library"
)
if (BUILD_STATIC_LIB)
set(LIBSSH_STATIC_LIBRARY
ssh_static
@@ -146,7 +126,6 @@ set(libssh_SRCS
pcap.c
pki.c
pki_container_openssh.c
pki_ed25519.c
poll.c
session.c
scp.c
@@ -157,14 +136,11 @@ set(libssh_SRCS
external/bcrypt_pbkdf.c
external/blowfish.c
external/chacha.c
external/ed25519.c
external/fe25519.c
external/ge25519.c
external/poly1305.c
external/sc25519.c
chachapoly.c
config_parser.c
token.c
pki_ed25519_common.c
)
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
@@ -201,6 +177,11 @@ if (WITH_GCRYPT)
pki_gcrypt.c
ecdh_gcrypt.c
dh_key.c
pki_ed25519.c
external/ed25519.c
external/fe25519.c
external/ge25519.c
external/sc25519.c
)
elseif (WITH_MBEDTLS)
set(libssh_SRCS
@@ -211,6 +192,11 @@ elseif (WITH_MBEDTLS)
pki_mbedcrypto.c
ecdh_mbedcrypto.c
dh_key.c
pki_ed25519.c
external/ed25519.c
external/fe25519.c
external/ge25519.c
external/sc25519.c
)
else (WITH_GCRYPT)
set(libssh_SRCS
@@ -221,6 +207,16 @@ else (WITH_GCRYPT)
libcrypto.c
dh_crypto.c
)
if (NOT HAVE_OPENSSL_ED25519)
set(libssh_SRCS
${libssh_SRCS}
pki_ed25519.c
external/ed25519.c
external/fe25519.c
external/ge25519.c
external/sc25519.c
)
endif (NOT HAVE_OPENSSL_ED25519)
if(OPENSSL_VERSION VERSION_LESS "1.1.0")
set(libssh_SRCS ${libssh_SRCS} libcrypto-compat.c)
endif()
@@ -271,17 +267,14 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (NOT WITH_NACL)
set(libssh_SRCS
${libssh_SRCS}
external/curve25519_ref.c
)
if (NOT HAVE_OPENSSL_ED25519)
set(libssh_SRCS
${libssh_SRCS}
external/curve25519_ref.c
)
endif (NOT HAVE_OPENSSL_ED25519)
endif (NOT WITH_NACL)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${LIBSSH_PRIVATE_INCLUDE_DIRS}
)
# Set the path to the default map file
set(MAP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.map")
@@ -313,13 +306,23 @@ if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT AND ABIMAP_FOUND)
)
endif (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT AND ABIMAP_FOUND)
add_library(${LIBSSH_SHARED_LIBRARY} SHARED ${libssh_SRCS})
target_compile_options(${LIBSSH_SHARED_LIBRARY}
# This gets built as a static library, if -DBUILD_SHARED_LIBS=OFF is passed to
# cmake.
add_library(ssh ${libssh_SRCS})
target_compile_options(ssh
PRIVATE
${DEFAULT_C_COMPILE_FLAGS}
-D_GNU_SOURCE)
target_include_directories(ssh
PUBLIC
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
target_link_libraries(${LIBSSH_SHARED_LIBRARY} ${LIBSSH_LINK_LIBRARIES})
target_link_libraries(ssh
PRIVATE ${LIBSSH_LINK_LIBRARIES})
add_library(ssh::ssh ALIAS ssh)
if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
if (ABIMAP_FOUND)
@@ -327,56 +330,63 @@ if (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
set(MAP_PATH "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_dev.map")
endif (ABIMAP_FOUND)
set_target_properties(${LIBSSH_SHARED_LIBRARY}
set_target_properties(ssh
PROPERTIES LINK_FLAGS
"-Wl,--version-script,\"${MAP_PATH}\"")
endif (WITH_SYMBOL_VERSIONING AND HAVE_LD_VERSION_SCRIPT)
set_target_properties(
${LIBSSH_SHARED_LIBRARY}
set_target_properties(ssh
PROPERTIES
VERSION
${LIBRARY_VERSION}
SOVERSION
${LIBRARY_SOVERSION}
OUTPUT_NAME
ssh
DEFINE_SYMBOL
LIBSSH_EXPORTS
)
if (WITH_VISIBILITY_HIDDEN)
set_target_properties(${LIBSSH_SHARED_LIBRARY} PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
set_target_properties(ssh PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
endif (WITH_VISIBILITY_HIDDEN)
if (MINGW)
set_target_properties(${LIBSSH_SHARED_LIBRARY} PROPERTIES LINK_FLAGS "-Wl,--enable-stdcall-fixup")
set_target_properties(ssh PROPERTIES LINK_FLAGS "-Wl,--enable-stdcall-fixup")
endif ()
install(
TARGETS
${LIBSSH_SHARED_LIBRARY}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
COMPONENT libraries
)
install(TARGETS ssh
EXPORT libssh-config
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT libraries)
install(EXPORT libssh-config
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
if (BUILD_STATIC_LIB)
add_library(${LIBSSH_STATIC_LIBRARY} STATIC ${libssh_SRCS})
target_compile_options(${LIBSSH_STATIC_LIBRARY}
add_library(ssh-static STATIC ${libssh_SRCS})
target_compile_options(ssh-static
PRIVATE
${DEFAULT_C_COMPILE_FLAGS}
-D_GNU_SOURCE)
target_include_directories(ssh-static
PUBLIC
$<BUILD_INTERFACE:${libssh_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE ${LIBSSH_PRIVATE_INCLUDE_DIRS})
target_link_libraries(ssh-static
PUBLIC ${LIBSSH_LINK_LIBRARIES})
add_library(ssh::static ALIAS ssh-static)
if (MSVC)
set(OUTPUT_SUFFIX static)
else (MSVC)
set(OUTPUT_SUFFIX )
endif (MSVC)
set_target_properties(
${LIBSSH_STATIC_LIBRARY}
ssh-static
PROPERTIES
VERSION
${LIBRARY_VERSION}
@@ -390,21 +400,12 @@ if (BUILD_STATIC_LIB)
if (WIN32)
set_target_properties(
${LIBSSH_STATIC_LIBRARY}
ssh-static
PROPERTIES
COMPILE_FLAGS
"-DLIBSSH_STATIC"
)
endif (WIN32)
if (WITH_STATIC_LIB)
install(TARGETS
${LIBSSH_STATIC_LIBRARY}
DESTINATION
${LIB_INSTALL_DIR}/${OUTPUT_SUFFIX}
COMPONENT
libraries)
endif (WITH_STATIC_LIB)
endif (BUILD_STATIC_LIB)
message(STATUS "Threads_FOUND=${Threads_FOUND}")

View File

@@ -25,6 +25,7 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#ifndef _WIN32
#include <netinet/in.h>
@@ -69,7 +70,7 @@ static int ssh_userauth_request_service(ssh_session session) {
int rc;
rc = ssh_service_request(session, "ssh-userauth");
if (rc != SSH_OK) {
if ((rc != SSH_OK) && (rc != SSH_AGAIN)) {
SSH_LOG(SSH_LOG_WARN,
"Failed to request \"ssh-userauth\" service");
}

View File

@@ -77,7 +77,7 @@ bignum ssh_make_string_bn(ssh_string string)
}
/* prints the bignum on stderr */
void ssh_print_bignum(const char *name, const bignum num)
void ssh_print_bignum(const char *name, const_bignum num)
{
unsigned char *hex = NULL;
if (num != NULL) {

View File

@@ -1119,6 +1119,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
goto cleanup;
}
rc = SSH_ERROR;
switch (*p) {
case 'b':
o.byte = va_arg(ap, uint8_t *);
@@ -1128,27 +1129,32 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
case 'w':
o.word = va_arg(ap, uint16_t *);
rlen = ssh_buffer_get_data(buffer, o.word, sizeof(uint16_t));
*o.word = ntohs(*o.word);
rc = rlen==2 ? SSH_OK : SSH_ERROR;
if (rlen == 2) {
*o.word = ntohs(*o.word);
rc = SSH_OK;
}
break;
case 'd':
o.dword = va_arg(ap, uint32_t *);
rlen = ssh_buffer_get_u32(buffer, o.dword);
*o.dword = ntohl(*o.dword);
rc = rlen==4 ? SSH_OK : SSH_ERROR;
if (rlen == 4) {
*o.dword = ntohl(*o.dword);
rc = SSH_OK;
}
break;
case 'q':
o.qword = va_arg(ap, uint64_t*);
rlen = ssh_buffer_get_u64(buffer, o.qword);
*o.qword = ntohll(*o.qword);
rc = rlen==8 ? SSH_OK : SSH_ERROR;
if (rlen == 8) {
*o.qword = ntohll(*o.qword);
rc = SSH_OK;
}
break;
case 'B':
o.bignum = va_arg(ap, bignum *);
*o.bignum = NULL;
tmp_string = ssh_buffer_get_ssh_string(buffer);
if (tmp_string == NULL) {
rc = SSH_ERROR;
break;
}
*o.bignum = ssh_make_string_bn(tmp_string);
@@ -1167,14 +1173,12 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
o.cstring = va_arg(ap, char **);
*o.cstring = NULL;
rc = ssh_buffer_get_u32(buffer, &u32len);
if (rc != 4){
rc = SSH_ERROR;
rlen = ssh_buffer_get_u32(buffer, &u32len);
if (rlen != 4){
break;
}
len = ntohl(u32len);
if (len > max_len - 1) {
rc = SSH_ERROR;
break;
}
@@ -1230,7 +1234,6 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
break;
default:
SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p);
rc = SSH_ERROR;
}
if (rc != SSH_OK) {
break;

View File

@@ -109,11 +109,11 @@ static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
out_packet->payload,
len - sizeof(uint32_t));
/* ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
/* ssh_log_hexdump("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx)); */
/* step 4, compute the MAC */
poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx);
/* ssh_print_hexa("poly1305 src", (uint8_t *)out_packet, len);
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN); */
/* ssh_log_hexdump("poly1305 src", (uint8_t *)out_packet, len);
ssh_log_hexdump("poly1305 tag", tag, POLY1305_TAGLEN); */
}
static int chacha20_poly1305_aead_decrypt_length(
@@ -159,17 +159,17 @@ static int chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
poly1305_ctx,
POLY1305_KEYLEN);
#if 0
ssh_print_hexa("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
ssh_log_hexdump("poly1305_ctx", poly1305_ctx, sizeof(poly1305_ctx));
#endif
poly1305_auth(tag, (uint8_t *)complete_packet, encrypted_size +
sizeof(uint32_t), poly1305_ctx);
#if 0
ssh_print_hexa("poly1305 src",
ssh_log_hexdump("poly1305 src",
(uint8_t*)complete_packet,
encrypted_size + 4);
ssh_print_hexa("poly1305 tag", tag, POLY1305_TAGLEN);
ssh_print_hexa("received tag", mac, POLY1305_TAGLEN);
ssh_log_hexdump("poly1305 tag", tag, POLY1305_TAGLEN);
ssh_log_hexdump("received tag", mac, POLY1305_TAGLEN);
#endif
cmp = memcmp(tag, mac, POLY1305_TAGLEN);

View File

@@ -277,74 +277,89 @@ static int ssh_channel_open_termination(void *c){
*
* @return SSH_OK if successful; SSH_ERROR otherwise.
*/
static int channel_open(ssh_channel channel, const char *type, int window,
int maxpacket, ssh_buffer payload) {
ssh_session session = channel->session;
int err=SSH_ERROR;
int rc;
static int
channel_open(ssh_channel channel,
const char *type,
int window,
int maxpacket,
ssh_buffer payload)
{
ssh_session session = channel->session;
int err = SSH_ERROR;
int rc;
switch(channel->state){
case SSH_CHANNEL_STATE_NOT_OPEN:
break;
case SSH_CHANNEL_STATE_OPENING:
goto pending;
case SSH_CHANNEL_STATE_OPEN:
case SSH_CHANNEL_STATE_CLOSED:
case SSH_CHANNEL_STATE_OPEN_DENIED:
goto end;
default:
ssh_set_error(session,SSH_FATAL,"Bad state in channel_open: %d",channel->state);
}
channel->local_channel = ssh_channel_new_id(session);
channel->local_maxpacket = maxpacket;
channel->local_window = window;
SSH_LOG(SSH_LOG_PROTOCOL,
"Creating a channel %d with %d window and %d max packet",
channel->local_channel, window, maxpacket);
rc = ssh_buffer_pack(session->out_buffer,
"bsddd",
SSH2_MSG_CHANNEL_OPEN,
type,
channel->local_channel,
channel->local_window,
channel->local_maxpacket);
if (rc != SSH_OK){
ssh_set_error_oom(session);
return err;
}
if (payload != NULL) {
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
ssh_set_error_oom(session);
return err;
switch (channel->state) {
case SSH_CHANNEL_STATE_NOT_OPEN:
break;
case SSH_CHANNEL_STATE_OPENING:
goto pending;
case SSH_CHANNEL_STATE_OPEN:
case SSH_CHANNEL_STATE_CLOSED:
case SSH_CHANNEL_STATE_OPEN_DENIED:
goto end;
default:
ssh_set_error(session, SSH_FATAL, "Bad state in channel_open: %d",
channel->state);
}
channel->local_channel = ssh_channel_new_id(session);
channel->local_maxpacket = maxpacket;
channel->local_window = window;
SSH_LOG(SSH_LOG_PROTOCOL,
"Creating a channel %d with %d window and %d max packet",
channel->local_channel, window, maxpacket);
rc = ssh_buffer_pack(session->out_buffer,
"bsddd",
SSH2_MSG_CHANNEL_OPEN,
type,
channel->local_channel,
channel->local_window,
channel->local_maxpacket);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
return err;
}
if (payload != NULL) {
if (ssh_buffer_add_buffer(session->out_buffer, payload) < 0) {
ssh_set_error_oom(session);
return err;
}
}
channel->state = SSH_CHANNEL_STATE_OPENING;
if (ssh_packet_send(session) == SSH_ERROR) {
return err;
}
SSH_LOG(SSH_LOG_PACKET,
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
type, channel->local_channel);
pending:
/* wait until channel is opened by server */
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:
/* This needs to pass the SSH_AGAIN from the above,
* but needs to catch failed channel states */
if (channel->state == SSH_CHANNEL_STATE_OPEN) {
err = SSH_OK;
} else if (err != SSH_AGAIN) {
/* Messages were handled correctly, but he channel state is invalid */
err = SSH_ERROR;
}
}
channel->state = SSH_CHANNEL_STATE_OPENING;
if (ssh_packet_send(session) == SSH_ERROR) {
return err;
}
SSH_LOG(SSH_LOG_PACKET,
"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d",
type, channel->local_channel);
pending:
/* wait until channel is opened by server */
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:
if(channel->state == SSH_CHANNEL_STATE_OPEN)
err=SSH_OK;
return err;
}
/* return channel with corresponding local id, or NULL if not found */
@@ -1949,6 +1964,18 @@ error:
return rc;
}
/**
* @brief Request sftp subsystem on the channel
*
* @param[in] channel The channel to request the sftp subsystem.
*
* @return SSH_OK on success,
* SSH_ERROR if an error occurred,
* SSH_AGAIN if in nonblocking mode and call has
* to be done again.
*
* @note You should use sftp_new() which does this for you.
*/
int ssh_channel_request_sftp( ssh_channel channel){
if(channel == NULL) {
return SSH_ERROR;
@@ -2513,12 +2540,12 @@ error:
*
* Example:
@code
rc = channel_request_exec(channel, "ps aux");
rc = ssh_channel_request_exec(channel, "ps aux");
if (rc > 0) {
return -1;
}
while ((rc = channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
while ((rc = ssh_channel_read(channel, buffer, sizeof(buffer), 0)) > 0) {
if (fwrite(buffer, 1, rc, stdout) != (unsigned int) rc) {
return -1;
}

View File

@@ -274,10 +274,8 @@ static int
ssh_config_match(char *value, const char *pattern, bool negate)
{
int ok, result = 0;
char *lowervalue;
lowervalue = (value) ? ssh_lowercase(value) : NULL;
ok = match_pattern_list(lowervalue, pattern, strlen(pattern), 0);
ok = match_pattern_list(value, pattern, strlen(pattern), 0);
if (ok <= 0 && negate == true) {
result = 1;
} else if (ok > 0 && negate == false) {
@@ -286,7 +284,6 @@ ssh_config_match(char *value, const char *pattern, bool negate)
SSH_LOG(SSH_LOG_TRACE, "%s '%s' against pattern '%s'%s (ok=%d)",
result == 1 ? "Matched" : "Not matched", value, pattern,
negate == true ? " (negated)" : "", ok);
SAFE_FREE(lowervalue);
return result;
}
@@ -450,6 +447,7 @@ ssh_config_parse_line(ssh_session session,
int result = 1;
size_t args = 0;
enum ssh_config_match_e opt;
char *localuser = NULL;
*parsing = 0;
do {
@@ -515,8 +513,29 @@ ssh_config_parse_line(ssh_session session,
result = 0;
break;
case MATCH_ORIGINALHOST:
case MATCH_LOCALUSER:
/* Here we match only one argument */
p = ssh_config_get_str_tok(&s, NULL);
if (p == NULL || p[0] == '\0') {
ssh_set_error(session, SSH_FATAL,
"line %d: ERROR - Match user keyword "
"requires argument", count);
SAFE_FREE(x);
return -1;
}
localuser = ssh_get_local_username();
if (localuser == NULL) {
SSH_LOG(SSH_LOG_WARN, "line %d: Can not get local username "
"for conditional matching.", count);
SAFE_FREE(x);
return -1;
}
result &= ssh_config_match(localuser, p, negate);
SAFE_FREE(localuser);
args++;
break;
case MATCH_ORIGINALHOST:
/* Skip one argument */
p = ssh_config_get_str_tok(&s, NULL);
if (p == NULL || p[0] == '\0') {

View File

@@ -90,131 +90,55 @@
#ifdef _WIN32
#ifndef gai_strerror
char WSAAPI *gai_strerrorA(int code) {
static char buf[256];
char WSAAPI *gai_strerrorA(int code)
{
static char buf[256];
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
snprintf(buf, sizeof(buf), "Undetermined error code (%d)", code);
return buf;
return buf;
}
#endif /* gai_strerror */
#endif /* _WIN32 */
static int ssh_connect_socket_close(socket_t s){
static int ssh_connect_socket_close(socket_t s)
{
#ifdef _WIN32
return closesocket(s);
return closesocket(s);
#else
return close(s);
return close(s);
#endif
}
static int getai(const char *host, int port, struct addrinfo **ai)
{
const char *service = NULL;
struct addrinfo hints;
char s_port[10];
static int getai(const char *host, int port, struct addrinfo **ai) {
const char *service = NULL;
struct addrinfo hints;
char s_port[10];
ZERO_STRUCT(hints);
ZERO_STRUCT(hints);
hints.ai_protocol = IPPROTO_TCP;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (port == 0) {
hints.ai_flags = AI_PASSIVE;
} else {
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
service = s_port;
if (port == 0) {
hints.ai_flags = AI_PASSIVE;
} else {
snprintf(s_port, sizeof(s_port), "%hu", (unsigned short)port);
service = s_port;
#ifdef AI_NUMERICSERV
hints.ai_flags=AI_NUMERICSERV;
hints.ai_flags = AI_NUMERICSERV;
#endif
}
}
if (ssh_is_ipaddr(host)) {
/* this is an IP address */
SSH_LOG(SSH_LOG_PACKET,"host %s matches an IP address",host);
hints.ai_flags |= AI_NUMERICHOST;
}
if (ssh_is_ipaddr(host)) {
/* this is an IP address */
SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host);
hints.ai_flags |= AI_NUMERICHOST;
}
return getaddrinfo(host, service, &hints, ai);
}
static int ssh_connect_ai_timeout(ssh_session session, const char *host,
int port, struct addrinfo *ai, long timeout, long usec, socket_t s) {
int timeout_ms;
ssh_pollfd_t fds;
int rc = 0;
int ret;
socklen_t len = sizeof(rc);
/* I know we're losing some precision. But it's not like poll-like family
* type of mechanisms are precise up to the microsecond.
*/
timeout_ms=timeout * 1000 + usec / 1000;
rc = ssh_socket_set_nonblocking(s);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to set socket non-blocking for %s:%d", host, port);
ssh_connect_socket_close(s);
return -1;
}
SSH_LOG(SSH_LOG_RARE, "Trying to connect to host: %s:%d with "
"timeout %d ms", host, port, timeout_ms);
/* The return value is checked later */
connect(s, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
fds.fd=s;
fds.revents=0;
fds.events=POLLOUT;
#ifdef _WIN32
fds.events |= POLLWRNORM;
#endif
rc = ssh_poll(&fds,1,timeout_ms);
if (rc == 0) {
/* timeout */
ssh_set_error(session, SSH_FATAL,
"Timeout while connecting to %s:%d", host, port);
ssh_connect_socket_close(s);
return -1;
}
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"poll error: %s", strerror(errno));
ssh_connect_socket_close(s);
return -1;
}
rc = -1;
/* Get connect(2) return code. Zero means no error */
ret = getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len);
if (ret < 0 || rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Connect to %s:%d failed: %s", host, port, strerror(rc));
ssh_connect_socket_close(s);
return -1;
}
/* s is connected ? */
SSH_LOG(SSH_LOG_PACKET, "Socket connected with timeout");
ret = ssh_socket_set_blocking(s);
if (ret < 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to set socket as blocking connecting to %s:%d failed: %s",
host, port, strerror(errno));
ssh_connect_socket_close(s);
return -1;
}
return s;
return getaddrinfo(host, service, &hints, ai);
}
static int set_tcp_nodelay(socket_t socket)
@@ -228,99 +152,6 @@ static int set_tcp_nodelay(socket_t socket)
sizeof(opt));
}
/**
* @internal
*
* @brief Connect to an IPv4 or IPv6 host specified by its IP address or
* hostname.
*
* @returns A file descriptor, < 0 on error.
*/
socket_t ssh_connect_host(ssh_session session, const char *host,
const char *bind_addr, int port, long timeout, long usec) {
socket_t s = -1;
int rc;
struct addrinfo *ai;
struct addrinfo *itr;
rc = getai(host, port, &ai);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
return -1;
}
for (itr = ai; itr != NULL; itr = itr->ai_next){
/* create socket */
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
if (s < 0) {
ssh_set_error(session, SSH_FATAL,
"Socket create failed: %s", strerror(errno));
continue;
}
if (bind_addr) {
struct addrinfo *bind_ai;
struct addrinfo *bind_itr;
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
rc = getai(bind_addr, 0, &bind_ai);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to resolve bind address %s (%s)",
bind_addr,
gai_strerror(rc));
freeaddrinfo(ai);
close(s);
return -1;
}
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
ssh_set_error(session, SSH_FATAL,
"Binding local address: %s", strerror(errno));
continue;
} else {
break;
}
}
freeaddrinfo(bind_ai);
/* Cannot bind to any local addresses */
if (bind_itr == NULL) {
ssh_connect_socket_close(s);
s = -1;
continue;
}
}
if (timeout || usec) {
socket_t ret = ssh_connect_ai_timeout(session, host, port, itr,
timeout, usec, s);
freeaddrinfo(ai);
return ret;
}
if (connect(s, itr->ai_addr, itr->ai_addrlen) < 0) {
ssh_set_error(session, SSH_FATAL, "Connect failed: %s", strerror(errno));
ssh_connect_socket_close(s);
s = -1;
continue;
} else {
/* We are connected */
break;
}
}
freeaddrinfo(ai);
return s;
}
/**
* @internal
*
@@ -331,102 +162,109 @@ socket_t ssh_connect_host(ssh_session session, const char *host,
* @warning very ugly !!!
*/
socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
const char *bind_addr, int port) {
socket_t s = -1;
int rc;
struct addrinfo *ai;
struct addrinfo *itr;
const char *bind_addr, int port)
{
socket_t s = -1;
int rc;
struct addrinfo *ai = NULL;
struct addrinfo *itr = NULL;
rc = getai(host, port, &ai);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to resolve hostname %s (%s)", host, gai_strerror(rc));
rc = getai(host, port, &ai);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to resolve hostname %s (%s)",
host, gai_strerror(rc));
return -1;
}
for (itr = ai; itr != NULL; itr = itr->ai_next){
/* create socket */
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
if (s < 0) {
ssh_set_error(session, SSH_FATAL,
"Socket create failed: %s", strerror(errno));
continue;
return -1;
}
if (bind_addr) {
struct addrinfo *bind_ai;
struct addrinfo *bind_itr;
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
rc = getai(bind_addr, 0, &bind_ai);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to resolve bind address %s (%s)",
bind_addr,
gai_strerror(rc));
ssh_connect_socket_close(s);
s=-1;
break;
}
for (bind_itr = bind_ai; bind_itr != NULL; bind_itr = bind_itr->ai_next) {
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
ssh_set_error(session, SSH_FATAL,
"Binding local address: %s", strerror(errno));
continue;
} else {
break;
for (itr = ai; itr != NULL; itr = itr->ai_next) {
/* create socket */
s = socket(itr->ai_family, itr->ai_socktype, itr->ai_protocol);
if (s < 0) {
ssh_set_error(session, SSH_FATAL,
"Socket create failed: %s", strerror(errno));
continue;
}
}
freeaddrinfo(bind_ai);
/* Cannot bind to any local addresses */
if (bind_itr == NULL) {
ssh_connect_socket_close(s);
s = -1;
continue;
}
}
if (bind_addr) {
struct addrinfo *bind_ai;
struct addrinfo *bind_itr;
rc = ssh_socket_set_nonblocking(s);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to set socket non-blocking for %s:%d", host, port);
ssh_connect_socket_close(s);
s = -1;
continue;
}
SSH_LOG(SSH_LOG_PACKET, "Resolving %s", bind_addr);
if (session->opts.nodelay) {
/* For winsock, socket options are only effective before connect */
rc = set_tcp_nodelay(s);
rc = getai(bind_addr, 0, &bind_ai);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to resolve bind address %s (%s)",
bind_addr,
gai_strerror(rc));
ssh_connect_socket_close(s);
s = -1;
break;
}
for (bind_itr = bind_ai;
bind_itr != NULL;
bind_itr = bind_itr->ai_next)
{
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
ssh_set_error(session, SSH_FATAL,
"Binding local address: %s", strerror(errno));
continue;
} else {
break;
}
}
freeaddrinfo(bind_ai);
/* Cannot bind to any local addresses */
if (bind_itr == NULL) {
ssh_connect_socket_close(s);
s = -1;
continue;
}
}
rc = ssh_socket_set_nonblocking(s);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to set TCP_NODELAY on socket: %s", strerror(errno));
"Failed to set socket non-blocking for %s:%d",
host, port);
ssh_connect_socket_close(s);
s = -1;
continue;
}
if (session->opts.nodelay) {
/* For winsock, socket options are only effective before connect */
rc = set_tcp_nodelay(s);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Failed to set TCP_NODELAY on socket: %s",
strerror(errno));
ssh_connect_socket_close(s);
s = -1;
continue;
}
}
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;
}
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;
}
freeaddrinfo(ai);
break;
}
freeaddrinfo(ai);
return s;
return s;
}
/**
@@ -435,11 +273,13 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
* @{
*/
static int ssh_select_cb (socket_t fd, int revents, void *userdata){
fd_set *set = (fd_set *)userdata;
if(revents & POLLIN)
FD_SET(fd, set);
return 0;
static int ssh_select_cb (socket_t fd, int revents, void *userdata)
{
fd_set *set = (fd_set *)userdata;
if (revents & POLLIN) {
FD_SET(fd, set);
}
return 0;
}
/**
@@ -473,73 +313,84 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
* @see select(2)
*/
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
fd_set *readfds, struct timeval *timeout) {
fd_set origfds;
socket_t fd;
size_t i, j;
int rc;
int base_tm, tm;
struct ssh_timestamp ts;
ssh_event event = ssh_event_new();
int firstround=1;
fd_set *readfds, struct timeval *timeout)
{
fd_set origfds;
socket_t fd;
size_t i, j;
int rc;
int base_tm, tm;
struct ssh_timestamp ts;
ssh_event event = ssh_event_new();
int firstround = 1;
base_tm = tm=timeout->tv_sec * 1000 + timeout->tv_usec/1000;
for (i=0 ; channels[i] != NULL; ++i){
ssh_event_add_session(event, channels[i]->session);
}
ZERO_STRUCT(origfds);
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;
FD_ZERO(readfds);
ssh_timestamp_init(&ts);
do {
/* Poll every channel */
j = 0;
for (i = 0; channels[i]; i++) {
if(ssh_channel_poll(channels[i], 0) != 0) {
outchannels[j] = channels[i];
j++;
} else if(ssh_channel_poll(channels[i], 1) != 0) {
outchannels[j] = channels[i];
j++;
}
base_tm = tm = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000);
for (i = 0 ; channels[i] != NULL; ++i) {
ssh_event_add_session(event, channels[i]->session);
}
outchannels[j] = NULL;
if(j != 0)
break;
/* watch if a user socket was triggered */
for (fd = 0; fd < maxfd; fd++) {
ZERO_STRUCT(origfds);
FD_ZERO(&origfds);
for (fd = 0; fd < maxfd ; fd++) {
if (FD_ISSET(fd, readfds)) {
goto out;
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
FD_SET(fd, &origfds);
}
}
outchannels[0] = NULL;
FD_ZERO(readfds);
ssh_timestamp_init(&ts);
do {
/* Poll every channel */
j = 0;
for (i = 0; channels[i]; i++) {
rc = ssh_channel_poll(channels[i], 0);
if (rc != 0) {
outchannels[j] = channels[i];
j++;
} else {
rc = ssh_channel_poll(channels[i], 1);
if (rc != 0) {
outchannels[j] = channels[i];
j++;
}
}
}
/* If the timeout is elapsed, we should go out */
if(!firstround && ssh_timeout_elapsed(&ts, base_tm))
goto out;
/* since there's nothing, let's fire the polling */
rc = ssh_event_dopoll(event,tm);
if (rc == SSH_ERROR){
goto out;
}
tm = ssh_timeout_update(&ts, base_tm);
firstround=0;
} while (1);
outchannels[j] = NULL;
if (j != 0) {
break;
}
/* watch if a user socket was triggered */
for (fd = 0; fd < maxfd; fd++) {
if (FD_ISSET(fd, readfds)) {
goto out;
}
}
/* If the timeout is elapsed, we should go out */
if (!firstround && ssh_timeout_elapsed(&ts, base_tm)) {
goto out;
}
/* since there's nothing, let's fire the polling */
rc = ssh_event_dopoll(event,tm);
if (rc == 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);
for (fd = 0; fd < maxfd; fd++) {
if (FD_ISSET(fd, &origfds)) {
ssh_event_remove_fd(event, fd);
}
}
}
ssh_event_free(event);
return SSH_OK;
ssh_event_free(event);
return SSH_OK;
}
/** @} */

View File

@@ -39,6 +39,10 @@
#include "libssh/pki.h"
#include "libssh/bignum.h"
#ifdef HAVE_OPENSSL_X25519
#include <openssl/err.h>
#endif
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply);
static ssh_packet_callback dh_client_callbacks[] = {
@@ -52,58 +56,221 @@ static struct ssh_packet_callbacks_struct ssh_curve25519_client_callbacks = {
.user = NULL
};
static int ssh_curve25519_init(ssh_session session)
{
int rc;
#ifdef HAVE_OPENSSL_X25519
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
size_t pkey_len = CURVE25519_PRIVKEY_SIZE;
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
if (pctx == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 context: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
rc = EVP_PKEY_keygen_init(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 keygen: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_CTX_free(pctx);
return SSH_ERROR;
}
rc = EVP_PKEY_keygen(pctx, &pkey);
EVP_PKEY_CTX_free(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate X25519 keys: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
if (session->server) {
rc = EVP_PKEY_get_raw_public_key(pkey,
session->next_crypto->curve25519_server_pubkey,
&pubkey_len);
} else {
rc = EVP_PKEY_get_raw_public_key(pkey,
session->next_crypto->curve25519_client_pubkey,
&pubkey_len);
}
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get X25519 raw public key: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
return SSH_ERROR;
}
rc = EVP_PKEY_get_raw_private_key(pkey,
session->next_crypto->curve25519_privkey,
&pkey_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get X25519 raw private key: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
return SSH_ERROR;
}
EVP_PKEY_free(pkey);
#else
rc = ssh_get_random(session->next_crypto->curve25519_privkey,
CURVE25519_PRIVKEY_SIZE, 1);
if (rc != 1) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
if (session->server) {
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
session->next_crypto->curve25519_privkey);
} else {
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
session->next_crypto->curve25519_privkey);
}
#endif /* HAVE_OPENSSL_X25519 */
return SSH_OK;
}
/** @internal
* @brief Starts curve25519-sha256@libssh.org / curve25519-sha256 key exchange
*/
int ssh_client_curve25519_init(ssh_session session){
int rc;
int ok;
int ssh_client_curve25519_init(ssh_session session)
{
int rc;
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (!ok) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
rc = ssh_curve25519_init(session);
if (rc != SSH_OK) {
return rc;
}
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
session->next_crypto->curve25519_privkey);
rc = ssh_buffer_pack(session->out_buffer,
"bdP",
SSH2_MSG_KEX_ECDH_INIT,
CURVE25519_PUBKEY_SIZE,
(size_t)CURVE25519_PUBKEY_SIZE,
session->next_crypto->curve25519_client_pubkey);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
rc = ssh_buffer_pack(session->out_buffer,
"bdP",
SSH2_MSG_KEX_ECDH_INIT,
CURVE25519_PUBKEY_SIZE,
(size_t)CURVE25519_PUBKEY_SIZE, session->next_crypto->curve25519_client_pubkey);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_curve25519_client_callbacks);
session->dh_handshake_state = DH_STATE_INIT_SENT;
rc = ssh_packet_send(session);
/* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_curve25519_client_callbacks);
session->dh_handshake_state = DH_STATE_INIT_SENT;
rc = ssh_packet_send(session);
return rc;
return rc;
}
static int ssh_curve25519_build_k(ssh_session session) {
ssh_curve25519_pubkey k;
static int ssh_curve25519_build_k(ssh_session session)
{
ssh_curve25519_pubkey k;
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);
#ifdef HAVE_OPENSSL_X25519
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL, *pubkey = NULL;
size_t shared_key_len;
int rc;
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
if (session->next_crypto->shared_secret == NULL) {
return SSH_ERROR;
}
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
session->next_crypto->curve25519_privkey,
CURVE25519_PRIVKEY_SIZE);
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create X25519 EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
pctx = EVP_PKEY_CTX_new(pkey, NULL);
if (pctx == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 context: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
return SSH_ERROR;
}
rc = EVP_PKEY_derive_init(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 key derivation: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(pctx);
return SSH_ERROR;
}
if (session->server) {
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
} else {
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
}
if (pubkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create X25519 public key EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(pctx);
return SSH_ERROR;
}
rc = EVP_PKEY_derive_set_peer(pctx, pubkey);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to set peer X25519 public key: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
EVP_PKEY_free(pubkey);
EVP_PKEY_CTX_free(pctx);
return SSH_ERROR;
}
rc = EVP_PKEY_derive(pctx,
k,
&shared_key_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to derive X25519 shared secret: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
EVP_PKEY_free(pubkey);
EVP_PKEY_CTX_free(pctx);
return SSH_ERROR;
}
#else
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);
}
#endif /* HAVE_OPENSSL_X25519 */
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
if (session->next_crypto->shared_secret == NULL) {
return SSH_ERROR;
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
ssh_log_hexdump("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
ssh_log_hexdump("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
#endif
@@ -221,8 +388,8 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
ssh_string sig_blob = NULL;
int ok;
int rc;
(void)type;
(void)user;
@@ -245,19 +412,16 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
}
memcpy(session->next_crypto->curve25519_client_pubkey,
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
ssh_string_free(q_c_string);
/* Build server's keypair */
ok = ssh_get_random(session->next_crypto->curve25519_privkey, CURVE25519_PRIVKEY_SIZE, 1);
if (!ok) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
rc = ssh_curve25519_init(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Failed to generate curve25519 keys");
goto error;
}
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
session->next_crypto->curve25519_privkey);
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
if (rc < 0) {
ssh_set_error_oom(session);
@@ -272,7 +436,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
rc = ssh_get_key_params(session, &privkey, &digest);
if (rc == SSH_ERROR) {
goto error;
}
@@ -315,7 +479,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
goto error;
}
/* add signature blob */
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
goto error;

View File

@@ -107,7 +107,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
int blen;
bignum pmin1 = NULL, one = NULL;
bignum_CTX ctx = bignum_ctx_new();
bignum modulus, generator;
bignum modulus = NULL, generator = NULL;
const_bignum pubkey;
(void) type;
(void) user;
@@ -179,14 +179,18 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
bignum_ctx_free(ctx);
ctx = NULL;
/* all checks passed, set parameters */
/* all checks passed, set parameters (the BNs are copied in openssl backend) */
rc = ssh_dh_set_parameters(session->next_crypto->dh_ctx,
modulus, generator);
if (rc != SSH_OK) {
bignum_safe_free(modulus);
bignum_safe_free(generator);
goto error;
}
#ifdef HAVE_LIBCRYPTO
bignum_safe_free(modulus);
bignum_safe_free(generator);
#endif
modulus = NULL;
generator = NULL;
/* compute and send DH public parameter */
rc = ssh_dh_keypair_gen_keys(session->next_crypto->dh_ctx,
@@ -194,8 +198,13 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
if (rc == SSH_ERROR) {
goto error;
}
rc = ssh_dh_keypair_get_keys(session->next_crypto->dh_ctx,
DH_CLIENT_KEYPAIR, NULL, &pubkey);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_buffer_pack(session->out_buffer,
"bB",
SSH2_MSG_KEX_DH_GEX_INIT,
@@ -216,6 +225,8 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group)
return SSH_PACKET_USED;
error:
bignum_safe_free(modulus);
bignum_safe_free(generator);
bignum_safe_free(one);
bignum_safe_free(pmin1);
if(!bignum_ctx_invalid(ctx)) {
@@ -262,6 +273,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
rc = ssh_dh_compute_shared_secret(session->next_crypto->dh_ctx,
DH_CLIENT_KEYPAIR, DH_SERVER_KEYPAIR,
&session->next_crypto->shared_secret);
ssh_dh_debug_crypto(session->next_crypto);
if (rc == SSH_ERROR) {
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
goto error;
@@ -636,8 +648,8 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request)
generator);
#ifdef HAVE_LIBCRYPTO
bignum_safe_free(generator);
bignum_safe_free(modulus);
bignum_safe_free(generator);
bignum_safe_free(modulus);
#endif
if (rc != SSH_OK) {

View File

@@ -373,6 +373,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
rc = ssh_dh_compute_shared_secret(session->next_crypto->dh_ctx,
DH_CLIENT_KEYPAIR, DH_SERVER_KEYPAIR,
&session->next_crypto->shared_secret);
ssh_dh_debug_crypto(session->next_crypto);
if (rc == SSH_ERROR){
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
goto error;
@@ -430,6 +431,7 @@ int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet)
{
struct ssh_crypto_struct *crypto = session->next_crypto;
ssh_key privkey = NULL;
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
ssh_string sig_blob = NULL;
ssh_string pubkey_blob = NULL;
bignum client_pubkey;
@@ -455,13 +457,14 @@ int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet)
goto error;
}
rc = ssh_get_key_params(session, &privkey);
rc = ssh_get_key_params(session, &privkey, &digest);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_dh_compute_shared_secret(crypto->dh_ctx,
DH_SERVER_KEYPAIR, DH_CLIENT_KEYPAIR,
&crypto->shared_secret);
ssh_dh_debug_crypto(crypto);
if (rc == SSH_ERROR) {
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
goto error;
@@ -471,7 +474,7 @@ int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet)
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
goto error;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
goto error;

View File

@@ -41,6 +41,27 @@ struct dh_ctx {
DH *keypair[2];
};
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c)
{
#ifdef DEBUG_CRYPTO
const_bignum x = NULL, y = NULL, e = NULL, f = NULL;
ssh_dh_keypair_get_keys(c->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
ssh_dh_keypair_get_keys(c->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
ssh_print_bignum("x", x);
ssh_print_bignum("y", y);
ssh_print_bignum("e", e);
ssh_print_bignum("f", f);
ssh_log_hexdump("Session server cookie", c->server_kex.cookie, 16);
ssh_log_hexdump("Session client cookie", c->client_kex.cookie, 16);
ssh_print_bignum("k", c->shared_secret);
#else
(void)c; /* UNUSED_PARAM */
#endif
}
int ssh_dh_keypair_get_keys(struct dh_ctx *ctx, int peer,
const_bignum *priv, const_bignum *pub)
{
@@ -96,12 +117,14 @@ int ssh_dh_get_parameters(struct dh_ctx *ctx,
int ssh_dh_set_parameters(struct dh_ctx *ctx,
const bignum modulus, const bignum generator)
{
size_t i;
int rc;
if ((ctx == NULL) || (modulus == NULL) || (generator == NULL)) {
return SSH_ERROR;
}
for (int i = 0; i < 2; i++) {
for (i = 0; i < 2; i++) {
bignum p = NULL;
bignum g = NULL;

View File

@@ -60,6 +60,28 @@ struct dh_ctx {
bignum modulus;
};
void ssh_dh_debug_crypto(struct ssh_crypto_struct *c)
{
#ifdef DEBUG_CRYPTO
const_bignum x = NULL, y = NULL, e = NULL, f = NULL;
ssh_dh_keypair_get_keys(c->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
ssh_dh_keypair_get_keys(c->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
ssh_print_bignum("p", c->dh_ctx->modulus);
ssh_print_bignum("g", c->dh_ctx->generator);
ssh_print_bignum("x", x);
ssh_print_bignum("y", y);
ssh_print_bignum("e", e);
ssh_print_bignum("f", f);
ssh_log_hexdump("Session server cookie", c->server_kex.cookie, 16);
ssh_log_hexdump("Session client cookie", c->client_kex.cookie, 16);
ssh_print_bignum("k", c->shared_secret);
#else
(void)c; /* UNUSED_PARAM */
#endif
}
static void ssh_dh_free_modulus(struct dh_ctx *ctx)
{
if ((ctx->modulus != ssh_dh_group1) &&
@@ -263,30 +285,6 @@ void ssh_dh_cleanup(struct ssh_crypto_struct *crypto)
crypto->dh_ctx = NULL;
}
#ifdef DEBUG_CRYPTO
static void ssh_dh_debug(ssh_session session)
{
struct ssh_crypto_struct *crypto = session->next_crypto;
const_bignum x, y, e, f;
ssh_dh_keypair_get_keys(crypto->dh_ctx, DH_CLIENT_KEYPAIR, &x, &e);
ssh_dh_keypair_get_keys(crypto->dh_ctx, DH_SERVER_KEYPAIR, &y, &f);
ssh_print_bignum("p", crypto->dh_ctx->modulus);
ssh_print_bignum("g", crypto->dh_ctx->generator);
ssh_print_bignum("x", x);
ssh_print_bignum("y", y);
ssh_print_bignum("e", e);
ssh_print_bignum("f", f);
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("k", session->next_crypto->shared_secret);
}
#else
#define ssh_dh_debug(session)
#endif
/** @internal
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
* security as well as the corresponding public key.
@@ -370,7 +368,6 @@ int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
done:
bignum_ctx_free(ctx);
ssh_dh_debug(session);
if (rc != 1) {
return SSH_ERROR;
}

View File

@@ -181,9 +181,9 @@ int ecdh_build_k(ssh_session session) {
session->next_crypto->ecdh_privkey = NULL;
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
ssh_log_hexdump("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
ssh_log_hexdump("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
#endif
@@ -206,6 +206,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
bignum_CTX ctx;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
ssh_string sig_blob = NULL;
ssh_string pubkey_blob = NULL;
int curve;
@@ -277,7 +278,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
rc = ssh_get_key_params(session, &privkey, &digest);
if (rc == SSH_ERROR) {
goto error;
}
@@ -288,7 +289,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
goto error;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
goto error;

View File

@@ -242,9 +242,9 @@ int ecdh_build_k(ssh_session session)
session->next_crypto->ecdh_privkey = NULL;
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
ssh_log_hexdump("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
ssh_log_hexdump("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
#endif
@@ -273,6 +273,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
gcry_sexp_t key = NULL;
/* SSH host keys (rsa,dsa,ecdsa) */
ssh_key privkey;
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
ssh_string sig_blob = NULL;
ssh_string pubkey_blob = NULL;
int rc = SSH_ERROR;
@@ -325,7 +326,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
rc = ssh_get_key_params(session, &privkey, &digest);
if (rc != SSH_OK) {
goto out;
}
@@ -336,7 +337,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
goto out;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
rc = SSH_ERROR;

View File

@@ -188,6 +188,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
ssh_string q_s_string = NULL;
mbedtls_ecp_group grp;
ssh_key privkey = NULL;
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
ssh_string sig_blob = NULL;
ssh_string pubkey_blob = NULL;
int rc;
@@ -250,7 +251,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey);
rc = ssh_get_key_params(session, &privkey, &digest);
if (rc == SSH_ERROR) {
rc = SSH_ERROR;
goto out;
@@ -263,7 +264,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
goto out;
}
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
rc = SSH_ERROR;

189
src/kex.c
View File

@@ -547,7 +547,7 @@ void ssh_list_kex(struct ssh_kex_struct *kex) {
int i = 0;
#ifdef DEBUG_CRYPTO
ssh_print_hexa("session cookie", kex->cookie, 16);
ssh_log_hexdump("session cookie", kex->cookie, 16);
#endif
for(i = 0; i < SSH_KEX_METHODS; i++) {
@@ -561,103 +561,94 @@ 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
* as some hostkey mechanisms may be present in known_hosts files.
*
* @returns a cstring containing a comma-separated list of hostkey methods.
* NULL if no method matches
*/
char *ssh_client_select_hostkeys(ssh_session session)
{
char methods_buffer[128]={0};
char tail_buffer[128]={0};
const char *wanted = NULL;
char *wanted_without_certs = NULL;
char *known_hosts_algorithms = NULL;
char *known_hosts_ordered = NULL;
char *new_hostkeys = NULL;
static const char *preferred_hostkeys[] = {
"ssh-ed25519",
"ecdsa-sha2-nistp521",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp256",
"rsa-sha2-512",
"rsa-sha2-256",
"ssh-rsa",
#ifdef HAVE_DSA
"ssh-dss",
#endif
NULL
};
struct ssh_list *algo_list = NULL;
struct ssh_iterator *it = NULL;
size_t algo_count;
int needcomma = 0;
size_t i, len;
char *fips_hostkeys = NULL;
algo_list = ssh_known_hosts_get_algorithms(session);
if (algo_list == NULL) {
wanted = session->opts.wanted_methods[SSH_HOSTKEYS];
if (wanted == NULL) {
if (ssh_fips_mode()) {
wanted = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
} else {
wanted = ssh_kex_get_default_methods(SSH_HOSTKEYS);
}
}
/* This removes the certificate types, unsupported for now */
wanted_without_certs = ssh_find_all_matching(HOSTKEYS, wanted);
if (wanted_without_certs == NULL) {
SSH_LOG(SSH_LOG_WARNING,
"List of allowed host key algorithms is empty or contains only "
"unsupported algorithms");
return NULL;
}
algo_count = ssh_list_count(algo_list);
if (algo_count == 0) {
ssh_list_free(algo_list);
return NULL;
}
SSH_LOG(SSH_LOG_DEBUG,
"Order of wanted host keys: \"%s\"",
wanted_without_certs);
for (i = 0; preferred_hostkeys[i] != NULL; ++i) {
bool found = false;
/* This is a signature type: We list also the SHA2 extensions */
enum ssh_keytypes_e base_preferred =
ssh_key_type_from_signature_name(preferred_hostkeys[i]);
for (it = ssh_list_get_iterator(algo_list);
it != NULL;
it = it->next) {
const char *algo = ssh_iterator_value(const char *, it);
/* This is always key type so we do not have to care for the
* SHA2 extension */
enum ssh_keytypes_e base_algo = ssh_key_type_from_name(algo);
if (base_preferred == base_algo) {
/* Matching the keys already verified it is a known type */
if (needcomma) {
strncat(methods_buffer,
",",
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
}
strncat(methods_buffer,
preferred_hostkeys[i],
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
needcomma = 1;
found = true;
}
}
/* Collect the rest of the algorithms in other buffer, that will
* follow the preferred buffer. This will signalize all the algorithms
* we are willing to accept.
*/
if (!found) {
snprintf(tail_buffer + strlen(tail_buffer),
sizeof(tail_buffer) - strlen(tail_buffer),
",%s", preferred_hostkeys[i]);
}
}
ssh_list_free(algo_list);
if (strlen(methods_buffer) == 0) {
known_hosts_algorithms = ssh_known_hosts_get_algorithms_names(session);
if (known_hosts_algorithms == NULL) {
SSH_LOG(SSH_LOG_DEBUG,
"No supported kex method for existing key in known_hosts file");
return NULL;
"No key found in known_hosts; "
"changing host key method to \"%s\"",
wanted_without_certs);
return wanted_without_certs;
}
/* Append the supported list to the preferred.
* The length is maximum 128 + 128 + 1, which will not overflow
*/
len = strlen(methods_buffer) + strlen(tail_buffer) + 1;
new_hostkeys = malloc(len);
SSH_LOG(SSH_LOG_DEBUG,
"Algorithms found in known_hosts files: \"%s\"",
known_hosts_algorithms);
/* Filter and order the keys from known_hosts according to wanted list */
known_hosts_ordered = ssh_find_all_matching(known_hosts_algorithms,
wanted_without_certs);
SAFE_FREE(known_hosts_algorithms);
if (known_hosts_ordered == NULL) {
SSH_LOG(SSH_LOG_DEBUG,
"No key found in known_hosts is allowed; "
"changing host key method to \"%s\"",
wanted_without_certs);
return wanted_without_certs;
}
/* Append the other supported keys after the preferred ones
* This function tolerates NULL pointers in parameters */
new_hostkeys = ssh_append_without_duplicates(known_hosts_ordered,
wanted_without_certs);
SAFE_FREE(known_hosts_ordered);
SAFE_FREE(wanted_without_certs);
if (new_hostkeys == NULL) {
ssh_set_error_oom(session);
return NULL;
}
snprintf(new_hostkeys, len,
"%s%s", methods_buffer, tail_buffer);
if (ssh_fips_mode()) {
/* Filter out algorithms not allowed in FIPS mode */
fips_hostkeys = ssh_keep_fips_algos(SSH_HOSTKEYS, new_hostkeys);
SAFE_FREE(new_hostkeys);
if (fips_hostkeys == NULL) {
SSH_LOG(SSH_LOG_WARNING,
"None of the wanted host keys or keys in known_hosts files "
"is allowed in FIPS mode.");
return NULL;
}
new_hostkeys = fips_hostkeys;
}
SSH_LOG(SSH_LOG_DEBUG,
"Changing host key method to \"%s\"",
@@ -672,7 +663,7 @@ char *ssh_client_select_hostkeys(ssh_session session)
*/
int ssh_set_client_kex(ssh_session session)
{
struct ssh_kex_struct *client= &session->next_crypto->client_kex;
struct ssh_kex_struct *client = &session->next_crypto->client_kex;
const char *wanted;
char *kex = NULL;
char *kex_tmp = NULL;
@@ -687,14 +678,22 @@ int ssh_set_client_kex(ssh_session session)
}
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);
}
/* Set the list of allowed algorithms in order of preference, if it hadn't
* been set yet. */
for (i = 0; i < KEX_METHODS_SIZE; i++) {
if (i == SSH_HOSTKEYS) {
/* Set the hostkeys in the following order:
* - First: keys present in known_hosts files ordered by preference
* - Next: other wanted algorithms ordered by preference */
client->methods[i] = ssh_client_select_hostkeys(session);
if (client->methods[i] == NULL) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
continue;
}
wanted = session->opts.wanted_methods[i];
if (wanted == NULL) {
if (ssh_fips_mode()) {
@@ -1120,7 +1119,7 @@ int ssh_make_sessionid(ssh_session session)
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
ssh_log_hexdump("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
#endif
switch (session->next_crypto->kex_type) {
@@ -1196,8 +1195,8 @@ int ssh_make_sessionid(ssh_session session)
}
#ifdef DEBUG_CRYPTO
printf("Session hash: \n");
ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
ssh_log_hexdump("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
ssh_log_hexdump("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
#endif
rc = SSH_OK;
@@ -1384,15 +1383,15 @@ int ssh_generate_session_keys(ssh_session session)
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Client to Server IV", IV_cli_to_srv, IV_len);
ssh_print_hexa("Server to Client IV", IV_srv_to_cli, IV_len);
ssh_print_hexa("Client to Server Encryption Key", enckey_cli_to_srv,
ssh_log_hexdump("Client to Server IV", IV_cli_to_srv, IV_len);
ssh_log_hexdump("Server to Client IV", IV_srv_to_cli, IV_len);
ssh_log_hexdump("Client to Server Encryption Key", enckey_cli_to_srv,
enckey_cli_to_srv_len);
ssh_print_hexa("Server to Client Encryption Key", enckey_srv_to_cli,
ssh_log_hexdump("Server to Client Encryption Key", enckey_srv_to_cli,
enckey_srv_to_cli_len);
ssh_print_hexa("Client to Server Integrity Key", intkey_cli_to_srv,
ssh_log_hexdump("Client to Server Integrity Key", intkey_cli_to_srv,
intkey_cli_to_srv_len);
ssh_print_hexa("Server to Client Integrity Key", intkey_srv_to_cli,
ssh_log_hexdump("Server to Client Integrity Key", intkey_srv_to_cli,
intkey_srv_to_cli_len);
#endif

View File

@@ -405,8 +405,12 @@ int ssh_is_server_known(ssh_session session)
if ((ret == SSH_SERVER_NOT_KNOWN) &&
(session->opts.StrictHostKeyChecking == 0)) {
ssh_write_knownhost(session);
ret = SSH_SERVER_KNOWN_OK;
int rv = ssh_session_update_known_hosts(session);
if (rv != SSH_OK) {
ret = SSH_SERVER_ERROR;
} else {
ret = SSH_SERVER_KNOWN_OK;
}
}
SAFE_FREE(host);
@@ -492,10 +496,12 @@ char * ssh_dump_knownhost(ssh_session session) {
* @deprecated Please use ssh_session_update_known_hosts()
* @brief This function is deprecated
*/
int ssh_write_knownhost(ssh_session session) {
int ssh_write_knownhost(ssh_session session)
{
FILE *file;
char *buffer;
char *buffer = NULL;
char *dir;
int rc;
if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) {
@@ -504,33 +510,45 @@ int ssh_write_knownhost(ssh_session session) {
}
}
/* Check if directory exists and create it if not */
dir = ssh_dirname(session->opts.knownhosts);
if (dir == NULL) {
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
return SSH_ERROR;
}
errno = 0;
file = fopen(session->opts.knownhosts, "a");
if (file == NULL) {
if (errno == ENOENT) {
dir = ssh_dirname(session->opts.knownhosts);
if (dir == NULL) {
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
return SSH_ERROR;
}
if (!ssh_file_readaccess_ok(dir)) {
if (ssh_mkdir(dir, 0700) < 0) {
ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory.", dir);
rc = ssh_mkdirs(dir, 0700);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory: %s",
dir, strerror(errno));
SAFE_FREE(dir);
return SSH_ERROR;
}
SAFE_FREE(dir);
errno = 0;
file = fopen(session->opts.knownhosts, "a");
if (file == NULL) {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s"
" for appending: %s",
session->opts.knownhosts, strerror(errno));
return SSH_ERROR;
}
} else {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s for appending: %s",
session->opts.knownhosts, strerror(errno));
return SSH_ERROR;
}
}
SAFE_FREE(dir);
file = fopen(session->opts.knownhosts, "a");
if (file == NULL) {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s for appending: %s",
session->opts.knownhosts, strerror(errno));
return SSH_ERROR;
}
buffer = ssh_dump_knownhost(session);
if (buffer == NULL) {
rc = ssh_session_export_known_hosts_entry(session, &buffer);
if (rc != SSH_OK) {
fclose(file);
return SSH_ERROR;
}

View File

@@ -42,6 +42,7 @@
#include "libssh/pki.h"
#include "libssh/dh.h"
#include "libssh/knownhosts.h"
#include "libssh/token.h"
/**
* @addtogroup libssh_session
@@ -306,7 +307,7 @@ static char *ssh_session_get_host_port(ssh_session session)
if (session->opts.host == NULL) {
ssh_set_error(session,
SSH_FATAL,
"Can't verify server inn known hosts if the host we "
"Can't verify server in known hosts if the host we "
"should connect to has not been set");
return NULL;
@@ -451,6 +452,146 @@ error:
return NULL;
}
/**
* @internal
*
* @brief Returns a static string containing a list of the signature types the
* given key type can generate.
*
* @returns A static cstring containing the signature types the key is able to
* generate separated by commas; NULL in case of error
*/
static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e type)
{
switch (type) {
case SSH_KEYTYPE_RSA:
return "rsa-sha2-512,rsa-sha2-256,ssh-rsa";
case SSH_KEYTYPE_ED25519:
return "ssh-ed25519";
#ifdef HAVE_DSA
case SSH_KEYTYPE_DSS:
return "ssh-dss";
#endif
#ifdef HAVE_ECDH
case SSH_KEYTYPE_ECDSA_P256:
return "ecdsa-sha2-nistp256";
case SSH_KEYTYPE_ECDSA_P384:
return "ecdsa-sha2-nistp384";
case SSH_KEYTYPE_ECDSA_P521:
return "ecdsa-sha2-nistp521";
#endif
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_WARN, "The given type %d is not a base private key type "
"or is unsupported", type);
return NULL;
}
}
/**
* @internal
* @brief Get the host keys algorithms identifiers from the known_hosts files
*
* This expands the signatures types that can be generated from the keys types
* present in the known_hosts files
*
* @param[in] session The ssh session to use.
*
* @return A newly allocated cstring containing a list of signature algorithms
* that can be generated by the host using the keys listed in the known_hosts
* files, NULL on error.
*/
char *ssh_known_hosts_get_algorithms_names(ssh_session session)
{
char methods_buffer[256 + 1] = {0};
struct ssh_list *entry_list = NULL;
struct ssh_iterator *it = NULL;
char *host_port = NULL;
size_t count;
bool needcomma = false;
char *names;
int rc;
if (session->opts.knownhosts == NULL ||
session->opts.global_knownhosts == NULL) {
if (ssh_options_apply(session) < 0) {
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Can't find a known_hosts file");
return NULL;
}
}
host_port = ssh_session_get_host_port(session);
if (host_port == NULL) {
return NULL;
}
rc = ssh_known_hosts_read_entries(host_port,
session->opts.knownhosts,
&entry_list);
if (rc != 0) {
SAFE_FREE(host_port);
ssh_list_free(entry_list);
return NULL;
}
rc = ssh_known_hosts_read_entries(host_port,
session->opts.global_knownhosts,
&entry_list);
SAFE_FREE(host_port);
if (rc != 0) {
ssh_list_free(entry_list);
return NULL;
}
if (entry_list == NULL) {
return NULL;
}
count = ssh_list_count(entry_list);
if (count == 0) {
ssh_list_free(entry_list);
return NULL;
}
for (it = ssh_list_get_iterator(entry_list);
it != NULL;
it = ssh_list_get_iterator(entry_list))
{
struct ssh_knownhosts_entry *entry = NULL;
const char *algo = NULL;
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
algo = ssh_known_host_sigs_from_hostkey_type(entry->publickey->type);
if (algo == NULL) {
continue;
}
if (needcomma) {
strncat(methods_buffer,
",",
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
}
strncat(methods_buffer,
algo,
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
needcomma = true;
ssh_knownhosts_entry_free(entry);
ssh_list_remove(entry_list, it);
}
ssh_list_free(entry_list);
names = ssh_remove_duplicates(methods_buffer);
return names;
}
/**
* @brief Parse a line from a known_hosts entry into a structure
*
@@ -638,14 +779,15 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
struct ssh_list *entry_list = NULL;
struct ssh_iterator *it = NULL;
char *host_port = NULL;
bool ok;
bool global_known_hosts_found = false;
bool known_hosts_found = false;
int rc;
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");
"Cannot find a known_hosts file");
return SSH_KNOWN_HOSTS_NOT_FOUND;
}
@@ -653,50 +795,67 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
if (session->opts.knownhosts == NULL &&
session->opts.global_knownhosts == NULL) {
ssh_set_error(session,
SSH_REQUEST_DENIED,
"No path set for a known_hosts file");
return SSH_KNOWN_HOSTS_NOT_FOUND;
}
if (session->opts.knownhosts != NULL) {
ok = ssh_file_readaccess_ok(session->opts.knownhosts);
if (!ok) {
return SSH_KNOWN_HOSTS_NOT_FOUND;
known_hosts_found = ssh_file_readaccess_ok(session->opts.knownhosts);
if (!known_hosts_found) {
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
session->opts.knownhosts);
}
}
if (session->opts.global_knownhosts != NULL) {
ok = ssh_file_readaccess_ok(session->opts.global_knownhosts);
if (!ok) {
return SSH_KNOWN_HOSTS_NOT_FOUND;
global_known_hosts_found =
ssh_file_readaccess_ok(session->opts.global_knownhosts);
if (!global_known_hosts_found) {
SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
session->opts.global_knownhosts);
}
}
if ((!known_hosts_found) && (!global_known_hosts_found)) {
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Cannot find a known_hosts file");
return SSH_KNOWN_HOSTS_NOT_FOUND;
}
host_port = ssh_session_get_host_port(session);
if (host_port == NULL) {
return SSH_KNOWN_HOSTS_ERROR;
}
if (session->opts.knownhosts != NULL) {
if (known_hosts_found) {
rc = ssh_known_hosts_read_entries(host_port,
session->opts.knownhosts,
&entry_list);
if (rc != 0) {
SAFE_FREE(host_port);
ssh_list_free(entry_list);
return SSH_KNOWN_HOSTS_UNKNOWN;
return SSH_KNOWN_HOSTS_ERROR;
}
}
if (session->opts.global_knownhosts != NULL) {
if (global_known_hosts_found) {
rc = ssh_known_hosts_read_entries(host_port,
session->opts.global_knownhosts,
&entry_list);
SAFE_FREE(host_port);
if (rc != 0) {
SAFE_FREE(host_port);
ssh_list_free(entry_list);
return SSH_KNOWN_HOSTS_UNKNOWN;
return SSH_KNOWN_HOSTS_ERROR;
}
}
SAFE_FREE(host_port);
if (ssh_list_count(entry_list) == 0) {
ssh_list_free(entry_list);
return SSH_KNOWN_HOSTS_UNKNOWN;
@@ -820,34 +979,41 @@ int ssh_session_update_known_hosts(ssh_session session)
}
}
/* Check if directory exists and create it if not */
dir = ssh_dirname(session->opts.knownhosts);
if (dir == NULL) {
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
return SSH_ERROR;
}
rc = ssh_file_readaccess_ok(dir);
if (rc == 0) {
rc = ssh_mkdir(dir, 0700);
} else {
rc = 0;
}
if (rc != 0) {
ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory.", dir);
SAFE_FREE(dir);
return SSH_ERROR;
}
SAFE_FREE(dir);
errno = 0;
fp = fopen(session->opts.knownhosts, "a");
if (fp == NULL) {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s for appending: %s",
session->opts.knownhosts, strerror(errno));
return SSH_ERROR;
if (errno == ENOENT) {
dir = ssh_dirname(session->opts.knownhosts);
if (dir == NULL) {
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
return SSH_ERROR;
}
rc = ssh_mkdirs(dir, 0700);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory: %s",
dir, strerror(errno));
SAFE_FREE(dir);
return SSH_ERROR;
}
SAFE_FREE(dir);
errno = 0;
fp = fopen(session->opts.knownhosts, "a");
if (fp == NULL) {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s"
" for appending: %s",
session->opts.knownhosts, strerror(errno));
return SSH_ERROR;
}
} else {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s for appending: %s",
session->opts.knownhosts, strerror(errno));
return SSH_ERROR;
}
}
rc = ssh_session_export_known_hosts_entry(session, &entry);

View File

@@ -686,8 +686,12 @@ static int aes_ctr_set_key(struct ssh_cipher_struct *cipher, void *key,
return SSH_OK;
}
static void aes_ctr_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
unsigned long len) {
static void
aes_ctr_encrypt(struct ssh_cipher_struct *cipher,
void *in,
void *out,
size_t len)
{
unsigned char tmp_buffer[AES_BLOCK_SIZE];
unsigned int num=0;
/* Some things are special with ctr128 :

View File

@@ -45,7 +45,7 @@ void ssh_mbedcry_bn_free(bignum bn)
SAFE_FREE(bn);
}
unsigned char *ssh_mbedcry_bn2num(bignum num, int radix)
unsigned char *ssh_mbedcry_bn2num(const_bignum num, int radix)
{
char *buf = NULL;
size_t olen;

View File

@@ -1491,12 +1491,18 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
msg->type = SSH_REQUEST_GLOBAL;
if (strcmp(request, "tcpip-forward") == 0) {
/* According to RFC4254, the client SHOULD reject this message */
if (session->client) {
goto reply_with_failure;
}
r = ssh_buffer_unpack(packet, "sd",
&msg->global_request.bind_address,
&msg->global_request.bind_port
);
if (r != SSH_OK){
goto error;
goto reply_with_failure;
}
msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
msg->global_request.want_reply = want_reply;
@@ -1516,11 +1522,17 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
return rc;
}
} else if (strcmp(request, "cancel-tcpip-forward") == 0) {
/* According to RFC4254, the client SHOULD reject this message */
if (session->client) {
goto reply_with_failure;
}
r = ssh_buffer_unpack(packet, "sd",
&msg->global_request.bind_address,
&msg->global_request.bind_port);
if (r != SSH_OK){
goto error;
goto reply_with_failure;
}
msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
msg->global_request.want_reply = want_reply;
@@ -1546,18 +1558,41 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){
ssh_message_global_request_reply_success(msg, 0);
}
} else {
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
rc = SSH_PACKET_NOT_USED;
SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, "
"want_reply = %d", request, want_reply);
goto reply_with_failure;
}
SAFE_FREE(msg);
SAFE_FREE(request);
return rc;
reply_with_failure:
/* Only report the failure if requested */
if (want_reply) {
r = ssh_buffer_add_u8(session->out_buffer,
SSH2_MSG_REQUEST_FAILURE);
if (r < 0) {
ssh_set_error_oom(session);
goto error;
}
r = ssh_packet_send(session);
if (r != SSH_OK) {
goto error;
}
} else {
SSH_LOG(SSH_LOG_PACKET,
"The requester doesn't want to know the request failed!");
}
/* Consume the message to avoid sending UNIMPLEMENTED later */
rc = SSH_PACKET_USED;
error:
SAFE_FREE(msg);
SAFE_FREE(request);
SSH_LOG(SSH_LOG_WARNING, "Invalid SSH_MSG_GLOBAL_REQUEST packet");
return SSH_PACKET_NOT_USED;
return rc;
}
#endif /* WITH_SERVER */

View File

@@ -130,6 +130,31 @@ int ssh_file_readaccess_ok(const char *file) {
return 1;
}
/**
* @brief Check if the given path is an existing directory and that is
* accessible for writing.
*
* @param[in] path Path to the directory to be checked
*
* @return Return 1 if the directory exists and is accessible; 0 otherwise
* */
int ssh_dir_writeable(const char *path)
{
struct _stat buffer;
int rc;
rc = _stat(path, &buffer);
if (rc < 0) {
return 0;
}
if ((buffer.st_mode & _S_IFDIR) && (buffer.st_mode & _S_IWRITE)) {
return 1;
}
return 0;
}
#define SSH_USEC_IN_SEC 1000000LL
#define SSH_SECONDS_SINCE_1601 11644473600LL
@@ -247,6 +272,31 @@ int ssh_file_readaccess_ok(const char *file)
return 1;
}
/**
* @brief Check if the given path is an existing directory and that is
* accessible for writing.
*
* @param[in] path Path to the directory to be checked
*
* @return Return 1 if the directory exists and is accessible; 0 otherwise
* */
int ssh_dir_writeable(const char *path)
{
struct stat buffer;
int rc;
rc = stat(path, &buffer);
if (rc < 0) {
return 0;
}
if (S_ISDIR(buffer.st_mode) && (buffer.st_mode & S_IWRITE)) {
return 1;
}
return 0;
}
char *ssh_get_local_username(void)
{
struct passwd pwd;
@@ -389,6 +439,193 @@ void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) {
free(hexa);
}
/**
* @brief Log the content of a buffer in hexadecimal format, similar to the
* output of 'hexdump -C' command.
*
* The first logged line is the given description followed by the length.
* Then the content of the buffer is logged 16 bytes per line in the following
* format:
*
* (offset) (first 8 bytes) (last 8 bytes) (the 16 bytes as ASCII char values)
*
* The output for a 16 bytes array containing values from 0x00 to 0x0f would be:
*
* "Example (16 bytes):"
* " 00000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................"
*
* The value for each byte as corresponding ASCII character is printed at the
* end if the value is printable. Otherwise it is replace with '.'.
*
* @param[in] descr A description for the content to be logged
* @param[in] what The buffer to be logged
* @param[in] len The length of the buffer given in what
*
* @note If a too long description is provided (which would result in a first
* line longer than 80 bytes), the function will fail.
*/
void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len)
{
size_t i;
char ascii[17];
const unsigned char *pc = NULL;
size_t count = 0;
ssize_t printed = 0;
/* The required buffer size is calculated from:
*
* 2 bytes for spaces at the beginning
* 8 bytes for the offset
* 2 bytes for spaces
* 24 bytes to print the first 8 bytes + spaces
* 1 byte for an extra space
* 24 bytes to print next 8 bytes + spaces
* 2 bytes for extra spaces
* 16 bytes for the content as ASCII characters at the end
* 1 byte for the ending '\0'
*
* Resulting in 80 bytes.
*
* Except for the first line (description + size), all lines have fixed
* length. If a too long description is used, the function will fail.
* */
char buffer[80];
/* Print description */
if (descr != NULL) {
printed = snprintf(buffer, sizeof(buffer), "%s ", descr);
if (printed < 0) {
goto error;
}
count += printed;
} else {
printed = snprintf(buffer, sizeof(buffer), "(NULL description) ");
if (printed < 0) {
goto error;
}
count += printed;
}
if (len == 0) {
printed = snprintf(buffer + count, sizeof(buffer) - count,
"(zero length):");
if (printed < 0) {
goto error;
}
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
return;
} else {
printed = snprintf(buffer + count, sizeof(buffer) - count,
"(%zu bytes):", len);
if (printed < 0) {
goto error;
}
count += printed;
}
if (what == NULL) {
printed = snprintf(buffer + count, sizeof(buffer) - count,
"(NULL)");
if (printed < 0) {
goto error;
}
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
return;
}
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
/* Reset state */
count = 0;
pc = what;
for (i = 0; i < len; i++) {
/* Add one space after printing 8 bytes */
if ((i % 8) == 0) {
if (i != 0) {
printed = snprintf(buffer + count, sizeof(buffer) - count, " ");
if (printed < 0) {
goto error;
}
count += printed;
}
}
/* Log previous line and reset state for new line */
if ((i % 16) == 0) {
if (i != 0) {
printed = snprintf(buffer + count, sizeof(buffer) - count,
" %s", ascii);
if (printed < 0) {
goto error;
}
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
count = 0;
}
/* Start a new line with the offset */
printed = snprintf(buffer, sizeof(buffer),
" %08zx ", i);
if (printed < 0) {
goto error;
}
count += printed;
}
/* Print the current byte hexadecimal representation */
printed = snprintf(buffer + count, sizeof(buffer) - count,
" %02x", pc[i]);
if (printed < 0) {
goto error;
}
count += printed;
/* If printable, store the ASCII character */
if (isprint(pc[i])) {
ascii[i % 16] = pc[i];
} else {
ascii[i % 16] = '.';
}
ascii[(i % 16) + 1] = '\0';
}
/* Add padding if not exactly 16 characters */
while ((i % 16) != 0) {
/* Add one space after printing 8 bytes */
if ((i % 8) == 0) {
if (i != 0) {
printed = snprintf(buffer + count, sizeof(buffer) - count, " ");
if (printed < 0) {
goto error;
}
count += printed;
}
}
printed = snprintf(buffer + count, sizeof(buffer) - count, " ");
if (printed < 0) {
goto error;
}
count += printed;
i++;
}
/* Print the last printable part */
printed = snprintf(buffer + count, sizeof(buffer) - count,
" %s", ascii);
if (printed < 0) {
goto error;
}
SSH_LOG(SSH_LOG_DEBUG, "%s", buffer);
return;
error:
SSH_LOG(SSH_LOG_WARN, "Could not print to buffer");
return;
}
/**
* @brief Check if libssh is the required version or get the version
* string.
@@ -713,16 +950,81 @@ char *ssh_basename (const char *path) {
*
* @return 0 on success, < 0 on error with errno set.
*/
int ssh_mkdir(const char *pathname, mode_t mode) {
int r;
int ssh_mkdir(const char *pathname, mode_t mode)
{
int r;
#ifdef _WIN32
r = _mkdir(pathname);
r = _mkdir(pathname);
#else
r = mkdir(pathname, mode);
r = mkdir(pathname, mode);
#endif
return r;
return r;
}
/**
* @brief Attempts to create a directory with the given pathname. The missing
* directories in the given pathname are created recursively.
*
* @param[in] pathname The path name to create the directory.
*
* @param[in] mode The permissions to use.
*
* @return 0 on success, < 0 on error with errno set.
*
* @note mode is ignored on Windows systems.
*/
int ssh_mkdirs(const char *pathname, mode_t mode)
{
int rc = 0;
char *parent = NULL;
if (pathname == NULL ||
pathname[0] == '\0' ||
!strcmp(pathname, "/") ||
!strcmp(pathname, "."))
{
errno = EINVAL;
return -1;
}
errno = 0;
#ifdef _WIN32
rc = _mkdir(pathname);
#else
rc = mkdir(pathname, mode);
#endif
if (rc < 0) {
/* If a directory was missing, try to create the parent */
if (errno == ENOENT) {
parent = ssh_dirname(pathname);
if (parent == NULL) {
errno = ENOMEM;
return -1;
}
rc = ssh_mkdirs(parent, mode);
if (rc < 0) {
/* We could not create the parent */
SAFE_FREE(parent);
return -1;
}
SAFE_FREE(parent);
/* Try again */
errno = 0;
#ifdef _WIN32
rc = _mkdir(pathname);
#else
rc = mkdir(pathname, mode);
#endif
}
}
return rc;
}
/**
@@ -825,6 +1127,7 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
for (i = 0; *p != '\0'; p++) {
if (*p != '%') {
escape:
buf[i] = *p;
i++;
if (i >= MAX_BUF_SIZE) {
@@ -841,6 +1144,8 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
}
switch (*p) {
case '%':
goto escape;
case 'd':
x = strdup(session->opts.sshdir);
break;

View File

@@ -1472,6 +1472,13 @@ int ssh_options_apply(ssh_session session) {
it != NULL;
it = it->next) {
char *id = (char *) it->data;
if (strncmp(id, "pkcs11:", 6) == 0) {
/* PKCS#11 URIs are using percent-encoding so we can not mix
* it with ssh expansion of ssh escape characters.
* Skip these identities now, before we will have PKCS#11 support
*/
continue;
}
tmp = ssh_path_expand_escape(session, id);
if (tmp == NULL) {
return -1;

View File

@@ -1438,37 +1438,54 @@ void ssh_packet_set_default_callbacks(ssh_session session){
* @brief dispatch the call of packet handlers callbacks for a received packet
* @param type type of packet
*/
void ssh_packet_process(ssh_session session, uint8_t type){
struct ssh_iterator *i;
int r=SSH_PACKET_NOT_USED;
ssh_packet_callbacks cb;
void ssh_packet_process(ssh_session session, uint8_t type)
{
struct ssh_iterator *i = NULL;
int rc = SSH_PACKET_NOT_USED;
ssh_packet_callbacks cb;
SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d",type);
if(session->packet_callbacks == NULL){
SSH_LOG(SSH_LOG_RARE,"Packet callback is not initialized !");
SSH_LOG(SSH_LOG_PACKET, "Dispatching handler for packet type %d", type);
if (session->packet_callbacks == NULL) {
SSH_LOG(SSH_LOG_RARE, "Packet callback is not initialized !");
return;
}
return;
}
i=ssh_list_get_iterator(session->packet_callbacks);
while(i != NULL){
cb=ssh_iterator_value(ssh_packet_callbacks,i);
i=i->next;
if(!cb)
continue;
if(cb->start > type)
continue;
if(cb->start + cb->n_callbacks <= type)
continue;
if(cb->callbacks[type - cb->start]==NULL)
continue;
r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user);
if(r==SSH_PACKET_USED)
break;
}
if(r==SSH_PACKET_NOT_USED){
SSH_LOG(SSH_LOG_RARE,"Couldn't do anything with packet type %d",type);
ssh_packet_send_unimplemented(session, session->recv_seq-1);
}
i = ssh_list_get_iterator(session->packet_callbacks);
while (i != NULL) {
cb = ssh_iterator_value(ssh_packet_callbacks, i);
i = i->next;
if (!cb) {
continue;
}
if (cb->start > type) {
continue;
}
if (cb->start + cb->n_callbacks <= type) {
continue;
}
if (cb->callbacks[type - cb->start] == NULL) {
continue;
}
rc = cb->callbacks[type - cb->start](session, type, session->in_buffer,
cb->user);
if (rc == SSH_PACKET_USED) {
break;
}
}
if (rc == SSH_PACKET_NOT_USED) {
SSH_LOG(SSH_LOG_RARE, "Couldn't do anything with packet type %d", type);
rc = ssh_packet_send_unimplemented(session, session->recv_seq - 1);
if (rc != SSH_OK) {
SSH_LOG(SSH_LOG_RARE, "Failed to send unimplemented: %s",
ssh_get_error(session));
}
}
}
/** @internal
@@ -1929,6 +1946,8 @@ ssh_packet_set_newkeys(ssh_session session,
session->next_crypto->decryptkey,
session->next_crypto->decryptIV);
if (rc < 0) {
/* On error, make sure it is not used */
session->next_crypto->used = 0;
return SSH_ERROR;
}
@@ -1937,6 +1956,8 @@ ssh_packet_set_newkeys(ssh_session session,
session->next_crypto->encryptkey,
session->next_crypto->encryptIV);
if (rc < 0) {
/* On error, make sure it is not used */
session->next_crypto->used = 0;
return SSH_ERROR;
}

View File

@@ -196,11 +196,11 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len)
hmac_final(ctx, crypto->hmacbuf, &finallen);
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("mac: ",data,hmac_digest_len(type));
ssh_log_hexdump("mac: ", data, len);
if (finallen != hmac_digest_len(type)) {
printf("Final len is %d\n",finallen);
printf("Final len is %d\n", finallen);
}
ssh_print_hexa("Packet hmac", crypto->hmacbuf, hmac_digest_len(type));
ssh_log_hexdump("Packet hmac", crypto->hmacbuf, hmac_digest_len(type));
#endif
}
explicit_bzero(out, len);
@@ -264,9 +264,9 @@ int ssh_packet_hmac_verify(ssh_session session,
hmac_final(ctx, hmacbuf, &hmaclen);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("received mac",mac,hmaclen);
ssh_print_hexa("Computed mac",hmacbuf,hmaclen);
ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(uint32_t));
ssh_log_hexdump("received mac",mac,hmaclen);
ssh_log_hexdump("Computed mac",hmacbuf,hmaclen);
ssh_log_hexdump("seq",(unsigned char *)&seq,sizeof(uint32_t));
#endif
if (secure_memcmp(mac, hmacbuf, hmaclen) == 0) {
return 0;

120
src/pki.c
View File

@@ -64,16 +64,22 @@
#include "libssh/misc.h"
#include "libssh/agent.h"
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey) {
if (strncmp(privkey, DSA_HEADER_BEGIN, strlen(DSA_HEADER_BEGIN)) == 0) {
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey)
{
char *start = NULL;
start = strstr(privkey, DSA_HEADER_BEGIN);
if (start != NULL) {
return SSH_KEYTYPE_DSS;
}
if (strncmp(privkey, RSA_HEADER_BEGIN, strlen(RSA_HEADER_BEGIN)) == 0) {
start = strstr(privkey, RSA_HEADER_BEGIN);
if (start != NULL) {
return SSH_KEYTYPE_RSA;
}
if (strncmp(privkey, ECDSA_HEADER_BEGIN, strlen(ECDSA_HEADER_BEGIN)) == 0) {
start = strstr(privkey, ECDSA_HEADER_BEGIN);
if (start != 0) {
/* We don't know what the curve is at this point, so we don't actually
* know the type. We figure out the actual curve and fix things up in
* pki_private_key_from_base64 */
@@ -156,7 +162,14 @@ void ssh_key_clean (ssh_key key){
}
#endif
if (key->ed25519_privkey != NULL){
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL implementation the private key is only the private
* original seed. In the internal implementation the private key is the
* concatenation of the original private seed with the public key.*/
explicit_bzero(key->ed25519_privkey, ED25519_KEY_LEN);
#else
explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey));
#endif
SAFE_FREE(key->ed25519_privkey);
}
SAFE_FREE(key->ed25519_pubkey);
@@ -292,7 +305,7 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
return NULL;
}
static enum ssh_digest_e ssh_key_hash_from_name(const char *name)
enum ssh_digest_e ssh_key_hash_from_name(const char *name)
{
if (name == NULL) {
/* TODO we should rather fail */
@@ -382,6 +395,19 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
case SSH_KEYTYPE_DSS:
return SSH_DIGEST_SHA1;
case SSH_KEYTYPE_RSA_CERT01:
/* If we are talking to an old OpenSSH version which does not support
* SHA2 in certificates */
if ((session->openssh > 0) &&
(session->openssh < SSH_VERSION_INT(7, 2, 0)))
{
SSH_LOG(SSH_LOG_DEBUG,
"We are talking to an old OpenSSH (%x); "
"returning SSH_DIGEST_SHA1",
session->openssh);
return SSH_DIGEST_SHA1;
}
FALL_THROUGH;
case SSH_KEYTYPE_RSA:
if (ssh_key_algorithm_allowed(session, "rsa-sha2-512") &&
(session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
@@ -435,6 +461,21 @@ ssh_key_get_signature_algorithm(ssh_session session,
{
enum ssh_digest_e hash_type;
if (type == SSH_KEYTYPE_RSA_CERT01) {
/* If we are talking to an old OpenSSH version which does not support
* rsa-sha2-{256,512}-cert-v01@openssh.com */
if ((session->openssh > 0) &&
(session->openssh < SSH_VERSION_INT(7, 8, 0)))
{
SSH_LOG(SSH_LOG_DEBUG,
"We are talking to an old OpenSSH (%x); "
"using old cert format",
session->openssh);
return "ssh-rsa-cert-v01@openssh.com";
}
}
hash_type = ssh_key_type_to_hash(session, type);
return ssh_key_signature_to_char(type, hash_type);
@@ -645,7 +686,10 @@ void ssh_signature_free(ssh_signature sig)
#endif
break;
case SSH_KEYTYPE_ED25519:
#ifndef HAVE_OPENSSL_ED25519
/* When using OpenSSL, the signature is stored in sig->raw_sig */
SAFE_FREE(sig->ed25519_sig);
#endif
break;
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
@@ -690,7 +734,7 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
ssh_key *pkey)
{
ssh_key key;
int cmp;
char *openssh_header = NULL;
if (b64_key == NULL || pkey == NULL) {
return SSH_ERROR;
@@ -705,9 +749,9 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
passphrase ? "true" : "false");
/* Test for OpenSSH key format first */
cmp = strncmp(b64_key, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
if (cmp == 0) {
key = ssh_pki_openssh_privkey_import(b64_key,
openssh_header = strstr(b64_key, OPENSSH_HEADER_BEGIN);
if (openssh_header != NULL) {
key = ssh_pki_openssh_privkey_import(openssh_header,
passphrase,
auth_fn,
auth_data);
@@ -1030,12 +1074,12 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
rc = pki_privkey_build_dss(key, p, q, g, pubkey, privkey);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g));
ssh_print_hexa("pubkey", ssh_string_data(pubkey),
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
ssh_log_hexdump("g", ssh_string_data(g), ssh_string_len(g));
ssh_log_hexdump("pubkey", ssh_string_data(pubkey),
ssh_string_len(pubkey));
ssh_print_hexa("privkey", ssh_string_data(privkey),
ssh_log_hexdump("privkey", ssh_string_data(privkey),
ssh_string_len(privkey));
#endif
ssh_string_burn(p);
@@ -1071,13 +1115,13 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n));
ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e));
ssh_print_hexa("d", ssh_string_data(d), ssh_string_len(d));
ssh_print_hexa("iqmp", ssh_string_data(iqmp),
ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
ssh_log_hexdump("d", ssh_string_data(d), ssh_string_len(d));
ssh_log_hexdump("iqmp", ssh_string_data(iqmp),
ssh_string_len(iqmp));
ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
#endif
ssh_string_burn(n);
ssh_string_free(n);
@@ -1203,9 +1247,9 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
rc = pki_pubkey_build_dss(key, p, q, g, pubkey);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g));
ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
ssh_log_hexdump("g", ssh_string_data(g), ssh_string_len(g));
#endif
ssh_string_burn(p);
ssh_string_free(p);
@@ -1234,8 +1278,8 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
rc = pki_pubkey_build_rsa(key, e, n);
#ifdef DEBUG_CRYPTO
ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e));
ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n));
ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
#endif
ssh_string_burn(e);
ssh_string_free(e);
@@ -1287,21 +1331,21 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
case SSH_KEYTYPE_ED25519:
{
ssh_string pubkey = ssh_buffer_get_ssh_string(buffer);
if (ssh_string_len(pubkey) != ED25519_PK_LEN) {
if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
SSH_LOG(SSH_LOG_WARN, "Invalid public key length");
ssh_string_burn(pubkey);
ssh_string_free(pubkey);
goto fail;
}
key->ed25519_pubkey = malloc(ED25519_PK_LEN);
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) {
ssh_string_burn(pubkey);
ssh_string_free(pubkey);
goto fail;
}
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN);
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
ssh_string_burn(pubkey);
ssh_string_free(pubkey);
}
@@ -2195,7 +2239,7 @@ int pki_key_check_hash_compatible(ssh_key key,
int ssh_pki_signature_verify(ssh_session session,
ssh_signature sig,
const ssh_key key,
unsigned char *input,
const unsigned char *input,
size_t input_len)
{
int rc;
@@ -2225,7 +2269,7 @@ int ssh_pki_signature_verify(ssh_session session,
return SSH_ERROR;
}
rc = pki_signature_verify(session, sig, key, input, input_len);
rc = pki_verify_data_signature(sig, key, input, input_len);
return rc;
}
@@ -2249,12 +2293,6 @@ ssh_signature pki_do_sign(const ssh_key privkey,
return NULL;
}
if (privkey->type == SSH_KEYTYPE_ED25519 ||
privkey->type == SSH_KEYTYPE_ED25519_CERT01)
{
return pki_do_sign_hash(privkey, input, input_len, SSH_DIGEST_AUTO);
}
return pki_sign_data(privkey, hash_type, input, input_len);
}
@@ -2385,7 +2423,8 @@ ssh_string ssh_pki_do_sign_agent(ssh_session session,
#ifdef WITH_SERVER
ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
const ssh_key privkey)
const ssh_key privkey,
const enum ssh_digest_e digest)
{
struct ssh_crypto_struct *crypto = NULL;
@@ -2394,8 +2433,6 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
ssh_buffer sign_input = NULL;
enum ssh_digest_e hash_type;
int rc;
if (session == NULL || privkey == NULL || !ssh_key_is_private(privkey)) {
@@ -2410,9 +2447,6 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
return NULL;
}
/* Get the hash type from the key type */
hash_type = ssh_key_type_to_hash(session, privkey->type);
/* Fill the input */
sign_input = ssh_buffer_new();
if (sign_input == NULL) {
@@ -2432,7 +2466,7 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
sig = pki_do_sign(privkey,
ssh_buffer_get(sign_input),
ssh_buffer_get_len(sign_input),
hash_type);
digest);
if (sig == NULL) {
goto end;
}

View File

@@ -233,7 +233,7 @@ ssh_pki_openssh_import(const char *text_key,
void *auth_data,
bool private)
{
const char *ptr=text_key;
const char *ptr = text_key;
const char *end;
char *base64;
int cmp;
@@ -250,7 +250,7 @@ ssh_pki_openssh_import(const char *text_key,
uint8_t padding;
cmp = strncmp(ptr, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
if (cmp != 0){
if (cmp != 0) {
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no header)");
goto out;
}
@@ -259,15 +259,15 @@ ssh_pki_openssh_import(const char *text_key,
ptr++;
}
end = strstr(ptr, OPENSSH_HEADER_END);
if (end == NULL){
if (end == NULL) {
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no footer)");
goto out;
}
base64 = malloc(end - ptr + 1);
if (base64 == NULL){
if (base64 == NULL) {
goto out;
}
for (i = 0; ptr < end; ptr++){
for (i = 0; ptr < end; ptr++) {
if (!isspace((int)ptr[0])) {
base64[i] = ptr[0];
i++;
@@ -276,7 +276,7 @@ ssh_pki_openssh_import(const char *text_key,
base64[i] = '\0';
buffer = base64_to_bin(base64);
SAFE_FREE(base64);
if (buffer == NULL){
if (buffer == NULL) {
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (base64 error)");
goto out;
}
@@ -289,21 +289,21 @@ ssh_pki_openssh_import(const char *text_key,
&nkeys,
&pubkey0,
&privkeys);
if (rc == SSH_ERROR){
if (rc == SSH_ERROR) {
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (unpack error)");
goto out;
}
cmp = strncmp(magic, OPENSSH_AUTH_MAGIC, strlen(OPENSSH_AUTH_MAGIC));
if (cmp != 0){
if (cmp != 0) {
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (bad magic)");
goto out;
}
SSH_LOG(SSH_LOG_INFO,
"Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d\n",
"Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d",
ciphername,
kdfname,
nkeys);
if (nkeys != 1){
if (nkeys != 1) {
SSH_LOG(SSH_LOG_WARN, "Opening OpenSSH private key: only 1 key supported (%d available)", nkeys);
goto out;
}
@@ -327,7 +327,7 @@ ssh_pki_openssh_import(const char *text_key,
kdfoptions,
auth_fn,
auth_data);
if (rc == SSH_ERROR){
if (rc == SSH_ERROR) {
goto out;
}
@@ -342,20 +342,20 @@ ssh_pki_openssh_import(const char *text_key,
ssh_string_len(privkeys));
rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2);
if (rc == SSH_ERROR || checkint1 != checkint2){
if (rc == SSH_ERROR || checkint1 != checkint2) {
SSH_LOG(SSH_LOG_WARN, "OpenSSH private key unpack error (correct password?)");
goto out;
}
rc = pki_openssh_import_privkey_blob(privkey_buffer, &key);
if (rc == SSH_ERROR){
if (rc == SSH_ERROR) {
goto out;
}
comment = ssh_buffer_get_ssh_string(privkey_buffer);
SAFE_FREE(comment);
/* verify that the remaining data is correct padding */
for (i=1; ssh_buffer_get_len(privkey_buffer) > 0; ++i){
for (i = 1; ssh_buffer_get_len(privkey_buffer) > 0; ++i) {
ssh_buffer_get_u8(privkey_buffer, &padding);
if (padding != i){
if (padding != i) {
ssh_key_free(key);
key = NULL;
SSH_LOG(SSH_LOG_WARN, "Invalid padding");
@@ -415,12 +415,13 @@ static int pki_openssh_export_privkey_blob(const ssh_key privkey,
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"sdPdP",
"sdPdPP",
privkey->type_c,
(uint32_t)ED25519_PK_LEN,
(size_t)ED25519_PK_LEN, privkey->ed25519_pubkey,
(uint32_t)ED25519_SK_LEN,
(size_t)ED25519_SK_LEN, privkey->ed25519_privkey);
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey,
(uint32_t)(2 * ED25519_KEY_LEN),
(size_t)ED25519_KEY_LEN, privkey->ed25519_privkey,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey);
return rc;
}

View File

@@ -529,7 +529,7 @@ int pki_key_generate_rsa(ssh_key key, int parameter){
BN_free(e);
if (rc == -1 || key->rsa == NULL)
if (rc <= 0 || key->rsa == NULL)
return SSH_ERROR;
return SSH_OK;
}
@@ -730,29 +730,58 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
return NULL;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
goto err;
}
switch (key->type) {
case SSH_KEYTYPE_DSS:
pkey = EVP_PKEY_new();
if (pkey == NULL) {
goto err;
}
rc = EVP_PKEY_set1_DSA(pkey, key->dsa);
break;
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1:
pkey = EVP_PKEY_new();
if (pkey == NULL) {
goto err;
}
rc = EVP_PKEY_set1_RSA(pkey, key->rsa);
break;
#ifdef HAVE_ECC
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521:
pkey = EVP_PKEY_new();
if (pkey == NULL) {
goto err;
}
rc = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
break;
#endif
case SSH_KEYTYPE_ED25519:
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL, the input is the private key seed only, which means
* the first half of the SSH private key (the second half is the
* public key) */
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
(const uint8_t *)key->ed25519_privkey,
ED25519_KEY_LEN);
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create ed25519 EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
/* Mark the operation as successful as for the other key types */
rc = 1;
break;
#else
SSH_LOG(SSH_LOG_WARN, "PEM output not supported for key type ssh-ed25519");
goto err;
#endif
case SSH_KEYTYPE_DSS_CERT01:
case SSH_KEYTYPE_RSA_CERT01:
case SSH_KEYTYPE_ECDSA_P256_CERT01:
@@ -821,7 +850,11 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
BIO *mem = NULL;
DSA *dsa = NULL;
RSA *rsa = NULL;
#ifdef HAVE_OPENSSL_ED25519
uint8_t *ed25519 = NULL;
#else
ed25519_privkey *ed25519 = NULL;
#endif
ssh_key key = NULL;
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
#ifdef HAVE_OPENSSL_ECC
@@ -861,7 +894,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
SSH_LOG(SSH_LOG_WARN,
"Parsing private key: %s",
ERR_error_string(ERR_get_error(),NULL));
return NULL;
goto fail;
}
type = SSH_KEYTYPE_DSS;
break;
@@ -871,7 +904,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
SSH_LOG(SSH_LOG_WARN,
"Parsing private key: %s",
ERR_error_string(ERR_get_error(),NULL));
return NULL;
goto fail;
}
type = SSH_KEYTYPE_RSA;
break;
@@ -882,7 +915,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
SSH_LOG(SSH_LOG_WARN,
"Parsing private key: %s",
ERR_error_string(ERR_get_error(), NULL));
return NULL;
goto fail;
}
/* pki_privatekey_type_from_string always returns P256 for ECDSA
@@ -894,6 +927,43 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
}
break;
#endif
#ifdef HAVE_OPENSSL_ED25519
case EVP_PKEY_ED25519:
{
size_t key_len;
int evp_rc = 0;
/* Get the key length */
evp_rc = EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len);
if (evp_rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get ed25519 raw private key length: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
if (key_len != ED25519_KEY_LEN) {
goto fail;
}
ed25519 = malloc(key_len);
if (ed25519 == NULL) {
SSH_LOG(SSH_LOG_WARN, "Out of memory");
goto fail;
}
evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)ed25519,
&key_len);
if (evp_rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get ed25519 raw private key: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
type = SSH_KEYTYPE_ED25519;
}
break;
#endif
default:
EVP_PKEY_free(pkey);
@@ -923,13 +993,16 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
return key;
fail:
EVP_PKEY_free(pkey);
ssh_key_free(key);
DSA_free(dsa);
RSA_free(rsa);
#ifdef HAVE_OPENSSL_ECC
EC_KEY_free(ecdsa);
#endif
#ifdef HAVE_OPENSSL_ED25519
SAFE_FREE(ed25519);
#endif
return NULL;
}
@@ -1473,7 +1546,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
sig_blob = ssh_string_copy(sig->raw_sig);
break;
case SSH_KEYTYPE_ED25519:
sig_blob = pki_ed25519_sig_to_blob(sig);
sig_blob = pki_ed25519_signature_to_blob(sig);
break;
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
@@ -1519,7 +1592,7 @@ static int pki_signature_from_rsa_blob(const ssh_key pubkey,
#ifdef DEBUG_CRYPTO
SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len);
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len);
#endif
if (len == rsalen) {
@@ -1583,8 +1656,8 @@ static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey),
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("r", ssh_string_data(sig_blob), 20);
ssh_print_hexa("s", (unsigned char *)ssh_string_data(sig_blob) + 20, 20);
ssh_log_hexdump("r", ssh_string_data(sig_blob), 20);
ssh_log_hexdump("s", (unsigned char *)ssh_string_data(sig_blob) + 20, 20);
#endif
r = ssh_string_new(20);
@@ -1695,7 +1768,7 @@ static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey),
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
ssh_log_hexdump("r", ssh_string_data(r), ssh_string_len(r));
#endif
pr = ssh_make_string_bn(r);
@@ -1723,7 +1796,7 @@ static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey),
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
ssh_log_hexdump("s", ssh_string_data(s), ssh_string_len(s));
#endif
ps = ssh_make_string_bn(s);
@@ -1821,7 +1894,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
break;
case SSH_KEYTYPE_ED25519:
rc = pki_ed25519_sig_from_blob(sig, sig_blob);
rc = pki_signature_from_ed25519_blob(sig, sig_blob);
if (rc != SSH_OK){
goto error;
}
@@ -1852,54 +1925,6 @@ error:
return NULL;
}
int pki_signature_verify(ssh_session session,
const ssh_signature sig,
const ssh_key key,
const unsigned char *input,
size_t input_len)
{
int rc;
if (session == NULL || sig == NULL || key == NULL || input == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
"pki_signature_verify()");
return SSH_ERROR;
}
if (ssh_key_type_plain(key->type) != sig->type) {
SSH_LOG(SSH_LOG_WARN,
"Can not verify %s signature with %s key",
sig->type_c,
key->type_c);
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(key, sig->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
/* For ed25519 keys, verify using the input directly */
if (key->type == SSH_KEYTYPE_ED25519 ||
key->type == SSH_KEYTYPE_ED25519_CERT01)
{
rc = pki_ed25519_verify(key, sig, input, input_len);
} else {
/* For the other key types, calculate the hash and verify the signature */
rc = pki_verify_data_signature(sig, key, input, input_len);
}
if (rc != SSH_OK){
ssh_set_error(session,
SSH_FATAL,
"Signature verification error");
return SSH_ERROR;
}
return SSH_OK;
}
static const EVP_MD *pki_digest_to_md(enum ssh_digest_e hash_type)
{
const EVP_MD *md = NULL;
@@ -1918,6 +1943,8 @@ static const EVP_MD *pki_digest_to_md(enum ssh_digest_e hash_type)
md = EVP_sha1();
break;
case SSH_DIGEST_AUTO:
md = NULL;
break;
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
hash_type);
@@ -1931,12 +1958,6 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
{
EVP_PKEY *pkey = NULL;
pkey = EVP_PKEY_new();
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
return NULL;
}
switch(key->type) {
case SSH_KEYTYPE_DSS:
case SSH_KEYTYPE_DSS_CERT01:
@@ -1944,6 +1965,12 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
SSH_LOG(SSH_LOG_TRACE, "NULL key->dsa");
goto error;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
return NULL;
}
EVP_PKEY_set1_DSA(pkey, key->dsa);
break;
case SSH_KEYTYPE_RSA:
@@ -1953,6 +1980,12 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
SSH_LOG(SSH_LOG_TRACE, "NULL key->rsa");
goto error;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
return NULL;
}
EVP_PKEY_set1_RSA(pkey, key->rsa);
break;
case SSH_KEYTYPE_ECDSA_P256:
@@ -1966,12 +1999,46 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key)
SSH_LOG(SSH_LOG_TRACE, "NULL key->ecdsa");
goto error;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
return NULL;
}
EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
break;
# endif
case SSH_KEYTYPE_ED25519:
/* Not supported yet. This type requires the use of EVP_DigestSign*()
* API and ECX keys. There is no EVP_set1_ECX_KEY() or equivalent yet. */
case SSH_KEYTYPE_ED25519_CERT01:
# if defined(HAVE_OPENSSL_ED25519)
if (ssh_key_is_private(key)) {
if (key->ed25519_privkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_privkey");
goto error;
}
/* In OpenSSL, the input is the private key seed only, which means
* the first half of the SSH private key (the second half is the
* public key). Both keys have the same length (32 bytes) */
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
(const uint8_t *)key->ed25519_privkey,
ED25519_KEY_LEN);
} else {
if (key->ed25519_pubkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_pubkey");
goto error;
}
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
(const uint8_t *)key->ed25519_pubkey,
ED25519_KEY_LEN);
}
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create ed25519 EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
break;
#endif
case SSH_KEYTYPE_UNKNOWN:
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown private key algorithm for type: %d",
@@ -2009,7 +2076,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
EVP_PKEY *pkey = NULL;
unsigned char *raw_sig_data = NULL;
unsigned int raw_sig_len;
size_t raw_sig_len;
ssh_signature sig = NULL;
@@ -2027,10 +2094,20 @@ ssh_signature pki_sign_data(const ssh_key privkey,
return NULL;
}
#ifndef HAVE_OPENSSL_ED25519
if (privkey->type == SSH_KEYTYPE_ED25519 ||
privkey->type == SSH_KEYTYPE_ED25519_CERT01)
{
return pki_do_sign_hash(privkey, input, input_len, hash_type);
}
#endif
/* Set hash algorithm to be used */
md = pki_digest_to_md(hash_type);
if (md == NULL) {
return NULL;
if (hash_type != SSH_DIGEST_AUTO) {
return NULL;
}
}
/* Setup private key EVP_PKEY */
@@ -2055,26 +2132,42 @@ ssh_signature pki_sign_data(const ssh_key privkey,
}
/* Sign the data */
rc = EVP_SignInit_ex(ctx, md, NULL);
if (!rc){
SSH_LOG(SSH_LOG_TRACE, "EVP_SignInit() failed");
rc = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey);
if (rc != 1){
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestSignInit() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_SignUpdate(ctx, input, input_len);
if (!rc) {
SSH_LOG(SSH_LOG_TRACE, "EVP_SignUpdate() failed");
#ifdef HAVE_OPENSSL_EVP_DIGESTSIGN
rc = EVP_DigestSign(ctx, raw_sig_data, &raw_sig_len, input, input_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestSign() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
#else
rc = EVP_DigestSignUpdate(ctx, input, input_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestSignUpdate() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_SignFinal(ctx, raw_sig_data, &raw_sig_len, pkey);
if (!rc) {
SSH_LOG(SSH_LOG_TRACE, "EVP_SignFinal() failed");
rc = EVP_DigestSignFinal(ctx, raw_sig_data, &raw_sig_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestSignFinal() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
#endif
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Generated signature", raw_sig_data, raw_sig_len);
ssh_log_hexdump("Generated signature", raw_sig_data, raw_sig_len);
#endif
/* Allocate and fill output signature */
@@ -2144,7 +2237,11 @@ int pki_verify_data_signature(ssh_signature signature,
int evp_rc;
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
signature == NULL || signature->raw_sig == NULL)
signature == NULL || (signature->raw_sig == NULL
#ifndef HAVE_OPENSSL_ED25519
&& signature->ed25519_sig == NULL
#endif
))
{
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
"pki_verify_data_signature()");
@@ -2157,6 +2254,14 @@ int pki_verify_data_signature(ssh_signature signature,
return SSH_ERROR;
}
#ifndef HAVE_OPENSSL_ED25519
if (pubkey->type == SSH_KEYTYPE_ED25519 ||
pubkey->type == SSH_KEYTYPE_ED25519_CERT01)
{
return pki_ed25519_verify(pubkey, signature, input, input_len);
}
#endif
/* Get the signature to be verified */
raw_sig_data = ssh_string_data(signature->raw_sig);
raw_sig_len = ssh_string_len(signature->raw_sig);
@@ -2167,7 +2272,9 @@ int pki_verify_data_signature(ssh_signature signature,
/* Set hash algorithm to be used */
md = pki_digest_to_md(signature->hash_type);
if (md == NULL) {
return SSH_ERROR;
if (signature->hash_type != SSH_DIGEST_AUTO) {
return SSH_ERROR;
}
}
/* Setup public key EVP_PKEY */
@@ -2179,33 +2286,42 @@ int pki_verify_data_signature(ssh_signature signature,
/* Create the context */
ctx = EVP_MD_CTX_create();
if (ctx == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Out of memory");
SSH_LOG(SSH_LOG_TRACE,
"Failed to create EVP_MD_CTX: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
/* Verify the signature */
evp_rc = EVP_VerifyInit_ex(ctx, md, NULL);
if (!evp_rc){
SSH_LOG(SSH_LOG_TRACE, "EVP_SignInit() failed");
evp_rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
if (evp_rc != 1){
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestVerifyInit() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
evp_rc = EVP_VerifyUpdate(ctx, input, input_len);
if (!evp_rc) {
SSH_LOG(SSH_LOG_TRACE, "EVP_SignUpdate() failed");
#ifdef HAVE_OPENSSL_EVP_DIGESTVERIFY
evp_rc = EVP_DigestVerify(ctx, raw_sig_data, raw_sig_len, input, input_len);
#else
evp_rc = EVP_DigestVerifyUpdate(ctx, input, input_len);
if (evp_rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestVerifyUpdate() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
evp_rc = EVP_VerifyFinal(ctx, raw_sig_data, raw_sig_len, pkey);
if (evp_rc < 0) {
SSH_LOG(SSH_LOG_TRACE, "EVP_SignFinal() failed");
rc = SSH_ERROR;
} else if (evp_rc == 0) {
SSH_LOG(SSH_LOG_TRACE, "Signature invalid");
rc = SSH_ERROR;
} else if (evp_rc == 1) {
evp_rc = EVP_DigestVerifyFinal(ctx, raw_sig_data, raw_sig_len);
#endif
if (evp_rc == 1) {
SSH_LOG(SSH_LOG_TRACE, "Signature valid");
rc = SSH_OK;
} else {
SSH_LOG(SSH_LOG_TRACE,
"Signature invalid: %s",
ERR_error_string(ERR_get_error(), NULL));
rc = SSH_ERROR;
}
out:
@@ -2218,6 +2334,92 @@ out:
return rc;
}
#ifdef HAVE_OPENSSL_ED25519
int pki_key_generate_ed25519(ssh_key key)
{
int evp_rc;
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
size_t privkey_len = ED25519_KEY_LEN;
size_t pubkey_len = ED25519_KEY_LEN;
if (key == NULL) {
return SSH_ERROR;
}
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL);
if (pctx == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create ed25519 EVP_PKEY_CTX: %s",
ERR_error_string(ERR_get_error(), NULL));
goto error;
}
evp_rc = EVP_PKEY_keygen_init(pctx);
if (evp_rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize ed25519 key generation: %s",
ERR_error_string(ERR_get_error(), NULL));
goto error;
}
evp_rc = EVP_PKEY_keygen(pctx, &pkey);
if (evp_rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate ed25519 key: %s",
ERR_error_string(ERR_get_error(), NULL));
goto error;
}
key->ed25519_privkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_privkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to allocate memory for ed25519 private key");
goto error;
}
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to allocate memory for ed25519 public key");
goto error;
}
evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)key->ed25519_privkey,
&privkey_len);
if (evp_rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get ed25519 raw private key: %s",
ERR_error_string(ERR_get_error(), NULL));
goto error;
}
evp_rc = EVP_PKEY_get_raw_public_key(pkey, (uint8_t *)key->ed25519_pubkey,
&pubkey_len);
if (evp_rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get ed25519 raw public key: %s",
ERR_error_string(ERR_get_error(), NULL));
goto error;
}
EVP_PKEY_CTX_free(pctx);
EVP_PKEY_free(pkey);
return SSH_OK;
error:
if (pctx != NULL) {
EVP_PKEY_CTX_free(pctx);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
SAFE_FREE(key->ed25519_privkey);
SAFE_FREE(key->ed25519_pubkey);
return SSH_ERROR;
}
#else
ssh_signature pki_do_sign_hash(const ssh_key privkey,
const unsigned char *hash,
size_t hlen,
@@ -2250,4 +2452,6 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey,
return sig;
}
#endif /* HAVE_OPENSSL_ED25519 */
#endif /* _PKI_CRYPTO_H */

View File

@@ -56,28 +56,6 @@ error:
return SSH_ERROR;
}
int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey,
ssh_string privkey)
{
if (ssh_string_len(pubkey) != ED25519_PK_LEN ||
ssh_string_len(privkey) != ED25519_SK_LEN) {
SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
return SSH_ERROR;
}
key->ed25519_privkey = malloc(ED25519_SK_LEN);
key->ed25519_pubkey = malloc(ED25519_PK_LEN);
if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
ED25519_SK_LEN);
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
ED25519_PK_LEN);
return SSH_OK;
}
int pki_ed25519_sign(const ssh_key privkey,
ssh_signature sig,
const unsigned char *hash,
@@ -170,165 +148,3 @@ error:
return SSH_ERROR;
}
/**
* @internal
*
* @brief Compare ed25519 keys if they are equal.
*
* @param[in] k1 The first key to compare.
*
* @param[in] k2 The second key to compare.
*
* @param[in] what What part or type of the key do you want to compare.
*
* @return 0 if equal, 1 if not.
*/
int pki_ed25519_key_cmp(const ssh_key k1,
const ssh_key k2,
enum ssh_keycmp_e what)
{
int cmp;
switch(what) {
case SSH_KEY_CMP_PRIVATE:
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
return 1;
}
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_SK_LEN);
if (cmp != 0) {
return 1;
}
/* FALL THROUGH */
case SSH_KEY_CMP_PUBLIC:
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
return 1;
}
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_PK_LEN);
if (cmp != 0) {
return 1;
}
}
return 0;
}
/**
* @internal
*
* @brief duplicate an ed25519 key
*
* @param[out\ new preinitialized output ssh_ke
*
* @param[in] key key to copy
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
{
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
if (key->ed25519_privkey != NULL) {
new->ed25519_privkey = malloc(ED25519_SK_LEN);
if (new->ed25519_privkey == NULL) {
return SSH_ERROR;
}
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
}
if (key->ed25519_pubkey != NULL) {
new->ed25519_pubkey = malloc(ED25519_PK_LEN);
if (new->ed25519_pubkey == NULL) {
SAFE_FREE(new->ed25519_privkey);
return SSH_ERROR;
}
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_LEN);
}
return SSH_OK;
}
/**
* @internal
*
* @brief outputs an ed25519 public key in a blob buffer.
*
* @param[out] buffer output buffer
*
* @param[in] key key to output
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
{
int rc;
if (key->ed25519_pubkey == NULL){
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dP",
(uint32_t)ED25519_PK_LEN,
(size_t)ED25519_PK_LEN, key->ed25519_pubkey);
return rc;
}
/**
* @internal
*
* @brief output a signature blob from an ed25519 signature
*
* @param[in] sig signature to convert
*
* @return Signature blob in SSH string, or NULL on error
*/
ssh_string pki_ed25519_sig_to_blob(ssh_signature sig)
{
ssh_string sig_blob;
if (sig->ed25519_sig == NULL) {
return NULL;
}
sig_blob = ssh_string_new(ED25519_SIG_LEN);
if (sig_blob == NULL) {
return NULL;
}
ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
return sig_blob;
}
/**
* @internal
*
* @brief Convert a signature blob in an ed25519 signature.
*
* @param[out] sig a preinitialized signature
*
* @param[in] sig_blob a signature blob
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob)
{
size_t len;
len = ssh_string_len(sig_blob);
if (len != ED25519_SIG_LEN){
SSH_LOG(SSH_LOG_WARN, "Invalid ssh-ed25519 signature len: %zu", len);
return SSH_ERROR;
}
sig->ed25519_sig = malloc(ED25519_SIG_LEN);
if (sig->ed25519_sig == NULL){
return SSH_ERROR;
}
memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN);
return SSH_OK;
}

280
src/pki_ed25519_common.c Normal file
View File

@@ -0,0 +1,280 @@
/*
* pki_ed25519_common.c - Common ed25519 functions
*
* This file is part of the SSH Library
*
* Copyright (c) 2014 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
* 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.
*/
#include "config.h"
#include "libssh/pki.h"
#include "libssh/pki_priv.h"
#include "libssh/buffer.h"
int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey,
ssh_string privkey)
{
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
{
SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
return SSH_ERROR;
}
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL implementation, the private key is the original private seed,
* without the public key. */
key->ed25519_privkey = malloc(ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation of
* the private seed with the public key. */
key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
#endif
if (key->ed25519_privkey == NULL) {
goto error;
}
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) {
goto error;
}
#ifdef HAVE_OPENSSL_ED25519
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
ED25519_KEY_LEN);
#else
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
2 * ED25519_KEY_LEN);
#endif
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
ED25519_KEY_LEN);
return SSH_OK;
error:
SAFE_FREE(key->ed25519_privkey);
SAFE_FREE(key->ed25519_pubkey);
return SSH_ERROR;
}
/**
* @internal
*
* @brief Compare ed25519 keys if they are equal.
*
* @param[in] k1 The first key to compare.
*
* @param[in] k2 The second key to compare.
*
* @param[in] what What part or type of the key do you want to compare.
*
* @return 0 if equal, 1 if not.
*/
int pki_ed25519_key_cmp(const ssh_key k1,
const ssh_key k2,
enum ssh_keycmp_e what)
{
int cmp;
switch(what) {
case SSH_KEY_CMP_PRIVATE:
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
return 1;
}
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL implementation, the private key is the original private
* seed, without the public key. */
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey,
2 * ED25519_KEY_LEN);
#endif
if (cmp != 0) {
return 1;
}
/* FALL THROUGH */
case SSH_KEY_CMP_PUBLIC:
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
return 1;
}
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
if (cmp != 0) {
return 1;
}
}
return 0;
}
/**
* @internal
*
* @brief Duplicate an Ed25519 key
*
* @param[out] new Pre-initialized ssh_key structure
*
* @param[in] key Key to copy
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
{
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
if (key->ed25519_privkey != NULL) {
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL implementation, the private key is the original private
* seed, without the public key. */
new->ed25519_privkey = malloc(ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
new->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
#endif
if (new->ed25519_privkey == NULL) {
return SSH_ERROR;
}
#ifdef HAVE_OPENSSL_ED25519
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN);
#else
memcpy(new->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN);
#endif
}
if (key->ed25519_pubkey != NULL) {
new->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (new->ed25519_pubkey == NULL) {
SAFE_FREE(new->ed25519_privkey);
return SSH_ERROR;
}
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
}
return SSH_OK;
}
/**
* @internal
*
* @brief Outputs an Ed25519 public key in a blob buffer.
*
* @param[out] buffer Output buffer
*
* @param[in] key Key to output
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
{
int rc;
if (key->ed25519_pubkey == NULL){
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dP",
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
return rc;
}
/**
* @internal
*
* @brief output a signature blob from an ed25519 signature
*
* @param[in] sig signature to convert
*
* @return Signature blob in SSH string, or NULL on error
*/
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig)
{
ssh_string sig_blob;
#ifdef HAVE_OPENSSL_ED25519
/* When using the OpenSSL implementation, the signature is stored in raw_sig
* which is shared by all algorithms.*/
if (sig->raw_sig == NULL) {
return NULL;
}
#else
/* When using the internal implementation, the signature is stored in an
* algorithm specific field. */
if (sig->ed25519_sig == NULL) {
return NULL;
}
#endif
sig_blob = ssh_string_new(ED25519_SIG_LEN);
if (sig_blob == NULL) {
return NULL;
}
#ifdef HAVE_OPENSSL_ED25519
ssh_string_fill(sig_blob, ssh_string_data(sig->raw_sig),
ssh_string_len(sig->raw_sig));
#else
ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
#endif
return sig_blob;
}
/**
* @internal
*
* @brief Convert a signature blob in an ed25519 signature.
*
* @param[out] sig a preinitialized signature
*
* @param[in] sig_blob a signature blob
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob)
{
size_t len;
len = ssh_string_len(sig_blob);
if (len != ED25519_SIG_LEN){
SSH_LOG(SSH_LOG_WARN, "Invalid ssh-ed25519 signature len: %zu", len);
return SSH_ERROR;
}
#ifdef HAVE_OPENSSL_ED25519
sig->raw_sig = ssh_string_copy(sig_blob);
#else
sig->ed25519_sig = malloc(ED25519_SIG_LEN);
if (sig->ed25519_sig == NULL){
return SSH_ERROR;
}
memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN);
#endif
return SSH_OK;
}

View File

@@ -1832,7 +1832,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
gcry_sexp_release(sexp);
break;
case SSH_KEYTYPE_ED25519:
sig_blob = pki_ed25519_sig_to_blob(sig);
sig_blob = pki_ed25519_signature_to_blob(sig);
break;
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
@@ -1945,7 +1945,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
SSH_LOG(SSH_LOG_DEBUG,
"DSA signature len: %lu",
(unsigned long)len);
ssh_print_hexa("DSA signature", ssh_string_data(sig_blob), len);
ssh_log_hexdump("DSA signature", ssh_string_data(sig_blob), len);
#endif
err = gcry_sexp_build(&sig->dsa_sig,
@@ -1980,7 +1980,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
#ifdef DEBUG_CRYPTO
SSH_LOG(SSH_LOG_DEBUG, "RSA signature len: %lu", (unsigned long)len);
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len);
#endif
err = gcry_sexp_build(&sig->rsa_sig,
@@ -1994,7 +1994,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
break;
case SSH_KEYTYPE_ED25519:
rc = pki_ed25519_sig_from_blob(sig, sig_blob);
rc = pki_signature_from_ed25519_blob(sig, sig_blob);
if (rc != SSH_OK){
ssh_signature_free(sig);
return NULL;
@@ -2055,8 +2055,8 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
ssh_log_hexdump("r", ssh_string_data(r), ssh_string_len(r));
ssh_log_hexdump("s", ssh_string_data(s), ssh_string_len(s));
#endif
err = gcry_sexp_build(&sig->ecdsa_sig,
@@ -2087,54 +2087,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
return sig;
}
int pki_signature_verify(ssh_session session,
const ssh_signature sig,
const ssh_key key,
const unsigned char *input,
size_t input_len)
{
int rc;
if (session == NULL || sig == NULL || key == NULL || input == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
"pki_signature_verify()");
return SSH_ERROR;
}
if (ssh_key_type_plain(key->type) != sig->type) {
SSH_LOG(SSH_LOG_WARN,
"Can not verify %s signature with %s key",
sig->type_c,
key->type_c);
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(key, sig->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
/* For ed25519 keys, verify using the input directly */
if (key->type == SSH_KEYTYPE_ED25519 ||
key->type == SSH_KEYTYPE_ED25519_CERT01)
{
rc = pki_ed25519_verify(key, sig, input, input_len);
} else {
/* For the other key types, calculate the hash and verify the signature */
rc = pki_verify_data_signature(sig, key, input, input_len);
}
if (rc != SSH_OK){
ssh_set_error(session,
SSH_FATAL,
"Signature verification error");
return SSH_ERROR;
}
return SSH_OK;
}
ssh_signature pki_do_sign_hash(const ssh_key privkey,
const unsigned char *hash,
size_t hlen,
@@ -2268,6 +2220,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
size_t input_len)
{
unsigned char hash[SHA512_DIGEST_LEN] = {0};
const unsigned char *sign_input = NULL;
uint32_t hlen = 0;
int rc;
@@ -2287,27 +2240,38 @@ ssh_signature pki_sign_data(const ssh_key privkey,
case SSH_DIGEST_SHA256:
sha256(input, input_len, hash);
hlen = SHA256_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_SHA384:
sha384(input, input_len, hash);
hlen = SHA384_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_SHA512:
sha512(input, input_len, hash);
hlen = SHA512_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_AUTO:
if (privkey->type == SSH_KEYTYPE_ED25519) {
/* SSH_DIGEST_AUTO should only be used with ed25519 */
sign_input = input;
hlen = input_len;
break;
}
FALL_THROUGH;
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
hash_type);
return NULL;
}
return pki_do_sign_hash(privkey, hash, hlen, hash_type);
return pki_do_sign_hash(privkey, sign_input, hlen, hash_type);
}
/**
@@ -2336,6 +2300,8 @@ int pki_verify_data_signature(ssh_signature signature,
unsigned char *hash = ghash + 1;
uint32_t hlen = 0;
const unsigned char *verify_input = NULL;
int rc;
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
@@ -2357,23 +2323,35 @@ int pki_verify_data_signature(ssh_signature signature,
sha256(input, input_len, hash);
hlen = SHA256_DIGEST_LEN;
hash_type = "sha256";
verify_input = hash;
break;
case SSH_DIGEST_SHA384:
sha384(input, input_len, hash);
hlen = SHA384_DIGEST_LEN;
hash_type = "sha384";
verify_input = hash;
break;
case SSH_DIGEST_SHA512:
sha512(input, input_len, hash);
hlen = SHA512_DIGEST_LEN;
hash_type = "sha512";
verify_input = hash;
break;
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
hash_type = "sha1";
verify_input = hash;
break;
case SSH_DIGEST_AUTO:
if (pubkey->type == SSH_KEYTYPE_ED25519 ||
pubkey->type == SSH_KEYTYPE_ED25519_CERT01)
{
verify_input = input;
hlen = input_len;
break;
}
FALL_THROUGH;
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d", signature->hash_type);
return SSH_ERROR;
@@ -2461,6 +2439,14 @@ int pki_verify_data_signature(ssh_signature signature,
}
break;
#endif
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_ED25519_CERT01:
rc = pki_ed25519_verify(pubkey, signature, verify_input, hlen);
if (rc != SSH_OK) {
SSH_LOG(SSH_LOG_TRACE, "ED25519 error: Signature invalid");
return SSH_ERROR;
}
break;
case SSH_KEYTYPE_RSA1:
case SSH_KEYTYPE_UNKNOWN:
default:

View File

@@ -32,6 +32,7 @@
#include "libssh/pki_priv.h"
#include "libssh/buffer.h"
#include "libssh/bignum.h"
#include "libssh/misc.h"
#define MAX_PASSPHRASE_SIZE 1024
#define MAX_KEY_SIZE 32
@@ -836,7 +837,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
break;
}
case SSH_KEYTYPE_ED25519:
sig_blob = pki_ed25519_sig_to_blob(sig);
sig_blob = pki_ed25519_signature_to_blob(sig);
break;
default:
SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %s",
@@ -873,7 +874,7 @@ static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey, const
}
#ifdef DEBUG_CRYPTO
SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len);
ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len);
ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len);
#endif
if (len == rsalen) {
@@ -966,7 +967,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
return NULL;
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("r", ssh_string_data(r), ssh_string_len(r));
ssh_log_hexdump("r", ssh_string_data(r), ssh_string_len(r));
#endif
sig->ecdsa_sig.r = ssh_make_string_bn(r);
ssh_string_burn(r);
@@ -986,7 +987,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
}
#ifdef DEBUG_CRYPTO
ssh_print_hexa("s", ssh_string_data(s), ssh_string_len(s));
ssh_log_hexdump("s", ssh_string_data(s), ssh_string_len(s));
#endif
sig->ecdsa_sig.s = ssh_make_string_bn(s);
ssh_string_burn(s);
@@ -1007,7 +1008,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
break;
}
case SSH_KEYTYPE_ED25519:
rc = pki_ed25519_sig_from_blob(sig, sig_blob);
rc = pki_signature_from_ed25519_blob(sig, sig_blob);
if (rc == SSH_ERROR) {
ssh_signature_free(sig);
return NULL;
@@ -1021,51 +1022,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
return sig;
}
int pki_signature_verify(ssh_session session, const ssh_signature sig, const
ssh_key key, const unsigned char *input, size_t input_len)
{
int rc;
if (session == NULL || sig == NULL || key == NULL || input == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
"pki_signature_verify()");
return SSH_ERROR;
}
if (ssh_key_type_plain(key->type) != sig->type) {
SSH_LOG(SSH_LOG_WARN,
"Can not verify %s signature with %s key",
sig->type_c,
key->type_c);
return SSH_ERROR;
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(key, sig->hash_type);
if (rc != SSH_OK) {
return SSH_ERROR;
}
/* For ed25519 keys, verify using the input directly */
if (key->type == SSH_KEYTYPE_ED25519 ||
key->type == SSH_KEYTYPE_ED25519_CERT01)
{
rc = pki_ed25519_verify(key, sig, input, input_len);
} else {
/* For the other key types, calculate the hash and verify the signature */
rc = pki_verify_data_signature(sig, key, input, input_len);
}
if (rc != SSH_OK){
ssh_set_error(session,
SSH_FATAL,
"Signature verification error");
return SSH_ERROR;
}
return SSH_OK;
}
static ssh_string rsa_do_sign_hash(const unsigned char *digest,
int dlen,
mbedtls_pk_context *privkey,
@@ -1213,6 +1169,7 @@ ssh_signature pki_sign_data(const ssh_key privkey,
size_t input_len)
{
unsigned char hash[SHA512_DIGEST_LEN] = {0};
const unsigned char *sign_input = NULL;
uint32_t hlen = 0;
int rc;
@@ -1232,27 +1189,38 @@ ssh_signature pki_sign_data(const ssh_key privkey,
case SSH_DIGEST_SHA256:
sha256(input, input_len, hash);
hlen = SHA256_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_SHA384:
sha384(input, input_len, hash);
hlen = SHA384_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_SHA512:
sha512(input, input_len, hash);
hlen = SHA512_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
sign_input = hash;
break;
case SSH_DIGEST_AUTO:
if (privkey->type == SSH_KEYTYPE_ED25519) {
/* SSH_DIGEST_AUTO should only be used with ed25519 */
sign_input = input;
hlen = input_len;
break;
}
FALL_THROUGH;
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown hash algorithm for type: %d",
hash_type);
return NULL;
}
return pki_do_sign_hash(privkey, hash, hlen, hash_type);
return pki_do_sign_hash(privkey, sign_input, hlen, hash_type);
}
/**
@@ -1275,6 +1243,7 @@ int pki_verify_data_signature(ssh_signature signature,
{
unsigned char hash[SHA512_DIGEST_LEN] = {0};
const unsigned char *verify_input = NULL;
uint32_t hlen = 0;
mbedtls_md_type_t md = 0;
@@ -1300,23 +1269,35 @@ int pki_verify_data_signature(ssh_signature signature,
sha256(input, input_len, hash);
hlen = SHA256_DIGEST_LEN;
md = MBEDTLS_MD_SHA256;
verify_input = hash;
break;
case SSH_DIGEST_SHA384:
sha384(input, input_len, hash);
hlen = SHA384_DIGEST_LEN;
md = MBEDTLS_MD_SHA384;
verify_input = hash;
break;
case SSH_DIGEST_SHA512:
sha512(input, input_len, hash);
hlen = SHA512_DIGEST_LEN;
md = MBEDTLS_MD_SHA512;
verify_input = hash;
break;
case SSH_DIGEST_SHA1:
sha1(input, input_len, hash);
hlen = SHA_DIGEST_LEN;
md = MBEDTLS_MD_SHA1;
verify_input = hash;
break;
case SSH_DIGEST_AUTO:
if (pubkey->type == SSH_KEYTYPE_ED25519 ||
pubkey->type == SSH_KEYTYPE_ED25519_CERT01)
{
verify_input = input;
hlen = input_len;
break;
}
FALL_THROUGH;
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown sig->hash_type: %d",
signature->hash_type);
@@ -1353,6 +1334,14 @@ int pki_verify_data_signature(ssh_signature signature,
}
break;
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_ED25519_CERT01:
rc = pki_ed25519_verify(pubkey, signature, verify_input, hlen);
if (rc != SSH_OK) {
SSH_LOG(SSH_LOG_TRACE, "ED25519 error: Signature invalid");
return SSH_ERROR;
}
break;
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown public key type");
return SSH_ERROR;

View File

@@ -264,7 +264,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexdh_init){
return SSH_PACKET_NOT_USED;
}
int ssh_get_key_params(ssh_session session, ssh_key *privkey){
int
ssh_get_key_params(ssh_session session,
ssh_key *privkey,
enum ssh_digest_e *digest)
{
ssh_key pubkey;
ssh_string pubkey_blob;
int rc;
@@ -290,6 +294,7 @@ int ssh_get_key_params(ssh_session session, ssh_key *privkey){
*privkey = NULL;
}
*digest = session->srv.hostkey_digest;
rc = ssh_pki_export_privkey_to_pubkey(*privkey, &pubkey);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,

View File

@@ -102,36 +102,37 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
* \internal
* \brief inits the socket system (windows specific)
*/
int ssh_socket_init(void) {
if (sockets_initialized == 0) {
int ssh_socket_init(void)
{
if (sockets_initialized == 0) {
#ifdef _WIN32
struct WSAData wsaData;
struct WSAData wsaData;
/* Initiates use of the Winsock DLL by a process. */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
return -1;
/* Initiates use of the Winsock DLL by a process. */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
return -1;
}
#endif
ssh_poll_init();
sockets_initialized = 1;
}
#endif
ssh_poll_init();
sockets_initialized = 1;
}
return 0;
return 0;
}
/**
* @brief Cleanup the socket system.
*/
void ssh_socket_cleanup(void) {
if (sockets_initialized == 1) {
ssh_poll_cleanup();
void ssh_socket_cleanup(void)
{
if (sockets_initialized == 1) {
ssh_poll_cleanup();
#ifdef _WIN32
WSACleanup();
WSACleanup();
#endif
sockets_initialized = 0;
}
sockets_initialized = 0;
}
}
@@ -139,37 +140,38 @@ void ssh_socket_cleanup(void) {
* \internal
* \brief creates a new Socket object
*/
ssh_socket ssh_socket_new(ssh_session session) {
ssh_socket s;
ssh_socket ssh_socket_new(ssh_session session)
{
ssh_socket s;
s = calloc(1, sizeof(struct ssh_socket_struct));
if (s == NULL) {
ssh_set_error_oom(session);
return NULL;
}
s->fd = SSH_INVALID_SOCKET;
s->last_errno = -1;
s->fd_is_socket = 1;
s->session = session;
s->in_buffer = ssh_buffer_new();
if (s->in_buffer == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(s);
return NULL;
}
s->out_buffer=ssh_buffer_new();
if (s->out_buffer == NULL) {
ssh_set_error_oom(session);
ssh_buffer_free(s->in_buffer);
SAFE_FREE(s);
return NULL;
}
s->read_wontblock = 0;
s->write_wontblock = 0;
s->data_except = 0;
s->poll_handle = NULL;
s->state=SSH_SOCKET_NONE;
return s;
s = calloc(1, sizeof(struct ssh_socket_struct));
if (s == NULL) {
ssh_set_error_oom(session);
return NULL;
}
s->fd = SSH_INVALID_SOCKET;
s->last_errno = -1;
s->fd_is_socket = 1;
s->session = session;
s->in_buffer = ssh_buffer_new();
if (s->in_buffer == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(s);
return NULL;
}
s->out_buffer=ssh_buffer_new();
if (s->out_buffer == NULL) {
ssh_set_error_oom(session);
ssh_buffer_free(s->in_buffer);
SAFE_FREE(s);
return NULL;
}
s->read_wontblock = 0;
s->write_wontblock = 0;
s->data_except = 0;
s->poll_handle = NULL;
s->state=SSH_SOCKET_NONE;
return s;
}
/**
@@ -177,17 +179,18 @@ ssh_socket ssh_socket_new(ssh_session session) {
* @brief Reset the state of a socket so it looks brand-new
* @param[in] s socket to rest
*/
void ssh_socket_reset(ssh_socket s){
s->fd = SSH_INVALID_SOCKET;
s->last_errno = -1;
s->fd_is_socket = 1;
ssh_buffer_reinit(s->in_buffer);
ssh_buffer_reinit(s->out_buffer);
s->read_wontblock = 0;
s->write_wontblock = 0;
s->data_except = 0;
s->poll_handle = NULL;
s->state=SSH_SOCKET_NONE;
void ssh_socket_reset(ssh_socket s)
{
s->fd = SSH_INVALID_SOCKET;
s->last_errno = -1;
s->fd_is_socket = 1;
ssh_buffer_reinit(s->in_buffer);
ssh_buffer_reinit(s->out_buffer);
s->read_wontblock = 0;
s->write_wontblock = 0;
s->data_except = 0;
s->poll_handle = NULL;
s->state=SSH_SOCKET_NONE;
}
/**
@@ -198,8 +201,9 @@ void ssh_socket_reset(ssh_socket s){
* @param callbacks a ssh_socket_callback object reference.
*/
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks){
s->callbacks=callbacks;
void ssh_socket_set_callbacks(ssh_socket s, ssh_socket_callbacks callbacks)
{
s->callbacks = callbacks;
}
/**
@@ -383,71 +387,73 @@ ssh_poll_handle ssh_socket_get_poll_handle(ssh_socket s)
/** \internal
* \brief Deletes a socket object
*/
void ssh_socket_free(ssh_socket s){
if (s == NULL) {
return;
}
ssh_socket_close(s);
ssh_buffer_free(s->in_buffer);
ssh_buffer_free(s->out_buffer);
SAFE_FREE(s);
void ssh_socket_free(ssh_socket s)
{
if (s == NULL) {
return;
}
ssh_socket_close(s);
ssh_buffer_free(s->in_buffer);
ssh_buffer_free(s->out_buffer);
SAFE_FREE(s);
}
#ifndef _WIN32
int ssh_socket_unix(ssh_socket s, const char *path) {
struct sockaddr_un sunaddr;
socket_t fd;
sunaddr.sun_family = AF_UNIX;
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
int ssh_socket_unix(ssh_socket s, const char *path)
{
struct sockaddr_un sunaddr;
socket_t fd;
sunaddr.sun_family = AF_UNIX;
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == SSH_INVALID_SOCKET) {
ssh_set_error(s->session, SSH_FATAL,
"Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
strerror(errno));
return -1;
}
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == SSH_INVALID_SOCKET) {
ssh_set_error(s->session, SSH_FATAL,
"Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
strerror(errno));
return -1;
}
if (fcntl(fd, F_SETFD, 1) == -1) {
ssh_set_error(s->session, SSH_FATAL,
"Error from fcntl(fd, F_SETFD, 1): %s",
strerror(errno));
close(fd);
return -1;
}
if (fcntl(fd, F_SETFD, 1) == -1) {
ssh_set_error(s->session, SSH_FATAL,
"Error from fcntl(fd, F_SETFD, 1): %s",
strerror(errno));
close(fd);
return -1;
}
if (connect(fd, (struct sockaddr *) &sunaddr,
sizeof(sunaddr)) < 0) {
ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
strerror(errno));
close(fd);
return -1;
}
ssh_socket_set_fd(s,fd);
return 0;
if (connect(fd, (struct sockaddr *) &sunaddr, sizeof(sunaddr)) < 0) {
ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
strerror(errno));
close(fd);
return -1;
}
ssh_socket_set_fd(s,fd);
return 0;
}
#endif
/** \internal
* \brief closes a socket
*/
void ssh_socket_close(ssh_socket s){
if (ssh_socket_is_open(s)) {
void ssh_socket_close(ssh_socket s)
{
if (ssh_socket_is_open(s)) {
#ifdef _WIN32
CLOSE_SOCKET(s->fd);
s->last_errno = WSAGetLastError();
CLOSE_SOCKET(s->fd);
s->last_errno = WSAGetLastError();
#else
CLOSE_SOCKET(s->fd);
s->last_errno = errno;
CLOSE_SOCKET(s->fd);
s->last_errno = errno;
#endif
}
}
if(s->poll_handle != NULL){
ssh_poll_free(s->poll_handle);
s->poll_handle=NULL;
}
if (s->poll_handle != NULL) {
ssh_poll_free(s->poll_handle);
s->poll_handle = NULL;
}
s->state = SSH_SOCKET_CLOSED;
s->state = SSH_SOCKET_CLOSED;
}
/**
@@ -458,7 +464,8 @@ void ssh_socket_close(ssh_socket s){
* @warning this function updates boths the input and output
* file descriptors
*/
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
void ssh_socket_set_fd(ssh_socket s, socket_t fd)
{
s->fd = fd;
if (s->poll_handle) {
@@ -479,14 +486,15 @@ void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
*/
socket_t ssh_socket_get_fd(ssh_socket s)
{
return s->fd;
return s->fd;
}
/** \internal
* \brief returns nonzero if the socket is open
*/
int ssh_socket_is_open(ssh_socket s) {
return s->fd != SSH_INVALID_SOCKET;
int ssh_socket_is_open(ssh_socket s)
{
return s->fd != SSH_INVALID_SOCKET;
}
/** \internal
@@ -564,29 +572,31 @@ static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
/** \internal
* \brief returns nonzero if the current socket is in the fd_set
*/
int ssh_socket_fd_isset(ssh_socket s, fd_set *set) {
if(s->fd == SSH_INVALID_SOCKET) {
return 0;
}
return FD_ISSET(s->fd,set);
int ssh_socket_fd_isset(ssh_socket s, fd_set *set)
{
if(s->fd == SSH_INVALID_SOCKET) {
return 0;
}
return FD_ISSET(s->fd,set);
}
/** \internal
* \brief sets the current fd in a fd_set and updates the max_fd
*/
void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
if (s->fd == SSH_INVALID_SOCKET) {
return;
}
void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd)
{
if (s->fd == SSH_INVALID_SOCKET) {
return;
}
FD_SET(s->fd,set);
FD_SET(s->fd,set);
if (s->fd >= 0 &&
s->fd >= *max_fd &&
s->fd != SSH_INVALID_SOCKET) {
*max_fd = s->fd + 1;
}
if (s->fd >= 0 &&
s->fd >= *max_fd &&
s->fd != SSH_INVALID_SOCKET) {
*max_fd = s->fd + 1;
}
}
/** \internal
@@ -594,16 +604,17 @@ void ssh_socket_fd_set(ssh_socket s, fd_set *set, socket_t *max_fd) {
* \returns SSH_OK, or SSH_ERROR
* \warning has no effect on socket before a flush
*/
int ssh_socket_write(ssh_socket s, const void *buffer, int len) {
if(len > 0) {
if (ssh_buffer_add_data(s->out_buffer, buffer, len) < 0) {
ssh_set_error_oom(s->session);
return SSH_ERROR;
int ssh_socket_write(ssh_socket s, const void *buffer, int len)
{
if (len > 0) {
if (ssh_buffer_add_data(s->out_buffer, buffer, len) < 0) {
ssh_set_error_oom(s->session);
return SSH_ERROR;
}
ssh_socket_nonblocking_flush(s);
}
ssh_socket_nonblocking_flush(s);
}
return SSH_OK;
return SSH_OK;
}
@@ -685,24 +696,29 @@ int ssh_socket_nonblocking_flush(ssh_socket s)
return SSH_OK;
}
void ssh_socket_set_write_wontblock(ssh_socket s) {
s->write_wontblock = 1;
void ssh_socket_set_write_wontblock(ssh_socket s)
{
s->write_wontblock = 1;
}
void ssh_socket_set_read_wontblock(ssh_socket s) {
s->read_wontblock = 1;
void ssh_socket_set_read_wontblock(ssh_socket s)
{
s->read_wontblock = 1;
}
void ssh_socket_set_except(ssh_socket s) {
s->data_except = 1;
void ssh_socket_set_except(ssh_socket s)
{
s->data_except = 1;
}
int ssh_socket_data_available(ssh_socket s) {
return s->read_wontblock;
int ssh_socket_data_available(ssh_socket s)
{
return s->read_wontblock;
}
int ssh_socket_data_writable(ssh_socket s) {
return s->write_wontblock;
int ssh_socket_data_writable(ssh_socket s)
{
return s->write_wontblock;
}
/** @internal
@@ -710,60 +726,69 @@ int ssh_socket_data_writable(ssh_socket s) {
* @param s the socket
* @returns numbers of bytes buffered, or 0 if the socket isn't connected
*/
int ssh_socket_buffered_write_bytes(ssh_socket s){
if(s==NULL || s->out_buffer == NULL)
return 0;
return ssh_buffer_get_len(s->out_buffer);
int ssh_socket_buffered_write_bytes(ssh_socket s)
{
if (s==NULL || s->out_buffer == NULL) {
return 0;
}
return ssh_buffer_get_len(s->out_buffer);
}
int ssh_socket_get_status(ssh_socket s) {
int r = 0;
int ssh_socket_get_status(ssh_socket s)
{
int r = 0;
if (ssh_buffer_get_len(s->in_buffer) > 0) {
r |= SSH_READ_PENDING;
}
if (ssh_buffer_get_len(s->in_buffer) > 0) {
r |= SSH_READ_PENDING;
}
if (ssh_buffer_get_len(s->out_buffer) > 0) {
r |= SSH_WRITE_PENDING;
}
if (ssh_buffer_get_len(s->out_buffer) > 0) {
r |= SSH_WRITE_PENDING;
}
if (s->data_except) {
r |= SSH_CLOSED_ERROR;
}
if (s->data_except) {
r |= SSH_CLOSED_ERROR;
}
return r;
return r;
}
int ssh_socket_get_poll_flags(ssh_socket s) {
int r = 0;
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLIN) > 0) {
r |= SSH_READ_PENDING;
}
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLOUT) > 0) {
r |= SSH_WRITE_PENDING;
}
return r;
int ssh_socket_get_poll_flags(ssh_socket s)
{
int r = 0;
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLIN) > 0) {
r |= SSH_READ_PENDING;
}
if (s->poll_handle != NULL && (ssh_poll_get_events (s->poll_handle) & POLLOUT) > 0) {
r |= SSH_WRITE_PENDING;
}
return r;
}
#ifdef _WIN32
int ssh_socket_set_nonblocking(socket_t fd) {
u_long nonblocking = 1;
return ioctlsocket(fd, FIONBIO, &nonblocking);
int ssh_socket_set_nonblocking(socket_t fd)
{
u_long nonblocking = 1;
return ioctlsocket(fd, FIONBIO, &nonblocking);
}
int ssh_socket_set_blocking(socket_t fd) {
u_long nonblocking = 0;
return ioctlsocket(fd, FIONBIO, &nonblocking);
int ssh_socket_set_blocking(socket_t fd)
{
u_long nonblocking = 0;
return ioctlsocket(fd, FIONBIO, &nonblocking);
}
#else /* _WIN32 */
int ssh_socket_set_nonblocking(socket_t fd) {
return fcntl(fd, F_SETFL, O_NONBLOCK);
int ssh_socket_set_nonblocking(socket_t fd)
{
return fcntl(fd, F_SETFL, O_NONBLOCK);
}
int ssh_socket_set_blocking(socket_t fd) {
return fcntl(fd, F_SETFL, 0);
int ssh_socket_set_blocking(socket_t fd)
{
return fcntl(fd, F_SETFL, 0);
}
#endif /* _WIN32 */
@@ -782,21 +807,24 @@ int ssh_socket_set_blocking(socket_t fd) {
* which is problematic for hosts having DNS fail-over.
*/
int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr){
socket_t fd;
if(s->state != SSH_SOCKET_NONE) {
ssh_set_error(s->session, SSH_FATAL,
"ssh_socket_connect called on socket not unconnected");
return SSH_ERROR;
}
fd=ssh_connect_host_nonblocking(s->session,host,bind_addr,port);
SSH_LOG(SSH_LOG_PROTOCOL,"Nonblocking connection socket: %d",fd);
if(fd == SSH_INVALID_SOCKET)
return SSH_ERROR;
ssh_socket_set_fd(s,fd);
return SSH_OK;
int
ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bind_addr)
{
socket_t fd;
if (s->state != SSH_SOCKET_NONE) {
ssh_set_error(s->session, SSH_FATAL,
"ssh_socket_connect called on socket not unconnected");
return SSH_ERROR;
}
fd = ssh_connect_host_nonblocking(s->session, host, bind_addr, port);
SSH_LOG(SSH_LOG_PROTOCOL, "Nonblocking connection socket: %d", fd);
if (fd == SSH_INVALID_SOCKET) {
return SSH_ERROR;
}
ssh_socket_set_fd(s,fd);
return SSH_OK;
}
#ifndef _WIN32
@@ -807,16 +835,26 @@ int ssh_socket_connect(ssh_socket s, const char *host, int port, const char *bin
* @param in input file descriptor
* @param out output file descriptor
*/
void ssh_execute_command(const char *command, socket_t in, socket_t out){
const char *args[]={"/bin/sh","-c",command,NULL};
/* redirect in and out to stdin, stdout and stderr */
dup2(in, 0);
dup2(out,1);
dup2(out,2);
close(in);
close(out);
execv(args[0],(char * const *)args);
exit(1);
void
ssh_execute_command(const char *command, socket_t in, socket_t out)
{
const char *args[] = {"/bin/sh", "-c", command, NULL};
/* Prepare /dev/null socket for the stderr redirection */
int devnull = open("/dev/null", O_WRONLY);
if (devnull == -1) {
SSH_LOG(SSH_LOG_WARNING, "Failed to open stderr");
exit(1);
}
/* redirect in and out to stdin, stdout */
dup2(in, 0);
dup2(out, 1);
/* Ignore anything on the stderr */
dup2(devnull, STDERR_FILENO);
close(in);
close(out);
execv(args[0], (char * const *)args);
exit(1);
}
/**
@@ -829,37 +867,39 @@ void ssh_execute_command(const char *command, socket_t in, socket_t out){
* @returns SSH_ERROR error while executing the command.
*/
int ssh_socket_connect_proxycommand(ssh_socket s, const char *command){
socket_t pair[2];
int pid;
int rc;
int
ssh_socket_connect_proxycommand(ssh_socket s, const char *command)
{
socket_t pair[2];
int pid;
int rc;
if (s->state != SSH_SOCKET_NONE) {
return SSH_ERROR;
}
if (s->state != SSH_SOCKET_NONE) {
return SSH_ERROR;
}
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
if (rc < 0) {
return SSH_ERROR;
}
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
if (rc < 0) {
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_PROTOCOL,"Executing proxycommand '%s'",command);
pid = fork();
if(pid == 0){
ssh_execute_command(command,pair[0],pair[0]);
}
close(pair[0]);
SSH_LOG(SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
ssh_socket_set_fd(s, pair[1]);
s->state=SSH_SOCKET_CONNECTED;
s->fd_is_socket=0;
/* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLIN | POLLOUT);
if(s->callbacks && s->callbacks->connected) {
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
}
SSH_LOG(SSH_LOG_PROTOCOL, "Executing proxycommand '%s'", command);
pid = fork();
if(pid == 0) {
ssh_execute_command(command, pair[0], pair[0]);
}
close(pair[0]);
SSH_LOG(SSH_LOG_PROTOCOL, "ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]);
ssh_socket_set_fd(s, pair[1]);
s->state=SSH_SOCKET_CONNECTED;
s->fd_is_socket=0;
/* POLLOUT is the event to wait for in a nonblocking connect */
ssh_poll_set_events(ssh_socket_get_poll_handle(s), POLLIN | POLLOUT);
if (s->callbacks && s->callbacks->connected) {
s->callbacks->connected(SSH_SOCKET_CONNECTED_OK, 0, s->callbacks->userdata);
}
return SSH_OK;
return SSH_OK;
}
#endif /* _WIN32 */

View File

@@ -26,6 +26,7 @@
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "libssh/priv.h"
#include "libssh/token.h"
@@ -175,7 +176,7 @@ char *ssh_find_matching(const char *available_list,
for (i = 0; p_tok->tokens[i]; i++) {
for (j = 0; a_tok->tokens[j]; j++) {
if (strcmp(a_tok->tokens[j], p_tok->tokens[i]) == 0){
if (strcmp(a_tok->tokens[j], p_tok->tokens[i]) == 0) {
ret = strdup(a_tok->tokens[j]);
goto out;
}
@@ -260,3 +261,152 @@ out:
ssh_tokens_free(p_tok);
return ret;
}
/**
* @internal
*
* @brief Given a string containing a list of elements, remove all duplicates
* and return in a newly allocated string.
*
* @param[in] list The list to be freed of duplicates
*
* @return A newly allocated copy of the string free of duplicates; NULL in
* case of error.
*/
char *ssh_remove_duplicates(const char *list)
{
struct ssh_tokens_st *tok = NULL;
size_t i, j, num_tokens, max_len;
char *ret = NULL;
bool *should_copy = NULL, need_comma = false;
if (list == NULL) {
return NULL;
}
/* The maximum number of tokens is the size of the list */
max_len = strlen(list);
if (max_len == 0) {
return NULL;
}
/* Add space for ending '\0' */
max_len++;
tok = ssh_tokenize(list, ',');
if ((tok == NULL) || (tok->tokens == NULL) || (tok->tokens[0] == NULL)) {
goto out;
}
should_copy = calloc(1, max_len);
if (should_copy == NULL) {
goto out;
}
if (strlen(tok->tokens[0]) > 0) {
should_copy[0] = true;
}
for (i = 1; tok->tokens[i]; i++) {
for (j = 0; j < i; j++) {
if (strcmp(tok->tokens[i], tok->tokens[j]) == 0) {
/* Found a duplicate; do not copy */
should_copy[i] = false;
break;
}
}
/* No matching token before */
if (j == i) {
/* Only copy if it is not an empty string */
if (strlen(tok->tokens[i]) > 0) {
should_copy[i] = true;
} else {
should_copy[i] = false;
}
}
}
num_tokens = i;
ret = calloc(1, max_len);
if (ret == NULL) {
goto out;
}
for (i = 0; i < num_tokens; i++) {
if (should_copy[i]) {
if (need_comma) {
strncat(ret, ",", (max_len - strlen(ret) - 1));
}
strncat(ret, tok->tokens[i], (max_len - strlen(ret) - 1));
need_comma = true;
}
}
/* If no comma is needed, nothing was copied */
if (!need_comma) {
SAFE_FREE(ret);
}
out:
SAFE_FREE(should_copy);
ssh_tokens_free(tok);
return ret;
}
/**
* @internal
*
* @brief Given two strings containing lists of tokens, return a newly
* allocated string containing all the elements of the first list appended with
* all the elements of the second list, without duplicates. The order of the
* elements will be preserved.
*
* @param[in] list The first list
* @param[in] appended_list The list to be appended
*
* @return A newly allocated copy list containing all the elements of the
* kept_list appended with the elements of the appended_list without duplicates;
* NULL in case of error.
*/
char *ssh_append_without_duplicates(const char *list,
const char *appended_list)
{
size_t concat_len = 0;
char *ret = NULL, *concat = NULL;
if (list != NULL) {
concat_len = strlen(list);
}
if (appended_list != NULL) {
concat_len += strlen(appended_list);
}
if (concat_len == 0) {
return NULL;
}
/* Add room for ending '\0' and for middle ',' */
concat_len += 2;
concat = calloc(1, concat_len);
if (concat == NULL) {
return NULL;
}
if (list != NULL) {
strcpy(concat, list);
strncat(concat, ",", concat_len - strlen(concat) - 1);
}
if (appended_list != NULL) {
strncat(concat, appended_list, concat_len - strlen(concat) - 1);
}
ret = ssh_remove_duplicates(concat);
SAFE_FREE(concat);
return ret;
}

View File

@@ -539,6 +539,7 @@ int crypt_set_algorithms_server(ssh_session session){
method = session->next_crypto->kex_methods[SSH_HOSTKEYS];
session->srv.hostkey = ssh_key_type_from_signature_name(method);
session->srv.hostkey_digest = ssh_key_hash_from_name(method);
/* setup DH key exchange type */
switch (session->next_crypto->kex_type) {

View File

@@ -6,20 +6,16 @@ endif (BSD OR SOLARIS OR OSX)
set(TORTURE_LIBRARY torture)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIR}
${CMOCKA_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}
)
include_directories(${OPENSSL_INCLUDE_DIR}
${CMOCKA_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${libssh_BINARY_DIR}
${libssh_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR})
set(TORTURE_LINK_LIBRARIES
${CMOCKA_LIBRARY}
${LIBSSH_STATIC_LIBRARY}
${LIBSSH_LINK_LIBRARIES})
ssh::static)
# create test library
add_library(${TORTURE_LIBRARY}
@@ -47,7 +43,7 @@ set(TEST_TARGET_LIBRARIES
add_subdirectory(unittests)
if (CLIENT_TESTING)
if (CLIENT_TESTING OR SERVER_TESTING)
find_package(socket_wrapper 1.1.5 REQUIRED)
find_package(nss_wrapper 1.1.2 REQUIRED)
find_package(uid_wrapper 1.2.0 REQUIRED)
@@ -67,8 +63,8 @@ if (CLIENT_TESTING)
find_program(SSH_EXECUTABLE NAMES ssh)
if (SSH_EXECUTABLE)
execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR)
string(REGEX REPLACE "^OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
string(REGEX REPLACE "^OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
string(REGEX REPLACE "^.*OpenSSH_([0-9]).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
string(REGEX REPLACE "^.*OpenSSH_[0-9].([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
add_definitions(-DOPENSSH_VERSION_MAJOR=${OPENSSH_VERSION_MAJOR} -DOPENSSH_VERSION_MINOR=${OPENSSH_VERSION_MINOR})
endif()
@@ -92,7 +88,7 @@ if (CLIENT_TESTING)
# ssh_ping
add_executable(ssh_ping ssh_ping.c)
target_compile_options(ssh_ping PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(ssh_ping ${LIBSSH_SHARED_LIBRARY})
target_link_libraries(ssh_ping ssh::ssh)
# homedir will be used in passwd
set(HOMEDIR ${CMAKE_CURRENT_BINARY_DIR}/home)
@@ -139,18 +135,20 @@ if (CLIENT_TESTING)
file(COPY keys/certauth/id_rsa-cert.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh_cert/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
message(STATUS "TORTURE_ENVIRONMENT=${TORTURE_ENVIRONMENT}")
add_subdirectory(client)
endif (CLIENT_TESTING)
endif ()
if (WITH_BENCHMARKS)
add_subdirectory(benchmarks)
endif (WITH_BENCHMARKS)
endif ()
if (CLIENT_TESTING)
add_subdirectory(client)
endif ()
if (WITH_SERVER AND SERVER_TESTING)
add_subdirectory(pkd)
add_subdirectory(server)
endif (WITH_SERVER AND SERVER_TESTING)
endif ()
if (FUZZ_TESTING)
add_subdirectory(fuzz)

View File

@@ -4,18 +4,8 @@ set(benchmarks_SRCS
bench_scp.c bench_sftp bench_raw.c benchmarks.c latency.c
)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
)
include_directories(${libssh_BINARY_DIR})
add_executable(benchmarks ${benchmarks_SRCS})
target_link_libraries(benchmarks ${LIBSSH_SHARED_LIBRARY})
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}
)
if (WITH_SFTP)
endif (WITH_SFTP)
target_link_libraries(benchmarks ssh::ssh)

View File

@@ -14,7 +14,8 @@ set(LIBSSH_CLIENT_TESTS
torture_knownhosts_verify
torture_proxycommand
torture_session
torture_request_env)
torture_request_env
torture_client_global_requests)
if (DEFAULT_C_NO_DEPRECATION_FLAGS)
set_source_files_properties(torture_knownhosts.c

View File

@@ -0,0 +1,152 @@
/*
* torture_client_global_requests.c - Tests for client global requests
*
* This file is part of the SSH Library
*
* Copyright (c) 2019 by Red Hat, Inc.
*
* Author: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
*
* 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.
*/
#include "config.h"
#define LIBSSH_STATIC
#include "torture.h"
#include "libssh/libssh.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/channels.h"
#include <errno.h>
#include <sys/types.h>
#include <pwd.h>
static int sshd_setup(void **state)
{
torture_setup_sshd_server(state, true);
return 0;
}
static int sshd_teardown(void **state)
{
torture_teardown_sshd_server(state);
return 0;
}
static int session_setup(void **state)
{
struct torture_state *s = *state;
int verbosity = torture_libssh_verbosity();
struct passwd *pwd;
bool b = false;
int rc;
pwd = getpwnam("bob");
assert_non_null(pwd);
rc = setuid(pwd->pw_uid);
assert_return_code(rc, errno);
s->ssh.session = ssh_new();
assert_non_null(s->ssh.session);
ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
/* Make sure no other configuration options from system will get used */
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b);
assert_ssh_return_code(s->ssh.session, rc);
return 0;
}
static int session_teardown(void **state)
{
struct torture_state *s = *state;
ssh_disconnect(s->ssh.session);
ssh_free(s->ssh.session);
return 0;
}
static int authenticate(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
int rc;
rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_BOB);
assert_int_equal(rc, SSH_OK);
rc = ssh_connect(session);
assert_int_equal(rc, SSH_OK);
rc = ssh_userauth_password(session, NULL, TORTURE_SSH_USER_BOB_PASSWORD);
assert_int_equal(rc, SSH_AUTH_SUCCESS);
return rc;
}
static void torture_unknown_request(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
ssh_channel channel;
int rc;
rc = authenticate(state);
assert_ssh_return_code(session, rc);
/* Request asking for reply */
rc = ssh_global_request(session, "unknown-request-00@test.com", NULL, 1);
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
/* Request and don't ask for reply */
rc = ssh_global_request(session, "another-bad-req-00@test.com", NULL, 0);
assert_ssh_return_code(session, rc);
/* Open channel to make sure the session is still working */
channel = ssh_channel_new(session);
assert_non_null(channel);
rc = ssh_channel_open_session(channel);
assert_ssh_return_code(session, rc);
ssh_channel_close(channel);
}
int torture_run_tests(void)
{
int rc;
struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(torture_unknown_request,
session_setup,
session_teardown),
};
ssh_init();
torture_filter_tests(tests);
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
ssh_finalize();
return rc;
}

View File

@@ -33,7 +33,7 @@
#include "session.c"
#include "known_hosts.c"
#define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts"
#define TMP_FILE_TEMPLATE "known_hosts_XXXXXX"
#define BADRSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQChm5" \
"a6Av65O8cKtx5YXOnui3wJnYE6A6J/I4kZSAibbn14Jcl+34VJQwv96f25AxNmo" \
@@ -62,6 +62,7 @@ static int session_setup(void **state)
struct torture_state *s = *state;
int verbosity = torture_libssh_verbosity();
struct passwd *pwd;
bool process_config = false;
int rc;
pwd = getpwnam("bob");
@@ -74,8 +75,9 @@ static int session_setup(void **state)
assert_non_null(s->ssh.session);
ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG,
&process_config);
ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
ssh_options_set(s->ssh.session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
return 0;
@@ -84,19 +86,10 @@ static int session_setup(void **state)
static int session_teardown(void **state)
{
struct torture_state *s = *state;
char known_hosts_file[1024];
snprintf(known_hosts_file,
sizeof(known_hosts_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
ssh_disconnect(s->ssh.session);
ssh_free(s->ssh.session);
unlink(known_hosts_file);
return 0;
}
@@ -104,17 +97,22 @@ static int session_teardown(void **state)
static void torture_knownhosts_port(void **state) {
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024];
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
char buffer[200];
char *p;
FILE *file;
int rc;
bool process_config = false;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
@@ -140,8 +138,10 @@ static void torture_knownhosts_port(void **state) {
/* Now, connect back to the ssh server and verify the known host line */
s->ssh.session = session = ssh_new();
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
free(known_hosts_file);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
@@ -155,16 +155,20 @@ static void torture_knownhosts_wildcard(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024];
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
const char *key = NULL;
FILE *file;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
file = fopen(known_hosts_file, "w");
assert_non_null(file);
@@ -176,6 +180,7 @@ static void torture_knownhosts_wildcard(void **state)
assert_ssh_return_code(session, rc);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
free(known_hosts_file);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
@@ -188,16 +193,20 @@ static void torture_knownhosts_standard_port(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024];
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
const char *key = NULL;
FILE *file;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
file = fopen(known_hosts_file, "w");
assert_non_null(file);
@@ -209,6 +218,7 @@ static void torture_knownhosts_standard_port(void **state)
assert_ssh_return_code(session, rc);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
free(known_hosts_file);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
@@ -220,15 +230,19 @@ static void torture_knownhosts_standard_port(void **state)
static void torture_knownhosts_fail(void **state) {
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024];
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
FILE *file;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
@@ -238,6 +252,7 @@ static void torture_knownhosts_fail(void **state) {
file = fopen(known_hosts_file, "w");
assert_non_null(file);
free(known_hosts_file);
fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA);
fclose(file);
@@ -252,15 +267,19 @@ static void torture_knownhosts_fail(void **state) {
static void torture_knownhosts_other(void **state) {
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024];
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
FILE *file;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
@@ -270,6 +289,8 @@ static void torture_knownhosts_other(void **state) {
file = fopen(known_hosts_file, "w");
assert_non_null(file);
free(known_hosts_file);
fprintf(file, "127.0.0.10 ssh-rsa %s\n", BADRSA);
fclose(file);
@@ -283,14 +304,18 @@ static void torture_knownhosts_other(void **state) {
static void torture_knownhosts_other_auto(void **state) {
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024];
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
assert_ssh_return_code(session, rc);
@@ -333,20 +358,25 @@ static void torture_knownhosts_other_auto(void **state) {
assert_int_equal(rc, SSH_SERVER_KNOWN_OK);
/* session will be freed by session_teardown() */
free(known_hosts_file);
}
static void torture_knownhosts_conflict(void **state) {
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024];
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
FILE *file;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
assert_ssh_return_code(session, rc);
@@ -393,6 +423,7 @@ static void torture_knownhosts_conflict(void **state) {
assert_int_equal(rc, SSH_SERVER_KNOWN_OK);
/* session will be freed by session_teardown() */
free(known_hosts_file);
}
static void torture_knownhosts_no_hostkeychecking(void **state)
@@ -400,19 +431,24 @@ static void torture_knownhosts_no_hostkeychecking(void **state)
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024] = {0};
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
enum ssh_known_hosts_e found;
int strict_host_key_checking = 0;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
free(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ecdsa-sha2-nistp521");
assert_ssh_return_code(session, rc);

View File

@@ -31,9 +31,17 @@
#include "knownhosts.c"
#define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts"
#define TMP_FILE_TEMPLATE "known_hosts_XXXXXX"
#define BAD_RSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQDXvXuawzaArEwkLIXTz/EWywLOCtqQL3P9yKkrhz6AplXP2PhOh5pyxa1VfGKe453jNeYBJ0ROto3BshXgZXbo86oLXTkbe0gO5xi3r5WjXxjOFvRRTLot5fPLNDOv9+TnsPmkNn0iIeyPnfrcPIyjWt5zSWUfkNC8oNHxsiSshjpbJvTXSDipukpUy41d7jg4uWGuonMTF7yu7HfuHqq7lhb0WlwSpfbqAbfYARBddcdcARyhix4RMWZZqVY20H3Vsjq8bjKC+NJXFce1PRg+qcOWQdlXEei4dkzAvHvfQRx1TjzkrBZ6B6thmZtyeb9IsiB0tg2g0JN2VTAGkxqp"
#define BAD_RSA "AAAAB3NzaC1yc2EAAAADAQABAAABAQDXvXuawzaArEwkLIXTz/EWywLOC" \
"tqQL3P9yKkrhz6AplXP2PhOh5pyxa1VfGKe453jNeYBJ0ROto3BshXgZX" \
"bo86oLXTkbe0gO5xi3r5WjXxjOFvRRTLot5fPLNDOv9+TnsPmkNn0iIey" \
"PnfrcPIyjWt5zSWUfkNC8oNHxsiSshjpbJvTXSDipukpUy41d7jg4uWGu" \
"onMTF7yu7HfuHqq7lhb0WlwSpfbqAbfYARBddcdcARyhix4RMWZZqVY20" \
"H3Vsjq8bjKC+NJXFce1PRg+qcOWQdlXEei4dkzAvHvfQRx1TjzkrBZ6B6" \
"thmZtyeb9IsiB0tg2g0JN2VTAGkxqp"
const char template[] = "temp_dir_XXXXXX";
static int sshd_group_setup(void **state)
{
@@ -55,6 +63,8 @@ static int session_setup(void **state)
struct passwd *pwd;
int rc;
bool process_config = false;
pwd = getpwnam("bob");
assert_non_null(pwd);
@@ -67,6 +77,10 @@ static int session_setup(void **state)
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG,
&process_config);
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
assert_ssh_return_code(s->ssh.session, rc);
@@ -81,19 +95,9 @@ static int session_setup(void **state)
static int session_teardown(void **state)
{
struct torture_state *s = *state;
char known_hosts_file[1024];
snprintf(known_hosts_file,
sizeof(known_hosts_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
ssh_disconnect(s->ssh.session);
ssh_free(s->ssh.session);
unlink(known_hosts_file);
return 0;
}
@@ -147,15 +151,19 @@ static void torture_knownhosts_precheck(void **state)
struct ssh_iterator *it = NULL;
size_t algo_count;
const char *algo = NULL;
char known_hosts_file[1024] = {0};
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
FILE *file;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
file = fopen(known_hosts_file, "w");
assert_non_null(file);
@@ -175,6 +183,7 @@ static void torture_knownhosts_precheck(void **state)
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
free(known_hosts_file);
algo_list = ssh_known_hosts_get_algorithms(session);
assert_non_null(algo_list);
@@ -212,15 +221,19 @@ static void torture_knownhosts_duplicate(void **state)
struct ssh_iterator *it = NULL;
size_t algo_count;
const char *algo = NULL;
char known_hosts_file[1024] = {0};
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
FILE *file;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
file = fopen(known_hosts_file, "w");
assert_non_null(file);
@@ -240,6 +253,7 @@ static void torture_knownhosts_duplicate(void **state)
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
free(known_hosts_file);
algo_list = ssh_known_hosts_get_algorithms(session);
assert_non_null(algo_list);
@@ -259,16 +273,20 @@ static void torture_knownhosts_other(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024] = {0};
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
enum ssh_known_hosts_e found;
FILE *file = NULL;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
@@ -282,6 +300,7 @@ static void torture_knownhosts_other(void **state)
"127.0.0.10 %s\n",
torture_get_testkey_pub(SSH_KEYTYPE_RSA));
fclose(file);
free(known_hosts_file);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
@@ -294,15 +313,19 @@ static void torture_knownhosts_unknown(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024] = {0};
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
enum ssh_known_hosts_e found;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
assert_ssh_return_code(session, rc);
@@ -347,22 +370,27 @@ static void torture_knownhosts_unknown(void **state)
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
/* session will be freed by session_teardown() */
free(known_hosts_file);
}
static void torture_knownhosts_conflict(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char known_hosts_file[1024] = {0};
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
enum ssh_known_hosts_e found;
FILE *file = NULL;
int rc;
snprintf(known_hosts_file,
sizeof(known_hosts_file),
snprintf(tmp_file,
sizeof(tmp_file),
"%s/%s",
s->socket_dir,
TORTURE_KNOWN_HOSTS_FILE);
TMP_FILE_TEMPLATE);
known_hosts_file = torture_create_temp_file(tmp_file);
assert_non_null(known_hosts_file);
file = fopen(known_hosts_file, "w");
assert_non_null(file);
@@ -412,6 +440,44 @@ static void torture_knownhosts_conflict(void **state)
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
/* session will be freed by session_teardown() */
free(known_hosts_file);
}
static void torture_knownhosts_new_file(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
enum ssh_known_hosts_e found;
int rc;
char new_known_hosts[256];
char *tmp_dir = NULL;
ssize_t count = 0;
/* Create a disposable directory */
tmp_dir = torture_make_temp_dir(template);
assert_non_null(tmp_dir);
count = snprintf(new_known_hosts, sizeof(new_known_hosts),
"%s/a/b/c/d/known_hosts", tmp_dir);
assert_return_code(count, errno);
rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, new_known_hosts);
assert_ssh_return_code(session, rc);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
rc = ssh_session_update_known_hosts(session);
assert_ssh_return_code(session, rc);
found = ssh_session_is_known_server(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
/* Cleanup */
torture_rmdirs(tmp_dir);
SAFE_FREE(tmp_dir);
}
int torture_run_tests(void) {
@@ -438,6 +504,9 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_knownhosts_duplicate,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_knownhosts_new_file,
session_setup,
session_teardown),
};
ssh_init();

View File

@@ -7,6 +7,7 @@
#include "libssh/priv.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <errno.h>
#include <fcntl.h>
@@ -65,10 +66,17 @@ static void torture_options_set_proxycommand(void **state)
const char *address = torture_server_address(AF_INET);
int port = torture_server_port();
char command[255] = {0};
struct stat sb;
int rc;
socket_t fd;
rc = snprintf(command, sizeof(command), "nc %s %d", address, port);
rc = stat("/bin/nc", &sb);
if (rc != 0 || (sb.st_mode & S_IXOTH) == 0) {
SSH_LOG(SSH_LOG_WARNING, "Could not find /bin/nc: Skipping the test");
skip();
}
rc = snprintf(command, sizeof(command), "/bin/nc %s %d", address, port);
assert_true((size_t)rc < sizeof(command));
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, command);
@@ -115,6 +123,28 @@ static void torture_options_set_proxycommand_ssh(void **state)
assert_int_equal(rc & O_RDWR, O_RDWR);
}
static void torture_options_set_proxycommand_ssh_stderr(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
const char *address = torture_server_address(AF_INET);
char command[255] = {0};
int rc;
socket_t fd;
rc = snprintf(command, sizeof(command), "ssh -vvv -W [%%h]:%%p alice@%s", address);
assert_true((size_t)rc < sizeof(command));
rc = ssh_options_set(session, SSH_OPTIONS_PROXYCOMMAND, command);
assert_int_equal(rc, 0);
rc = ssh_connect(session);
assert_ssh_return_code(session, rc);
fd = ssh_get_fd(session);
assert_true(fd != SSH_INVALID_SOCKET);
rc = fcntl(fd, F_GETFL);
assert_int_equal(rc & O_RDWR, O_RDWR);
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -127,6 +157,9 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh_stderr,
session_setup,
session_teardown),
};

View File

@@ -2,14 +2,12 @@ project(pkd C)
if (WITH_SERVER AND UNIX AND NOT WIN32)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${CMOCKA_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}
)
include_directories(${libssh_SOURCE_DIR}/include
${CMOCKA_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${CMAKE_BINARY_DIR}
${libssh_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR})
set(pkd_hello_src
pkd_daemon.c
@@ -20,8 +18,7 @@ set(pkd_hello_src
set(pkd_libs
${CMOCKA_LIBRARY}
${LIBSSH_STATIC_LIBRARY}
${LIBSSH_LINK_LIBRARIES}
ssh::static
${ARGP_LIBRARIES}
pthread
)

View File

@@ -252,6 +252,7 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
size_t kex_len = 0;
const char *all_ciphers = NULL;
const uint64_t rekey_data_limit = args->rekey_data_limit;
bool process_config = false;
pkd_state.eof_received = 0;
pkd_state.close_received = 0;
@@ -291,6 +292,13 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
goto outclose;
}
rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_PROCESS_CONFIG,
&process_config);
if (rc != 0) {
pkderr("ssh_bind_options_set process config: %s\n", ssh_get_error(b));
goto outclose;
}
if (!ssh_fips_mode()) {
/* Add methods not enabled by default */
#define GEX_SHA1 "diffie-hellman-group-exchange-sha1"

View File

@@ -261,7 +261,7 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
f(client, ecdsa_256_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_256, teardown) \
f(client, ecdsa_384_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_384, teardown) \
f(client, ecdsa_521_diffie_hellman_group_exchange_sha256, kexcmd(GEX_SHA256), setup_ecdsa_521, teardown)
#elif /* !defined(WITH_GEX) */
#else /* !defined(WITH_GEX) */
#define PKDTESTS_KEX_FIPS(f, client, kexcmd) \
f(client, rsa_ecdh_sha2_nistp256, kexcmd("ecdh-sha2-nistp256"), setup_rsa, teardown) \
f(client, rsa_ecdh_sha2_nistp384, kexcmd("ecdh-sha2-nistp384"), setup_rsa, teardown) \

View File

@@ -12,11 +12,9 @@ set(LIBSSH_SERVER_TESTS
torture_server_config
)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}
test_server
)
include_directories(${libssh_SOURCE_DIR}/include
${libssh_BINARY_DIR}
test_server)
if (ARGP_INCLUDE_DIR)
include_directories(${ARGP_INCLUDE_DIR})

View File

@@ -16,10 +16,8 @@ set(LIBSSH_SERVER_TESTS
# torture_server_kbdint
)
include_directories(
${LIBSSH_PUBLIC_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}
)
include_directories(${libssh_SOURCE_DIR}/include
${libssh_BINARY_DIR})
if (ARGP_INCLUDE_DIR)
include_directories(${ARGP_INCLUDE_DIR})
@@ -30,7 +28,7 @@ if (UNIX AND NOT WIN32)
target_compile_options(test_server PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(test_server
testserver
${LIBSSH_SHARED_LIBRARY}
ssh::ssh
${ARGP_LIBRARY}
util)
endif ()

View File

@@ -73,7 +73,9 @@ int run_server(struct server_state_st *state)
ssh_bind sshbind = NULL;
ssh_event event = NULL;
struct sigaction sa = {0};
struct sigaction sa = {
.sa_flags = 0
};
int rc;

View File

@@ -473,6 +473,50 @@ static void torture_server_hostkey_mismatch(void **state)
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
}
static void torture_server_unknown_global_request(void **state)
{
struct test_server_st *tss = *state;
struct torture_state *s = NULL;
ssh_session session = NULL;
ssh_channel channel;
int rc;
assert_non_null(tss);
s = tss->state;
assert_non_null(s);
session = s->ssh.session;
assert_non_null(session);
rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER);
assert_int_equal(rc, SSH_OK);
rc = ssh_connect(session);
assert_int_equal(rc, SSH_OK);
/* Using the default password for the server */
rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD);
assert_int_equal(rc, SSH_AUTH_SUCCESS);
/* Request asking for reply */
rc = ssh_global_request(session, "unknown-request-00@test.com", NULL, 1);
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
/* Request and don't ask for reply */
rc = ssh_global_request(session, "another-bad-req-00@test.com", NULL, 0);
assert_ssh_return_code(session, rc);
/* Open channel to make sure the session is still working */
channel = ssh_channel_new(session);
assert_non_null(channel);
rc = ssh_channel_open_session(channel);
assert_ssh_return_code(session, rc);
ssh_channel_close(channel);
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -488,6 +532,9 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_server_hostkey_mismatch,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_server_unknown_global_request,
session_setup,
session_teardown),
};
ssh_init();

View File

@@ -657,9 +657,9 @@ static int session_setup(void **state)
assert_non_null(s->ssh.session);
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
assert_return_code(s->ssh.session, rc);
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
assert_return_code(s->ssh.session, rc);
assert_ssh_return_code(s->ssh.session, rc);
/* Make sure no other configuration options from system will get used */
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b);
assert_ssh_return_code(s->ssh.session, rc);

View File

@@ -430,10 +430,7 @@ static size_t setup_hostkey_files(struct test_server_st *tss)
hostkey_files[0] = tss->rsa_hostkey;
#ifndef TEST_ALL_CRYPTO_COMBINATIONS
goto end;
#endif
#ifdef TEST_ALL_CRYPTO_COMBINATIONS
hostkey_files[1] = tss->ecdsa_256_hostkey;
hostkey_files[2] = tss->ecdsa_384_hostkey;
hostkey_files[3] = tss->ecdsa_521_hostkey;
@@ -448,8 +445,8 @@ static size_t setup_hostkey_files(struct test_server_st *tss)
num_hostkey_files++;
#endif
}
#endif /* TEST_ALL_CRYPTO_COMBINATIONS */
end:
return num_hostkey_files;
}
@@ -471,9 +468,6 @@ static void torture_server_config_hostkey(void **state)
"HostKey %s\n",
hostkey_files[i]);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
}
@@ -513,9 +507,6 @@ static void torture_server_config_ciphers(void **state)
"HostKey %s\nCiphers %s\n",
hostkey_files[i], ciphers);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -527,9 +518,6 @@ static void torture_server_config_ciphers(void **state)
"HostKey %s\nCiphers %s\n",
hostkey_files[i], tokens->tokens[j]);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -574,9 +562,6 @@ static void torture_server_config_macs(void **state)
"HostKey %s\nMACs %s\n",
hostkey_files[i], macs);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -588,9 +573,6 @@ static void torture_server_config_macs(void **state)
"HostKey %s\nMACs %s\n",
hostkey_files[i], tokens->tokens[j]);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -635,9 +617,6 @@ static void torture_server_config_kex(void **state)
"HostKey %s\nKexAlgorithms %s\n",
hostkey_files[i], kex);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -649,9 +628,6 @@ static void torture_server_config_kex(void **state)
"HostKey %s\nKexAlgorithms %s\n",
hostkey_files[i], tokens->tokens[j]);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -691,9 +667,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostKeyAlgorithms %s\n",
hostkey_files[i], allowed);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
}
@@ -707,9 +680,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->ed25519_hostkey, "ssh-ed25519");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -719,9 +689,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->rsa_hostkey, "ssh-rsa");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
}
@@ -732,9 +699,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->rsa_hostkey, "rsa-sha2-256");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -744,9 +708,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->rsa_hostkey, "rsa-sha2-512");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -756,9 +717,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->ecdsa_256_hostkey, "ecdsa-sha2-nistp256");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -768,9 +726,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->ecdsa_384_hostkey, "ecdsa-sha2-nistp384");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -780,9 +735,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->ecdsa_521_hostkey, "ecdsa-sha2-nistp521");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
@@ -794,9 +746,6 @@ static void torture_server_config_hostkey_algorithms(void **state)
"HostKey %s\nHostkeyAlgorithms %s\n",
tss->dsa_hostkey, "ssh-dss");
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
}
@@ -818,9 +767,6 @@ static void torture_server_config_unknown(void **state)
"HostKey %s\nUnknownOption unknown-value1,unknown-value2\n",
tss->rsa_hostkey);
rc = try_config_content(state, config_content, true);
assert_int_equal(rc, 0);
rc = try_config_content(state, config_content, false);
assert_int_equal(rc, 0);
}

View File

@@ -262,6 +262,8 @@ ssh_session torture_ssh_session(struct torture_state *s,
int method;
int rc;
bool process_config = false;
if (host == NULL) {
return NULL;
}
@@ -277,6 +279,10 @@ ssh_session torture_ssh_session(struct torture_state *s,
}
#endif /* WITH_PCAP */
if (ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity) < 0) {
goto failed;
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
goto failed;
}
@@ -293,7 +299,8 @@ ssh_session torture_ssh_session(struct torture_state *s,
}
}
if (ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity) < 0) {
if (ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG,
&process_config) < 0) {
goto failed;
}

View File

@@ -602,7 +602,12 @@ static const char torture_ecdsa521_testkey_cert[] =
* ED25519 KEYS
****************************************************************************/
static const char torture_ed25519_private_testkey[] =
static const char torture_ed25519_private_pkcs8_testkey[] =
"-----BEGIN PRIVATE KEY-----\n"
"MC4CAQAwBQYDK2VwBCIEIGBhcqLe61tkqVjIHKEzwB3oINasSHWGbIWXQWcLPmGN\n"
"-----END PRIVATE KEY-----\n";
static const char torture_ed25519_private_openssh_testkey[] =
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"
"QyNTUxOQAAACAVlp8bgmIjsrzGC7ZIKBMhCpS1fpJTPgVOjYdz5gIqlwAAAJBzsDN1c7Az\n"
@@ -611,16 +616,24 @@ static const char torture_ed25519_private_testkey[] =
"lLV+klM+BU6Nh3PmAiqXAAAADGFyaXNAa2FsaXg4NgE=\n"
"-----END OPENSSH PRIVATE KEY-----\n";
static const char torture_ed25519_private_testkey_passphrase[] =
static const char torture_ed25519_private_openssh_testkey_passphrase[] =
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
"b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABB3FWpQcE\n"
"KHKq6PcjkxjmKzAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIOGFVuOyZBL0T+NR\n"
"C7qEV9qr6QiGhz2XSXrxuQoU84FgAAAAkBlOVfS5U7FxtBEtxfxQhZjrZAj2z9d4OfGRPl\n"
"ZfCnAJNEM3BZ3XCabsujhMkqEs9eptRfj41X6NA8aSFs5JYT+JFVfg470FKtpyUmAibMIo\n"
"JzI41zAncFd1x7bAgO5HBDe3xNsV159D+sXRkWB9Tzk0l4F8SZvInheIS7VSbqH7t1+yDB\n"
"Y3GsmYTDstmicanQ==\n"
"b3BlbnNzaC1rZXktdjEAAAAACmFlczEyOC1jYmMAAAAGYmNyeXB0AAAAGAAAABDYuz+a8i\n"
"nb/BgGjQjQtvkUAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBWWnxuCYiOyvMYL\n"
"tkgoEyEKlLV+klM+BU6Nh3PmAiqXAAAAkOBxqvzvPSns3TbhjkCayvANI66100OELnpDOm\n"
"JBGgXr5q846NkAovH3pmJ4O7qzPLTQ/cm0+959VUODRhM1i96qBg5MTNtV33lf5Y57Klzu\n"
"JegbiexcqkHIzriH42K0XSOEpfW8f/rTH7ffjbE/7l8HRNwf7AmcnxLx/d8J8FTBr+8aU7\n"
"qMU3xAJ4ixnwhYFg==\n"
"-----END OPENSSH PRIVATE KEY-----\n";
static const char torture_ed25519_private_pkcs8_testkey_passphrase[] =
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n"
"MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAie1RBk/ub+EwICCAAw\n"
"DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEECRLkPChQx/sZPYLdNJhxMUEQFLj\n"
"7nelAdOx3WXIBbCOfOqg3aAn8C5cXPtIQ+fiui1V8wlXXV8RBiuDCC97ScLs91D5\n"
"qQhQtw0vgfnq1um/izg=\n"
"-----END ENCRYPTED PRIVATE KEY-----\n";
static const char torture_ed25519_public_testkey[] =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBWWnxuCYiOyvMYLtkgoEyEKlLV+klM+"
"BU6Nh3PmAiqX aris@kalix86";
@@ -733,16 +746,19 @@ static const char *torture_get_testkey_internal(enum ssh_keytypes_e type,
return torture_ed25519_public_testkey;
} else if (with_passphrase) {
if (format == 1) {
return torture_ed25519_private_testkey_passphrase;
return torture_ed25519_private_openssh_testkey_passphrase;
}
if (format == 2) {
return torture_ed25519_private_pkcs8_testkey_passphrase;
}
/* ed25519 keys are not available in legacy PEM format */
return NULL;
}
if (format == 1) {
return torture_ed25519_private_testkey;
return torture_ed25519_private_openssh_testkey;
}
/* ed25519 keys are not available in legacy PEM format */
return NULL;
return torture_ed25519_private_pkcs8_testkey;
case SSH_KEYTYPE_DSS_CERT01:
return torture_dsa_testkey_cert;
case SSH_KEYTYPE_RSA_CERT01:

View File

@@ -440,6 +440,8 @@ static void torture_config_unknown(void **state) {
static void torture_config_match(void **state)
{
ssh_session session = *state;
char *localuser = NULL;
char config[1024];
int ret = 0;
/* Without any settings we should get all-matched.com hostname */
@@ -531,6 +533,19 @@ static void torture_config_match(void **state)
assert_ssh_return_code(session, ret);
assert_string_equal(session->opts.host, "canonical.com");
localuser = ssh_get_local_username();
assert_non_null(localuser);
snprintf(config, sizeof(config),
"Match localuser %s\n"
"\tHostName otherhost\n"
"", localuser);
free(localuser);
torture_write_file(LIBSSH_TESTCONFIG10, config);
torture_reset_config(session);
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
assert_ssh_return_code(session, ret);
assert_string_equal(session->opts.host, "otherhost");
/* Try to create some invalid configurations */
/* Missing argument to Match*/
torture_write_file(LIBSSH_TESTCONFIG10,
@@ -550,7 +565,7 @@ static void torture_config_match(void **state)
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
/* Missing argument to unsupported option localuser */
/* Missing argument to option localuser */
torture_write_file(LIBSSH_TESTCONFIG10,
"Match localuser\n"
"\tUser localuser2\n"
@@ -559,7 +574,7 @@ static void torture_config_match(void **state)
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
/* Missing argument to option user*/
/* Missing argument to option user */
torture_write_file(LIBSSH_TESTCONFIG10,
"Match user\n"
"\tUser user2\n"

View File

@@ -28,6 +28,8 @@
#define TMP_FILE_NAME "/tmp/known_hosts_XXXXXX"
const char template[] = "temp_dir_XXXXXX";
static int setup_knownhosts_file(void **state)
{
char *tmp_file = NULL;
@@ -369,6 +371,140 @@ static void torture_knownhosts_read_file(void **state)
ssh_list_free(entry_list);
}
static void torture_knownhosts_get_algorithms_names(void **state)
{
const char *knownhosts_file = *state;
ssh_session session;
const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa";
char *names = NULL;
bool process_config = false;
session = ssh_new();
assert_non_null(session);
/* This makes sure the global configuration file is not processed */
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
names = ssh_known_hosts_get_algorithms_names(session);
assert_non_null(names);
assert_string_equal(names, expect);
SAFE_FREE(names);
ssh_free(session);
}
static void torture_knownhosts_algorithms_wanted(void **state)
{
const char *knownhosts_file = *state;
char *algo_list = NULL;
ssh_session session;
bool process_config = false;
const char *wanted = "ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,"
"rsa-sha2-256,ecdsa-sha2-nistp521";
const char *expect = "rsa-sha2-256,ecdsa-sha2-nistp384,"
"ecdsa-sha2-nistp256,ecdsa-sha2-nistp521";
int verbose = 4;
session = ssh_new();
assert_non_null(session);
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbose);
/* This makes sure the global configuration file is not processed */
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
/* Set the wanted list of hostkeys, ordered by preference */
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
algo_list = ssh_client_select_hostkeys(session);
assert_non_null(algo_list);
assert_string_equal(algo_list, expect);
free(algo_list);
ssh_free(session);
}
static void torture_knownhosts_algorithms_negative(UNUSED_PARAM(void **state))
{
const char *wanted = NULL;
const char *expect = NULL;
char *algo_list = NULL;
char *cwd = NULL;
char *tmp_dir = NULL;
bool process_config = false;
int verbose = 4;
int rc = 0;
ssh_session session;
/* Create temporary directory */
cwd = torture_get_current_working_dir();
assert_non_null(cwd);
tmp_dir = torture_make_temp_dir(template);
assert_non_null(tmp_dir);
rc = torture_change_dir(tmp_dir);
assert_int_equal(rc, 0);
session = ssh_new();
assert_non_null(session);
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbose);
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
/* Test with unknown key type in known_hosts */
wanted = "rsa-sha2-256";
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
torture_write_file("unknown_key_type", "localhost unknown AAAABBBBCCCC");
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "unknown_key_type");
algo_list = ssh_client_select_hostkeys(session);
assert_non_null(algo_list);
assert_string_equal(algo_list, wanted);
SAFE_FREE(algo_list);
/* Test with unsupported, but existing types */
wanted = "rsa-sha2-256-cert-v01@openssh.com,"
"rsa-sha2-512-cert-v01@openssh.com";
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
algo_list = ssh_client_select_hostkeys(session);
assert_null(algo_list);
/* In FIPS mode, test filtering keys not allowed */
if (ssh_fips_mode()) {
wanted = "ssh-ed25519,rsa-sha2-256,ssh-rsa";
expect = "rsa-sha2-256";
ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, wanted);
torture_write_file("no_fips", LOCALHOST_DEFAULT_ED25519);
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "no_fips");
algo_list = ssh_client_select_hostkeys(session);
assert_non_null(algo_list);
assert_string_equal(algo_list, expect);
SAFE_FREE(algo_list);
}
ssh_free(session);
/* Teardown */
rc = torture_change_dir(cwd);
assert_int_equal(rc, 0);
rc = torture_rmdirs(tmp_dir);
assert_int_equal(rc, 0);
SAFE_FREE(tmp_dir);
SAFE_FREE(cwd);
}
#ifndef _WIN32 /* There is no /dev/null on Windows */
static void torture_knownhosts_host_exists(void **state)
{
@@ -381,16 +517,22 @@ static void torture_knownhosts_host_exists(void **state)
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
/* This makes sure the system's known_hosts are not used */
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "/dev/null");
found = ssh_session_has_known_hosts_entry(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
assert_true(found == SSH_KNOWN_HOSTS_OK);
/* This makes sure the check will not fail when the system's known_hosts is
* not accessible*/
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, "./unaccessible");
found = ssh_session_has_known_hosts_entry(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
/* This makes sure the check will fail for an unknown host */
ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
found = ssh_session_has_known_hosts_entry(session);
assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
assert_int_equal(found, SSH_KNOWN_HOSTS_UNKNOWN);
ssh_free(session);
}
@@ -405,27 +547,33 @@ static void torture_knownhosts_host_exists_global(void **state)
assert_non_null(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
/* This makes sure the user's known_hosts are not used */
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, knownhosts_file);
/* This makes sure the user's known_hosts are not used */
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
found = ssh_session_has_known_hosts_entry(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
assert_true(found == SSH_KNOWN_HOSTS_OK);
/* This makes sure the check will not fail when the user's known_hosts is
* not accessible*/
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "./unaccessible");
found = ssh_session_has_known_hosts_entry(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
/* This makes sure the check will fail for an unknown host */
ssh_options_set(session, SSH_OPTIONS_HOST, "wurstbrot");
found = ssh_session_has_known_hosts_entry(session);
assert_true(found == SSH_KNOWN_HOSTS_UNKNOWN);
assert_int_equal(found, SSH_KNOWN_HOSTS_UNKNOWN);
ssh_free(session);
}
static void
torture_knownhosts_algorithms(void **state)
static void torture_knownhosts_algorithms(void **state)
{
const char *knownhosts_file = *state;
char *algo_list = NULL;
ssh_session session;
bool process_config = false;
const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,"
"ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,"
"ecdsa-sha2-nistp256"
@@ -433,10 +581,15 @@ torture_knownhosts_algorithms(void **state)
",ssh-dss"
#endif
;
const char *expect_fips = "rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp521,"
"ecdsa-sha2-nistp384,ecdsa-sha2-nistp256";
session = ssh_new();
assert_non_null(session);
/* This makes sure the global configuration file is not processed */
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
/* This makes sure the system's known_hosts are not used */
@@ -444,18 +597,22 @@ torture_knownhosts_algorithms(void **state)
algo_list = ssh_client_select_hostkeys(session);
assert_non_null(algo_list);
assert_string_equal(algo_list, expect);
if (ssh_fips_mode()) {
assert_string_equal(algo_list, expect_fips);
} else {
assert_string_equal(algo_list, expect);
}
free(algo_list);
ssh_free(session);
}
static void
torture_knownhosts_algorithms_global(void **state)
static void torture_knownhosts_algorithms_global(void **state)
{
const char *knownhosts_file = *state;
char *algo_list = NULL;
ssh_session session;
bool process_config = false;
const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa,"
"ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,"
"ecdsa-sha2-nistp256"
@@ -463,10 +620,15 @@ torture_knownhosts_algorithms_global(void **state)
",ssh-dss"
#endif
;
const char *expect_fips = "rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp521,"
"ecdsa-sha2-nistp384,ecdsa-sha2-nistp256";
session = ssh_new();
assert_non_null(session);
/* This makes sure the global configuration file is not processed */
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
/* This makes sure the current-user's known hosts are not used */
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, "/dev/null");
@@ -474,12 +636,17 @@ torture_knownhosts_algorithms_global(void **state)
algo_list = ssh_client_select_hostkeys(session);
assert_non_null(algo_list);
assert_string_equal(algo_list, expect);
if (ssh_fips_mode()) {
assert_string_equal(algo_list, expect_fips);
} else {
assert_string_equal(algo_list, expect);
}
free(algo_list);
ssh_free(session);
}
#endif
#endif /* _WIN32 There is no /dev/null on Windows */
int torture_run_tests(void) {
int rc;
@@ -498,6 +665,13 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_knownhosts_read_file,
setup_knownhosts_file_duplicate,
teardown_knownhosts_file),
cmocka_unit_test_setup_teardown(torture_knownhosts_get_algorithms_names,
setup_knownhosts_file,
teardown_knownhosts_file),
cmocka_unit_test_setup_teardown(torture_knownhosts_algorithms_wanted,
setup_knownhosts_file,
teardown_knownhosts_file),
cmocka_unit_test(torture_knownhosts_algorithms_negative),
#ifndef _WIN32
cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
setup_knownhosts_file,

View File

@@ -19,6 +19,7 @@
#define TORTURE_TEST_DIR "/usr/local/bin/truc/much/.."
const char template[] = "temp_dir_XXXXXX";
static int setup(void **state)
{
@@ -192,6 +193,18 @@ static void torture_path_expand_known_hosts(void **state) {
free(tmp);
}
static void torture_path_expand_percent(void **state) {
ssh_session session = *state;
char *tmp;
session->opts.sshdir = strdup("/home/guru/.ssh");
tmp = ssh_path_expand_escape(session, "%d/config%%1");
assert_non_null(tmp);
assert_string_equal(tmp, "/home/guru/.ssh/config%1");
free(tmp);
}
static void torture_timeout_elapsed(void **state){
struct ssh_timestamp ts;
(void) state;
@@ -351,6 +364,143 @@ static void torture_ssh_analyze_banner(void **state) {
ssh_free(session);
}
static void torture_ssh_dir_writeable(UNUSED_PARAM(void **state))
{
char *tmp_dir = NULL;
int rc = 0;
FILE *file = NULL;
char buffer[256];
tmp_dir = torture_make_temp_dir(template);
assert_non_null(tmp_dir);
rc = ssh_dir_writeable(tmp_dir);
assert_int_equal(rc, 1);
/* Create a file */
snprintf(buffer, sizeof(buffer), "%s/a", tmp_dir);
file = fopen(buffer, "w");
assert_non_null(file);
fprintf(file, "Hello world!\n");
fclose(file);
/* Negative test for checking a normal file */
rc = ssh_dir_writeable(buffer);
assert_int_equal(rc, 0);
/* Negative test for non existent file */
snprintf(buffer, sizeof(buffer), "%s/b", tmp_dir);
rc = ssh_dir_writeable(buffer);
assert_int_equal(rc, 0);
#ifndef _WIN32
/* Negative test for directory without write permission */
rc = ssh_mkdir(buffer, 0400);
assert_return_code(rc, errno);
rc = ssh_dir_writeable(buffer);
assert_int_equal(rc, 0);
#endif
torture_rmdirs(tmp_dir);
SAFE_FREE(tmp_dir);
}
static void torture_ssh_mkdirs(UNUSED_PARAM(void **state))
{
char *tmp_dir = NULL;
char *cwd = NULL;
char buffer[256];
ssize_t count = 0;
int rc;
/* Get current working directory */
cwd = torture_get_current_working_dir();
assert_non_null(cwd);
/* Create a base disposable directory */
tmp_dir = torture_make_temp_dir(template);
assert_non_null(tmp_dir);
/* Create a single directory */
count = snprintf(buffer, sizeof(buffer), "%s/a", tmp_dir);
assert_return_code(count, errno);
rc = ssh_mkdirs(buffer, 0700);
assert_return_code(rc, errno);
rc = ssh_dir_writeable(buffer);
assert_int_equal(rc, 1);
/* Create directories recursively */
count = snprintf(buffer, sizeof(buffer), "%s/b/c/d", tmp_dir);
assert_return_code(count, errno);
rc = ssh_mkdirs(buffer, 0700);
assert_return_code(rc, errno);
rc = ssh_dir_writeable(buffer);
assert_int_equal(rc, 1);
/* Change directory */
rc = torture_change_dir(tmp_dir);
assert_return_code(rc, errno);
/* Create single local directory */
rc = ssh_mkdirs("e", 0700);
assert_return_code(rc, errno);
rc = ssh_dir_writeable("e");
assert_int_equal(rc, 1);
/* Create local directories recursively */
rc = ssh_mkdirs("f/g/h", 0700);
assert_return_code(rc, errno);
rc = ssh_dir_writeable("f/g/h");
assert_int_equal(rc, 1);
/* Negative test for creating "." directory */
rc = ssh_mkdirs(".", 0700);
assert_int_equal(rc, -1);
assert_int_equal(errno, EINVAL);
/* Negative test for creating "/" directory */
rc = ssh_mkdirs("/", 0700);
assert_int_equal(rc, -1);
assert_int_equal(errno, EINVAL);
/* Negative test for creating "" directory */
rc = ssh_mkdirs("", 0700);
assert_int_equal(rc, -1);
assert_int_equal(errno, EINVAL);
/* Negative test for creating NULL directory */
rc = ssh_mkdirs(NULL, 0700);
assert_int_equal(rc, -1);
assert_int_equal(errno, EINVAL);
/* Negative test for creating existing directory */
rc = ssh_mkdirs("a", 0700);
assert_int_equal(rc, -1);
assert_int_equal(errno, EEXIST);
/* Return to original directory */
rc = torture_change_dir(cwd);
assert_return_code(rc, errno);
/* Cleanup */
torture_rmdirs(tmp_dir);
SAFE_FREE(tmp_dir);
SAFE_FREE(cwd);
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -365,9 +515,12 @@ int torture_run_tests(void) {
#endif
cmocka_unit_test_setup_teardown(torture_path_expand_escape, setup, teardown),
cmocka_unit_test_setup_teardown(torture_path_expand_known_hosts, setup, teardown),
cmocka_unit_test_setup_teardown(torture_path_expand_percent, setup, teardown),
cmocka_unit_test(torture_timeout_elapsed),
cmocka_unit_test(torture_timeout_update),
cmocka_unit_test(torture_ssh_analyze_banner),
cmocka_unit_test(torture_ssh_dir_writeable),
cmocka_unit_test(torture_ssh_mkdirs),
};
ssh_init();

View File

@@ -571,6 +571,7 @@ static void torture_options_config_host(void **state) {
static void torture_options_config_match(void **state)
{
ssh_session session = *state;
char *localuser = NULL;
FILE *config = NULL;
int rv;
@@ -665,11 +666,16 @@ static void torture_options_config_match(void **state)
session->opts.port = 0;
/* The Match localuser keyword is ignored */
/* The Match localuser keyword */
torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match originalhost origin\n"
fputs("Match localuser ", config);
localuser = ssh_get_local_username();
assert_non_null(localuser);
fputs(localuser, config);
free(localuser);
fputs("\n"
"\tPort 33\n"
"Match all\n"
"\tPort 34\n",
@@ -678,7 +684,7 @@ static void torture_options_config_match(void **state)
rv = ssh_options_parse_config(session, "test_config");
assert_ssh_return_code(session, rv);
assert_int_equal(session->opts.port, 34);
assert_int_equal(session->opts.port, 33);
session->opts.port = 0;

View File

@@ -331,7 +331,7 @@ static void torture_pki_verify_mismatch(void **state)
assert_int_equal(import_sig->type, key->type);
assert_string_equal(import_sig->type_c, skey_attrs.sig_type_c);
rc = pki_signature_verify(session,
rc = ssh_pki_signature_verify(session,
import_sig,
pubkey,
INPUT,
@@ -374,7 +374,7 @@ static void torture_pki_verify_mismatch(void **state)
assert_non_null(verify_pubkey);
/* Should gracefully fail, but not crash */
rc = pki_signature_verify(session,
rc = ssh_pki_signature_verify(session,
sign,
verify_pubkey,
INPUT,
@@ -382,7 +382,7 @@ static void torture_pki_verify_mismatch(void **state)
assert_true(rc != SSH_OK);
/* Try the same with the imported signature */
rc = pki_signature_verify(session,
rc = ssh_pki_signature_verify(session,
import_sig,
verify_pubkey,
INPUT,
@@ -401,7 +401,7 @@ static void torture_pki_verify_mismatch(void **state)
assert_string_equal(new_sig->type_c, skey_attrs.sig_type_c);
/* The verification should not work */
rc = pki_signature_verify(session,
rc = ssh_pki_signature_verify(session,
new_sig,
verify_pubkey,
INPUT,

View File

@@ -168,6 +168,68 @@ static void torture_pki_dsa_import_privkey_base64(void **state)
SSH_KEY_FREE(key);
}
static void torture_pki_dsa_import_privkey_base64_comment(void **state)
{
int rc, file_str_len;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
const char *comment_str = "#this is line-comment\n#this is another\n";
const char *key_str = NULL;
char *file_str = NULL;
(void) state; /* unused */
key_str = torture_get_testkey(SSH_KEYTYPE_DSS, 0);
assert_non_null(key_str);
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str,
passphrase,
NULL,
NULL,
&key);
assert_true(rc == 0);
free(file_str);
SSH_KEY_FREE(key);
}
static void torture_pki_dsa_import_privkey_base64_whitespace(void **state)
{
int rc, file_str_len;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
const char *key_str = NULL;
char *file_str = NULL;
(void) state; /* unused */
key_str = torture_get_testkey(SSH_KEYTYPE_DSS, 0);
assert_non_null(key_str);
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str,
passphrase,
NULL,
NULL,
&key);
assert_true(rc == 0);
free(file_str);
SSH_KEY_FREE(key);
}
static int test_sign_verify_data(ssh_key key,
enum ssh_digest_e hash_type,
const unsigned char *input,
@@ -747,7 +809,7 @@ static void torture_pki_dsa_generate_key(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
@@ -761,7 +823,7 @@ static void torture_pki_dsa_generate_key(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
@@ -775,7 +837,7 @@ static void torture_pki_dsa_generate_key(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
@@ -806,7 +868,7 @@ static void torture_pki_dsa_cert_verify(void **state)
sign = pki_do_sign(privkey, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(privkey);
@@ -833,6 +895,12 @@ int torture_run_tests(void)
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
setup_dsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64_comment,
setup_dsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64_whitespace,
setup_dsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_dsa_import_privkey_base64,
setup_openssh_dsa_key,
teardown),

View File

@@ -241,6 +241,69 @@ static void torture_pki_ecdsa_import_privkey_base64(void **state)
SSH_KEY_FREE(key);
}
static void torture_pki_ecdsa_import_privkey_base64_comment(void **state)
{
int rc, file_str_len;
const char *comment_str = "#this is line-comment\n#this is another\n";
char *key_str = NULL, *file_str = NULL;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
(void) state; /* unused */
key_str = torture_pki_read_file(LIBSSH_ECDSA_TESTKEY);
assert_non_null(key_str);
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
assert_true(rc == 0);
assert_non_null(key);
rc = ssh_key_is_private(key);
assert_true(rc == 1);
free(key_str);
free(file_str);
SSH_KEY_FREE(key);
}
static void torture_pki_ecdsa_import_privkey_base64_whitespace(void **state)
{
int rc, file_str_len;
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
char *key_str = NULL, *file_str = NULL;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
(void) state; /* unused */
key_str = torture_pki_read_file(LIBSSH_ECDSA_TESTKEY);
assert_non_null(key_str);
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
assert_true(rc == 0);
assert_non_null(key);
rc = ssh_key_is_private(key);
assert_true(rc == 1);
free(key_str);
free(file_str);
SSH_KEY_FREE(key);
}
static void torture_pki_ecdsa_publickey_from_privatekey(void **state)
{
int rc;
@@ -483,7 +546,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ECDSA_P256);
@@ -505,7 +568,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ECDSA_P256);
@@ -526,7 +589,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA384);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ECDSA_P384);
@@ -548,7 +611,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA384);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ECDSA_P384);
@@ -569,7 +632,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA512);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ECDSA_P521);
@@ -591,7 +654,7 @@ static void torture_pki_generate_key_ecdsa(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA512);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ECDSA_P521);
@@ -633,7 +696,7 @@ static void torture_pki_ecdsa_cert_verify(void **state)
sign = pki_do_sign(privkey, INPUT, sizeof(INPUT), hash_type);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(privkey);
@@ -904,6 +967,24 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
setup_ecdsa_key_521,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
setup_ecdsa_key_256,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
setup_ecdsa_key_384,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_comment,
setup_ecdsa_key_521,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_whitespace,
setup_ecdsa_key_521,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_whitespace,
setup_ecdsa_key_521,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64_whitespace,
setup_ecdsa_key_521,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ecdsa_import_privkey_base64,
setup_openssh_ecdsa_key_256,
teardown),

View File

@@ -149,6 +149,84 @@ static void torture_pki_ed25519_import_privkey_base64(void **state)
}
static void torture_pki_ed25519_import_privkey_base64_comment(void **state)
{
int rc, file_str_len;
const char *comment_str = "#this is line-comment\n#this is another\n";
char *key_str = NULL, *file_str = NULL;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
enum ssh_keytypes_e type;
(void) state; /* unused */
key_str = torture_pki_read_file(LIBSSH_ED25519_TESTKEY);
assert_non_null(key_str);
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
assert_true(rc == 0);
assert_non_null(key);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ED25519);
rc = ssh_key_is_private(key);
assert_true(rc == 1);
rc = ssh_key_is_public(key);
assert_true(rc == 1);
free(key_str);
free(file_str);
SSH_KEY_FREE(key);
}
static void torture_pki_ed25519_import_privkey_base64_whitespace(void **state)
{
int rc, file_str_len;
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
char *key_str = NULL, *file_str = NULL;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
enum ssh_keytypes_e type;
(void) state; /* unused */
key_str = torture_pki_read_file(LIBSSH_ED25519_TESTKEY);
assert_non_null(key_str);
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
assert_true(rc == 0);
assert_non_null(key);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ED25519);
rc = ssh_key_is_private(key);
assert_true(rc == 1);
rc = ssh_key_is_public(key);
assert_true(rc == 1);
free(key_str);
free(file_str);
SSH_KEY_FREE(key);
}
static void torture_pki_ed25519_import_export_privkey_base64(void **state)
{
char *b64_key = NULL;
@@ -339,19 +417,30 @@ static void torture_pki_ed25519_generate_pubkey_from_privkey(void **state)
static void torture_pki_ed25519_generate_key(void **state)
{
int rc;
ssh_key key = NULL;
ssh_key key = NULL, pubkey = NULL;
ssh_signature sign = NULL;
enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN;
const char *type_char = NULL;
ssh_session session=ssh_new();
uint8_t *raw_sig_data = NULL;
(void) state;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(session);
rc = ssh_pki_generate(SSH_KEYTYPE_ED25519, 256, &key);
assert_true(rc == SSH_OK);
assert_non_null(key);
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
assert_int_equal(rc, SSH_OK);
assert_non_null(pubkey);
sign = pki_do_sign(key, HASH, 20, SSH_DIGEST_AUTO);
assert_non_null(sign);
rc = pki_signature_verify(session,sign,key,HASH,20);
rc = ssh_pki_signature_verify(session, sign, pubkey, HASH, 20);
assert_true(rc == SSH_OK);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_ED25519);
@@ -359,12 +448,19 @@ static void torture_pki_ed25519_generate_key(void **state)
assert_true(strcmp(type_char, "ssh-ed25519") == 0);
/* try an invalid signature */
(*sign->ed25519_sig)[3]^= 0xff;
rc = pki_signature_verify(session,sign,key,HASH,20);
#ifdef HAVE_OPENSSL_ED25519
raw_sig_data = ssh_string_data(sign->raw_sig);
#else
raw_sig_data = (uint8_t *)sign->ed25519_sig;
#endif
assert_non_null(raw_sig_data);
(raw_sig_data)[3]^= 0xff;
rc = ssh_pki_signature_verify(session, sign, pubkey, HASH, 20);
assert_true(rc == SSH_ERROR);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
SSH_KEY_FREE(pubkey);
ssh_free(session);
}
@@ -377,6 +473,13 @@ static void torture_pki_ed25519_cert_verify(void **state)
ssh_session session=ssh_new();
(void) state;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(session);
rc = ssh_pki_import_privkey_file(LIBSSH_ED25519_TESTKEY,
NULL,
NULL,
@@ -391,7 +494,7 @@ static void torture_pki_ed25519_cert_verify(void **state)
sign = pki_do_sign(privkey, HASH, 20, SSH_DIGEST_AUTO);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, cert, HASH, 20);
rc = ssh_pki_signature_verify(session, sign, cert, HASH, 20);
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(privkey);
@@ -517,10 +620,12 @@ static void torture_pki_ed25519_sign(void **state)
const char *keystring = NULL;
int rc;
(void)state;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
sig = ssh_signature_new();
assert_non_null(sig);
(void)state;
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0);
rc = ssh_pki_import_privkey_base64(keystring,
@@ -531,31 +636,157 @@ static void torture_pki_ed25519_sign(void **state)
assert_true(rc == SSH_OK);
assert_non_null(privkey);
sig->type = SSH_KEYTYPE_ED25519;
rc = pki_ed25519_sign(privkey, sig, HASH, sizeof(HASH));
assert_true(rc == SSH_OK);
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
assert_non_null(sig);
blob = pki_signature_to_blob(sig);
assert_non_null(blob);
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
assert_memory_equal(ssh_string_data(blob), ref_signature, sizeof(ref_signature));
/* ssh_print_hexa("signature", ssh_string_data(blob), ssh_string_len(blob)); */
assert_memory_equal(ssh_string_data(blob), ref_signature,
sizeof(ref_signature));
ssh_signature_free(sig);
SSH_KEY_FREE(privkey);
SSH_STRING_FREE(blob);
}
static void torture_pki_ed25519_sign_openssh_privkey_passphrase(void **state)
{
ssh_key privkey = NULL;
ssh_signature sig = NULL;
ssh_string blob = NULL;
const char *keystring = NULL;
int rc;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
(void)state;
keystring = torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 1);
rc = ssh_pki_import_privkey_base64(keystring,
torture_get_testkey_passphrase(),
NULL,
NULL,
&privkey);
assert_true(rc == SSH_OK);
assert_non_null(privkey);
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
assert_non_null(sig);
blob = pki_signature_to_blob(sig);
assert_non_null(blob);
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
assert_memory_equal(ssh_string_data(blob), ref_signature,
sizeof(ref_signature));
ssh_signature_free(sig);
SSH_KEY_FREE(privkey);
SSH_STRING_FREE(blob);
}
#ifdef HAVE_OPENSSL_ED25519
static void torture_pki_ed25519_sign_pkcs8_privkey(void **state)
{
ssh_key privkey = NULL;
ssh_signature sig = NULL;
ssh_string blob = NULL;
const char *keystring = NULL;
int rc;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
(void)state;
keystring = torture_get_testkey(SSH_KEYTYPE_ED25519, 0);
rc = ssh_pki_import_privkey_base64(keystring,
NULL,
NULL,
NULL,
&privkey);
assert_true(rc == SSH_OK);
assert_non_null(privkey);
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
assert_non_null(sig);
blob = pki_signature_to_blob(sig);
assert_non_null(blob);
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
assert_memory_equal(ssh_string_data(blob), ref_signature,
sizeof(ref_signature));
ssh_signature_free(sig);
SSH_KEY_FREE(privkey);
SSH_STRING_FREE(blob);
}
static void torture_pki_ed25519_sign_pkcs8_privkey_passphrase(void **state)
{
ssh_key privkey = NULL;
ssh_signature sig = NULL;
ssh_string blob = NULL;
const char *keystring = NULL;
int rc;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
(void)state;
keystring = torture_get_testkey(SSH_KEYTYPE_ED25519, 1);
rc = ssh_pki_import_privkey_base64(keystring,
torture_get_testkey_passphrase(),
NULL,
NULL,
&privkey);
assert_true(rc == SSH_OK);
assert_non_null(privkey);
sig = pki_do_sign(privkey, HASH, sizeof(HASH), SSH_DIGEST_AUTO);
assert_non_null(sig);
blob = pki_signature_to_blob(sig);
assert_non_null(blob);
assert_int_equal(ssh_string_len(blob), sizeof(ref_signature));
assert_memory_equal(ssh_string_data(blob), ref_signature,
sizeof(ref_signature));
ssh_signature_free(sig);
SSH_KEY_FREE(privkey);
SSH_STRING_FREE(blob);
}
#endif /* HAVE_OPENSSL_ED25519 */
static void torture_pki_ed25519_verify(void **state){
ssh_key pubkey = NULL;
ssh_signature sig = NULL;
ssh_session session = NULL;
ssh_string blob = ssh_string_new(ED25519_SIG_LEN);
char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1);
char *ptr = NULL;
uint8_t *raw_sig_data = NULL;
int rc;
(void) state;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
session = ssh_new();
assert_non_null(session);
/* remove trailing comment */
ptr = strchr(pkey_ptr, ' ');
if(ptr != NULL){
@@ -569,20 +800,32 @@ static void torture_pki_ed25519_verify(void **state){
sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO);
assert_non_null(sig);
rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH));
rc = ssh_pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH));
assert_true(rc == SSH_OK);
/* Alter signature and expect verification error */
#if defined(HAVE_OPENSSL_ED25519)
raw_sig_data = ssh_string_data(sig->raw_sig);
#else
raw_sig_data = (uint8_t *)sig->ed25519_sig;
#endif
assert_non_null(raw_sig_data);
(raw_sig_data)[3]^= 0xff;
rc = ssh_pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH));
assert_true(rc == SSH_ERROR);
ssh_signature_free(sig);
/* alter signature and expect false result */
SSH_KEY_FREE(pubkey);
SSH_STRING_FREE(blob);
free(pkey_ptr);
ssh_free(session);
}
static void torture_pki_ed25519_verify_bad(void **state){
ssh_key pubkey = NULL;
ssh_signature sig = NULL;
ssh_session session = NULL;
ssh_string blob = ssh_string_new(ED25519_SIG_LEN);
char *pkey_ptr = strdup(strchr(torture_get_testkey_pub(SSH_KEYTYPE_ED25519), ' ') + 1);
char *ptr = NULL;
@@ -590,6 +833,14 @@ static void torture_pki_ed25519_verify_bad(void **state){
int i;
(void) state;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
session = ssh_new();
assert_non_null(session);
/* remove trailing comment */
ptr = strchr(pkey_ptr, ' ');
if(ptr != NULL){
@@ -607,7 +858,7 @@ static void torture_pki_ed25519_verify_bad(void **state){
sig = pki_signature_from_blob(pubkey, blob, SSH_KEYTYPE_ED25519, SSH_DIGEST_AUTO);
assert_non_null(sig);
rc = pki_ed25519_verify(pubkey, sig, HASH, sizeof(HASH));
rc = ssh_pki_signature_verify(session, sig, pubkey, HASH, sizeof(HASH));
assert_true(rc == SSH_ERROR);
ssh_signature_free(sig);
@@ -615,6 +866,7 @@ static void torture_pki_ed25519_verify_bad(void **state){
SSH_KEY_FREE(pubkey);
SSH_STRING_FREE(blob);
free(pkey_ptr);
ssh_free(session);
}
static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state)
@@ -730,6 +982,12 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_privkey_base64,
setup_ed25519_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_privkey_base64_comment,
setup_ed25519_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_privkey_base64_whitespace,
setup_ed25519_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_ed25519_import_export_privkey_base64,
setup_ed25519_key,
teardown),
@@ -754,6 +1012,11 @@ int torture_run_tests(void) {
teardown),
cmocka_unit_test(torture_pki_ed25519_import_privkey_base64_passphrase),
cmocka_unit_test(torture_pki_ed25519_sign),
cmocka_unit_test(torture_pki_ed25519_sign_openssh_privkey_passphrase),
#ifdef HAVE_OPENSSL_ED25519
cmocka_unit_test(torture_pki_ed25519_sign_pkcs8_privkey),
cmocka_unit_test(torture_pki_ed25519_sign_pkcs8_privkey_passphrase),
#endif
cmocka_unit_test(torture_pki_ed25519_verify),
cmocka_unit_test(torture_pki_ed25519_verify_bad),
cmocka_unit_test(torture_pki_ed25519_privkey_dup),

View File

@@ -213,6 +213,82 @@ static void torture_pki_rsa_import_privkey_base64(void **state)
SSH_KEY_FREE(key);
}
static void torture_pki_rsa_import_privkey_base64_comment(void **state)
{
int rc, file_str_len;
const char *comment_str = "#this is line-comment\n#this is another\n";
char *key_str = NULL, *file_str = NULL;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
enum ssh_keytypes_e type;
(void) state; /* unused */
key_str = torture_pki_read_file(LIBSSH_RSA_TESTKEY);
assert_non_null(key_str);
file_str_len = strlen(comment_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", comment_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
assert_true(rc == 0);
assert_non_null(key);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_RSA);
rc = ssh_key_is_private(key);
assert_true(rc == 1);
rc = ssh_key_is_public(key);
assert_true(rc == 1);
free(key_str);
free(file_str);
SSH_KEY_FREE(key);
}
static void torture_pki_rsa_import_privkey_base64_whitespace(void **state)
{
int rc, file_str_len;
const char *whitespace_str = " \n\t\t\t\t\t\n\n\n\n\n";
char *key_str = NULL, *file_str = NULL;
ssh_key key = NULL;
const char *passphrase = torture_get_testkey_passphrase();
enum ssh_keytypes_e type;
(void) state; /* unused */
key_str = torture_pki_read_file(LIBSSH_RSA_TESTKEY);
assert_non_null(key_str);
file_str_len = strlen(whitespace_str) + strlen(key_str) + 1;
file_str = malloc(file_str_len);
assert_non_null(file_str);
rc = snprintf(file_str, file_str_len, "%s%s", whitespace_str, key_str);
assert_int_equal(rc, file_str_len - 1);
rc = ssh_pki_import_privkey_base64(file_str, passphrase, NULL, NULL, &key);
assert_true(rc == 0);
assert_non_null(key);
type = ssh_key_type(key);
assert_true(type == SSH_KEYTYPE_RSA);
rc = ssh_key_is_private(key);
assert_true(rc == 1);
rc = ssh_key_is_public(key);
assert_true(rc == 1);
free(key_str);
free(file_str);
SSH_KEY_FREE(key);
}
static void torture_pki_rsa_publickey_from_privatekey(void **state)
{
int rc;
@@ -468,21 +544,23 @@ static void torture_pki_rsa_generate_key(void **state)
ssh_session session=ssh_new();
(void) state;
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
assert_true(rc == SSH_OK);
assert_non_null(key);
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
assert_int_equal(rc, SSH_OK);
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
SSH_KEY_FREE(pubkey);
key = NULL;
pubkey = NULL;
if (!ssh_fips_mode()) {
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
assert_true(rc == SSH_OK);
assert_non_null(key);
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
assert_int_equal(rc, SSH_OK);
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
SSH_KEY_FREE(pubkey);
key = NULL;
pubkey = NULL;
}
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key);
assert_true(rc == SSH_OK);
@@ -492,7 +570,7 @@ static void torture_pki_rsa_generate_key(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
@@ -508,7 +586,7 @@ static void torture_pki_rsa_generate_key(void **state)
assert_non_null(pubkey);
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_true(rc == SSH_OK);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
@@ -547,9 +625,9 @@ static void torture_pki_rsa_sha2(void **state)
/* Sign using old SHA1 digest */
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA1);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_ssh_return_code(session, rc);
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
assert_ssh_return_code(session, rc);
ssh_signature_free(sign);
}
@@ -557,18 +635,18 @@ static void torture_pki_rsa_sha2(void **state)
/* Sign using new SHA256 digest */
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_ssh_return_code(session, rc);
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
assert_ssh_return_code(session, rc);
ssh_signature_free(sign);
/* Sign using rsa-sha2-512 algorithm */
sign = pki_do_sign(key, INPUT, sizeof(INPUT), SSH_DIGEST_SHA512);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, pubkey, INPUT, sizeof(INPUT));
assert_ssh_return_code(session, rc);
rc = pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
rc = ssh_pki_signature_verify(session, sign, cert, INPUT, sizeof(INPUT));
assert_ssh_return_code(session, rc);
ssh_signature_free(sign);
@@ -877,6 +955,12 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64_comment,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64_whitespace,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
setup_openssh_rsa_key,
teardown),

View File

@@ -571,23 +571,25 @@ static void *thread_pki_rsa_generate_key(void *threadid)
session = ssh_new();
assert_non_null(session);
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
assert_ssh_return_code(session, rc);
assert_non_null(key);
if (!ssh_fips_mode()) {
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 1024, &key);
assert_ssh_return_code(session, rc);
assert_non_null(key);
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
assert_int_equal(rc, SSH_OK);
assert_non_null(pubkey);
rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey);
assert_int_equal(rc, SSH_OK);
assert_non_null(pubkey);
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
assert_non_null(sign);
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
assert_ssh_return_code(session, rc);
rc = ssh_pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
assert_ssh_return_code(session, rc);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
SSH_KEY_FREE(pubkey);
ssh_signature_free(sign);
SSH_KEY_FREE(key);
SSH_KEY_FREE(pubkey);
}
rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key);
assert_ssh_return_code(session, rc);
@@ -600,7 +602,7 @@ static void *thread_pki_rsa_generate_key(void *threadid)
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
rc = ssh_pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
assert_ssh_return_code(session, rc);
ssh_signature_free(sign);
@@ -618,7 +620,7 @@ static void *thread_pki_rsa_generate_key(void *threadid)
sign = pki_do_sign(key, RSA_HASH, 20, SSH_DIGEST_SHA256);
assert_non_null(sign);
rc = pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
rc = ssh_pki_signature_verify(session, sign, pubkey, RSA_HASH, 20);
assert_true(rc == SSH_OK);
ssh_signature_free(sign);

View File

@@ -146,6 +146,126 @@ static void torture_tokens_sanity(UNUSED_PARAM(void **state))
tokenize_compare_expected(",", single_colon, 1);
}
static void torture_remove_duplicate(UNUSED_PARAM(void **state))
{
const char *simple[] = {"a,a,b,b,c,c",
"a,b,c,a,b,c",
"a,b,c,c,b,a",
"a,a,,b,b,,c,c",
",a,a,b,b,c,c",
"a,a,b,b,c,c,"};
const char *empty[] = {"",
",,,,,,,,,",
NULL};
char *ret = NULL;
int i;
for (i = 0; i < 6; i++) {
ret = ssh_remove_duplicates(simple[i]);
assert_non_null(ret);
assert_string_equal("a,b,c", ret);
printf("simple[%d] resulted in '%s'\n", i, ret);
SAFE_FREE(ret);
}
for (i = 0; i < 3; i++) {
ret = ssh_remove_duplicates(empty[i]);
if (ret != NULL) {
printf("empty[%d] resulted in '%s'\n", i, ret);
}
assert_null(ret);
}
ret = ssh_remove_duplicates("a");
assert_non_null(ret);
assert_string_equal("a", ret);
SAFE_FREE(ret);
}
static void torture_append_without_duplicate(UNUSED_PARAM(void **state))
{
const char *s1[] = {"a,a,b,b,c,c",
"a,b,c,a,b,c",
"a,b,c,c,b,a",
"a,a,,b,b,,c,c",
",a,a,b,b,c,c",
"a,a,b,b,c,c,"};
const char *s2[] = {"a,a,b,b,c,c,d,d",
"a,b,c,d,a,b,c,d",
"a,b,c,d,d,c,b,a",
"a,a,,b,b,,c,c,,d,d",
",a,a,b,b,c,c,d,d",
"a,a,b,b,c,c,d,d,",
"d"};
const char *empty[] = {"",
",,,,,,,,,",
NULL,
NULL};
char *ret = NULL;
int i, j;
ret = ssh_append_without_duplicates("a", "a");
assert_non_null(ret);
assert_string_equal("a", ret);
SAFE_FREE(ret);
ret = ssh_append_without_duplicates("a", "b");
assert_non_null(ret);
assert_string_equal("a,b", ret);
SAFE_FREE(ret);
ret = ssh_append_without_duplicates("a", NULL);
assert_non_null(ret);
assert_string_equal("a", ret);
SAFE_FREE(ret);
ret = ssh_append_without_duplicates(NULL, "b");
assert_non_null(ret);
assert_string_equal("b", ret);
SAFE_FREE(ret);
for (i = 0; i < 6; i++) {
for (j = 0; j < 7; j++) {
ret = ssh_append_without_duplicates(s1[i], s2[j]);
assert_non_null(ret);
printf("s1[%d] + s2[%d] resulted in '%s'\n", i, j, ret);
assert_string_equal("a,b,c,d", ret);
SAFE_FREE(ret);
}
}
for (i = 0; i < 6; i++) {
for (j = 0; j < 3; j++) {
ret = ssh_append_without_duplicates(s1[i], empty[j]);
assert_non_null(ret);
printf("s1[%d] + empty[%d] resulted in '%s'\n", i, j, ret);
assert_string_equal("a,b,c", ret);
SAFE_FREE(ret);
}
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 6; j++) {
ret = ssh_append_without_duplicates(empty[i], s1[j]);
assert_non_null(ret);
printf("empty[%d] + s1[%d] resulted in '%s'\n", i, j, ret);
assert_string_equal("a,b,c", ret);
SAFE_FREE(ret);
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
ret = ssh_append_without_duplicates(empty[i], empty[j]);
if (ret != NULL) {
printf("empty[%d] + empty[%d] resulted in '%s'\n", i, j, ret);
}
assert_null(ret);
}
}
}
int torture_run_tests(void)
{
int rc;
@@ -153,6 +273,8 @@ int torture_run_tests(void)
cmocka_unit_test(torture_tokens_sanity),
cmocka_unit_test(torture_find_matching),
cmocka_unit_test(torture_find_all_matching),
cmocka_unit_test(torture_remove_duplicate),
cmocka_unit_test(torture_append_without_duplicate),
};
ssh_init();