Compare commits

...

32 Commits

Author SHA1 Message Date
Jakub Jelen
301d0e16df Bump version to 0.11.3
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
2025-09-09 10:01:48 +02:00
Jakub Jelen
c182a21e11 poll: Use is_locked helper where possible
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit df4e907dff)
2025-08-14 11:02:39 +02:00
Philippe Antoine
3a28fbe5c6 socket: do not free poll object if it is locked
As it may a cause a use after free if `send` fails when
ssh_poll_ctx_dopoll does its callback
ssh_poll_ctx_dopoll still wants to use the poll object later

Signed-off-by: Philippe Antoine <p.antoine@catenacyber.fr>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c99261437f)
2025-08-14 11:02:39 +02:00
Andreas Schneider
65f363c9e3 CVE-2025-8114: Fix NULL pointer dereference after allocation failure
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 53ac23ded4)
2025-08-14 11:02:39 +02:00
Jakub Jelen
1c763e29d1 CVE-2025-8277: mbedtls: Avoid leaking ecdh keys
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit ffed80f8c0)
2025-08-14 11:02:39 +02:00
Jakub Jelen
7d85085d2a tests: Invoke all combinations of wrong guesses during rekey
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit d357a9f3e2)
2025-08-14 11:02:39 +02:00
Jakub Jelen
8e4d67aa9e CVE-2025-8277: ecdh: Free previously allocated pubkeys
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c9d95ab0c7)
2025-08-14 11:02:39 +02:00
Francesco Rollo
266174a6d3 CVE-2025-8277: Fix memory leak of unused ephemeral key pair after client's wrong KEX guess
Signed-off-by: Francesco Rollo <eferollo@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit ccff22d378)
2025-08-14 11:02:39 +02:00
Jakub Jelen
87db2659ec CVE-2025-8277: packet: Adjust packet filter to work when DH-GEX is guessed wrongly
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 4310a696f2)
2025-08-14 11:02:39 +02:00
Jakub Jelen
0fad4e6307 tests: Enable all key exchange methods in ssh_ping
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 771e19a7a9)
2025-08-14 11:02:39 +02:00
Andreas Schneider
02cbd41b92 tests: Call disable_secmem() before ssh_init()
ssh_init calls ssh_crypto_init() which initializes the secure memory of
gcrypt. Those should actually be just called by the application once.
Lets do that.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 2966a4a33c)
2025-08-08 16:11:26 +02:00
Andreas Schneider
750693d10b tests: Reformat cmocka_unit_test calls in torture_threads_pki_rsa.c
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 867630750c)
2025-08-08 16:11:24 +02:00
Jakub Jelen
56953f8aab mbedtls: Avoid one more memory leak
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
(cherry picked from commit 4f239f79c6)
2025-08-08 13:49:35 +02:00
Jakub Jelen
0f1723b5c7 mbedtls: Rename label to match the current meaning
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
(cherry picked from commit b314fd3e04)
2025-08-08 13:49:29 +02:00
Jakub Jelen
f1998d6064 mbedtls: Avoid code duplication between v2 and v3 branches
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
(cherry picked from commit d1ad796496)
2025-08-08 13:49:28 +02:00
Jakub Jelen
d0ef7afdfa pki: Make sure the buffer is zeroized too
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
(cherry picked from commit e2064b743d)
2025-08-08 13:49:26 +02:00
Jakub Jelen
6e459f5756 pki_mbedtls: Simplify memory cleanup
The spread out initialization and variable definition (and alising)
was hell to keep up with and was causing memory issues as reported by valgrind:

==4480== 128 bytes in 1 blocks are definitely lost in loss record 1 of 12
==4480==    at 0x48463F3: calloc (vg_replace_malloc.c:1675)
==4480==    by 0x487D152: mbedtls_mpi_grow (bignum.c:218)
==4480==    by 0x487D6C5: mbedtls_mpi_copy (bignum.c:334)
==4480==    by 0x48B9627: mbedtls_rsa_export (rsa.c:899)
==4480==    by 0x283955: pki_key_to_blob (pki_mbedcrypto.c:976)
==4480==    by 0x24F162: ssh_pki_export_privkey_blob (pki.c:2188)
==4480==    by 0x278001: ssh_pki_openssh_privkey_export (pki_container_openssh.c:546)
==4480==    by 0x24D7D2: ssh_pki_export_privkey_file_format (pki.c:1122)
==4480==    by 0x24D916: torture_pki_rsa_write_privkey_format (torture_pki_rsa.c:895)
==4480==    by 0x24D916: torture_pki_rsa_write_privkey (torture_pki_rsa.c:962)
==4480==    by 0x4865499: ??? (in /usr/lib64/libcmocka.so.0.8.0)
==4480==    by 0x4865C0B: _cmocka_run_group_tests (in /usr/lib64/libcmocka.so.0.8.0)
==4480==    by 0x252115: torture_run_tests (torture_pki_rsa.c:1160)
==4480==    by 0x2546B8: main (torture.c:1984)
==4480==

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
(cherry picked from commit 6d2a3e4eb6)
2025-08-08 13:49:25 +02:00
Jakub Jelen
51746e51f0 mbedcrypto: Refromat pki_key_to_blob()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
(cherry picked from commit 7c34fa783d)
2025-08-08 13:49:23 +02:00
Jakub Jelen
e7ef3f2962 CentOS 9 and 10 were updated to OpenSSL 3.5
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 51bd08027e)
2025-08-08 11:37:19 +02:00
Jakub Jelen
b8d92bbcc7 tests: Fix build script to work also on MacOS correctly
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit c2e9d39dbe)
2025-08-08 11:30:53 +02:00
Jakub Jelen
f2aaee53df tests: Add more valgrind supressions for krb5
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit ab44f606b2)
2025-08-08 11:29:54 +02:00
Jakub Jelen
b026b24b55 tests: Avoid needless call to pthread_exit()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 444982b38a)
2025-08-08 11:29:50 +02:00
Jakub Jelen
028859ce99 pkd: Cleanup OpenSSL context
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 3df61a4e86)
2025-08-08 11:29:45 +02:00
Jakub Jelen
d64f06f98a tests: Cleanup OpenSSL in the forked server processes
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 7eefbbd478)
2025-08-08 11:29:32 +02:00
Jakub Jelen
b298a04f96 tests: Cleanup OpenSSL in tests when GSSAPI is built
also from the fuzzer tests

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 08a32ac381)
2025-08-08 11:28:18 +02:00
Jakub Jelen
962012bbf6 Cleanup the loaded pkcs11 provider
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 62762bbbc9)
2025-08-08 11:28:13 +02:00
Jakub Jelen
abfc42fad3 Finalize OpenSSL context from tests to make the valgrind output clean
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit ab3e08c2b5)
2025-08-08 11:28:09 +02:00
Jakub Jelen
1ad67bd66e tests: Adjust valgrind supression to match new calls stack
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 809898b980)
2025-08-08 11:24:55 +02:00
Jakub Jelen
f553a6740a pkd: Run hmac-sha1 tests with OpenSSH
This was initially in hurry disabled in
ca4c874a9e because dropbear dropped support for
these HMACs. The follow-up commit enabled running these tests on old dropbear in
c17112f070, but still did not run them on openssh,
when the new dropbear was installed.

This fixes up the above commit to run the HMAC-SHA1 tests with OpenSSH even if
the new dropbear is installed.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
(cherry picked from commit 9817392e26)
2025-08-08 11:24:32 +02:00
Nguyễn Thái Ngọc Duy
bac5d3f10a Fix ssh_handle_key_exchange() timeout
See libssh-mirror#311 for background. But in some case, it's possible to
trigger the code in ssh_handle_key_exchange() to move session state
directly to SSH_SESSION_STATE_AUTHENTICATED. The exit condition for this
function is SSH_SESSION_STATE_AUTHENTICATING though, so when it happens,
ssh_handle_key_exchange() will time out eventually.

