aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml21
-rw-r--r--CMakeLists.txt1
-rw-r--r--CONTRIBUTING.md (renamed from README.CodingStyle)195
-rw-r--r--ChangeLog10
-rw-r--r--ConfigureChecks.cmake17
-rw-r--r--DefineOptions.cmake1
-rw-r--r--README2
-rw-r--r--README.md3
-rw-r--r--SubmittingPatches118
-rw-r--r--examples/CMakeLists.txt2
-rw-r--r--examples/exec.c29
-rw-r--r--include/libssh/CMakeLists.txt6
-rw-r--r--include/libssh/libssh.h21
-rw-r--r--include/libssh/libssh_version.h.cmake41
-rw-r--r--include/libssh/options.h1
-rw-r--r--include/libssh/priv.h4
-rw-r--r--include/libssh/sftp.h18
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/auth.c49
-rw-r--r--src/buffer.c39
-rw-r--r--src/channels.c7
-rw-r--r--src/client.c143
-rw-r--r--src/config.c54
-rw-r--r--src/kex.c95
-rw-r--r--src/libssh.map1
-rw-r--r--src/misc.c26
-rw-r--r--src/options.c4
-rw-r--r--src/packet.c2
-rw-r--r--src/pki.c6
-rw-r--r--src/pki_crypto.c8
-rw-r--r--src/pki_gcrypt.c5
-rw-r--r--src/sftp.c2
-rw-r--r--src/sftpserver.c17
-rw-r--r--src/wrapper.c1
-rw-r--r--tests/CMakeLists.txt4
-rw-r--r--tests/authentication.c74
-rw-r--r--tests/client/torture_algorithms.c57
-rw-r--r--tests/client/torture_auth.c93
-rw-r--r--tests/client/torture_auth_pkcs11.c2
-rw-r--r--tests/client/torture_knownhosts.c8
-rw-r--r--tests/client/torture_scp.c84
-rw-r--r--tests/client/torture_session.c56
-rw-r--r--tests/connection.c31
-rw-r--r--tests/fuzz/README.md64
-rw-r--r--tests/keys/id_rsa_protected28
-rw-r--r--tests/keys/id_rsa_protected.pub1
-rwxr-xr-xtests/pkcs11/setup-softhsm-tokens.sh22
-rw-r--r--tests/pkd/CMakeLists.txt1
-rw-r--r--tests/pkd/pkd_daemon.c33
-rw-r--r--tests/pkd/pkd_hello.c65
-rw-r--r--tests/server/CMakeLists.txt2
-rw-r--r--tests/server/test_server/CMakeLists.txt1
-rw-r--r--tests/server/torture_server_algorithms.c364
-rw-r--r--tests/server/torture_server_config.c99
-rw-r--r--tests/sftp_stress/main.c174
-rw-r--r--tests/test_exec.c62
-rw-r--r--tests/test_pcap.c50
-rw-r--r--tests/test_ssh_bind_accept_fd.c147
-rw-r--r--tests/test_tunnel.c76
-rw-r--r--tests/tests.h8
-rw-r--r--tests/torture.c29
-rw-r--r--tests/torture.h5
-rw-r--r--tests/unittests/torture_config.c1238
-rw-r--r--tests/unittests/torture_pki_ecdsa_uri.c69
-rw-r--r--tests/unittests/torture_pki_rsa_uri.c2
65 files changed, 2427 insertions, 1473 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d72a67f2..1a887203 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -15,7 +15,7 @@ stages:
stage: build
variables:
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
- CMAKE_BUILD_OPTIONS: "-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"
+ CMAKE_BUILD_OPTIONS: "-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 -DWITH_DSA=ON"
CMAKE_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON"
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
before_script:
@@ -109,7 +109,7 @@ fedora/openssl_1.1.x/x86_64/fips:
-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
+ -DWITH_DEBUG_CRYPTO=ON -DWITH_DEBUG_PACKET=ON -DWITH_DEBUG_CALLTRACE=ON -DWITH_DSA=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON ..
script:
- cmake $CMAKE_OPTIONS .. &&
@@ -125,6 +125,7 @@ fedora/openssl_1.1.x/x86_64/minimal:
-DWITH_SERVER=OFF
-DWITH_ZLIB=OFF
-DWITH_PCAP=OFF
+ -DWITH_DSA=OFF
-DUNIT_TESTING=ON
-DCLIENT_TESTING=ON
-DWITH_GEX=OFF .. &&
@@ -188,7 +189,7 @@ fedora/libgcrypt/x86_64:
fedora/mbedtls/x86_64:
extends: .fedora
variables:
- CMAKE_ADDTIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON"
+ CMAKE_ADDTIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_DSA=OFF"
# Unit testing only, no client and pkd testing, because cwrap is not available
# for MinGW
@@ -260,7 +261,7 @@ fedora/csbuild/openssl_1.1.x:
script:
- csbuild
--build-dir=obj-csbuild
- --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)"
+ --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 -DWITH_DSA=ON @SRCDIR@ && make clean && make -j$(nproc)"
--git-commit-range $CI_COMMIT_RANGE
--color
--print-current --print-fixed
@@ -270,7 +271,7 @@ fedora/csbuild/libgcrypt:
script:
- csbuild
--build-dir=obj-csbuild
- --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 -DWITH_GCRYPT=ON @SRCDIR@ && 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 -DWITH_GCRYPT=ON -DWITH_DSA=ON @SRCDIR@ && make clean && make -j$(nproc)"
--git-commit-range $CI_COMMIT_RANGE
--color
--print-current --print-fixed
@@ -315,6 +316,7 @@ tumbleweed/openssl_1.1.x/x86/gcc:
-DWITH_SERVER=ON
-DWITH_ZLIB=ON
-DWITH_PCAP=ON
+ -DWITH_DSA=ON
-DUNIT_TESTING=ON ..
tumbleweed/openssl_1.1.x/x86_64/gcc7:
@@ -329,7 +331,7 @@ tumbleweed/openssl_1.1.x/x86/gcc7:
-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cross-m32.cmake
-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7
$CMAKE_DEFAULT_OPTIONS
- -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
+ -DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON -DWITH_DSA=ON
-DUNIT_TESTING=ON .. &&
make -j$(nproc) &&
ctest --output-on-failure
@@ -443,6 +445,11 @@ visualstudio/x86:
###############################################################################
# Coverity #
###############################################################################
+#
+# git push -o ci.variable="COVERITY_SCAN_TOKEN=XXXXXX" \
+# -o ci.variable="COVERITY_SCAN_PROJECT_NAME=XXXXXX" \
+# -o ci.variable="COVERITY_SCAN_EMAIL=XXXXXX" \
+# -f gitlab
coverity:
stage: analysis
@@ -475,4 +482,4 @@ coverity:
expire_in: 1 week
when: on_failure
paths:
- - cov-int/*.txt
+ - obj/cov-int/*.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2dc8118f..39bc0471 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -235,6 +235,7 @@ message(STATUS "Unit testing: ${UNIT_TESTING}")
message(STATUS "Client code testing: ${CLIENT_TESTING}")
message(STATUS "Blowfish cipher support: ${WITH_BLOWFISH_CIPHER}")
message(STATUS "PKCS #11 URI support: ${WITH_PKCS11_URI}")
+message(STATUS "DSA support: ${WITH_DSA}")
set(_SERVER_TESTING OFF)
if (WITH_SERVER)
set(_SERVER_TESTING ${SERVER_TESTING})
diff --git a/README.CodingStyle b/CONTRIBUTING.md
index 7489cce7..71c449b0 100644
--- a/README.CodingStyle
+++ b/CONTRIBUTING.md
@@ -1,9 +1,126 @@
-Coding conventions in the libssh tree
-======================================
+# How to contribute a patch to libssh
-===========
-Quick Start
-===========
+Please checkout the libssh source code using git.
+
+For contributions we prefer Merge Requests on Gitlab:
+
+https://gitlab.com/libssh/libssh-mirror/
+
+This way you get contintious integration which runs the complete libssh
+testsuite for you.
+
+For larger code changes, breaking the changes up into a set of simple
+patches, each of which does a single thing, are much easier to review.
+Patch sets like that will most likely have an easier time being merged
+into the libssh code than large single patches that make lots of
+changes in one large diff.
+
+Also bugfixes and new features should be covered by tests. We use the cmocka
+and cwrap framework for our testing and you can simply run it locally by
+calling `make test`.
+
+## Ownership of the contributed code
+
+libssh is a project with distributed copyright ownership, which means
+we prefer the copyright on parts of libssh to be held by individuals
+rather than corporations if possible. There are historical legal
+reasons for this, but one of the best ways to explain it is that it's
+much easier to work with individuals who have ownership than corporate
+legal departments if we ever need to make reasonable compromises with
+people using and working with libssh.
+
+We track the ownership of every part of libssh via https://git.libssh.org,
+our source code control system, so we know the provenance of every piece
+of code that is committed to libssh.
+
+So if possible, if you're doing libssh changes on behalf of a company
+who normally owns all the work you do please get them to assign
+personal copyright ownership of your changes to you as an individual,
+that makes things very easy for us to work with and avoids bringing
+corporate legal departments into the picture.
+
+If you can't do this we can still accept patches from you owned by
+your employer under a standard employment contract with corporate
+copyright ownership. It just requires a simple set-up process first.
+
+We use a process very similar to the way things are done in the Linux
+Kernel community, so it should be very easy to get a sign off from
+your corporate legal department. The only changes we've made are to
+accommodate the license we use, which is LGPLv2 (or later) whereas the
+Linux kernel uses GPLv2.
+
+The process is called signing.
+
+## How to sign your work
+
+Once you have permission to contribute to libssh from your employer, simply
+email a copy of the following text from your corporate email address to:
+
+contributing@libssh.org
+
+
+```
+libssh Developer's Certificate of Origin. Version 1.0
+
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the appropriate
+ version of the GNU General Public License; or
+
+(b) The contribution is based upon previous work that, to the best of
+ my knowledge, is covered under an appropriate open source license
+ and I have the right under that license to submit that work with
+ modifications, whether created in whole or in part by me, under
+ the GNU General Public License, in the appropriate version; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a) or (b) and I have not modified it.
+
+(d) I understand and agree that this project and the contribution are
+ public and that a record of the contribution (including all
+ metadata and personal information I submit with it, including my
+ sign-off) is maintained indefinitely and may be redistributed
+ consistent with the libssh Team's policies and the requirements of
+ the GNU GPL where they are relevant.
+
+(e) I am granting this work to this project 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 the option of the project) any later version.
+
+ https://www.gnu.org/licenses/lgpl-2.1.html
+```
+
+We will maintain a copy of that email as a record that you have the
+rights to contribute code to libssh under the required licenses whilst
+working for the company where the email came from.
+
+Then when sending in a patch via the normal mechanisms described
+above, add a line that states:
+
+ Signed-off-by: Random J Developer <random@developer.example.org>
+
+using your real name and the email address you sent the original email
+you used to send the libssh Developer's Certificate of Origin to us
+(sorry, no pseudonyms or anonymous contributions.)
+
+That's it! Such code can then quite happily contain changes that have
+copyright messages such as:
+
+ (c) Example Corporation.
+
+and can be merged into the libssh codebase in the same way as patches
+from any other individual. You don't need to send in a copy of the
+libssh Developer's Certificate of Origin for each patch, or inside each
+patch. Just the sign-off message is all that is required once we've
+received the initial email.
+
+
+# Coding conventions in the libssh tree
+
+## Quick Start
Coding style guidelines are about reducing the number of unnecessary
reformatting patches and making things easier for developers to work together.
@@ -36,31 +153,28 @@ are the highlights.
have a copy of "The C Programming Language" anyways right?
-=============
-Editor Hints
-=============
+## Editor Hints
+
+### Emacs
-Emacs
-------
Add the follow to your $HOME/.emacs file:
- (add-hook 'c-mode-hook
- (lambda ()
- (c-set-style "linux")
- (c-toggle-auto-state)))
+ (add-hook 'c-mode-hook
+ (lambda ()
+ (c-set-style "linux")
+ (c-toggle-auto-state)))
-Vim
-----
+## Neovim/VIM
For the basic vi editor included with all variants of \*nix, add the
-following to $HOME/.vimrc:
+following to ~/.config/nvim/init.rc or ~/.vimrc:
set ts=4 sw=4 et cindent
You can use the Vim gitmodline plugin to store this in the git config:
- https://git.cryptomilk.org/projects/vim-gitmodeline.git/
+https://git.cryptomilk.org/projects/vim-gitmodeline.git/
For Vim, the following settings in $HOME/.vimrc will also deal with
displaying trailing whitespace:
@@ -81,12 +195,9 @@ displaying trailing whitespace:
autocmd BufNewFile,BufRead *.c,*.h exec 'match Todo /\%>' . &textwidth . 'v.\+/'
-==========================
-FAQ & Statement Reference
-==========================
+## FAQ & Statement Reference
-Comments
----------
+### Comments
Comments should always use the standard C syntax. C++ style comments are not
currently allowed.
@@ -163,8 +274,7 @@ This is bad:
* This is a multi line comment,
* with some more words...*/
-Indention & Whitespace & 80 columns
-------------------------------------
+### Indention & Whitespace & 80 columns
To avoid confusion, indentations have to be 4 spaces. Do not use tabs!. When
wrapping parameters for function calls, align the parameter list with the first
@@ -180,8 +290,7 @@ splitting. Never split a line before columns 70 - 79 unless you
have a really good reason. Be smart about formatting.
-If, switch, & Code blocks
---------------------------
+### If, switch, & Code blocks
Always follow an 'if' keyword with a space but don't include additional
spaces following or preceding the parentheses in the conditional.
@@ -207,7 +316,7 @@ invoking functions.
Braces for code blocks used by for, if, switch, while, do..while, etc. should
begin on the same line as the statement keyword and end on a line of their own.
You should always include braces, even if the block only contains one
-statement. NOTE: Functions are different and the beginning left brace should
+statement. **NOTE**: Functions are different and the beginning left brace should
be located in the first column on the next line.
If the beginning statement has to be broken across lines due to length, the
@@ -254,8 +363,7 @@ Bad examples:
print("I should be in braces.\n");
-Goto
------
+### Goto
While many people have been academically taught that "goto"s are fundamentally
evil, they can greatly enhance readability and reduce memory leaks when used as
@@ -287,14 +395,13 @@ Good Examples:
return rc;
}
-Initialize pointers
--------------------
+### Initialize pointers
-All pointer variables MUST be initialized to NULL. History has
+All pointer variables **MUST** be initialized to `NULL`. History has
demonstrated that uninitialized pointer variables have lead to various
bugs and security issues.
-Pointers MUST be initialized even if the assignment directly follows
+Pointers **MUST** be initialized even if the assignment directly follows
the declaration, like pointer2 in the example below, because the
instructions sequence may change over time.
@@ -309,15 +416,13 @@ Good Example:
pointer1 = some_func1();
-Typedefs
----------
+### Typedefs
-libssh tries to avoid "typedef struct { .. } x_t;" so we do always try to use
-"struct x { .. };". We know there are still such typedefs in the code, but for
+libssh tries to avoid `typedef struct { .. } x_t;` so we do always try to use
+`struct x { .. };`. We know there are still such typedefs in the code, but for
new code, please don't do that anymore.
-Make use of helper variables
------------------------------
+### Make use of helper variables
Please try to avoid passing function calls as function parameters in new code.
This makes the code much easier to read and it's also easier to use the "step"
@@ -367,9 +472,13 @@ an iterator style:
But in general, please try to avoid this pattern.
-Control-Flow changing macros
------------------------------
+### Control-Flow changing macros
-Macros like STATUS_NOT_OK_RETURN that change control flow (return/goto/etc)
+Macros like `STATUS_NOT_OK_RETURN` that change control flow (return/goto/etc)
from within the macro are considered bad, because they look like function calls
that never change control flow. Please do not introduce them.
+
+
+Have fun and happy libssh hacking!
+
+The libssh Team
diff --git a/ChangeLog b/ChangeLog
index 91c3d0e5..8bc15d9a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -362,14 +362,6 @@ version 0.3.1 (released 2009-07-14)
* Fixed a possible crash bug.
* Fixed build warnings.
* Fixed cmake on BSD.
-version 0.3.1 (released 2009-07-14)
- * Added return code SSH_SERVER_FILE_NOT_FOUND.
- * Fixed compilation of SSHv1.
- * Fixed several memory leaks.
- * Fixed possible infinite loops.
- * Fixed a possible crash bug.
- * Fixed build warnings.
- * Fixed cmake on BSD.
version 0.3 (released 2009-05-21)
* Added support for ssh-agent authentication.
@@ -411,7 +403,7 @@ version 0.2 (released 2007-11-29)
version 0.11-dev
* Server implementation development.
* Small bug corrected when connecting to sun ssh servers.
- * Channel wierdness corrected (writing huge data packets)
+ * Channel weirdness corrected (writing huge data packets)
* Channel_read_nonblocking added
* Channel bug where stderr wasn't correctly read fixed.
* Added sftp_file_set_nonblocking(), which is nonblocking SFTP IO
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index b17b6c77..c62f4b92 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -185,9 +185,11 @@ if (NOT WITH_GCRYPT AND NOT WITH_MBEDTLS)
endif (HAVE_OPENSSL_ECC)
endif ()
-if (NOT WITH_MBEDTLS)
- set(HAVE_DSA 1)
-endif (NOT WITH_MBEDTLS)
+if (WITH_DSA)
+ if (NOT WITH_MBEDTLS)
+ set(HAVE_DSA 1)
+ endif (NOT WITH_MBEDTLS)
+endif()
# FUNCTIONS
@@ -480,12 +482,19 @@ if (WITH_PKCS11_URI)
message(FATAL_ERROR "PKCS #11 is not supported for gcrypt.")
set(WITH_PKCS11_URI 0)
endif()
- if (WITH_WITH_MBEDTLS)
+ if (WITH_MBEDTLS)
message(FATAL_ERROR "PKCS #11 is not supported for mbedcrypto")
set(WITH_PKCS11_URI 0)
endif()
endif()
+if (WITH_MBEDTLS)
+ if (WITH_DSA)
+ message(FATAL_ERROR "DSA is not supported with mbedTLS crypto")
+ set(HAVE_DSA 0)
+ endif()
+endif()
+
# ENDIAN
if (NOT WIN32)
test_big_endian(WORDS_BIGENDIAN)
diff --git a/DefineOptions.cmake b/DefineOptions.cmake
index 85a30376..068db988 100644
--- a/DefineOptions.cmake
+++ b/DefineOptions.cmake
@@ -5,6 +5,7 @@ option(WITH_SERVER "Build with SSH server support" ON)
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)
+option(WITH_DSA "Build with DSA" OFF)
option(WITH_GCRYPT "Compile against libgcrypt" OFF)
option(WITH_MBEDTLS "Compile against libmbedtls" OFF)
option(WITH_BLOWFISH_CIPHER "Compile with blowfish support" OFF)
diff --git a/README b/README
index 44100e7c..09a7e569 100644
--- a/README
+++ b/README
@@ -36,7 +36,7 @@ https://www.libssh.org
4* Contributing
-_-_-_-_-_-_-_-_-_
-Please read the file 'SubmittingPatches' next to this README file. It explains
+Please read the file 'CONTRIBUTING.md' next to this README file. It explains
our copyright policy and how you should send patches for upstream inclusion.
Have fun and happy libssh hacking!
diff --git a/README.md b/README.md
index 450b67ca..cd6b9eaa 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
[![pipeline status](https://gitlab.com/libssh/libssh-mirror/badges/master/pipeline.svg)](https://gitlab.com/libssh/libssh-mirror/commits/master)
+[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libssh.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:libssh)
```
_ _ _ _
@@ -36,7 +37,7 @@ https://www.libssh.org
# Contributing
-Please read the file 'SubmittingPatches' next to this README file. It explains
+Please read the file 'CONTRIBUTING.md' next to this README file. It explains
our copyright policy and how you should send patches for upstream inclusion.
Have fun and happy libssh hacking!
diff --git a/SubmittingPatches b/SubmittingPatches
deleted file mode 100644
index d01e3b6b..00000000
--- a/SubmittingPatches
+++ /dev/null
@@ -1,118 +0,0 @@
-How to contribute a patch to libssh
-====================================
-
-Please checkout the libssh source code using git. Change the code and then
-use "git format-patch" to create a patch. The patch should be signed (see
-below) and send it to libssh@libssh.org, or attach it to a bug report at
-https://bugs.libssh.org/
-
-For larger code changes, breaking the changes up into a set of simple
-patches, each of which does a single thing, are much easier to review.
-Patch sets like that will most likely have an easier time being merged
-into the libssh code than large single patches that make lots of
-changes in one large diff.
-
-Ownership of the contributed code
-==================================
-
-libssh is a project with distributed copyright ownership, which means
-we prefer the copyright on parts of libssh to be held by individuals
-rather than corporations if possible. There are historical legal
-reasons for this, but one of the best ways to explain it is that it's
-much easier to work with individuals who have ownership than corporate
-legal departments if we ever need to make reasonable compromises with
-people using and working with libssh.
-
-We track the ownership of every part of libssh via https://git.libssh.org,
-our source code control system, so we know the provenance of every piece
-of code that is committed to libssh.
-
-So if possible, if you're doing libssh changes on behalf of a company
-who normally owns all the work you do please get them to assign
-personal copyright ownership of your changes to you as an individual,
-that makes things very easy for us to work with and avoids bringing
-corporate legal departments into the picture.
-
-If you can't do this we can still accept patches from you owned by
-your employer under a standard employment contract with corporate
-copyright ownership. It just requires a simple set-up process first.
-
-We use a process very similar to the way things are done in the Linux
-Kernel community, so it should be very easy to get a sign off from
-your corporate legal department. The only changes we've made are to
-accommodate the license we use, which is LGPLv2 (or later) whereas the
-Linux kernel uses GPLv2.
-
-The process is called signing.
-
-How to sign your work
-----------------------
-
-Once you have permission to contribute to libssh from your employer, simply
-email a copy of the following text from your corporate email address to:
-
-contributing@libssh.org
-
-
-
-libssh Developer's Certificate of Origin. Version 1.0
-
-
-By making a contribution to this project, I certify that:
-
-(a) The contribution was created in whole or in part by me and I
- have the right to submit it under the appropriate
- version of the GNU General Public License; or
-
-(b) The contribution is based upon previous work that, to the best of
- my knowledge, is covered under an appropriate open source license
- and I have the right under that license to submit that work with
- modifications, whether created in whole or in part by me, under
- the GNU General Public License, in the appropriate version; or
-
-(c) The contribution was provided directly to me by some other
- person who certified (a) or (b) and I have not modified it.
-
-(d) I understand and agree that this project and the contribution are
- public and that a record of the contribution (including all
- metadata and personal information I submit with it, including my
- sign-off) is maintained indefinitely and may be redistributed
- consistent with the libssh Team's policies and the requirements of
- the GNU GPL where they are relevant.
-
-(e) I am granting this work to this project 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 the option of the project) any later version.
-
- https://www.gnu.org/licenses/lgpl-2.1.html
-
-
-We will maintain a copy of that email as a record that you have the
-rights to contribute code to libssh under the required licenses whilst
-working for the company where the email came from.
-
-Then when sending in a patch via the normal mechanisms described
-above, add a line that states:
-
- Signed-off-by: Random J Developer <random@developer.example.org>
-
-using your real name and the email address you sent the original email
-you used to send the libssh Developer's Certificate of Origin to us
-(sorry, no pseudonyms or anonymous contributions.)
-
-That's it! Such code can then quite happily contain changes that have
-copyright messages such as:
-
- (c) Example Corporation.
-
-and can be merged into the libssh codebase in the same way as patches
-from any other individual. You don't need to send in a copy of the
-libssh Developer's Certificate of Origin for each patch, or inside each
-patch. Just the sign-off message is all that is required once we've
-received the initial email.
-
-Have fun and happy libssh hacking !
-
-The libssh Team
-
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index b3b6b358..4e09083a 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -6,7 +6,7 @@ set(examples_SRCS
connect_ssh.c
)
-include_directories(${libssh_BINARY_DIR})
+include_directories(${libssh_BINARY_DIR}/include ${libssh_BINARY_DIR})
if (ARGP_INCLUDE_DIR)
include_directories(${ARGP_INCLUDE_DIR})
diff --git a/examples/exec.c b/examples/exec.c
index 4d5e0c1a..7200ddef 100644
--- a/examples/exec.c
+++ b/examples/exec.c
@@ -8,7 +8,7 @@ int main(void) {
ssh_session session;
ssh_channel channel;
char buffer[256];
- int nbytes;
+ int rbytes, wbytes, total = 0;
int rc;
session = connect_ssh("localhost", NULL, 0);
@@ -35,15 +35,30 @@ int main(void) {
goto failed;
}
- nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
- while (nbytes > 0) {
- if (fwrite(buffer, 1, nbytes, stdout) != (unsigned int) nbytes) {
+ rbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
+ if (rbytes <= 0) {
+ goto failed;
+ }
+
+ do {
+ wbytes = fwrite(buffer + total, 1, rbytes, stdout);
+ if (wbytes <= 0) {
goto failed;
}
- nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
- }
- if (nbytes < 0) {
+ total += wbytes;
+
+ /* When it was not possible to write the whole buffer to stdout */
+ if (wbytes < rbytes) {
+ rbytes -= wbytes;
+ continue;
+ }
+
+ rbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
+ total = 0;
+ } while (rbytes > 0);
+
+ if (rbytes < 0) {
goto failed;
}
diff --git a/include/libssh/CMakeLists.txt b/include/libssh/CMakeLists.txt
index acc966e3..83e7b9f8 100644
--- a/include/libssh/CMakeLists.txt
+++ b/include/libssh/CMakeLists.txt
@@ -31,3 +31,9 @@ install(
headers
)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libssh_version.h.cmake
+ ${libssh_BINARY_DIR}/include/libssh/libssh_version.h
+ @ONLY)
+install(FILES ${libssh_BINARY_DIR}/include/libssh/libssh_version.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${APPLICATION_NAME}
+ COMPONENT headers)
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 7b96541a..d8b35950 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -21,6 +21,8 @@
#ifndef _LIBSSH_H
#define _LIBSSH_H
+#include <libssh/libssh_version.h>
+
#if defined _WIN32 || defined __CYGWIN__
#ifdef LIBSSH_STATIC
#define LIBSSH_API
@@ -71,23 +73,6 @@
#define SSH_STRINGIFY(s) SSH_TOSTRING(s)
#define SSH_TOSTRING(s) #s
-/* libssh version macros */
-#define SSH_VERSION_INT(a, b, c) ((a) << 16 | (b) << 8 | (c))
-#define SSH_VERSION_DOT(a, b, c) a ##.## b ##.## c
-#define SSH_VERSION(a, b, c) SSH_VERSION_DOT(a, b, c)
-
-/* libssh version */
-#define LIBSSH_VERSION_MAJOR 0
-#define LIBSSH_VERSION_MINOR 8
-#define LIBSSH_VERSION_MICRO 90
-
-#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
- LIBSSH_VERSION_MINOR, \
- LIBSSH_VERSION_MICRO)
-#define LIBSSH_VERSION SSH_VERSION(LIBSSH_VERSION_MAJOR, \
- LIBSSH_VERSION_MINOR, \
- LIBSSH_VERSION_MICRO)
-
/* GCC have printf type attribute check. */
#ifdef __GNUC__
#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
@@ -772,6 +757,8 @@ LIBSSH_API int ssh_userauth_publickey(ssh_session session,
LIBSSH_API int ssh_userauth_agent(ssh_session session,
const char *username);
#endif
+LIBSSH_API int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
+ char** value);
LIBSSH_API int ssh_userauth_publickey_auto(ssh_session session,
const char *username,
const char *passphrase);
diff --git a/include/libssh/libssh_version.h.cmake b/include/libssh/libssh_version.h.cmake
new file mode 100644
index 00000000..464fa14d
--- /dev/null
+++ b/include/libssh/libssh_version.h.cmake
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2020 by Heiko Thiery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _LIBSSH_VERSION_H
+#define _LIBSSH_VERSION_H
+
+/* libssh version macros */
+#define SSH_VERSION_INT(a, b, c) ((a) << 16 | (b) << 8 | (c))
+#define SSH_VERSION_DOT(a, b, c) a ##.## b ##.## c
+#define SSH_VERSION(a, b, c) SSH_VERSION_DOT(a, b, c)
+
+/* libssh version */
+#define LIBSSH_VERSION_MAJOR @libssh_VERSION_MAJOR@
+#define LIBSSH_VERSION_MINOR @libssh_VERSION_MINOR@
+#define LIBSSH_VERSION_MICRO @libssh_VERSION_PATCH@
+
+#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
+ LIBSSH_VERSION_MINOR, \
+ LIBSSH_VERSION_MICRO)
+#define LIBSSH_VERSION SSH_VERSION(LIBSSH_VERSION_MAJOR, \
+ LIBSSH_VERSION_MINOR, \
+ LIBSSH_VERSION_MICRO)
+
+#endif /* _LIBSSH_VERSION_H */
diff --git a/include/libssh/options.h b/include/libssh/options.h
index 5b1cb9f0..e8dc6c69 100644
--- a/include/libssh/options.h
+++ b/include/libssh/options.h
@@ -22,6 +22,7 @@
#define _OPTIONS_H
int ssh_config_parse_file(ssh_session session, const char *filename);
+int ssh_config_parse_string(ssh_session session, const char *input);
int ssh_options_set_algo(ssh_session session,
enum ssh_kex_types_e algo,
const char *list);
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
index 3cf2004e..b18ece4c 100644
--- a/include/libssh/priv.h
+++ b/include/libssh/priv.h
@@ -167,7 +167,7 @@ int gettimeofday(struct timeval *__p, void *__t);
#include "libssh/callbacks.h"
/* some constants */
-#ifndef MAX_PACKAT_LEN
+#ifndef MAX_PACKET_LEN
#define MAX_PACKET_LEN 262144
#endif
#ifndef ERROR_BUFFERLEN
@@ -341,7 +341,7 @@ void explicit_bzero(void *s, size_t n);
#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
/**
- * Get the argument cound of variadic arguments
+ * Get the argument count of variadic arguments
*/
/*
* Since MSVC 2010 there is a bug in passing __VA_ARGS__ to subsequent
diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h
index 8c14b21d..c855df8a 100644
--- a/include/libssh/sftp.h
+++ b/include/libssh/sftp.h
@@ -258,7 +258,7 @@ LIBSSH_API int sftp_init(sftp_session sftp);
* @param sftp The sftp session where the error is saved.
*
* @return The saved error (see server responses), < 0 if an error
- * in the function occured.
+ * in the function occurred.
*
* @see Server responses
*/
@@ -413,7 +413,7 @@ LIBSSH_API void sftp_attributes_free(sftp_attributes file);
*
* @param dir The sftp directory handle to close.
*
- * @return Returns SSH_NO_ERROR or SSH_ERROR if an error occured.
+ * @return Returns SSH_NO_ERROR or SSH_ERROR if an error occurred.
*/
LIBSSH_API int sftp_closedir(sftp_dir dir);
@@ -422,7 +422,7 @@ LIBSSH_API int sftp_closedir(sftp_dir dir);
*
* @param file The open sftp file handle to close.
*
- * @return Returns SSH_NO_ERROR or SSH_ERROR if an error occured.
+ * @return Returns SSH_NO_ERROR or SSH_ERROR if an error occurred.
*
* @see sftp_open()
*/
@@ -478,7 +478,7 @@ LIBSSH_API void sftp_file_set_blocking(sftp_file handle);
*
* @param file The opened sftp file handle to be read from.
*
- * @param buf Pointer to buffer to recieve read data.
+ * @param buf Pointer to buffer to receive read data.
*
* @param count Size of the buffer in bytes.
*
@@ -527,7 +527,7 @@ LIBSSH_API int sftp_async_read_begin(sftp_file file, uint32_t len);
*
* @param file The opened sftp file handle to be read from.
*
- * @param data Pointer to buffer to recieve read data.
+ * @param data Pointer to buffer to receive read data.
*
* @param len Size of the buffer in bytes. It should be bigger or
* equal to the length parameter of the
@@ -537,7 +537,7 @@ LIBSSH_API int sftp_async_read_begin(sftp_file file, uint32_t len);
* function.
*
* @return Number of bytes read, 0 on EOF, SSH_ERROR if an error
- * occured, SSH_AGAIN if the file is opened in nonblocking
+ * occurred, SSH_AGAIN if the file is opened in nonblocking
* mode and the request hasn't been executed yet.
*
* @warning A call to this function with an invalid identifier
@@ -632,7 +632,7 @@ LIBSSH_API void sftp_rewind(sftp_file file);
LIBSSH_API int sftp_unlink(sftp_session sftp, const char *file);
/**
- * @brief Remove a directoy.
+ * @brief Remove a directory.
*
* @param sftp The sftp session handle.
*
@@ -806,7 +806,7 @@ LIBSSH_API void sftp_statvfs_free(sftp_statvfs_t statvfs_o);
/**
* @brief Synchronize a file's in-core state with storage device
*
- * This calls the "fsync@openssh.com" extention. You should check if the
+ * This calls the "fsync@openssh.com" extension. You should check if the
* extensions is supported using:
*
* @code
@@ -854,7 +854,7 @@ LIBSSH_API int sftp_server_version(sftp_session sftp);
LIBSSH_API sftp_session sftp_server_new(ssh_session session, ssh_channel chan);
/**
- * @brief Intialize the sftp server.
+ * @brief Initialize the sftp server.
*
* @param sftp The sftp session to init.
*
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a5129ba4..621f8b35 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LIBSSH_PUBLIC_INCLUDE_DIRS ${libssh_SOURCE_DIR}/include)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
+ ${libssh_BINARY_DIR}/include
${libssh_BINARY_DIR}
)
@@ -378,6 +379,7 @@ endif (WITH_VISIBILITY_HIDDEN)
if (MINGW)
set_target_properties(ssh PROPERTIES LINK_FLAGS "-Wl,--enable-stdcall-fixup")
+ set_target_properties(ssh PROPERTIES COMPILE_FLAGS "-D_POSIX_SOURCE")
endif ()
diff --git a/src/auth.c b/src/auth.c
index 89272290..fcf39b7a 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -976,6 +976,55 @@ struct ssh_auth_auto_state_struct {
};
/**
+ * @brief Get the identity that is currenly being processed by
+ * ssh_userauth_publickey_auto()
+ *
+ * This is meant to be used by a callback that happens as part of the
+ * execution of ssh_userauth_publickey_auto(). The auth_function
+ * callback might want to know which key a passphrase is needed for,
+ * for example.
+ *
+ * @param[in] session The SSH session.
+ *
+ * @param[out] value The value to get into. As a char**, space will be
+ * allocated by the function for the value, it is
+ * your responsibility to free the memory using
+ * ssh_string_free_char().
+ *
+ * @return SSH_OK on success, SSH_ERROR on error.
+ */
+int ssh_userauth_publickey_auto_get_current_identity(ssh_session session,
+ char** value)
+{
+ const char *id = NULL;
+
+ if (session == NULL) {
+ return SSH_ERROR;
+ }
+
+ if (value == NULL) {
+ ssh_set_error_invalid(session);
+ return SSH_ERROR;
+ }
+
+ if (session->auth.auto_state != NULL && session->auth.auto_state->it != NULL) {
+ id = session->auth.auto_state->it->data;
+ }
+
+ if (id == NULL) {
+ return SSH_ERROR;
+ }
+
+ *value = strdup(id);
+ if (*value == NULL) {
+ ssh_set_error_oom(session);
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
+}
+
+/**
* @brief Tries to automatically authenticate with public key and "none"
*
* It may fail, for instance it doesn't ask for a password and uses a default
diff --git a/src/buffer.c b/src/buffer.c
index a2e6246a..ce12f491 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -299,28 +299,33 @@ int ssh_buffer_reinit(struct ssh_buffer_struct *buffer)
*/
int ssh_buffer_add_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len)
{
- buffer_verify(buffer);
+ if (buffer == NULL) {
+ return -1;
+ }
- if (data == NULL) {
- return -1;
- }
+ buffer_verify(buffer);
- if (buffer->used + len < len) {
- return -1;
- }
+ if (data == NULL) {
+ return -1;
+ }
- if (buffer->allocated < (buffer->used + len)) {
- if(buffer->pos > 0)
- buffer_shift(buffer);
- if (realloc_buffer(buffer, buffer->used + len) < 0) {
- return -1;
+ if (buffer->used + len < len) {
+ return -1;
}
- }
- memcpy(buffer->data+buffer->used, data, len);
- buffer->used+=len;
- buffer_verify(buffer);
- return 0;
+ if (buffer->allocated < (buffer->used + len)) {
+ if (buffer->pos > 0) {
+ buffer_shift(buffer);
+ }
+ if (realloc_buffer(buffer, buffer->used + len) < 0) {
+ return -1;
+ }
+ }
+
+ memcpy(buffer->data + buffer->used, data, len);
+ buffer->used += len;
+ buffer_verify(buffer);
+ return 0;
}
/**
diff --git a/src/channels.c b/src/channels.c
index 9fe309d0..607bd568 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -2932,15 +2932,16 @@ int ssh_channel_read_timeout(ssh_channel channel,
if (session->session_state == SSH_SESSION_STATE_ERROR) {
return SSH_ERROR;
}
+ /* If the server closed the channel properly, there is nothing to do */
+ if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) {
+ return 0;
+ }
if (channel->state == SSH_CHANNEL_STATE_CLOSED) {
ssh_set_error(session,
SSH_FATAL,
"Remote channel is closed.");
return SSH_ERROR;
}
- if (channel->remote_eof && ssh_buffer_get_len(stdbuf) == 0) {
- return 0;
- }
len = ssh_buffer_get_len(stdbuf);
/* Read count bytes if len is greater, everything otherwise */
len = (len > count ? count : len);
diff --git a/src/client.c b/src/client.c
index 4610b787..3984b3f4 100644
--- a/src/client.c
+++ b/src/client.c
@@ -689,84 +689,89 @@ int ssh_get_openssh_version(ssh_session session) {
*
* @param[in] session The SSH session to use.
*/
-void ssh_disconnect(ssh_session session) {
- struct ssh_iterator *it;
- int rc;
+void
+ssh_disconnect(ssh_session session)
+{
+ struct ssh_iterator *it;
+ int rc;
- if (session == NULL) {
- return;
- }
+ if (session == NULL) {
+ return;
+ }
- if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
- rc = ssh_buffer_pack(session->out_buffer,
- "bdss",
- SSH2_MSG_DISCONNECT,
- SSH2_DISCONNECT_BY_APPLICATION,
- "Bye Bye",
- ""); /* language tag */
- if (rc != SSH_OK){
- ssh_set_error_oom(session);
- goto error;
+ if (session->socket != NULL && ssh_socket_is_open(session->socket)) {
+ rc = ssh_buffer_pack(session->out_buffer,
+ "bdss",
+ SSH2_MSG_DISCONNECT,
+ SSH2_DISCONNECT_BY_APPLICATION,
+ "Bye Bye",
+ ""); /* language tag */
+ if (rc != SSH_OK) {
+ ssh_set_error_oom(session);
+ goto error;
+ }
+
+ ssh_packet_send(session);
+ ssh_socket_close(session->socket);
}
- ssh_packet_send(session);
- ssh_socket_close(session->socket);
- }
error:
- session->recv_seq = 0;
- session->send_seq = 0;
- session->alive = 0;
- if (session->socket != NULL){
- ssh_socket_reset(session->socket);
- }
- session->opts.fd = SSH_INVALID_SOCKET;
- session->session_state=SSH_SESSION_STATE_DISCONNECTED;
+ session->recv_seq = 0;
+ session->send_seq = 0;
+ session->alive = 0;
+ if (session->socket != NULL){
+ ssh_socket_reset(session->socket);
+ }
+ session->opts.fd = SSH_INVALID_SOCKET;
+ session->session_state = SSH_SESSION_STATE_DISCONNECTED;
+ session->pending_call_state = SSH_PENDING_CALL_NONE;
- while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
- ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));
- ssh_list_remove(session->channels, it);
- }
- if(session->current_crypto){
- crypto_free(session->current_crypto);
- session->current_crypto=NULL;
- }
- if (session->next_crypto) {
- crypto_free(session->next_crypto);
- session->next_crypto = crypto_new();
- if (session->next_crypto == NULL) {
- ssh_set_error_oom(session);
+ while ((it = ssh_list_get_iterator(session->channels)) != NULL) {
+ ssh_channel_do_free(ssh_iterator_value(ssh_channel, it));
+ ssh_list_remove(session->channels, it);
}
- }
- if (session->in_buffer) {
- ssh_buffer_reinit(session->in_buffer);
- }
- if (session->out_buffer) {
- ssh_buffer_reinit(session->out_buffer);
- }
- if (session->in_hashbuf) {
- ssh_buffer_reinit(session->in_hashbuf);
- }
- if (session->out_hashbuf) {
- ssh_buffer_reinit(session->out_hashbuf);
- }
- session->auth.supported_methods = 0;
- SAFE_FREE(session->serverbanner);
- SAFE_FREE(session->clientbanner);
-
- if(session->ssh_message_list){
- ssh_message msg;
- while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list))
- != NULL){
- ssh_message_free(msg);
+ if (session->current_crypto) {
+ crypto_free(session->current_crypto);
+ session->current_crypto = NULL;
}
- ssh_list_free(session->ssh_message_list);
- session->ssh_message_list=NULL;
- }
+ if (session->next_crypto) {
+ crypto_free(session->next_crypto);
+ session->next_crypto = crypto_new();
+ if (session->next_crypto == NULL) {
+ ssh_set_error_oom(session);
+ }
+ }
+ if (session->in_buffer) {
+ ssh_buffer_reinit(session->in_buffer);
+ }
+ if (session->out_buffer) {
+ ssh_buffer_reinit(session->out_buffer);
+ }
+ if (session->in_hashbuf) {
+ ssh_buffer_reinit(session->in_hashbuf);
+ }
+ if (session->out_hashbuf) {
+ ssh_buffer_reinit(session->out_hashbuf);
+ }
+ session->auth.supported_methods = 0;
+ SAFE_FREE(session->serverbanner);
+ SAFE_FREE(session->clientbanner);
- if (session->packet_callbacks){
- ssh_list_free(session->packet_callbacks);
- session->packet_callbacks=NULL;
- }
+ if (session->ssh_message_list) {
+ ssh_message msg = NULL;
+
+ while ((msg = ssh_list_pop_head(ssh_message,
+ session->ssh_message_list)) != NULL) {
+ ssh_message_free(msg);
+ }
+ ssh_list_free(session->ssh_message_list);
+ session->ssh_message_list = NULL;
+ }
+
+ if (session->packet_callbacks) {
+ ssh_list_free(session->packet_callbacks);
+ session->packet_callbacks = NULL;
+ }
}
const char *ssh_copyright(void) {
diff --git a/src/config.c b/src/config.c
index 79a64339..198a4726 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1170,3 +1170,57 @@ int ssh_config_parse_file(ssh_session session, const char *filename)
fclose(f);
return 0;
}
+
+/* @brief Parse configuration string and set the options to the given session
+ *
+ * @params[in] session The ssh session
+ * @params[in] input Null terminated string containing the configuration
+ *
+ * @returns SSH_OK on successful parsing the configuration string,
+ * SSH_ERROR on error
+ */
+int ssh_config_parse_string(ssh_session session, const char *input)
+{
+ char line[MAX_LINE_SIZE] = {0};
+ const char *c = input, *line_start = input;
+ unsigned int line_num = 0, line_len;
+ int parsing, rv;
+
+ SSH_LOG(SSH_LOG_DEBUG, "Reading configuration data from string:");
+ SSH_LOG(SSH_LOG_DEBUG, "START\n%s\nEND", input);
+
+ parsing = 1;
+ while (1) {
+ line_num++;
+ line_start = c;
+ c = strchr(line_start, '\n');
+ if (c == NULL) {
+ /* if there is no newline in the end of the string */
+ c = strchr(line_start, '\0');
+ }
+ if (c == NULL) {
+ /* should not happen, would mean a string without trailing '\0' */
+ SSH_LOG(SSH_LOG_WARN, "No trailing '\\0' in config string");
+ return SSH_ERROR;
+ }
+ line_len = c - line_start;
+ if (line_len > MAX_LINE_SIZE - 1) {
+ SSH_LOG(SSH_LOG_WARN, "Line %u too long: %u characters",
+ line_num, line_len);
+ return SSH_ERROR;
+ }
+ memcpy(line, line_start, line_len);
+ line[line_len] = '\0';
+ SSH_LOG(SSH_LOG_DEBUG, "Line %u: %s", line_num, line);
+ rv = ssh_config_parse_line(session, line, line_num, &parsing);
+ if (rv < 0) {
+ return SSH_ERROR;
+ }
+ if (*c == '\0') {
+ break;
+ }
+ c++;
+ }
+
+ return SSH_OK;
+}
diff --git a/src/kex.c b/src/kex.c
index dc9d5097..95948136 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -57,8 +57,8 @@
#ifdef HAVE_LIBGCRYPT
# define AES "aes256-gcm@openssh.com,aes128-gcm@openssh.com," \
- "aes256-ctr,aes192-ctr,aes128-ctr," \
- "aes256-cbc,aes192-cbc,aes128-cbc,"
+ "aes256-ctr,aes192-ctr,aes128-ctr,"
+# define AES_CBC "aes256-cbc,aes192-cbc,aes128-cbc,"
# define DES "3des-cbc"
# define DES_SUPPORTED "3des-cbc"
@@ -68,8 +68,8 @@
# else
# define GCM ""
# endif /* MBEDTLS_GCM_C */
-# define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr," \
- "aes256-cbc,aes192-cbc,aes128-cbc,"
+# define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr,"
+# define AES_CBC "aes256-cbc,aes192-cbc,aes128-cbc,"
# define DES "3des-cbc"
# define DES_SUPPORTED "3des-cbc"
@@ -81,12 +81,15 @@
# define GCM ""
# endif /* HAVE_OPENSSL_EVP_AES_GCM */
# ifdef BROKEN_AES_CTR
-# define AES GCM "aes256-cbc,aes192-cbc,aes128-cbc,"
+# define AES GCM
+# define AES_CBC "aes256-cbc,aes192-cbc,aes128-cbc,"
# else /* BROKEN_AES_CTR */
-# define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
+# define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr,"
+# define AES_CBC "aes256-cbc,aes192-cbc,aes128-cbc,"
# endif /* BROKEN_AES_CTR */
# else /* HAVE_OPENSSL_AES_H */
# define AES ""
+# define AES_CBC ""
# endif /* HAVE_OPENSSL_AES_H */
# define DES "3des-cbc"
@@ -165,16 +168,17 @@
#define CHACHA20 "chacha20-poly1305@openssh.com,"
-#define KEY_EXCHANGE \
+#define DEFAULT_KEY_EXCHANGE \
CURVE25519 \
ECDH \
"diffie-hellman-group18-sha512,diffie-hellman-group16-sha512," \
GEX_SHA256 \
- "diffie-hellman-group14-sha256," \
- "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
+ "diffie-hellman-group14-sha256" \
+
#define KEY_EXCHANGE_SUPPORTED \
GEX_SHA1 \
- KEY_EXCHANGE
+ DEFAULT_KEY_EXCHANGE \
+ ",diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
/* RFC 8308 */
#define KEX_EXTENSION_CLIENT "ext-info-c"
@@ -228,12 +232,12 @@ static const char *fips_methods[] = {
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
static const char *default_methods[] = {
- KEY_EXCHANGE,
+ DEFAULT_KEY_EXCHANGE,
DEFAULT_PUBLIC_KEY_ALGORITHMS,
- CHACHA20 AES BLOWFISH DES,
- CHACHA20 AES BLOWFISH DES,
- "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1",
- "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1",
+ CHACHA20 AES,
+ CHACHA20 AES,
+ "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512",
+ "hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512",
"none",
"none",
"",
@@ -245,8 +249,8 @@ static const char *default_methods[] = {
static const char *supported_methods[] = {
KEY_EXCHANGE_SUPPORTED,
PUBLIC_KEY_ALGORITHMS,
- CHACHA20 AES BLOWFISH DES_SUPPORTED NONE,
- CHACHA20 AES BLOWFISH DES_SUPPORTED NONE,
+ CHACHA20 AES AES_CBC BLOWFISH DES_SUPPORTED NONE,
+ CHACHA20 AES AES_CBC BLOWFISH DES_SUPPORTED NONE,
"hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1" NONE,
"hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1" NONE,
ZLIB,
@@ -751,13 +755,29 @@ int ssh_set_client_kex(ssh_session session)
return SSH_OK;
}
+static const char *ssh_find_aead_hmac(const char *cipher)
+{
+ if (cipher == NULL) {
+ return NULL;
+ } else if (strcmp(cipher, "chacha20-poly1305@openssh.com") == 0) {
+ return "aead-poly1305";
+ } else if (strcmp(cipher, "aes256-gcm@openssh.com") == 0) {
+ return "aead-gcm";
+ } else if (strcmp(cipher, "aes128-gcm@openssh.com") == 0) {
+ return "aead-gcm";
+ }
+ return NULL;
+}
+
/** @brief Select the different methods on basis of client's and
* server's kex messages, and watches out if a match is possible.
*/
-int ssh_kex_select_methods (ssh_session session){
+int ssh_kex_select_methods (ssh_session session)
+{
struct ssh_kex_struct *server = &session->next_crypto->server_kex;
struct ssh_kex_struct *client = &session->next_crypto->client_kex;
char *ext_start = NULL;
+ const char *aead_hmac = NULL;
int i;
/* Here we should drop the ext-info-c from the list so we avoid matching.
@@ -769,7 +789,15 @@ int ssh_kex_select_methods (ssh_session session){
for (i = 0; i < SSH_KEX_METHODS; i++) {
session->next_crypto->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]);
- if(session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){
+
+ if (i == SSH_MAC_C_S || i == SSH_MAC_S_C) {
+ aead_hmac = ssh_find_aead_hmac(session->next_crypto->kex_methods[i-2]);
+ if (aead_hmac) {
+ free(session->next_crypto->kex_methods[i]);
+ session->next_crypto->kex_methods[i] = strdup(aead_hmac);
+ }
+ }
+ if (session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){
ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]",
ssh_kex_descriptions[i],server->methods[i],client->methods[i]);
return SSH_ERROR;
@@ -778,31 +806,31 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_methods[i] = strdup("");
}
}
- if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
+ if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha1") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha1") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha256") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha256") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA256;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group16-sha512") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group16-sha512") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP16_SHA512;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group18-sha512") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group18-sha512") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP18_SHA512;
#ifdef WITH_GEX
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha1") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha1") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA1;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha256") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha256") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA256;
#endif /* WITH_GEX */
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp384") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp384") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP384;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp521") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp521") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP521;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256") == 0){
+ } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256;
}
SSH_LOG(SSH_LOG_INFO, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
@@ -822,7 +850,8 @@ int ssh_kex_select_methods (ssh_session session){
/* this function only sends the predefined set of kex methods */
-int ssh_send_kex(ssh_session session, int server_kex) {
+int ssh_send_kex(ssh_session session, int server_kex)
+{
struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex :
&session->next_crypto->client_kex);
ssh_string str = NULL;
@@ -1039,7 +1068,7 @@ int ssh_make_sessionid(ssh_session session)
ssh_buffer_get(server_hash),
server_pubkey_blob);
SSH_STRING_FREE(server_pubkey_blob);
- if(rc != SSH_OK){
+ if (rc != SSH_OK){
goto error;
}
diff --git a/src/libssh.map b/src/libssh.map
index c9bedee0..e30c2449 100644
--- a/src/libssh.map
+++ b/src/libssh.map
@@ -402,6 +402,7 @@ LIBSSH_4_5_0 # Released
ssh_userauth_pubkey;
ssh_userauth_publickey;
ssh_userauth_publickey_auto;
+ ssh_userauth_publickey_auto_get_current_identity;
ssh_userauth_try_publickey;
ssh_version;
ssh_write_knownhost;
diff --git a/src/misc.c b/src/misc.c
index faa185f9..167beaf1 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1300,7 +1300,8 @@ int ssh_analyze_banner(ssh_session session, int server)
session->openssh = SSH_VERSION_INT(((int) major), ((int) minor), 0);
SSH_LOG(SSH_LOG_PROTOCOL,
- "We are talking to an OpenSSH client version: %lu.%lu (%x)",
+ "We are talking to an OpenSSH %s version: %lu.%lu (%x)",
+ server ? "client" : "server",
major, minor, session->openssh);
}
}
@@ -1748,6 +1749,8 @@ int ssh_tmpname(char *template)
{
char *tmp = NULL;
size_t i = 0;
+ int rc = 0;
+ uint8_t random[6];
if (template == NULL) {
goto err;
@@ -1766,17 +1769,18 @@ int ssh_tmpname(char *template)
}
}
- srand(time(NULL));
+ rc = ssh_get_random(random, 6, 0);
+ if (!rc) {
+ SSH_LOG(SSH_LOG_WARNING,
+ "Could not generate random data\n");
+ goto err;
+ }
- for (i = 0; i < 6; ++i) {
-#ifdef _WIN32
- /* in win32 MAX_RAND is 32767, thus we can not shift that far,
- * otherwise the last three chars are 0 */
- int hexdigit = (rand() >> (i * 2)) & 0x1f;
-#else
- int hexdigit = (rand() >> (i * 5)) & 0x1f;
-#endif
- tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
+ for (i = 0; i < 6; i++) {
+ /* Limit the random[i] < 32 */
+ random[i] &= 0x1f;
+ /* For values from 0 to 9 use numbers, otherwise use letters */
+ tmp[i] = random[i] > 9 ? random[i] + 'a' - 10 : random[i] + '0';
}
return 0;
diff --git a/src/options.c b/src/options.c
index b2aeba89..692fc837 100644
--- a/src/options.c
+++ b/src/options.c
@@ -1370,7 +1370,7 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
*
* This should be the last call of all options, it may overwrite options which
* are already set. It requires that the host name is already set with
- * ssh_options_set_host().
+ * ssh_options_set(SSH_OPTIONS_HOST).
*
* @param session SSH session handle
*
@@ -1379,7 +1379,7 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
*
* @return 0 on success, < 0 on error.
*
- * @see ssh_options_set_host()
+ * @see ssh_options_set()
*/
int ssh_options_parse_config(ssh_session session, const char *filename) {
char *expanded_filename;
diff --git a/src/packet.c b/src/packet.c
index 3d675252..f14731c9 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -1036,7 +1036,7 @@ static bool ssh_packet_need_rekey(ssh_session session,
in_cipher->blocks + next_blocks > in_cipher->max_blocks);
SSH_LOG(SSH_LOG_PACKET,
- "packet: [data_rekey_needed=%d, out_blocks=%" PRIu64 ", in_blocks=%" PRIu64,
+ "rekey: [data_rekey_needed=%d, out_blocks=%" PRIu64 ", in_blocks=%" PRIu64 "]",
data_rekey_needed,
out_cipher->blocks + next_blocks,
in_cipher->blocks + next_blocks);
diff --git a/src/pki.c b/src/pki.c
index 9e28ea6e..0d86fbcd 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -1218,6 +1218,10 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type,
nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
SSH_STRING_FREE(i);
if (nid == -1) {
+ ssh_string_burn(e);
+ SSH_STRING_FREE(e);
+ ssh_string_burn(exp);
+ SSH_STRING_FREE(exp);
goto fail;
}
@@ -1373,6 +1377,8 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
SSH_STRING_FREE(i);
if (nid == -1) {
+ ssh_string_burn(e);
+ SSH_STRING_FREE(e);
goto fail;
}
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index 689faa1e..08409209 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -1330,6 +1330,14 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
return NULL;
}
+#ifdef WITH_PKCS11_URI
+ if (ssh_key_is_private(key) && !EC_KEY_get0_public_key(key->ecdsa)) {
+ SSH_LOG(SSH_LOG_INFO, "It is mandatory to have separate public"
+ " ECDSA key objects in the PKCS #11 device. Unlike RSA,"
+ " ECDSA public keys cannot be derived from their private keys.");
+ goto fail;
+ }
+#endif
e = make_ecpoint_string(EC_KEY_get0_group(key->ecdsa),
EC_KEY_get0_public_key(key->ecdsa));
if (e == NULL) {
diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c
index 62ec8ea7..0373cdae 100644
--- a/src/pki_gcrypt.c
+++ b/src/pki_gcrypt.c
@@ -1983,8 +1983,9 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
if (len > rsalen) {
SSH_LOG(SSH_LOG_WARN,
- "Signature is to big size: %lu",
- (unsigned long)len);
+ "Signature is too big: %lu > %lu",
+ (unsigned long)len,
+ (unsigned long)rsalen);
ssh_signature_free(sig);
return NULL;
}
diff --git a/src/sftp.c b/src/sftp.c
index 53582f45..07cb1c0e 100644
--- a/src/sftp.c
+++ b/src/sftp.c
@@ -1269,7 +1269,7 @@ static char *sftp_parse_longname(const char *longname,
size_t len, field = 0;
p = longname;
- /* Find the beginning of the field which is specified by sftp_longanme_field_e. */
+ /* Find the beginning of the field which is specified by sftp_longname_field_e. */
while(field != longname_field) {
if(isspace(*p)) {
field++;
diff --git a/src/sftpserver.c b/src/sftpserver.c
index 5a2110e5..9117f155 100644
--- a/src/sftpserver.c
+++ b/src/sftpserver.c
@@ -67,9 +67,20 @@ sftp_client_message sftp_get_client_message(sftp_session sftp) {
/* take a copy of the whole packet */
msg->complete_message = ssh_buffer_new();
- ssh_buffer_add_data(msg->complete_message,
- ssh_buffer_get(payload),
- ssh_buffer_get_len(payload));
+ if (msg->complete_message == NULL) {
+ ssh_set_error_oom(session);
+ sftp_client_message_free(msg);
+ return NULL;
+ }
+
+ rc = ssh_buffer_add_data(msg->complete_message,
+ ssh_buffer_get(payload),
+ ssh_buffer_get_len(payload));
+ if (rc < 0) {
+ ssh_set_error_oom(session);
+ sftp_client_message_free(msg);
+ return NULL;
+ }
ssh_buffer_get_u32(payload, &msg->id);
diff --git a/src/wrapper.c b/src/wrapper.c
index d53a61a3..bbd4e4b2 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -185,6 +185,7 @@ void crypto_free(struct ssh_crypto_struct *crypto)
crypto->ecdh_privkey = NULL;
}
#endif
+ SAFE_FREE(crypto->dh_server_signature);
if (crypto->session_id != NULL) {
explicit_bzero(crypto->session_id, crypto->digest_len);
SAFE_FREE(crypto->session_id);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 31a16a39..208d62dd 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -9,6 +9,7 @@ set(TORTURE_LIBRARY torture)
include_directories(${OPENSSL_INCLUDE_DIR}
${CMOCKA_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
+ ${libssh_BINARY_DIR}/include
${libssh_BINARY_DIR}
${libssh_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}
@@ -207,6 +208,9 @@ if (CLIENT_TESTING OR SERVER_TESTING)
# Give bob some keys
file(COPY keys/id_rsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_rsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
+ # Same as id_rsa, protected with passphrase "secret"
+ file(COPY keys/id_rsa_protected DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
+ file(COPY keys/id_rsa_protected.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ecdsa DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ecdsa.pub DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
file(COPY keys/id_ed25519 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/home/bob/.ssh/ FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
diff --git a/tests/authentication.c b/tests/authentication.c
deleted file mode 100644
index 248b646f..00000000
--- a/tests/authentication.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-This file is distributed in public domain. You can do whatever you want
-with its content.
-*/
-
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libssh/libssh.h>
-
-#include "tests.h"
-static int auth_kbdint(SSH_SESSION *session){
- int err=ssh_userauth_kbdint(session,NULL,NULL);
- char *name,*instruction,*prompt,*ptr;
- char buffer[128];
- int i,n;
- char echo;
- while (err==SSH_AUTH_INFO){
- name=ssh_userauth_kbdint_getname(session);
- instruction=ssh_userauth_kbdint_getinstruction(session);
- n=ssh_userauth_kbdint_getnprompts(session);
- if(strlen(name)>0)
- printf("%s\n",name);
- if(strlen(instruction)>0)
- printf("%s\n",instruction);
- for(i=0;i<n;++i){
- prompt=ssh_userauth_kbdint_getprompt(session,i,&echo);
- if(echo){
- printf("%s",prompt);
- fgets(buffer,sizeof(buffer),stdin);
- buffer[sizeof(buffer)-1]=0;
- if((ptr=strchr(buffer,'\n')))
- *ptr=0;
- ssh_userauth_kbdint_setanswer(session,i,buffer);
- memset(buffer,0,strlen(buffer));
- } else {
- ptr=getpass(prompt);
- ssh_userauth_kbdint_setanswer(session,i,ptr);
- }
- }
- err=ssh_userauth_kbdint(session,NULL,NULL);
- }
- return err;
-}
-
-int authenticate (SSH_SESSION *session){
- int auth=ssh_userauth_autopubkey(session, NULL);
- char *password;
- if(auth==SSH_AUTH_ERROR){
- fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(session));
- return auth;
- }
- if(auth!=SSH_AUTH_SUCCESS){
- auth=auth_kbdint(session);
- if(auth==SSH_AUTH_ERROR){
- fprintf(stderr,"authenticating with keyb-interactive: %s\n",
- ssh_get_error(session));
- return auth;
- }
- }
- if(auth!=SSH_AUTH_SUCCESS){
- password=getpass("Password : ");
- auth = ssh_userauth_password(session,NULL,password);
- memset(password,0,strlen(password));
- if (auth==SSH_AUTH_ERROR){
- fprintf(stderr,"Authentication with password failed: %s\n",ssh_get_error(session));
- return auth;
- }
- }
- return auth;
-}
diff --git a/tests/client/torture_algorithms.c b/tests/client/torture_algorithms.c
index 729505ef..ea3b647b 100644
--- a/tests/client/torture_algorithms.c
+++ b/tests/client/torture_algorithms.c
@@ -45,6 +45,16 @@ static int sshd_teardown(void **state) {
return 0;
}
+static int sshd_setup_hmac(void **state)
+{
+ torture_setup_sshd_server(state, false);
+ /* Set MAC to be something other than what the client will offer */
+ torture_update_sshd_config(state, "MACs hmac-sha2-512");
+
+ return 0;
+}
+
+
static int session_setup(void **state) {
struct torture_state *s = *state;
int verbosity = torture_libssh_verbosity();
@@ -412,6 +422,20 @@ static void torture_algorithms_aes256_gcm(void **state)
test_algorithm(s->ssh.session, NULL/*kex*/, "aes256-gcm@openssh.com", NULL);
}
+static void torture_algorithms_aes128_gcm_mac(void **state)
+{
+ struct torture_state *s = *state;
+
+ test_algorithm(s->ssh.session, NULL/*kex*/, "aes128-gcm@openssh.com", "hmac-sha1");
+}
+
+static void torture_algorithms_aes256_gcm_mac(void **state)
+{
+ struct torture_state *s = *state;
+
+ test_algorithm(s->ssh.session, NULL/*kex*/, "aes256-gcm@openssh.com", "hmac-sha1");
+}
+
static void torture_algorithms_3des_cbc_hmac_sha1(void **state) {
struct torture_state *s = *state;
@@ -548,6 +572,19 @@ static void torture_algorithms_chacha20_poly1305(void **state)
"chacha20-poly1305@openssh.com",
NULL);
}
+static void torture_algorithms_chacha20_poly1305_mac(void **state)
+{
+ struct torture_state *s = *state;
+
+ if (ssh_fips_mode()) {
+ skip();
+ }
+
+ test_algorithm(s->ssh.session,
+ NULL, /*kex*/
+ "chacha20-poly1305@openssh.com",
+ "hmac-sha1"); /* different from the server */
+}
#endif /* OPENSSH_CHACHA20_POLY1305_OPENSSH_COM */
static void torture_algorithms_zlib(void **state) {
@@ -951,10 +988,30 @@ int torture_run_tests(void) {
#endif
};
+ struct CMUnitTest tests_hmac[] = {
+ cmocka_unit_test_setup_teardown(torture_algorithms_aes128_gcm_mac,
+ session_setup,
+ session_teardown),
+ cmocka_unit_test_setup_teardown(torture_algorithms_aes256_gcm_mac,
+ session_setup,
+ session_teardown),
+#ifdef OPENSSH_CHACHA20_POLY1305_OPENSSH_COM
+ cmocka_unit_test_setup_teardown(torture_algorithms_chacha20_poly1305_mac,
+ session_setup,
+ session_teardown),
+#endif /* OPENSSH_CHACHA20_POLY1305_OPENSSH_COM */
+ };
+
ssh_init();
torture_filter_tests(tests);
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
+ if (rc != 0) {
+ return rc;
+ }
+
+ torture_filter_tests(tests);
+ rc = cmocka_run_group_tests(tests_hmac, sshd_setup_hmac, sshd_teardown);
ssh_finalize();
diff --git a/tests/client/torture_auth.c b/tests/client/torture_auth.c
index 24ecc507..29f6f5a5 100644
--- a/tests/client/torture_auth.c
+++ b/tests/client/torture_auth.c
@@ -281,6 +281,96 @@ static void torture_auth_autopubkey(void **state) {
assert_int_equal(rc, SSH_AUTH_SUCCESS);
}
+struct torture_auth_autopubkey_protected_data {
+ ssh_session session;
+ int n_calls;
+};
+
+static int
+torture_auth_autopubkey_protected_auth_function (const char *prompt, char *buf, size_t len,
+ int echo, int verify, void *userdata)
+{
+ int rc;
+ char *id, *expected_id;
+ struct torture_auth_autopubkey_protected_data *data = userdata;
+
+ assert_true(prompt != NULL);
+ assert_int_equal(echo, 0);
+ assert_int_equal(verify, 0);
+
+ expected_id = ssh_path_expand_escape(data->session, "%d/id_rsa_protected");
+ assert_true(expected_id != NULL);
+
+ rc = ssh_userauth_publickey_auto_get_current_identity(data->session, &id);
+ assert_int_equal(rc, SSH_OK);
+
+ assert_string_equal(expected_id, id);
+
+ ssh_string_free_char(id);
+ ssh_string_free_char(expected_id);
+
+ data->n_calls += 1;
+ strncpy(buf, "secret", len);
+ return 0;
+}
+
+static void torture_auth_autopubkey_protected(void **state) {
+ struct torture_state *s = *state;
+ ssh_session session = s->ssh.session;
+ char *id;
+ int rc;
+
+ struct torture_auth_autopubkey_protected_data data = {
+ .session = session,
+ .n_calls = 0
+ };
+
+ struct ssh_callbacks_struct callbacks = {
+ .userdata = &data,
+ .auth_function = torture_auth_autopubkey_protected_auth_function
+ };
+
+ /* no session pointer */
+ rc = ssh_userauth_publickey_auto_get_current_identity(NULL, &id);
+ assert_int_equal(rc, SSH_ERROR);
+
+ /* no result pointer */
+ rc = ssh_userauth_publickey_auto_get_current_identity(session, NULL);
+ assert_int_equal(rc, SSH_ERROR);
+
+ /* no auto auth going on */
+ rc = ssh_userauth_publickey_auto_get_current_identity(session, &id);
+ assert_int_equal(rc, SSH_ERROR);
+
+ ssh_callbacks_init(&callbacks);
+ ssh_set_callbacks(session, &callbacks);
+
+ /* Authenticate as alice with bob his pubkey */
+ rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
+ assert_int_equal(rc, SSH_OK);
+
+ /* Try id_rsa_protected first.
+ */
+ rc = ssh_options_set(session, SSH_OPTIONS_IDENTITY, "%d/id_rsa_protected");
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_connect(session);
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_userauth_none(session,NULL);
+ /* This request should return a SSH_REQUEST_DENIED error */
+ if (rc == SSH_ERROR) {
+ assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED);
+ }
+ rc = ssh_userauth_list(session, NULL);
+ assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
+
+ rc = ssh_userauth_publickey_auto(session, NULL, NULL);
+ assert_int_equal(rc, SSH_AUTH_SUCCESS);
+
+ assert_int_equal (data.n_calls, 1);
+}
+
static void torture_auth_autopubkey_nonblocking(void **state) {
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
@@ -918,6 +1008,9 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_auth_autopubkey,
pubkey_setup,
session_teardown),
+ cmocka_unit_test_setup_teardown(torture_auth_autopubkey_protected,
+ pubkey_setup,
+ session_teardown),
cmocka_unit_test_setup_teardown(torture_auth_autopubkey_nonblocking,
pubkey_setup,
session_teardown),
diff --git a/tests/client/torture_auth_pkcs11.c b/tests/client/torture_auth_pkcs11.c
index 79b32e15..ee97bff4 100644
--- a/tests/client/torture_auth_pkcs11.c
+++ b/tests/client/torture_auth_pkcs11.c
@@ -61,7 +61,7 @@ static int setup_tokens(void **state, const char *type, const char *obj_name)
snprintf(priv_filename, sizeof(priv_filename), "%s%s", test_state->keys_dir, type);
- torture_setup_tokens(cwd, priv_filename, obj_name);
+ torture_setup_tokens(cwd, priv_filename, obj_name, "1");
return 0;
}
diff --git a/tests/client/torture_knownhosts.c b/tests/client/torture_knownhosts.c
index fcc54846..55aee217 100644
--- a/tests/client/torture_knownhosts.c
+++ b/tests/client/torture_knownhosts.c
@@ -307,6 +307,7 @@ static void torture_knownhosts_other_auto(void **state) {
char tmp_file[1024] = {0};
char *known_hosts_file = NULL;
int rc;
+ bool process_config = false;
snprintf(tmp_file,
sizeof(tmp_file),
@@ -344,6 +345,9 @@ static void torture_knownhosts_other_auto(void **state) {
s->ssh.session = session;
+ rc = ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
+ assert_ssh_return_code(session, rc);
+
rc = ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
assert_ssh_return_code(session, rc);
@@ -368,6 +372,7 @@ static void torture_knownhosts_conflict(void **state) {
char *known_hosts_file = NULL;
FILE *file;
int rc;
+ bool process_config = false;
snprintf(tmp_file,
sizeof(tmp_file),
@@ -411,6 +416,9 @@ static void torture_knownhosts_conflict(void **state) {
s->ssh.session = session;
+ rc = ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
+ assert_ssh_return_code(session, rc);
+
ssh_options_set(session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file);
rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "rsa-sha2-256");
diff --git a/tests/client/torture_scp.c b/tests/client/torture_scp.c
index 8f080af3..59a00bae 100644
--- a/tests/client/torture_scp.c
+++ b/tests/client/torture_scp.c
@@ -37,6 +37,7 @@
#define BUF_SIZE 1024
#define TEMPLATE BINARYDIR "/tests/home/alice/temp_dir_XXXXXX"
+#define ALICE_HOME BINARYDIR "/tests/home/alice"
struct scp_st {
struct torture_state *s;
@@ -540,6 +541,86 @@ static void torture_scp_upload_newline(void **state)
fclose(file);
}
+static void torture_scp_upload_appended_command(void **state)
+{
+ struct scp_st *ts = NULL;
+ struct torture_state *s = NULL;
+
+ ssh_session session = NULL;
+ ssh_scp scp = NULL;
+
+ FILE *file = NULL;
+
+ char buf[1024];
+ char *rs = NULL;
+ int rc;
+
+ assert_non_null(state);
+ ts = *state;
+
+ assert_non_null(ts->s);
+ s = ts->s;
+
+ session = s->ssh.session;
+ assert_non_null(session);
+
+ assert_non_null(ts->tmp_dir_basename);
+ assert_non_null(ts->tmp_dir);
+
+ /* Upload a file path with a command appended */
+
+ /* Append a command to the file path */
+ snprintf(buf, BUF_SIZE, "%s"
+ "/;touch hack",
+ ts->tmp_dir);
+
+ /* When writing the file_name must be the directory name */
+ scp = ssh_scp_new(session, SSH_SCP_WRITE | SSH_SCP_RECURSIVE,
+ buf);
+ assert_non_null(scp);
+
+ rc = ssh_scp_init(scp);
+ assert_ssh_return_code(session, rc);
+
+ /* Push directory where the new file will be copied */
+ rc = ssh_scp_push_directory(scp, ";touch hack", 0755);
+ assert_ssh_return_code(session, rc);
+
+ /* Try to push file */
+ rc = ssh_scp_push_file(scp, "original", 8, 0644);
+ assert_ssh_return_code(session, rc);
+
+ rc = ssh_scp_write(scp, "original", 8);
+ assert_ssh_return_code(session, rc);
+
+ /* Leave the directory */
+ rc = ssh_scp_leave_directory(scp);
+ assert_ssh_return_code(session, rc);
+
+ /* Cleanup */
+ ssh_scp_close(scp);
+ ssh_scp_free(scp);
+
+ /* Make sure the command was not executed */
+ snprintf(buf, BUF_SIZE, ALICE_HOME "/hack");
+ file = fopen(buf, "r");
+ assert_null(file);
+
+ /* Open the file and check content */
+ snprintf(buf, BUF_SIZE, "%s"
+ "/;touch hack/original",
+ ts->tmp_dir);
+
+ file = fopen(buf, "r");
+ assert_non_null(file);
+
+ rs = fgets(buf, 1024, file);
+ assert_non_null(rs);
+ assert_string_equal(buf, "original");
+
+ fclose(file);
+}
+
int torture_run_tests(void)
{
int rc;
@@ -559,6 +640,9 @@ int torture_run_tests(void)
cmocka_unit_test_setup_teardown(torture_scp_upload_newline,
session_setup,
session_teardown),
+ cmocka_unit_test_setup_teardown(torture_scp_upload_appended_command,
+ session_setup,
+ session_teardown),
};
ssh_init();
diff --git a/tests/client/torture_session.c b/tests/client/torture_session.c
index 41309f17..d83ec9b6 100644
--- a/tests/client/torture_session.c
+++ b/tests/client/torture_session.c
@@ -166,6 +166,58 @@ static void torture_channel_poll_timeout(void **state) {
ssh_channel_free(channel);
}
+/*
+ * Check that the client can properly handle the error returned from the server
+ * when the maximum number of sessions is exceeded.
+ *
+ * Related: T75, T239
+ *
+ */
+static void torture_max_sessions(void **state)
+{
+ struct torture_state *s = *state;
+ ssh_session session = s->ssh.session;
+ char max_session_config[32] = {0};
+#define MAX_CHANNELS 10
+ ssh_channel channels[MAX_CHANNELS + 1];
+ size_t i;
+ int rc;
+
+ snprintf(max_session_config,
+ sizeof(max_session_config),
+ "MaxSessions %u",
+ MAX_CHANNELS);
+
+ /* Update server configuration to limit number of sessions */
+ torture_update_sshd_config(state, max_session_config);
+
+ /* Open the maximum number of channel sessions */
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ channels[i] = ssh_channel_new(session);
+ assert_non_null(channels[i]);
+
+ rc = ssh_channel_open_session(channels[i]);
+ assert_ssh_return_code(session, rc);
+ }
+
+ /* Try to open an extra session and expect failure */
+ channels[i] = ssh_channel_new(session);
+ assert_non_null(channels[i]);
+
+ rc = ssh_channel_open_session(channels[i]);
+ assert_int_equal(rc, SSH_ERROR);
+
+ /* Free the unused channel */
+ ssh_channel_free(channels[i]);
+
+ /* Close and free channels */
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ ssh_channel_close(channels[i]);
+ ssh_channel_free(channels[i]);
+ }
+#undef MAX_CHANNELS
+}
+
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -178,12 +230,16 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_channel_poll_timeout,
session_setup,
session_teardown),
+ cmocka_unit_test_setup_teardown(torture_max_sessions,
+ session_setup,
+ session_teardown),
};
ssh_init();
torture_filter_tests(tests);
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
+
ssh_finalize();
return rc;
diff --git a/tests/connection.c b/tests/connection.c
deleted file mode 100644
index 889c5117..00000000
--- a/tests/connection.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-This file is distributed in public domain. You can do whatever you want
-with its content.
-*/
-
-#include <libssh/libssh.h>
-#include <stdio.h>
-#include "tests.h"
-SSH_OPTIONS *set_opts(int argc, char **argv){
- SSH_OPTIONS *options=ssh_options_new();
- char *host=NULL;
- if(ssh_options_getopt(options,&argc, argv)){
- fprintf(stderr,"error parsing command line :%s\n",ssh_get_error(options));
- return NULL;
- }
- int i;
- while((i=getopt(argc,argv,""))!=-1){
- switch(i){
- default:
- fprintf(stderr,"unknown option %c\n",optopt);
- }
- }
- if(optind < argc)
- host=argv[optind++];
- if(host==NULL){
- fprintf(stderr,"must provide an host name\n");
- return NULL;
- }
- ssh_options_set_host(options,host);
- return options;
-}
diff --git a/tests/fuzz/README.md b/tests/fuzz/README.md
index 12afbb51..c68ef3d1 100644
--- a/tests/fuzz/README.md
+++ b/tests/fuzz/README.md
@@ -67,3 +67,67 @@ to use none cipher for the key exchange to be plausible.
cp /tmp/ssh_client tests/fuzz/ssh_client_fuzzer_corpus/$(sha1sum /tmp/ssh_client | cut -d ' ' -f 1)
cp /tmp/ssh_server tests/fuzz/ssh_server_fuzzer_corpus/$(sha1sum /tmp/ssh_server | cut -d ' ' -f 1)
+
+## Debugging issues reported by oss-fuzz
+
+OSS Fuzz provides helper scripts to reproduce issues locally. Even though the
+fuzzing scripts can ran anywhere, the best bet for reproducing is to use
+their container infrastructure. There is a
+[complete documentation](https://google.github.io/oss-fuzz/advanced-topics/reproducing/)
+but I will try to focus here on the workflow I use and libssh specifics.
+
+### Environment
+
+The helper scripts are written in Python and use docker to run containers
+so these needs to be installed. I am using podman instead of docker for
+some time, but it has some quirks that needs to be addressed in advance
+and that I describe in the rejected [PR](https://github.com/google/oss-fuzz/pull/4774).
+You can either pick up my branch or workaround them locally:
+
+ * Package `podman-docker` installs symlink from `/bin/docker` to `/bin/podman`
+ * The directories mounted to the containers need to have `container_file_t`
+ SELinux labels -- this is needed for the `build` directory that is created
+ under the oss-fuzz repository, for testcases and for source files
+ * `podman` does not like combination of `--privileged` and
+ `--cap-add SYS_PTRACE` flags. Podman can work with non-privileged containers
+ so you can just remove the `--privileged` from the `infra/helper.py`
+
+### Reproduce locally
+
+Clone the above repository from https://github.com/google/oss-fuzz/, apply
+changes from previous secion if needed, setup local clone of libssh repository
+and build the fuzzers locally (where `~/devel/libssh` is path to local libssh
+checkout):
+
+ python infra/helper.py build_fuzzers libssh ~/devel/libssh/
+
+Now, download the testcase from oss-fuzz.com (the file under `~/Downloads`)
+and we are ready to reproduce the issue locally (replace the `ssh_client_fuzzer`
+with the fuzzer name if the issue happens in other fuzzer):
+
+ python infra/helper.py reproduce libssh ssh_client_fuzzer ~/Downloads/clusterfuzz-testcase-ssh_client_fuzzer-4637376441483264
+
+This should give you the same error/leak/crash as you see on the testcase
+detail in oss-fuzz.com.
+
+I find it very useful to run libssh in debug mode, to see what happened and
+what exit path was taken to get to the error. Fortunatelly, we can simply
+pass environment variables to the container:
+
+ python infra/helper.py reproduce -eLIBSSH_VERBOSITY=9 libssh ssh_client_fuzzer ~/Downloads/clusterfuzz-testcase-ssh_client_fuzzer-4637376441483264
+
+### Fix the issue and verify the fix
+
+Now, we can properly investigate the issue and once we have a fix, we can
+make changes in our local checkout and repeat the steps above (from building
+fuzzers) to verify the issue is no longer present.
+
+### Fuzzing locally
+
+We can use the oss-fuzz tools even further and run the fuzzing process
+locally, to verify there are no similar issues happening very close to
+existing code paths and which would cause more reports very soon after
+we would fix the current issue. The following command will run fuzzer
+until it finds an issue or until killed:
+
+ python infra/helper.py run_fuzzer libssh ssh_client_fuzzer
diff --git a/tests/keys/id_rsa_protected b/tests/keys/id_rsa_protected
new file mode 100644
index 00000000..cdf5c2b8
--- /dev/null
+++ b/tests/keys/id_rsa_protected
@@ -0,0 +1,28 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBjmItEMS
+YKDxy/7xvsZY+uAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCz98jP4bLz
+1eNSFd5s2rauzUrREkRlcNt9yh9vXcRIMn19Jt35GUJQzqL5+gRVXbfFZ1qd2zYGSfva0a
+Kclp0iA5ZT6SjGn6BGa0ksT842IAolCpErd44k0EfoC33o0yongbC/nobhbry4+APBRVDB
+UhzoRzpHKmLPsMT5L76BK8FAhVRC3teQ9xc7I3nO6PmoOFkziXpXs6D0taPj/YgXlpy8qN
+8gyl6qaen3PoFNhlC25BTpvVW4RiFfK8zouQzCd2xUaHjqQMoyZFCHIDwDqq8sCWIwyrzy
+TmBHgB4l5OeoNH9DXbQjo8ypg2XpMtOTz8qic448NH9dcZveIXrvAAADwCLre52Jer2DTQ
+TJi91b/xNm5NRuW9366ZdoOC5NdWtbQFk4YJmdImEDo8k1t3Re24rVNxLMQwHwZX4ZLISl
+/e49RtSd6TDP44FkQF4NgtCjLUdmEWRTQj0mtENGto+wdLpL25HkmmI5WGrQU9SufVhhvj
+TxKi6ediSXIXEA5bSrWNvUaw084TT3ZfP9g98/6wr9tAYL1jVfTFUabvZzCR6+wRVoJIVc
+/+uN1bubj+IdOzYSm9Dhj4kUlK+KvI4GtouCzjuEZosjvn0ino3du1vgyT7SPdjmDxtIds
+YI7YiB1Xy3QcWdWFk+SoXhDizf9pupo2r1+G50GoBuXg2ELdsKBLXtxQ9bh37JyAcLzagq
+iVMCJjk3XMZvNXhdELRqLeWyhQ7U1BCtUBatbem0VsH6hQZ/pHReX2We8/GAUQkh4ZN8U2
+lkta9v5cb7XaBm49JjzIa3WeOS+tFHIUAWqd7MQ4f2FCTMhBssLAM7EJDOUXyo6938pa75
++LvdLZRUycE8d/PWG9SuFWSe4CJJrRlBQqPEwx9OPtKNNKgsXIGVKAFLXe+nJ4z6RXTR3R
+IGe0uaf8v9Jra5j22rq/dbQG1fP1fZNcCnIZQQo6olLaoyQmGCboC8CiCz1PNTsC1+r4pB
+oaRiCx5/qLF6EXQ03mdEqL1L/R+KMDa2+Ncw2hCSRU3GBby4wXmSqFsboRy5uxJB5sK0Ut
+sI3FW48k9zijiqVpdysRkalVVSQj8ymTG9LbjjEEmE7qxRf2dZCEnS/iPFUIu7iO9ISiOm
+4ThpROBspNyHMXKFR6mKArJX1vIwjehlaLAXA3UMY9PEFRDrWQcbatGWj4f/L6e3Tq+n7a
+t0djAgKlh40IvVL+Xf+Bsv8vUr7HAbKnOxpX69nEShiJqR5YWlEPXba+JCOjryE2ycoRB6
+d2d0SgDlB1M04uUmv2sy2Kw/CcSNHPLKGiYqqv8DAZ4GiKH2rI4oWvH9z2uRuQni98/Gw1
+1D5/QwJOHpqrUnVat4JXPBeTqiHYYtbTtqJLeIPX+Dsa6tbdjEOVgx2FkH3104xMwJyUKb
+Ccip4AbWsTwfM4GVPnJE6WCBcXC5WR6AOzuEEDQjhyzLs5K7RVb7irfhHa4Vs1/2LvxnRT
+dmTzdv/mhUNqS9RIPmFttfsSveDqY0P6WOn+K6FcCHQjpFJ3pK08glD+Sx4cbFv3lUQLfw
+hsjL0P+p+M+gTqeJ1kb2z87fiS03mHMV15lmb7nzoqyeJLIukV1jidWdGxf0efnQfmUVfX
+Wa+ehGaw==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/tests/keys/id_rsa_protected.pub b/tests/keys/id_rsa_protected.pub
new file mode 100644
index 00000000..15a35b3a
--- /dev/null
+++ b/tests/keys/id_rsa_protected.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCz98jP4bLz1eNSFd5s2rauzUrREkRlcNt9yh9vXcRIMn19Jt35GUJQzqL5+gRVXbfFZ1qd2zYGSfva0aKclp0iA5ZT6SjGn6BGa0ksT842IAolCpErd44k0EfoC33o0yongbC/nobhbry4+APBRVDBUhzoRzpHKmLPsMT5L76BK8FAhVRC3teQ9xc7I3nO6PmoOFkziXpXs6D0taPj/YgXlpy8qN8gyl6qaen3PoFNhlC25BTpvVW4RiFfK8zouQzCd2xUaHjqQMoyZFCHIDwDqq8sCWIwyrzyTmBHgB4l5OeoNH9DXbQjo8ypg2XpMtOTz8qic448NH9dcZveIXrv asn@krikkit.cryptomilk.site
diff --git a/tests/pkcs11/setup-softhsm-tokens.sh b/tests/pkcs11/setup-softhsm-tokens.sh
index 4aca191c..532c86a7 100755
--- a/tests/pkcs11/setup-softhsm-tokens.sh
+++ b/tests/pkcs11/setup-softhsm-tokens.sh
@@ -5,7 +5,8 @@
TESTDIR=$1
PRIVKEY=$2
OBJNAME=$3
-shift 3
+LOADPUBLIC=$4
+shift 4
PUBKEY="$PRIVKEY.pub"
@@ -13,6 +14,7 @@ echo "TESTDIR: $TESTDIR"
echo "PRIVKEY: $PRIVKEY"
echo "PUBKEY: $PUBKEY"
echo "OBJNAME: $OBJNAME"
+echo "LOADPUBLIC: $LOADPUBLIC"
# Create temporary directory for tokens
install -d -m 0755 $TESTDIR/db
@@ -54,15 +56,17 @@ cat $PUBKEY
ls -l $TESTDIR
+if [ $LOADPUBLIC -ne 0 ]; then
#load public key
-cmd='p11tool --provider /usr/lib64/pkcs11/libsofthsm2.so --write --load-pubkey "$PUBKEY" --label "$OBJNAME" --login --set-pin=1234 "pkcs11:token="$OBJNAME""'
-eval echo "$cmd"
-out=$(eval $cmd)
-ret=$?
-if [ $ret -ne 0 ]; then
- echo "Loading pubkey failed"
- echo "$out"
- exit 1
+ cmd='p11tool --provider /usr/lib64/pkcs11/libsofthsm2.so --write --load-pubkey "$PUBKEY" --label "$OBJNAME" --login --set-pin=1234 "pkcs11:token="$OBJNAME""'
+ eval echo "$cmd"
+ out=$(eval $cmd)
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "Loading pubkey failed"
+ echo "$out"
+ exit 1
+ fi
fi
cmd='p11tool --list-all --login "pkcs11:token="$OBJNAME"" --set-pin=1234'
diff --git a/tests/pkd/CMakeLists.txt b/tests/pkd/CMakeLists.txt
index 85a57775..9e550462 100644
--- a/tests/pkd/CMakeLists.txt
+++ b/tests/pkd/CMakeLists.txt
@@ -3,6 +3,7 @@ project(pkd C)
if (WITH_SERVER AND UNIX AND NOT WIN32)
include_directories(${libssh_SOURCE_DIR}/include
+ ${libssh_BINARY_DIR}/include
${CMOCKA_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
${CMAKE_BINARY_DIR}
diff --git a/tests/pkd/pkd_daemon.c b/tests/pkd/pkd_daemon.c
index 239bdd36..5325a5de 100644
--- a/tests/pkd/pkd_daemon.c
+++ b/tests/pkd/pkd_daemon.c
@@ -247,10 +247,9 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
int level = args->opts.libssh_log_level;
enum pkd_hostkey_type_e type = args->type;
const char *hostkeypath = args->hostkeypath;
- const char *default_kex = NULL;
- char *all_kex = NULL;
- size_t kex_len = 0;
+ const char *all_kex = NULL;
const char *all_ciphers = NULL;
+ const char *all_macs = NULL;
const uint64_t rekey_data_limit = args->rekey_data_limit;
bool process_config = false;
@@ -302,17 +301,10 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
if (!ssh_fips_mode()) {
const char *all_hostkeys = NULL;
/* Add methods not enabled by default */
-#define GEX_SHA1 "diffie-hellman-group-exchange-sha1"
- default_kex = ssh_kex_get_default_methods(SSH_KEX);
- kex_len = strlen(default_kex) + strlen(GEX_SHA1) + 2;
- all_kex = malloc(kex_len);
- if (all_kex == NULL) {
- pkderr("Failed to alloc more memory.\n");
- goto outclose;
- }
- snprintf(all_kex, kex_len, "%s," GEX_SHA1, default_kex);
+
+ /* Enable all supported key exchange methods */
+ all_kex = ssh_kex_get_supported_method(SSH_KEX);
rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_KEY_EXCHANGE, all_kex);
- free(all_kex);
if (rc != 0) {
pkderr("ssh_bind_options_set kex methods: %s\n", ssh_get_error(b));
goto outclose;
@@ -341,6 +333,21 @@ static int pkd_exec_hello(int fd, struct pkd_daemon_args *args)
goto outclose;
}
+ /* Enable all message authentication codes */
+ all_macs = ssh_kex_get_supported_method(SSH_MAC_C_S);
+ rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_HMAC_C_S, all_macs);
+ if (rc != 0) {
+ pkderr("ssh_bind_options_set MACs C-S: %s\n", ssh_get_error(b));
+ goto outclose;
+ }
+
+ all_macs = ssh_kex_get_supported_method(SSH_MAC_S_C);
+ rc = ssh_bind_options_set(b, SSH_BIND_OPTIONS_HMAC_S_C, all_macs);
+ if (rc != 0) {
+ pkderr("ssh_bind_options_set MACs S-C: %s\n", ssh_get_error(b));
+ goto outclose;
+ }
+
}
s = ssh_new();
diff --git a/tests/pkd/pkd_hello.c b/tests/pkd/pkd_hello.c
index 3a5768d7..01b1b10d 100644
--- a/tests/pkd/pkd_hello.c
+++ b/tests/pkd/pkd_hello.c
@@ -392,45 +392,37 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
#endif
-#define PKDTESTS_CIPHER_FIPS(f, client, ciphercmd) \
- f(client, rsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_rsa, teardown) \
+#define PKDTESTS_CIPHER_COMMON(f, client, ciphercmd) \
f(client, rsa_aes128_ctr, ciphercmd("aes128-ctr"), setup_rsa, teardown) \
- f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \
f(client, rsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_rsa, teardown) \
- f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_256, teardown) \
- f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_256, teardown) \
- f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_384, teardown) \
- f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_384, teardown) \
- f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_aes128_ctr, ciphercmd("aes128-ctr"), setup_ecdsa_521, teardown) \
- f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_aes256_ctr, ciphercmd("aes256-ctr"), setup_ecdsa_521, teardown)
+#define PKDTESTS_CIPHER_FIPS(f, client, ciphercmd) \
+ PKDTESTS_CIPHER_COMMON(f, client, ciphercmd) \
+ f(client, rsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_rsa, teardown) \
+ f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \
+ f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \
+ f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown)
+
#ifdef HAVE_DSA
#define PKDTESTS_CIPHER(f, client, ciphercmd) \
/* Ciphers. */ \
- PKDTESTS_CIPHER_FIPS(f, client, ciphercmd) \
- f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \
- f(client, dsa_3des_cbc, ciphercmd("3des-cbc"), setup_dsa, teardown) \
- f(client, dsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_dsa, teardown) \
+ PKDTESTS_CIPHER_COMMON(f, client, ciphercmd) \
f(client, dsa_aes128_ctr, ciphercmd("aes128-ctr"), setup_dsa, teardown) \
- f(client, dsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_dsa, teardown) \
- f(client, dsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_dsa, teardown) \
- f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \
- f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \
- f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown)
+ f(client, dsa_aes256_ctr, ciphercmd("aes256-ctr"), setup_dsa, teardown)
#else
#define PKDTESTS_CIPHER(f, client, ciphercmd) \
/* Ciphers. */ \
- PKDTESTS_CIPHER_FIPS(f, client, ciphercmd) \
- f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \
- f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \
- f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \
- f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown)
+ PKDTESTS_CIPHER_COMMON(f, client, ciphercmd)
#endif
#define CHACHA20 "chacha20-poly1305@openssh.com"
@@ -451,10 +443,16 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
#define PKDTESTS_CIPHER_OPENSSHONLY(f, client, ciphercmd) \
/* Ciphers. */ \
PKDTESTS_CIPHER_OPENSSHONLY_FIPS(f, client, ciphercmd) \
+ f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \
+ f(client, rsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_rsa, teardown) \
f(client, rsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_rsa, teardown) \
+ f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \
f(client, rsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_rsa, teardown) \
f(client, rsa_chacha20, ciphercmd(CHACHA20), setup_rsa, teardown) \
+ f(client, dsa_3des_cbc, ciphercmd("3des-cbc"), setup_dsa, teardown) \
+ f(client, dsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_dsa, teardown) \
f(client, dsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_dsa, teardown) \
+ f(client, dsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_dsa, teardown) \
f(client, dsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_dsa, teardown) \
f(client, dsa_chacha20, ciphercmd(CHACHA20), setup_dsa, teardown) \
f(client, dsa_aes128_gcm, ciphercmd(AES128_GCM), setup_dsa, teardown) \
@@ -469,20 +467,32 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
f(client, ed25519_chacha20, ciphercmd(CHACHA20), setup_ed25519, teardown) \
f(client, ed25519_aes128_gcm, ciphercmd(AES128_GCM), setup_ed25519, teardown) \
f(client, ed25519_aes256_gcm, ciphercmd(AES256_GCM), setup_ed25519, teardown) \
+ f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_chacha20, ciphercmd(CHACHA20), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_chacha20, ciphercmd(CHACHA20), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown) \
+ f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \
+ f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_chacha20, ciphercmd(CHACHA20), setup_ecdsa_521, teardown)
#else
#define PKDTESTS_CIPHER_OPENSSHONLY(f, client, ciphercmd) \
/* Ciphers. */ \
PKDTESTS_CIPHER_OPENSSHONLY_FIPS(f, client, ciphercmd) \
+ f(client, rsa_3des_cbc, ciphercmd("3des-cbc"), setup_rsa, teardown) \
+ f(client, rsa_aes128_cbc, ciphercmd("aes128-cbc"), setup_rsa, teardown) \
f(client, rsa_aes192_cbc, ciphercmd("aes192-cbc"), setup_rsa, teardown) \
+ f(client, rsa_aes256_cbc, ciphercmd("aes256-cbc"), setup_rsa, teardown) \
f(client, rsa_aes192_ctr, ciphercmd("aes192-ctr"), setup_rsa, teardown) \
f(client, rsa_chacha20, ciphercmd(CHACHA20), setup_rsa, teardown) \
f(client, ed25519_3des_cbc, ciphercmd("3des-cbc"), setup_ed25519, teardown) \
@@ -493,13 +503,22 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
f(client, ed25519_aes192_cbc, ciphercmd("aes192-cbc"), setup_ed25519, teardown) \
f(client, ed25519_aes192_ctr, ciphercmd("aes192-ctr"), setup_ed25519, teardown) \
f(client, ed25519_chacha20, ciphercmd(CHACHA20), setup_ed25519, teardown) \
+ f(client, ecdsa_256_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_256_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_256_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_chacha20, ciphercmd(CHACHA20), setup_ecdsa_256, teardown) \
+ f(client, ecdsa_384_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_384_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_384_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_384, teardown) \
f(client, ecdsa_384_chacha20, ciphercmd(CHACHA20), setup_ecdsa_384, teardown) \
+ f(client, ecdsa_521_3des_cbc, ciphercmd("3des-cbc"), setup_ecdsa_521, teardown) \
+ f(client, ecdsa_521_aes128_cbc, ciphercmd("aes128-cbc"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_aes192_cbc, ciphercmd("aes192-cbc"), setup_ecdsa_521, teardown) \
+ f(client, ecdsa_521_aes256_cbc, ciphercmd("aes256-cbc"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown) \
f(client, ecdsa_521_chacha20, ciphercmd(CHACHA20), setup_ecdsa_521, teardown)
#endif
diff --git a/tests/server/CMakeLists.txt b/tests/server/CMakeLists.txt
index 9476ea91..96457cd2 100644
--- a/tests/server/CMakeLists.txt
+++ b/tests/server/CMakeLists.txt
@@ -10,9 +10,11 @@ set(LIBSSH_SERVER_TESTS
torture_server
torture_server_auth_kbdint
torture_server_config
+ torture_server_algorithms
)
include_directories(${libssh_SOURCE_DIR}/include
+ ${libssh_BINARY_DIR}/include
${libssh_BINARY_DIR}
test_server)
diff --git a/tests/server/test_server/CMakeLists.txt b/tests/server/test_server/CMakeLists.txt
index 10bf4b7d..fe5e7d09 100644
--- a/tests/server/test_server/CMakeLists.txt
+++ b/tests/server/test_server/CMakeLists.txt
@@ -17,6 +17,7 @@ set(LIBSSH_SERVER_TESTS
)
include_directories(${libssh_SOURCE_DIR}/include
+ ${libssh_BINARY_DIR}/include
${libssh_BINARY_DIR})
if (ARGP_INCLUDE_DIR)
diff --git a/tests/server/torture_server_algorithms.c b/tests/server/torture_server_algorithms.c
new file mode 100644
index 00000000..3963e368
--- /dev/null
+++ b/tests/server/torture_server_algorithms.c
@@ -0,0 +1,364 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <pwd.h>
+
+#include "torture.h"
+#include "torture_key.h"
+#include "libssh/libssh.h"
+#include "libssh/priv.h"
+#include "libssh/session.h"
+#include "libssh/token.h"
+
+#include "test_server.h"
+#include "default_cb.h"
+
+const char template[] = "temp_dir_XXXXXX";
+
+struct test_server_st {
+ struct torture_state *state;
+ char *cwd;
+ char *temp_dir;
+ char rsa_hostkey[1024];
+};
+
+static int setup_files(void **state)
+{
+ struct test_server_st *tss;
+ struct torture_state *s;
+ char sshd_path[1024];
+
+ int rc;
+
+ tss = (struct test_server_st*)calloc(1, sizeof(struct test_server_st));
+ assert_non_null(tss);
+
+ torture_setup_socket_dir((void **)&s);
+ assert_non_null(s->socket_dir);
+
+ /* Set the default interface for the server */
+ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
+
+ snprintf(sshd_path,
+ sizeof(sshd_path),
+ "%s/sshd",
+ s->socket_dir);
+
+ rc = mkdir(sshd_path, 0755);
+ assert_return_code(rc, errno);
+
+ snprintf(tss->rsa_hostkey,
+ sizeof(tss->rsa_hostkey),
+ "%s/sshd/ssh_host_rsa_key",
+ s->socket_dir);
+ torture_write_file(tss->rsa_hostkey, torture_get_testkey(SSH_KEYTYPE_RSA, 0));
+
+ tss->state = s;
+ *state = tss;
+
+ return 0;
+}
+
+static int teardown_files(void **state)
+{
+ struct torture_state *s;
+ struct test_server_st *tss;
+
+ tss = *state;
+ assert_non_null(tss);
+
+ s = tss->state;
+ assert_non_null(s);
+
+ torture_teardown_socket_dir((void **)&s);
+ SAFE_FREE(tss);
+
+ return 0;
+}
+
+static int setup_temp_dir(void **state)
+{
+ struct test_server_st *tss = *state;
+ struct torture_state *s;
+
+ char *cwd = NULL;
+ char *tmp_dir = NULL;
+
+ assert_non_null(tss);
+
+ s = tss->state;
+ assert_non_null(s);
+
+ cwd = torture_get_current_working_dir();
+ assert_non_null(cwd);
+
+ tmp_dir = torture_make_temp_dir(template);
+ assert_non_null(tmp_dir);
+
+ tss->cwd = cwd;
+ tss->temp_dir = tmp_dir;
+
+ return 0;
+}
+
+static int teardown_temp_dir(void **state)
+{
+ struct test_server_st *tss = *state;
+ int rc;
+
+ assert_non_null(tss);
+
+ rc = torture_change_dir(tss->cwd);
+ assert_int_equal(rc, 0);
+
+ rc = torture_rmdirs(tss->temp_dir);
+ assert_int_equal(rc, 0);
+
+ SAFE_FREE(tss->temp_dir);
+ SAFE_FREE(tss->cwd);
+
+ return 0;
+}
+
+static int start_server(void **state)
+{
+ struct test_server_st *tss = *state;
+ struct torture_state *s;
+
+ assert_non_null(tss);
+
+ s = tss->state;
+ assert_non_null(s);
+
+ /* Start the server using the default values */
+ torture_setup_libssh_server((void **)&s, "./test_server/test_server");
+ assert_non_null(s);
+
+ return 0;
+}
+
+static int stop_server(void **state)
+{
+ struct torture_state *s;
+ struct test_server_st *tss;
+
+ int rc;
+
+ tss = *state;
+ assert_non_null(tss);
+
+ s = tss->state;
+ assert_non_null(s);
+
+ rc = torture_terminate_process(s->srv_pidfile);
+ assert_return_code(rc, errno);
+
+ unlink(s->srv_pidfile);
+
+ return 0;
+}
+
+static int session_setup(void **state)
+{
+ struct test_server_st *tss = *state;
+ struct torture_state *s;
+ int verbosity = torture_libssh_verbosity();
+ struct passwd *pwd;
+ bool b = false;
+ int rc;
+
+ assert_non_null(tss);
+
+ /* Make sure we do not test the agent */
+ unsetenv("SSH_AUTH_SOCK");
+
+ s = tss->state;
+ assert_non_null(s);
+
+ 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);
+
+ 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_HOST, TORTURE_SSH_SERVER);
+ 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);
+
+ return 0;
+}
+
+static int session_teardown(void **state)
+{
+ struct test_server_st *tss = *state;
+ struct torture_state *s;
+
+ assert_non_null(tss);
+
+ s = tss->state;
+ assert_non_null(s);
+
+ ssh_disconnect(s->ssh.session);
+ ssh_free(s->ssh.session);
+
+ return 0;
+}
+
+/*
+ * Check that the handshake works with an AEAD cipher configured
+ * but with no overlap for HMACs. AEAD ciphers have an implied HMAC
+ * so no HMAC overlap in the handshake should not fail the connection.
+ */
+static void test_algorithm_no_hmac_overlap(void **state, const char *algorithm)
+{
+ struct test_server_st *tss = *state;
+ struct torture_state *s = NULL;
+ char config_content[4096];
+
+ ssh_session session = NULL;
+
+ int rc;
+
+ assert_non_null(tss);
+ s = tss->state;
+ assert_non_null(s);
+
+ /* Prepare key files */
+ snprintf(config_content,
+ sizeof(config_content),
+ "HostKey %s\nCiphers %s\nMACs %s\n",
+ tss->rsa_hostkey,
+ algorithm,
+ "hmac-sha2-512-etm@openssh.com");
+
+ assert_non_null(s->srv_config);
+ torture_write_file(s->srv_config, config_content);
+
+ fprintf(stderr, "Config file %s content: \n\n%s\n", s->srv_config,
+ config_content);
+ fflush(stderr);
+
+ /* Start server */
+ rc = start_server(state);
+ assert_int_equal(rc, 0);
+
+ /* Setup session */
+ rc = session_setup(state);
+ assert_int_equal(rc, 0);
+
+ session = s->ssh.session;
+ assert_non_null(session);
+
+ rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, algorithm);
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, algorithm);
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, "hmac-sha2-512");
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, "hmac-sha2-512");
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_connect(session);
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_userauth_none(session, NULL);
+ /* This request should return a SSH_REQUEST_DENIED error */
+ if (rc == SSH_ERROR) {
+ assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED);
+ }
+ rc = ssh_userauth_list(session, NULL);
+ assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
+
+ rc = ssh_userauth_publickey_auto(session, NULL, NULL);
+ assert_ssh_return_code(session, rc);
+
+ rc = session_teardown(state);
+ assert_int_equal(rc, 0);
+
+ rc = stop_server(state);
+ assert_int_equal(rc, 0);
+
+ SAFE_FREE(s->srv_additional_config);
+}
+
+static void torture_algorithm_chacha20_with_no_hmac_overlap(void **state)
+{
+ if (ssh_fips_mode()) {
+ skip();
+ }
+ test_algorithm_no_hmac_overlap(state, "chacha20-poly1305@openssh.com");
+}
+
+static void torture_algorithm_aes256gcm_with_no_hmac_overlap(void **state)
+{
+ test_algorithm_no_hmac_overlap(state, "aes256-gcm@openssh.com");
+}
+
+static void torture_algorithm_aes128gcm_with_no_hmac_overlap(void **state)
+{
+ test_algorithm_no_hmac_overlap(state, "aes128-gcm@openssh.com");
+}
+
+int torture_run_tests(void)
+{
+ int rc;
+ struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(torture_algorithm_chacha20_with_no_hmac_overlap,
+ setup_temp_dir, teardown_temp_dir),
+ cmocka_unit_test_setup_teardown(torture_algorithm_aes256gcm_with_no_hmac_overlap,
+ setup_temp_dir, teardown_temp_dir),
+ cmocka_unit_test_setup_teardown(torture_algorithm_aes128gcm_with_no_hmac_overlap,
+ setup_temp_dir, teardown_temp_dir),
+ };
+
+ ssh_init();
+
+ torture_filter_tests(tests);
+ rc = cmocka_run_group_tests(tests,
+ setup_files,
+ teardown_files);
+
+ ssh_finalize();
+
+ return rc;
+}
diff --git a/tests/server/torture_server_config.c b/tests/server/torture_server_config.c
index 2f0fa8c9..5f66f015 100644
--- a/tests/server/torture_server_config.c
+++ b/tests/server/torture_server_config.c
@@ -703,6 +703,103 @@ static void torture_server_config_unknown(void **state)
assert_int_equal(rc, 0);
}
+/*
+ * Check that the server returns the correct signature when the negotiated host
+ * key is RSA but the signature algorithm is not the server's preferred
+ * algorithm (e.g. when the client prefers ssh-rsa over rsa-sha2-256 or
+ * rsa-sha2-512).
+ *
+ * Related: T191, T240
+ */
+static void torture_server_config_rsa_hostkey_order(void **state)
+{
+ struct test_server_st *tss = *state;
+ struct torture_state *s = NULL;
+ char config_content[4096];
+ size_t num_hostkey_files;
+ const char *allowed = NULL;
+
+ ssh_session session = NULL;
+
+ int rc;
+
+ assert_non_null(tss);
+ s = tss->state;
+ assert_non_null(s);
+
+ /* Prepare key files */
+ num_hostkey_files = setup_hostkey_files(tss);
+ assert_true(num_hostkey_files > 0);
+
+ /* Create the server configuration file */
+ if (ssh_fips_mode()) {
+ allowed = "rsa-sha2-512,rsa-sha2-256";
+ } else {
+ allowed = "rsa-sha2-256,ssh-rsa";
+ }
+
+ snprintf(config_content,
+ sizeof(config_content),
+ "HostKey %s\nHostkeyAlgorithms %s\n",
+ tss->rsa_hostkey, allowed);
+
+ assert_non_null(s->srv_config);
+ torture_write_file(s->srv_config, config_content);
+
+ fprintf(stderr, "Config file %s content: \n\n%s\n", s->srv_config,
+ config_content);
+ fflush(stderr);
+
+ /* Start server */
+ rc = start_server(state);
+ assert_int_equal(rc, 0);
+
+ /* Setup session */
+ rc = session_setup(state);
+ assert_int_equal(rc, 0);
+
+ session = s->ssh.session;
+ assert_non_null(session);
+
+ rc = ssh_options_set(session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
+ assert_int_equal(rc, SSH_OK);
+
+ /* Set client order of preference different from the server */
+ if (ssh_fips_mode()) {
+ /* Set the host keys with rsa-sha2-256 before rsa-sha2-512 */
+ rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS,
+ "rsa-sha2-256,rsa-sha2-512");
+ assert_int_equal(rc, SSH_OK);
+ } else {
+ /* Set the host keys with ssh-rsa before rsa-sha2-256 */
+ rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS,
+ "ssh-rsa,rsa-sha2-256");
+ assert_int_equal(rc, SSH_OK);
+ }
+
+ rc = ssh_connect(session);
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_userauth_none(session, NULL);
+ /* This request should return a SSH_REQUEST_DENIED error */
+ if (rc == SSH_ERROR) {
+ assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED);
+ }
+ rc = ssh_userauth_list(session, NULL);
+ assert_true(rc & SSH_AUTH_METHOD_PUBLICKEY);
+
+ rc = ssh_userauth_publickey_auto(session, NULL, NULL);
+ assert_ssh_return_code(session, rc);
+
+ rc = session_teardown(state);
+ assert_int_equal(rc, 0);
+
+ rc = stop_server(state);
+ assert_int_equal(rc, 0);
+
+ SAFE_FREE(s->srv_additional_config);
+}
+
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -718,6 +815,8 @@ int torture_run_tests(void) {
setup_temp_dir, teardown_temp_dir),
cmocka_unit_test_setup_teardown(torture_server_config_unknown,
setup_temp_dir, teardown_temp_dir),
+ cmocka_unit_test_setup_teardown(torture_server_config_rsa_hostkey_order,
+ setup_temp_dir, teardown_temp_dir),
};
ssh_init();
diff --git a/tests/sftp_stress/main.c b/tests/sftp_stress/main.c
deleted file mode 100644
index ac3f8bb4..00000000
--- a/tests/sftp_stress/main.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * main.c
- *
- * Created on: 22 juin 2009
- * Author: aris
- */
-#include <stdio.h>
-#include <libssh/libssh.h>
-#include <libssh/sftp.h>
-#include <time.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pthread.h>
-#define TEST_READ 1
-#define TEST_WRITE 2
-#define NTHREADS 3
-#define FILESIZE 100000
-unsigned char samplefile[FILESIZE];
-volatile int stop=0;
-
-const char* hosts[]={"localhost","barebone"};
-void signal_stop(){
- stop=1;
- printf("Stopping...\n");
-}
-
-SSH_SESSION *connect_host(const char *hostname);
-int sftp_test(SSH_SESSION *session, int test);
-
-int docycle(const char *host, int test){
- SSH_SESSION *session=connect_host(host);
- int ret=SSH_ERROR;
- if(!session){
- printf("connect failed\n");
- } else {
- printf("Connected\n");
- ret=sftp_test(session,test);
- if(ret != SSH_OK){
- printf("Error in sftp\n");
- }
- ssh_disconnect(session);
- }
- return ret;
-}
-
-int thread(){
- while(docycle(hosts[rand()%2],TEST_WRITE) == SSH_OK)
- if(stop)
- break;
- return 0;
-}
-
-int main(int argc, char **argv){
- int i;
- pthread_t threads[NTHREADS];
- ssh_init();
- srand(time(NULL));
- for(i=0;i<FILESIZE;++i)
- samplefile[i]=rand() & 0xff;
- signal(SIGTERM,signal_stop);
- signal(SIGINT,signal_stop);
-
- for(i=0;i<NTHREADS;++i){
- srand(i);
- pthread_create(&threads[i],NULL,(void *) thread, NULL);
- }
- for(i=0;i<NTHREADS;++i){
- pthread_join(threads[i],NULL);
- }
- ssh_finalize();
- printf("Ended\n");
- return 0;
-}
-
-SSH_SESSION *connect_host(const char *hostname){
- SSH_SESSION *session;
- SSH_OPTIONS *options;
- int auth=0;
- int state;
-
- options=ssh_options_new();
- ssh_options_set_host(options,hostname);
- session=ssh_new();
- ssh_set_options(session,options);
- if(ssh_connect(session)){
- fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
- ssh_disconnect(session);
- return NULL;
- }
-
- state = ssh_session_is_known_server(session);
- switch(state){
- case SSH_SERVER_KNOWN_OK:
- break; /* ok */
- case SSH_SERVER_KNOWN_CHANGED:
- fprintf(stderr,"Host key for server changed : server's one is now :\n");
- fprintf(stderr,"For security reason, connection will be stopped\n");
- ssh_disconnect(session);
- ssh_finalize();
- return NULL;
- case SSH_SERVER_FOUND_OTHER:
- fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
- fprintf(stderr,"An attacker might change the default server key to confuse your client"
- "into thinking the key does not exist\n"
- "We advise you to rerun the client with -d or -r for more safety.\n");
- ssh_disconnect(session);
- ssh_finalize();
- return NULL;
- case SSH_SERVER_NOT_KNOWN:
- fprintf(stderr,"The server is unknown. Leaving now");
- ssh_disconnect(session);
- return NULL;
- case SSH_SERVER_ERROR:
- fprintf(stderr,"%s",ssh_get_error(session));
- ssh_disconnect(session);
- return NULL;
- }
-
- ssh_userauth_none(session, NULL);
-
- auth=ssh_userauth_autopubkey(session, NULL);
- if(auth==SSH_AUTH_ERROR){
- fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(session));
- ssh_disconnect(session);
- return NULL;
- }
- if(auth!=SSH_AUTH_SUCCESS){
- fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
- ssh_disconnect(session);
- return NULL;
- }
- ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success");
- return session;
-}
-
-int sftp_test(SSH_SESSION *session, int test){
- SFTP_SESSION *sftp=sftp_new(session);
- SFTP_FILE *file;
- int wrote=0;
- char name[128];
- if(sftp == NULL)
- return SSH_ERROR;
- if(sftp_init(sftp)<0){
- printf("problem initializing sftp : %s\n",ssh_get_error(session));
- return SSH_ERROR;
- }
- if(test==TEST_WRITE){
- snprintf(name,sizeof(name),"/tmp/libsshstress%d",rand());
- file=sftp_open(sftp,name,O_RDWR|O_CREAT,0777);
- if(!file){
- printf("Failed to open file : %s\n",ssh_get_error(session));
- sftp_free(sftp);
- return SSH_ERROR;
- }
- while(wrote<FILESIZE){
- int max=FILESIZE-wrote;
- int towrite=rand()%max + 1;
- int ret=sftp_write(file,&samplefile[wrote],towrite);
- if(ret<=0){
- printf("Problem while writing : %s\n",ssh_get_error(session));
- sftp_free(sftp);
- return SSH_ERROR;
- }
- if(ret != towrite){
- printf("Asked to write %d, wrote %d\n",towrite,ret);
- }
- wrote += ret;
- }
- sftp_close(file);
- }
- sftp_free(sftp);
- return SSH_OK;
-}
diff --git a/tests/test_exec.c b/tests/test_exec.c
deleted file mode 100644
index 352cc837..00000000
--- a/tests/test_exec.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-This file is distributed in public domain. You can do whatever you want
-with its content.
-*/
-#include <libssh/libssh.h>
-#include <stdio.h>
-#include <string.h>
-#include "tests.h"
-
-void do_connect(SSH_SESSION *session) {
- char buf[4096] = {0};
- CHANNEL *channel;
-
- int error = ssh_connect(session);
- if (error != SSH_OK) {
- fprintf(stderr,"Error at connection: %s\n", ssh_get_error(session));
- return;
- }
- printf("Connected\n");
-
- ssh_session_is_known_server(session);
-
- error = authenticate(session);
- if(error != SSH_AUTH_SUCCESS) {
- fprintf(stderr,"Error at authentication: %s\n", ssh_get_error(session));
- return;
- }
- printf("Authenticated\n");
- channel = ssh_channel_new(session);
- ssh_channel_open_session(channel);
- printf("Execute 'ls' on the channel\n");
- error = ssh_channel_request_exec(channel, "ls");
- if(error != SSH_OK){
- fprintf(stderr, "Error executing command: %s\n", ssh_get_error(session));
- return;
- }
- printf("--------------------output----------------------\n");
- while (ssh_channel_read(channel, buf, sizeof(buf), 0)) {
- printf("%s", buf);
- }
- printf("\n");
- printf("---------------------end------------------------\n");
- ssh_channel_send_eof(channel);
- fprintf(stderr, "Exit status: %d\n", ssh_channel_get_exit_status(channel));
-
- printf("\nChannel test finished\n");
- ssh_channel_close(channel);
- ssh_channel_free(channel);
-}
-
-int main(int argc, char **argv){
- SSH_OPTIONS *options=set_opts(argc, argv);
- SSH_SESSION *session=ssh_new();
- if(options==NULL){
- return 1;
- }
- ssh_set_options(session,options);
- do_connect(session);
- ssh_disconnect(session);
- ssh_finalize();
- return 0;
-}
diff --git a/tests/test_pcap.c b/tests/test_pcap.c
deleted file mode 100644
index 01aa714a..00000000
--- a/tests/test_pcap.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * This file is part of the SSH Library
- *
- * Copyright (c) 2009 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.
- */
-
-/* Simple test for the pcap functions */
-
-#include <libssh/libssh.h>
-#include <libssh/pcap.h>
-#include <libssh/buffer.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int main(int argc, char **argv){
- ssh_pcap_file pcap;
- ssh_pcap_context ctx;
- ssh_buffer buffer=ssh_buffer_new();
- char *str="Hello, this is a test string to test the capabilities of the"
- "pcap file writer.";
- printf("Simple pcap tester\n");
- pcap=ssh_pcap_file_new();
- if(ssh_pcap_file_open(pcap,"test.cap") != SSH_OK){
- printf("error happened\n");
- return EXIT_FAILURE;
- }
- buffer_add_data(buffer,str,strlen(str));
- ctx=ssh_pcap_context_new(NULL);
- ssh_pcap_context_set_file(ctx,pcap);
- ssh_pcap_context_write(ctx,SSH_PCAP_DIR_OUT,str,strlen(str),strlen(str));
-
- return EXIT_SUCCESS;
-}
diff --git a/tests/test_ssh_bind_accept_fd.c b/tests/test_ssh_bind_accept_fd.c
deleted file mode 100644
index 5aa8211a..00000000
--- a/tests/test_ssh_bind_accept_fd.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Test the ability to use ssh_bind_accept_fd.
- *
- * Expected behavior: Prints "SUCCESS!"
- *
- * Faulty behavior observed before change: Connection timeout
- */
-
-#include <arpa/inet.h>
-#include <err.h>
-#include <libssh/libssh.h>
-#include <libssh/server.h>
-#include <netinet/in.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-struct options {
- const char *server_keyfile;
-} options;
-
-const char HOST[] = "127.0.0.1";
-const int PORT = 3333;
-
-int get_connection() {
- int rc, server_socket, client_conn = -1;
- struct sockaddr_in server_socket_addr;
- struct sockaddr_storage client_conn_addr;
- socklen_t client_conn_addr_size = sizeof(client_conn_addr);
-
- server_socket = socket(PF_INET, SOCK_STREAM, 0);
- if (server_socket < 0) {
- goto out;
- }
-
- server_socket_addr.sin_family = AF_INET;
- server_socket_addr.sin_port = htons(PORT);
- if (inet_pton(AF_INET, HOST, &server_socket_addr.sin_addr) != 1) {
- goto out;
- }
-
- rc = bind(server_socket, (struct sockaddr *)&server_socket_addr,
- sizeof(server_socket_addr));
- if (rc < 0) {
- goto out;
- }
-
- if (listen(server_socket, 0) < 0) {
- goto out;
- }
-
- client_conn = accept(server_socket,
- (struct sockaddr *)&client_conn_addr,
- &client_conn_addr_size);
-
- out:
- return client_conn;
-}
-
-void ssh_server() {
- ssh_bind bind;
- ssh_session session;
-
- int client_conn = get_connection();
- if (client_conn < 0) {
- err(1, "get_connection");
- }
-
- bind = ssh_bind_new();
- if (!bind) {
- errx(1, "ssh_bind_new");
- }
-
-#ifdef HAVE_DSA
- /*TODO mbedtls this is probably required */
- if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_DSAKEY,
- options.server_keyfile) != SSH_OK) {
- errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_DSAKEY");
- }
-#else
- if (ssh_bind_options_set(bind, SSH_BIND_OPTIONS_RSAKEY,
- options.server_keyfile) != SSH_OK) {
- errx(1, "ssh_bind_options_set(SSH_BIND_OPTIONS_RSAKEY");
- }
-#endif
-
- session = ssh_new();
- if (!session) {
- errx(1, "ssh_new");
- }
-
- if (ssh_bind_accept_fd(bind, session, client_conn) != SSH_OK) {
- errx(1, "ssh_bind_accept: %s", ssh_get_error(bind));
- }
-
- if (ssh_handle_key_exchange(session) != SSH_OK) {
- errx(1, "ssh_handle_key_exchange: %s", ssh_get_error(session));
- }
-
- printf("SUCCESS!\n");
-}
-
-void ssh_client() {
- ssh_session session;
-
- session = ssh_new();
- if (!session) {
- errx(1, "ssh_new");
- }
-
- if (ssh_options_set(session, SSH_OPTIONS_HOST, HOST) < 0) {
- errx(1, "ssh_options_set(SSH_OPTIONS_HOST)");
- }
- if (ssh_options_set(session, SSH_OPTIONS_PORT, &PORT) < 0) {
- errx(1, "ssh_options_set(SSH_OPTIONS_PORT)");
- }
-
- if (ssh_connect(session) != SSH_OK) {
- errx(1, "ssh_connect: %s", ssh_get_error(session));
- }
-}
-
-int main(int argc, const char *argv[]) {
- if (argc != 2) {
- printf("Usage: %s <private key file>\n", argv[0]);
- exit(1);
- }
-
- options.server_keyfile = argv[1];
-
- pid_t pid = fork();
- if (pid < 0) {
- errx(1, "fork");
- }
- if (pid == 0) {
- /* Allow the server to get set up */
- sleep(3);
-
- ssh_client();
- } else {
- ssh_server();
- }
-
- return 0;
-}
diff --git a/tests/test_tunnel.c b/tests/test_tunnel.c
deleted file mode 100644
index 952c73e1..00000000
--- a/tests/test_tunnel.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-This file is distributed in public domain. You can do whatever you want
-with its content.
-*/
-#include <libssh/libssh.h>
-#include <stdio.h>
-#include <string.h>
-#include "tests.h"
-#define ECHO_PORT 7
-void do_connect(SSH_SESSION *session){
- int error=ssh_connect(session);
- if(error != SSH_OK){
- fprintf(stderr,"Error at connection :%s\n",ssh_get_error(session));
- return;
- }
- printf("Connected\n");
- ssh_session_is_known_server(session);
- // we don't care what happens here
- error=authenticate(session);
- if(error != SSH_AUTH_SUCCESS){
- fprintf(stderr,"Error at authentication :%s\n",ssh_get_error(session));
- return;
- }
- printf("Authenticated\n");
- CHANNEL *channel=ssh_channel_new(session);
- error=ssh_channel_open_forward(channel,"localhost",ECHO_PORT,"localhost",42);
- if(error!=SSH_OK){
- fprintf(stderr,"Error when opening forward:%s\n",ssh_get_error(session));
- return;
- }
- printf("Forward opened\n");
- int i=0;
- char string[20];
- char buffer[20];
- for(i=0;i<2000;++i){
- sprintf(string,"%d\n",i);
- ssh_channel_write(channel,string,strlen(string));
- do {
- error=ssh_channel_poll(channel,0);
- //if(error < strlen(string))
- //usleep(10);
- } while(error < strlen(string) && error >= 0);
- if(error>0){
- error=ssh_channel_read_nonblocking(channel,buffer,strlen(string),0);
- if(error>=0){
- if(memcmp(buffer,string,strlen(string))!=0){
- fprintf(stderr,"Problem with answer: wanted %s got %s\n",string,buffer);
- } else {
- printf(".");
- fflush(stdout);
- }
- }
-
- }
- if(error==-1){
- fprintf(stderr,"Channel reading error : %s\n",ssh_get_error(session));
- break;
- }
- }
- printf("\nChannel test finished\n");
- ssh_channel_close(channel);
- ssh_channel_free(channel);
-}
-
-int main(int argc, char **argv){
- SSH_OPTIONS *options=set_opts(argc, argv);
- SSH_SESSION *session=ssh_new();
- if(options==NULL){
- return 1;
- }
- ssh_set_options(session,options);
- do_connect(session);
- ssh_disconnect(session);
- ssh_finalize();
- return 0;
-}
diff --git a/tests/tests.h b/tests/tests.h
deleted file mode 100644
index dd001f1f..00000000
--- a/tests/tests.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-This file is distributed in public domain. You can do whatever you want
-with its content.
-*/
-#include <libssh/libssh.h>
-int authenticate (SSH_SESSION *session);
-SSH_OPTIONS *set_opts(int argc, char **argv);
-
diff --git a/tests/torture.c b/tests/torture.c
index 1c64f6de..7d26b013 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -719,6 +719,7 @@ static void torture_setup_create_sshd_config(void **state, bool pam)
struct stat sb;
const char *sftp_server_locations[] = {
"/usr/lib/ssh/sftp-server",
+ "/usr/libexec/ssh/sftp-server", /* Tumbleweed 20200829 */
"/usr/libexec/sftp-server",
"/usr/libexec/openssh/sftp-server",
"/usr/lib/openssh/sftp-server", /* Debian */
@@ -743,7 +744,8 @@ static void torture_setup_create_sshd_config(void **state, bool pam)
"\n"
"StrictModes no\n"
"\n"
- "%s" /* Here comes UsePam */
+ "%s\n" /* Here comes UsePam */
+ "%s" /* The space for test-specific options */
"\n"
/* add all supported algorithms */
"HostKeyAlgorithms " OPENSSH_KEYS "\n"
@@ -758,8 +760,7 @@ static void torture_setup_create_sshd_config(void **state, bool pam)
"AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT\n"
"AcceptEnv LC_IDENTIFICATION LC_ALL LC_LIBSSH\n"
"\n"
- "PidFile %s\n"
- "%s\n"; /* The space for test-specific options */
+ "PidFile %s\n";
/* FIPS config */
const char fips_config_string[]=
"Port 22\n"
@@ -777,7 +778,8 @@ static void torture_setup_create_sshd_config(void **state, bool pam)
"\n"
"StrictModes no\n"
"\n"
- "%s" /* UsePam */
+ "%s\n" /* Here comes UsePam */
+ "%s" /* The space for test-specific options */
"\n"
"Ciphers "
"aes256-gcm@openssh.com,aes256-ctr,aes256-cbc,"
@@ -806,8 +808,7 @@ static void torture_setup_create_sshd_config(void **state, bool pam)
"AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT\n"
"AcceptEnv LC_IDENTIFICATION LC_ALL LC_LIBSSH\n"
"\n"
- "PidFile %s\n" /* PID file */
- "%s\n"; /* The space for test-specific options */
+ "PidFile %s\n"; /* PID file */
const char usepam_yes[] =
"UsePAM yes\n"
"KbdInteractiveAuthentication yes\n";
@@ -908,8 +909,8 @@ static void torture_setup_create_sshd_config(void **state, bool pam)
trusted_ca_pubkey,
sftp_server,
usepam,
- s->srv_pidfile,
- additional_config);
+ additional_config,
+ s->srv_pidfile);
} else {
snprintf(sshd_config, sizeof(sshd_config),
config_string,
@@ -922,8 +923,8 @@ static void torture_setup_create_sshd_config(void **state, bool pam)
trusted_ca_pubkey,
sftp_server,
usepam,
- s->srv_pidfile,
- additional_config);
+ additional_config,
+ s->srv_pidfile);
}
torture_write_file(s->srv_config, sshd_config);
@@ -1127,16 +1128,18 @@ void torture_setup_sshd_server(void **state, bool pam)
void torture_setup_tokens(const char *temp_dir,
const char *filename,
- const char object_name[])
+ const char object_name[],
+ const char *load_public)
{
char token_setup_start_cmd[1024] = {0};
int rc;
snprintf(token_setup_start_cmd, sizeof(token_setup_start_cmd),
- "%s/tests/pkcs11/setup-softhsm-tokens.sh %s %s %s",
+ "%s/tests/pkcs11/setup-softhsm-tokens.sh %s %s %s %s",
BINARYDIR,
temp_dir,
- filename, object_name);
+ filename,
+ object_name, load_public);
rc = system(token_setup_start_cmd);
assert_return_code(rc, errno);
diff --git a/tests/torture.h b/tests/torture.h
index 69ce5dc9..dc211443 100644
--- a/tests/torture.h
+++ b/tests/torture.h
@@ -125,7 +125,10 @@ int torture_server_port(void);
void torture_setup_socket_dir(void **state);
void torture_setup_sshd_server(void **state, bool pam);
-void torture_setup_tokens(const char *temp_dir, const char *filename, const char object_name[]);
+void torture_setup_tokens(const char *temp_dir,
+ const char *filename,
+ const char object_name[],
+ const char *load_public);
void torture_teardown_socket_dir(void **state);
void torture_teardown_sshd_server(void **state);
diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index 671e88c2..7ae846a4 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -10,6 +10,18 @@
extern LIBSSH_THREAD int ssh_log_level;
+#define USERNAME "testuser"
+#define PROXYCMD "ssh -q -W %h:%p gateway.example.com"
+#define ID_FILE "/etc/xxx"
+#define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha1"
+#define HOSTKEYALGORITHMS "ssh-ed25519,ecdsa-sha2-nistp521,ssh-rsa"
+#define PUBKEYACCEPTEDTYPES "rsa-sha2-512,ssh-rsa,ecdsa-sha2-nistp521"
+#define MACS "hmac-sha1,hmac-sha2-256,hmac-sha2-512,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com"
+#define USER_KNOWN_HOSTS "%d/my_known_hosts"
+#define GLOBAL_KNOWN_HOSTS "/etc/ssh/my_ssh_known_hosts"
+#define BIND_ADDRESS "::1"
+
+
#define LIBSSH_TESTCONFIG1 "libssh_testconfig1.tmp"
#define LIBSSH_TESTCONFIG2 "libssh_testconfig2.tmp"
#define LIBSSH_TESTCONFIG3 "libssh_testconfig3.tmp"
@@ -23,25 +35,177 @@ extern LIBSSH_THREAD int ssh_log_level;
#define LIBSSH_TESTCONFIG11 "libssh_testconfig11.tmp"
#define LIBSSH_TESTCONFIG12 "libssh_testconfig12.tmp"
#define LIBSSH_TESTCONFIGGLOB "libssh_testc*[36].tmp"
-#define LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES "libssh_test_PubkeyAcceptedKeyTypes.tmp"
+#define LIBSSH_TEST_PUBKEYTYPES "libssh_test_PubkeyAcceptedKeyTypes.tmp"
+#define LIBSSH_TEST_NONEWLINEEND "libssh_test_NoNewLineEnd.tmp"
+#define LIBSSH_TEST_NONEWLINEONELINE "libssh_test_NoNewLineOneline.tmp"
+
+#define LIBSSH_TESTCONFIG_STRING1 \
+ "User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n"
+
+#define LIBSSH_TESTCONFIG_STRING2 \
+ "Include "LIBSSH_TESTCONFIG3"\n" \
+ "ProxyCommand "PROXYCMD"\n\n"
+
+#define LIBSSH_TESTCONFIG_STRING3 \
+ "\n\nIdentityFile "ID_FILE"\n" \
+ "\n\nKexAlgorithms "KEXALGORITHMS"\n" \
+ "\n\nHostKeyAlgorithms "HOSTKEYALGORITHMS"\n" \
+ "\n\nPubkeyAcceptedTypes "PUBKEYACCEPTEDTYPES"\n" \
+ "\n\nMACs "MACS"\n"
+
+/* Multiple Port settings -> parsing returns early. */
+#define LIBSSH_TESTCONFIG_STRING4 \
+ "Port 123\nPort 456\n"
+
+/* Testing glob include */
+#define LIBSSH_TESTCONFIG_STRING5 \
+ "User "USERNAME"\nInclude "LIBSSH_TESTCONFIGGLOB"\n\n" \
+
+#define LIBSSH_TESTCONFIG_STRING6 \
+ "ProxyCommand "PROXYCMD"\n\n"
+
+/* new options */
+#define LIBSSH_TESTCONFIG_STRING7 \
+ "\tBindAddress "BIND_ADDRESS"\n" \
+ "\tConnectTimeout 30\n" \
+ "\tLogLevel DEBUG3\n" \
+ "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n" \
+ "\tCompression yes\n" \
+ "\tStrictHostkeyChecking no\n" \
+ "\tGSSAPIDelegateCredentials yes\n" \
+ "\tGSSAPIServerIdentity example.com\n" \
+ "\tGSSAPIClientIdentity home.sweet\n" \
+ "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n"
+
+/* authentication methods */
+#define LIBSSH_TESTCONFIG_STRING8 \
+ "Host gss\n" \
+ "\tGSSAPIAuthentication yes\n" \
+ "Host kbd\n" \
+ "\tKbdInteractiveAuthentication yes\n" \
+ "Host pass\n" \
+ "\tPasswordAuthentication yes\n" \
+ "Host pubkey\n" \
+ "\tPubkeyAuthentication yes\n" \
+ "Host nogss\n" \
+ "\tGSSAPIAuthentication no\n" \
+ "Host nokbd\n" \
+ "\tKbdInteractiveAuthentication no\n" \
+ "Host nopass\n" \
+ "\tPasswordAuthentication no\n" \
+ "Host nopubkey\n" \
+ "\tPubkeyAuthentication no\n"
+
+/* unsupported options and corner cases */
+#define LIBSSH_TESTCONFIG_STRING9 \
+ "\n" /* empty line */ \
+ "# comment line\n" \
+ " # comment line not starting with hash\n" \
+ "UnknownConfigurationOption yes\n" \
+ "GSSAPIKexAlgorithms yes\n" \
+ "ControlMaster auto\n" /* SOC_NA */ \
+ "VisualHostkey yes\n" /* SOC_UNSUPPORTED */ \
+ "HostName =equal.sign\n" /* valid */ \
+ "ProxyJump = many-spaces.com\n" /* valid */
+
+/* Match keyword */
+#define LIBSSH_TESTCONFIG_STRING10 \
+ "Match host example\n" \
+ "\tHostName example.com\n" \
+ "Match host example1,example2\n" \
+ "\tHostName exampleN\n" \
+ "Match user guest\n" \
+ "\tHostName guest.com\n" \
+ "Match user tester host testhost\n" \
+ "\tHostName testhost.com\n" \
+ "Match !user tester host testhost\n" \
+ "\tHostName nonuser-testhost.com\n" \
+ "Match all\n" \
+ "\tHostName all-matched.com\n" \
+ /* Unsupported options */ \
+ "Match originalhost example\n" \
+ "\tHostName original-example.com\n" \
+ "Match localuser guest\n" \
+ "\tHostName local-guest.com\n"
+
+/* ProxyJump */
+#define LIBSSH_TESTCONFIG_STRING11 \
+ "Host simple\n" \
+ "\tProxyJump jumpbox\n" \
+ "Host user\n" \
+ "\tProxyJump user@jumpbox\n" \
+ "Host port\n" \
+ "\tProxyJump jumpbox:2222\n" \
+ "Host two-step\n" \
+ "\tProxyJump u1@first:222,u2@second:33\n" \
+ "Host none\n" \
+ "\tProxyJump none\n" \
+ "Host only-command\n" \
+ "\tProxyCommand "PROXYCMD"\n" \
+ "\tProxyJump jumpbox\n" \
+ "Host only-jump\n" \
+ "\tProxyJump jumpbox\n" \
+ "\tProxyCommand "PROXYCMD"\n" \
+ "Host ipv6\n" \
+ "\tProxyJump [2620:52:0::fed]\n"
+
+/* RekeyLimit combinations */
+#define LIBSSH_TESTCONFIG_STRING12 \
+ "Host default\n" \
+ "\tRekeyLimit default none\n" \
+ "Host data1\n" \
+ "\tRekeyLimit 42G\n" \
+ "Host data2\n" \
+ "\tRekeyLimit 31M\n" \
+ "Host data3\n" \
+ "\tRekeyLimit 521K\n" \
+ "Host time1\n" \
+ "\tRekeyLimit default 3D\n" \
+ "Host time2\n" \
+ "\tRekeyLimit default 2h\n" \
+ "Host time3\n" \
+ "\tRekeyLimit default 160m\n" \
+ "Host time4\n" \
+ "\tRekeyLimit default 9600\n"
+
+#define LIBSSH_TEST_PUBKEYTYPES_STRING \
+ "PubkeyAcceptedKeyTypes "PUBKEYACCEPTEDTYPES"\n"
+
+#define LIBSSH_TEST_NONEWLINEEND_STRING \
+ "ConnectTimeout 30\n" \
+ "LogLevel DEBUG3"
+
+#define LIBSSH_TEST_NONEWLINEONELINE_STRING \
+ "ConnectTimeout 30"
-#define USERNAME "testuser"
-#define PROXYCMD "ssh -q -W %h:%p gateway.example.com"
-#define ID_FILE "/etc/xxx"
-#define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha1"
-#define HOSTKEYALGORITHMS "ssh-ed25519,ecdsa-sha2-nistp521,ssh-rsa"
-#define PUBKEYACCEPTEDTYPES "rsa-sha2-512,ssh-rsa,ecdsa-sha2-nistp521"
-#define MACS "hmac-sha1,hmac-sha2-256,hmac-sha2-512,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com"
-#define USER_KNOWN_HOSTS "%d/my_known_hosts"
-#define GLOBAL_KNOWN_HOSTS "/etc/ssh/my_ssh_known_hosts"
-#define BIND_ADDRESS "::1"
+/**
+ * @brief helper function loading configuration from either file or string
+ */
+static void _parse_config(ssh_session session,
+ const char *file, const char *string, int expected)
+{
+ int ret = -1;
+ /* make sure either config file or config string is given,
+ * not both */
+ assert_int_not_equal(file == NULL, string == NULL);
+ if (file != NULL) {
+ ret = ssh_config_parse_file(session, file);
+ } else if (string != NULL) {
+ ret = ssh_config_parse_string(session, string);
+ } else {
+ /* should not happen */
+ fail();
+ }
+
+ /* make sure parsing went as expected */
+ assert_ssh_return_code_equal(session, ret, expected);
+}
static int setup_config_files(void **state)
{
- ssh_session session;
- int verbosity;
+ (void) state; /* unused */
unlink(LIBSSH_TESTCONFIG1);
unlink(LIBSSH_TESTCONFIG2);
@@ -55,154 +219,68 @@ static int setup_config_files(void **state)
unlink(LIBSSH_TESTCONFIG10);
unlink(LIBSSH_TESTCONFIG11);
unlink(LIBSSH_TESTCONFIG12);
- unlink(LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES);
+ unlink(LIBSSH_TEST_PUBKEYTYPES);
+ unlink(LIBSSH_TEST_NONEWLINEEND);
+ unlink(LIBSSH_TEST_NONEWLINEONELINE);
torture_write_file(LIBSSH_TESTCONFIG1,
- "User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n");
+ LIBSSH_TESTCONFIG_STRING1);
torture_write_file(LIBSSH_TESTCONFIG2,
- "Include "LIBSSH_TESTCONFIG3"\n"
- "ProxyCommand "PROXYCMD"\n\n");
+ LIBSSH_TESTCONFIG_STRING2);
torture_write_file(LIBSSH_TESTCONFIG3,
- "\n\nIdentityFile "ID_FILE"\n"
- "\n\nKexAlgorithms "KEXALGORITHMS"\n"
- "\n\nHostKeyAlgorithms "HOSTKEYALGORITHMS"\n"
- "\n\nPubkeyAcceptedTypes "PUBKEYACCEPTEDTYPES"\n"
- "\n\nMACs "MACS"\n");
+ LIBSSH_TESTCONFIG_STRING3);
/* Multiple Port settings -> parsing returns early. */
torture_write_file(LIBSSH_TESTCONFIG4,
- "Port 123\nPort 456\n");
+ LIBSSH_TESTCONFIG_STRING4);
/* Testing glob include */
torture_write_file(LIBSSH_TESTCONFIG5,
- "User "USERNAME"\nInclude "LIBSSH_TESTCONFIGGLOB"\n\n");
+ LIBSSH_TESTCONFIG_STRING5);
torture_write_file(LIBSSH_TESTCONFIG6,
- "ProxyCommand "PROXYCMD"\n\n");
+ LIBSSH_TESTCONFIG_STRING6);
/* new options */
torture_write_file(LIBSSH_TESTCONFIG7,
- "\tBindAddress "BIND_ADDRESS"\n"
- "\tConnectTimeout 30\n"
- "\tLogLevel DEBUG3\n"
- "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n"
- "\tCompression yes\n"
- "\tStrictHostkeyChecking no\n"
- "\tGSSAPIDelegateCredentials yes\n"
- "\tGSSAPIServerIdentity example.com\n"
- "\tGSSAPIClientIdentity home.sweet\n"
- "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n");
+ LIBSSH_TESTCONFIG_STRING7);
/* authentication methods */
torture_write_file(LIBSSH_TESTCONFIG8,
- "Host gss\n"
- "\tGSSAPIAuthentication yes\n"
- "Host kbd\n"
- "\tKbdInteractiveAuthentication yes\n"
- "Host pass\n"
- "\tPasswordAuthentication yes\n"
- "Host pubkey\n"
- "\tPubkeyAuthentication yes\n"
- "Host nogss\n"
- "\tGSSAPIAuthentication no\n"
- "Host nokbd\n"
- "\tKbdInteractiveAuthentication no\n"
- "Host nopass\n"
- "\tPasswordAuthentication no\n"
- "Host nopubkey\n"
- "\tPubkeyAuthentication no\n");
+ LIBSSH_TESTCONFIG_STRING8);
/* unsupported options and corner cases */
torture_write_file(LIBSSH_TESTCONFIG9,
- "\n" /* empty line */
- "# comment line\n"
- " # comment line not starting with hash\n"
- "UnknownConfigurationOption yes\n"
- "GSSAPIKexAlgorithms yes\n"
- "ControlMaster auto\n" /* SOC_NA */
- "VisualHostkey yes\n" /* SOC_UNSUPPORTED */
- "HostName =equal.sign\n" /* valid */
- "ProxyJump = many-spaces.com\n" /* valid */
- "");
+ LIBSSH_TESTCONFIG_STRING9);
/* Match keyword */
torture_write_file(LIBSSH_TESTCONFIG10,
- "Match host example\n"
- "\tHostName example.com\n"
- "Match host example1,example2\n"
- "\tHostName exampleN\n"
- "Match user guest\n"
- "\tHostName guest.com\n"
- "Match user tester host testhost\n"
- "\tHostName testhost.com\n"
- "Match !user tester host testhost\n"
- "\tHostName nonuser-testhost.com\n"
- "Match all\n"
- "\tHostName all-matched.com\n"
- /* Unsupported options */
- "Match originalhost example\n"
- "\tHostName original-example.com\n"
- "Match localuser guest\n"
- "\tHostName local-guest.com\n"
- "");
+ LIBSSH_TESTCONFIG_STRING10);
/* ProxyJump */
torture_write_file(LIBSSH_TESTCONFIG11,
- "Host simple\n"
- "\tProxyJump jumpbox\n"
- "Host user\n"
- "\tProxyJump user@jumpbox\n"
- "Host port\n"
- "\tProxyJump jumpbox:2222\n"
- "Host two-step\n"
- "\tProxyJump u1@first:222,u2@second:33\n"
- "Host none\n"
- "\tProxyJump none\n"
- "Host only-command\n"
- "\tProxyCommand "PROXYCMD"\n"
- "\tProxyJump jumpbox\n"
- "Host only-jump\n"
- "\tProxyJump jumpbox\n"
- "\tProxyCommand "PROXYCMD"\n"
- "Host ipv6\n"
- "\tProxyJump [2620:52:0::fed]\n"
- "");
+ LIBSSH_TESTCONFIG_STRING11);
/* RekeyLimit combinations */
torture_write_file(LIBSSH_TESTCONFIG12,
- "Host default\n"
- "\tRekeyLimit default none\n"
- "Host data1\n"
- "\tRekeyLimit 42G\n"
- "Host data2\n"
- "\tRekeyLimit 31M\n"
- "Host data3\n"
- "\tRekeyLimit 521K\n"
- "Host time1\n"
- "\tRekeyLimit default 3D\n"
- "Host time2\n"
- "\tRekeyLimit default 2h\n"
- "Host time3\n"
- "\tRekeyLimit default 160m\n"
- "Host time4\n"
- "\tRekeyLimit default 9600\n"
- "");
-
- torture_write_file(LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES,
- "PubkeyAcceptedKeyTypes "PUBKEYACCEPTEDTYPES"\n");
+ LIBSSH_TESTCONFIG_STRING12);
- session = ssh_new();
+ torture_write_file(LIBSSH_TEST_PUBKEYTYPES,
+ LIBSSH_TEST_PUBKEYTYPES_STRING);
- verbosity = torture_libssh_verbosity();
- ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+ torture_write_file(LIBSSH_TEST_NONEWLINEEND,
+ LIBSSH_TEST_NONEWLINEEND_STRING);
- *state = session;
+ torture_write_file(LIBSSH_TEST_NONEWLINEONELINE,
+ LIBSSH_TEST_NONEWLINEONELINE_STRING);
return 0;
}
-static int teardown(void **state)
+static int teardown_config_files(void **state)
{
+ (void) state; /* unused */
+
unlink(LIBSSH_TESTCONFIG1);
unlink(LIBSSH_TESTCONFIG2);
unlink(LIBSSH_TESTCONFIG3);
@@ -215,27 +293,47 @@ static int teardown(void **state)
unlink(LIBSSH_TESTCONFIG10);
unlink(LIBSSH_TESTCONFIG11);
unlink(LIBSSH_TESTCONFIG12);
- unlink(LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES);
+ unlink(LIBSSH_TEST_PUBKEYTYPES);
+ return 0;
+}
+
+static int setup(void **state)
+{
+ ssh_session session = NULL;
+ int verbosity;
+
+ session = ssh_new();
+
+ verbosity = torture_libssh_verbosity();
+ ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+
+ *state = session;
+
+ return 0;
+}
+
+static int teardown(void **state)
+{
ssh_free(*state);
return 0;
}
/**
- * @brief tests ssh_config_parse_file with Include directives
+ * @brief tests ssh config parsing with Include directives
*/
-static void torture_config_from_file(void **state) {
- ssh_session session = *state;
+static void torture_config_include(void **state,
+ const char *file, const char *string)
+{
int ret;
char *v = NULL;
char *fips_algos = NULL;
+ ssh_session session = *state;
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG1);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
/* Test the variable presence */
-
ret = ssh_options_get(session, SSH_OPTIONS_PROXYCOMMAND, &v);
assert_true(ret == 0);
assert_non_null(v);
@@ -264,7 +362,8 @@ static void torture_config_from_file(void **state) {
SAFE_FREE(fips_algos);
fips_algos = ssh_keep_fips_algos(SSH_HOSTKEYS, HOSTKEYALGORITHMS);
assert_non_null(fips_algos);
- assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], fips_algos);
+ assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS],
+ fips_algos);
SAFE_FREE(fips_algos);
fips_algos = ssh_keep_fips_algos(SSH_HOSTKEYS, PUBKEYACCEPTEDTYPES);
assert_non_null(fips_algos);
@@ -272,19 +371,24 @@ static void torture_config_from_file(void **state) {
SAFE_FREE(fips_algos);
fips_algos = ssh_keep_fips_algos(SSH_MAC_C_S, MACS);
assert_non_null(fips_algos);
- assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], fips_algos);
+ assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S],
+ fips_algos);
SAFE_FREE(fips_algos);
fips_algos = ssh_keep_fips_algos(SSH_MAC_S_C, MACS);
assert_non_null(fips_algos);
- assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C], fips_algos);
+ assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C],
+ fips_algos);
SAFE_FREE(fips_algos);
} else {
assert_non_null(session->opts.wanted_methods[SSH_KEX]);
- assert_string_equal(session->opts.wanted_methods[SSH_KEX], KEXALGORITHMS);
+ assert_string_equal(session->opts.wanted_methods[SSH_KEX],
+ KEXALGORITHMS);
assert_non_null(session->opts.wanted_methods[SSH_HOSTKEYS]);
- assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], HOSTKEYALGORITHMS);
+ assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS],
+ HOSTKEYALGORITHMS);
assert_non_null(session->opts.pubkey_accepted_types);
- assert_string_equal(session->opts.pubkey_accepted_types, PUBKEYACCEPTEDTYPES);
+ assert_string_equal(session->opts.pubkey_accepted_types,
+ PUBKEYACCEPTEDTYPES);
assert_non_null(session->opts.wanted_methods[SSH_MAC_S_C]);
assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], MACS);
assert_non_null(session->opts.wanted_methods[SSH_MAC_S_C]);
@@ -293,27 +397,49 @@ static void torture_config_from_file(void **state) {
}
/**
+ * @brief tests ssh_config_parse_file with Include directives from file
+ */
+static void torture_config_include_file(void **state)
+{
+ torture_config_include(state, LIBSSH_TESTCONFIG1, NULL);
+}
+
+/**
+ * @brief tests ssh_config_parse_string with Include directives from string
+ */
+static void torture_config_include_string(void **state)
+{
+ torture_config_include(state, NULL, LIBSSH_TESTCONFIG_STRING1);
+}
+
+/**
* @brief tests ssh_config_parse_file with multiple Port settings.
*/
-static void torture_config_double_ports(void **state) {
- ssh_session session = *state;
- int ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG4);
- assert_true(ret == 0);
+static void torture_config_double_ports_file(void **state)
+{
+ _parse_config(*state, LIBSSH_TESTCONFIG4, NULL, SSH_OK);
}
-static void torture_config_glob(void **state) {
- ssh_session session = *state;
- int ret;
+/**
+ * @brief tests ssh_config_parse_string with multiple Port settings.
+ */
+static void torture_config_double_ports_string(void **state)
+{
+ _parse_config(*state, NULL, LIBSSH_TESTCONFIG_STRING4, SSH_OK);
+}
+
+static void torture_config_glob(void **state,
+ const char *file, const char *string)
+{
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
+ int ret;
char *v;
-#endif /* HAVE_GLOB && HAVE_GLOB_GL_FLAGS_MEMBER */
+ ssh_session session = *state;
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG5);
- assert_true(ret == 0); /* non-existing files should not error */
+ _parse_config(session, file, string, SSH_OK);
/* Test the variable presence */
-#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
ret = ssh_options_get(session, SSH_OPTIONS_PROXYCOMMAND, &v);
assert_true(ret == 0);
assert_non_null(v);
@@ -330,16 +456,25 @@ static void torture_config_glob(void **state) {
#endif /* HAVE_GLOB && HAVE_GLOB_GL_FLAGS_MEMBER */
}
+static void torture_config_glob_file(void **state)
+{
+ torture_config_glob(state, LIBSSH_TESTCONFIG5, NULL);
+}
+
+static void torture_config_glob_string(void **state)
+{
+ torture_config_glob(state, NULL, LIBSSH_TESTCONFIG_STRING5);
+}
+
/**
* @brief Verify the new options are passed from configuration
*/
-static void torture_config_new(void **state)
+static void torture_config_new(void ** state,
+ const char *file, const char *string)
{
ssh_session session = *state;
- int ret = 0;
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG7);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.knownhosts, USER_KNOWN_HOSTS);
assert_string_equal(session->opts.global_knownhosts, GLOBAL_KNOWN_HOSTS);
@@ -363,33 +498,40 @@ static void torture_config_new(void **state)
assert_int_equal(session->common.log_verbosity, SSH_LOG_TRACE);
}
+static void torture_config_new_file(void **state)
+{
+ torture_config_new(state, LIBSSH_TESTCONFIG7, NULL);
+}
+
+static void torture_config_new_string(void **state)
+{
+ torture_config_new(state, NULL, LIBSSH_TESTCONFIG_STRING7);
+}
+
/**
* @brief Verify the authentication methods from configuration are effective
*/
-static void torture_config_auth_methods(void **state) {
+static void torture_config_auth_methods(void **state,
+ const char *file, const char *string)
+{
ssh_session session = *state;
- int ret = 0;
/* gradually disable all the methods based on different hosts */
ssh_options_set(session, SSH_OPTIONS_HOST, "nogss");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_false(session->opts.flags & SSH_OPT_FLAG_GSSAPI_AUTH);
assert_true(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH);
ssh_options_set(session, SSH_OPTIONS_HOST, "nokbd");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_false(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH);
ssh_options_set(session, SSH_OPTIONS_HOST, "nopass");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_false(session->opts.flags & SSH_OPT_FLAG_PASSWORD_AUTH);
ssh_options_set(session, SSH_OPTIONS_HOST, "nopubkey");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_false(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH);
/* no method should be left enabled */
@@ -398,39 +540,55 @@ static void torture_config_auth_methods(void **state) {
/* gradually enable them again */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "gss");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_true(session->opts.flags & SSH_OPT_FLAG_GSSAPI_AUTH);
assert_false(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH);
ssh_options_set(session, SSH_OPTIONS_HOST, "kbd");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_true(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH);
ssh_options_set(session, SSH_OPTIONS_HOST, "pass");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_true(session->opts.flags & SSH_OPT_FLAG_PASSWORD_AUTH);
ssh_options_set(session, SSH_OPTIONS_HOST, "pubkey");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
- assert_true(ret == 0);
+ _parse_config(session, file, string, SSH_OK);
assert_true(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH);
}
/**
+ * @brief Verify the authentication methods from configuration file
+ * are effective
+ */
+static void torture_config_auth_methods_file(void **state)
+{
+ torture_config_auth_methods(state, LIBSSH_TESTCONFIG8, NULL);
+}
+
+/**
+ * @brief Verify the authentication methods from configuration string
+ * are effective
+ */
+static void torture_config_auth_methods_string(void **state)
+{
+ torture_config_auth_methods(state, NULL, LIBSSH_TESTCONFIG_STRING8);
+}
+
+/**
* @brief Verify the configuration parser does not choke on unknown
* or unsupported configuration options
*/
-static void torture_config_unknown(void **state) {
+static void torture_config_unknown(void **state,
+ const char *file, const char *string)
+{
ssh_session session = *state;
int ret = 0;
/* test corner cases */
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG9);
- assert_true(ret == 0);
- assert_string_equal(session->opts.ProxyCommand, "ssh -W [%h]:%p many-spaces.com");
+ _parse_config(session, file, string, SSH_OK);
+ assert_string_equal(session->opts.ProxyCommand,
+ "ssh -W [%h]:%p many-spaces.com");
assert_string_equal(session->opts.host, "equal.sign");
ret = ssh_config_parse_file(session, "/etc/ssh/ssh_config");
@@ -439,128 +597,155 @@ static void torture_config_unknown(void **state) {
assert_true(ret == 0);
}
+/**
+ * @brief Verify the configuration parser does not choke on unknown
+ * or unsupported configuration options in configuration file
+ */
+static void torture_config_unknown_file(void **state)
+{
+ torture_config_unknown(state, LIBSSH_TESTCONFIG9, NULL);
+}
+
+/**
+ * @brief Verify the configuration parser does not choke on unknown
+ * or unsupported configuration options in configuration string
+ */
+static void torture_config_unknown_string(void **state)
+{
+ torture_config_unknown(state, NULL, LIBSSH_TESTCONFIG_STRING9);
+}
/**
* @brief Verify the configuration parser accepts Match keyword with
* full OpenSSH syntax.
*/
-static void torture_config_match(void **state)
+static void torture_config_match(void **state,
+ const char *file, const char *string)
{
ssh_session session = *state;
char *localuser = NULL;
- char config[1024];
- int ret = 0;
+ const char *config;
+ char config_string[1024];
/* Without any settings we should get all-matched.com hostname */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "unmatched");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "all-matched.com");
/* Hostname example does simple hostname matching */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "example");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "example.com");
/* We can match also both hosts from a comma separated list */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "example1");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "exampleN");
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "example2");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "exampleN");
/* We can match by user */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_USER, "guest");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "guest.com");
/* We can combine two options on a single line to match both of them */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_USER, "tester");
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "testhost.com");
/* We can also negate conditions */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_USER, "not-tester");
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "nonuser-testhost.com");
+ /* In this part, we try various other config files and strings. */
+
/* Match final is not completely supported, but should do quite much the
* same as "match all". The trailing "all" is not mandatory. */
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match final all\n"
- "\tHostName final-all.com\n"
- "");
+ config = "Match final all\n"
+ "\tHostName final-all.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "final-all.com");
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match final\n"
- "\tHostName final.com\n"
- "");
+ config = "Match final\n"
+ "\tHostName final.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "final.com");
- /* Match canonical is not completely supported, but should do quite much the
- * same as "match all". The trailing "all" is not mandatory. */
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match canonical all\n"
- "\tHostName canonical-all.com\n"
- "");
+ /* Match canonical is not completely supported, but should do quite
+ * much the same as "match all". The trailing "all" is not mandatory. */
+ config = "Match canonical all\n"
+ "\tHostName canonical-all.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "canonical-all.com");
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match canonical all\n"
- "\tHostName canonical.com\n"
- "");
+ config = "Match canonical all\n"
+ "\tHostName canonical.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "canonical.com");
localuser = ssh_get_local_username();
assert_non_null(localuser);
- snprintf(config, sizeof(config),
+ snprintf(config_string, sizeof(config_string),
"Match localuser %s\n"
- "\tHostName otherhost\n"
- "", localuser);
+ "\tHostName otherhost\n",
+ localuser);
+ config = config_string;
free(localuser);
- torture_write_file(LIBSSH_TESTCONFIG10, config);
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.host, "otherhost");
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match exec true\n"
- "\tHostName execed-true.com\n"
- "");
+ config = "Match exec true\n"
+ "\tHostName execed-true.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
#ifdef _WIN32
/* The match exec is not supported on windows at this moment */
assert_string_equal(session->opts.host, "otherhost");
@@ -568,13 +753,15 @@ static void torture_config_match(void **state)
assert_string_equal(session->opts.host, "execed-true.com");
#endif
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match !exec false\n"
- "\tHostName execed-false.com\n"
- "");
+ config = "Match !exec false\n"
+ "\tHostName execed-false.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
#ifdef _WIN32
/* The match exec is not supported on windows at this moment */
assert_string_equal(session->opts.host, "otherhost");
@@ -582,13 +769,15 @@ static void torture_config_match(void **state)
assert_string_equal(session->opts.host, "execed-false.com");
#endif
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match exec \"test 1 -eq 1\"\n"
- "\tHostName execed-arguments.com\n"
- "");
+ config = "Match exec \"test 1 -eq 1\"\n"
+ "\tHostName execed-arguments.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
#ifdef _WIN32
/* The match exec is not supported on windows at this moment */
assert_string_equal(session->opts.host, "otherhost");
@@ -598,355 +787,435 @@ static void torture_config_match(void **state)
/* Try to create some invalid configurations */
/* Missing argument to Match*/
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match\n"
- "\tHost missing.com\n"
- "");
+ config = "Match\n"
+ "\tHost missing.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing argument to unsupported option originalhost */
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match originalhost\n"
- "\tHost originalhost.com\n"
- "");
+ config = "Match originalhost\n"
+ "\tHost originalhost.com\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing argument to option localuser */
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match localuser\n"
- "\tUser localuser2\n"
- "");
+ config = "Match localuser\n"
+ "\tUser localuser2\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing argument to option user */
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match user\n"
- "\tUser user2\n"
- "");
+ config = "Match user\n"
+ "\tUser user2\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing argument to option host */
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match host\n"
- "\tUser host2\n"
- "");
+ config = "Match host\n"
+ "\tUser host2\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing argument to option exec */
- torture_write_file(LIBSSH_TESTCONFIG10,
- "Match exec\n"
- "\tUser exec\n"
- "");
+ config = "Match exec\n"
+ "\tUser exec\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
+}
+
+/**
+ * @brief Verify the configuration parser accepts Match keyword with
+ * full OpenSSH syntax through configuration file.
+ */
+static void torture_config_match_file(void **state)
+{
+ torture_config_match(state, LIBSSH_TESTCONFIG10, NULL);
+}
+
+/**
+ * @brief Verify the configuration parser accepts Match keyword with
+ * full OpenSSH syntax through configuration string.
+ */
+static void torture_config_match_string(void **state)
+{
+ torture_config_match(state, NULL, LIBSSH_TESTCONFIG_STRING10);
}
/**
* @brief Verify we can parse ProxyJump configuration option
*/
-static void torture_config_proxyjump(void **state) {
+static void torture_config_proxyjump(void **state,
+ const char *file, const char *string)
+{
ssh_session session = *state;
- int ret = 0;
+ const char *config;
/* Simplest version with just a hostname */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "simple");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.ProxyCommand, "ssh -W [%h]:%p jumpbox");
/* With username */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "user");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.ProxyCommand,
"ssh -l user -W [%h]:%p jumpbox");
/* With port */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "port");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.ProxyCommand,
"ssh -p 2222 -W [%h]:%p jumpbox");
/* Two step jump */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "two-step");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.ProxyCommand,
"ssh -l u1 -p 222 -J u2@second:33 -W [%h]:%p first");
/* none */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "none");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_true(session->opts.ProxyCommand == NULL);
/* If also ProxyCommand is specifed, the first is applied */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "only-command");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.ProxyCommand, PROXYCMD);
/* If also ProxyCommand is specifed, the first is applied */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "only-jump");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.ProxyCommand,
"ssh -W [%h]:%p jumpbox");
/* IPv6 address */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "ipv6");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_string_equal(session->opts.ProxyCommand,
"ssh -W [%h]:%p 2620:52:0::fed");
+ /* In this part, we try various other config files and strings. */
+
/* Try to create some invalid configurations */
/* Non-numeric port */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host bad-port\n"
- "\tProxyJump jumpbox:22bad22\n"
- "");
+ config = "Host bad-port\n"
+ "\tProxyJump jumpbox:22bad22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "bad-port");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Too many @ */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host bad-hostname\n"
- "\tProxyJump user@principal.com@jumpbox:22\n"
- "");
+ config = "Host bad-hostname\n"
+ "\tProxyJump user@principal.com@jumpbox:22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Braces mismatch in hostname */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host mismatch\n"
- "\tProxyJump [::1\n"
- "");
+ config = "Host mismatch\n"
+ "\tProxyJump [::1\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "mismatch");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Bad host-port separator */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host beef\n"
- "\tProxyJump [dead::beef]::22\n"
- "");
+ config = "Host beef\n"
+ "\tProxyJump [dead::beef]::22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "beef");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing hostname */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host no-host\n"
- "\tProxyJump user@:22\n"
- "");
+ config = "Host no-host\n"
+ "\tProxyJump user@:22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "no-host");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing user */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host no-user\n"
- "\tProxyJump @host:22\n"
- "");
+ config = "Host no-user\n"
+ "\tProxyJump @host:22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "no-user");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing port */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host no-port\n"
- "\tProxyJump host:\n"
- "");
+ config = "Host no-port\n"
+ "\tProxyJump host:\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "no-port");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Non-numeric port in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host bad-port-2\n"
- "\tProxyJump localhost,jumpbox:22bad22\n"
- "");
+ config = "Host bad-port-2\n"
+ "\tProxyJump localhost,jumpbox:22bad22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "bad-port-2");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Too many @ in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host bad-hostname\n"
- "\tProxyJump localhost,user@principal.com@jumpbox:22\n"
- "");
+ config = "Host bad-hostname\n"
+ "\tProxyJump localhost,user@principal.com@jumpbox:22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Braces mismatch in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host mismatch\n"
- "\tProxyJump localhost,[::1:20\n"
- "");
+ config = "Host mismatch\n"
+ "\tProxyJump localhost,[::1:20\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "mismatch");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Bad host-port separator in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host beef\n"
- "\tProxyJump localhost,[dead::beef]::22\n"
- "");
+ config = "Host beef\n"
+ "\tProxyJump localhost,[dead::beef]::22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "beef");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing hostname in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host no-host\n"
- "\tProxyJump localhost,user@:22\n"
- "");
+ config = "Host no-host\n"
+ "\tProxyJump localhost,user@:22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "no-host");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing user in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host no-user\n"
- "\tProxyJump localhost,@host:22\n"
- "");
+ config = "Host no-user\n"
+ "\tProxyJump localhost,@host:22\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "no-user");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
/* Missing port in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host no-port\n"
- "\tProxyJump localhost,host:\n"
- "");
+ config = "Host no-port\n"
+ "\tProxyJump localhost,host:\n";
+ if (file != NULL) {
+ torture_write_file(file, config);
+ } else {
+ string = config;
+ }
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "no-port");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ _parse_config(session, file, string, SSH_ERROR);
+}
+
+/**
+ * @brief Verify we can parse ProxyJump configuration option from file
+ */
+static void torture_config_proxyjump_file(void **state)
+{
+ torture_config_proxyjump(state, LIBSSH_TESTCONFIG11, NULL);
+}
+
+/**
+ * @brief Verify we can parse ProxyJump configuration option from string
+ */
+static void torture_config_proxyjump_string(void **state)
+{
+ torture_config_proxyjump(state, NULL, LIBSSH_TESTCONFIG_STRING11);
}
/**
* @brief Verify the configuration parser handles all the possible
* versions of RekeyLimit configuration option.
*/
-static void torture_config_rekey(void **state)
+static void torture_config_rekey(void **state,
+ const char *file, const char *string)
{
ssh_session session = *state;
- int ret = 0;
/* Default values */
ssh_options_set(session, SSH_OPTIONS_HOST, "default");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_int_equal(session->opts.rekey_data, 0);
assert_int_equal(session->opts.rekey_time, 0);
/* 42 GB */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "data1");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
- assert_int_equal(session->opts.rekey_data, (uint64_t) 42 * 1024 * 1024 * 1024);
+ _parse_config(session, file, string, SSH_OK);
+ assert_int_equal(session->opts.rekey_data,
+ (uint64_t) 42 * 1024 * 1024 * 1024);
assert_int_equal(session->opts.rekey_time, 0);
/* 41 MB */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "data2");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_int_equal(session->opts.rekey_data, 31 * 1024 * 1024);
assert_int_equal(session->opts.rekey_time, 0);
/* 521 KB */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "data3");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_int_equal(session->opts.rekey_data, 521 * 1024);
assert_int_equal(session->opts.rekey_time, 0);
/* default 3D */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "time1");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_int_equal(session->opts.rekey_data, 0);
assert_int_equal(session->opts.rekey_time, 3 * 24 * 60 * 60 * 1000);
/* default 2h */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "time2");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_int_equal(session->opts.rekey_data, 0);
assert_int_equal(session->opts.rekey_time, 2 * 60 * 60 * 1000);
/* default 160m */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "time3");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_int_equal(session->opts.rekey_data, 0);
assert_int_equal(session->opts.rekey_time, 160 * 60 * 1000);
/* default 9600 [s] */
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "time4");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12);
- assert_ssh_return_code(session, ret);
+ _parse_config(session, file, string, SSH_OK);
assert_int_equal(session->opts.rekey_data, 0);
assert_int_equal(session->opts.rekey_time, 9600 * 1000);
}
/**
- * @brief test ssh_config_parse_file with PubkeyAcceptedKeyTypes
+ * @brief Verify the configuration parser handles all the possible
+ * versions of RekeyLimit configuration option in file
+ */
+static void torture_config_rekey_file(void **state)
+{
+ torture_config_rekey(state, LIBSSH_TESTCONFIG12, NULL);
+}
+
+/**
+ * @brief Verify the configuration parser handles all the possible
+ * versions of RekeyLimit configuration option in string
+ */
+static void torture_config_rekey_string(void **state)
+{
+ torture_config_rekey(state, NULL, LIBSSH_TESTCONFIG_STRING12);
+}
+
+/**
+ * @brief test PubkeyAcceptedKeyTypes helper function
*/
-static void torture_config_pubkeyacceptedkeytypes(void **state)
+static void torture_config_pubkeytypes(void **state,
+ const char *file, const char *string)
{
ssh_session session = *state;
- int rc;
char *fips_algos;
- rc = ssh_config_parse_file(session, LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES);
- assert_int_equal(rc, SSH_OK);
+ _parse_config(session, file, string, SSH_OK);
if (ssh_fips_mode()) {
fips_algos = ssh_keep_fips_algos(SSH_HOSTKEYS, PUBKEYACCEPTEDTYPES);
@@ -954,10 +1223,85 @@ static void torture_config_pubkeyacceptedkeytypes(void **state)
assert_string_equal(session->opts.pubkey_accepted_types, fips_algos);
SAFE_FREE(fips_algos);
} else {
- assert_string_equal(session->opts.pubkey_accepted_types, PUBKEYACCEPTEDTYPES);
+ assert_string_equal(session->opts.pubkey_accepted_types,
+ PUBKEYACCEPTEDTYPES);
}
}
+/**
+ * @brief test parsing PubkeyAcceptedKeyTypes from file
+ */
+static void torture_config_pubkeytypes_file(void **state)
+{
+ torture_config_pubkeytypes(state, LIBSSH_TEST_PUBKEYTYPES, NULL);
+}
+
+/**
+ * @brief test parsing PubkeyAcceptedKeyTypes from string
+ */
+static void torture_config_pubkeytypes_string(void **state)
+{
+ torture_config_pubkeytypes(state, NULL, LIBSSH_TEST_PUBKEYTYPES_STRING);
+}
+
+/**
+ * @brief Verify the configuration parser handles
+ * missing newline in the end
+ */
+static void torture_config_nonewlineend(void **state,
+ const char *file, const char *string)
+{
+ _parse_config(*state, file, string, SSH_OK);
+}
+
+/**
+ * @brief Verify the configuration parser handles
+ * missing newline in the end of file
+ */
+static void torture_config_nonewlineend_file(void **state)
+{
+ torture_config_nonewlineend(state, LIBSSH_TEST_NONEWLINEEND, NULL);
+}
+
+/**
+ * @brief Verify the configuration parser handles
+ * missing newline in the end of string
+ */
+static void torture_config_nonewlineend_string(void **state)
+{
+ torture_config_nonewlineend(state, NULL, LIBSSH_TEST_NONEWLINEEND_STRING);
+}
+
+/**
+ * @brief Verify the configuration parser handles
+ * missing newline in the end
+ */
+static void torture_config_nonewlineoneline(void **state,
+ const char *file,
+ const char *string)
+{
+ _parse_config(*state, file, string, SSH_OK);
+}
+
+/**
+ * @brief Verify the configuration parser handles
+ * missing newline in the end of file
+ */
+static void torture_config_nonewlineoneline_file(void **state)
+{
+ torture_config_nonewlineend(state, LIBSSH_TEST_NONEWLINEONELINE, NULL);
+}
+
+/**
+ * @brief Verify the configuration parser handles
+ * missing newline in the end of string
+ */
+static void torture_config_nonewlineoneline_string(void **state)
+{
+ torture_config_nonewlineoneline(state,
+ NULL, LIBSSH_TEST_NONEWLINEONELINE_STRING);
+}
+
/* ssh_config_get_cmd() does three things:
* * Strips leading whitespace
* * Terminate the characted on the end of next quotes-enclosed string
@@ -994,7 +1338,8 @@ static void torture_config_parser_get_cmd(void **state)
assert_string_equal(tok, "something");
assert_int_equal(*p, '\0');
- /* But it does not split tokens by whitespace if they are not quoted, which is weird */
+ /* But it does not split tokens by whitespace
+ * if they are not quoted, which is weird */
strncpy(data, "multi string something\n", sizeof(data));
p = data;
tok = ssh_config_get_cmd(&p);
@@ -1004,7 +1349,8 @@ static void torture_config_parser_get_cmd(void **state)
/* ssh_config_get_token() should behave as expected
* * Strip leading whitespace
- * * Return first token separated by whitespace or equal sign, respecting quotes!
+ * * Return first token separated by whitespace or equal sign,
+ * respecting quotes!
*/
static void torture_config_parser_get_token(void **state)
{
@@ -1206,7 +1552,8 @@ static void torture_config_match_pattern(void **state)
assert_int_equal(rv, 1);
rv = match_pattern("aa", "?", MAX_MATCH_RECURSION);
assert_int_equal(rv, 0);
- rv = match_pattern("?", "a", MAX_MATCH_RECURSION); /* Wildcard in search string */
+ /* Wildcard in search string */
+ rv = match_pattern("?", "a", MAX_MATCH_RECURSION);
assert_int_equal(rv, 0);
rv = match_pattern("?", "?", MAX_MATCH_RECURSION);
assert_int_equal(rv, 1);
@@ -1216,7 +1563,8 @@ static void torture_config_match_pattern(void **state)
assert_int_equal(rv, 1);
rv = match_pattern("aa", "*", MAX_MATCH_RECURSION);
assert_int_equal(rv, 1);
- rv = match_pattern("*", "a", MAX_MATCH_RECURSION); /* Wildcard in search string */
+ /* Wildcard in search string */
+ rv = match_pattern("*", "a", MAX_MATCH_RECURSION);
assert_int_equal(rv, 0);
rv = match_pattern("*", "*", MAX_MATCH_RECURSION);
assert_int_equal(rv, 1);
@@ -1256,34 +1604,78 @@ static void torture_config_match_pattern(void **state)
/* Limit the maximum recursion */
rv = match_pattern("hostname", "*p*a*t*t*e*r*n*", 5);
assert_int_equal(rv, 0);
- rv = match_pattern("pattern", "*p*a*t*t*e*r*n*", 5); /* Too much recursion */
+ /* Too much recursion */
+ rv = match_pattern("pattern", "*p*a*t*t*e*r*n*", 5);
assert_int_equal(rv, 0);
}
-int torture_run_tests(void) {
+int torture_run_tests(void)
+{
int rc;
struct CMUnitTest tests[] = {
- cmocka_unit_test(torture_config_from_file),
- cmocka_unit_test(torture_config_double_ports),
- cmocka_unit_test(torture_config_glob),
- cmocka_unit_test(torture_config_new),
- cmocka_unit_test(torture_config_auth_methods),
- cmocka_unit_test(torture_config_unknown),
- cmocka_unit_test(torture_config_match),
- cmocka_unit_test(torture_config_proxyjump),
- cmocka_unit_test(torture_config_rekey),
- cmocka_unit_test(torture_config_pubkeyacceptedkeytypes),
- cmocka_unit_test(torture_config_parser_get_cmd),
- cmocka_unit_test(torture_config_parser_get_token),
- cmocka_unit_test(torture_config_match_pattern),
+ cmocka_unit_test_setup_teardown(torture_config_include_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_include_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_double_ports_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_double_ports_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_glob_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_glob_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_new_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_new_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_auth_methods_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_auth_methods_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_unknown_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_unknown_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_match_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_match_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_proxyjump_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_proxyjump_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_rekey_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_rekey_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_pubkeytypes_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_pubkeytypes_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_nonewlineend_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_nonewlineend_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_nonewlineoneline_file,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_nonewlineoneline_string,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_parser_get_cmd,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_parser_get_token,
+ setup, teardown),
+ cmocka_unit_test_setup_teardown(torture_config_match_pattern,
+ setup, teardown),
};
ssh_init();
torture_filter_tests(tests);
- rc = cmocka_run_group_tests(tests, setup_config_files, teardown);
+ rc = cmocka_run_group_tests(tests,
+ setup_config_files, teardown_config_files);
ssh_finalize();
return rc;
}
diff --git a/tests/unittests/torture_pki_ecdsa_uri.c b/tests/unittests/torture_pki_ecdsa_uri.c
index 78772db7..0fa6ecf3 100644
--- a/tests/unittests/torture_pki_ecdsa_uri.c
+++ b/tests/unittests/torture_pki_ecdsa_uri.c
@@ -20,6 +20,9 @@
#define PRIV_URI_FMT_384 "pkcs11:token=ecdsa384;object=ecdsa384;type=private?pin-value=1234"
#define PUB_URI_FMT_521 "pkcs11:token=ecdsa521;object=ecdsa521;type=public"
#define PRIV_URI_FMT_521 "pkcs11:token=ecdsa521;object=ecdsa521;type=private?pin-value=1234"
+#define PRIV_URI_FMT_256_NO_PUB "pkcs11:token=ecdsa256_no_pub_uri;object=ecdsa256_no_pub_uri;type=private?pin-value=1234"
+#define PRIV_URI_FMT_384_NO_PUB "pkcs11:token=ecdsa384_no_pub_uri;object=ecdsa384_no_pub_uri;type=private?pin-value=1234"
+#define PRIV_URI_FMT_521_NO_PUB "pkcs11:token=ecdsa521_no_pub_uri;object=ecdsa521_no_pub_uri;type=private?pin-value=1234"
/** PKCS#11 URIs with invalid fields**/
@@ -37,7 +40,7 @@ struct pki_st {
enum ssh_keytypes_e type;
};
-static int setup_tokens_ecdsa(void **state, int ecdsa_bits, const char *obj_tempname)
+static int setup_tokens_ecdsa(void **state, int ecdsa_bits, const char *obj_tempname, const char *load_public)
{
struct pki_st *test_state = *state;
@@ -67,7 +70,7 @@ static int setup_tokens_ecdsa(void **state, int ecdsa_bits, const char *obj_temp
torture_get_testkey(test_state->type, 0));
torture_write_file(pub_filename,
torture_get_testkey_pub_pem(test_state->type));
- torture_setup_tokens(cwd, priv_filename, obj_tempname);
+ torture_setup_tokens(cwd, priv_filename, obj_tempname, load_public);
return 0;
}
@@ -99,9 +102,12 @@ static int setup_directory_structure(void **state)
snprintf(conf_path, sizeof(conf_path), "%s/softhsm.conf", test_state->temp_dir);
setenv("SOFTHSM2_CONF", conf_path, 1);
- setup_tokens_ecdsa(state, 256, "ecdsa256");
- setup_tokens_ecdsa(state, 384, "ecdsa384");
- setup_tokens_ecdsa(state, 521, "ecdsa521");
+ setup_tokens_ecdsa(state, 256, "ecdsa256", "1");
+ setup_tokens_ecdsa(state, 384, "ecdsa384", "1");
+ setup_tokens_ecdsa(state, 521, "ecdsa521", "1");
+ setup_tokens_ecdsa(state, 256, "ecdsa256_no_pub_uri", "0");
+ setup_tokens_ecdsa(state, 384, "ecdsa384_no_pub_uri", "0");
+ setup_tokens_ecdsa(state, 521, "ecdsa521_no_pub_uri", "0");
return 0;
}
@@ -161,6 +167,7 @@ static void torture_pki_ecdsa_publickey_from_privatekey_uri(void **state, const
int rc;
ssh_key privkey = NULL;
ssh_key pubkey = NULL;
+ ssh_string pblob = NULL;
char pubkey_original[4096] = {0};
char pubkey_generated[4096] = {0};
char convert_key_to_pem[4096];
@@ -177,6 +184,11 @@ static void torture_pki_ecdsa_publickey_from_privatekey_uri(void **state, const
assert_true(rc == 0);
assert_non_null(privkey);
+ rc = ssh_pki_export_pubkey_blob(privkey, &pblob);
+ assert_return_code(rc, errno);
+ assert_true(rc == SSH_OK);
+ assert_non_null(pblob);
+
rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
assert_return_code(rc, errno);
assert_true(rc == SSH_OK);
@@ -196,7 +208,6 @@ static void torture_pki_ecdsa_publickey_from_privatekey_uri(void **state, const
assert_return_code(rc, errno);
assert_true(rc == 0);
-
/* remove the public key, generate it from the private key and write it. */
unlink(pub_filename);
@@ -216,6 +227,34 @@ static void torture_pki_ecdsa_publickey_from_privatekey_uri(void **state, const
SSH_KEY_FREE(pubkey);
}
+static void import_pubkey_without_loading_public_uri(void **state, const char *uri, const char *type)
+{
+ int rc;
+ ssh_key privkey = NULL;
+ ssh_key pubkey = NULL;
+ ssh_string pblob = NULL;
+
+ rc = ssh_pki_import_privkey_file(uri,
+ NULL,
+ NULL,
+ NULL,
+ &privkey);
+ assert_return_code(rc, errno);
+ assert_true(rc == 0);
+ assert_non_null(privkey);
+
+ rc = ssh_pki_export_pubkey_blob(privkey, &pblob);
+ assert_int_not_equal(rc, 0);
+ assert_null(pblob);
+
+ rc = ssh_pki_export_privkey_to_pubkey(privkey, &pubkey);
+ assert_int_not_equal(rc, 0);
+ assert_null(pubkey);
+
+ SSH_KEY_FREE(privkey);
+ SSH_KEY_FREE(pubkey);
+}
+
static void torture_pki_ecdsa_publickey_from_privatekey_uri_256(void **state)
{
torture_pki_ecdsa_publickey_from_privatekey_uri(state, PRIV_URI_FMT_256, "ecdsa256");
@@ -231,6 +270,21 @@ static void torture_pki_ecdsa_publickey_from_privatekey_uri_521(void **state)
torture_pki_ecdsa_publickey_from_privatekey_uri(state, PRIV_URI_FMT_521, "ecdsa521");
}
+static void torture_pki_ecdsa_import_pubkey_without_loading_public_uri_256(void **state)
+{
+ import_pubkey_without_loading_public_uri(state, PRIV_URI_FMT_256_NO_PUB, "ecdsa256_no_pub_uri");
+}
+
+static void torture_pki_ecdsa_import_pubkey_without_loading_public_uri_384(void **state)
+{
+ import_pubkey_without_loading_public_uri(state, PRIV_URI_FMT_384_NO_PUB, "ecdsa384_no_pub_uri");
+}
+
+static void torture_pki_ecdsa_import_pubkey_without_loading_public_uri_521(void **state)
+{
+ import_pubkey_without_loading_public_uri(state, PRIV_URI_FMT_521_NO_PUB, "ecdsa521_no_pub_uri");
+}
+
static void torture_ecdsa_sign_verify_uri(void **state, const char *uri, enum ssh_digest_e dig_type)
{
int rc;
@@ -482,6 +536,9 @@ int torture_run_tests(void) {
/** Expect fail on these negative test cases **/
cmocka_unit_test(torture_pki_ecdsa_import_pubkey_uri_invalid_configurations),
+ cmocka_unit_test(torture_pki_ecdsa_import_pubkey_without_loading_public_uri_256),
+ cmocka_unit_test(torture_pki_ecdsa_import_pubkey_without_loading_public_uri_384),
+ cmocka_unit_test(torture_pki_ecdsa_import_pubkey_without_loading_public_uri_521),
};
ssh_session session = ssh_new();
diff --git a/tests/unittests/torture_pki_rsa_uri.c b/tests/unittests/torture_pki_rsa_uri.c
index 09b41b5d..370c6ec3 100644
--- a/tests/unittests/torture_pki_rsa_uri.c
+++ b/tests/unittests/torture_pki_rsa_uri.c
@@ -83,7 +83,7 @@ static int setup_tokens(void **state)
torture_write_file(keys_path_pub,
torture_get_testkey_pub_pem(SSH_KEYTYPE_RSA));
- torture_setup_tokens(cwd, keys_path, obj_tempname);
+ torture_setup_tokens(cwd, keys_path, obj_tempname, "1");
snprintf(conf_path, sizeof(conf_path), "%s/softhsm.conf", cwd);