The fix is straightforward. Tested with the problematic
client (trilead-ssh2) and made sure the bad condition happened (and not
cause timeout)

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 168302b9d6)
2025-08-08 11:24:28 +02:00
abdallah elhdad
c8c3d418ee Enable HMAC SHA1 tests for dropbear <2025.87
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit c17112f070)
2025-08-08 11:23:41 +02:00
Theo Buehler
33be8038fe Unbreak torture_config_make_absolute() on OpenBSD
The torture_config_make_absolute() and its _no_sshdir() version both
segfault on OpenBSD. The reason for this is that the storage returned
by getpwuid() is backed by mmap and is unapped by the getpwnam() call
in ssh_path_expand_tilde(), so a later access to home segfaults. The
possibility of this happening (getpwnam() overwriting values returned
by getpwuid()) is explicitly called out in POSIX.

A simple fix is to work with copies of username and homedir.

Signed-off-by: Theo Buehler <tb@openbsd.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit ccb8cf88c8)
2025-08-08 11:22:05 +02:00
46 changed files with 1126 additions and 358 deletions

View File

@@ -121,7 +121,7 @@ review:
###############################################################################
# CentOS builds #
###############################################################################
centos10s/openssl_3.2.x/x86_64:
centos10s/openssl_3.5.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
extends: .tests
variables:
@@ -132,7 +132,7 @@ centos10s/openssl_3.2.x/x86_64:
make -j$(nproc) &&
ctest --output-on-failure
centos10s/openssl_3.2.x/x86_64/fips:
centos10s/openssl_3.5.x/x86_64/fips:
extends: .fips
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS10_BUILD
variables:
@@ -143,7 +143,7 @@ centos10s/openssl_3.2.x/x86_64/fips:
make -j$(nproc) &&
OPENSSL_FORCE_FIPS_MODE=1 ctest --output-on-failure
centos9s/openssl_3.0.x/x86_64:
centos9s/openssl_3.5.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
extends: .tests
variables:
@@ -160,7 +160,7 @@ centos9s/mbedtls_2.x/x86_64:
variables:
CMAKE_ADDITIONAL_OPTIONS: "-DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF"
centos9s/openssl_3.0.x/x86_64/fips:
centos9s/openssl_3.5.x/x86_64/fips:
extends: .fips
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
script:

View File

@@ -1,6 +1,15 @@
CHANGELOG
=========
version 0.11.3 (released 2025-09-09)
* Security:
* CVE-2025-8114: Fix NULL pointer dereference after allocation failure
* CVE-2025-8277: Fix memory leak of ephemeral key pair during repeated wrong KEX
* Potential UAF when send() fails during key exchange
* Fix possible timeout during KEX if client sends authentication too early (#311)
* Cleanup OpenSSL PKCS#11 provider when loaded
* Zeroize buffers containing private key blobs during export
version 0.11.2 (released 2025-06-24)
* Security:
* CVE-2025-4877 - Write beyond bounds in binary to base64 conversion

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12.0)
cmake_minimum_required(VERSION 3.14.0)
# Specify search path for CMake modules to be loaded by include()
# and find_package()
@@ -9,7 +9,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
include(DefineCMakeDefaults)
include(DefineCompilerFlags)
project(libssh VERSION 0.11.2 LANGUAGES C)
project(libssh VERSION 0.11.3 LANGUAGES C)
# global needed variable
set(APPLICATION_NAME ${PROJECT_NAME})
@@ -21,7 +21,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
# Increment AGE. Set REVISION to 0
# If the source code was changed, but there were no interface changes:
# Increment REVISION.
set(LIBRARY_VERSION "4.10.2")
set(LIBRARY_VERSION "4.10.3")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked

View File

@@ -223,9 +223,6 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
size_t requested_len);
int secure_memcmp(const void *s1, const void *s2, size_t n);
#if defined(HAVE_LIBCRYPTO) && !defined(WITH_PKCS11_PROVIDER)
ENGINE *pki_get_engine(void);
#endif /* HAVE_LIBCRYPTO */
void compress_cleanup(struct ssh_crypto_struct *crypto);

View File

@@ -121,6 +121,15 @@ typedef BN_CTX* bignum_CTX;
ssh_string pki_key_make_ecpoint_string(const EC_GROUP *g, const EC_POINT *p);
int pki_key_ecgroup_name_to_nid(const char *group);
#if defined(WITH_PKCS11_URI)
#if defined(WITH_PKCS11_PROVIDER)
int pki_load_pkcs11_provider(void);
#else
ENGINE *pki_get_engine(void);
#endif
#endif /* WITH_PKCS11_PROVIDER */
#endif /* HAVE_LIBCRYPTO */
#endif /* LIBCRYPTO_H_ */

View File

@@ -157,6 +157,7 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx);
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p);
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, struct ssh_socket_struct *s);
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p);
bool ssh_poll_is_locked(ssh_poll_handle p);
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout);
ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session);
int ssh_event_add_poll(ssh_event event, ssh_poll_handle p);

View File

@@ -1 +1 @@
4.10.2
4.10.3

View File

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

View File

@@ -407,6 +407,11 @@ int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
struct dh_ctx *ctx = NULL;
int rc;
/* Cleanup any previously allocated dh_ctx */
if (crypto->dh_ctx != NULL) {
ssh_dh_cleanup(crypto);
}
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL) {
return SSH_ERROR;

View File

@@ -237,6 +237,11 @@ int ssh_dh_init_common(struct ssh_crypto_struct *crypto)
struct dh_ctx *ctx = NULL;
int rc;
/* Cleanup any previously allocated dh_ctx */
if (crypto->dh_ctx != NULL) {
ssh_dh_cleanup(crypto);
}
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL) {
return SSH_ERROR;

View File

@@ -191,6 +191,17 @@ static ssh_string ssh_ecdh_generate(ssh_session session)
#endif /* OPENSSL_VERSION_NUMBER */
return NULL;
}
/* Free any previously allocated privkey */
if (session->next_crypto->ecdh_privkey != NULL) {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
EC_KEY_free(session->next_crypto->ecdh_privkey);
#else
EVP_PKEY_free(session->next_crypto->ecdh_privkey);
#endif
session->next_crypto->ecdh_privkey = NULL;
}
session->next_crypto->ecdh_privkey = key;
return pubkey_string;
}
@@ -219,6 +230,7 @@ int ssh_client_ecdh_init(ssh_session session)
return SSH_ERROR;
}
ssh_string_free(session->next_crypto->ecdh_client_pubkey);
session->next_crypto->ecdh_client_pubkey = client_pubkey;
/* register the packet callbacks */

View File

@@ -101,8 +101,15 @@ int ssh_client_ecdh_init(ssh_session session)
goto out;
}
/* Free any previously allocated privkey */
if (session->next_crypto->ecdh_privkey != NULL) {
gcry_sexp_release(session->next_crypto->ecdh_privkey);
session->next_crypto->ecdh_privkey = NULL;
}
session->next_crypto->ecdh_privkey = key;
key = NULL;
SSH_STRING_FREE(session->next_crypto->ecdh_client_pubkey);
session->next_crypto->ecdh_client_pubkey = client_pubkey;
client_pubkey = NULL;

View File

@@ -70,6 +70,12 @@ int ssh_client_ecdh_init(ssh_session session)
return SSH_ERROR;
}
/* Free any previously allocated privkey */
if (session->next_crypto->ecdh_privkey != NULL) {
mbedtls_ecp_keypair_free(session->next_crypto->ecdh_privkey);
SAFE_FREE(session->next_crypto->ecdh_privkey);
}
session->next_crypto->ecdh_privkey = malloc(sizeof(mbedtls_ecp_keypair));
if (session->next_crypto->ecdh_privkey == NULL) {
return SSH_ERROR;
@@ -110,6 +116,7 @@ int ssh_client_ecdh_init(ssh_session session)
goto out;
}
SSH_STRING_FREE(session->next_crypto->ecdh_client_pubkey);
session->next_crypto->ecdh_client_pubkey = client_pubkey;
client_pubkey = NULL;

View File

@@ -1487,6 +1487,8 @@ int ssh_make_sessionid(ssh_session session)
ssh_log_hexdump("hash buffer", ssh_buffer_get(buf), ssh_buffer_get_len(buf));
#endif
/* Set rc for the following switch statement in case we goto error. */
rc = SSH_ERROR;
switch (session->next_crypto->kex_type) {
case SSH_KEX_DH_GROUP1_SHA1:
case SSH_KEX_DH_GROUP14_SHA1:
@@ -1546,6 +1548,7 @@ int ssh_make_sessionid(ssh_session session)
session->next_crypto->secret_hash);
break;
}
/* During the first kex, secret hash and session ID are equal. However, after
* a key re-exchange, a new secret hash is calculated. This hash will not replace
* but complement existing session id.
@@ -1554,6 +1557,7 @@ int ssh_make_sessionid(ssh_session session)
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
if (session->next_crypto->session_id == NULL) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,

View File

@@ -49,8 +49,9 @@
#include <openssl/rsa.h>
#include <openssl/hmac.h>
#else
#include <openssl/param_build.h>
#include <openssl/core_names.h>
#include <openssl/param_build.h>
#include <openssl/provider.h>
#endif /* OPENSSL_VERSION_NUMBER */
#include <openssl/rand.h>
#if defined(WITH_PKCS11_URI) && !defined(WITH_PKCS11_PROVIDER)
@@ -96,7 +97,37 @@ void ssh_reseed(void){
#endif
}
#if defined(WITH_PKCS11_URI) && !defined(WITH_PKCS11_PROVIDER)
#if defined(WITH_PKCS11_URI)
#if defined(WITH_PKCS11_PROVIDER)
static OSSL_PROVIDER *provider = NULL;
static bool pkcs11_provider_failed = false;
int pki_load_pkcs11_provider(void)
{
if (OSSL_PROVIDER_available(NULL, "pkcs11") == 1) {
/* the provider is already available.
* Loaded through a configuration file? */
return SSH_OK;
}
if (pkcs11_provider_failed) {
/* the loading failed previously -- do not retry */
return SSH_ERROR;
}
provider = OSSL_PROVIDER_try_load(NULL, "pkcs11", 1);
if (provider != NULL) {
return SSH_OK;
}
SSH_LOG(SSH_LOG_TRACE,
"Failed to load the pkcs11 provider: %s",
ERR_error_string(ERR_get_error(), NULL));
/* Do not attempt to load it again */
pkcs11_provider_failed = true;
return SSH_ERROR;
}
#else
static ENGINE *engine = NULL;
ENGINE *pki_get_engine(void)
@@ -128,7 +159,8 @@ ENGINE *pki_get_engine(void)
}
return engine;
}
#endif /* defined(WITH_PKCS11_URI) && !defined(WITH_PKCS11_PROVIDER) */
#endif /* defined(WITH_PKCS11_PROVIDER) */
#endif /* defined(WITH_PKCS11_URI) */
#ifdef HAVE_OPENSSL_EVP_KDF_CTX
#if OPENSSL_VERSION_NUMBER < 0x30000000L
@@ -1402,6 +1434,14 @@ void ssh_crypto_finalize(void)
engine = NULL;
}
#endif
#if defined(WITH_PKCS11_URI)
#if defined(WITH_PKCS11_PROVIDER)
if (provider != NULL) {
OSSL_PROVIDER_unload(provider);
provider = NULL;
}
#endif /* WITH_PKCS11_PROVIDER */
#endif /* WITH_PKCS11_URI */
libcrypto_initialized = 0;
}

View File

@@ -294,6 +294,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
* or session_state == SSH_SESSION_STATE_INITIAL_KEX
* - dh_handshake_state == DH_STATE_INIT
* or dh_handshake_state == DH_STATE_INIT_SENT (re-exchange)
* or dh_handshake_state == DH_STATE_REQUEST_SENT (dh-gex)
* or dh_handshake_state == DH_STATE_FINISHED (re-exchange)
*
* Transitions:
@@ -313,6 +314,7 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
if ((session->dh_handshake_state != DH_STATE_INIT) &&
(session->dh_handshake_state != DH_STATE_INIT_SENT) &&
(session->dh_handshake_state != DH_STATE_REQUEST_SENT) &&
(session->dh_handshake_state != DH_STATE_FINISHED))
{
rc = SSH_PACKET_DENIED;

View File

@@ -46,7 +46,6 @@
#include <openssl/param_build.h>
#if defined(WITH_PKCS11_URI) && defined(WITH_PKCS11_PROVIDER)
#include <openssl/store.h>
#include <openssl/provider.h>
#endif
#endif /* OPENSSL_VERSION_NUMBER */
@@ -1429,6 +1428,8 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
if (buffer == NULL) {
return NULL;
}
/* The buffer will contain sensitive information. Make sure it is erased */
ssh_buffer_set_secure(buffer);
if (key->cert != NULL) {
rc = ssh_buffer_add_buffer(buffer, key->cert);
@@ -2719,9 +2720,6 @@ error:
}
#ifdef WITH_PKCS11_URI
#ifdef WITH_PKCS11_PROVIDER
static bool pkcs11_provider_failed = false;
#endif
/**
* @internal
@@ -2787,19 +2785,10 @@ int pki_uri_import(const char *uri_name,
/* The provider can be either configured in openssl.cnf or dynamically
* loaded, assuming it does not need any special configuration */
if (OSSL_PROVIDER_available(NULL, "pkcs11") == 0 &&
!pkcs11_provider_failed) {
OSSL_PROVIDER *pkcs11_provider = NULL;
pkcs11_provider = OSSL_PROVIDER_try_load(NULL, "pkcs11", 1);
if (pkcs11_provider == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize provider: %s",
ERR_error_string(ERR_get_error(), NULL));
/* Do not attempt to load it again */
pkcs11_provider_failed = true;
goto fail;
}
rv = pki_load_pkcs11_provider();
if (rv != SSH_OK) {
SSH_LOG(SSH_LOG_TRACE, "Failed to load or initialize pkcs11 provider");
goto fail;
}
store = OSSL_STORE_open(uri_name, NULL, NULL, NULL, NULL);

View File

@@ -1409,6 +1409,8 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
if (buffer == NULL) {
return NULL;
}
/* The buffer will contain sensitive information. Make sure it is erased */
ssh_buffer_set_secure(buffer);
if (key->cert != NULL) {
rc = ssh_buffer_add_buffer(buffer, key->cert);

View File

@@ -864,7 +864,12 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
ssh_string type_s = NULL;
ssh_string e = NULL;
ssh_string n = NULL;
ssh_string p = NULL;
ssh_string q = NULL;
ssh_string d = NULL;
ssh_string iqmp = NULL;
ssh_string str = NULL;
int rc;
#if MBEDTLS_VERSION_MAJOR > 2
mbedtls_mpi E = {0};
mbedtls_mpi N = {0};
@@ -872,18 +877,21 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
mbedtls_mpi IQMP = {0};
mbedtls_mpi P = {0};
mbedtls_mpi Q = {0};
#endif
int rc;
#if MBEDTLS_VERSION_MAJOR > 2
mbedtls_mpi_init(&E);
mbedtls_mpi_init(&N);
mbedtls_mpi_init(&D);
mbedtls_mpi_init(&IQMP);
mbedtls_mpi_init(&P);
mbedtls_mpi_init(&Q);
#endif
buffer = ssh_buffer_new();
if (buffer == NULL) {
return NULL;
}
/* The buffer will contain sensitive information. Make sure it is erased */
ssh_buffer_set_secure(buffer);
if (key->cert != NULL) {
rc = ssh_buffer_add_buffer(buffer, key->cert);
@@ -909,279 +917,241 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
}
switch (key->type) {
case SSH_KEYTYPE_RSA: {
mbedtls_rsa_context *rsa;
if (mbedtls_pk_can_do(key->pk, MBEDTLS_PK_RSA) == 0) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
case SSH_KEYTYPE_RSA: {
mbedtls_rsa_context *rsa = NULL;
mbedtls_mpi *E_ptr = NULL, *N_ptr = NULL;
rsa = mbedtls_pk_rsa(*key->pk);
#if MBEDTLS_VERSION_MAJOR > 2
rc = mbedtls_rsa_export(rsa, &N, NULL, NULL, NULL, &E);
if (rc != 0) {
goto fail;
}
e = ssh_make_bignum_string(&E);
if (e == NULL) {
goto fail;
}
n = ssh_make_bignum_string(&N);
if (n == NULL) {
goto fail;
}
#else
e = ssh_make_bignum_string(&rsa->E);
if (e == NULL) {
goto fail;
}
n = ssh_make_bignum_string(&rsa->N);
if (n == NULL) {
goto fail;
}
#endif
if (type == SSH_KEY_PUBLIC) {
/* The N and E parts are swapped in the public key export ! */
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
} else if (type == SSH_KEY_PRIVATE) {
ssh_string p = NULL;
ssh_string q = NULL;
ssh_string d = NULL;
ssh_string iqmp = NULL;
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
#if MBEDTLS_VERSION_MAJOR > 2
rc = mbedtls_rsa_export(rsa, NULL, &P, &Q, &D, NULL);
if (rc != 0) {
goto fail;
}
p = ssh_make_bignum_string(&P);
if (p == NULL) {
goto fail;
}
q = ssh_make_bignum_string(&Q);
if (q == NULL) {
goto fail;
}
d = ssh_make_bignum_string(&D);
if (d == NULL) {
goto fail;
}
rc = mbedtls_rsa_export_crt(rsa, NULL, NULL, &IQMP);
if (rc != 0) {
goto fail;
}
iqmp = ssh_make_bignum_string(&IQMP);
if (iqmp == NULL) {
goto fail;
}
#else
p = ssh_make_bignum_string(&rsa->P);
if (p == NULL) {
goto fail;
}
q = ssh_make_bignum_string(&rsa->Q);
if (q == NULL) {
goto fail;
}
d = ssh_make_bignum_string(&rsa->D);
if (d == NULL) {
goto fail;
}
iqmp = ssh_make_bignum_string(&rsa->QP);
if (iqmp == NULL) {
goto fail;
}
#endif
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, iqmp);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, p);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, q);
if (rc < 0) {
goto fail;
}
ssh_string_burn(d);
SSH_STRING_FREE(d);
d = NULL;
ssh_string_burn(iqmp);
SSH_STRING_FREE(iqmp);
iqmp = NULL;
ssh_string_burn(p);
SSH_STRING_FREE(p);
p = NULL;
ssh_string_burn(q);
SSH_STRING_FREE(q);
q = NULL;
}
ssh_string_burn(e);
SSH_STRING_FREE(e);
e = NULL;
ssh_string_burn(n);
SSH_STRING_FREE(n);
n = NULL;
break;
if (mbedtls_pk_can_do(key->pk, MBEDTLS_PK_RSA) == 0) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521:
case SSH_KEYTYPE_SK_ECDSA:
type_s =
ssh_string_from_char(pki_key_ecdsa_nid_to_char(key->ecdsa_nid));
if (type_s == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
rc = ssh_buffer_add_ssh_string(buffer, type_s);
SSH_STRING_FREE(type_s);
rsa = mbedtls_pk_rsa(*key->pk);
#if MBEDTLS_VERSION_MAJOR > 2
rc = mbedtls_rsa_export(rsa, &N, NULL, NULL, NULL, &E);
if (rc != 0) {
goto out;
}
E_ptr = &E;
N_ptr = &N;
#else
E_ptr = &rsa->E;
N_ptr = &rsa->N;
#endif
e = ssh_make_bignum_string(E_ptr);
if (e == NULL) {
goto out;
}
n = ssh_make_bignum_string(N_ptr);
if (n == NULL) {
goto out;
}
if (type == SSH_KEY_PUBLIC) {
/* The N and E parts are swapped in the public key export ! */
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
SSH_BUFFER_FREE(buffer);
return NULL;
goto out;
}
e = make_ecpoint_string(&key->ecdsa->MBEDTLS_PRIVATE(grp),
&key->ecdsa->MBEDTLS_PRIVATE(Q));
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto out;
}
} else if (type == SSH_KEY_PRIVATE) {
mbedtls_mpi *P_ptr = NULL, *Q_ptr = NULL, *D_ptr = NULL;
mbedtls_mpi *IQMP_ptr = NULL;
if (e == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto out;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
goto out;
}
ssh_string_burn(e);
SSH_STRING_FREE(e);
e = NULL;
#if MBEDTLS_VERSION_MAJOR > 2
rc = mbedtls_rsa_export(rsa, NULL, &P, &Q, &D, NULL);
if (rc != 0) {
goto out;
}
if (type == SSH_KEY_PRIVATE) {
ssh_string d = NULL;
d = ssh_make_bignum_string(&key->ecdsa->MBEDTLS_PRIVATE(d));
rc = mbedtls_rsa_export_crt(rsa, NULL, NULL, &IQMP);
if (rc != 0) {
goto out;
}
if (d == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
P_ptr = &P;
Q_ptr = &Q;
D_ptr = &D;
IQMP_ptr = &IQMP;
#else
P_ptr = &rsa->P;
Q_ptr = &rsa->Q;
D_ptr = &rsa->D;
IQMP_ptr = &rsa->QP;
#endif
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
p = ssh_make_bignum_string(P_ptr);
if (p == NULL) {
goto out;
}
ssh_string_burn(d);
SSH_STRING_FREE(d);
d = NULL;
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
/* public key can contain certificate sk information */
q = ssh_make_bignum_string(Q_ptr);
if (q == NULL) {
goto out;
}
d = ssh_make_bignum_string(D_ptr);
if (d == NULL) {
goto out;
}
iqmp = ssh_make_bignum_string(IQMP_ptr);
if (iqmp == NULL) {
goto out;
}
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto out;
}
rc = ssh_buffer_add_ssh_string(buffer, iqmp);
if (rc < 0) {
goto out;
}
rc = ssh_buffer_add_ssh_string(buffer, p);
if (rc < 0) {
goto out;
}
rc = ssh_buffer_add_ssh_string(buffer, q);
if (rc < 0) {
goto out;
}
}
break;
}
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521:
case SSH_KEYTYPE_SK_ECDSA:
type_s =
ssh_string_from_char(pki_key_ecdsa_nid_to_char(key->ecdsa_nid));
if (type_s == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
rc = ssh_buffer_add_ssh_string(buffer, type_s);
SSH_STRING_FREE(type_s);
if (rc < 0) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
e = make_ecpoint_string(&key->ecdsa->MBEDTLS_PRIVATE(grp),
&key->ecdsa->MBEDTLS_PRIVATE(Q));
if (e == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto out;
}
if (type == SSH_KEY_PRIVATE) {
d = ssh_make_bignum_string(&key->ecdsa->MBEDTLS_PRIVATE(d));
if (d == NULL) {
SSH_BUFFER_FREE(buffer);
goto out;
}
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto out;
}
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
/* public key can contain certificate sk information */
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto out;
}
}
break;
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
if (type == SSH_KEY_PUBLIC) {
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto out;
}
/* public key can contain certificate sk information */
if (key->type == SSH_KEYTYPE_SK_ED25519) {
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
break;
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
if (type == SSH_KEY_PUBLIC) {
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
}
/* public key can contain certificate sk information */
if (key->type == SSH_KEYTYPE_SK_ED25519) {
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
} else {
rc = pki_ed25519_private_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
goto out;
}
}
break;
default:
goto fail;
} else {
rc = pki_ed25519_private_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto out;
}
}
break;
default:
goto out;
}
makestring:
str = ssh_string_new(ssh_buffer_get_len(buffer));
if (str == NULL) {
goto fail;
goto out;
}
rc = ssh_string_fill(str, ssh_buffer_get(buffer),
ssh_buffer_get_len(buffer));
rc = ssh_string_fill(str,
ssh_buffer_get(buffer),
ssh_buffer_get_len(buffer));
if (rc < 0) {
goto fail;
ssh_string_burn(str);
SSH_STRING_FREE(str);
}
out:
SSH_BUFFER_FREE(buffer);
#if MBEDTLS_VERSION_MAJOR > 2
mbedtls_mpi_free(&N);
mbedtls_mpi_free(&E);
#endif
return str;
fail:
SSH_BUFFER_FREE(buffer);
ssh_string_burn(str);
SSH_STRING_FREE(str);
ssh_string_burn(e);
SSH_STRING_FREE(e);
ssh_string_burn(n);
SSH_STRING_FREE(n);
ssh_string_burn(d);
SSH_STRING_FREE(d);
ssh_string_burn(iqmp);
SSH_STRING_FREE(iqmp);
ssh_string_burn(p);
SSH_STRING_FREE(p);
ssh_string_burn(q);
SSH_STRING_FREE(q);
#if MBEDTLS_VERSION_MAJOR > 2
mbedtls_mpi_free(&N);
mbedtls_mpi_free(&E);
mbedtls_mpi_free(&D);
mbedtls_mpi_free(&IQMP);
mbedtls_mpi_free(&P);
mbedtls_mpi_free(&Q);
#endif
return NULL;
return str;
}
ssh_string pki_signature_to_blob(const ssh_signature sig)

View File

@@ -422,7 +422,7 @@ void ssh_poll_set_events(ssh_poll_handle p, short events)
{
p->events = events;
if (p->ctx != NULL) {
if (p->lock_cnt == 0) {
if (!ssh_poll_is_locked(p)) {
p->ctx->pollfds[p->x.idx].events = events;
} else if (!(p->ctx->pollfds[p->x.idx].events & POLLOUT)) {
/* if locked, allow only setting POLLOUT to prevent recursive
@@ -669,6 +669,20 @@ void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p)
}
}
/**
* @brief Returns if a poll object is locked.
*
* @param p Pointer to an already allocated poll object.
* @returns true if the poll object is locked; false otherwise.
*/
bool ssh_poll_is_locked(ssh_poll_handle p)
{
if (p == NULL) {
return false;
}
return p->lock_cnt > 0;
}
/**
* @brief Poll all the sockets associated through a poll object with a
* poll context. If any of the events are set after the poll, the
@@ -703,7 +717,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout)
* output buffer */
for (i = 0; i < ctx->polls_used; i++) {
/* The lock allows only POLLOUT events: drop the rest */
if (ctx->pollptrs[i]->lock_cnt > 0) {
if (ssh_poll_is_locked(ctx->pollptrs[i])) {
ctx->pollfds[i].events &= POLLOUT;
}
}

View File

@@ -523,6 +523,7 @@ static int ssh_server_kex_termination(void *s){
ssh_session session = s;
if (session->session_state != SSH_SESSION_STATE_ERROR &&
session->session_state != SSH_SESSION_STATE_AUTHENTICATING &&
session->session_state != SSH_SESSION_STATE_AUTHENTICATED &&
session->session_state != SSH_SESSION_STATE_DISCONNECTED)
return 0;
else

View File

@@ -478,7 +478,7 @@ void ssh_socket_close(ssh_socket s)
#endif
}
if (s->poll_handle != NULL) {
if (s->poll_handle != NULL && !ssh_poll_is_locked(s->poll_handle)) {
ssh_poll_free(s->poll_handle);
s->poll_handle = NULL;
}

View File

@@ -181,7 +181,10 @@ void crypto_free(struct ssh_crypto_struct *crypto)
#endif /* OPENSSL_VERSION_NUMBER */
#elif defined HAVE_GCRYPT_ECC
gcry_sexp_release(crypto->ecdh_privkey);
#endif
#elif defined HAVE_LIBMBEDCRYPTO
mbedtls_ecp_keypair_free(crypto->ecdh_privkey);
SAFE_FREE(crypto->ecdh_privkey);
#endif /* HAVE_LIBGCRYPT */
crypto->ecdh_privkey = NULL;
}
#endif

View File

@@ -23,6 +23,12 @@ if (NOT WIN32)
${TORTURE_LINK_LIBRARIES}
pthread)
endif(NOT WIN32)
if (WITH_GSSAPI AND GSSAPI_FOUND)
find_package(OpenSSL 1.1.1 REQUIRED)
set(TORTURE_LINK_LIBRARIES
${TORTURE_LINK_LIBRARIES}
OpenSSL::Crypto)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
# create test library
add_library(${TORTURE_LIBRARY}
@@ -99,6 +105,7 @@ add_subdirectory(unittests)
# OpenSSH Capabilities are required for all unit tests
find_program(SSH_EXECUTABLE NAMES ssh)
if (SSH_EXECUTABLE)
file(SIZE ${SSH_EXECUTABLE} SSH_EXECUTABLE_SIZE)
execute_process(COMMAND ${SSH_EXECUTABLE} -V ERROR_VARIABLE OPENSSH_VERSION_STR)
string(REGEX REPLACE "^.*OpenSSH_([0-9]+).[0-9].*$" "\\1" OPENSSH_VERSION_MAJOR "${OPENSSH_VERSION_STR}")
string(REGEX REPLACE "^.*OpenSSH_[0-9]+.([0-9]).*$" "\\1" OPENSSH_VERSION_MINOR "${OPENSSH_VERSION_STR}")
@@ -163,6 +170,22 @@ if (SSH_EXECUTABLE)
endif()
find_program(DROPBEAR_EXECUTABLE NAMES dbclient)
if (DROPBEAR_EXECUTABLE)
execute_process(COMMAND ${DROPBEAR_EXECUTABLE} -V ERROR_VARIABLE DROPBEAR_VERSION_STR)
string(REGEX REPLACE "^.*Dropbear v([0-9]+)\\.([0-9]+).*$" "\\1.\\2" DROPBEAR_VERSION "${DROPBEAR_VERSION_STR}")
set(DROPBEAR_VERSION "${DROPBEAR_VERSION}")
# HMAC-SHA1 support was removed in version 2025.87
if("${DROPBEAR_VERSION}" VERSION_LESS "2025.87")
message("Dropbear Version less than 2025.87, enabling dropbear HMAC-SHA1 tests")
add_definitions(-DDROPBEAR_SUPPORTS_HMAC_SHA1)
endif()
else()
message(STATUS "Could NOT find Dropbear (missing: dbclient executable)")
set(DROPBEAR_EXECUTABLE "/bin/false")
endif()
find_program(SSHD_EXECUTABLE
NAME
sshd

View File

@@ -272,5 +272,5 @@ torture_run_tests(void)
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
ssh_finalize();
pthread_exit((void *)&rc);
return rc;
}

View File

@@ -31,6 +31,7 @@
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/crypto.h"
#include "libssh/token.h"
#include <errno.h>
#include <sys/types.h>
@@ -96,6 +97,7 @@ static int session_teardown(void **state)
struct torture_state *s = *state;
ssh_free(s->ssh.session);
s->ssh.session = NULL;
return 0;
}
@@ -148,7 +150,7 @@ static void torture_rekey_default(void **state)
ssh_disconnect(s->ssh.session);
}
static void sanity_check_session(void **state)
static void sanity_check_session_size(void **state, uint64_t rekey_limit)
{
struct torture_state *s = *state;
struct ssh_crypto_struct *c = NULL;
@@ -156,9 +158,9 @@ static void sanity_check_session(void **state)
c = s->ssh.session->current_crypto;
assert_non_null(c);
assert_int_equal(c->in_cipher->max_blocks,
bytes / c->in_cipher->blocksize);
rekey_limit / c->in_cipher->blocksize);
assert_int_equal(c->out_cipher->max_blocks,
bytes / c->out_cipher->blocksize);
rekey_limit / c->out_cipher->blocksize);
/* when strict kex is used, the newkeys reset the sequence number */
if ((s->ssh.session->flags & SSH_SESSION_FLAG_KEX_STRICT) != 0) {
assert_int_equal(c->out_cipher->packets, s->ssh.session->send_seq);
@@ -170,6 +172,10 @@ static void sanity_check_session(void **state)
assert_true(c->in_cipher->packets < s->ssh.session->recv_seq);
}
}
static void sanity_check_session(void **state)
{
sanity_check_session_size(state, bytes);
}
/* We lower the rekey limits manually and check that the rekey
* really happens when sending data
@@ -275,7 +281,7 @@ static int session_setup_sftp_client(void **state)
/* To trigger rekey by receiving data, the easiest thing is probably to
* use sftp
*/
static void torture_rekey_recv(void **state)
static void torture_rekey_recv_size(void **state, uint64_t rekey_limit)
{
struct torture_state *s = *state;
struct ssh_crypto_struct *c = NULL;
@@ -290,7 +296,7 @@ static void torture_rekey_recv(void **state)
mode_t mask;
int rc;
sanity_check_session(state);
sanity_check_session_size(state, rekey_limit);
/* Copy the initial secret hash = session_id so we know we changed keys later */
c = s->ssh.session->current_crypto;
assert_non_null(c);
@@ -324,8 +330,10 @@ static void torture_rekey_recv(void **state)
/* The rekey limit was restored in the new crypto to the same value */
c = s->ssh.session->current_crypto;
assert_int_equal(c->in_cipher->max_blocks, bytes / c->in_cipher->blocksize);
assert_int_equal(c->out_cipher->max_blocks, bytes / c->out_cipher->blocksize);
assert_int_equal(c->in_cipher->max_blocks,
rekey_limit / c->in_cipher->blocksize);
assert_int_equal(c->out_cipher->max_blocks,
rekey_limit / c->out_cipher->blocksize);
/* Check that the secret hash is different than initially */
assert_memory_not_equal(secret_hash, c->secret_hash, c->digest_len);
free(secret_hash);
@@ -333,6 +341,11 @@ static void torture_rekey_recv(void **state)
torture_sftp_close(s->ssh.tsftp);
ssh_disconnect(s->ssh.session);
}
static void torture_rekey_recv(void **state)
{
torture_rekey_recv_size(state, bytes);
}
#endif /* WITH_SFTP */
/* Rekey time requires rekey after specified time and is off by default.
@@ -836,6 +849,81 @@ static void torture_rekey_guess_wrong_recv(void **state)
torture_rekey_recv(state);
}
static void torture_rekey_guess_all_combinations(void **state)
{
struct torture_state *s = *state;
char sshd_config[256] = "";
char client_kex[256] = "";
const char *supported = NULL;
struct ssh_tokens_st *s_tok = NULL;
uint64_t rekey_limit = 0;
int rc, i, j;
/* The rekey limit is 1/2 of the transferred file size so we will likely get
* 2 rekeys per test, which still runs for acceptable time */
rekey_limit = atoll(SSH_EXECUTABLE_SIZE);
rekey_limit /= 2;
if (ssh_fips_mode()) {
supported = ssh_kex_get_fips_methods(SSH_KEX);
} else {
supported = ssh_kex_get_supported_method(SSH_KEX);
}
assert_non_null(supported);
s_tok = ssh_tokenize(supported, ',');
assert_non_null(s_tok);
for (i = 0; s_tok->tokens[i]; i++) {
/* Skip algorithms not supported by the OpenSSH server */
if (strstr(OPENSSH_KEX, s_tok->tokens[i]) == NULL) {
SSH_LOG(SSH_LOG_INFO, "Server: %s [skipping]", s_tok->tokens[i]);
continue;
}
SSH_LOG(SSH_LOG_INFO, "Server: %s", s_tok->tokens[i]);
snprintf(sshd_config,
sizeof(sshd_config),
"KexAlgorithms %s",
s_tok->tokens[i]);
/* This sets an only supported kex algorithm that we do not have as
* a first option in the client */
torture_update_sshd_config(state, sshd_config);
for (j = 0; s_tok->tokens[j]; j++) {
if (i == j) {
continue;
}
session_setup(state);
/* Make the client send the first_kex_packet_follows flag during key
* exchange as well as during the rekey */
s->ssh.session->send_first_kex_follows = true;
rc = ssh_options_set(s->ssh.session,
SSH_OPTIONS_REKEY_DATA,
&rekey_limit);
assert_ssh_return_code(s->ssh.session, rc);
/* Client kex preference will have the second of the pair and the
* server one as a second to negotiate on the second attempt */
snprintf(client_kex,
sizeof(client_kex),
"%s,%s",
s_tok->tokens[j],
s_tok->tokens[i]);
SSH_LOG(SSH_LOG_INFO, "Client: %s", client_kex);
rc = ssh_options_set(s->ssh.session,
SSH_OPTIONS_KEY_EXCHANGE,
client_kex);
assert_ssh_return_code(s->ssh.session, rc);
session_setup_sftp(state);
torture_rekey_recv_size(state, rekey_limit);
session_teardown(state);
}
}
ssh_tokens_free(s_tok);
}
#endif /* WITH_SFTP */
int torture_run_tests(void) {
@@ -905,6 +993,7 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_rekey_guess_wrong_recv,
session_setup,
session_teardown),
cmocka_unit_test(torture_rekey_guess_all_combinations),
#endif /* WITH_SFTP */
};

View File

@@ -2,9 +2,7 @@ project(fuzzing CXX)
macro(fuzzer name)
add_executable(${name} ${name}.c)
target_link_libraries(${name}
PRIVATE
ssh::static pthread)
target_link_libraries(${name} PRIVATE ${TORTURE_LINK_LIBRARIES})
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set_target_properties(${name}
PROPERTIES

View File

@@ -1,8 +1,14 @@
/* Simpler gnu89 version of StandaloneFuzzTargetMain.c from LLVM */
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(HAVE_LIBCRYPTO) || defined(WITH_GSSAPI)
/* for OPENSSL_cleanup() of GSSAPI's OpenSSL context */
#include <openssl/crypto.h>
#endif
int LLVMFuzzerTestOneInput (const unsigned char *data, size_t size);
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
@@ -35,5 +41,9 @@ main (int argc, char **argv)
free (buf);
printf ("Done!\n");
#if defined(HAVE_LIBCRYPTO) || defined(WITH_GSSAPI)
OPENSSL_cleanup();
#endif
return 0;
}

View File

@@ -17,10 +17,8 @@ set(pkd_hello_src
)
set(pkd_libs
${CMOCKA_LIBRARY}
ssh::static
${TORTURE_LINK_LIBRARIES}
${ARGP_LIBRARIES}
pthread
)
add_executable(pkd_hello ${pkd_hello_src})

View File

@@ -61,7 +61,7 @@
/* Dropbear */
#define DROPBEAR_BINARY "dbclient"
#define DROPBEAR_BINARY DROPBEAR_EXECUTABLE
#define DROPBEAR_KEYGEN "dropbearkey"
#define DROPBEAR_CMD_START \

View File

@@ -22,6 +22,11 @@
#include "pkd_keyutil.h"
#include "pkd_util.h"
#if defined(HAVE_LIBCRYPTO)
/* for OPENSSL_cleanup() of OpenSSL context */
#include <openssl/crypto.h>
#endif
#define DEFAULT_ITERATIONS 10
static struct pkd_daemon_args pkd_dargs;
@@ -410,22 +415,32 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
f(client, ecdsa_521_aes192_ctr, ciphercmd("aes192-ctr"), setup_ecdsa_521, teardown)
#define PKDTESTS_MAC_FIPS(f, client, maccmd) \
#define PKDTESTS_MAC_FIPS_BASE(f, client, maccmd) \
f(client, ecdsa_256_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_256, teardown) \
f(client, ecdsa_384_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_384, teardown) \
f(client, ecdsa_521_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_ecdsa_521, teardown) \
f(client, rsa_hmac_sha2_256, maccmd("hmac-sha2-256"), setup_rsa, teardown)
/* TODO: Include these tests when an older version of dropbear is used. Currently, they have been removed as the latest dropbear version
does not support these MACs.
#define PKDTESTS_MAC_FIPS_SHA1(f, client, maccmd) \
f(client, ecdsa_256_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_256, teardown) \
f(client, ecdsa_384_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_384, teardown) \
f(client, ecdsa_521_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_521, teardown) \
f(client, rsa_hmac_sha1, maccmd("hmac-sha1"), setup_rsa, teardown)
f(client, ecdsa_256_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_256, teardown) \
f(client, ecdsa_384_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_384, teardown) \
f(client, ecdsa_521_hmac_sha1, maccmd("hmac-sha1"), setup_ecdsa_521, teardown) \
f(client, rsa_hmac_sha1, maccmd("hmac-sha1"), setup_rsa, teardown) \
*/
#ifdef DROPBEAR_SUPPORTS_HMAC_SHA1
#define PKDTESTS_MAC_FIPS(f, client, maccmd) \
PKDTESTS_MAC_FIPS_BASE(f, client, maccmd) \
PKDTESTS_MAC_FIPS_SHA1(f, client, maccmd)
#define PKDTESTS_MAC_OPENSSHONLY_FIPS_SHA1(f, client, maccmd)
#else
#define PKDTESTS_MAC_FIPS(f, client, maccmd) \
PKDTESTS_MAC_FIPS_BASE(f, client, maccmd)
#define PKDTESTS_MAC_OPENSSHONLY_FIPS_SHA1(f, client, maccmd) \
PKDTESTS_MAC_FIPS_SHA1(f, client, maccmd)
#endif
#define PKDTESTS_MAC_OPENSSHONLY_FIPS(f, client, maccmd) \
PKDTESTS_MAC_OPENSSHONLY_FIPS_SHA1(f, client, maccmd) \
f(client, ecdsa_256_hmac_sha1_etm, maccmd("hmac-sha1-etm@openssh.com"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_hmac_sha2_256_etm, maccmd("hmac-sha2-256-etm@openssh.com"), setup_ecdsa_256, teardown) \
f(client, ecdsa_256_hmac_sha2_512, maccmd("hmac-sha2-512"), setup_ecdsa_256, teardown) \
@@ -990,6 +1005,9 @@ out_finalize:
if (rc != 0) {
fprintf(stderr, "ssh_finalize: %d\n", rc);
}
#if defined(HAVE_LIBCRYPTO)
OPENSSL_cleanup();
#endif
out:
return exit_code;
}

View File

@@ -11,7 +11,8 @@ set(server_SRCS
add_library(testserver STATIC
test_server.c
default_cb.c
sftpserver_cb.c)
sftpserver_cb.c
testserver_common.c)
if (WITH_COVERAGE)
append_coverage_compiler_flags_to_target(testserver)
endif (WITH_COVERAGE)
@@ -32,7 +33,7 @@ if (UNIX AND NOT WIN32)
add_executable(test_server ${server_SRCS})
target_compile_options(test_server PRIVATE ${DEFAULT_C_COMPILE_FLAGS})
target_link_libraries(test_server
PRIVATE testserver ssh::ssh ${ARGP_LIBRARIES} util)
PRIVATE testserver ${TORTURE_LINK_LIBRARIES} ${ARGP_LIBRARIES} util)
if (WITH_COVERAGE)
append_coverage_compiler_flags_to_target(test_server)
endif (WITH_COVERAGE)

View File

@@ -21,9 +21,11 @@
* MA 02111-1307, USA.
*/
#include "config.h"
#include "test_server.h"
#include "default_cb.h"
#include "testserver_common.h"
#include <libssh/callbacks.h>
#include <libssh/server.h>
@@ -448,9 +450,11 @@ static int exec_pty(const char *mode,
case 0:
close(cdata->pty_master);
if (login_tty(cdata->pty_slave) != 0) {
finalize_openssl();
exit(1);
}
execl("/bin/sh", "sh", mode, command, NULL);
finalize_openssl();
exit(0);
default:
close(cdata->pty_slave);
@@ -500,6 +504,7 @@ static int exec_nopty(const char *command, struct channel_data_st *cdata)
close(err[1]);
/* exec the requested command. */
execl("/bin/sh", "sh", "-c", command, NULL);
finalize_openssl();
exit(0);
}

View File

@@ -22,6 +22,7 @@
*/
#include "test_server.h"
#include "testserver_common.h"
#include <libssh/priv.h>
#include <libssh/libssh.h>
@@ -288,6 +289,7 @@ int run_server(struct server_state_st *state)
free_server_state(state);
SAFE_FREE(state);
finalize_openssl();
exit(0);
case -1:
fprintf(stderr, "Failed to fork\n");
@@ -355,11 +357,8 @@ fork_run_server(struct server_state_st *state,
/* The child process starts a server which will listen for connections */
rc = run_server(state);
if (rc != 0) {
exit(rc);
}
exit(0);
finalize_openssl();
exit(rc);
case -1:
strerror_r(errno, err_str, 1024);
fprintf(stderr, "Failed to fork: %s\n",

View File

@@ -0,0 +1,36 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2025 by Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@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 "testserver_common.h"
#if defined(HAVE_LIBCRYPTO) || defined(WITH_GSSAPI)
/* for OPENSSL_cleanup() of GSSAPI's OpenSSL context */
#include <openssl/crypto.h>
#endif
void finalize_openssl(void)
{
#if defined(HAVE_LIBCRYPTO) || defined(WITH_GSSAPI)
OPENSSL_cleanup();
#endif
}

View File

@@ -0,0 +1,26 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2025 by Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@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"
void finalize_openssl(void);

View File

@@ -451,5 +451,5 @@ torture_run_tests(void)
teardown_default_server);
ssh_finalize();
pthread_exit((void *)&rc);
return rc;
}

View File

@@ -475,5 +475,5 @@ torture_run_tests(void)
teardown_default_server);
ssh_finalize();
pthread_exit((void *)&rc);
return rc;
}

View File

@@ -371,5 +371,5 @@ torture_run_tests(void)
teardown_default_server);
ssh_finalize();
pthread_exit((void *)&rc);
return rc;
}

View File

@@ -27,6 +27,7 @@ int main(int argc, char **argv)
const char *banner = NULL;
ssh_session session = NULL;
const char *hostkeys = NULL;
const char *kex = NULL;
int rc = 1;
bool process_config = false;
@@ -67,6 +68,13 @@ int main(int argc, char **argv)
goto out;
}
/* Enable all supported kex algorithms */
kex = ssh_kex_get_supported_method(SSH_KEX);
rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, kex);
if (rc < 0) {
goto out;
}
rc = ssh_connect(session);
if (rc != SSH_OK) {
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));

View File

@@ -65,6 +65,8 @@
#cmakedefine NCAT_EXECUTABLE "${NCAT_EXECUTABLE}"
#cmakedefine SSHD_EXECUTABLE "${SSHD_EXECUTABLE}"
#cmakedefine SSH_EXECUTABLE "${SSH_EXECUTABLE}"
#cmakedefine SSH_EXECUTABLE_SIZE "${SSH_EXECUTABLE_SIZE}"
#cmakedefine DROPBEAR_EXECUTABLE "${DROPBEAR_EXECUTABLE}"
#cmakedefine WITH_TIMEOUT ${WITH_TIMEOUT}
#cmakedefine TIMEOUT_EXECUTABLE "${TIMEOUT_EXECUTABLE}"
#cmakedefine SOFTHSM2_LIBRARY "${SOFTHSM2_LIBRARY}"

View File

@@ -52,6 +52,11 @@
#include <valgrind/valgrind.h>
#endif
#ifdef WITH_GSSAPI
/* for OPENSSL_cleanup() of GSSAPI's OpenSSL context */
#include <openssl/crypto.h>
#endif
#define TORTURE_SSHD_SRV_IPV4 "127.0.0.10"
/* socket wrapper IPv6 prefix fd00::5357:5fxx */
#define TORTURE_SSHD_SRV_IPV6 "fd00::5357:5f0a"
@@ -1848,9 +1853,31 @@ __attribute__((weak)) int torture_run_tests(void)
}
#endif /* defined(HAVE_WEAK_ATTRIBUTE) && defined(TORTURE_SHARED) */
int main(int argc, char **argv) {
/**
* Finalize the torture context. No-op except for OpenSSL or GSSAPI
*
* When OpenSSL is built without the at-exit handlers, it won't call the
* OPENSSL_cleanup() from destructor or at-exit handler, which means we need to
* do it manually in the tests.
*
* It is never a good idea to call this function from the library context as we
* can not be sure the libssh is really the last one using the OpenSSL.
*
* This needs to be called at the end of the main function or any time before
* any forked process (servers) exits.
*/
void torture_finalize(void)
{
#if defined(HAVE_LIBCRYPTO) || defined(WITH_GSSAPI)
OPENSSL_cleanup();
#endif
}
int main(int argc, char **argv)
{
struct argument_s arguments;
char *env = getenv("LIBSSH_VERBOSITY");
int rv;
arguments.verbose=0;
arguments.pattern=NULL;
@@ -1868,5 +1895,9 @@ int main(int argc, char **argv) {
cmocka_set_test_filter(pattern);
#endif
return torture_run_tests();
rv = torture_run_tests();
torture_finalize();
return rv;
}

View File

@@ -178,4 +178,6 @@ int torture_change_dir(char *path);
void torture_setenv(char const* variable, char const* value);
void torture_unsetenv(char const* variable);
void torture_finalize(void);
#endif /* _TORTURE_H */

View File

@@ -2468,9 +2468,9 @@ static void torture_config_make_absolute_int(void **state, bool no_sshdir_fails)
char *home = NULL;
struct passwd *pw = getpwuid(getuid());
assert_non_null(pw);
user = pw->pw_name;
user = strdup(pw->pw_name);
assert_non_null(user);
home = pw->pw_dir;
home = strdup(pw->pw_dir);
assert_non_null(home);
#endif
@@ -2528,6 +2528,8 @@ static void torture_config_make_absolute_int(void **state, bool no_sshdir_fails)
snprintf(h, 256 - 1, "/etc/ssh/~%s/.ssh/config.d/*.conf", user);
assert_string_equal(result, h);
free(result);
free(home);
free(user);
#endif
}

View File

@@ -133,10 +133,9 @@ static int teardown(void **state) {
return 0;
}
static int disable_secmem(void **state)
static void
disable_secmem(void)
{
(void) state; /*unused*/
#if defined(HAVE_LIBGCRYPT)
/* gcrypt currently is configured to use only 4kB of locked secmem
* (see ssh_crypto_init() in src/libcrypt.c)
@@ -145,23 +144,10 @@ static int disable_secmem(void **state)
* To avoid the expected warning, disable the secure memory.
* */
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN);
gcry_control(GCRYCTL_DISABLE_SECMEM);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
#endif
return 0;
}
static int enable_secmem(void **state)
{
(void) state; /*unused*/
#if defined(HAVE_LIBGCRYPT)
/* Re-enable secmem */
gcry_control(GCRYCTL_INIT_SECMEM, 4096);
gcry_control(GCRYCTL_RESUME_SECMEM_WARN);
#endif
return 0;
}
static void *thread_pki_rsa_import_pubkey_file(void *threadid)
@@ -756,18 +742,21 @@ int torture_run_tests(void)
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_pubkey_file,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64_NULL_key,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64_NULL_str,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(
torture_pki_rsa_import_privkey_base64_NULL_key,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(
torture_pki_rsa_import_privkey_base64_NULL_str,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_import_privkey_base64,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_publickey_from_privatekey,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(
torture_pki_rsa_publickey_from_privatekey,
setup_rsa_key,
teardown),
cmocka_unit_test(torture_pki_rsa_import_privkey_base64_passphrase),
cmocka_unit_test_setup_teardown(torture_pki_rsa_copy_cert_to_privkey,
setup_rsa_key,
@@ -781,12 +770,8 @@ int torture_run_tests(void)
cmocka_unit_test_setup_teardown(torture_pki_rsa_duplicate_key,
setup_rsa_key,
teardown),
cmocka_unit_test_setup_teardown(torture_pki_rsa_generate_key,
disable_secmem,
enable_secmem),
cmocka_unit_test_setup_teardown(torture_mixed,
setup_rsa_key,
teardown),
cmocka_unit_test(torture_pki_rsa_generate_key),
cmocka_unit_test_setup_teardown(torture_mixed, setup_rsa_key, teardown),
};
/*
@@ -801,6 +786,7 @@ int torture_run_tests(void)
* If the library is statically linked, ssh_init() is not called
* automatically
*/
disable_secmem();
ssh_init();
torture_filter_tests(tests);
rc = cmocka_run_group_tests(tests, NULL, NULL);

View File

@@ -248,23 +248,9 @@
Reachable memory from getaddrinfo
Memcheck:Leak
match-leak-kinds: reachable
fun:malloc
fun:UnknownInlinedFun
fun:_dl_new_object
fun:_dl_map_object_from_fd
fun:_dl_map_object
fun:dl_open_worker_begin
fun:_dl_catch_exception
fun:dl_open_worker
fun:_dl_catch_exception
fun:_dl_open
fun:do_dlopen
fun:_dl_catch_exception
fun:_dl_catch_error
fun:dlerror_run
fun:__libc_dlopen_mode
fun:module_load
...
fun:__nss_module_get_function
...
fun:getaddrinfo
...
fun:krb5_sname_to_principal
@@ -285,7 +271,6 @@
fun:torture_run_tests
fun:main
}
## libkrb5
# krb5_mcc_generate_new allocates a hashtab on a static global variable
# It doesn't get freed.
@@ -298,3 +283,30 @@
...
fun:krb5_mcc_generate_new*
}
{
Error string from acquire creds in krb5
Memcheck:Leak
match-leak-kinds: reachable
fun:malloc
...
fun:krb5_gss_save_error_string
fun:UnknownInlinedFun
fun:acquire_cred_context.isra.0
fun:acquire_cred_from.isra.0
fun:gss_add_cred_from
fun:gss_acquire_cred_from
...
fun:gss_acquire_cred
}
{
error string from gss init sec context
Memcheck:Leak
match-leak-kinds: reachable
fun:malloc
...
fun:krb5_gss_save_error_string
fun:UnknownInlinedFun
fun:krb5_gss_init_sec_context_ext
fun:krb5_gss_init_sec_context
fun:gss_init_sec_context
}