Compare commits

..

289 Commits

Author SHA1 Message Date
Jakub Jelen
118a747acd socket: Free poll handle when resetting socket state
Since 07cb0be12 we are not closing the user provided FDs,
but the above change also resulted in memory leak during
ssh_disconnect that left the poll_handle allocated during
reset.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:31 +02:00
Jakub Jelen
5691e0f609 poll: Initialize ssh_poll_handle pointers
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:31 +02:00
Jakub Jelen
5a6e2fd02a poll: Fix memory leak on failed realloc()
In cases where this is the initial allocation, the shrinking of the polltrs
buffer would result in 0B realloc, which really does not make sense. Also,
when this second realloc fails, the memory is never freed as the outer code
believes there is nothing allocated on the poll_ctx

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:31 +02:00
Jakub Jelen
e8099375fe poll: Check return value of ssh_poll_ctx_add()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:13:27 +02:00
Jakub Jelen
d00f267bc6 Make ssh_socket_set_fd() return errors
and properly check the return value where it is used

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:12:47 +02:00
Jakub Jelen
35d337834b options: Avoid memory leaks on allocation failures
When allocation during tilde expansion fails, libssh could
leak a memory.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:12:47 +02:00
Jakub Jelen
ba1e8303f8 reformat remains of poll.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-12 12:12:43 +02:00
Jakub Jelen
ef50a3c0f0 tests: Remove tests of operations on freed channels
These tests are flaky because even though the care was taken to guess if
the ssh_channel_free() really freed the channel, it might not always be correct
and call to operation on the freed channel results in use after free.

Generally, no operation should be called after the channel is freed by the user.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:18:45 +02:00
Jakub Jelen
e7cffe7e1b pki: Simplify ed25519 private key duplication
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:18:20 +02:00
Jakub Jelen
d1bf9068a9 Use calloc instead of zeroizing structure after malloc
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:16:58 +02:00
Jakub Jelen
737f9ecc3c agent: Reformat the rest of the file
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-08-06 11:16:58 +02:00
Praneeth Sarode
cc667021e5 tests(pki): add torture tests for security keys
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:58 +05:30
Praneeth Sarode
f9f8c939bc tests(pki): add security key testing helper functions to torture library
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:54 +05:30
Praneeth Sarode
aab6ce364a tests(pki): add sk type keys to the testing infrastructure
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:41 +05:30
Praneeth Sarode
0cec257077 pki: add security key file import/export functionality
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 15:28:36 +05:30
Praneeth Sarode
957efe51a2 format(pki): format the pki_import_privkey_buffer function
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-08-01 00:29:27 +05:30
Praneeth Sarode
bb85492d4f feat(pki): add support for SK key types in signature handling
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 23:00:53 +05:30
Praneeth Sarode
22c1b6970c pki: add security key fields to ssh_key_struct and update compare, copying and cleaning functions
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 22:47:59 +05:30
Praneeth Sarode
09155adb19 tests(string): add unit tests for ssh_string_cmp function
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:06:32 +02:00
Praneeth Sarode
95f8cbc7f0 feat(string): add ssh_string_cmp function for comparing ssh_strings
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:06:31 +02:00
Praneeth Sarode
3423399f98 fix(pki): remove redundant key type_c assignment in pki_import_pubkey_buffer
We already assign the correct key type_c using ssh_key_type_to_char before this point.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:05:52 +02:00
Praneeth Sarode
ccbec9c275 fix(pki): remove redundant key type_c assignment in build pubkey and privkey functions
Whenever the pki_pubkey_build_ecdsa and pki_privkey_build_ecdsa functions are called, the key type assignment is already done. So, we don't need to assign it again. Moreover, because the pki_key_ecdsa_nid_to_name function was used, for key types like the SSH_KEYTYPE_SK_ECDSA, we assign the wrong type string to the key, based on the nid.

Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 16:05:51 +02:00
Praneeth Sarode
ed52c88a03 feat(misc): add burn_free function and BURN_FREE macro for secure memory deallocation
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 12:35:12 +02:00
Till Wimmer
0f0ac314d2 session: add err messages for most common WSA error codes (+ applied clang-format to file)
Signed-off-by: Till Wimmer <github@tonarchiv.ch>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-30 12:33:42 +02:00
Navid Fayezi
95e4c39e8a Refactor: fix inconsistency in ssh_callback_struct
Signed-off-by: Navid Fayezi <navidfayezi.98@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-30 12:31:07 +02:00
Jakub Jelen
8c89633a45 pki: Avoid possible memory leak
Actually the condition was duplicated at the beginning of the function and this
one could not be hit (again), but it is an error to be fixed anyway.

Thanks Coverity!

CID 1618865

CID 1618864

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-29 15:39:37 +02:00
Rémi Coulom
8069679033 remove unused ssh_string in ssh_channel_open_forward_unix
Signed-off-by: Rémi Coulom <remi.coulom@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-25 19:52:37 +02:00
Jakub Jelen
c2e9d39dbe 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>
2025-07-25 16:40:56 +02:00
Jakub Jelen
ab44f606b2 tests: Add more valgrind supressions for krb5
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
444982b38a tests: Avoid needless call to pthread_exit()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
3df61a4e86 pkd: Cleanup OpenSSL context
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
961c79637c options: Fix possible memory leaks on error conditions when setting keys for bind
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
7eefbbd478 tests: Cleanup OpenSSL in the forked server processes
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
c4c28c6473 tests: Skip test leaking handle under valgrind
This is leaking memory allocated in process_open(), which is stored in the
handles list in the sftpserver session. Given that the data is provided by the
use callbacks, we can not universally free them on our side, but we should, in
the long term, introduce some way for the implementers to free outstanding
handles that were not closed by misbehaving clients.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
08a32ac381 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>
2025-07-25 13:20:15 +02:00
Jakub Jelen
62762bbbc9 Cleanup the loaded pkcs11 provider
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
ab3e08c2b5 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>
2025-07-25 13:20:15 +02:00
Jakub Jelen
809898b980 tests: Adjust valgrind supression to match new calls stack
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-25 13:20:15 +02:00
Jakub Jelen
51bd08027e 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>
2025-07-25 13:20:15 +02:00
Praneeth Sarode
0b4b71cc11 fix(callbacks): make is_callback_valid's behaviour consistent with its name
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-24 16:10:54 +02:00
Praneeth Sarode
5d3ef7261c refactor(callbacks): reformat to improve readability
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-24 16:10:53 +02:00
Jakub Jelen
9817392e26 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>
2025-07-24 16:09:55 +02:00
Nguyễn Thái Ngọc Duy
168302b9d6 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>
2025-07-24 13:08:46 +02:00
Jakub Jelen
82c8bbc504 tests: Add missing header file to unbreak build on freebsd
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-07-24 11:13:35 +02:00
Jakub Jelen
1ea1782036 Add simple sshsig fuzzer
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-07-24 11:13:34 +02:00
abdallah elhdad
c17112f070 Enable HMAC SHA1 tests for dropbear <2025.87
Signed-off-by: abdallah elhdad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-24 10:49:51 +02:00
Nicolas Graves
28c0056bca Add logging for private API functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-10 11:21:44 +02:00
Nicolas Graves
7e4f08e22a Add logging to public API functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-10 11:21:44 +02:00
Nicolas Graves
aeb0b2ec6f Add unittests for sshsig functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-10 11:21:44 +02:00
Nicolas Graves
67cf8e3702 Implement sshsig functions
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-02 14:38:07 +02:00
Nicolas Graves
309f36fa83 pki: Add key_to_type_hash helper
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-07-02 14:38:07 +02:00
Praneeth Sarode
7a2a743a39 fix(string): handle empty string case in ssh_string_copy
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-02 13:58:51 +02:00
Theo Buehler
ccb8cf88c8 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>
2025-07-01 20:50:25 +02:00
Praneeth Sarode
b43392c31d tests(string): add unit tests for ssh_string functions
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-01 20:49:39 +02:00
Andreas Schneider
5fc65e7270 agent: Fix resource leak
CID 1611718

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-01 20:48:52 +02:00
Navid Fayezi
8310b8cc2b Remove redundant line and change strlen(buffer) to sizeof(buffer) in examples/authentication.c
Signed-off-by: Navid Fayezi <navidfayezi.98@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-07-01 20:47:55 +02:00
Navid
b0063b52d8 Remove more redundant casts
Signed-off-by: Navid Fayezi navidfayezi.98@gmail.com
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-01 20:38:03 +02:00
Navid
33a947dcb0 Remove unnecessary char* cast in memset call in examples/examples_common.h
Signed-off-by: Navid Fayezi navidfayezi.98@gmail.com
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-07-01 20:38:03 +02:00
Jakub Jelen
72c282434b dh-gex: Reformat the dhgex_server_callbacks structure
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-24 10:14:29 +02:00
Jakub Jelen
ba9642882d dh-gex.c: Fix typo in the constant name
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-24 10:14:25 +02:00
Jakub Jelen
a6b73219e2 packet: Implement missing packet filter for DH GEX
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-24 10:14:21 +02:00
Jakub Jelen
e2afe196d8 CVE-2025-5372 libgcrypto: Simplify error checking and handling of return codes in ssh_kdf()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
32833b40bc libgcrypto: Reformat ssh_kdf()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
bc4804aa9b CVE-2025-5987 libcrypto: Correctly detect failures of chacha initialization
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
acb158e827 CVE-2025-5351 pki_crypto: Avoid double-free on low-memory conditions
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
faf9caafc6 pki_crypto: Reformat pki_key_to_blob()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
8dc29f140b CVE-2025-4878 legacy: Properly check return value to avoid NULL pointer dereference
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
7501ca1e08 examples: Fix possible pass of NULL into strchr()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
2eb2af4426 CVE-2025-4878 Initialize pointers where possible
This is mostly mechanical change initializing all the pointers I was able to
find with some grep and manual review of sources and examples.

Used the following greps (which yield some false positives though):

    git grep "    \w* *\* *\w*;$"
    git grep " ssh_session \w*;"
    git grep " ssh_channel \w*;"
    git grep " struct ssh_iterator \*\w*;"
    git grep " ssh_bind \w*;"
    git grep " ssh_key \w*;"
    git grep " ssh_string \w*;"
    git grep " ssh_buffer \w*;"
    git grep " HMACCTX \w*;"
    git grep " SHACTX \w*;"
    grep -rinP '^(?!.*=)\s*(?:\w+\s+)*\w+\s*\*\s*\w+\s*;'

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
5d27f69494 string: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
6fc1bf6901 session: Reformat ssh_get_publickey_hash
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
a85813e6e6 poll: Reformat ssh_poll_ctx_resize
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Jakub Jelen
f039edd85d examples: Reformat sshnetcat.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 15:24:30 +02:00
Andreas Schneider
1229ad650b src: Reformat pki_gcrypt.c
clang-format -i pki_gcrypt.c

Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-06-23 15:24:18 +02:00
Jakub Jelen
937552aed2 pki: Reformat ssh_pki_copy_cert_to_privkey()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
f6709b03e6 misc: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
96595d1674 messages: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
c799a18d89 channels: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
babd891e82 examples: Reformat senddata.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
320e5154b2 examples: Reformat scp_download.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
986e0c593f examples: Reformat connect_ssh.c
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:48:16 +02:00
Jakub Jelen
d38007c4be CVE-2025-5449 sftpserver: Use constant for return values
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
c22bfa792f CVE-2025-5449 tests: Reproducer for payload length overrun
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
926d45b6dd CVE-2025-5449 sftpserver: Fix possible read behind buffer on 32bit arch
On 32b architecture when processing the SFTP packets, the value
0x7ffffffc in the payload_len will overflow to negative integer values,
causing these checks to pass and possibly reading behind the buffer
bounds later.

This affects only SFTP server implementations running on 32b
architecture.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
681a5aaa26 CVE-2025-5449 tests: Reproducer for server processing invalid handles
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
e322e8f50c CVE-2025-5449 sftpserver: Avoid NULL dereference for invalid handles
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
a4118ddc06 CVE-2025-5449 tests: Reproducer for sftp handles exhaustion
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
db7f101d1c CVE-2025-5449 sftpserver: Avoid memory leak when we run out of handles during sftp_open
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
ae8881dfe5 CVE-2025-5318: sftpserver: Fix possible buffer overrun
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:37:06 +02:00
Jakub Jelen
00f09acbec CVE-2025-4877 base64: Prevent integer overflow and potential OOB
Set maximum input to 256MB to have safe margin to the 1GB trigger point
for 32b arch.

The OOB should not be reachable by any internal code paths as most of
the buffers and strings we use as input for this operation already have
similar limit and none really allows this much of data.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-06-23 13:33:10 +02:00
Lucas Mulling
74eb01f26d tests: Cleanup torture_channel_exit_signal
Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-06-04 19:46:12 +02:00
Jakub Jelen
4f239f79c6 mbedtls: Avoid one more memory leak
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
b8e587e498 pki: Set ECDSA signature buffers secure
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
b314fd3e04 mbedtls: Rename label to match the current meaning
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
d1ad796496 mbedtls: Avoid code duplication between v2 and v3 branches
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
e2064b743d pki: Make sure the buffer is zeroized too
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
6d2a3e4eb6 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>
2025-06-03 15:38:24 +02:00
Jakub Jelen
7c34fa783d mbedcrypto: Refromat pki_key_to_blob()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-06-03 15:38:24 +02:00
Jakub Jelen
2a2c714dfa tests: Auth without none method
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-06-03 10:23:17 +02:00
Jakub Jelen
12baa5200a auth: Process outstanding packets before selecting signature algorithm
Originally reported by Till on mailing list here:

https://archive.libssh.org/libssh/2025-05/0000000.html

After some debugging, it turns out the client code does not guarantee
the extensions are processed before making decisions on the signature algorithm
that is being used for authentication, causing false-positive failures.

This does not happen in the tests, where we initially call ssh_userauth_none,
which enumerates authentications methods and as a side effect processes
outstanding packets such as SSH_EXT_INFO message with the server-sig-algs
extension.

When the first function called after `ssh_connect()` is
`ssh_userauth_publickey()`, the `ssh_userauth_request_service()` was wrongly
called only after the signature algorithm compatibility was checked.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-06-03 10:23:17 +02:00
Jakub Jelen
f2b64abcbd buffer: Use sizeof instead of magic number
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-06-03 10:23:17 +02:00
Nicolas Graves
4135154b6d cmocka_unit_test_setup_teardown: Comply with codespell style.
Signed-off-by: Nicolas Graves <ngraves@ngraves.fr>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-30 20:11:51 +02:00
Praneeth Sarode
ca4c874a9e tests: remove unsupported SHA1 HMAC tests for compatibility with latest dropbear version
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-27 13:50:03 +02:00
Rohan Eden
c7b6ffad0e Remove height due to inconsistent display in browser
Signed-off-by: Rohan Eden <rohan.eden@citypaine.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-20 18:27:46 +02:00
salonidabgar
c1fb0d872d Reformatted torture_auth_cert.c
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
3a167a89b5 Added tests for auth agent forwarding
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
dfa9421e01 Added preprocessor directives for Windows
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
efc5bc633f Reformatted torture.c and torture.h
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
3a4ba8b763 Fix file permissions: remove executable bit from CMakeLists.txt as it's a configuration file
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
47db54b7c1 Move torture_setup_ssh_agent() and torture_cleanup_ssh_agent() to torture.c
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
salonidabgar
d1c2d3db9d Added .DS_Store to .gitignore
Signed-off-by: salonidabgar <salonidabgar@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-14 13:45:23 +02:00
Praneeth Sarode
dcb65fe584 refactor(curve25519): split the single file curve25519.c into multiple files for better readability
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-05-06 22:03:18 +02:00
Lucas Mulling
d758990d39 misc: Fix OpenSSH banner parsing
Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-28 14:56:27 -03:00
Andreas Schneider
bfae56634c tests:unittests: Fix tests on FreeBSD
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-24 10:47:26 +02:00
Jakub Jelen
3d0226cadc examples: Avoid using uninitialized memory
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
0bcd7d12d8 dh-gex: Avoid reading the EOF stream
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
bd10ec1162 tests: Use fseek instead of rewind to simplify error checking
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
69c169e4cb sftpserver: Free memory on error condition
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
f0b9db586b test: Fix potential leak of fds on error
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
c735b44f83 test: Fix unused variables and potential memory leaks
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
3b4b8033de tests: Make the static ananlyzers happy with the threads
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 17:41:22 +02:00
Jakub Jelen
0068fdd594 examples: Fix possible null pointer passed to open()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-16 16:19:42 +02:00
Praneeth Sarode
344235c954 fix(tests): improve synchronization in torture_forwarded_tcpip_callback tests
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-16 14:49:40 +02:00
Jakub Jelen
d00f7b1bf9 Make sure we pass right parameters to buffer_pack
Fixes: #299

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
b14018ecab tests: Do not build zlib test when built without
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
5e47b1c1c2 kex: Add more noisy errors to simplify debugging ssh_make_sessionid
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
9ce885b168 ci: Add mbedTLS + clang build combination
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
Jakub Jelen
184dad101d Move the PKCS#11 provider environment variable where it needs to be
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-04-15 16:15:52 +02:00
RaviRaaja
04a58919f8 Fix: NULL pointer check in ssh_channel_is_closed
The ssh_channel_is_closed function would crash when
accessing channel->session->alive if session is NULL.
This patch adds a null check before accessing the session
pointer.

- build succeeded
- unit test passed
- no new unit test added

https://gitlab.com/libssh/libssh-mirror/-/issues/239

Signed-off-by: Raviraaja Lakshmanan <mailstoraviraaja@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-14 22:20:35 +02:00
Norbert Pocs
b106211d92 clang-format: Align consecutive macros
This option makes padding between macro names and the values based on
the longest macro name in a consecutive list of macro lines.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-14 22:20:08 +02:00
Norbert Pocs
af10857aa3 CmakeLists: Fix multiple digit major version for OpenSSH
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-14 22:19:18 +02:00
Praneeth Sarode
f3b389d112 tests: add unit test for direct-tcpip channel open request
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-07 14:02:41 +02:00
Praneeth Sarode
18e7423e70 Add direct-tcpip channel open request callback support
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-07 14:02:21 +02:00
Praneeth Sarode
8c8d3ceef7 tests: add unit test for forwarded-tcpip callback
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-07 10:57:21 +02:00
Praneeth Sarode
0d0ed4b1f8 curve25519: add support for gcrypt's Curve25519 implementation
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-03 11:28:44 +02:00
Arek Ouzounian
8dc234c909 Add clarification to INSTALL for unit testing on Windows via the cmocka dependency
Signed-off-by: Arek Ouzounian <agouzo777@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-03 11:27:45 +02:00
Praneeth Sarode
2e686c5cea cmake: fix MbedTLS version detection
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-03 11:27:08 +02:00
Jakub Jelen
d3706d5940 Add missing symbol to the map
This was omitted from the 84d02e74 and caused issues to build when abimap is
not present.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-04-02 10:59:53 +02:00
Praneeth Sarode
d92a057090 tests: fix torture_server_x11 and add it to tests
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-04-01 10:19:14 +02:00
Jakub Jelen
1434f24911 auth: Avoid forward-null pointer dereference
This could happen only if the function would really be called with the NULL
session, but this was never the case as the session is dereferenced already on
all code paths toward this place.

This is just to make the scanner happy that the session can not really be NULL
here.

Thanks coverity!

CID 1593926

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <norbertpocs0@gmail.com>
2025-03-31 11:05:37 +02:00
Aditya Sinha
cce600f980 test for ssh_get_kex_algo()
Signed-off-by: Aditya Sinha <aditya072006@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:10:53 +02:00
Aditya Sinha
95150b1137 Adding the missing Algorithms to ssh_get_kex_algo() function
Signed-off-by: Aditya Sinha <aditya072006@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:10:52 +02:00
Aditya Sinha
65b2591b91 Reformatting the ssh_get_kex_aglo() function
Signed-off-by: Aditya Sinha <aditya072006@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:10:51 +02:00
Praneeth Sarode
a5e9529ca7 curve25519: refactor mbedTLS code to remove code duplication
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:04:48 +02:00
Praneeth Sarode
49a355c272 curve25519: Use mbedTLS curve25519 for ECDH, if available
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 13:04:47 +02:00
David Wedderwille
84d02e7440 kex: Make existing convenience features available
Signed-off-by: David Wedderwille <davidwe@posteo.de>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 12:17:42 +02:00
David Wedderwille
0b91ba779c kex: Improved naming of variables.
Signed-off-by: David Wedderwille <davidwe@posteo.de>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 12:17:41 +02:00
Yuvraj Saxena
d02163546d fuzz: Add ProxyJump misconfiguration cases to ssh_client_config_fuzzer_corpus
This commit adds test cases to catch issues where ProxyJump configurations lead to infinite loops or incorrect username usage, as reported in issue #287, and issue #291

Signed-off-by: Yuvraj Saxena <ysaxenax@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-30 12:14:37 +02:00
AsadaShino
a93e84efb9 authenticate_console:Stop authentication after SSH session disconnection to avoid hanging up in poll
Signed-off-by: AsadaShino <1164429449@qq.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-20 15:29:59 +01:00
Eshan Kelkar
a59d587060 sftpserver.c: Add support for O_TRUNC while opening files
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 18:13:52 +01:00
Eshan Kelkar
6c4e4a9e1c torture_sftpserver.c: Add test for O_TRUNC while opening files
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 18:13:51 +01:00
Abdallah Alhadad
aa681c268e extensions: Host-bound public key authentication
Signed-off-by: Abdallah Alhadad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 17:34:04 +02:00
Abdallah Alhadad
fe381d6aa4 refactor: Extract build_pubkey_auth_request function for public key authentication
Signed-off-by: Abdallah Alhadad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-18 17:33:57 +02:00
Abdallah Alhadad
1f76cc0c6a reformat: functions related to pubkey authentication
Signed-off-by: Abdallah Alhadad <abdallahselhdad@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-15 22:16:46 +00:00
John Thacker
bf2b8954e8 CMake: Add Requires.private information for GSSAPI to .pc file
Try to find GSSAPI via pkg-config. If found, add the appropriate
module name, depending on the flavor, to the libssh.pc file so that
the pkg-config can report the list of libraries needed when linking
against the static library version of libssh.

Fix #293

Signed-off-by: John Thacker <johnthacker@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-12 15:05:57 +01:00
Jakub Jelen
7e3935e7d2 Add timeout extension requirement to the MR template
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-11 14:03:23 +01:00
Jakub Jelen
d38b471fd8 ci: Move MR template from webui to git
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-11 14:03:22 +01:00
Jakub Jelen
735a4368c2 Document the need to extend the CI timeout
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-11 14:03:21 +01:00
Jakub Jelen
a25f9d211d tests: Fix variable names to avoid codespell issues
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 16:00:33 +01:00
Jakub Jelen
3a52bf1679 tests: Reproducer for graceful failure on ignored Match arguments
https://gitlab.com/libssh/libssh-mirror/-/issues/291#note_2376323499
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 16:00:33 +01:00
Jakub Jelen
f7bdd779d6 config: Be less strict when parsing unknown Match keywords
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 16:00:33 +01:00
Jakub Jelen
8ef249a4a4 config: Fix copy&paste error in error message
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-03-04 14:09:08 +01:00
Praneeth Sarode
d9da8f212d docs: Add section on ABI versioning and symbol management to CONTRIBUTING.
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-04 13:00:27 +01:00
Norbert Pocs
9613e9508d tests/torture_proxyjump: Fix codespell issues
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-03 11:20:48 +01:00
Norbert Pocs
6b9a6529bd tests: Add torture_proxyjump_multiple_users_sshd_jump with Doe
Tests proxyjump with two servers and two users.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-03 11:20:48 +01:00
Norbert Pocs
b14cde6d2a tests: Add multiple server proxyjump testcase
Tests proxyjump with the same user through two servers.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-03-03 11:20:48 +01:00
Norbert Pocs
e01c32f41e tests: Add torture_setup_sshd_servers
Starts a second sshd. This enables to test proxyjump through
multiple servers.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-02-28 10:05:12 +01:00
Jakub Jelen
dd6a711354 Use windows-compatible access() function to unbreak windows build
Fixes up 3372c2ad78 which did not properly check
the included header file.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-27 13:31:35 +01:00
Jakub Jelen
c1a7de78d1 tests: Add PKCS#11 URI tests with Ed25519 keys
This will work only with pkcs11 provider. Not tested with engines.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
9735f074ba tests: Skip Ed25519 keys in FIPS mode
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
b2b56151c0 pki: Fail more gracefully when parsing Ed25519 keys in FIPS mode
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
de7903a633 Do not import Ed25519 keys in FIPS Mode
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
a089513e40 pki_crypto: OpenSSL 1.1.1 compatible Ed25519 key duplication
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
ec9d7d13fd Use Ed25519 in OpenSSL through the EVP_PKEY API
... instead of keeping around public and private key blobs.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
f14568262a tests: Update PKCS#11 tests to follow global verbosity
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
257e8eb2c1 tests: Add PEM public Ed25519 key
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
99fcd56135 tests: Remove p11-kit remoting from pkcs11 tests
The p11-kit remoting was initially introduced because softhsm
was crashing during cleanup with OpenSSL 3.0. This was resolved
since then and this code introduces a lot of complexity and
possible bugs, such as when using the mechanisms from PKCS#11 3.0
that are unknown to the p11-kit remoting tool. It decides to remove
them from the list as demonstrated here:

https://github.com/p11-glue/p11-kit/issues/668

This resulted in pkcs11-provider not registering EDDSA siganture
methods to the OpenSSL and failing when asked to provide a singature
by the Ed25519 key from the PKCS#11 token.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
8922e43578 tests: Improve logging on failures in ed25519 test
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
e36ca61e36 pki: Fix error message
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
02c092d3d9 pki: Avoid needless assignment
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
520f758902 pki_crypto: Reformat pki_key_compare
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Jakub Jelen
12b8eed093 pki_crypto: Reformat pki_private_key_to_pem
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-02-27 10:52:17 +01:00
Lucas Mulling
3372c2ad78 cmake: Add option WITH_HERMETIC_USR
Add a cmake option to enable hermetic-usr, i.e., use of config files in /usr/.
If turned on, GLOBAL_*_CONFIG is prepended with /usr/ and defined as
USR_GLOBAL_*_CONFIG. Config lookup follows this path GLOBAL_*_CONFIG ->
USR_GLOBAL_*_CONFIG.

Introduce a ssh_config_parse primitive. This avoids convoluted checks for file
presence (without modifing the behaviour of ssh_config_parse_file) and allows
marking whether the config is global at the call site.

Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-02-27 10:24:42 +01:00
John Thacker
6b83aa9a40 CMake: Use GSSAPI_INCLUDE_DIR consistently
The GSSAPI find module sets GSSAPI_INCLUDE_DIR (singular) only and
passes that to find_package_handle_standard_arguments, but later
tests and marks as advanced GSSAPI_INCLUDE_DIRS (plural), which doesn't
exist. GSSAPI_INCLUDE_DIR is what's used in src/CMakeLists.txt

This hasn't had a major effect, because GSSAPI_FOUND gets set by
find_package_handle_standard_args, so the if statement that tests
GSSAPI_INCLUDE_DIRS (and never succeeded) would have been a no-op
in any case, so remove it. Standardize on the singular version when
marking as advanced.

Signed-off-by: John Thacker <johnthacker@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-26 10:14:59 +01:00
Jakub Jelen
7f045e2d91 tests: Unit test nested quotes
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 13:20:20 +01:00
Jakub Jelen
2b916b3b88 tests: Reformat test list
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 12:17:34 +01:00
Jakub Jelen
a10553ae57 Reproducer for #291
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 12:17:34 +01:00
Jakub Jelen
d1ce336ae3 config: Allow escaping quotes inside of quoted tokens
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-02-11 12:17:34 +01:00
Praneeth Sarode
79ac8b85d8 tests: add tests for users-groups-by-id@openssh.com on client side
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-02-05 17:01:40 +05:30
Praneeth Sarode
9a9cafeed5 sftp: add users-groups-by-id@openssh.com extension for client
Signed-off-by: Praneeth Sarode <praneethsarode@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2025-02-05 17:01:20 +05:30
Andreas Schneider
a0a5292692 gitlab-ci: Improve abidiff
Only fail if it is an ABI incompatible change.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-01-31 11:39:01 +01:00
Eshan Kelkar
1a64c577f6 sftp.c: Validate that the SSH session is in nonblocking mode
The sftp API functions cannot interoperate properly with a
nonblocking ssh session.

Therefore code has been added in sftp_new() due to which the
function will return failure if the caller passes a non
blocking session without even trying to connect.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2025-01-29 13:52:51 +01:00
Jakub Jelen
c03d0d4823 ci: Do not run macos tests on third-party MRs
The macos images are not available for third-party contributors and
they prevent the CI to continue from the tests stage.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-26 22:14:59 +01:00
Jakub Jelen
d5456931cc examples: Fix format string unearthed during macos build
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-21 11:35:12 +01:00
Jakub Jelen
dc18b41357 cmake: Do not attempt to use -fstack-clash-protection on MacOS M1 chips
This is supported in clang, but only on x86_64 so we need to back down to the
architecture checks. Otherwise the checks pass with warning, but the build
itself fails with errors (-Werror).

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-21 11:35:12 +01:00
DreadPirate07
0f5dec7fb7 ci: add macOS environment to GitLab CI
Fixes: #161

Co-Authored-By: DreadPirate07 <tanayraikhere@gmail.com>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-21 11:35:12 +01:00
Jakub Jelen
0cda1c0e83 bignum: Make sure the padding is large enough for the number
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
1ea9708409 tests: Verify the right implementation is used
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
39fcaac3ca Use gcrypt implementation of ntruprime
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
dab51d8e20 buffer: Calculate correctly the bignum size in buffer
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
4becc8eb82 kex: Add sntrup761x25519-sha512@openssh.com.
All of the initial work was done by Simon. Jakub cleaned up the
formatting issues, resolved the padding of bignum to match specs
and be interoperable with OpenSSH (and few more minor details).

Closes: #194.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
3468cc0dc5 tests: Allow killing processes to take more time.
A too low timeout caused spurious self-test failures in pkd_hello_i1.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
4bd8d8d362 curve25519: Add ssh_curve25519_create_k to allow code re-use.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
083a4781d8 curve25519: Drop static from ssh_curve25519_init to allow code re-use.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
7e3263d995 tests: Check buffer bignum behaviour.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
fbf02d5936 buffer.c: Support 'F' for padded bignums
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Simon Josefsson
16fd55b4b2 tests: Check ssh_make_padded_bignum_string.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
799557384d bignum: Add ssh_make_unpadded_bignum_string.
Signed-off-by: Simon Josefsson <simon@josefsson.org>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
c6be50cc97 reformat enum ssh_key_exchange_e
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
af90168624 bignum: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
9dbd1ec80b client: Reformat dh_handshake
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Jakub Jelen
9b9a2ea97d clang-format: Update config for clang 19
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-21 11:32:49 +01:00
Andreas Schneider
e9b76ff1bd torture_config: Use getpwuid() instead of env variables
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-15 13:24:41 +01:00
Andreas Schneider
e9046fc069 torture_misc: Do not rely on environment variables
The safest way is to use getpwuid().

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2025-01-15 13:22:38 +01:00
Jakub Jelen
0cd749a533 zlib: Move conditional compilation inside of the gzip.c
This implements stub for the compression functions and includes the
gzip.c in the compilation target uncoditionally, keeping the WITH_ZLIB
conditional compilation only in the gzip.c

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-14 14:47:44 +01:00
Jakub Jelen
e795849299 tests: fix spelling error
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 17:00:42 +01:00
Jakub Jelen
d887e1320a sftp: Avoid dead code and possible overruns
Coverity did not like the DEADCODE on 64b architecture.

After better look, the SFTP packet have read/write lengths in uint32 so
we really can not use the limits up to the uint64. Therefore we cap the
limits to uint32 while parsing and ignore any large value.

We then cap our reads/writes to this value, which is safe to cast to uint32
for wire format.

Thanks Coverity CID 1589435, CID 1589434, CID 1589432, CID 1589431

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:47:43 +01:00
Jakub Jelen
9eaa7a6394 sftp: Avoid memory leaks from extended attributes
Thanks coverity CID 1589433

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:47:43 +01:00
Jakub Jelen
4af88c84d4 sftp: Reformat read/write functions
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:47:43 +01:00
Jakub Jelen
00fce9cb6c gzip: Move cleanup to separate function
to avoid exposing gzip function into wrapper.c

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 15:28:13 +01:00
Jakub Jelen
a547b7f115 gzip: Avoid potential memory leak
Thanks coverity CID 1589436

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-13 13:38:33 +01:00
Jakub Jelen
8bf908a56f tests: Make sure to pass right type to buffer_pack
For some reason, the mingw64 builds were failing on these inputs quite reliably
as the passed value was interpretted as a value larger than UINT32_MAX.

This was not caught before because the value is casted from size_t to uint32_t
implicitly so the MSBs were not affecting the result.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-03 15:18:53 +01:00
Jakub Jelen
b7018c17c7 Fix implicit type conversions and warnings on windows builds
The visual studio windows builds spit dozens of lines of warnings
on these.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-03 15:18:53 +01:00
Jakub Jelen
a15c977cdc tests: Test vectors for related documentation
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-02 11:39:18 +01:00
Jakub Jelen
91e228b08b options: Clarify format of HOST option
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-02 11:39:18 +01:00
Jakub Jelen
cbcd6d6f46 Happy new year 2025!
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2025-01-02 11:35:55 +01:00
Jakub Jelen
49b0c859f9 packet: Implement logging of SSH2_MSG_DEBUG message
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 15:09:54 +01:00
Jakub Jelen
79ba546cde channels: Remove callbacks from freed channels
When the user frees the channel, they no longer expect any callbacks
to be triggered on it. When we delay the close before we receive
the remaining messages, we should not trigger the user callbacks
as it might be already freed.

I believe this is the random torture_session test failures and
errors we are getting from valgrind from time to time.

We keep the callbacks cleanup in the do_cleanup() in case the
calling application sets the callback after free for some reason.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 15:09:54 +01:00
Jakub Jelen
0ea982d4ec channels: Warn against executing multiple commands in single channel
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 15:09:54 +01:00
Jakub Jelen
c043122655 tests: Close channel before freeying
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 14:20:29 +01:00
Jakub Jelen
5da8963c1d tests: Verify channel requests return valid replies
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 14:20:29 +01:00
Jakub Jelen
f3d80833fe examples: Remove remaining references to default hostkeys
This is fixup of a9d1cfa9e2, where we missed this
corner case.

Fixes: #285
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 13:52:37 +01:00
Jakub Jelen
874b75429f tests: Fix random failure on too fast systems
On mingw we are frequently getting a failure like this:

[  ERROR   ] --- 451 is not within the range 1-450

This means the 50ms sleep did not manage to elapse the 50ms in the timeout
structure. Extending the range to 460 will give use more wiggle room if the
clock is not as it should be.

Related: #273
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 10:29:08 +01:00
Jakub Jelen
f8a6b1e2b3 ci: Skip torture_rand in mingw as it keeps hanging
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-12-20 10:12:44 +01:00
Andreas Schneider
5b9b901e48 gitlab-ci: Add abidiff
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
2966a4a33c 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>
2024-12-03 15:19:51 +01:00
Andreas Schneider
867630750c 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>
2024-12-03 15:19:51 +01:00
Andreas Schneider
9a40d51162 gcrypt: Store random numbers in secure memory
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
259721e523 gcrypt: Allocate 32k of secure memory
In the meantime libgcrypt allocates 32k of secure memory, the minimum is
16k.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Andreas Schneider
4bc40a47a3 tests:valgrind: Add suppression memleak in krb5_mcc_generate_new
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-03 15:19:51 +01:00
Norbert Pocs
f0b55391a8 gitlab-ci: Move Visual Studio builds back to test stage
The Visual Studio builds are completing in a manageable speed now.
Putting it back to the dependent chain of the CI to not cause any false
positive representation of the analysis stage (when the stage has all
skipped jobs, but the independent VS jobs succeed, the stage is shown as
success)

Reverting part of commit 91703202

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-12-02 20:27:56 +01:00
Norbert Pocs
d2e5b69b02 gitlab-ci.yml: Bump openssl version numbers on runner titles
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-13 18:41:05 +01:00
Norbert Pocs
2971e122d0 gitlab-ci.yml: Run fedora without pkcs11
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-13 18:41:05 +01:00
Jakub Jelen
e2524538f6 curve25519: Avoid reading private curve25519 keys from OpenSSL structures
The previous code created private key curve25519 in OpenSSL, then exported
private key and during key generation, created a new OpenSSL private key object.
This is needless amount of copying potentially sensitive data back and forth and
this will not work when the private key would be backed with external OpenSSL
provider, such as pkcs11 provider or different crypto accelerator handling the
private key operations for us.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-11-12 17:47:04 +01:00
Jakub Jelen
d0ecb5388c sftpserver: Do not override the ssh error code
Fixes: https://gitlab.com/libssh/libssh-mirror/-/issues/275#note_2162076660

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-11-12 17:46:38 +01:00
Eshan Kelkar
72b6fad284 Add tests for sftp_recv_response_msg()
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:44 +01:00
Eshan Kelkar
258c2eef3b sftp_common (bug fix): Change the way sftp responses are received
This commit changes the way in which receiving sftp
responses is handled.

The old way polled/blocked on the channel before
checking the sftp response queue which could cause infinite
waiting by default if the required response is already present
in the response queue and no other sftp response is ever sent
by the server.

The new way checks the sftp response queue first for the
response before polling/blocking on the channel. This gets
rid of the potential infinite waiting bug.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:42 +01:00
Eshan Kelkar
a02268a254 Add helper to receive sftp response messages
For the sake of reducing code repetition, this commit
adds a helper function to receive sftp response
messages. The function can operate in both blocking
and non-blocking modes.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:41 +01:00
Eshan Kelkar
f16b3539da sftp_aio: Add tests for unordered waits
This commit adds tests to check that the sftp aio API works
properly if the API user waits for responses of the read/write
requests in an order different from the sending order of the
requests.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:45:40 +01:00
Jakub Jelen
0306581f1c sftp: Do not fail if the status message does not contain error message
Some SFTP servers (Cisco) do not implement the v3 protocol correctly and do not
send the mandatory part of the status message. This falls back to the v2
behavior when the error message and language tag are not provided.

Fixes: #272

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-11-12 17:44:26 +01:00
Eshan Kelkar
d8f00aca20 priv.h, torture_misc.c: Fix clang-format formatting complaints
Fixed include order and formatting issues regarding the 80 char
column width limit

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:15 +01:00
Eshan Kelkar
e0aa182e7e log.c: Use localtime_r() in current_timestring()
Use localtime_r() instead of the thread unsafe localtime().

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:14 +01:00
Eshan Kelkar
0e756306f0 log.c: Fix current_timestring()
The second argument to strftime() should be the size of the buffer
as per the manpage.

The previous code used size - 1 as the second argument. This commit modifies
that behaviour to use buffer size as the second argument of strftime().

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:13 +01:00
Eshan Kelkar
904c3e024c torture_misc.c Add test for localtime_r()
Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:11 +01:00
Eshan Kelkar
b58cb9f72b misc.c, priv.h: Add support for localtime_r() on Windows
Windows supports localtime_s() instead of POSIX's localtime_r()
and the function prototype of localtime_s() is different as compared
to localtime_r().

This commit introduces ssh_localtime() (having same prototype as localtime_r())
for Windows which acts as a wrapper for localtime_s(), and defines localtime_r
as a macro which expands to ssh_localtime for Windows.

As a result, libssh can now use localtime_r() on Windows in the same manner
as localtime_r() can be used on POSIX systems.

Signed-off-by: Eshan Kelkar <eshankelkar@galorithm.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-11-12 17:41:04 +01:00
Axel Lin
861590192f Add #ifndef __VA_NARG__ guard to avoid "__VA_NARG__" redefined warnings
Some SDK already defined __VA_NARG__, so without #ifndef __VA_NARG__ guard
we got a lot of "__VA_NARG__" redefined warnings.
Fix it by adding #ifndef __VA_NARG__ guard in include/libssh/priv.h.

Fixes: #279
Signed-off-by: Axel Lin <axel.lin@ingics.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:50:51 +02:00
JamesWrigley
9ad2f6b3b1 Add missing #include's to sftpserver.h
Presumably this header is always imported with all the other necessary ones so
it doesn't usually make a difference, but generating Julia bindings from the
header by itself requires all the types to be defined (e.g. ssh_session,
ssh_channel, etc).

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:50:43 +02:00
JamesWrigley
ef8e90863b Make codespell ignore PENDIN in CI
This is the correct name of a terminal opcode.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:50:07 +02:00
Simon Josefsson
d29ed23010 tests: Permit slow systems to take 1-450 instead of 1-40ms.
Thanks to Jakub Jelen for debugging and suggested fix.  Fixes #273.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-25 13:48:58 +02:00
Jakub Jelen
46d7417620 tests: Do not use global openssl.cnf
The global openssl configuration file automatically loads a pkcs11
provider, but it does it before we set up the token, which makes
the pkcs11 tests failing.

The workaround is to not load the global configuration, which is
delaying the loading of the pkcs11 provider to the time of first
use.

Consequently, this will require separate integration end-to-end
test that will verify the libssh works correctly with the pkcs11
provider loaded early.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-10-25 13:46:22 +02:00
Jakub Jelen
c73a8a824e ci: Add Centos 10 development container
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Sahana Prasad <sahana@redhat.com>
2024-10-25 13:46:22 +02:00
Davidwed
7712c7d0f9 cmake: Fixed compatibility issues with "CPM.cmake" in combination with the libraries MBedTLS and libgcrypt.
Signed-off-by: Davidwed <davidwe@posteo.de>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:56:23 +02:00
Simon Josefsson
d7a0cbcfbb tests: Permit slow systems to take 300ms instead of 75ms.
Thanks to Jakub Jelen for debugging.  Fixes #273.

Reproduce problem by changing the value to 1ms.

Signed-off-by: Simon Josefsson <simon@josefsson.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:54:09 +02:00
Thomas Perale
cb0237e85b cmake: Only enable CXX when running the coverage
Commit 25a678190c introduced code coverage
collection. That also introduced a dependency to CXX language.

When cross-compiling libssh in an environment that doesn't have a C++ compiler
the following error is raised: "No CMAKE_CXX_COMPILER could be found.".

Since the C++ part is only needed for the coverage part, this commit only enable
that language dependency when actually needing it.

Signed-off-by: Thomas Perale <thomas.perale@mind.be>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:52:12 +02:00
JamesWrigley
5b0f480acd Document that most SFTP functions require a blocking ssh_session
Currently if a non-blocking `ssh_session` is passed most calls will fail because
they don't know how to handle `SSH_AGAIN`.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:48:56 +02:00
JamesWrigley
629ba3fd34 Fix typo
Renamed `process_unsupposed` to `process_unsupported`.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-10-21 13:48:14 +02:00
Jakub Jelen
48d474f78c ttyopts: Adjust the default TTY modes to be sane
The "sane" default is now based on the man stty "sane" alias with addition of
utf8.

Fixes: #270

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-29 09:07:25 +02:00
Carlo Bramini
e298600303 CYGWIN: fix build.
Signed-off-by: Carlo Bramini <carlo_bramini@users.sourceforge.net>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
8295945011 Add explicit -Werror=unused-variable
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
8363929104 cmake: Do not build server examples and tests when built without server
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
71e1baeb5f kex: Avoid unused variable when built without server
Fixes: #267

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Eshan Kelkar <eshankelkar@galorithm.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
82b363f294 config: Do not parse unsupported ControlPath/ControlMaster
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
8fb2c5d2fd tests: Do not crash on cleanup when sshd does not come up
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
9ce53b6972 tests: Do not override verbosity set by environment
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
7b89ff760a test: Workaround the new OpenSSH failure rate limiting
The new OpenSSH rate limits the failed authentication attempts per source
address and drops connection when the amount is reached, which is happening
in our testsuite.

By whitelisting the IP address of the client on the socket wrapper,
this allows the tests to pass.

https://man.openbsd.org/sshd_config.5#PerSourcePenaltyExemptList

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Andreas Schneider
362ab3a684 cpack: Make sure to not package .git file
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-19 13:12:27 +02:00
Jakub Jelen
ea97d41bbb tests: Avoid unused variables
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
c85268c38b wrapper: Use calloc instead of zerostructp
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
c9cfeb9b83 wrapper: Avoid asymmetric termination of gzip context
For some reason, both compress and decompress contexts were terminated
with both compress and decompress end functions (if the deflateEnd worked),
which was causing for some another unexplained reasons issues on i686
architecture when running the torture_packet unit test.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
deedc0e108 tests: Describe reason for using internal-sftp
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
57073d588a tests: Remove needless printf
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
d416ef533f tests: Rewrite fs_wrapper for readability
includes also additional syscalls for 32b archs.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
2743b510ac tests: Assemble the output into single buffer
... before checking the content.

This test was failing randomly when the read returned only partial buffer.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
Jakub Jelen
41d370864e tests: Be explicit about types.
Casting int to bool might not always work as expected

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-19 13:12:27 +02:00
JamesWrigley
7e4ea0d111 Use CMake's C_STANDARD property
This is more portable than specifying a compiler flag explicitly.

Signed-off-by: James Wrigley <james@puiterwijk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-15 09:53:52 +02:00
Francesco Rollo
b0b2e8fefd tests: add support for IPv4/IPv6 loopback network ID fallback in torture_config_match_localnetwork.c
Signed-off-by: Francesco <eferollo@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
2024-08-02 11:19:05 +02:00
Jakub Jelen
b804aa9286 Fix proxy_disconnect on systems without pthread
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-02 11:00:47 +02:00
Jakub Jelen
ab10f5c2f7 match: Workaround matching on systems without IPv6
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-02 10:35:31 +02:00
Jakub Jelen
9634668258 Conditional compilation of localnetwork matching
Some architectures (esp32) might not have this API.

Fixes: #263

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2024-08-02 10:35:31 +02:00
172 changed files with 17089 additions and 7468 deletions

View File

@@ -26,3 +26,4 @@ BreakAfterReturnType: ExceptShortType
AlwaysBreakAfterReturnType: AllDefinitions
AlignEscapedNewlines: Left
ForEachMacros: ['ssh_callbacks_iterate']
AlignConsecutiveMacros: 'Consecutive'

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ tags
/build
/obj*
doc/tags.xml
.DS_Store

View File

@@ -27,13 +27,17 @@ workflow:
when: never
- if: '$CI_COMMIT_BRANCH'
.build:
stage: build
.build_options:
variables:
CMAKE_DEFAULT_OPTIONS: "-DCMAKE_BUILD_TYPE=RelWithDebInfo -DPICKY_DEVELOPER=ON"
CMAKE_DEFAULT_DEBUG_OPTIONS: "-DCMAKE_C_FLAGS='-O0 -g -ggdb' -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_TEST_OPTIONS: "-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON -DGSSAPI_TESTING=ON -DWITH_BENCHMARKS=ON -DFUZZ_TESTING=ON"
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
.build:
extends: .build_options
stage: build
before_script: &build
- uname -a
- cat /etc/os-release
@@ -121,7 +125,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 +136,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 +147,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 +164,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:
@@ -225,15 +229,15 @@ fedora/coverage:
coverage_format: cobertura
path: obj/coverage_xml.xml
fedora/openssl_3.0.x/x86_64:
fedora/openssl_3.x/x86_64:
extends: .fedora
fedora/openssl_3.0.x/x86_64/pkcs11-provider:
fedora/openssl_3.x/x86_64/pkcs11-provider:
variables:
CMAKE_ADDITIONAL_OPTIONS: -DWITH_PKCS11_URI=ON -DWITH_PKCS11_PROVIDER=ON
extends: .fedora
fedora/openssl_3.0.x/x86_64/minimal:
fedora/openssl_3.x/x86_64/minimal:
extends: .fedora
variables:
script:
@@ -405,7 +409,7 @@ fedora/mingw32:
paths:
- obj-csbuild/
fedora/csbuild/openssl_3.0.x:
fedora/csbuild/openssl_3.x:
extends: .csbuild
script:
- csbuild
@@ -435,6 +439,62 @@ fedora/csbuild/mbedtls:
--color
--print-current --print-fixed
###############################################################################
# Fedora abidiff #
###############################################################################
fedora/abidiff:
stage: analysis
variables:
GIT_DEPTH: "100"
CMAKE_OPTIONS: $CMAKE_DEFAULT_DEBUG_OPTIONS $CMAKE_BUILD_OPTIONS
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
before_script:
- uname -a
- cat /etc/os-release
- mount
- df -h
- cat /proc/swaps
- free -h
- |
# for merge requests
if [[ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]]; then
export CI_COMMIT_BEFORE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
fi
# for branches run
if [[ -z "$CI_COMMIT_BEFORE_SHA" ]]; then
export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
fi
# Check if the commit exists in this branch
# This is not the case for a force push
git branch --contains $CI_COMMIT_BEFORE_SHA 2>/dev/null || export CI_COMMIT_BEFORE_SHA=$(git rev-parse "${CI_COMMIT_SHA}~20")
- mkdir -p obj-${CI_COMMIT_BEFORE_SHA}
- mkdir -p obj-${CI_COMMIT_SHA}
- export INSTALL_DIR1=$(pwd)/install/${CI_COMMIT_BEFORE_SHA}
- export INSTALL_DIR2=$(pwd)/install/${CI_COMMIT_SHA}
script:
- git checkout ${CI_COMMIT_BEFORE_SHA}
- pushd obj-${CI_COMMIT_BEFORE_SHA}
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR1} .. &&
make -j$(nproc) && make -j$(nproc) install
- popd
- ls -l ${INSTALL_DIR1}/lib*/
- git checkout ${CI_COMMIT_SHA}
- pushd obj-${CI_COMMIT_SHA}
- cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR2} .. &&
make -j$(nproc) && make -j$(nproc) install
- popd
- ls -l ${INSTALL_DIR2}/lib*/
- ./.gitlab-ci/checkabi.sh ${INSTALL_DIR1} ${INSTALL_DIR2}
tags:
- saas-linux-small-amd64
except:
- tags
only:
- merge_requests
###############################################################################
# Ubuntu builds #
@@ -447,7 +507,7 @@ ubuntu/openssl_3.0.x/x86_64:
###############################################################################
# Alpine builds #
###############################################################################
alpine/openssl_3.0.x/musl:
alpine/openssl_3.x/musl:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$ALPINE_BUILD
extends: .tests
script:
@@ -464,10 +524,10 @@ alpine/openssl_3.0.x/musl:
###############################################################################
# Tumbleweed builds #
###############################################################################
tumbleweed/openssl_3.0.x/x86_64/gcc:
tumbleweed/openssl_3.x/x86_64/gcc:
extends: .tumbleweed
tumbleweed/openssl_3.0.x/x86/gcc:
tumbleweed/openssl_3.x/x86/gcc:
extends: .tumbleweed
script:
- cmake
@@ -480,12 +540,12 @@ tumbleweed/openssl_3.0.x/x86/gcc:
-DUNIT_TESTING=ON .. &&
make -j$(nproc)
tumbleweed/openssl_3.0.x/x86_64/gcc7:
tumbleweed/openssl_3.x/x86_64/gcc7:
extends: .tumbleweed
variables:
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=gcc-7 -DCMAKE_CXX_COMPILER=g++-7"
tumbleweed/openssl_3.0.x/x86/gcc7:
tumbleweed/openssl_3.x/x86/gcc7:
extends: .tumbleweed
script:
- cmake
@@ -497,7 +557,7 @@ tumbleweed/openssl_3.0.x/x86/gcc7:
make -j$(nproc) &&
ctest --output-on-failure
tumbleweed/openssl_3.0.x/x86_64/clang:
tumbleweed/openssl_3.x/x86_64/clang:
extends: .tumbleweed
variables:
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
@@ -507,6 +567,11 @@ tumbleweed/mbedtls-3.6.x/x86_64/gcc:
variables:
CMAKE_ADDITIONAL_OPTIONS: "-DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
tumbleweed/mbedtls-3.6.x/x86_64/clang:
extends: .tumbleweed
variables:
CMAKE_ADDITIONAL_OPTIONS: "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DKRB5_CONFIG=/usr/lib/mit/bin/krb5-config -DWITH_MBEDTLS=ON -DWITH_DEBUG_CRYPTO=ON -DWITH_BLOWFISH_CIPHER=OFF "
tumbleweed/static-analysis:
extends: .tests
stage: analysis
@@ -568,9 +633,7 @@ freebsd/openssl_1.1.1/x86_64:
# 2024-05-13: These jobs run out of the stages as they take extremely long and
# usually timeout with the update to Gitlab 17.0
.vs:
stage: analysis
needs: []
allow_failure: true
stage: test
cache:
key: vcpkg.${CI_JOB_NAME}
paths:
@@ -662,3 +725,41 @@ coverity:
when: on_failure
paths:
- obj/cov-int/*.txt
###############################################################################
# MacOS #
###############################################################################
.macos:
tags:
- saas-macos-medium-m1
image: macos-14-xcode-15
before_script:
- echo "MacOS runner started"
- brew update
- brew install cmake openssl cmocka doxygen
- mkdir obj && cd obj
only:
- branches@libssh/libssh-mirror
- branches@cryptomilk/libssh-mirror
- branches@jjelen/libssh-mirror
- branches@marco.fortina/libssh-mirror
# TODO add -DFUZZ_TESTING=ON clang cant find _LLVMFuzzerInitialize on arm64
macos-m1:
extends: .macos
variables:
HOMEBREW_NO_AUTO_UPDATE: 1
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_TEST_OPTIONS: "-DUNIT_TESTING=ON"
CMAKE_OPTIONS: $CMAKE_DEFAULT_OPTIONS $CMAKE_BUILD_OPTIONS $CMAKE_TEST_OPTIONS
stage: test
script:
- cmake $CMAKE_OPTIONS .. &&
make -j$(sysctl -n hw.logicalcpu) &&
ctest --output-on-failure
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/

42
.gitlab-ci/checkabi.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/bash
INSTALL_DIR1=${1}
INSTALL_DIR2=${2}
abidiff \
--headers-dir1 "${INSTALL_DIR1}/include/libssh/" \
--headers-dir2 "${INSTALL_DIR2}/include/libssh/" \
"${INSTALL_DIR1}/lib64/libssh.so" \
"${INSTALL_DIR2}/lib64/libssh.so" \
--fail-no-debug-info
abiret=$?
ABIDIFF_ERROR=$(((abiret & 0x01) != 0))
ABIDIFF_USAGE_ERROR=$(((abiret & 0x02) != 0))
ABIDIFF_ABI_CHANGE=$(((abiret & 0x04) != 0))
ABIDIFF_ABI_INCOMPATIBLE_CHANGE=$(((abiret & 0x08) != 0))
ABIDIFF_UNKNOWN_BIT_SET=$(((abiret & 0xf0) != 0))
if [ $ABIDIFF_ERROR -ne 0 ]; then
echo "abidiff reported ABIDIFF_ERROR."
exit 1
fi
if [ $ABIDIFF_USAGE_ERROR -ne 0 ]; then
echo "abidiff reported ABIDIFF_USAGE_ERROR."
exit 1
fi
if [ $ABIDIFF_UNKNOWN_BIT_SET -ne 0 ]; then
echo "abidiff reported ABIDIFF_UNKNOWN_BIT_SET."
exit 1
fi
if [ $ABIDIFF_ABI_INCOMPATIBLE_CHANGE -ne 0 ]; then
echo "abidiff result ABIDIFF_ABI_INCOMPATIBLE_CHANGE, this breaks the API!"
exit 1
fi
if [ $ABIDIFF_ABI_CHANGE -ne 0 ]; then
echo "Ignoring abidiff result ABI_CHANGE"
fi
exit 0

View File

@@ -0,0 +1,16 @@
Add a description of the new feature/bug fix. Reference any relevant bugs.
## Checklist
* [ ] Commits have `Signed-off-by:` with name/author being identical to the commit author
* [ ] Code modified for feature
* [ ] Test suite updated with functionality tests
* [ ] Test suite updated with negative tests
* [ ] Documentation updated
* [ ] The project pipelines timeout is [extended](https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run) at least to 2 hours.
## Reviewer's checklist:
* [ ] Any issues marked for closing are addressed
* [ ] There is a test suite reasonably covering new functionality or modifications
* [ ] Function naming, parameters, return values, types, etc., are consistent and according to [CONTRIBUTING.md](https://gitlab.com/libssh/libssh-mirror/-/blob/master/CONTRIBUTING.md)
* [ ] This feature/change has adequate documentation added
* [ ] No obvious mistakes in the code

View File

@@ -1,35 +1,6 @@
CHANGELOG
=========
version 0.11.2 (released 2025-06-24)
* Security:
* CVE-2025-4877 - Write beyond bounds in binary to base64 conversion
* CVE-2025-4878 - Use of uninitialized variable in privatekey_from_file()
* CVE-2025-5318 - Likely read beyond bounds in sftp server handle management
* CVE-2025-5351 - Double free in functions exporting keys
* CVE-2025-5372 - ssh_kdf() returns a success code on certain failures
* CVE-2025-5449 - Likely read beyond bounds in sftp server message decoding
* CVE-2025-5987 - Invalid return code for chacha20 poly1305 with OpenSSL
* Compatibility
* Fixed compatibility with CPM.cmake
* Compatibility with OpenSSH 10.0
* Tests compatibility with new Dropbear releases
* Removed p11-kit remoting from the pkcs11 testsuite
* Bugfixes
* Implement missing packet filter for DH GEX
* Properly process the SSH2_MSG_DEBUG message
* Allow escaping quotes in quoted arguments to ssh configuration
* Do not fail with unknown match keywords in ssh configuration
* Process packets before selecting signature algorithm during authentication
* Do not fail hard when the SFTP status message is not sent by noncompliant
servers
version 0.11.1 (released 2024-08-30)
* Fixed default TTY modes that are set when stdin is not connected to tty (#270)
* Fixed zlib cleanup procedure, which could crash on i386
* Various test fixes improving their stability
* Fixed cygwin build
version 0.11.0 (released 2024-07-31)
* Deprecations and Removals:
* Dropped support for DSA

View File

@@ -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.00 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.0")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
@@ -41,6 +41,8 @@ macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source buil
# Copy library files to a lib sub-directory
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(LIBSSSH_PC_REQUIRES_PRIVATE "")
# search for libraries
if (WITH_ZLIB)
find_package(ZLIB REQUIRED)
@@ -66,6 +68,7 @@ find_package(Threads)
if (WITH_GSSAPI)
find_package(GSSAPI)
list(APPEND LIBSSH_PC_REQUIRES_PRIVATE ${GSSAPI_PC_REQUIRES})
endif (WITH_GSSAPI)
if (WITH_NACL)
@@ -249,9 +252,15 @@ message(STATUS "Benchmarks: ${WITH_BENCHMARKS}")
message(STATUS "Symbol versioning: ${WITH_SYMBOL_VERSIONING}")
message(STATUS "Allow ABI break: ${WITH_ABI_BREAK}")
message(STATUS "Release is final: ${WITH_FINAL}")
if (WITH_HERMETIC_USR)
message(STATUS "User global client config: ${USR_GLOBAL_CLIENT_CONFIG}")
endif ()
message(STATUS "Global client config: ${GLOBAL_CLIENT_CONFIG}")
if (WITH_SERVER)
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
if (WITH_HERMETIC_USR)
message(STATUS "User global bind config: ${USR_GLOBAL_BIND_CONFIG}")
endif ()
message(STATUS "Global bind config: ${GLOBAL_BIND_CONFIG}")
endif()
message(STATUS "********************************************")

View File

@@ -117,6 +117,25 @@ 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.
## Continuous Integration
Contributing patches through Merge Request workflow on Gitlab allows us to run
various checks on various configuration as part of Gitlab CI. Unfortunately,
some pipelines are slower (as they involve building dependencies) so the default
timeout of 1 hour needs to be extended at least to 2 hours. This can be done in
project settings of your libssh fork:
https://docs.gitlab.com/ee/ci/pipelines/settings.html#set-a-limit-for-how-long-jobs-can-run
Otherwise you will encounter errors like these, usually on visualstudio builds:
```
ERROR: Job failed: execution took longer than 1h0m0s seconds
The script exceeded the maximum execution time set for the job
```
Note, that the built dependencies are cached so after successful build in your
namespace, the rebuilds should be much faster.
# Coding conventions in the libssh tree
@@ -517,6 +536,37 @@ Bad example:
break;
}
## ABI Versioning and Symbol Management
To maintain [ABI](https://en.wikipedia.org/wiki/Application_binary_interface) stability
and ensure backward compatibility, libssh uses **symbol versioning** to track and manage
exported functions and variables. This allows libssh to introduce new symbols or modify
existing functions in an ABI-compatible way.
When introducing a new symbol:
1. Use the `LIBSSH_API` macro to mark the symbol as part of the public API.
2. If you have [abimap](https://github.com/ansasaki/abimap) installed, the new symbols are
automatically generated in the `src/libssh_dev.map` file in the **build** directory and used automatically for building the updated library. But, depending on the version of `abimap` under use, you may face linker errors like: `unable to find version dependency LIBSSH_4_9_0`. In this case, you need to manually replace the existing `src/libssh.map` file with the generated `libssh_dev.map` file to update the symbol versioning.
3. If you do not have abimap installed, the modified/added symbols must manually be added to the
`src/libssh.map` file. The symbols must be added in the following format (assuming that 4_10_0 is the latest released version):
```
LIBSSH_AFTER_4_10_0
{
global:
new_function;
new_variable;
} LIBSSH_4_10_0;
```
4. After following either of the above steps, the library can be successfully built and
tested without any linker errors.
5. When submitting the patch, make sure that any new symbols have been added to `libssh.map` as described in step 3, so that the new additions may not be excluded from the next release due to human error.
Also, to maintain ABI compatibility, existing symbols must not be removed. Instead, they can
be marked as deprecated using the `LIBSSH_DEPRECATED` macro. This allows the symbol to be
removed in a future release without breaking the ABI.
Have fun and happy libssh hacking!

View File

@@ -226,6 +226,7 @@ if (GCRYPT_FOUND)
endif (GCRYPT_VERSION VERSION_GREATER "1.4.6")
if (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
set(HAVE_GCRYPT_CHACHA_POLY 1)
set(HAVE_GCRYPT_CURVE25519 1)
endif (NOT GCRYPT_VERSION VERSION_LESS "1.7.0")
endif (GCRYPT_FOUND)
@@ -236,6 +237,13 @@ if (MBEDTLS_FOUND)
set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_INCLUDE_DIR}/mbedtls")
check_include_file(chacha20.h HAVE_MBEDTLS_CHACHA20_H)
check_include_file(poly1305.h HAVE_MBEDTLS_POLY1305_H)
if (MBEDTLS_VERSION VERSION_LESS "3.0.0")
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "config.h" HAVE_MBEDTLS_CURVE25519)
else()
check_symbol_exists(MBEDTLS_ECP_DP_CURVE25519_ENABLED "mbedtls_config.h" HAVE_MBEDTLS_CURVE25519)
endif()
if (WITH_BLOWFISH_CIPHER)
check_include_file(blowfish.h HAVE_BLOWFISH)
endif()

View File

@@ -27,6 +27,7 @@ option(WITH_INSECURE_NONE "Enable insecure none cipher and MAC algorithms (not s
option(WITH_EXEC "Enable libssh to execute arbitrary commands from configuration files or options (match exec, proxy commands and OpenSSH-based proxy-jumps)." ON)
option(FUZZ_TESTING "Build with fuzzer for the server and client (automatically enables none cipher!)" OFF)
option(PICKY_DEVELOPER "Build with picky developer flags" OFF)
option(WITH_HERMETIC_USR "Build with support for hermetic /usr/" OFF)
if (WITH_ZLIB)
set(WITH_LIBZ ON)
@@ -59,6 +60,11 @@ if (NOT GLOBAL_CLIENT_CONFIG)
set(GLOBAL_CLIENT_CONFIG "/etc/ssh/ssh_config")
endif (NOT GLOBAL_CLIENT_CONFIG)
if (WITH_HERMETIC_USR)
set(USR_GLOBAL_BIND_CONFIG "/usr${GLOBAL_BIND_CONFIG}")
set(USR_GLOBAL_CLIENT_CONFIG "/usr${GLOBAL_CLIENT_CONFIG}")
endif (WITH_HERMETIC_USR)
if (FUZZ_TESTING)
set(WITH_INSECURE_NONE ON)
endif (FUZZ_TESTING)

View File

@@ -38,14 +38,16 @@ First, you need to configure the compilation, using CMake. Go inside the
`build` dir. Create it if it doesn't exist.
GNU/Linux, MacOS X, MSYS/MinGW:
cmake -DUNIT_TESTING=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug ..
make
On Windows you should choose a makefile generator with -G or use
cmake-gui.exe ..
To enable building tests use -DUNIT_TESTING=ON. For this, the
[cmocka](https://cmocka.org) dependency is required.
To enable additional client tests against a local OpenSSH server, add the
compile option -DCLIENT_TESTING=ON. These tests require an OpenSSH
server package and some wrapper libraries (see optional requirements) to

View File

@@ -11,6 +11,8 @@
# GSSAPI_INCLUDE_DIR - the GSSAPI include directory
# GSSAPI_LIBRARIES - Link these to use GSSAPI
# GSSAPI_DEFINITIONS - Compiler switches required for using GSSAPI
# GSSAPI_PC_REQUIRES - pkg-config module name if found, needed for
# Requires.private for static linking
#
#=============================================================================
# Copyright (c) 2013 Andreas Schneider <asn@cryptomilk.org>
@@ -24,12 +26,23 @@
#=============================================================================
#
set(_mit_modname "mit-krb5-gssapi")
set(_heimdal_modname "heimdal-gssapi")
if(NOT _GSSAPI_ROOT_HINTS AND NOT _GSSAPI_ROOT_PATHS)
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_search_module(_GSSAPI ${_mit_modname} ${_heimdal_modname})
endif()
endif()
find_path(GSSAPI_ROOT_DIR
NAMES
include/gssapi.h
include/gssapi/gssapi.h
HINTS
${_GSSAPI_ROOT_HINTS}
"${_GSSAPI_INCLUDEDIR}"
PATHS
${_GSSAPI_ROOT_PATHS}
)
@@ -317,9 +330,15 @@ endif (GSSAPI_FLAVOR_HEIMDAL)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GSSAPI DEFAULT_MSG GSSAPI_LIBRARIES GSSAPI_INCLUDE_DIR)
if (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
set(GSSAPI_FOUND TRUE)
endif (GSSAPI_INCLUDE_DIRS AND GSSAPI_LIBRARIES)
if(GSSAPI_FOUND)
if(_GSSAPI_FOUND) # via pkg-config
if (GSSAPI_FLAVOR_MIT)
set(GSSAPI_PC_REQUIRES ${_mit_modname})
elseif (GSSAPI_FLAVOR_HEIMDAL)
set(GSSAPI_PC_REQUIRES ${_heimdal_modname})
endif()
endif()
endif()
# show the GSSAPI_INCLUDE_DIRS and GSSAPI_LIBRARIES variables only in the advanced view
mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
# show the GSSAPI_INCLUDE_DIR and GSSAPI_LIBRARIES variables only in the advanced view
mark_as_advanced(GSSAPI_INCLUDE_DIR GSSAPI_LIBRARIES)

View File

@@ -72,21 +72,23 @@ find_library(MBEDTLS_X509_LIBRARY
set(MBEDTLS_LIBRARIES ${MBEDTLS_SSL_LIBRARY} ${MBEDTLS_CRYPTO_LIBRARY}
${MBEDTLS_X509_LIBRARY})
# mbedtls 2.8
if (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h")
# mbedtls 2.8
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+\\.[0-9]+\\.[0-9]+).*$"
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
elseif (MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
# mbedtls 3.6
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h" _mbedtls_version_str REGEX
endif()
# mbedtls 3.6
if (NOT MBEDTLS_VERSION AND MBEDTLS_INCLUDE_DIR AND EXISTS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h")
file(STRINGS "${MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h" _mbedtls_version_str REGEX
"^#[\t ]*define[\t ]+MBEDTLS_VERSION_STRING[\t ]+\"[0-9]+.[0-9]+.[0-9]+\"")
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+.[0-9]+.[0-9]+).*"
string(REGEX REPLACE "^.*MBEDTLS_VERSION_STRING.*([0-9]+\\.[0-9]+\\.[0-9]+).*$"
"\\1" MBEDTLS_VERSION "${_mbedtls_version_str}")
endif ()
endif()
include(FindPackageHandleStandardArgs)
if (MBEDTLS_VERSION)

View File

@@ -9,9 +9,11 @@
#cmakedefine SOURCEDIR "${SOURCEDIR}"
/* Global bind configuration file path */
#cmakedefine USR_GLOBAL_BIND_CONFIG "${USR_GLOBAL_BIND_CONFIG}"
#cmakedefine GLOBAL_BIND_CONFIG "${GLOBAL_BIND_CONFIG}"
/* Global client configuration file path */
#cmakedefine USR_GLOBAL_CLIENT_CONFIG "${USR_GLOBAL_CLIENT_CONFIG}"
#cmakedefine GLOBAL_CLIENT_CONFIG "${GLOBAL_CLIENT_CONFIG}"
/************************** HEADER FILES *************************/
@@ -85,6 +87,9 @@
/* Define to 1 if you have elliptic curve cryptography in openssl */
#cmakedefine HAVE_OPENSSL_ECC 1
/* Define to 1 if mbedTLS supports curve25519 */
#cmakedefine HAVE_MBEDTLS_CURVE25519 1
/* Define to 1 if you have elliptic curve cryptography in gcrypt */
#cmakedefine HAVE_GCRYPT_ECC 1
@@ -97,6 +102,9 @@
/* Define to 1 if you have gcrypt with ChaCha20/Poly1305 support */
#cmakedefine HAVE_GCRYPT_CHACHA_POLY 1
/* Define to 1 if you have gcrypt with curve25519 support */
#cmakedefine HAVE_GCRYPT_CURVE25519
/*************************** FUNCTIONS ***************************/
/* Define to 1 if you have the `EVP_chacha20' function. */

View File

@@ -91,4 +91,10 @@ that it used:
}
@endcode
Warning: In a single channel, only ONE command can be executed!
If you want to executed multiple commands, allocate separate channels for
them or consider opening interactive shell.
Attempting to run multiple consecutive commands in one channel will fail.
*/

View File

@@ -19,7 +19,7 @@ the interesting functions as you go.
The libssh library provides:
- <strong>Key Exchange Methods</strong>: <i>curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
- <strong>Key Exchange Methods</strong>: <i>sntrup761x25519-sha512@openssh.com, curve25519-sha256, curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521</i>, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1
- <strong>Public Key Algorithms</strong>: ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa, rsa-sha2-512, rsa-sha2-256
- <strong>Ciphers</strong>: <i>aes256-ctr, aes192-ctr, aes128-ctr</i>, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, blowfish-cbc
- <strong>Compression Schemes</strong>: zlib, <i>zlib@openssh.com</i>, none

View File

@@ -303,7 +303,6 @@ span.lineno {
padding-right: 4px;
text-align: right;
color: black;
height: 100px;
white-space: pre;
border-right: 3px solid #1d7567;
background-color: #323232; }

View File

@@ -66,7 +66,6 @@ int authenticate_kbdint(ssh_session session, const char *password)
return SSH_AUTH_ERROR;
}
buffer[sizeof(buffer) - 1] = '\0';
if ((p = strchr(buffer, '\n'))) {
*p = '\0';
}
@@ -75,7 +74,7 @@ int authenticate_kbdint(ssh_session session, const char *password)
return SSH_AUTH_ERROR;
}
memset(buffer, 0, strlen(buffer));
memset(buffer, 0, sizeof(buffer));
} else {
if (password && strstr(prompt, "Password:")) {
answer = password;
@@ -147,7 +146,7 @@ int authenticate_console(ssh_session session)
// Try to authenticate
rc = ssh_userauth_none(session, NULL);
if (rc == SSH_AUTH_ERROR) {
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session);
return rc;
}
@@ -156,7 +155,7 @@ int authenticate_console(ssh_session session)
while (rc != SSH_AUTH_SUCCESS) {
if (method & SSH_AUTH_METHOD_GSSAPI_MIC){
rc = ssh_userauth_gssapi(session);
if(rc == SSH_AUTH_ERROR) {
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session);
return rc;
} else if (rc == SSH_AUTH_SUCCESS) {
@@ -166,7 +165,7 @@ int authenticate_console(ssh_session session)
// Try to authenticate with public key first
if (method & SSH_AUTH_METHOD_PUBLICKEY) {
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
if (rc == SSH_AUTH_ERROR) {
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session);
return rc;
} else if (rc == SSH_AUTH_SUCCESS) {
@@ -206,7 +205,7 @@ int authenticate_console(ssh_session session)
// Try to authenticate with keyboard interactive";
if (method & SSH_AUTH_METHOD_INTERACTIVE) {
rc = authenticate_kbdint(session, NULL);
if (rc == SSH_AUTH_ERROR) {
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session);
return rc;
} else if (rc == SSH_AUTH_SUCCESS) {
@@ -221,7 +220,7 @@ int authenticate_console(ssh_session session)
// Try to authenticate with password
if (method & SSH_AUTH_METHOD_PASSWORD) {
rc = ssh_userauth_password(session, NULL, password);
if (rc == SSH_AUTH_ERROR) {
if (rc == SSH_AUTH_ERROR || !ssh_is_connected(session)) {
error(session);
return rc;
} else if (rc == SSH_AUTH_SUCCESS) {

View File

@@ -21,47 +21,50 @@ clients must be made or how a client should react.
#include "examples_common.h"
#include <stdio.h>
ssh_session connect_ssh(const char *host, const char *user,int verbosity){
ssh_session session = NULL;
int auth=0;
ssh_session connect_ssh(const char *host, const char *user, int verbosity)
{
ssh_session session = NULL;
int auth = 0;
session=ssh_new();
if (session == NULL) {
return NULL;
}
if(user != NULL){
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
ssh_free(session);
return NULL;
session = ssh_new();
if (session == NULL) {
return NULL;
}
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
ssh_free(session);
return NULL;
}
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
if(ssh_connect(session)){
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
if (user != NULL) {
if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
ssh_free(session);
return NULL;
}
}
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0) {
ssh_free(session);
return NULL;
}
ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
if (ssh_connect(session)) {
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
ssh_disconnect(session);
ssh_free(session);
return NULL;
}
if (verify_knownhost(session) < 0) {
ssh_disconnect(session);
ssh_free(session);
return NULL;
}
auth = authenticate_console(session);
if (auth == SSH_AUTH_SUCCESS) {
return session;
} else if (auth == SSH_AUTH_DENIED) {
fprintf(stderr, "Authentication failed\n");
} else {
fprintf(stderr,
"Error while authenticating : %s\n",
ssh_get_error(session));
}
ssh_disconnect(session);
ssh_free(session);
return NULL;
}
if(verify_knownhost(session)<0){
ssh_disconnect(session);
ssh_free(session);
return NULL;
}
auth=authenticate_console(session);
if(auth==SSH_AUTH_SUCCESS){
return session;
} else if(auth==SSH_AUTH_DENIED){
fprintf(stderr,"Authentication failed\n");
} else {
fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session));
}
ssh_disconnect(session);
ssh_free(session);
return NULL;
}

View File

@@ -16,7 +16,7 @@ clients must be made or how a client should react.
#include <libssh/libssh.h>
/** Zero a structure */
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
#define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
int authenticate_console(ssh_session session);
int authenticate_kbdint(ssh_session session, const char *password);

View File

@@ -350,7 +350,12 @@ int main(int argc, char *argv[])
goto end;
}
if (arguments.action_list && arguments.file) {
if (arguments.file == NULL) {
fprintf(stderr, "Error: Missing argument file\n");
goto end;
}
if (arguments.action_list) {
list_fingerprint(arguments.file);
goto end;
}

View File

@@ -119,6 +119,10 @@ static struct location *parse_location(char *loc)
struct location *location = NULL;
char *ptr = NULL;
if (loc == NULL) {
return NULL;
}
location = malloc(sizeof(struct location));
if (location == NULL) {
return NULL;

View File

@@ -32,151 +32,163 @@ static const char *createcommand =
"cd /tmp/libssh_tests && date > a && date > b && mkdir c && date > d";
static char *host = NULL;
static void usage(const char *argv0){
fprintf(stderr,"Usage : %s [options] host\n"
"sample tiny scp downloader client - libssh-%s\n"
"This program will create files in /tmp and try to fetch them\n",
// "Options :\n",
// " -r : use RSA to verify host public key\n",
argv0,
ssh_version(0));
exit(0);
static void usage(const char *argv0)
{
fprintf(stderr,
"Usage : %s [options] host\n"
"sample tiny scp downloader client - libssh-%s\n"
"This program will create files in /tmp and try to fetch them\n",
argv0,
ssh_version(0));
exit(0);
}
static int opts(int argc, char **argv){
int i;
while((i=getopt(argc,argv,"v"))!=-1){
switch(i){
case 'v':
verbosity++;
break;
default:
fprintf(stderr,"unknown option %c\n",optopt);
static int opts(int argc, char **argv)
{
int i;
while ((i = getopt(argc, argv, "v")) != -1) {
switch (i) {
case 'v':
verbosity++;
break;
default:
fprintf(stderr, "unknown option %c\n", optopt);
usage(argv[0]);
return -1;
}
}
host = argv[optind];
if (host == NULL)
usage(argv[0]);
return 0;
}
static void create_files(ssh_session session)
{
ssh_channel channel = ssh_channel_new(session);
char buffer[1];
int rc;
if (channel == NULL) {
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
exit(EXIT_FAILURE);
}
if (ssh_channel_open_session(channel) != SSH_OK) {
fprintf(stderr, "Error creating channel: %s\n", ssh_get_error(session));
ssh_channel_free(channel);
exit(EXIT_FAILURE);
}
if (ssh_channel_request_exec(channel, createcommand) != SSH_OK) {
fprintf(stderr,
"Error executing command: %s\n",
ssh_get_error(session));
ssh_channel_close(channel);
ssh_channel_free(channel);
exit(EXIT_FAILURE);
}
while (!ssh_channel_is_eof(channel)) {
rc = ssh_channel_read(channel, buffer, 1, 1);
if (rc != 1) {
fprintf(stderr, "Error reading from channel\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
rc = write(1, buffer, 1);
if (rc < 0) {
fprintf(stderr, "Error writing to buffer\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
}
ssh_channel_close(channel);
ssh_channel_free(channel);
}
static int fetch_files(ssh_session session)
{
int size;
char buffer[BUF_SIZE];
int mode;
char *filename = NULL;
int r;
ssh_scp scp = ssh_scp_new(session,
SSH_SCP_READ | SSH_SCP_RECURSIVE,
"/tmp/libssh_tests/*");
if (ssh_scp_init(scp) != SSH_OK) {
fprintf(stderr, "error initializing scp: %s\n", ssh_get_error(session));
ssh_scp_free(scp);
return -1;
}
}
host = argv[optind];
if(host == NULL)
usage(argv[0]);
return 0;
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
do {
r = ssh_scp_pull_request(scp);
switch (r) {
case SSH_SCP_REQUEST_NEWFILE:
size = ssh_scp_request_get_size(scp);
filename = strdup(ssh_scp_request_get_filename(scp));
mode = ssh_scp_request_get_permissions(scp);
printf("downloading file %s, size %d, perms 0%o\n",
filename,
size,
mode);
free(filename);
ssh_scp_accept_request(scp);
r = ssh_scp_read(scp, buffer, sizeof(buffer));
if (r == SSH_ERROR) {
fprintf(stderr,
"Error reading scp: %s\n",
ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
}
printf("done\n");
break;
case SSH_ERROR:
fprintf(stderr, "Error: %s\n", ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
case SSH_SCP_REQUEST_WARNING:
fprintf(stderr, "Warning: %s\n", ssh_scp_request_get_warning(scp));
break;
case SSH_SCP_REQUEST_NEWDIR:
filename = strdup(ssh_scp_request_get_filename(scp));
mode = ssh_scp_request_get_permissions(scp);
printf("downloading directory %s, perms 0%o\n", filename, mode);
free(filename);
ssh_scp_accept_request(scp);
break;
case SSH_SCP_REQUEST_ENDDIR:
printf("End of directory\n");
break;
case SSH_SCP_REQUEST_EOF:
printf("End of requests\n");
goto end;
}
} while (1);
end:
ssh_scp_close(scp);
ssh_scp_free(scp);
return 0;
}
static void create_files(ssh_session session){
ssh_channel channel=ssh_channel_new(session);
char buffer[1];
int rc;
if(channel == NULL){
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
exit(EXIT_FAILURE);
}
if(ssh_channel_open_session(channel) != SSH_OK){
fprintf(stderr,"Error creating channel: %s\n",ssh_get_error(session));
ssh_channel_free(channel);
exit(EXIT_FAILURE);
}
if(ssh_channel_request_exec(channel,createcommand) != SSH_OK){
fprintf(stderr,"Error executing command: %s\n",ssh_get_error(session));
ssh_channel_close(channel);
ssh_channel_free(channel);
exit(EXIT_FAILURE);
}
while(!ssh_channel_is_eof(channel)){
rc = ssh_channel_read(channel,buffer,1,1);
if (rc != 1) {
fprintf(stderr, "Error reading from channel\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
rc = write(1, buffer, 1);
if (rc < 0) {
fprintf(stderr, "Error writing to buffer\n");
ssh_channel_close(channel);
ssh_channel_free(channel);
return;
}
}
ssh_channel_close(channel);
ssh_channel_free(channel);
}
static int fetch_files(ssh_session session){
int size;
char buffer[BUF_SIZE];
int mode;
char *filename = NULL;
int r;
ssh_scp scp=ssh_scp_new(session, SSH_SCP_READ | SSH_SCP_RECURSIVE, "/tmp/libssh_tests/*");
if(ssh_scp_init(scp) != SSH_OK){
fprintf(stderr,"error initializing scp: %s\n",ssh_get_error(session));
ssh_scp_free(scp);
return -1;
}
printf("Trying to download 3 files (a,b,d) and 1 directory (c)\n");
do {
r=ssh_scp_pull_request(scp);
switch(r){
case SSH_SCP_REQUEST_NEWFILE:
size=ssh_scp_request_get_size(scp);
filename=strdup(ssh_scp_request_get_filename(scp));
mode=ssh_scp_request_get_permissions(scp);
printf("downloading file %s, size %d, perms 0%o\n",filename,size,mode);
free(filename);
ssh_scp_accept_request(scp);
r=ssh_scp_read(scp,buffer,sizeof(buffer));
if(r==SSH_ERROR){
fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
}
printf("done\n");
break;
case SSH_ERROR:
fprintf(stderr,"Error: %s\n",ssh_get_error(session));
ssh_scp_close(scp);
ssh_scp_free(scp);
return -1;
case SSH_SCP_REQUEST_WARNING:
fprintf(stderr,"Warning: %s\n",ssh_scp_request_get_warning(scp));
break;
case SSH_SCP_REQUEST_NEWDIR:
filename=strdup(ssh_scp_request_get_filename(scp));
mode=ssh_scp_request_get_permissions(scp);
printf("downloading directory %s, perms 0%o\n",filename,mode);
free(filename);
ssh_scp_accept_request(scp);
break;
case SSH_SCP_REQUEST_ENDDIR:
printf("End of directory\n");
break;
case SSH_SCP_REQUEST_EOF:
printf("End of requests\n");
goto end;
}
} while (1);
end:
ssh_scp_close(scp);
ssh_scp_free(scp);
return 0;
}
int main(int argc, char **argv){
ssh_session session = NULL;
if(opts(argc,argv)<0)
return EXIT_FAILURE;
session=connect_ssh(host,NULL,verbosity);
if(session == NULL)
return EXIT_FAILURE;
create_files(session);
fetch_files(session);
ssh_disconnect(session);
ssh_free(session);
ssh_finalize();
return 0;
int main(int argc, char **argv)
{
ssh_session session = NULL;
if (opts(argc, argv) < 0)
return EXIT_FAILURE;
session = connect_ssh(host, NULL, verbosity);
if (session == NULL)
return EXIT_FAILURE;
create_files(session);
fetch_files(session);
ssh_disconnect(session);
ssh_free(session);
ssh_finalize();
return 0;
}

View File

@@ -5,60 +5,60 @@
#define LIMIT 0x100000000UL
int main(void) {
ssh_session session = NULL;
ssh_channel channel;
char buffer[1024*1024];
int rc;
uint64_t total=0;
uint64_t lastshown=4096;
session = connect_ssh("localhost", NULL, 0);
if (session == NULL) {
return 1;
}
channel = ssh_channel_new(session);
if (channel == NULL) {
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_open_session(channel);
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
total += rc;
if(total/2 >= lastshown){
printf("written %llx\n", (long long unsigned int) total);
lastshown=total;
int main(void)
{
ssh_session session = NULL;
ssh_channel channel = NULL;
char buffer[1024 * 1024] = {0};
int rc;
uint64_t total = 0;
uint64_t lastshown = 4096;
session = connect_ssh("localhost", NULL, 0);
if (session == NULL) {
return 1;
}
if(total > LIMIT)
break;
}
if (rc < 0) {
printf("error : %s\n",ssh_get_error(session));
channel = ssh_channel_new(session);
if (channel == NULL) {
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_open_session(channel);
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
rc = ssh_channel_request_exec(channel, "cat > /dev/null");
if (rc < 0) {
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
while ((rc = ssh_channel_write(channel, buffer, sizeof(buffer))) > 0) {
total += rc;
if (total / 2 >= lastshown) {
printf("written %llx\n", (long long unsigned int)total);
lastshown = total;
}
if (total > LIMIT)
break;
}
if (rc < 0) {
printf("error : %s\n", ssh_get_error(session));
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_disconnect(session);
return 1;
}
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_disconnect(session);
return 0;
return 0;
}

View File

@@ -192,9 +192,6 @@ static struct argp argp = {options, parse_opt, args_doc, doc, NULL, NULL, NULL};
static int
parse_opt(int argc, char **argv, ssh_bind sshbind)
{
int no_default_keys = 0;
int rsa_already_set = 0;
int ecdsa_already_set = 0;
int key;
while((key = getopt(argc, argv, "a:e:k:p:P:r:u:v")) != -1) {
@@ -202,16 +199,10 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT_STR, optarg);
} else if (key == 'k') {
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
/* We can't track the types of keys being added with this
option, so let's ensure we keep the keys we're adding
by just not setting the default keys */
no_default_keys = 1;
} else if (key == 'r') {
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
rsa_already_set = 1;
} else if (key == 'e') {
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_HOSTKEY, optarg);
ecdsa_already_set = 1;
} else if (key == 'a') {
strncpy(authorizedkeys, optarg, DEF_STR_SIZE-1);
} else if (key == 'u') {
@@ -256,12 +247,6 @@ parse_opt(int argc, char **argv, ssh_bind sshbind)
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDADDR, argv[optind]);
if (!no_default_keys) {
set_default_keys(sshbind,
rsa_already_set,
ecdsa_already_set);
}
return 0;
}
#endif /* HAVE_ARGP_H */

View File

@@ -40,222 +40,236 @@ clients must be made or how a client should react.
#endif
char *host = NULL;
const char *desthost="localhost";
const char *port="22";
const char *desthost = "localhost";
const char *port = "22";
#ifdef WITH_PCAP
#include <libssh/pcap.h>
char *pcap_file=NULL;
char *pcap_file = NULL;
#endif
static void usage(void)
{
fprintf(stderr,"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
exit(1);
fprintf(stderr,
"Usage : sshnetcat [user@]host forwarded_host forwarded_port\n");
exit(1);
}
static int opts(int argc, char **argv){
static int opts(int argc, char **argv)
{
int i;
while((i=getopt(argc,argv,"P:"))!=-1){
switch(i){
while ((i = getopt(argc, argv, "P:")) != -1) {
switch (i) {
#ifdef WITH_PCAP
case 'P':
pcap_file=optarg;
break;
case 'P':
pcap_file = optarg;
break;
#endif
default:
fprintf(stderr,"unknown option %c\n",optopt);
usage();
default:
fprintf(stderr, "unknown option %c\n", optopt);
usage();
}
}
if(optind < argc)
host=argv[optind++];
if(optind < argc)
desthost=argv[optind++];
if(optind < argc)
port=argv[optind++];
if(host==NULL)
if (optind < argc)
host = argv[optind++];
if (optind < argc)
desthost = argv[optind++];
if (optind < argc)
port = argv[optind++];
if (host == NULL)
usage();
return 0;
}
static void select_loop(ssh_session session,ssh_channel channel){
fd_set fds;
struct timeval timeout;
char buffer[BUF_SIZE];
/* channels will be set to the channels to poll.
* outchannels will contain the result of the poll
*/
ssh_channel channels[2], outchannels[2];
int lus;
int eof=0;
int maxfd;
int ret;
while(channel){
do{
static void select_loop(ssh_session session, ssh_channel channel)
{
fd_set fds;
struct timeval timeout;
char buffer[BUF_SIZE];
/* channels will be set to the channels to poll.
* outchannels will contain the result of the poll
*/
ssh_channel channels[2], outchannels[2];
int lus;
int eof = 0;
int maxfd;
int ret;
while (channel) {
do {
int fd;
ZERO_STRUCT(fds);
FD_ZERO(&fds);
if(!eof)
FD_SET(0,&fds);
timeout.tv_sec=30;
timeout.tv_usec=0;
FD_ZERO(&fds);
if (!eof)
FD_SET(0, &fds);
timeout.tv_sec = 30;
timeout.tv_usec = 0;
fd = ssh_get_fd(session);
if (fd == -1) {
fprintf(stderr, "Error getting the session file descriptor: %s\n",
ssh_get_error(session));
fprintf(stderr,
"Error getting the session file descriptor: %s\n",
ssh_get_error(session));
return;
}
FD_SET(fd, &fds);
maxfd = fd + 1;
channels[0]=channel; // set the first channel we want to read from
channels[1]=NULL;
ret=ssh_select(channels,outchannels,maxfd,&fds,&timeout);
if(ret==EINTR)
continue;
if(FD_ISSET(0,&fds)){
lus=read(0,buffer,sizeof(buffer));
if(lus)
ssh_channel_write(channel,buffer,lus);
else {
eof=1;
ssh_channel_send_eof(channel);
}
}
if(channel && ssh_channel_is_closed(channel)){
ssh_channel_free(channel);
channel=NULL;
channels[0]=NULL;
}
if(outchannels[0]){
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,0)){
lus = ssh_channel_read(channel,buffer,sizeof(buffer),0);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if(lus==0){
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else {
ret = write(1, buffer, lus);
if (ret < 0) {
fprintf(stderr, "Error writing to stdin: %s",
strerror(errno));
return;
}
}
}
while(channel && ssh_channel_is_open(channel) && ssh_channel_poll(channel,1)){ /* stderr */
lus = ssh_channel_read(channel, buffer, sizeof(buffer), 1);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if(lus==0){
ssh_channel_free(channel);
channel=channels[0]=NULL;
} else {
ret = write(2, buffer, lus);
if (ret < 0) {
fprintf(stderr, "Error writing to stderr: %s",
strerror(errno));
return;
}
channels[0] = channel; // set the first channel we want to read from
channels[1] = NULL;
ret = ssh_select(channels, outchannels, maxfd, &fds, &timeout);
if (ret == EINTR)
continue;
if (FD_ISSET(0, &fds)) {
lus = read(0, buffer, sizeof(buffer));
if (lus)
ssh_channel_write(channel, buffer, lus);
else {
eof = 1;
ssh_channel_send_eof(channel);
}
}
if (channel && ssh_channel_is_closed(channel)) {
ssh_channel_free(channel);
channel = NULL;
channels[0] = NULL;
}
if (outchannels[0]) {
while (channel && ssh_channel_is_open(channel) &&
ssh_channel_poll(channel, 0)) {
lus = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
if (lus == -1) {
fprintf(stderr,
"Error reading channel: %s\n",
ssh_get_error(session));
return;
}
}
}
if(channel && ssh_channel_is_closed(channel)){
ssh_channel_free(channel);
channel=NULL;
}
} while (ret==EINTR || ret==SSH_EINTR);
}
if (lus == 0) {
ssh_channel_free(channel);
channel = channels[0] = NULL;
} else {
ret = write(1, buffer, lus);
if (ret < 0) {
fprintf(stderr,
"Error writing to stdin: %s",
strerror(errno));
return;
}
}
}
while (channel && ssh_channel_is_open(channel) &&
ssh_channel_poll(channel, 1)) { /* stderr */
lus = ssh_channel_read(channel, buffer, sizeof(buffer), 1);
if (lus == -1) {
fprintf(stderr,
"Error reading channel: %s\n",
ssh_get_error(session));
return;
}
if (lus == 0) {
ssh_channel_free(channel);
channel = channels[0] = NULL;
} else {
ret = write(2, buffer, lus);
if (ret < 0) {
fprintf(stderr,
"Error writing to stderr: %s",
strerror(errno));
return;
}
}
}
}
if (channel && ssh_channel_is_closed(channel)) {
ssh_channel_free(channel);
channel = NULL;
}
} while (ret == EINTR || ret == SSH_EINTR);
}
}
static void forwarding(ssh_session session){
static void forwarding(ssh_session session)
{
ssh_channel channel;
int r;
channel = ssh_channel_new(session);
r = ssh_channel_open_forward(channel, desthost, atoi(port), "localhost", 22);
if(r<0) {
printf("error forwarding port : %s\n",ssh_get_error(session));
if (r < 0) {
printf("error forwarding port : %s\n", ssh_get_error(session));
return;
}
select_loop(session,channel);
select_loop(session, channel);
}
static int client(ssh_session session){
int auth=0;
char *banner = NULL;
int state;
static int client(ssh_session session)
{
int auth = 0;
char *banner = NULL;
int state;
if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0)
return -1;
ssh_options_parse_config(session, NULL);
if (ssh_options_set(session, SSH_OPTIONS_HOST, host) < 0)
return -1;
ssh_options_parse_config(session, NULL);
if(ssh_connect(session)){
fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session));
return -1;
}
state=verify_knownhost(session);
if (state != 0)
return -1;
ssh_userauth_none(session, NULL);
banner=ssh_get_issue_banner(session);
if(banner){
printf("%s\n",banner);
free(banner);
}
auth=authenticate_console(session);
if(auth != SSH_AUTH_SUCCESS){
return -1;
}
forwarding(session);
return 0;
if (ssh_connect(session)) {
fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session));
return -1;
}
state = verify_knownhost(session);
if (state != 0)
return -1;
ssh_userauth_none(session, NULL);
banner = ssh_get_issue_banner(session);
if (banner) {
printf("%s\n", banner);
free(banner);
}
auth = authenticate_console(session);
if (auth != SSH_AUTH_SUCCESS) {
return -1;
}
forwarding(session);
return 0;
}
#ifdef WITH_PCAP
ssh_pcap_file pcap;
void set_pcap(ssh_session session);
void set_pcap(ssh_session session){
if(!pcap_file)
return;
pcap=ssh_pcap_file_new();
if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){
printf("Error opening pcap file\n");
ssh_pcap_file_free(pcap);
pcap=NULL;
return;
}
ssh_set_pcap_file(session,pcap);
void set_pcap(ssh_session session)
{
if (!pcap_file)
return;
pcap = ssh_pcap_file_new();
if (ssh_pcap_file_open(pcap, pcap_file) == SSH_ERROR) {
printf("Error opening pcap file\n");
ssh_pcap_file_free(pcap);
pcap = NULL;
return;
}
ssh_set_pcap_file(session, pcap);
}
void cleanup_pcap(void);
void cleanup_pcap(void)
{
ssh_pcap_file_free(pcap);
pcap = NULL;
ssh_pcap_file_free(pcap);
pcap = NULL;
}
#endif
int main(int argc, char **argv){
int main(int argc, char **argv)
{
ssh_session session = NULL;
session = ssh_new();
if(ssh_options_getopt(session, &argc, argv)) {
fprintf(stderr, "error parsing command line :%s\n",
ssh_get_error(session));
usage();
if (ssh_options_getopt(session, &argc, argv)) {
fprintf(stderr,
"error parsing command line :%s\n",
ssh_get_error(session));
usage();
}
opts(argc,argv);
opts(argc, argv);
#ifdef WITH_PCAP
set_pcap(session);
#endif

View File

@@ -31,6 +31,7 @@ extern "C" {
bignum ssh_make_string_bn(ssh_string string);
ssh_string ssh_make_bignum_string(bignum num);
ssh_string ssh_make_padded_bignum_string(bignum num, size_t pad_len);
void ssh_print_bignum(const char *which, const_bignum num);
#ifdef __cplusplus

View File

@@ -113,6 +113,17 @@ typedef void (*ssh_status_callback) (ssh_session session, float status,
typedef void (*ssh_global_request_callback) (ssh_session session,
ssh_message message, void *userdata);
/**
* @brief SSH connect status callback. These are functions that report the
* status of the connection i,e. a function indicating the completed percentage
* of the connection
* steps.
* @param userdata Userdata to be passed to the callback function.
* @param status Percentage of connection status, going from 0.0 to 1.0
* once connection is done.
*/
typedef void (*ssh_connect_status_callback)(void *userdata, float status);
/**
* @brief Handles an SSH new channel open X11 request. This happens when the server
* sends back an X11 connection attempt. This is a client-side API
@@ -181,7 +192,7 @@ struct ssh_callbacks_struct {
* This function gets called during connection time to indicate the
* percentage of connection steps completed.
*/
void (*connect_status_function)(void *userdata, float status);
ssh_connect_status_callback connect_status_function;
/**
* This function will be called each time a global request is received.
*/
@@ -325,6 +336,28 @@ typedef int (*ssh_gssapi_accept_sec_ctx_callback) (ssh_session session,
typedef int (*ssh_gssapi_verify_mic_callback) (ssh_session session,
ssh_string mic, void *mic_buffer, size_t mic_buffer_size, void *userdata);
/**
* @brief Handles an SSH new channel open "direct-tcpip" request. This
* happens when the client forwards an incoming TCP connection on a port it
* wants to forward to the destination. This is a server-side API
* @param session current session handler
* @param destination_address the address that the TCP connection connected to
* @param destination_port the port that the TCP connection connected to
* @param originator_address the originator IP address
* @param originator_port the originator port
* @param userdata Userdata to be passed to the callback function.
* @returns a valid ssh_channel handle if the request is to be allowed
* @returns NULL if the request should not be allowed
* @warning The channel pointer returned by this callback must be closed by the
* application.
*/
typedef ssh_channel (*ssh_channel_open_request_direct_tcpip_callback)(
ssh_session session,
const char *destination_address,
int destination_port,
const char *originator_address,
int originator_port,
void *userdata);
/**
* This structure can be used to implement a libssh server, with appropriate callbacks.
@@ -375,6 +408,12 @@ struct ssh_server_callbacks_struct {
/* This function will be called when a MIC needs to be verified.
*/
ssh_gssapi_verify_mic_callback gssapi_verify_mic_function;
/**
* This function will be called when an incoming "direct-tcpip"
* request is received.
*/
ssh_channel_open_request_direct_tcpip_callback
channel_open_request_direct_tcpip_function;
};
typedef struct ssh_server_callbacks_struct *ssh_server_callbacks;

View File

@@ -45,10 +45,11 @@
#ifdef HAVE_OPENSSL_ECDH_H
#include <openssl/ecdh.h>
#endif
#include "libssh/curve25519.h"
#include "libssh/dh.h"
#include "libssh/ecdh.h"
#include "libssh/kex.h"
#include "libssh/curve25519.h"
#include "libssh/sntrup761.h"
#define DIGEST_MAX_LEN 64
@@ -56,32 +57,34 @@
#define AES_GCM_IVLEN 12
enum ssh_key_exchange_e {
/* diffie-hellman-group1-sha1 */
SSH_KEX_DH_GROUP1_SHA1=1,
/* diffie-hellman-group14-sha1 */
SSH_KEX_DH_GROUP14_SHA1,
/* diffie-hellman-group1-sha1 */
SSH_KEX_DH_GROUP1_SHA1 = 1,
/* diffie-hellman-group14-sha1 */
SSH_KEX_DH_GROUP14_SHA1,
#ifdef WITH_GEX
/* diffie-hellman-group-exchange-sha1 */
SSH_KEX_DH_GEX_SHA1,
/* diffie-hellman-group-exchange-sha256 */
SSH_KEX_DH_GEX_SHA256,
/* diffie-hellman-group-exchange-sha1 */
SSH_KEX_DH_GEX_SHA1,
/* diffie-hellman-group-exchange-sha256 */
SSH_KEX_DH_GEX_SHA256,
#endif /* WITH_GEX */
/* ecdh-sha2-nistp256 */
SSH_KEX_ECDH_SHA2_NISTP256,
/* ecdh-sha2-nistp384 */
SSH_KEX_ECDH_SHA2_NISTP384,
/* ecdh-sha2-nistp521 */
SSH_KEX_ECDH_SHA2_NISTP521,
/* curve25519-sha256@libssh.org */
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
/* curve25519-sha256 */
SSH_KEX_CURVE25519_SHA256,
/* diffie-hellman-group16-sha512 */
SSH_KEX_DH_GROUP16_SHA512,
/* diffie-hellman-group18-sha512 */
SSH_KEX_DH_GROUP18_SHA512,
/* diffie-hellman-group14-sha256 */
SSH_KEX_DH_GROUP14_SHA256,
/* ecdh-sha2-nistp256 */
SSH_KEX_ECDH_SHA2_NISTP256,
/* ecdh-sha2-nistp384 */
SSH_KEX_ECDH_SHA2_NISTP384,
/* ecdh-sha2-nistp521 */
SSH_KEX_ECDH_SHA2_NISTP521,
/* curve25519-sha256@libssh.org */
SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG,
/* curve25519-sha256 */
SSH_KEX_CURVE25519_SHA256,
/* diffie-hellman-group16-sha512 */
SSH_KEX_DH_GROUP16_SHA512,
/* diffie-hellman-group18-sha512 */
SSH_KEX_DH_GROUP18_SHA512,
/* diffie-hellman-group14-sha256 */
SSH_KEX_DH_GROUP14_SHA256,
/* sntrup761x25519-sha512@openssh.com */
SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM,
};
enum ssh_cipher_e {
@@ -125,9 +128,20 @@ struct ssh_crypto_struct {
ssh_string ecdh_server_pubkey;
#endif
#ifdef HAVE_CURVE25519
#ifdef HAVE_LIBCRYPTO
EVP_PKEY *curve25519_privkey;
#elif defined(HAVE_GCRYPT_CURVE25519)
gcry_sexp_t curve25519_privkey;
#else
ssh_curve25519_privkey curve25519_privkey;
#endif
ssh_curve25519_pubkey curve25519_client_pubkey;
ssh_curve25519_pubkey curve25519_server_pubkey;
#endif
#ifdef HAVE_SNTRUP761
ssh_sntrup761_privkey sntrup761_privkey;
ssh_sntrup761_pubkey sntrup761_client_pubkey;
ssh_sntrup761_ciphertext sntrup761_ciphertext;
#endif
ssh_string dh_server_signature; /* information used by dh_handshake. */
size_t session_id_len;
@@ -223,9 +237,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

@@ -50,6 +50,9 @@ int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned c
typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE];
typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
int ssh_curve25519_init(ssh_session session);
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k);
int ssh_curve25519_create_k(ssh_session session, ssh_curve25519_pubkey k);
int ssh_client_curve25519_init(ssh_session session);
void ssh_client_curve25519_remove_callbacks(ssh_session session);

View File

@@ -52,10 +52,10 @@ char *ssh_prefix_default_algos(enum ssh_kex_types_e algo, const char *list);
char **ssh_space_tokenize(const char *chain);
int ssh_get_kex1(ssh_session session);
char *ssh_find_matching(const char *in_d, const char *what_d);
const char *ssh_kex_get_supported_method(uint32_t algo);
const char *ssh_kex_get_default_methods(uint32_t algo);
const char *ssh_kex_get_fips_methods(uint32_t algo);
const char *ssh_kex_get_description(uint32_t algo);
const char *ssh_kex_get_supported_method(enum ssh_kex_types_e type);
const char *ssh_kex_get_default_methods(enum ssh_kex_types_e type);
const char *ssh_kex_get_fips_methods(enum ssh_kex_types_e type);
const char *ssh_kex_get_description(enum ssh_kex_types_e type);
char *ssh_client_select_hostkeys(ssh_session session);
int ssh_send_rekex(ssh_session session);
int server_set_kex(ssh_session session);

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

@@ -49,9 +49,10 @@
#endif
#endif
#include <stdarg.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef _MSC_VER
typedef int mode_t;
@@ -850,6 +851,7 @@ LIBSSH_API char *ssh_string_to_char(ssh_string str);
#define SSH_STRING_FREE_CHAR(x) \
do { if ((x) != NULL) { ssh_string_free_char(x); x = NULL; } } while(0)
LIBSSH_API void ssh_string_free_char(char *s);
LIBSSH_API int ssh_string_cmp(ssh_string s1, ssh_string s2);
LIBSSH_API int ssh_getpass(const char *prompt, char *buf, size_t len, int echo,
int verify);
@@ -874,6 +876,7 @@ LIBSSH_API const char* ssh_get_cipher_in(ssh_session session);
LIBSSH_API const char* ssh_get_cipher_out(ssh_session session);
LIBSSH_API const char* ssh_get_hmac_in(ssh_session session);
LIBSSH_API const char* ssh_get_hmac_out(ssh_session session);
LIBSSH_API const char *ssh_get_supported_methods(enum ssh_kex_types_e type);
LIBSSH_API ssh_buffer ssh_buffer_new(void);
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
@@ -886,6 +889,27 @@ LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
LIBSSH_API int ssh_session_set_disconnect_message(ssh_session session, const char *message);
/* SSHSIG hashes data independently from the key used, so we use a new enum
to avoid confusion. See
https://gitlab.com/jas/ietf-sshsig-format/-/blob/cc70a225cbd695d5a6f20aaebdb4b92b0818e43a/ietf-sshsig-format.md#L137
*/
enum sshsig_digest_e {
SSHSIG_DIGEST_SHA2_256 = 0,
SSHSIG_DIGEST_SHA2_512 = 1,
};
LIBSSH_API int sshsig_sign(const void *data,
size_t data_length,
ssh_key privkey,
const char *sig_namespace,
enum sshsig_digest_e hash_alg,
char **signature);
LIBSSH_API int sshsig_verify(const void *data,
size_t data_length,
const char *signature,
const char *sig_namespace,
ssh_key *sign_key);
#ifndef LIBSSH_LEGACY_0_4
#include "libssh/legacy.h"
#endif

View File

@@ -28,6 +28,7 @@ struct ssh_auth_request {
int method;
char *password;
struct ssh_key_struct *pubkey;
struct ssh_key_struct *server_pubkey;
char *sigtype;
enum ssh_publickey_state_e signature_state;
char kbdint_response;

View File

@@ -25,6 +25,7 @@
extern "C" {
#endif
int ssh_config_parse(ssh_session session, FILE *fp, bool global);
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,

View File

@@ -51,6 +51,15 @@
#define SSH_KEY_FLAG_PRIVATE 0x0002
#define SSH_KEY_FLAG_PKCS11_URI 0x0004
/* Constants matching the Lightweight Secure Shell Signature Format */
/* https://datatracker.ietf.org/doc/draft-josefsson-sshsig-format */
#define SSHSIG_VERSION 0x01
#define SSHSIG_MAGIC_PREAMBLE "SSHSIG"
#define SSHSIG_MAGIC_PREAMBLE_LEN (sizeof(SSHSIG_MAGIC_PREAMBLE) - 1)
#define SSHSIG_BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----"
#define SSHSIG_END_SIGNATURE "-----END SSH SIGNATURE-----"
#define SSHSIG_LINE_LENGTH 76
struct ssh_key_struct {
enum ssh_keytypes_e type;
int flags;
@@ -63,11 +72,12 @@ struct ssh_key_struct {
mbedtls_pk_context *pk;
mbedtls_ecdsa_context *ecdsa;
#elif defined(HAVE_LIBCRYPTO)
/* This holds either ENGINE key for PKCS#11 support or just key in
* high-level format */
/* This holds either ENGINE/PROVIDER key for PKCS#11 support
* or just key in high-level format */
EVP_PKEY *key;
/* keep this around for FIPS mode so we can parse the public keys. We won't
* be able to use them nor use the private keys though */
uint8_t *ed25519_pubkey;
uint8_t *ed25519_privkey;
#endif /* HAVE_LIBGCRYPT */
#ifndef HAVE_LIBCRYPTO
ed25519_pubkey *ed25519_pubkey;
@@ -76,6 +86,11 @@ struct ssh_key_struct {
ssh_string sk_application;
ssh_buffer cert;
enum ssh_keytypes_e cert_type;
/* Security Key specific private data */
uint8_t sk_flags;
ssh_string sk_key_handle;
ssh_string sk_reserved;
};
struct ssh_signature_struct {
@@ -127,6 +142,11 @@ enum ssh_digest_e ssh_key_hash_from_name(const char *name);
((kt) >= SSH_KEYTYPE_ECDSA_P256_CERT01 &&\
(kt) <= SSH_KEYTYPE_ED25519_CERT01))
#define is_sk_key_type(kt) \
((kt) == SSH_KEYTYPE_SK_ECDSA || (kt) == SSH_KEYTYPE_SK_ED25519 || \
(kt) == SSH_KEYTYPE_SK_ECDSA_CERT01 || \
(kt) == SSH_KEYTYPE_SK_ED25519_CERT01)
/* SSH Signature Functions */
ssh_signature ssh_signature_new(void);
void ssh_signature_free(ssh_signature sign);

View File

@@ -61,6 +61,7 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
enum ssh_keytypes_e type);
/* SSH Key Functions */
ssh_key pki_key_dup_common_init(const ssh_key key, int demote);
ssh_key pki_key_dup(const ssh_key key, int demote);
int pki_key_generate_rsa(ssh_key key, int parameter);
int pki_key_generate_ecdsa(ssh_key key, int parameter);
@@ -148,6 +149,7 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey,
ssh_string privkey);
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey);
/* PKI Container OpenSSH */
ssh_key ssh_pki_openssh_pubkey_import(const char *text_key);
@@ -162,6 +164,11 @@ int pki_uri_import(const char *uri_name, ssh_key *key, enum ssh_key_e key_type);
#endif /* WITH_PKCS11_URI */
bool ssh_key_size_allowed_rsa(int min_size, ssh_key key);
/* Security Key Helper Functions */
int pki_buffer_pack_sk_priv_data(ssh_buffer buffer, const ssh_key key);
int pki_buffer_unpack_sk_priv_data(ssh_buffer buffer, ssh_key key);
#ifdef __cplusplus
}
#endif

View File

@@ -30,10 +30,11 @@
#define _LIBSSH_PRIV_H
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#if !defined(HAVE_STRTOULL)
# if defined(HAVE___STRTOULL)
@@ -164,6 +165,9 @@ int ssh_gettimeofday(struct timeval *__p, void *__t);
#define gettimeofday ssh_gettimeofday
struct tm *ssh_localtime(const time_t *timer, struct tm *result);
# define localtime_r ssh_localtime
#define _XCLOSESOCKET closesocket
# ifdef HAVE_IO_H
@@ -329,7 +333,7 @@ int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
/* match.c */
int match_pattern_list(const char *string, const char *pattern,
size_t len, int dolower);
int match_hostname(const char *host, const char *pattern, unsigned int len);
int match_hostname(const char *host, const char *pattern, size_t len);
#ifndef _WIN32
int match_cidr_address_list(const char *address,
const char *addrlist,
@@ -353,10 +357,10 @@ int ssh_connector_remove_event(ssh_connector connector);
#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
/** Zero a structure */
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
#define ZERO_STRUCT(x) memset(&(x), 0, sizeof(x))
/** Zero a structure given a pointer to the structure */
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((x), 0, sizeof(*(x))); } while(0)
/** Get the size of an array */
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
@@ -365,6 +369,17 @@ int ssh_connector_remove_event(ssh_connector connector);
void explicit_bzero(void *s, size_t n);
#endif /* !HAVE_EXPLICIT_BZERO */
void burn_free(void *ptr, size_t len);
/** Free memory space after zeroing it */
#define BURN_FREE(x, len) \
do { \
if ((x) != NULL) { \
burn_free((x), (len)); \
(x) = NULL; \
} \
} while (0)
/**
* This is a hack to fix warnings. The idea is to use this everywhere that we
* get the "discarding const" warning by the compiler. That doesn't actually

View File

@@ -120,6 +120,8 @@ enum ssh_pending_call_e {
/* server-sig-algs extension */
#define SSH_EXT_SIG_RSA_SHA256 0x02
#define SSH_EXT_SIG_RSA_SHA512 0x04
/* Host-bound public key authentication extension */
#define SSH_EXT_PUBLICKEY_HOSTBOUND 0x08
/* members that are common to ssh_session and ssh_bind */
struct ssh_common_struct {

View File

@@ -79,6 +79,7 @@ typedef struct sftp_status_message_struct* sftp_status_message;
typedef struct sftp_statvfs_struct* sftp_statvfs_t;
typedef struct sftp_limits_struct* sftp_limits_t;
typedef struct sftp_aio_struct* sftp_aio;
typedef struct sftp_name_id_map_struct *sftp_name_id_map;
struct sftp_session_struct {
ssh_session session;
@@ -213,6 +214,22 @@ struct sftp_limits_struct {
uint64_t max_open_handles; /** maximum number of active handles allowed by server */
};
/**
* @brief SFTP names map structure to store the mapping between ids and names.
*
* This is mainly for the use of sftp_get_users_groups_by_id() function.
*/
struct sftp_name_id_map_struct {
/** @brief Count of name-id pairs in the map */
uint32_t count;
/** @brief Array of ids, ids[i] mapped to names[i] */
uint32_t *ids;
/** @brief Array of names, names[i] mapped to ids[i] */
char **names;
};
/**
* @brief Creates a new sftp session.
*
@@ -220,24 +237,30 @@ struct sftp_limits_struct {
* with the server inside of the provided ssh session. This function call is
* usually followed by the sftp_init(), which initializes SFTP protocol itself.
*
* @param session The ssh session to use.
* @param session The ssh session to use. The session *must* be in
* blocking mode since most `sftp_*` functions do not
* support the non-blocking API.
*
* @return A new sftp session or NULL on error.
*
* @see sftp_free()
* @see sftp_init()
* @see ssh_set_blocking()
*/
LIBSSH_API sftp_session sftp_new(ssh_session session);
/**
* @brief Start a new sftp session with an existing channel.
*
* @param session The ssh session to use.
* @param session The ssh session to use. The session *must* be in
* blocking mode since most `sftp_*` functions do not
* support the non-blocking API.
* @param channel An open session channel with subsystem already allocated
*
* @return A new sftp session or NULL on error.
*
* @see sftp_free()
* @see ssh_set_blocking()
*/
LIBSSH_API sftp_session sftp_new_channel(ssh_session session, ssh_channel channel);
@@ -1188,6 +1211,58 @@ LIBSSH_API char *sftp_expand_path(sftp_session sftp, const char *path);
*/
LIBSSH_API char *sftp_home_directory(sftp_session sftp, const char *username);
/**
* @brief Create a new sftp_name_id_map struct.
*
* @param count The number of ids/names to store in the map.
*
* @return A pointer to the newly allocated sftp_name_id_map
* struct.
*/
LIBSSH_API sftp_name_id_map sftp_name_id_map_new(uint32_t count);
/**
* @brief Free the memory of an allocated `sftp_name_id_map` struct.
*
* @param map A pointer to the `sftp_name_id_map` struct to free.
*/
LIBSSH_API void sftp_name_id_map_free(sftp_name_id_map map);
/**
* @brief Retrieves usernames and group names based on provided user and group
* IDs.
*
* The retrieved names are stored in the `names` field of the
* `sftp_name_id_map` structure. In case a uid or gid is not found, an empty
* string is stored.
*
* This calls the "users-groups-by-id@openssh.com" extension.
* You should check if the extension is supported using:
*
* @code
* int supported = sftp_extension_supported(sftp,
* "users-groups-by-id@openssh.com", "1");
* @endcode
*
* @param sftp The SFTP session handle.
*
* @param users_map A pointer to a `sftp_name_id_map` struct with the user
* IDs. Can be NULL if only group names are needed.
*
* @param groups_map A pointer to a `sftp_name_id_map` struct with the group
* IDs. Can be NULL if only user names are needed.
*
* @return 0 on success, < 0 on error with ssh and sftp error set.
*
* @note The caller needs to free the memory used for
* the maps later using `sftp_name_id_map_free()`.
*
* @see sftp_get_error()
*/
LIBSSH_API int sftp_get_users_groups_by_id(sftp_session sftp,
sftp_name_id_map users_map,
sftp_name_id_map groups_map);
#ifdef WITH_SERVER
/**
* @brief Create a new sftp server session.

View File

@@ -21,6 +21,8 @@
#ifndef SFTP_PRIV_H
#define SFTP_PRIV_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -62,6 +64,39 @@ int sftp_read_and_dispatch(sftp_session sftp);
sftp_message sftp_dequeue(sftp_session sftp, uint32_t id);
/**
* @brief Receive the response of an sftp request
*
* In blocking mode, if the response hasn't arrived at the time of call, this
* function waits for the response to arrive.
*
* @param sftp The sftp session via which the request was sent.
*
* @param id The request identifier of the request whose
* corresponding response is required.
*
* @param blocking Flag to indicate the operating mode. true indicates
* blocking mode and false indicates non-blocking mode
*
* @param msg_ptr Pointer to the location to store the response message.
* In case of success, the message is allocated
* dynamically and must be freed (using
* sftp_message_free()) by the caller after usage. In case
* of failure, this is left untouched.
*
* @returns SSH_OK on success
* @returns SSH_ERROR on failure with the sftp and ssh errors set
* @returns SSH_AGAIN in case of non-blocking mode if the response hasn't
* arrived yet.
*
* @warning In blocking mode, this may block indefinitely for an invalid request
* identifier.
*/
int sftp_recv_response_msg(sftp_session sftp,
uint32_t id,
bool blocking,
sftp_message *msg_ptr);
/*
* Assigns a new SFTP ID for new requests and assures there is no collision
* between them.

View File

@@ -0,0 +1,86 @@
/*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
* Copyright (c) 2023 Simon Josefsson <simon@josefsson.org>
* Copyright (c) 2025 Jakub Jelen <jjelen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation,
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef SNTRUP761_H_
#define SNTRUP761_H_
#include "config.h"
#include "curve25519.h"
#include "libssh.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef HAVE_CURVE25519
#define HAVE_SNTRUP761 1
#endif
extern void crypto_hash_sha512(unsigned char *out,
const unsigned char *in,
unsigned long long inlen);
/*
* Derived from public domain source, written by (in alphabetical order):
* - Daniel J. Bernstein
* - Chitchanok Chuengsatiansup
* - Tanja Lange
* - Christine van Vredendaal
*/
#include <stdint.h>
#include <string.h>
#define SNTRUP761_SECRETKEY_SIZE 1763
#define SNTRUP761_PUBLICKEY_SIZE 1158
#define SNTRUP761_CIPHERTEXT_SIZE 1039
#define SNTRUP761_SIZE 32
typedef void sntrup761_random_func(void *ctx, size_t length, uint8_t *dst);
void sntrup761_keypair(uint8_t *pk,
uint8_t *sk,
void *random_ctx,
sntrup761_random_func *random);
void sntrup761_enc(uint8_t *c,
uint8_t *k,
const uint8_t *pk,
void *random_ctx,
sntrup761_random_func *random);
void sntrup761_dec(uint8_t *k, const uint8_t *c, const uint8_t *sk);
typedef unsigned char ssh_sntrup761_pubkey[SNTRUP761_PUBLICKEY_SIZE];
typedef unsigned char ssh_sntrup761_privkey[SNTRUP761_SECRETKEY_SIZE];
typedef unsigned char ssh_sntrup761_ciphertext[SNTRUP761_CIPHERTEXT_SIZE];
int ssh_client_sntrup761x25519_init(ssh_session session);
void ssh_client_sntrup761x25519_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_sntrup761x25519_init(ssh_session session);
#endif /* WITH_SERVER */
#ifdef __cplusplus
}
#endif
#endif /* SNTRUP761_H_ */

View File

@@ -33,7 +33,7 @@ void ssh_socket_cleanup(void);
ssh_socket ssh_socket_new(ssh_session session);
void ssh_socket_reset(ssh_socket s);
void ssh_socket_free(ssh_socket s);
void ssh_socket_set_fd(ssh_socket s, socket_t fd);
int ssh_socket_set_fd(ssh_socket s, socket_t fd);
socket_t ssh_socket_get_fd(ssh_socket s);
void ssh_socket_set_connected(ssh_socket s, struct ssh_poll_handle_struct *p);
int ssh_socket_unix(ssh_socket s, const char *path);

View File

@@ -129,6 +129,7 @@ int evp_build_pkey(const char* name, OSSL_PARAM_BLD *param_bld, EVP_PKEY **pkey,
int evp_dup_dsa_pkey(const ssh_key key, ssh_key new_key, int demote);
int evp_dup_rsa_pkey(const ssh_key key, ssh_key new_key, int demote);
int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote);
int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote);
#endif /* HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER */
#ifdef __cplusplus

View File

@@ -8,3 +8,4 @@ Description: The SSH Library
Version: @PROJECT_VERSION@
Libs: -L${libdir} -lssh
Cflags: -I${includedir}
Requires.private: @LIBSSH_PC_REQUIRES_PRIVATE@

View File

@@ -1 +1 @@
4.10.2
4.10.0

View File

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

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

@@ -87,6 +87,7 @@ set(libssh_SRCS
connector.c
crypto_common.c
curve25519.c
sntrup761.c
dh.c
ecdh.c
error.c
@@ -174,6 +175,13 @@ if (WITH_GCRYPT)
chachapoly.c
)
endif (NOT HAVE_GCRYPT_CHACHA_POLY)
if (HAVE_GCRYPT_CURVE25519)
set(libssh_SRCS
${libssh_SRCS}
curve25519_gcrypt.c
)
endif(HAVE_GCRYPT_CURVE25519)
elseif (WITH_MBEDTLS)
set(libssh_SRCS
${libssh_SRCS}
@@ -190,6 +198,7 @@ elseif (WITH_MBEDTLS)
external/fe25519.c
external/ge25519.c
external/sc25519.c
external/sntrup761.c
)
if (NOT (HAVE_MBEDTLS_CHACHA20_H AND HAVE_MBEDTLS_POLY1305_H))
set(libssh_SRCS
@@ -199,17 +208,24 @@ elseif (WITH_MBEDTLS)
chachapoly.c
)
endif()
if (HAVE_MBEDTLS_CURVE25519)
set(libssh_SRCS
${libssh_SRCS}
curve25519_mbedcrypto.c
)
endif(HAVE_MBEDTLS_CURVE25519)
else (WITH_GCRYPT)
set(libssh_SRCS
${libssh_SRCS}
threads/libcrypto.c
pki_crypto.c
ecdh_crypto.c
curve25519_crypto.c
getrandom_crypto.c
md_crypto.c
libcrypto.c
dh_crypto.c
external/sntrup761.c
)
if (NOT HAVE_OPENSSL_EVP_CHACHA20)
set(libssh_SRCS
@@ -261,9 +277,10 @@ if (WITH_GSSAPI AND GSSAPI_FOUND)
endif (WITH_GSSAPI AND GSSAPI_FOUND)
if (NOT WITH_NACL)
if (NOT HAVE_LIBCRYPTO)
if (NOT (HAVE_LIBCRYPTO OR HAVE_MBEDTLS_CURVE25519 OR HAVE_GCRYPT_CURVE25519))
set(libssh_SRCS
${libssh_SRCS}
curve25519_fallback.c
external/curve25519_ref.c
)
endif()

View File

@@ -67,87 +67,94 @@
(((x) == SSH_AGENT_FAILURE) || ((x) == SSH_COM_AGENT2_FAILURE) || \
((x) == SSH2_AGENT_FAILURE))
static uint32_t atomicio(struct ssh_agent_struct *agent, void *buf, uint32_t n, int do_read) {
char *b = buf;
uint32_t pos = 0;
ssize_t res;
ssh_pollfd_t pfd;
ssh_channel channel = agent->channel;
socket_t fd;
static uint32_t
atomicio(struct ssh_agent_struct *agent, void *buf, uint32_t n, int do_read)
{
char *b = buf;
uint32_t pos = 0;
ssize_t res;
ssh_pollfd_t pfd;
ssh_channel channel = agent->channel;
socket_t fd;
/* Using a socket ? */
if (channel == NULL) {
fd = ssh_socket_get_fd(agent->sock);
pfd.fd = fd;
pfd.events = do_read ? POLLIN : POLLOUT;
/* Using a socket ? */
if (channel == NULL) {
fd = ssh_socket_get_fd(agent->sock);
pfd.fd = fd;
pfd.events = do_read ? POLLIN : POLLOUT;
while (n > pos) {
if (do_read) {
res = recv(fd, b + pos, n - pos, 0);
} else {
res = send(fd, b + pos, n - pos, 0);
}
switch (res) {
case -1:
if (errno == EINTR) {
continue;
}
while (n > pos) {
if (do_read) {
res = recv(fd, b + pos, n - pos, 0);
} else {
res = send(fd, b + pos, n - pos, 0);
}
switch (res) {
case -1:
if (errno == EINTR) {
continue;
}
#ifdef EWOULDBLOCK
if (errno == EAGAIN || errno == EWOULDBLOCK) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
#else
if (errno == EAGAIN) {
if (errno == EAGAIN) {
#endif
(void) ssh_poll(&pfd, 1, -1);
continue;
}
return 0;
case 0:
/* read returns 0 on end-of-file */
errno = do_read ? 0 : EPIPE;
return pos;
default:
pos += (uint32_t) res;
(void)ssh_poll(&pfd, 1, -1);
continue;
}
return 0;
case 0:
/* read returns 0 on end-of-file */
errno = do_read ? 0 : EPIPE;
return pos;
default:
pos += (uint32_t)res;
}
}
}
return pos;
return pos;
} else {
/* using an SSH channel */
while (n > pos){
if (do_read)
res = ssh_channel_read(channel,b + pos, n-pos, 0);
else
res = ssh_channel_write(channel, b+pos, n-pos);
if (res == SSH_AGAIN)
continue;
if (res == SSH_ERROR)
return 0;
pos += (uint32_t)res;
}
return pos;
/* using an SSH channel */
while (n > pos) {
if (do_read) {
res = ssh_channel_read(channel, b + pos, n - pos, 0);
} else {
res = ssh_channel_write(channel, b + pos, n - pos);
}
if (res == SSH_AGAIN) {
continue;
}
if (res == SSH_ERROR) {
return 0;
}
pos += (uint32_t)res;
}
return pos;
}
}
ssh_agent ssh_agent_new(struct ssh_session_struct *session) {
ssh_agent agent = NULL;
ssh_agent ssh_agent_new(struct ssh_session_struct *session)
{
ssh_agent agent = NULL;
agent = malloc(sizeof(struct ssh_agent_struct));
if (agent == NULL) {
return NULL;
}
ZERO_STRUCTP(agent);
agent = calloc(1, sizeof(struct ssh_agent_struct));
if (agent == NULL) {
return NULL;
}
agent->count = 0;
agent->sock = ssh_socket_new(session);
if (agent->sock == NULL) {
SAFE_FREE(agent);
return NULL;
}
agent->channel = NULL;
return agent;
agent->count = 0;
agent->sock = ssh_socket_new(session);
if (agent->sock == NULL) {
SAFE_FREE(agent);
return NULL;
}
agent->channel = NULL;
return agent;
}
static void agent_set_channel(struct ssh_agent_struct *agent, ssh_channel channel){
agent->channel = channel;
static void agent_set_channel(struct ssh_agent_struct *agent,
ssh_channel channel)
{
agent->channel = channel;
}
/**
@@ -168,15 +175,19 @@ static void agent_set_channel(struct ssh_agent_struct *agent, ssh_channel channe
* @returns SSH_OK in case of success
* SSH_ERROR in case of an error
*/
int ssh_set_agent_channel(ssh_session session, ssh_channel channel){
if (!session)
return SSH_ERROR;
if (!session->agent){
ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent");
return SSH_ERROR;
}
agent_set_channel(session->agent, channel);
return SSH_OK;
int ssh_set_agent_channel(ssh_session session, ssh_channel channel)
{
if (!session) {
return SSH_ERROR;
}
if (!session->agent) {
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Session has no active agent");
return SSH_ERROR;
}
agent_set_channel(session->agent, channel);
return SSH_OK;
}
/** @brief sets the SSH agent socket.
@@ -187,64 +198,71 @@ int ssh_set_agent_channel(ssh_session session, ssh_channel channel){
* @returns SSH_OK in case of success
* SSH_ERROR in case of an error
*/
int ssh_set_agent_socket(ssh_session session, socket_t fd){
if (!session)
return SSH_ERROR;
if (!session->agent){
ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent");
return SSH_ERROR;
}
int ssh_set_agent_socket(ssh_session session, socket_t fd)
{
if (!session) {
return SSH_ERROR;
}
if (!session->agent) {
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Session has no active agent");
return SSH_ERROR;
}
ssh_socket_set_fd(session->agent->sock, fd);
return SSH_OK;
return ssh_socket_set_fd(session->agent->sock, fd);
}
/**
* @}
*/
void ssh_agent_close(struct ssh_agent_struct *agent) {
if (agent == NULL) {
return;
}
void ssh_agent_close(struct ssh_agent_struct *agent)
{
if (agent == NULL) {
return;
}
ssh_socket_close(agent->sock);
ssh_socket_close(agent->sock);
}
void ssh_agent_free(ssh_agent agent) {
if (agent) {
if (agent->ident) {
SSH_BUFFER_FREE(agent->ident);
void ssh_agent_free(ssh_agent agent)
{
if (agent) {
if (agent->ident) {
SSH_BUFFER_FREE(agent->ident);
}
if (agent->sock) {
ssh_agent_close(agent);
ssh_socket_free(agent->sock);
}
SAFE_FREE(agent);
}
if (agent->sock) {
ssh_agent_close(agent);
ssh_socket_free(agent->sock);
}
SAFE_FREE(agent);
}
}
static int agent_connect(ssh_session session) {
const char *auth_sock = NULL;
static int agent_connect(ssh_session session)
{
const char *auth_sock = NULL;
if (session == NULL || session->agent == NULL) {
return -1;
}
if (session->agent->channel != NULL) {
return 0;
}
auth_sock = session->opts.agent_socket ? session->opts.agent_socket
: getenv("SSH_AUTH_SOCK");
if (auth_sock && *auth_sock) {
if (ssh_socket_unix(session->agent->sock, auth_sock) < 0) {
return -1;
}
return 0;
}
if (session == NULL || session->agent == NULL) {
return -1;
}
if (session->agent->channel != NULL)
return 0;
auth_sock = session->opts.agent_socket ?
session->opts.agent_socket : getenv("SSH_AUTH_SOCK");
if (auth_sock && *auth_sock) {
if (ssh_socket_unix(session->agent->sock, auth_sock) < 0) {
return -1;
}
return 0;
}
return -1;
}
#if 0
@@ -268,61 +286,66 @@ static int agent_decode_reply(struct ssh_session_struct *session, int type) {
#endif
static int agent_talk(struct ssh_session_struct *session,
struct ssh_buffer_struct *request, struct ssh_buffer_struct *reply) {
uint32_t len = 0;
uint8_t tmpbuf[4];
uint8_t *payload = tmpbuf;
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
struct ssh_buffer_struct *request,
struct ssh_buffer_struct *reply)
{
uint32_t len = 0;
uint8_t tmpbuf[4];
uint8_t *payload = tmpbuf;
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
len = ssh_buffer_get_len(request);
SSH_LOG(SSH_LOG_TRACE, "Request length: %" PRIu32, len);
PUSH_BE_U32(payload, 0, len);
len = ssh_buffer_get_len(request);
SSH_LOG(SSH_LOG_TRACE, "Request length: %" PRIu32, len);
PUSH_BE_U32(payload, 0, len);
/* send length and then the request packet */
if (atomicio(session->agent, payload, 4, 0) == 4) {
if (atomicio(session->agent, ssh_buffer_get(request), len, 0)
!= len) {
SSH_LOG(SSH_LOG_TRACE, "atomicio sending request failed: %s",
strerror(errno));
return -1;
/* send length and then the request packet */
if (atomicio(session->agent, payload, 4, 0) == 4) {
if (atomicio(session->agent, ssh_buffer_get(request), len, 0) != len) {
SSH_LOG(SSH_LOG_TRACE,
"atomicio sending request failed: %s",
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return -1;
}
} else {
SSH_LOG(SSH_LOG_TRACE,
"atomicio sending request length failed: %s",
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return -1;
}
} else {
SSH_LOG(SSH_LOG_TRACE,
"atomicio sending request length failed: %s",
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return -1;
}
/* wait for response, read the length of the response packet */
if (atomicio(session->agent, payload, 4, 1) != 4) {
SSH_LOG(SSH_LOG_TRACE, "atomicio read response length failed: %s",
strerror(errno));
return -1;
}
/* wait for response, read the length of the response packet */
if (atomicio(session->agent, payload, 4, 1) != 4) {
SSH_LOG(SSH_LOG_TRACE,
"atomicio read response length failed: %s",
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return -1;
}
len = PULL_BE_U32(payload, 0);
if (len > 256 * 1024) {
ssh_set_error(session, SSH_FATAL,
"Authentication response too long: %" PRIu32, len);
return -1;
}
SSH_LOG(SSH_LOG_TRACE, "Response length: %" PRIu32, len);
len = PULL_BE_U32(payload, 0);
if (len > 256 * 1024) {
ssh_set_error(session,
SSH_FATAL,
"Authentication response too long: %" PRIu32,
len);
return -1;
}
SSH_LOG(SSH_LOG_TRACE, "Response length: %" PRIu32, len);
payload = ssh_buffer_allocate(reply, len);
if (payload == NULL) {
SSH_LOG(SSH_LOG_DEBUG, "Not enough space");
return -1;
}
payload = ssh_buffer_allocate(reply, len);
if (payload == NULL) {
SSH_LOG(SSH_LOG_DEBUG, "Not enough space");
return -1;
}
if (atomicio(session->agent, payload, len, 1) != len) {
SSH_LOG(SSH_LOG_DEBUG,
"Error reading response from authentication socket.");
/* Rollback the unused space */
ssh_buffer_pass_bytes_end(reply, len);
return -1;
}
if (atomicio(session->agent, payload, len, 1) != len) {
SSH_LOG(SSH_LOG_DEBUG,
"Error reading response from authentication socket.");
/* Rollback the unused space */
ssh_buffer_pass_bytes_end(reply, len);
return -1;
}
return 0;
return 0;
}
uint32_t ssh_agent_get_ident_count(struct ssh_session_struct *session)
@@ -471,22 +494,23 @@ ssh_key ssh_agent_get_next_ident(struct ssh_session_struct *session,
return key;
}
int ssh_agent_is_running(ssh_session session) {
if (session == NULL || session->agent == NULL) {
return 0;
}
if (ssh_socket_is_open(session->agent->sock)) {
return 1;
} else {
if (agent_connect(session) < 0) {
return 0;
} else {
return 1;
int ssh_agent_is_running(ssh_session session)
{
if (session == NULL || session->agent == NULL) {
return 0;
}
}
return 0;
if (ssh_socket_is_open(session->agent->sock)) {
return 1;
} else {
if (agent_connect(session) < 0) {
return 0;
} else {
return 1;
}
}
return 0;
}
ssh_string ssh_agent_sign_data(ssh_session session,
@@ -500,6 +524,7 @@ ssh_string ssh_agent_sign_data(ssh_session session,
unsigned int type = 0;
unsigned int flags = 0;
uint32_t dlen;
size_t request_len;
int rc;
request = ssh_buffer_new();
@@ -525,11 +550,14 @@ ssh_string ssh_agent_sign_data(ssh_session session,
* - 2 x uint32_t
* - 1 x ssh_string (uint8_t + data)
*/
rc = ssh_buffer_allocate_size(request,
sizeof(uint8_t) * 2 +
sizeof(uint32_t) * 2 +
ssh_string_len(key_blob));
request_len = sizeof(uint8_t) * 2 +
sizeof(uint32_t) * 2 +
ssh_string_len(key_blob);
/* this can't overflow the uint32_t as the
* STRING_SIZE_MAX is (UINT32_MAX >> 8) + 1 */
rc = ssh_buffer_allocate_size(request, (uint32_t)request_len);
if (rc < 0) {
SSH_STRING_FREE(key_blob);
SSH_BUFFER_FREE(request);
return NULL;
}

View File

@@ -463,6 +463,108 @@ fail:
return SSH_AUTH_ERROR;
}
/**
* @internal
*
* @brief Adds the server's public key to the authentication request.
*
* This function is used internally when the hostbound public key authentication
* extension is enabled. It export the server's public key and adds it to the
* authentication buffer.
*
* @param[in] session The SSH session.
*
* @returns SSH_OK on success, SSH_ERROR if an error occurred.
*/
static int add_hostbound_pubkey(ssh_session session)
{
int rc;
ssh_string server_pubkey_s = NULL;
if (session == NULL) {
return SSH_ERROR;
}
if (session->current_crypto == NULL ||
session->current_crypto->server_pubkey == NULL) {
ssh_set_error(session,
SSH_FATAL,
"Invalid session or server public key");
return SSH_ERROR;
}
rc = ssh_pki_export_pubkey_blob(session->current_crypto->server_pubkey,
&server_pubkey_s);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_ssh_string(session->out_buffer, server_pubkey_s);
if (rc < 0) {
goto error;
}
error:
SSH_STRING_FREE(server_pubkey_s);
return rc;
}
/**
* @internal
*
* @brief Build a public key authentication request.
*
* This helper function creates a SSH2_MSG_USERAUTH_REQUEST message for public
* key authentication and adds the server's public key if the hostbound
* extension is enabled.
*
* @param[in] session The SSH session.
* @param[in] username The username, may be NULL.
* @param[in] auth_type Authentication type (0 for key offer, 1 for actual
* auth).
* @param[in] sig_type_c The signature algorithm name.
* @param[in] pubkey_s The public key string.
*
* @return SSH_OK on success, SSH_ERROR if an error occurred.
*/
static int build_pubkey_auth_request(ssh_session session,
const char *username,
int has_signature,
const char *sig_type_c,
ssh_string pubkey_s)
{
int rc;
const char *auth_method = "publickey";
if (session->extensions & SSH_EXT_PUBLICKEY_HOSTBOUND) {
auth_method = "publickey-hostbound-v00@openssh.com";
}
/* request */
rc = ssh_buffer_pack(session->out_buffer,
"bsssbsS",
SSH2_MSG_USERAUTH_REQUEST,
username ? username : session->opts.username,
"ssh-connection",
auth_method,
has_signature, /* private key? */
sig_type_c, /* algo */
pubkey_s /* public key */
);
if (rc < 0) {
return SSH_ERROR;
}
if (session->extensions & SSH_EXT_PUBLICKEY_HOSTBOUND) {
rc = add_hostbound_pubkey(session);
if (rc < 0) {
return SSH_ERROR;
}
}
return SSH_OK;
}
/**
* @brief Try to authenticate with the given public key.
*
@@ -509,17 +611,17 @@ int ssh_userauth_try_publickey(ssh_session session,
return SSH_AUTH_ERROR;
}
switch(session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
goto pending;
default:
ssh_set_error(session,
SSH_FATAL,
"Wrong state (%d) during pending SSH call",
session->pending_call_state);
return SSH_AUTH_ERROR;
switch (session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
case SSH_PENDING_CALL_AUTH_OFFER_PUBKEY:
goto pending;
default:
ssh_set_error(session,
SSH_FATAL,
"Wrong state (%d) during pending SSH call",
session->pending_call_state);
return SSH_AUTH_ERROR;
}
/* Note, that this is intentionally before checking the signature type
@@ -536,13 +638,15 @@ int ssh_userauth_try_publickey(ssh_session session,
/* Check if the given public key algorithm is allowed */
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
if (sig_type_c == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Invalid key type (unknown)");
return SSH_AUTH_DENIED;
}
rc = ssh_key_algorithm_allowed(session, sig_type_c);
if (!rc) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"The key algorithm '%s' is not allowed to be used by"
" PUBLICKEY_ACCEPTED_TYPES configuration option",
sig_type_c);
@@ -550,9 +654,12 @@ int ssh_userauth_try_publickey(ssh_session session,
}
allowed = ssh_key_size_allowed(session, pubkey);
if (!allowed) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"The '%s' key type of size %d is not allowed by "
"RSA_MIN_SIZE", sig_type_c, ssh_key_size(pubkey));
"RSA_MIN_SIZE",
sig_type_c,
ssh_key_size(pubkey));
return SSH_AUTH_DENIED;
}
@@ -563,20 +670,10 @@ int ssh_userauth_try_publickey(ssh_session session,
}
SSH_LOG(SSH_LOG_TRACE, "Trying signature type %s", sig_type_c);
/* request */
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
SSH2_MSG_USERAUTH_REQUEST,
username ? username : session->opts.username,
"ssh-connection",
"publickey",
0, /* private key ? */
sig_type_c, /* algo */
pubkey_s /* public key */
);
rc = build_pubkey_auth_request(session, username, 0, sig_type_c, pubkey_s);
if (rc < 0) {
goto fail;
}
SSH_STRING_FREE(pubkey_s);
session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY;
@@ -645,16 +742,17 @@ int ssh_userauth_publickey(ssh_session session,
return SSH_AUTH_ERROR;
}
switch(session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
case SSH_PENDING_CALL_AUTH_PUBKEY:
goto pending;
default:
ssh_set_error(session,
SSH_FATAL,
"Bad call during pending SSH call in ssh_userauth_try_publickey");
return SSH_AUTH_ERROR;
switch (session->pending_call_state) {
case SSH_PENDING_CALL_NONE:
break;
case SSH_PENDING_CALL_AUTH_PUBKEY:
goto pending;
default:
ssh_set_error(
session,
SSH_FATAL,
"Bad call during pending SSH call in ssh_userauth_try_publickey");
return SSH_AUTH_ERROR;
}
/* Note, that this is intentionally before checking the signature type
@@ -674,13 +772,15 @@ int ssh_userauth_publickey(ssh_session session,
/* Check if the given public key algorithm is allowed */
sig_type_c = ssh_key_get_signature_algorithm(session, key_type);
if (sig_type_c == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Invalid key type (unknown)");
return SSH_AUTH_DENIED;
}
rc = ssh_key_algorithm_allowed(session, sig_type_c);
if (!rc) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"The key algorithm '%s' is not allowed to be used by"
" PUBLICKEY_ACCEPTED_TYPES configuration option",
sig_type_c);
@@ -688,9 +788,12 @@ int ssh_userauth_publickey(ssh_session session,
}
allowed = ssh_key_size_allowed(session, privkey);
if (!allowed) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"The '%s' key type of size %d is not allowed by "
"RSA_MIN_SIZE", sig_type_c, ssh_key_size(privkey));
"RSA_MIN_SIZE",
sig_type_c,
ssh_key_size(privkey));
return SSH_AUTH_DENIED;
}
@@ -701,16 +804,7 @@ int ssh_userauth_publickey(ssh_session session,
}
SSH_LOG(SSH_LOG_TRACE, "Sending signature type %s", sig_type_c);
/* request */
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
SSH2_MSG_USERAUTH_REQUEST,
username ? username : session->opts.username,
"ssh-connection",
"publickey",
1, /* private key */
sig_type_c, /* algo */
str /* public key or cert */
);
rc = build_pubkey_auth_request(session, username, 1, sig_type_c, str);
if (rc < 0) {
goto fail;
}
@@ -798,14 +892,16 @@ static int ssh_userauth_agent_publickey(ssh_session session,
/* Check if the given public key algorithm is allowed */
sig_type_c = ssh_key_get_signature_algorithm(session, pubkey->type);
if (sig_type_c == NULL) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Invalid key type (unknown)");
SSH_STRING_FREE(pubkey_s);
return SSH_AUTH_DENIED;
}
rc = ssh_key_algorithm_allowed(session, sig_type_c);
if (!rc) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"The key algorithm '%s' is not allowed to be used by"
" PUBLICKEY_ACCEPTED_TYPES configuration option",
sig_type_c);
@@ -814,27 +910,21 @@ static int ssh_userauth_agent_publickey(ssh_session session,
}
allowed = ssh_key_size_allowed(session, pubkey);
if (!allowed) {
ssh_set_error(session, SSH_REQUEST_DENIED,
ssh_set_error(session,
SSH_REQUEST_DENIED,
"The '%s' key type of size %d is not allowed by "
"RSA_MIN_SIZE", sig_type_c, ssh_key_size(pubkey));
"RSA_MIN_SIZE",
sig_type_c,
ssh_key_size(pubkey));
SSH_STRING_FREE(pubkey_s);
return SSH_AUTH_DENIED;
}
/* request */
rc = ssh_buffer_pack(session->out_buffer, "bsssbsS",
SSH2_MSG_USERAUTH_REQUEST,
username ? username : session->opts.username,
"ssh-connection",
"publickey",
1, /* private key */
sig_type_c, /* algo */
pubkey_s /* public key */
);
SSH_STRING_FREE(pubkey_s);
rc = build_pubkey_auth_request(session, username, 1, sig_type_c, pubkey_s);
if (rc < 0) {
goto fail;
}
SSH_STRING_FREE(pubkey_s);
/* sign the buffer with the private key */
sig_blob = ssh_pki_do_sign_agent(session, session->out_buffer, pubkey);
@@ -892,7 +982,7 @@ void ssh_agent_state_free(void *data)
if (state) {
SSH_STRING_FREE_CHAR(state->comment);
ssh_key_free(state->pubkey);
free (state);
free(state);
}
}
@@ -918,8 +1008,7 @@ void ssh_agent_state_free(void *data)
* authentication. The username should only be set with ssh_options_set() only
* before you connect to the server.
*/
int ssh_userauth_agent(ssh_session session,
const char *username)
int ssh_userauth_agent(ssh_session session, const char *username)
{
int rc = SSH_AUTH_ERROR;
struct ssh_agent_state_struct *state = NULL;
@@ -938,12 +1027,11 @@ int ssh_userauth_agent(ssh_session session,
}
if (!session->agent_state) {
session->agent_state = malloc(sizeof(struct ssh_agent_state_struct));
session->agent_state = calloc(1, sizeof(struct ssh_agent_state_struct));
if (!session->agent_state) {
ssh_set_error_oom(session);
return SSH_AUTH_ERROR;
}
ZERO_STRUCTP(session->agent_state);
session->agent_state->state = SSH_AGENT_STATE_NONE;
}

View File

@@ -186,7 +186,7 @@ error:
static int to_block4(unsigned long *block, const char *source, int num)
{
const char *ptr = NULL;
unsigned int i;
size_t i;
*block = 0;
if (num < 1) {

View File

@@ -27,40 +27,52 @@
#include "libssh/bignum.h"
#include "libssh/string.h"
ssh_string ssh_make_bignum_string(bignum num) {
ssh_string ptr = NULL;
size_t pad = 0;
size_t len = bignum_num_bytes(num);
size_t bits = bignum_num_bits(num);
static ssh_string make_bignum_string(bignum num, size_t pad_to_len)
{
ssh_string ptr = NULL;
size_t pad = 0;
size_t len = bignum_num_bytes(num);
size_t bits = bignum_num_bits(num);
if (len == 0) {
return NULL;
}
/* If the first bit is set we have a negative number */
if (!(bits % 8) && bignum_is_bit_set(num, bits - 1)) {
pad++;
}
if (pad_to_len == 0) {
/* If the first bit is set we have a negative number */
if (!(bits % 8) && bignum_is_bit_set(num, bits - 1)) {
pad++;
}
} else {
if (len > pad_to_len) {
return NULL;
}
pad = pad_to_len - len;
}
#ifdef DEBUG_CRYPTO
SSH_LOG(SSH_LOG_TRACE,
"%zu bits, %zu bytes, %zu padding",
bits, len, pad);
SSH_LOG(SSH_LOG_TRACE, "%zu bits, %zu bytes, %zu padding", bits, len, pad);
#endif /* DEBUG_CRYPTO */
ptr = ssh_string_new(len + pad);
if (ptr == NULL) {
return NULL;
}
ptr = ssh_string_new(len + pad);
if (ptr == NULL) {
return NULL;
}
/* We have a negative number so we need a leading zero */
if (pad) {
ptr->data[0] = 0;
}
/* We have a negative number so we need a leading zero */
if (pad) {
memset(ptr->data, 0, pad);
}
bignum_bn2bin(num, len, ptr->data + pad);
bignum_bn2bin(num, len, ptr->data + pad);
return ptr;
return ptr;
}
ssh_string ssh_make_bignum_string(bignum num)
{
return make_bignum_string(num, 0);
}
ssh_string ssh_make_padded_bignum_string(bignum num, size_t pad_len)
{
return make_bignum_string(num, pad_len);
}
bignum ssh_make_string_bn(ssh_string string)
@@ -71,10 +83,11 @@ bignum ssh_make_string_bn(ssh_string string)
#ifdef DEBUG_CRYPTO
SSH_LOG(SSH_LOG_TRACE,
"Importing a %zu bits, %zu bytes object ...",
len * 8, len);
len * 8,
len);
#endif /* DEBUG_CRYPTO */
bignum_bin2bn(string->data, len, &bn);
bignum_bin2bn(string->data, (int)len, &bn);
return bn;
}
@@ -86,7 +99,9 @@ void ssh_print_bignum(const char *name, const_bignum num)
if (num != NULL) {
bignum_bn2hex(num, &hex);
}
SSH_LOG(SSH_LOG_DEBUG, "%s value: %s", name,
SSH_LOG(SSH_LOG_DEBUG,
"%s value: %s",
name,
(hex == NULL) ? "(null)" : (char *)hex);
ssh_crypto_free(hex);
}

View File

@@ -505,7 +505,10 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
ssh_set_error_oom(sshbind);
return SSH_ERROR;
}
ssh_socket_set_fd(session->socket, fd);
rc = ssh_socket_set_fd(session->socket, fd);
if (rc != SSH_OK) {
return rc;
}
handle = ssh_socket_get_poll_handle(session->socket);
if (handle == NULL) {
ssh_set_error_oom(sshbind);

View File

@@ -669,7 +669,8 @@ int ssh_bind_config_parse_string(ssh_bind bind, const char *input)
{
char line[MAX_LINE_SIZE] = {0};
const char *c = input, *line_start = input;
unsigned int line_num = 0, line_len;
unsigned int line_num = 0;
size_t line_len;
uint32_t parser_flags;
int rv;
@@ -698,8 +699,10 @@ int ssh_bind_config_parse_string(ssh_bind bind, const char *input)
}
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);
SSH_LOG(SSH_LOG_WARN,
"Line %u too long: %zu characters",
line_num,
line_len);
return SSH_ERROR;
}
memcpy(line, line_start, line_len);

View File

@@ -407,20 +407,26 @@ void *ssh_buffer_allocate(struct ssh_buffer_struct *buffer, uint32_t len)
*
* @return 0 on success, < 0 on error.
*/
int ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
struct ssh_string_struct *string) {
uint32_t len = 0;
int
ssh_buffer_add_ssh_string(struct ssh_buffer_struct *buffer,
struct ssh_string_struct *string)
{
size_t len;
int rc;
if (string == NULL) {
return -1;
}
if (string == NULL) {
return -1;
}
len = ssh_string_len(string);
if (ssh_buffer_add_data(buffer, string, len + sizeof(uint32_t)) < 0) {
return -1;
}
len = ssh_string_len(string) + sizeof(uint32_t);
/* this can't overflow the uint32_t as the
* STRING_SIZE_MAX is (UINT32_MAX >> 8) + 1 */
rc = ssh_buffer_add_data(buffer, string, (uint32_t)len);
if (rc < 0) {
return -1;
}
return 0;
return 0;
}
/**
@@ -823,6 +829,7 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
const char *p = NULL;
ssh_string string = NULL;
char *cstring = NULL;
bignum b = NULL;
size_t needed_size = 0;
size_t len;
size_t count;
@@ -867,13 +874,18 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer,
va_arg(ap, void *);
count++; /* increase argument count */
break;
case 'F':
case 'B':
va_arg(ap, bignum);
/*
* Use a fixed size for a bignum
* (they should normally be around 32)
*/
needed_size += 64;
b = va_arg(ap, bignum);
if (*p == 'F') {
/* For padded bignum, we know the exact length */
len = va_arg(ap, size_t);
count++; /* increase argument count */
needed_size += sizeof(uint32_t) + len;
} else {
/* The bignum bytes + 1 for possible padding */
needed_size += sizeof(uint32_t) + bignum_num_bytes(b) + 1;
}
break;
case 't':
cstring = va_arg(ap, char *);
@@ -979,24 +991,40 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
case 's':
cstring = va_arg(ap, char *);
len = strlen(cstring);
rc = ssh_buffer_add_u32(buffer, htonl(len));
if (len > UINT32_MAX) {
rc = SSH_ERROR;
break;
}
o.dword = (uint32_t)len;
rc = ssh_buffer_add_u32(buffer, htonl(o.dword));
if (rc == SSH_OK){
rc = ssh_buffer_add_data(buffer, cstring, len);
rc = ssh_buffer_add_data(buffer, cstring, o.dword);
}
cstring = NULL;
break;
case 'P':
len = va_arg(ap, size_t);
if (len > UINT32_MAX) {
rc = SSH_ERROR;
break;
}
o.data = va_arg(ap, void *);
count++; /* increase argument count */
rc = ssh_buffer_add_data(buffer, o.data, len);
rc = ssh_buffer_add_data(buffer, o.data, (uint32_t)len);
o.data = NULL;
break;
case 'F':
case 'B':
b = va_arg(ap, bignum);
o.string = ssh_make_bignum_string(b);
if (*p == 'F') {
len = va_arg(ap, size_t);
count++; /* increase argument count */
o.string = ssh_make_padded_bignum_string(b, len);
} else {
o.string = ssh_make_bignum_string(b);
}
if(o.string == NULL){
rc = SSH_ERROR;
break;
@@ -1007,7 +1035,11 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
case 't':
cstring = va_arg(ap, char *);
len = strlen(cstring);
rc = ssh_buffer_add_data(buffer, cstring, len);
if (len > UINT32_MAX) {
rc = SSH_ERROR;
break;
}
rc = ssh_buffer_add_data(buffer, cstring, (uint32_t)len);
cstring = NULL;
break;
default:
@@ -1048,6 +1080,8 @@ ssh_buffer_pack_va(struct ssh_buffer_struct *buffer,
* 'P': size_t, void * (len of data, pointer to data)
* only pushes data.
* 'B': bignum (pushed as SSH string)
* 'F': bignum, size_t (bignum, padded to fixed length,
* pushed as SSH string)
* @returns SSH_OK on success
* SSH_ERROR on error
* @warning when using 'P' with a constant size (e.g. 8), do not
@@ -1187,28 +1221,28 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
if (rlen != 4){
break;
}
len = ntohl(u32len);
if (len > max_len - 1) {
u32len = ntohl(u32len);
if (u32len > max_len - 1) {
break;
}
rc = ssh_buffer_validate_length(buffer, len);
rc = ssh_buffer_validate_length(buffer, u32len);
if (rc != SSH_OK) {
break;
}
*o.cstring = malloc(len + 1);
*o.cstring = malloc(u32len + 1);
if (*o.cstring == NULL){
rc = SSH_ERROR;
break;
}
rlen = ssh_buffer_get_data(buffer, *o.cstring, len);
if (rlen != len){
rlen = ssh_buffer_get_data(buffer, *o.cstring, u32len);
if (rlen != u32len) {
SAFE_FREE(*o.cstring);
rc = SSH_ERROR;
break;
}
(*o.cstring)[len] = '\0';
(*o.cstring)[u32len] = '\0';
o.cstring = NULL;
rc = SSH_OK;
break;
@@ -1233,7 +1267,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer,
rc = SSH_ERROR;
break;
}
rlen = ssh_buffer_get_data(buffer, *o.data, len);
rlen = ssh_buffer_get_data(buffer, *o.data, (uint32_t)len);
if (rlen != len){
SAFE_FREE(*o.data);
rc = SSH_ERROR;

View File

@@ -24,11 +24,11 @@
#include "config.h"
#include "libssh/callbacks.h"
#include "libssh/session.h"
#include "libssh/misc.h"
#include "libssh/session.h"
#define is_callback_valid(session, cb) \
(cb->size <= 0 || cb->size > 1024 * sizeof(void *))
(cb->size > 0 || cb->size <= 1024 * sizeof(void *))
/* LEGACY */
static void ssh_legacy_log_callback(int priority,
@@ -45,8 +45,7 @@ static void ssh_legacy_log_callback(int priority,
log_fn(session, priority, buffer, log_data);
}
void
_ssh_remove_legacy_log_cb(void)
void _ssh_remove_legacy_log_cb(void)
{
if (ssh_get_log_callback() == ssh_legacy_log_callback) {
_ssh_reset_log_cb();
@@ -54,26 +53,27 @@ _ssh_remove_legacy_log_cb(void)
}
}
int ssh_set_callbacks(ssh_session session, ssh_callbacks cb) {
if (session == NULL || cb == NULL) {
return SSH_ERROR;
}
int ssh_set_callbacks(ssh_session session, ssh_callbacks cb)
{
if (session == NULL || cb == NULL) {
return SSH_ERROR;
}
if (is_callback_valid(session, cb)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
};
session->common.callbacks = cb;
if (!is_callback_valid(session, cb)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
};
session->common.callbacks = cb;
/* LEGACY */
if (ssh_get_log_callback() == NULL && cb->log_function) {
ssh_set_log_callback(ssh_legacy_log_callback);
ssh_set_log_userdata(session);
}
/* LEGACY */
if (ssh_get_log_callback() == NULL && cb->log_function) {
ssh_set_log_callback(ssh_legacy_log_callback);
ssh_set_log_userdata(session);
}
return 0;
return 0;
}
static int ssh_add_set_channel_callbacks(ssh_channel channel,
@@ -84,11 +84,11 @@ static int ssh_add_set_channel_callbacks(ssh_channel channel,
int rc;
if (channel == NULL || cb == NULL) {
return SSH_ERROR;
return SSH_ERROR;
}
session = channel->session;
if (is_callback_valid(session, cb)) {
if (!is_callback_valid(session, cb)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid callback passed in (badly initialized)");
@@ -96,7 +96,7 @@ static int ssh_add_set_channel_callbacks(ssh_channel channel,
};
if (channel->callbacks == NULL) {
channel->callbacks = ssh_list_new();
if (channel->callbacks == NULL){
if (channel->callbacks == NULL) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
@@ -124,12 +124,12 @@ int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
{
struct ssh_iterator *it = NULL;
if (channel == NULL || channel->callbacks == NULL){
if (channel == NULL || channel->callbacks == NULL) {
return SSH_ERROR;
}
it = ssh_list_find(channel->callbacks, cb);
if (it == NULL){
if (it == NULL) {
return SSH_ERROR;
}
@@ -138,19 +138,19 @@ int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb)
return SSH_OK;
}
int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb)
{
if (session == NULL || cb == NULL) {
return SSH_ERROR;
}
int ssh_set_server_callbacks(ssh_session session, ssh_server_callbacks cb){
if (session == NULL || cb == NULL) {
return SSH_ERROR;
}
if (is_callback_valid(session, cb)) {
if (!is_callback_valid(session, cb)) {
ssh_set_error(session,
SSH_FATAL,
"Invalid callback passed in (badly initialized)");
return SSH_ERROR;
};
session->server_callbacks = cb;
session->server_callbacks = cb;
return 0;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -226,7 +226,7 @@ int ssh_send_banner(ssh_session session, int server)
terminator);
}
rc = ssh_socket_write(session->socket, buffer, strlen(buffer));
rc = ssh_socket_write(session->socket, buffer, (uint32_t)strlen(buffer));
if (rc == SSH_ERROR) {
goto end;
}
@@ -235,8 +235,8 @@ int ssh_send_banner(ssh_session session, int server)
ssh_pcap_context_write(session->pcap_ctx,
SSH_PCAP_DIR_OUT,
buffer,
strlen(buffer),
strlen(buffer));
(uint32_t)strlen(buffer),
(uint32_t)strlen(buffer));
}
#endif
@@ -254,45 +254,52 @@ end:
*/
int dh_handshake(ssh_session session)
{
int rc = SSH_AGAIN;
int rc = SSH_AGAIN;
SSH_LOG(SSH_LOG_TRACE, "dh_handshake_state = %d, kex_type = %d",
session->dh_handshake_state, session->next_crypto->kex_type);
SSH_LOG(SSH_LOG_TRACE,
"dh_handshake_state = %d, kex_type = %d",
session->dh_handshake_state,
session->next_crypto->kex_type);
switch (session->dh_handshake_state) {
switch (session->dh_handshake_state) {
case DH_STATE_INIT:
switch(session->next_crypto->kex_type){
switch (session->next_crypto->kex_type) {
case SSH_KEX_DH_GROUP1_SHA1:
case SSH_KEX_DH_GROUP14_SHA1:
case SSH_KEX_DH_GROUP14_SHA256:
case SSH_KEX_DH_GROUP16_SHA512:
case SSH_KEX_DH_GROUP18_SHA512:
rc = ssh_client_dh_init(session);
break;
rc = ssh_client_dh_init(session);
break;
#ifdef WITH_GEX
case SSH_KEX_DH_GEX_SHA1:
case SSH_KEX_DH_GEX_SHA256:
rc = ssh_client_dhgex_init(session);
break;
rc = ssh_client_dhgex_init(session);
break;
#endif /* WITH_GEX */
#ifdef HAVE_ECDH
case SSH_KEX_ECDH_SHA2_NISTP256:
case SSH_KEX_ECDH_SHA2_NISTP384:
case SSH_KEX_ECDH_SHA2_NISTP521:
rc = ssh_client_ecdh_init(session);
break;
rc = ssh_client_ecdh_init(session);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
rc = ssh_client_curve25519_init(session);
break;
rc = ssh_client_curve25519_init(session);
break;
#endif
#ifdef HAVE_SNTRUP761
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
rc = ssh_client_sntrup761x25519_init(session);
break;
#endif
default:
rc = SSH_ERROR;
}
rc = SSH_ERROR;
}
break;
break;
case DH_STATE_INIT_SENT:
/* wait until ssh_packet_dh_reply is called */
break;
@@ -300,15 +307,17 @@ int dh_handshake(ssh_session session)
/* wait until ssh_packet_newkeys is called */
break;
case DH_STATE_FINISHED:
return SSH_OK;
return SSH_OK;
default:
ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d",
session->dh_handshake_state);
ssh_set_error(session,
SSH_FATAL,
"Invalid state in dh_handshake(): %d",
session->dh_handshake_state);
return SSH_ERROR;
}
return SSH_ERROR;
}
return rc;
return rc;
}
static int ssh_service_request_termination(void *s)
@@ -593,8 +602,7 @@ int ssh_connect(ssh_session session)
if (session->opts.fd != SSH_INVALID_SOCKET) {
session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED;
ssh_socket_set_fd(session->socket, session->opts.fd);
ret = SSH_OK;
ret = ssh_socket_set_fd(session->socket, session->opts.fd);
#ifndef _WIN32
#ifdef HAVE_PTHREAD
} else if (ssh_libssh_proxy_jumps() &&

View File

@@ -1451,6 +1451,32 @@ ssh_config_parse_line(ssh_session session,
return 0;
}
/* @brief Parse configuration from a file pointer
*
* @params[in] session The ssh session
* @params[in] fp A valid file pointer
* @params[in] global Whether the config is global or not
*
* @returns 0 on successful parsing the configuration file, -1 on error
*/
int ssh_config_parse(ssh_session session, FILE *fp, bool global)
{
char line[MAX_LINE_SIZE] = {0};
unsigned int count = 0;
int parsing, rv;
parsing = 1;
while (fgets(line, sizeof(line), fp)) {
count++;
rv = ssh_config_parse_line(session, line, count, &parsing, 0, global);
if (rv < 0) {
return -1;
}
}
return 0;
}
/* @brief Parse configuration file and set the options to the given session
*
* @params[in] session The ssh session
@@ -1460,36 +1486,32 @@ ssh_config_parse_line(ssh_session session,
*/
int ssh_config_parse_file(ssh_session session, const char *filename)
{
char line[MAX_LINE_SIZE] = {0};
unsigned int count = 0;
FILE *f = NULL;
int parsing, rv;
FILE *fp = NULL;
int rv;
bool global = 0;
f = fopen(filename, "r");
if (f == NULL) {
fp = fopen(filename, "r");
if (fp == NULL) {
return 0;
}
rv = strcmp(filename, GLOBAL_CLIENT_CONFIG);
#ifdef USR_GLOBAL_CLIENT_CONFIG
if (rv != 0) {
rv = strcmp(filename, USR_GLOBAL_CLIENT_CONFIG);
}
#endif
if (rv == 0) {
global = true;
}
SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
parsing = 1;
while (fgets(line, sizeof(line), f)) {
count++;
rv = ssh_config_parse_line(session, line, count, &parsing, 0, global);
if (rv < 0) {
fclose(f);
return -1;
}
}
rv = ssh_config_parse(session, fp, global);
fclose(f);
return 0;
fclose(fp);
return rv;
}
/* @brief Parse configuration string and set the options to the given session
@@ -1504,7 +1526,8 @@ 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;
unsigned int line_num = 0;
size_t line_len;
int parsing, rv;
SSH_LOG(SSH_LOG_DEBUG, "Reading configuration data from string:");
@@ -1526,8 +1549,10 @@ int ssh_config_parse_string(ssh_session session, const char *input)
}
line_len = c - line_start;
if (line_len > MAX_LINE_SIZE - 1) {
SSH_LOG(SSH_LOG_TRACE, "Line %u too long: %u characters",
line_num, line_len);
SSH_LOG(SSH_LOG_TRACE,
"Line %u too long: %zu characters",
line_num,
line_len);
return SSH_ERROR;
}
memcpy(line, line_start, line_len);

View File

@@ -209,7 +209,8 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
bind_itr != NULL;
bind_itr = bind_itr->ai_next)
{
if (bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen) < 0) {
rc = bind(s, bind_itr->ai_addr, bind_itr->ai_addrlen);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Binding local address: %s",
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));

View File

@@ -264,17 +264,17 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
}
connector->in_available = 1; /* Don't poll on it */
return;
} else if (r> 0) {
} else if (r > 0) {
/* loop around ssh_channel_write in case our window reduced due to a race */
while (total != r){
if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
w = ssh_channel_write(connector->out_channel,
buffer + total,
r - total);
(uint32_t)(r - total));
} else {
w = ssh_channel_write_stderr(connector->out_channel,
buffer + total,
r - total);
(uint32_t)(r - total));
}
if (w == SSH_ERROR) {
return;
@@ -294,7 +294,7 @@ static void ssh_connector_fd_in_cb(ssh_connector connector)
while (total < r) {
w = ssh_connector_fd_write(connector,
buffer + total,
r - total);
(uint32_t)(r - total));
if (w < 0) {
ssh_connector_except(connector, connector->out_fd);
return;
@@ -340,8 +340,9 @@ ssh_connector_fd_out_cb(ssh_connector connector)
} else if (r > 0) {
/* loop around write in case the write blocks even for CHUNKSIZE bytes */
while (total != r) {
w = ssh_connector_fd_write(connector, buffer + total,
r - total);
w = ssh_connector_fd_write(connector,
buffer + total,
(uint32_t)(r - total));
if (w < 0) {
ssh_connector_except(connector, connector->out_fd);
return;
@@ -476,9 +477,11 @@ static int ssh_connector_channel_data_cb(ssh_session session,
ssh_connector_except_channel(connector, connector->out_channel);
}
} else if (connector->out_fd != SSH_INVALID_SOCKET) {
w = ssh_connector_fd_write(connector, data, len);
if (w < 0)
ssize_t ws = ssh_connector_fd_write(connector, data, len);
if (ws < 0) {
ssh_connector_except(connector, connector->out_fd);
}
w = (int)ws;
} else {
ssh_set_error(session, SSH_FATAL, "output socket or channel closed");
return SSH_ERROR;

View File

@@ -26,119 +26,43 @@
#include "libssh/curve25519.h"
#ifdef HAVE_CURVE25519
#ifdef WITH_NACL
#include "nacl/crypto_scalarmult_curve25519.h"
#endif
#include "libssh/ssh2.h"
#include "libssh/bignum.h"
#include "libssh/buffer.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/crypto.h"
#include "libssh/dh.h"
#include "libssh/pki.h"
#include "libssh/bignum.h"
#ifdef HAVE_LIBCRYPTO
#include <openssl/err.h>
#endif
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/ssh2.h"
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply);
static ssh_packet_callback dh_client_callbacks[] = {
ssh_packet_client_curve25519_reply
ssh_packet_client_curve25519_reply,
};
static struct ssh_packet_callbacks_struct ssh_curve25519_client_callbacks = {
.start = SSH2_MSG_KEX_ECDH_REPLY,
.n_callbacks = 1,
.callbacks = dh_client_callbacks,
.user = NULL
.user = NULL,
};
static int ssh_curve25519_init(ssh_session session)
int ssh_curve25519_create_k(ssh_session session, ssh_curve25519_pubkey k)
{
int rc;
#ifdef HAVE_LIBCRYPTO
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
size_t pkey_len = CURVE25519_PRIVKEY_SIZE;
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
if (pctx == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 context: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("Session server cookie",
session->next_crypto->server_kex.cookie,
16);
ssh_log_hexdump("Session client cookie",
session->next_crypto->client_kex.cookie,
16);
#endif
rc = EVP_PKEY_keygen_init(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 keygen: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_CTX_free(pctx);
return SSH_ERROR;
}
rc = EVP_PKEY_keygen(pctx, &pkey);
EVP_PKEY_CTX_free(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate X25519 keys: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
if (session->server) {
rc = EVP_PKEY_get_raw_public_key(pkey,
session->next_crypto->curve25519_server_pubkey,
&pubkey_len);
} else {
rc = EVP_PKEY_get_raw_public_key(pkey,
session->next_crypto->curve25519_client_pubkey,
&pubkey_len);
}
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get X25519 raw public key: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
return SSH_ERROR;
}
rc = EVP_PKEY_get_raw_private_key(pkey,
session->next_crypto->curve25519_privkey,
&pkey_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get X25519 raw private key: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
return SSH_ERROR;
}
EVP_PKEY_free(pkey);
#else
rc = ssh_get_random(session->next_crypto->curve25519_privkey,
CURVE25519_PRIVKEY_SIZE, 1);
if (rc != 1) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
if (session->server) {
crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey,
session->next_crypto->curve25519_privkey);
} else {
crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey,
session->next_crypto->curve25519_privkey);
}
#endif /* HAVE_LIBCRYPTO */
return SSH_OK;
rc = curve25519_do_create_k(session, k);
return rc;
}
/** @internal
@@ -180,193 +104,120 @@ void ssh_client_curve25519_remove_callbacks(ssh_session session)
static int ssh_curve25519_build_k(ssh_session session)
{
ssh_curve25519_pubkey k;
int rc;
#ifdef HAVE_LIBCRYPTO
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL, *pubkey = NULL;
size_t shared_key_len = sizeof(k);
int rc, ret = SSH_ERROR;
pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
session->next_crypto->curve25519_privkey,
CURVE25519_PRIVKEY_SIZE);
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create X25519 EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
rc = ssh_curve25519_create_k(session, k);
if (rc != SSH_OK) {
return rc;
}
pctx = EVP_PKEY_CTX_new(pkey, NULL);
if (pctx == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 context: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_PKEY_derive_init(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 key derivation: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
if (session->server) {
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
} else {
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
}
if (pubkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create X25519 public key EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_PKEY_derive_set_peer(pctx, pubkey);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to set peer X25519 public key: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_PKEY_derive(pctx, k, &shared_key_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to derive X25519 shared secret: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
ret = SSH_OK;
out:
EVP_PKEY_free(pkey);
EVP_PKEY_free(pubkey);
EVP_PKEY_CTX_free(pctx);
if (ret == SSH_ERROR) {
return ret;
}
#else
if (session->server) {
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_client_pubkey);
} else {
crypto_scalarmult(k, session->next_crypto->curve25519_privkey,
session->next_crypto->curve25519_server_pubkey);
}
#endif /* HAVE_LIBCRYPTO */
bignum_bin2bn(k, CURVE25519_PUBKEY_SIZE, &session->next_crypto->shared_secret);
bignum_bin2bn(k,
CURVE25519_PUBKEY_SIZE,
&session->next_crypto->shared_secret);
if (session->next_crypto->shared_secret == NULL) {
return SSH_ERROR;
}
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_log_hexdump("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
#endif
return 0;
return SSH_OK;
}
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
*/
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
ssh_string q_s_string = NULL;
ssh_string pubkey_blob = NULL;
ssh_string signature = NULL;
int rc;
(void)type;
(void)user;
static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply)
{
ssh_string q_s_string = NULL;
ssh_string pubkey_blob = NULL;
ssh_string signature = NULL;
int rc;
(void)type;
(void)user;
ssh_client_curve25519_remove_callbacks(session);
ssh_client_curve25519_remove_callbacks(session);
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
ssh_set_error(session,SSH_FATAL, "No public key in packet");
goto error;
}
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "No public key in packet");
goto error;
}
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
SSH_STRING_FREE(pubkey_blob);
if (rc != 0) {
ssh_set_error(session,
SSH_FATAL,
"Failed to import next public key");
goto error;
}
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
SSH_STRING_FREE(pubkey_blob);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL, "Failed to import next public key");
goto error;
}
q_s_string = ssh_buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_S ECC point in packet");
goto error;
}
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){
ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d",
(int)ssh_string_len(q_s_string));
SSH_STRING_FREE(q_s_string);
goto error;
}
memcpy(session->next_crypto->curve25519_server_pubkey, ssh_string_data(q_s_string), CURVE25519_PUBKEY_SIZE);
SSH_STRING_FREE(q_s_string);
q_s_string = ssh_buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session, SSH_FATAL, "No Q_S ECC point in packet");
goto error;
}
if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE) {
ssh_set_error(session,
SSH_FATAL,
"Incorrect size for server Curve25519 public key: %zu",
ssh_string_len(q_s_string));
SSH_STRING_FREE(q_s_string);
goto error;
}
memcpy(session->next_crypto->curve25519_server_pubkey,
ssh_string_data(q_s_string),
CURVE25519_PUBKEY_SIZE);
SSH_STRING_FREE(q_s_string);
signature = ssh_buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature=NULL; /* ownership changed */
/* TODO: verify signature now instead of waiting for NEWKEYS */
if (ssh_curve25519_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
signature = ssh_buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature = NULL; /* ownership changed */
/* TODO: verify signature now instead of waiting for NEWKEYS */
if (ssh_curve25519_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* Send the MSG_NEWKEYS */
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
/* Send the MSG_NEWKEYS */
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
return SSH_PACKET_USED;
return SSH_PACKET_USED;
error:
session->session_state=SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
session->session_state = SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
}
#ifdef WITH_SERVER
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init);
static ssh_packet_callback dh_server_callbacks[]= {
ssh_packet_server_curve25519_init
static ssh_packet_callback dh_server_callbacks[] = {
ssh_packet_server_curve25519_init,
};
static struct ssh_packet_callbacks_struct ssh_curve25519_server_callbacks = {
.start = SSH2_MSG_KEX_ECDH_INIT,
.n_callbacks = 1,
.callbacks = dh_server_callbacks,
.user = NULL
.user = NULL,
};
/** @internal
* @brief sets up the curve25519-sha256@libssh.org kex callbacks
*/
void ssh_server_curve25519_init(ssh_session session){
void ssh_server_curve25519_init(ssh_session session)
{
/* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_curve25519_server_callbacks);
}
@@ -374,7 +225,8 @@ void ssh_server_curve25519_init(ssh_session session){
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init)
{
/* ECDH keys */
ssh_string q_c_string = NULL;
ssh_string q_s_string = NULL;
@@ -393,10 +245,10 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
/* Extract the client pubkey from the init packet */
q_c_string = ssh_buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet");
ssh_set_error(session, SSH_FATAL, "No Q_C ECC point in packet");
goto error;
}
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){
if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE) {
ssh_set_error(session,
SSH_FATAL,
"Incorrect size for server Curve25519 public key: %zu",
@@ -405,7 +257,8 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
}
memcpy(session->next_crypto->curve25519_client_pubkey,
ssh_string_data(q_c_string), CURVE25519_PUBKEY_SIZE);
ssh_string_data(q_c_string),
CURVE25519_PUBKEY_SIZE);
SSH_STRING_FREE(q_c_string);
/* Build server's key pair */
@@ -447,8 +300,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
}
/* add host's public key */
rc = ssh_buffer_add_ssh_string(session->out_buffer,
server_pubkey_blob);
rc = ssh_buffer_add_ssh_string(session->out_buffer, server_pubkey_blob);
SSH_STRING_FREE(server_pubkey_blob);
if (rc < 0) {
ssh_set_error_oom(session);
@@ -509,7 +361,7 @@ error:
SSH_STRING_FREE(q_c_string);
SSH_STRING_FREE(q_s_string);
ssh_buffer_reinit(session->out_buffer);
session->session_state=SSH_SESSION_STATE_ERROR;
session->session_state = SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
}

158
src/curve25519_crypto.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* curve25519_crypto.c - Curve25519 ECDH functions for key exchange (OpenSSL)
*
* This file is part of the SSH Library
*
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/curve25519.h"
#include "libssh/crypto.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include <openssl/err.h>
#include <openssl/evp.h>
int ssh_curve25519_init(ssh_session session)
{
ssh_curve25519_pubkey *pubkey_loc = NULL;
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL;
size_t pubkey_len = CURVE25519_PUBKEY_SIZE;
int rc;
if (session->server) {
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
} else {
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
}
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
if (pctx == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 context: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
rc = EVP_PKEY_keygen_init(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 keygen: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_CTX_free(pctx);
return SSH_ERROR;
}
rc = EVP_PKEY_keygen(pctx, &pkey);
EVP_PKEY_CTX_free(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate X25519 keys: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
rc = EVP_PKEY_get_raw_public_key(pkey, *pubkey_loc, &pubkey_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to get X25519 raw public key: %s",
ERR_error_string(ERR_get_error(), NULL));
EVP_PKEY_free(pkey);
return SSH_ERROR;
}
session->next_crypto->curve25519_privkey = pkey;
pkey = NULL;
return SSH_OK;
}
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
{
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
int rc, ret = SSH_ERROR;
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL, *pubkey = NULL;
size_t shared_key_len = CURVE25519_PUBKEY_SIZE;
if (session->server) {
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
} else {
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
}
pkey = session->next_crypto->curve25519_privkey;
if (pkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create X25519 EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
return SSH_ERROR;
}
pctx = EVP_PKEY_CTX_new(pkey, NULL);
if (pctx == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 context: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_PKEY_derive_init(pctx);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to initialize X25519 key derivation: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
pubkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519,
NULL,
*peer_pubkey_loc,
CURVE25519_PUBKEY_SIZE);
if (pubkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create X25519 public key EVP_PKEY: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_PKEY_derive_set_peer(pctx, pubkey);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to set peer X25519 public key: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
rc = EVP_PKEY_derive(pctx, k, &shared_key_len);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to derive X25519 shared secret: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
ret = SSH_OK;
out:
EVP_PKEY_free(pubkey);
EVP_PKEY_CTX_free(pctx);
return ret;
}

73
src/curve25519_fallback.c Normal file
View File

@@ -0,0 +1,73 @@
/*
* curve25519_fallback.c - Curve25519 ECDH functions for key exchange
*
* This file is part of the SSH Library
*
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/curve25519.h"
#include "libssh/crypto.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#ifdef WITH_NACL
#include "nacl/crypto_scalarmult_curve25519.h"
#endif
int ssh_curve25519_init(ssh_session session)
{
ssh_curve25519_pubkey *pubkey_loc = NULL;
int rc;
if (session->server) {
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
} else {
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
}
rc = ssh_get_random(session->next_crypto->curve25519_privkey,
CURVE25519_PRIVKEY_SIZE,
1);
if (rc != 1) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
crypto_scalarmult_base(*pubkey_loc,
session->next_crypto->curve25519_privkey);
return SSH_OK;
}
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
{
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
if (session->server) {
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
} else {
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
}
crypto_scalarmult(k,
session->next_crypto->curve25519_privkey,
*peer_pubkey_loc);
return SSH_OK;
}

199
src/curve25519_gcrypt.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* curve25519_gcrypt.c - Curve25519 ECDH functions for key exchange (Gcrypt)
*
* This file is part of the SSH Library
*
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.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, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/curve25519.h"
#include "libssh/buffer.h"
#include "libssh/crypto.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include <gcrypt.h>
int ssh_curve25519_init(ssh_session session)
{
ssh_curve25519_pubkey *pubkey_loc = NULL;
gcry_error_t gcry_err;
gcry_sexp_t param = NULL, keypair_sexp = NULL;
ssh_string pubkey = NULL;
const char *pubkey_data = NULL;
int ret = SSH_ERROR;
if (session->server) {
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
} else {
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
}
gcry_err =
gcry_sexp_build(&param, NULL, "(genkey (ecdh (curve Curve25519)))");
if (gcry_err != GPG_ERR_NO_ERROR) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create keypair sexp: %s",
gcry_strerror(gcry_err));
goto out;
}
gcry_err = gcry_pk_genkey(&keypair_sexp, param);
if (gcry_err != GPG_ERR_NO_ERROR) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate keypair: %s",
gcry_strerror(gcry_err));
goto out;
}
/* Extract the public key */
pubkey = ssh_sexp_extract_mpi(keypair_sexp,
"q",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (pubkey == NULL) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to extract public key: %s",
gcry_strerror(gcry_err));
goto out;
}
/* Store the public key in the session */
/* The first byte should be 0x40 indicating that the point is compressed, so
* we skip storing it */
pubkey_data = (char *)ssh_string_data(pubkey);
if (ssh_string_len(pubkey) != CURVE25519_PUBKEY_SIZE + 1 ||
pubkey_data[0] != 0x40) {
SSH_LOG(SSH_LOG_TRACE,
"Invalid public key with length: %zu",
ssh_string_len(pubkey));
goto out;
}
memcpy(*pubkey_loc, pubkey_data + 1, CURVE25519_PUBKEY_SIZE);
/* Store the private key */
session->next_crypto->curve25519_privkey = keypair_sexp;
keypair_sexp = NULL;
ret = SSH_OK;
out:
ssh_string_burn(pubkey);
SSH_STRING_FREE(pubkey);
gcry_sexp_release(param);
gcry_sexp_release(keypair_sexp);
return ret;
}
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
{
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
gcry_error_t gcry_err;
gcry_sexp_t pubkey_sexp = NULL, privkey_data_sexp = NULL,
result_sexp = NULL;
ssh_string shared_secret = NULL, privkey = NULL;
char *shared_secret_data = NULL;
int ret = SSH_ERROR;
if (session->server) {
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
} else {
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
}
gcry_err = gcry_sexp_build(
&pubkey_sexp,
NULL,
"(key-data(public-key (ecdh (curve Curve25519) (q %b))))",
CURVE25519_PUBKEY_SIZE,
*peer_pubkey_loc);
if (gcry_err != GPG_ERR_NO_ERROR) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create peer public key sexp: %s",
gcry_strerror(gcry_err));
goto out;
}
privkey = ssh_sexp_extract_mpi(session->next_crypto->curve25519_privkey,
"d",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (privkey == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Failed to extract private key");
goto out;
}
gcry_err = gcry_sexp_build(&privkey_data_sexp,
NULL,
"(data(flags raw)(value %b))",
ssh_string_len(privkey),
ssh_string_data(privkey));
if (gcry_err != GPG_ERR_NO_ERROR) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to create private key sexp: %s",
gcry_strerror(gcry_err));
goto out;
}
gcry_err = gcry_pk_encrypt(&result_sexp, privkey_data_sexp, pubkey_sexp);
if (gcry_err != GPG_ERR_NO_ERROR) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to compute shared secret: %s",
gcry_strerror(gcry_err));
goto out;
}
shared_secret = ssh_sexp_extract_mpi(result_sexp,
"s",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_USG);
if (shared_secret == NULL) {
SSH_LOG(SSH_LOG_TRACE, "Failed to extract shared secret");
goto out;
}
/* Copy the shared secret to the output buffer */
/* The first byte should be 0x40 indicating that it is a compressed point,
* so we skip it */
shared_secret_data = (char *)ssh_string_data(shared_secret);
if (ssh_string_len(shared_secret) != CURVE25519_PUBKEY_SIZE + 1 ||
shared_secret_data[0] != 0x40) {
SSH_LOG(SSH_LOG_TRACE,
"Invalid shared secret with length: %zu",
ssh_string_len(shared_secret));
goto out;
}
memcpy(k, shared_secret_data + 1, CURVE25519_PUBKEY_SIZE);
ret = SSH_OK;
gcry_sexp_release(session->next_crypto->curve25519_privkey);
session->next_crypto->curve25519_privkey = NULL;
out:
ssh_string_burn(shared_secret);
SSH_STRING_FREE(shared_secret);
ssh_string_burn(privkey);
SSH_STRING_FREE(privkey);
gcry_sexp_release(privkey_data_sexp);
gcry_sexp_release(pubkey_sexp);
gcry_sexp_release(result_sexp);
return ret;
}

189
src/curve25519_mbedcrypto.c Normal file
View File

@@ -0,0 +1,189 @@
/*
* curve25519_mbedcrypto.c - Curve25519 ECDH functions for key exchange
* (MbedTLS)
*
* This file is part of the SSH Library
*
* Copyright (c) 2013-2023 by Aris Adamantiadis <aris@badcode.be>
* Copyright (c) 2025 Praneeth Sarode <praneethsarode@gmail.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, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/curve25519.h"
#include "libssh/crypto.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "mbedcrypto-compat.h"
#include <mbedtls/ecdh.h>
#include <mbedtls/error.h>
int ssh_curve25519_init(ssh_session session)
{
ssh_curve25519_pubkey *pubkey_loc = NULL;
mbedtls_ecdh_context ecdh_ctx;
mbedtls_ecdh_params *ecdh_params = NULL;
mbedtls_ctr_drbg_context *ctr_drbg = NULL;
int rc, ret = SSH_ERROR;
char error_buf[128];
if (session->server) {
pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
} else {
pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
}
ctr_drbg = ssh_get_mbedtls_ctr_drbg_context();
mbedtls_ecdh_init(&ecdh_ctx);
rc = mbedtls_ecdh_setup(&ecdh_ctx, MBEDTLS_ECP_DP_CURVE25519);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE, "Failed to setup X25519 context: %s", error_buf);
goto out;
}
ecdh_params = &MBEDTLS_ECDH_PARAMS(ecdh_ctx);
rc = mbedtls_ecdh_gen_public(&ecdh_params->MBEDTLS_ECDH_PRIVATE(grp),
&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Q),
mbedtls_ctr_drbg_random,
ctr_drbg);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate X25519 keypair: %s",
error_buf);
goto out;
}
rc = mbedtls_mpi_write_binary_le(&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
session->next_crypto->curve25519_privkey,
CURVE25519_PRIVKEY_SIZE);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE,
"Failed to write X25519 private key: %s",
error_buf);
goto out;
}
rc = mbedtls_mpi_write_binary_le(
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Q).MBEDTLS_ECDH_PRIVATE(X),
*pubkey_loc,
CURVE25519_PUBKEY_SIZE);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE,
"Failed to write X25519 public key: %s",
error_buf);
goto out;
}
ret = SSH_OK;
out:
mbedtls_ecdh_free(&ecdh_ctx);
return ret;
}
int curve25519_do_create_k(ssh_session session, ssh_curve25519_pubkey k)
{
ssh_curve25519_pubkey *peer_pubkey_loc = NULL;
int rc, ret = SSH_ERROR;
mbedtls_ecdh_context ecdh_ctx;
mbedtls_ecdh_params *ecdh_params = NULL;
mbedtls_ctr_drbg_context *ctr_drbg = NULL;
char error_buf[128];
if (session->server) {
peer_pubkey_loc = &session->next_crypto->curve25519_client_pubkey;
} else {
peer_pubkey_loc = &session->next_crypto->curve25519_server_pubkey;
}
ctr_drbg = ssh_get_mbedtls_ctr_drbg_context();
mbedtls_ecdh_init(&ecdh_ctx);
rc = mbedtls_ecdh_setup(&ecdh_ctx, MBEDTLS_ECP_DP_CURVE25519);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE, "Failed to setup X25519 context: %s", error_buf);
goto out;
}
ecdh_params = &MBEDTLS_ECDH_PARAMS(ecdh_ctx);
rc = mbedtls_mpi_read_binary_le(&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
session->next_crypto->curve25519_privkey,
CURVE25519_PRIVKEY_SIZE);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE, "Failed to read private key: %s", error_buf);
goto out;
}
rc = mbedtls_mpi_read_binary_le(
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Qp).MBEDTLS_ECDH_PRIVATE(X),
*peer_pubkey_loc,
CURVE25519_PUBKEY_SIZE);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE, "Failed to read peer public key: %s", error_buf);
goto out;
}
rc = mbedtls_mpi_lset(
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Qp).MBEDTLS_ECDH_PRIVATE(Z),
1);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE, "Failed to set Z coordinate: %s", error_buf);
goto out;
}
rc = mbedtls_ecdh_compute_shared(&ecdh_params->MBEDTLS_ECDH_PRIVATE(grp),
&ecdh_params->MBEDTLS_ECDH_PRIVATE(z),
&ecdh_params->MBEDTLS_ECDH_PRIVATE(Qp),
&ecdh_params->MBEDTLS_ECDH_PRIVATE(d),
mbedtls_ctr_drbg_random,
ctr_drbg);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE,
"Failed to compute shared secret: %s",
error_buf);
goto out;
}
rc = mbedtls_mpi_write_binary_le(&ecdh_params->MBEDTLS_ECDH_PRIVATE(z),
k,
CURVE25519_PUBKEY_SIZE);
if (rc != 0) {
mbedtls_strerror(rc, error_buf, sizeof(error_buf));
SSH_LOG(SSH_LOG_TRACE, "Failed to write shared secret: %s", error_buf);
goto out;
}
ret = SSH_OK;
out:
mbedtls_ecdh_free(&ecdh_ctx);
return ret;
}

View File

@@ -416,6 +416,9 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
do {
firstbyte = getc(moduli);
} while(firstbyte != '\n' && firstbyte != EOF);
if (firstbyte == EOF) {
break;
}
continue;
}
if (firstbyte == EOF) {
@@ -439,6 +442,9 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli,
do {
firstbyte = getc(moduli);
} while(firstbyte != '\n' && firstbyte != EOF);
if (firstbyte == EOF) {
break;
}
continue;
}

View File

@@ -592,7 +592,7 @@ int ssh_dh_compute_shared_secret(struct dh_ctx *dh_ctx, int local, int remote,
}
#endif /* OPENSSL_VERSION_NUMBER */
*dest = BN_bin2bn(kstring, klen, NULL);
*dest = BN_bin2bn(kstring, (int)klen, NULL);
if (*dest == NULL) {
rc = SSH_ERROR;
goto done;

1060
src/external/sntrup761.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@ static int ssh_gets(const char *prompt, char *buf, size_t len, int verify)
fprintf(stdout, "%s", prompt);
}
fflush(stdout);
if (fgets(tmp, len, stdin) == NULL) {
if (fgets(tmp, (int)len, stdin) == NULL) {
free(tmp);
return 0;
}
@@ -87,7 +87,7 @@ static int ssh_gets(const char *prompt, char *buf, size_t len, int verify)
fprintf(stdout, "\nVerifying, please re-enter. %s", prompt);
fflush(stdout);
if (! fgets(key_string, len, stdin)) {
if (!fgets(key_string, (int)len, stdin)) {
explicit_bzero(key_string, len);
SAFE_FREE(key_string);
clearerr(stdin);

126
src/kex.c
View File

@@ -40,6 +40,7 @@
#include "libssh/ssh2.h"
#include "libssh/string.h"
#include "libssh/curve25519.h"
#include "libssh/sntrup761.h"
#include "libssh/knownhosts.h"
#include "libssh/misc.h"
#include "libssh/pki.h"
@@ -95,6 +96,12 @@
#define CURVE25519 ""
#endif /* HAVE_CURVE25519 */
#ifdef HAVE_SNTRUP761
#define SNTRUP761X25519 "sntrup761x25519-sha512@openssh.com,"
#else
#define SNTRUP761X25519 ""
#endif /* HAVE_SNTRUP761 */
#ifdef HAVE_ECC
#define ECDH "ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,"
#define EC_HOSTKEYS "ecdsa-sha2-nistp521," \
@@ -159,6 +166,7 @@
#define DEFAULT_KEY_EXCHANGE \
CURVE25519 \
SNTRUP761X25519 \
ECDH \
"diffie-hellman-group18-sha512,diffie-hellman-group16-sha512," \
GEX_SHA256 \
@@ -267,38 +275,58 @@ static const char *ssh_kex_descriptions[] = {
NULL
};
const char *ssh_kex_get_default_methods(uint32_t algo)
const char *ssh_kex_get_default_methods(enum ssh_kex_types_e type)
{
if (algo >= SSH_KEX_METHODS) {
if (type >= SSH_KEX_METHODS) {
return NULL;
}
return default_methods[algo];
return default_methods[type];
}
const char *ssh_kex_get_supported_method(uint32_t algo)
const char *ssh_kex_get_supported_method(enum ssh_kex_types_e type)
{
if (algo >= SSH_KEX_METHODS) {
if (type >= SSH_KEX_METHODS) {
return NULL;
}
return supported_methods[algo];
return supported_methods[type];
}
const char *ssh_kex_get_description(uint32_t algo) {
if (algo >= SSH_KEX_METHODS) {
return NULL;
}
const char *ssh_kex_get_description(enum ssh_kex_types_e type)
{
if (type >= SSH_KEX_METHODS) {
return NULL;
}
return ssh_kex_descriptions[algo];
return ssh_kex_descriptions[type];
}
const char *ssh_kex_get_fips_methods(uint32_t algo) {
if (algo >= SSH_KEX_METHODS) {
return NULL;
}
const char *ssh_kex_get_fips_methods(enum ssh_kex_types_e type)
{
if (type >= SSH_KEX_METHODS) {
return NULL;
}
return fips_methods[algo];
return fips_methods[type];
}
/**
* @brief Get a list of supported algorithms of a given type. This respects the
* FIPS mode status.
*
* @param[in] type The type of the algorithm to query (SSH_KEX, SSH_MAC_C_S,
* ...).
*
* @return The list of supported methods as comma-separated string, or NULL for
* unknown type.
*/
const char *ssh_get_supported_methods(enum ssh_kex_types_e type)
{
if (ssh_fips_mode()) {
return ssh_kex_get_fips_methods(type);
} else {
return ssh_kex_get_supported_method(type);
}
}
/**
@@ -894,6 +922,8 @@ kex_select_kex_type(const char *kex)
return SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
} else if (strcmp(kex, "curve25519-sha256") == 0) {
return SSH_KEX_CURVE25519_SHA256;
} else if (strcmp(kex, "sntrup761x25519-sha512@openssh.com") == 0) {
return SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM;
}
/* should not happen. We should be getting only valid names at this stage */
return 0;
@@ -933,6 +963,11 @@ static void revert_kex_callbacks(ssh_session session)
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
ssh_client_curve25519_remove_callbacks(session);
break;
#endif
#ifdef HAVE_SNTRUP761
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
ssh_client_sntrup761x25519_remove_callbacks(session);
break;
#endif
}
}
@@ -1340,6 +1375,7 @@ int ssh_make_sessionid(ssh_session session)
buf = ssh_buffer_new();
if (buf == NULL) {
ssh_set_error_oom(session);
return rc;
}
@@ -1348,6 +1384,9 @@ int ssh_make_sessionid(ssh_session session)
session->clientbanner,
session->serverbanner);
if (rc == SSH_ERROR) {
ssh_set_error(session,
SSH_FATAL,
"Failed to pack client and server banner");
goto error;
}
@@ -1361,6 +1400,9 @@ int ssh_make_sessionid(ssh_session session)
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != SSH_OK) {
ssh_set_error(session,
SSH_FATAL,
"Failed to get next server pubkey blob");
goto error;
}
@@ -1375,6 +1417,9 @@ int ssh_make_sessionid(ssh_session session)
server_pubkey_blob);
SSH_STRING_FREE(server_pubkey_blob);
if (rc != SSH_OK){
ssh_set_error(session,
SSH_FATAL,
"Failed to pack hashes and pubkey blob");
goto error;
}
@@ -1399,6 +1444,7 @@ int ssh_make_sessionid(ssh_session session)
client_pubkey,
server_pubkey);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Failed to pack DH pubkeys");
goto error;
}
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
@@ -1434,6 +1480,7 @@ int ssh_make_sessionid(ssh_session session)
client_pubkey,
server_pubkey);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Failed to pack DH GEX params");
goto error;
}
#if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
@@ -1456,6 +1503,7 @@ int ssh_make_sessionid(ssh_session session)
session->next_crypto->ecdh_client_pubkey,
session->next_crypto->ecdh_server_pubkey);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Failed to pack ECDH pubkeys");
goto error;
}
break;
@@ -1473,13 +1521,47 @@ int ssh_make_sessionid(ssh_session session)
session->next_crypto->curve25519_server_pubkey);
if (rc != SSH_OK) {
ssh_set_error(session,
SSH_FATAL,
"Failed to pack Curve25519 pubkeys");
goto error;
}
break;
#endif /* HAVE_CURVE25519 */
#ifdef HAVE_SNTRUP761
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
rc = ssh_buffer_pack(buf,
"dPPdPP",
SNTRUP761_PUBLICKEY_SIZE + CURVE25519_PUBKEY_SIZE,
(size_t)SNTRUP761_PUBLICKEY_SIZE,
session->next_crypto->sntrup761_client_pubkey,
(size_t)CURVE25519_PUBKEY_SIZE,
session->next_crypto->curve25519_client_pubkey,
SNTRUP761_CIPHERTEXT_SIZE + CURVE25519_PUBKEY_SIZE,
(size_t)SNTRUP761_CIPHERTEXT_SIZE,
session->next_crypto->sntrup761_ciphertext,
(size_t)CURVE25519_PUBKEY_SIZE,
session->next_crypto->curve25519_server_pubkey);
if (rc != SSH_OK) {
ssh_set_error(session,
SSH_FATAL,
"Failed to pack SNTRU Prime params");
goto error;
}
break;
#endif /* HAVE_SNTRUP761 */
}
if (session->next_crypto->kex_type == SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM) {
rc = ssh_buffer_pack(buf,
"F",
session->next_crypto->shared_secret,
SHA512_DIGEST_LEN);
} else {
rc = ssh_buffer_pack(buf, "B", session->next_crypto->shared_secret);
}
rc = ssh_buffer_pack(buf, "B", session->next_crypto->shared_secret);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Failed to pack shared secret");
goto error;
}
@@ -1534,6 +1616,7 @@ int ssh_make_sessionid(ssh_session session)
case SSH_KEX_DH_GROUP16_SHA512:
case SSH_KEX_DH_GROUP18_SHA512:
case SSH_KEX_ECDH_SHA2_NISTP521:
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
session->next_crypto->digest_len = SHA512_DIGEST_LENGTH;
session->next_crypto->digest_type = SSH_KDF_SHA512;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
@@ -1670,7 +1753,12 @@ int ssh_generate_session_keys(ssh_session session)
size_t intkey_srv_to_cli_len = 0;
int rc = -1;
k_string = ssh_make_bignum_string(crypto->shared_secret);
if (session->next_crypto->kex_type == SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM) {
k_string = ssh_make_padded_bignum_string(crypto->shared_secret,
SHA512_DIGEST_LEN);
} else {
k_string = ssh_make_bignum_string(crypto->shared_secret);
}
if (k_string == NULL) {
ssh_set_error_oom(session);
goto error;

View File

@@ -171,7 +171,7 @@ static int known_hosts_read_line(FILE *fp,
size_t *buf_len,
size_t *lineno)
{
while (fgets(buf, buf_size, fp) != NULL) {
while (fgets(buf, (int)buf_size, fp) != NULL) {
size_t len;
if (buf[0] == '\0') {
continue;

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
@@ -317,7 +349,7 @@ HMACCTX hmac_init(const void *key, size_t len, enum ssh_hmac_e type)
return NULL;
}
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, len);
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, (int)len);
if (pkey == NULL) {
goto error;
}
@@ -603,7 +635,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
(unsigned char *)out + aadlen,
&tmplen,
(unsigned char *)in + aadlen,
(int)len - aadlen);
(int)(len - aadlen));
outlen = tmplen;
if (rc != 1 || outlen != (int)len - aadlen) {
SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptUpdate failed");
@@ -621,7 +653,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher,
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
EVP_CTRL_GCM_GET_TAG,
authlen,
(int)authlen,
(unsigned char *)tag);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_GET_TAG failed");
@@ -659,7 +691,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
/* set tag for authentication */
rc = EVP_CIPHER_CTX_ctrl(cipher->ctx,
EVP_CTRL_GCM_SET_TAG,
authlen,
(int)authlen,
(unsigned char *)complete_packet + aadlen + encrypted_size);
if (rc == 0) {
SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_TAG failed");
@@ -684,7 +716,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher,
(unsigned char *)out,
&outlen,
(unsigned char *)complete_packet + aadlen,
encrypted_size /* already subtracted aadlen */);
(int)encrypted_size /* already subtracted aadlen */);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptUpdate failed");
return SSH_ERROR;
@@ -966,7 +998,7 @@ chacha20_poly1305_aead_decrypt_length(struct ssh_cipher_struct *cipher,
return SSH_ERROR;
}
rv = EVP_CipherUpdate(ctx->header_evp, out, &outlen, in, len);
rv = EVP_CipherUpdate(ctx->header_evp, out, &outlen, in, (int)len);
if (rv != 1 || outlen != sizeof(uint32_t)) {
SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
return SSH_ERROR;
@@ -1053,9 +1085,11 @@ chacha20_poly1305_aead_decrypt(struct ssh_cipher_struct *cipher,
}
/* Decrypt the message */
rv = EVP_CipherUpdate(ctx->main_evp, out, &len,
rv = EVP_CipherUpdate(ctx->main_evp,
out,
&len,
(uint8_t *)complete_packet + sizeof(uint32_t),
encrypted_size);
(int)encrypted_size);
if (rv != 1) {
SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
goto out;
@@ -1122,7 +1156,7 @@ chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
out_packet->payload,
&outlen,
in_packet->payload,
len - sizeof(uint32_t));
(int)(len - sizeof(uint32_t)));
if (ret != 1) {
SSH_LOG(SSH_LOG_TRACE, "EVP_CipherUpdate failed");
return;
@@ -1402,6 +1436,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;
}
@@ -1546,6 +1588,12 @@ int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote)
{
return evp_dup_pkey("EC", key, demote, new_key);
}
int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote)
{
return evp_dup_pkey("ED25519", key, demote, new_key);
}
#endif /* OPENSSL_VERSION_NUMBER */
ssh_string

View File

@@ -966,7 +966,8 @@ int ssh_crypto_init(void)
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P, 0)) {
gcry_control(GCRYCTL_INIT_SECMEM, 4096);
gcry_control(GCRYCTL_USE_SECURE_RNDPOOL);
gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
}

View File

@@ -481,3 +481,16 @@ LIBSSH_4_10_0 # Released
ssh_pki_export_privkey_file_format;
ssh_request_no_more_sessions;
} LIBSSH_4_9_0;
LIBSSH_AFTER_4_10_0
{
global:
sftp_get_users_groups_by_id;
sftp_name_id_map_free;
sftp_name_id_map_new;
ssh_get_supported_methods;
sshsig_sign;
sshsig_verify;
ssh_string_cmp;
} LIBSSH_4_10_0;

View File

@@ -59,22 +59,22 @@ static int current_timestring(int hires, char *buf, size_t len)
{
char tbuf[64];
struct timeval tv;
struct tm *tm;
struct tm tm, *tm_ptr = NULL;
time_t t;
gettimeofday(&tv, NULL);
t = (time_t) tv.tv_sec;
tm = localtime(&t);
if (tm == NULL) {
tm_ptr = localtime_r(&t, &tm);
if (tm_ptr == NULL) {
return -1;
}
if (hires) {
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
strftime(tbuf, sizeof(tbuf), "%Y/%m/%d %H:%M:%S", &tm);
snprintf(buf, len, "%s.%06ld", tbuf, (long)tv.tv_usec);
} else {
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
strftime(tbuf, sizeof(tbuf), "%Y/%m/%d %H:%M:%S", &tm);
snprintf(buf, len, "%s", tbuf);
}

View File

@@ -205,8 +205,10 @@ int match_pattern_list(const char *string, const char *pattern,
* Returns -1 if negation matches, 1 if there is a positive match, 0 if there
* is no match at all.
*/
int match_hostname(const char *host, const char *pattern, unsigned int len) {
return match_pattern_list(host, pattern, len, 1);
int
match_hostname(const char *host, const char *pattern, size_t len)
{
return match_pattern_list(host, pattern, len, 1);
}
#ifndef _WIN32

View File

@@ -5,13 +5,17 @@
* v3 defines the version inside build_info.h so if it isn't defined
* in version.h we should have v3
*/
#include <mbedtls/version.h>
#include <mbedtls/cipher.h>
#ifdef MBEDTLS_VERSION_MAJOR
#include <mbedtls/version.h>
#ifndef MBEDTLS_VERSION_MAJOR
#include <mbedtls/build_info.h>
#endif /* MBEDTLS_VERSION_MAJOR */
#if MBEDTLS_VERSION_MAJOR < 3
static inline size_t mbedtls_cipher_info_get_key_bitlen(
const mbedtls_cipher_info_t *info)
static inline size_t
mbedtls_cipher_info_get_key_bitlen(const mbedtls_cipher_info_t *info)
{
if (info == NULL) {
return 0;
@@ -19,8 +23,8 @@ static inline size_t mbedtls_cipher_info_get_key_bitlen(
return info->key_bitlen;
}
static inline size_t mbedtls_cipher_info_get_iv_size(
const mbedtls_cipher_info_t *info)
static inline size_t
mbedtls_cipher_info_get_iv_size(const mbedtls_cipher_info_t *info)
{
if (info == NULL) {
return 0;
@@ -29,11 +33,24 @@ static inline size_t mbedtls_cipher_info_get_iv_size(
}
#define MBEDTLS_PRIVATE(X) X
#ifdef HAVE_MBEDTLS_CURVE25519
#include <mbedtls/ecdh.h>
#define MBEDTLS_ECDH_PRIVATE(X) X
#define MBEDTLS_ECDH_PARAMS(X) X
typedef mbedtls_ecdh_context mbedtls_ecdh_params;
#endif /* HAVE_MBEDTLS_CURVE25519 */
#else /* MBEDTLS_VERSION_MAJOR < 3 */
#ifdef HAVE_MBEDTLS_CURVE25519
#include <mbedtls/ecdh.h>
#define MBEDTLS_ECDH_PRIVATE(X) MBEDTLS_PRIVATE(X)
#define MBEDTLS_ECDH_PARAMS(X) X.MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh)
typedef mbedtls_ecdh_context_mbed mbedtls_ecdh_params;
#endif /* HAVE_MBEDTLS_CURVE25519 */
#endif /* MBEDTLS_VERSION_MAJOR < 3 */
#else /* MBEDTLS_VERSION_MAJOR */
#include <mbedtls/build_info.h>
#if MBEDTLS_VERSION_MAJOR < 3
#define MBEDTLS_PRIVATE(X) X
#endif /* MBEDTLS_VERSION_MAJOR < 3 */
#endif /* MBEDTLS_VERSION_MAJOR */
#endif /* MBEDCRYPTO_COMPAT_H */

View File

@@ -204,8 +204,35 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
ssh_message_reply_default(msg);
}
return SSH_OK;
#define CB channel_open_request_direct_tcpip_function
} else if (msg->channel_request_open.type == SSH_CHANNEL_DIRECT_TCPIP &&
ssh_callbacks_exists(session->server_callbacks, CB)) {
struct ssh_channel_request_open *rq = &msg->channel_request_open;
channel = session->server_callbacks->CB(session,
rq->destination,
rq->destination_port,
rq->originator,
rq->originator_port,
session->server_callbacks->userdata);
#undef CB
if (channel != NULL) {
rc = ssh_message_channel_request_open_reply_accept_channel(
msg,
channel);
if (rc != SSH_OK) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to send reply for accepting a channel "
"open");
}
return SSH_OK;
} else {
ssh_message_reply_default(msg);
}
return SSH_OK;
}
break;
case SSH_REQUEST_CHANNEL:
channel = msg->channel_request.channel;
@@ -519,30 +546,36 @@ static void ssh_message_queue(ssh_session session, ssh_message message)
*
* @returns The head message or NULL if it doesn't exist.
*/
ssh_message ssh_message_pop_head(ssh_session session){
ssh_message msg=NULL;
struct ssh_iterator *i = NULL;
if(session->ssh_message_list == NULL)
return NULL;
i=ssh_list_get_iterator(session->ssh_message_list);
if(i != NULL){
msg=ssh_iterator_value(ssh_message,i);
ssh_list_remove(session->ssh_message_list,i);
}
return msg;
ssh_message ssh_message_pop_head(ssh_session session)
{
ssh_message msg = NULL;
struct ssh_iterator *i = NULL;
if (session->ssh_message_list == NULL)
return NULL;
i = ssh_list_get_iterator(session->ssh_message_list);
if (i != NULL) {
msg = ssh_iterator_value(ssh_message, i);
ssh_list_remove(session->ssh_message_list, i);
}
return msg;
}
/* Returns 1 if there is a message available */
static int ssh_message_termination(void *s){
ssh_session session = s;
struct ssh_iterator *it = NULL;
if(session->session_state == SSH_SESSION_STATE_ERROR)
return 1;
it = ssh_list_get_iterator(session->ssh_message_list);
if(!it)
return 0;
else
return 1;
static int ssh_message_termination(void *s)
{
ssh_session session = s;
struct ssh_iterator *it = NULL;
if (session->session_state == SSH_SESSION_STATE_ERROR)
return 1;
it = ssh_list_get_iterator(session->ssh_message_list);
if (!it)
return 0;
else
return 1;
}
/**
* @brief Retrieve a SSH message from a SSH session.
@@ -642,6 +675,7 @@ void ssh_message_free(ssh_message msg){
SAFE_FREE(msg->auth_request.password);
}
ssh_key_free(msg->auth_request.pubkey);
ssh_key_free(msg->auth_request.server_pubkey);
break;
case SSH_REQUEST_CHANNEL_OPEN:
SAFE_FREE(msg->channel_request_open.originator);
@@ -733,11 +767,12 @@ error:
static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
ssh_message msg,
const char *service,
ssh_string algo)
ssh_string algo,
const char *method)
{
struct ssh_crypto_struct *crypto = NULL;
ssh_buffer buffer = NULL;
ssh_string str=NULL;
ssh_string str = NULL;
int rc;
crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN);
@@ -763,10 +798,10 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
SSH2_MSG_USERAUTH_REQUEST, /* type */
msg->auth_request.username,
service,
"publickey", /* method */
method,
1, /* has to be signed (true) */
ssh_string_get_char(algo), /* pubkey algorithm */
str); /* public key as a blob */
str); /* public key as a blob */
SSH_STRING_FREE(str);
if (rc != SSH_OK) {
@@ -775,6 +810,25 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
return NULL;
}
/* Add server public key for hostbound extension */
if (strcmp(method, "publickey-hostbound-v00@openssh.com") == 0 &&
msg->auth_request.server_pubkey != NULL) {
rc = ssh_pki_export_pubkey_blob(msg->auth_request.server_pubkey, &str);
if (rc < 0) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
rc = ssh_buffer_add_ssh_string(buffer, str);
SSH_STRING_FREE(str);
if (rc < 0) {
ssh_set_error_oom(session);
SSH_BUFFER_FREE(buffer);
return NULL;
}
}
return buffer;
}
@@ -784,263 +838,334 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
* @brief Handle a SSH_MSG_MSG_USERAUTH_REQUEST packet and queue a
* SSH Message
*/
SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
ssh_message msg = NULL;
ssh_signature sig = NULL;
char *service = NULL;
char *method = NULL;
int cmp;
int rc;
SSH_PACKET_CALLBACK(ssh_packet_userauth_request)
{
ssh_message msg = NULL;
ssh_signature sig = NULL;
char *service = NULL;
char *method = NULL;
int cmp;
int rc;
(void)user;
(void)type;
(void)user;
(void)type;
msg = ssh_message_new(session);
if (msg == NULL) {
ssh_set_error_oom(session);
goto error;
}
msg->type = SSH_REQUEST_AUTH;
rc = ssh_buffer_unpack(packet,
"sss",
&msg->auth_request.username,
&service,
&method);
if (rc != SSH_OK) {
goto error;
}
SSH_LOG(SSH_LOG_PACKET,
"Auth request for service %s, method %s for user '%s'",
service, method,
msg->auth_request.username);
cmp = strcmp(service, "ssh-connection");
if (cmp != 0) {
SSH_LOG(SSH_LOG_TRACE,
"Invalid service request: %s",
service);
goto end;
}
if (strcmp(method, "none") == 0) {
msg->auth_request.method = SSH_AUTH_METHOD_NONE;
goto end;
}
if (strcmp(method, "password") == 0) {
uint8_t tmp;
msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
rc = ssh_buffer_unpack(packet, "bs", &tmp, &msg->auth_request.password);
if (rc != SSH_OK) {
goto error;
}
goto end;
}
if (strcmp(method, "keyboard-interactive") == 0) {
ssh_string lang = NULL;
ssh_string submethods = NULL;
msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
lang = ssh_buffer_get_ssh_string(packet);
if (lang == NULL) {
goto error;
}
/* from the RFC 4256
* 3.1. Initial Exchange
* "The language tag is deprecated and SHOULD be the empty string."
*/
SSH_STRING_FREE(lang);
submethods = ssh_buffer_get_ssh_string(packet);
if (submethods == NULL) {
goto error;
}
/* from the RFC 4256
* 3.1. Initial Exchange
* "One possible implementation strategy of the submethods field on the
* server is that, unless the user may use multiple different
* submethods, the server ignores this field."
*/
SSH_STRING_FREE(submethods);
goto end;
}
if (strcmp(method, "publickey") == 0) {
ssh_string algo = NULL;
ssh_string pubkey_blob = NULL;
uint8_t has_sign;
msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
SAFE_FREE(method);
rc = ssh_buffer_unpack(packet, "bSS",
&has_sign,
&algo,
&pubkey_blob
);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_pki_import_pubkey_blob(pubkey_blob, &msg->auth_request.pubkey);
SSH_STRING_FREE(pubkey_blob);
pubkey_blob = NULL;
if (rc < 0) {
SSH_STRING_FREE(algo);
algo = NULL;
msg = ssh_message_new(session);
if (msg == NULL) {
ssh_set_error_oom(session);
goto error;
}
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
msg->auth_request.sigtype = strdup(ssh_string_get_char(algo));
if (msg->auth_request.sigtype == NULL) {
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
SSH_STRING_FREE(algo);
algo = NULL;
msg->type = SSH_REQUEST_AUTH;
rc = ssh_buffer_unpack(packet,
"sss",
&msg->auth_request.username,
&service,
&method);
if (rc != SSH_OK) {
goto error;
}
// has a valid signature ?
if(has_sign) {
ssh_string sig_blob = NULL;
ssh_buffer digest = NULL;
SSH_LOG(SSH_LOG_PACKET,
"Auth request for service %s, method %s for user '%s'",
service,
method,
msg->auth_request.username);
sig_blob = ssh_buffer_get_ssh_string(packet);
if(sig_blob == NULL) {
SSH_LOG(SSH_LOG_PACKET, "Invalid signature packet from peer");
cmp = strcmp(service, "ssh-connection");
if (cmp != 0) {
SSH_LOG(SSH_LOG_TRACE, "Invalid service request: %s", service);
goto end;
}
if (strcmp(method, "none") == 0) {
msg->auth_request.method = SSH_AUTH_METHOD_NONE;
goto end;
}
if (strcmp(method, "password") == 0) {
uint8_t tmp;
msg->auth_request.method = SSH_AUTH_METHOD_PASSWORD;
rc = ssh_buffer_unpack(packet, "bs", &tmp, &msg->auth_request.password);
if (rc != SSH_OK) {
goto error;
}
goto end;
}
if (strcmp(method, "keyboard-interactive") == 0) {
ssh_string lang = NULL;
ssh_string submethods = NULL;
msg->auth_request.method = SSH_AUTH_METHOD_INTERACTIVE;
lang = ssh_buffer_get_ssh_string(packet);
if (lang == NULL) {
goto error;
}
/* from the RFC 4256
* 3.1. Initial Exchange
* "The language tag is deprecated and SHOULD be the empty string."
*/
SSH_STRING_FREE(lang);
submethods = ssh_buffer_get_ssh_string(packet);
if (submethods == NULL) {
goto error;
}
/* from the RFC 4256
* 3.1. Initial Exchange
* "One possible implementation strategy of the submethods field on the
* server is that, unless the user may use multiple different
* submethods, the server ignores this field."
*/
SSH_STRING_FREE(submethods);
goto end;
}
if (strcmp(method, "publickey") == 0 ||
strcmp(method, "publickey-hostbound-v00@openssh.com") == 0) {
ssh_string algo = NULL;
ssh_string pubkey_blob = NULL;
ssh_string server_pubkey_blob = NULL;
uint8_t has_sign;
msg->auth_request.method = SSH_AUTH_METHOD_PUBLICKEY;
rc = ssh_buffer_unpack(packet, "bSS", &has_sign, &algo, &pubkey_blob);
if (rc != SSH_OK) {
goto error;
}
cmp = strcmp(method, "publickey-hostbound-v00@openssh.com");
if (cmp == 0) {
server_pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (server_pubkey_blob == NULL) {
SSH_STRING_FREE(pubkey_blob);
SSH_STRING_FREE(algo);
goto error;
}
rc = ssh_pki_import_pubkey_blob(server_pubkey_blob,
&msg->auth_request.server_pubkey);
SSH_STRING_FREE(server_pubkey_blob);
if (rc < 0) {
SSH_STRING_FREE(pubkey_blob);
SSH_STRING_FREE(algo);
goto error;
}
}
rc = ssh_pki_import_pubkey_blob(pubkey_blob, &msg->auth_request.pubkey);
SSH_STRING_FREE(pubkey_blob);
pubkey_blob = NULL;
if (rc < 0) {
SSH_STRING_FREE(algo);
algo = NULL;
goto error;
}
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_NONE;
msg->auth_request.sigtype = strdup(ssh_string_get_char(algo));
if (msg->auth_request.sigtype == NULL) {
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
SSH_STRING_FREE(algo);
algo = NULL;
goto error;
}
digest = ssh_msg_userauth_build_digest(session, msg, service, algo);
SSH_STRING_FREE(algo);
algo = NULL;
if (digest == NULL) {
SSH_STRING_FREE(sig_blob);
SSH_LOG(SSH_LOG_PACKET, "Failed to get digest");
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
goto error;
}
// has a valid signature ?
if (has_sign) {
ssh_string sig_blob = NULL;
ssh_buffer digest = NULL;
rc = ssh_pki_import_signature_blob(sig_blob,
msg->auth_request.pubkey,
&sig);
if (rc == SSH_OK) {
/* Check if the signature from client matches server preferences */
if (session->opts.pubkey_accepted_types) {
cmp = match_group(session->opts.pubkey_accepted_types,
sig->type_c);
if (cmp != 1) {
ssh_set_error(session,
sig_blob = ssh_buffer_get_ssh_string(packet);
if (sig_blob == NULL) {
SSH_LOG(SSH_LOG_PACKET, "Invalid signature packet from peer");
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_ERROR;
SSH_STRING_FREE(algo);
algo = NULL;
goto error;
}
digest = ssh_msg_userauth_build_digest(session,
msg,
service,
algo,
method);
SSH_STRING_FREE(algo);
algo = NULL;
if (digest == NULL) {
SSH_STRING_FREE(sig_blob);
SSH_LOG(SSH_LOG_PACKET, "Failed to get digest");
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
goto error;
}
rc = ssh_pki_import_signature_blob(sig_blob,
msg->auth_request.pubkey,
&sig);
if (rc == SSH_OK) {
/* Check if the signature from client matches server preferences
*/
if (session->opts.pubkey_accepted_types) {
cmp = match_group(session->opts.pubkey_accepted_types,
sig->type_c);
if (cmp != 1) {
ssh_set_error(
session,
SSH_FATAL,
"Public key from client (%s) doesn't match server "
"preference (%s)",
sig->type_c,
session->opts.pubkey_accepted_types);
rc = SSH_ERROR;
rc = SSH_ERROR;
}
}
if (rc == SSH_OK) {
rc = ssh_pki_signature_verify(session,
sig,
msg->auth_request.pubkey,
ssh_buffer_get(digest),
ssh_buffer_get_len(digest));
}
}
if (rc == SSH_OK) {
rc = ssh_pki_signature_verify(session,
sig,
msg->auth_request.pubkey,
ssh_buffer_get(digest),
ssh_buffer_get_len(digest));
SSH_STRING_FREE(sig_blob);
SSH_BUFFER_FREE(digest);
ssh_signature_free(sig);
if (rc < 0) {
SSH_LOG(SSH_LOG_PACKET,
"Received an invalid signature from peer");
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
goto error;
}
SSH_LOG(SSH_LOG_PACKET, "Valid signature received");
cmp = strcmp(method, "publickey-hostbound-v00@openssh.com");
if (cmp == 0) {
ssh_key server_key = NULL;
if (msg->auth_request.server_pubkey == NULL) {
SSH_LOG(SSH_LOG_PACKET,
"Server public key not provided by client");
msg->auth_request.signature_state =
SSH_PUBLICKEY_STATE_WRONG;
goto error;
}
rc = ssh_get_server_publickey(session, &server_key);
if (rc != SSH_OK) {
SSH_LOG(SSH_LOG_PACKET,
"Failed to get server public key for hostbound "
"verification");
msg->auth_request.signature_state =
SSH_PUBLICKEY_STATE_ERROR;
ssh_key_free(server_key);
goto error;
}
if (ssh_key_cmp(server_key,
msg->auth_request.server_pubkey,
SSH_KEY_CMP_PUBLIC) != 0) {
SSH_LOG(SSH_LOG_PACKET,
"Server public key doesn't match the one provided "
"by client");
msg->auth_request.signature_state =
SSH_PUBLICKEY_STATE_WRONG;
ssh_key_free(server_key);
goto error;
}
ssh_key_free(server_key);
}
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID;
}
SSH_STRING_FREE(sig_blob);
SSH_BUFFER_FREE(digest);
ssh_signature_free(sig);
if (rc < 0) {
SSH_LOG(
SSH_LOG_PACKET,
"Received an invalid signature from peer");
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_WRONG;
SAFE_FREE(method);
SSH_STRING_FREE(algo);
goto end;
}
#ifdef WITH_GSSAPI
if (strcmp(method, "gssapi-with-mic") == 0) {
uint32_t n_oid;
ssh_string *oids = NULL;
ssh_string oid = NULL;
char *hexa = NULL;
int i;
ssh_buffer_get_u32(packet, &n_oid);
n_oid = ntohl(n_oid);
if (n_oid > 100) {
ssh_set_error(
session,
SSH_FATAL,
"USERAUTH_REQUEST: gssapi-with-mic OID count too big (%d)",
n_oid);
goto error;
}
SSH_LOG(SSH_LOG_PACKET, "gssapi: %d OIDs", n_oid);
oids = calloc(n_oid, sizeof(ssh_string));
if (oids == NULL) {
ssh_set_error_oom(session);
goto error;
}
for (i = 0; i < (int)n_oid; ++i) {
oid = ssh_buffer_get_ssh_string(packet);
if (oid == NULL) {
for (i = i - 1; i >= 0; --i) {
SAFE_FREE(oids[i]);
}
SAFE_FREE(oids);
ssh_set_error(session,
SSH_LOG_PACKET,
"USERAUTH_REQUEST: gssapi-with-mic missing OID");
goto error;
}
oids[i] = oid;
if (session->common.log_verbosity >= SSH_LOG_PACKET) {
hexa = ssh_get_hexa(ssh_string_data(oid), ssh_string_len(oid));
SSH_LOG(SSH_LOG_PACKET, "gssapi: OID %d: %s", i, hexa);
SAFE_FREE(hexa);
}
}
ssh_gssapi_handle_userauth(session,
msg->auth_request.username,
n_oid,
oids);
SSH_LOG(SSH_LOG_PACKET, "Valid signature received");
for (i = 0; i < (int)n_oid; ++i) {
SAFE_FREE(oids[i]);
}
SAFE_FREE(oids);
/* bypass the message queue thing */
SAFE_FREE(service);
SAFE_FREE(method);
SSH_MESSAGE_FREE(msg);
msg->auth_request.signature_state = SSH_PUBLICKEY_STATE_VALID;
return SSH_PACKET_USED;
}
SSH_STRING_FREE(algo);
goto end;
}
#ifdef WITH_GSSAPI
if (strcmp(method, "gssapi-with-mic") == 0) {
uint32_t n_oid;
ssh_string *oids = NULL;
ssh_string oid = NULL;
char *hexa = NULL;
int i;
ssh_buffer_get_u32(packet, &n_oid);
n_oid=ntohl(n_oid);
if(n_oid > 100){
ssh_set_error(session, SSH_FATAL, "USERAUTH_REQUEST: gssapi-with-mic OID count too big (%d)",n_oid);
goto error;
}
SSH_LOG(SSH_LOG_PACKET, "gssapi: %d OIDs", n_oid);
oids = calloc(n_oid, sizeof(ssh_string));
if (oids == NULL){
ssh_set_error_oom(session);
goto error;
}
for (i=0;i<(int) n_oid;++i){
oid=ssh_buffer_get_ssh_string(packet);
if(oid == NULL){
for(i=i-1;i>=0;--i){
SAFE_FREE(oids[i]);
}
SAFE_FREE(oids);
ssh_set_error(session, SSH_LOG_PACKET, "USERAUTH_REQUEST: gssapi-with-mic missing OID");
goto error;
}
oids[i] = oid;
if(session->common.log_verbosity >= SSH_LOG_PACKET){
hexa = ssh_get_hexa(ssh_string_data(oid), ssh_string_len(oid));
SSH_LOG(SSH_LOG_PACKET,"gssapi: OID %d: %s",i, hexa);
SAFE_FREE(hexa);
}
}
ssh_gssapi_handle_userauth(session, msg->auth_request.username, n_oid, oids);
for(i=0;i<(int)n_oid;++i){
SAFE_FREE(oids[i]);
}
SAFE_FREE(oids);
/* bypass the message queue thing */
SAFE_FREE(service);
SAFE_FREE(method);
SSH_MESSAGE_FREE(msg);
return SSH_PACKET_USED;
}
#endif
msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
SAFE_FREE(method);
goto end;
msg->auth_request.method = SSH_AUTH_METHOD_UNKNOWN;
SAFE_FREE(method);
goto end;
error:
SAFE_FREE(service);
SAFE_FREE(method);
SAFE_FREE(service);
SAFE_FREE(method);
SSH_MESSAGE_FREE(msg);
SSH_MESSAGE_FREE(msg);
return SSH_PACKET_USED;
return SSH_PACKET_USED;
end:
SAFE_FREE(service);
SAFE_FREE(method);
SAFE_FREE(service);
SAFE_FREE(method);
ssh_message_queue(session,msg);
ssh_message_queue(session, msg);
return SSH_PACKET_USED;
return SSH_PACKET_USED;
}
#endif /* WITH_SERVER */
@@ -1301,7 +1426,9 @@ end:
*
* @returns SSH_OK on success, SSH_ERROR if an error occurred.
*/
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_channel chan) {
int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg,
ssh_channel chan)
{
ssh_session session = NULL;
int rc;
@@ -1352,25 +1479,25 @@ int ssh_message_channel_request_open_reply_accept_channel(ssh_message msg, ssh_c
*
* @returns NULL in case of error
*/
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) {
ssh_channel chan = NULL;
int rc;
ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg)
{
ssh_channel chan = NULL;
int rc;
if (msg == NULL) {
return NULL;
}
chan = ssh_channel_new(msg->session);
if (chan == NULL) {
return NULL;
}
rc = ssh_message_channel_request_open_reply_accept_channel(msg, chan);
if (rc < 0) {
ssh_channel_free(chan);
chan = NULL;
}
return chan;
if (msg == NULL) {
return NULL;
}
chan = ssh_channel_new(msg->session);
if (chan == NULL) {
return NULL;
}
rc = ssh_message_channel_request_open_reply_accept_channel(msg, chan);
if (rc < 0) {
ssh_channel_free(chan);
chan = NULL;
}
return chan;
}
/**

View File

@@ -178,6 +178,35 @@ int ssh_gettimeofday(struct timeval *__p, void *__t)
return (0);
}
/**
* @internal
*
* @brief Convert time in seconds since the Epoch to broken-down local time
*
* This is a helper used to provide localtime_r() like function interface
* on Windows.
*
* @param timer Pointer to a location storing the time_t which
* represents the time in seconds since the Epoch.
*
* @param result Pointer to a location where the broken-down time
* (expressed as local time) should be stored.
*
* @returns A pointer to the structure pointed to by the parameter
* <tt>result</tt> on success, NULL on error with the errno
* set to indicate the error.
*/
struct tm *ssh_localtime(const time_t *timer, struct tm *result)
{
errno_t rc;
rc = localtime_s(result, timer);
if (rc != 0) {
return NULL;
}
return result;
}
char *ssh_get_local_username(void)
{
DWORD size = 0;
@@ -401,22 +430,22 @@ int ssh_is_ipaddr(const char *str)
char *ssh_lowercase(const char* str)
{
char *new = NULL, *p = NULL;
char *new = NULL, *p = NULL;
if (str == NULL) {
return NULL;
}
if (str == NULL) {
return NULL;
}
new = strdup(str);
if (new == NULL) {
return NULL;
}
new = strdup(str);
if (new == NULL) {
return NULL;
}
for (p = new; *p; p++) {
*p = tolower(*p);
}
for (p = new; *p; p++) {
*p = tolower(*p);
}
return new;
return new;
}
char *ssh_hostport(const char *host, int port)
@@ -836,32 +865,32 @@ int ssh_list_prepend(struct ssh_list *list, const void *data)
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator)
{
struct ssh_iterator *ptr = NULL, *prev = NULL;
struct ssh_iterator *ptr = NULL, *prev = NULL;
if (list == NULL) {
return;
}
if (list == NULL) {
return;
}
prev=NULL;
ptr=list->root;
while(ptr && ptr != iterator){
prev=ptr;
ptr=ptr->next;
}
if(!ptr){
/* we did not find the element */
return;
}
/* unlink it */
if(prev)
prev->next=ptr->next;
/* if iterator was the head */
if(list->root == iterator)
list->root=iterator->next;
/* if iterator was the tail */
if(list->end == iterator)
list->end = prev;
SAFE_FREE(iterator);
prev = NULL;
ptr = list->root;
while (ptr && ptr != iterator) {
prev = ptr;
ptr = ptr->next;
}
if (!ptr) {
/* we did not find the element */
return;
}
/* unlink it */
if (prev)
prev->next = ptr->next;
/* if iterator was the head */
if (list->root == iterator)
list->root = iterator->next;
/* if iterator was the tail */
if (list->end == iterator)
list->end = prev;
SAFE_FREE(iterator);
}
/**
@@ -1590,6 +1619,27 @@ void explicit_bzero(void *s, size_t n)
}
#endif /* !HAVE_EXPLICIT_BZERO */
/**
* @brief Securely free memory by overwriting it before deallocation
*
* Overwrites the memory region with zeros before calling free() to prevent
* sensitive data from remaining in memory after deallocation.
*
* @param[in] ptr Pointer to the memory region to securely free.
* Can be NULL (no operation performed).
* @param[in] len Length of the memory region in bytes.
*
*/
void burn_free(void *ptr, size_t len)
{
if (ptr == NULL || len == 0) {
return;
}
explicit_bzero(ptr, len);
free(ptr);
}
#if !defined(HAVE_STRNDUP)
char *strndup(const char *s, size_t n)
{
@@ -1802,7 +1852,7 @@ int ssh_quote_file_name(const char *file_name, char *buf, size_t buf_len)
/* Put the string terminator */
*dst = '\0';
return dst - buf;
return (int)(dst - buf);
error:
return SSH_ERROR;
@@ -1848,7 +1898,7 @@ int ssh_newline_vis(const char *string, char *buf, size_t buf_len)
}
*out = '\0';
return out - buf;
return (int)(out - buf);
}
/**

View File

@@ -1814,6 +1814,8 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
*
* @param filename The options file to use, if NULL the default
* ~/.ssh/config and /etc/ssh/ssh_config will be used.
* If complied with support for hermetic-usr,
* /usr/etc/ssh/ssh_config will be used last.
*
* @return 0 on success, < 0 on error.
*
@@ -1821,48 +1823,63 @@ int ssh_options_getopt(ssh_session session, int *argcptr, char **argv)
*/
int ssh_options_parse_config(ssh_session session, const char *filename)
{
char *expanded_filename = NULL;
int r;
char *expanded_filename = NULL;
int r;
FILE *fp = NULL;
if (session == NULL) {
return -1;
}
if (session->opts.host == NULL) {
ssh_set_error_invalid(session);
return -1;
}
if (session == NULL) {
return -1;
}
if (session->opts.host == NULL) {
ssh_set_error_invalid(session);
return -1;
}
if (session->opts.sshdir == NULL) {
r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
if (r < 0) {
ssh_set_error_oom(session);
return -1;
}
}
if (session->opts.sshdir == NULL) {
r = ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL);
if (r < 0) {
ssh_set_error_oom(session);
return -1;
}
}
/* set default filename */
if (filename == NULL) {
expanded_filename = ssh_path_expand_escape(session, "%d/config");
} else {
expanded_filename = ssh_path_expand_escape(session, filename);
}
if (expanded_filename == NULL) {
return -1;
}
/* set default filename */
if (filename == NULL) {
expanded_filename = ssh_path_expand_escape(session, "%d/config");
} else {
expanded_filename = ssh_path_expand_escape(session, filename);
}
if (expanded_filename == NULL) {
return -1;
}
r = ssh_config_parse_file(session, expanded_filename);
if (r < 0) {
goto out;
}
if (filename == NULL) {
r = ssh_config_parse_file(session, GLOBAL_CLIENT_CONFIG);
}
r = ssh_config_parse_file(session, expanded_filename);
if (r < 0) {
goto out;
}
if (filename == NULL) {
if ((fp = fopen(GLOBAL_CLIENT_CONFIG, "r")) != NULL) {
filename = GLOBAL_CLIENT_CONFIG;
#ifdef USR_GLOBAL_CLIENT_CONFIG
} else if ((fp = fopen(USR_GLOBAL_CLIENT_CONFIG, "r")) != NULL) {
filename = USR_GLOBAL_CLIENT_CONFIG;
#endif
}
/* Do not process the default configuration as part of connection again */
session->opts.config_processed = true;
if (fp) {
SSH_LOG(SSH_LOG_PACKET,
"Reading configuration data from %s",
filename);
r = ssh_config_parse(session, fp, true);
fclose(fp);
}
}
/* Do not process the default configuration as part of connection again */
session->opts.config_processed = true;
out:
free(expanded_filename);
return r;
free(expanded_filename);
return r;
}
int ssh_options_apply(ssh_session session)
@@ -1968,10 +1985,10 @@ int ssh_options_apply(ssh_session session)
* it with ssh expansion of ssh escape characters.
*/
tmp = ssh_path_expand_escape(session, id);
free(id);
if (tmp == NULL) {
return -1;
}
free(id);
}
/* use append to keep the order at first call and use prepend
@@ -1982,6 +1999,7 @@ int ssh_options_apply(ssh_session session)
rc = ssh_list_append(session->opts.identity, tmp);
}
if (rc != SSH_OK) {
free(tmp);
return -1;
}
}
@@ -1993,13 +2011,14 @@ int ssh_options_apply(ssh_session session)
char *id = tmp;
tmp = ssh_path_expand_escape(session, id);
free(id);
if (tmp == NULL) {
return -1;
}
free(id);
rc = ssh_list_append(session->opts.certificate, tmp);
if (rc != SSH_OK) {
free(tmp);
return -1;
}
}
@@ -2268,6 +2287,9 @@ ssh_bind_options_set(ssh_bind sshbind,
SSH_FATAL,
"The host key size %d is too small.",
ssh_key_size(key));
if (type != SSH_BIND_OPTIONS_IMPORT_KEY) {
SSH_KEY_FREE(key);
}
return -1;
}
key_type = ssh_key_type(key);
@@ -2313,6 +2335,11 @@ ssh_bind_options_set(ssh_bind sshbind,
ssh_key_free(key);
return -1;
}
} else if (type == SSH_BIND_OPTIONS_IMPORT_KEY_STR) {
if (bind_key_loc == NULL) {
ssh_key_free(key);
return -1;
}
} else {
if (bind_key_loc == NULL) {
return -1;
@@ -2706,7 +2733,13 @@ int ssh_bind_options_parse_config(ssh_bind sshbind, const char *filename)
/* If the global default configuration hasn't been processed yet, process it
* before the provided configuration. */
if (!(sshbind->config_processed)) {
rc = ssh_bind_config_parse_file(sshbind, GLOBAL_BIND_CONFIG);
if (ssh_file_readaccess_ok(GLOBAL_BIND_CONFIG)) {
rc = ssh_bind_config_parse_file(sshbind, GLOBAL_BIND_CONFIG);
#ifdef USR_GLOBAL_BIND_CONFIG
} else {
rc = ssh_bind_config_parse_file(sshbind, USR_GLOBAL_BIND_CONFIG);
#endif
}
if (rc != 0) {
return rc;
}

View File

@@ -1158,7 +1158,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
uint32_t lenfield_blocksize = 8;
size_t current_macsize = 0;
uint8_t *ptr = NULL;
long to_be_read;
ssize_t to_be_read;
int rc;
uint8_t *cleartext_packet = NULL;
uint8_t *packet_second_block = NULL;
@@ -1268,7 +1268,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
/* remote sshd sends invalid sizes? */
ssh_set_error(session,
SSH_FATAL,
"Given numbers of bytes left to be read < 0 (%ld)!",
"Given numbers of bytes left to be read < 0 (%zd)!",
to_be_read);
goto error;
}
@@ -1286,7 +1286,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
/* give up, not enough data in buffer */
SSH_LOG(SSH_LOG_PACKET,
"packet: partial packet (read len) "
"[len=%" PRIu32 ", receivedlen=%zu, to_be_read=%ld]",
"[len=%" PRIu32 ", receivedlen=%zu, to_be_read=%zd]",
packet_len,
receivedlen,
to_be_read);
@@ -1300,7 +1300,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
/* remaining encrypted bytes from the packet, MAC not included */
packet_remaining = packet_len - (packet_offset - sizeof(uint32_t));
cleartext_packet = ssh_buffer_allocate(session->in_buffer,
packet_remaining);
(uint32_t)packet_remaining);
if (cleartext_packet == NULL) {
goto error;
}
@@ -1476,6 +1476,7 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
session->packet_state = PACKET_STATE_INIT;
if (processed < receivedlen) {
size_t num;
/* Handle a potential packet left in socket buffer */
SSH_LOG(SSH_LOG_PACKET,
"Processing %zu bytes left in socket buffer",
@@ -1483,9 +1484,10 @@ ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
ptr = ((uint8_t*)data) + processed;
rc = ssh_packet_socket_callback(ptr, receivedlen - processed,
user);
processed += rc;
num = ssh_packet_socket_callback(ptr,
receivedlen - processed,
user);
processed += num;
}
ok = ssh_packet_need_rekey(session, 0);
@@ -1854,7 +1856,7 @@ static int packet_send2(ssh_session session)
if (hmac != NULL) {
rc = ssh_buffer_add_data(session->out_buffer,
hmac,
hmac_digest_len(hmac_type));
(uint32_t)hmac_digest_len(hmac_type));
if (rc < 0) {
goto error;
}

View File

@@ -291,7 +291,6 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info)
for (i = 0; i < nr_extensions; i++) {
char *name = NULL;
char *value = NULL;
int cmp;
rc = ssh_buffer_unpack(packet, "ss", &name, &value);
if (rc != SSH_OK) {
@@ -299,8 +298,7 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info)
return SSH_PACKET_USED;
}
cmp = strcmp(name, "server-sig-algs");
if (cmp == 0) {
if (strcmp(name, "server-sig-algs") == 0) {
/* TODO check for NULL bytes */
SSH_LOG(SSH_LOG_PACKET, "Extension: %s=<%s>", name, value);
@@ -313,6 +311,9 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info)
if (rc == 1) {
session->extensions |= SSH_EXT_SIG_RSA_SHA256;
}
} else if (strcmp(name, "publickey-hostbound@openssh.com") == 0) {
SSH_LOG(SSH_LOG_PACKET, "Extension: %s=<%s>", name, value);
session->extensions |= SSH_EXT_PUBLICKEY_HOSTBOUND;
} else {
SSH_LOG(SSH_LOG_PACKET, "Unknown extension: %s", name);
}

View File

@@ -126,11 +126,10 @@ ssh_pcap_file ssh_pcap_file_new(void)
{
struct ssh_pcap_file_struct *pcap = NULL;
pcap = malloc(sizeof(struct ssh_pcap_file_struct));
pcap = calloc(1, sizeof(struct ssh_pcap_file_struct));
if (pcap == NULL) {
return NULL;
}
ZERO_STRUCTP(pcap);
return pcap;
}
@@ -296,12 +295,13 @@ void ssh_pcap_file_free(ssh_pcap_file pcap)
*/
ssh_pcap_context ssh_pcap_context_new(ssh_session session)
{
ssh_pcap_context ctx = (struct ssh_pcap_context_struct *)malloc(sizeof(struct ssh_pcap_context_struct));
ssh_pcap_context ctx = NULL;
ctx = calloc(1, sizeof(struct ssh_pcap_context_struct));
if (ctx == NULL) {
ssh_set_error_oom(session);
return NULL;
}
ZERO_STRUCTP(ctx);
ctx->session = session;
return ctx;
}

1175
src/pki.c

File diff suppressed because it is too large Load Diff

View File

@@ -155,7 +155,7 @@ static int pki_private_key_decrypt(ssh_string blob,
}
rc = ssh_buffer_add_data(buffer,
ssh_string_data(kdfoptions),
ssh_string_len(kdfoptions));
(uint32_t)ssh_string_len(kdfoptions));
if (rc != SSH_ERROR){
rc = ssh_buffer_unpack(buffer, "Sd", &salt, &rounds);
}
@@ -339,7 +339,7 @@ ssh_pki_openssh_import(const char *text_key,
ssh_buffer_set_secure(privkey_buffer);
ssh_buffer_add_data(privkey_buffer,
ssh_string_data(privkeys),
ssh_string_len(privkeys));
(uint32_t)ssh_string_len(privkeys));
rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2);
if (rc == SSH_ERROR || checkint1 != checkint2) {

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,205 @@
#include "libssh/ed25519.h"
#include "libssh/buffer.h"
int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey)
{
if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
return SSH_ERROR;
}
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
return SSH_OK;
}
int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey,
ssh_string privkey)
{
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) {
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
return SSH_ERROR;
}
/* In the internal implementation, the private key is the concatenation of
* the private seed with the public key. */
key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
if (key->ed25519_privkey == NULL) {
goto error;
}
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) {
goto error;
}
memcpy(key->ed25519_privkey, ssh_string_data(privkey), 2 * ED25519_KEY_LEN);
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
return SSH_OK;
error:
SAFE_FREE(key->ed25519_privkey);
SAFE_FREE(key->ed25519_pubkey);
return SSH_ERROR;
}
/**
* @internal
*
* @brief Compare ed25519 keys if they are equal.
*
* @param[in] k1 The first key to compare.
*
* @param[in] k2 The second key to compare.
*
* @param[in] what What part or type of the key do you want to compare.
*
* @return 0 if equal, 1 if not.
*/
int
pki_ed25519_key_cmp(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
{
int cmp;
switch (what) {
case SSH_KEY_CMP_PRIVATE:
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
return 1;
}
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
cmp = memcmp(k1->ed25519_privkey,
k2->ed25519_privkey,
2 * ED25519_KEY_LEN);
if (cmp != 0) {
return 1;
}
FALL_THROUGH;
case SSH_KEY_CMP_PUBLIC:
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
return 1;
}
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
if (cmp != 0) {
return 1;
}
break;
case SSH_KEY_CMP_CERTIFICATE:
/* handled globally */
return 1;
}
return 0;
}
/**
* @internal
*
* @brief Duplicate an Ed25519 key
*
* @param[out] new Pre-initialized ssh_key structure
*
* @param[in] key Key to copy
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key)
{
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
if (key->ed25519_privkey != NULL) {
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
if (new_key->ed25519_privkey == NULL) {
return SSH_ERROR;
}
memcpy(new_key->ed25519_privkey,
key->ed25519_privkey,
2 * ED25519_KEY_LEN);
}
if (key->ed25519_pubkey != NULL) {
new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (new_key->ed25519_pubkey == NULL) {
SAFE_FREE(new_key->ed25519_privkey);
return SSH_ERROR;
}
memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
}
return SSH_OK;
}
/**
* @internal
*
* @brief Outputs an Ed25519 public key in a blob buffer.
*
* @param[out] buffer Output buffer
*
* @param[in] key Key to output
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
{
int rc;
if (key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dP",
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN,
key->ed25519_pubkey);
return rc;
}
/** @internal
* @brief exports a ed25519 private key to a string blob.
* @param[in] privkey private key to convert
* @param[out] buffer buffer to write the blob in.
* @returns SSH_OK on success
*/
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey)
{
int rc;
if (privkey->type != SSH_KEYTYPE_ED25519) {
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
return SSH_ERROR;
}
if (privkey->ed25519_privkey == NULL || privkey->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dPdPP",
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN,
privkey->ed25519_pubkey,
(uint32_t)(2 * ED25519_KEY_LEN),
(size_t)ED25519_KEY_LEN,
privkey->ed25519_privkey,
(size_t)ED25519_KEY_LEN,
privkey->ed25519_pubkey);
return rc;
}
int pki_key_generate_ed25519(ssh_key key)
{
int rc;

View File

@@ -27,213 +27,6 @@
#include "libssh/pki_priv.h"
#include "libssh/buffer.h"
int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey,
ssh_string privkey)
{
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
{
SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len");
return SSH_ERROR;
}
#ifdef HAVE_LIBCRYPTO
/* In OpenSSL implementation, the private key is the original private seed,
* without the public key. */
key->ed25519_privkey = malloc(ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation of
* the private seed with the public key. */
key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
#endif
if (key->ed25519_privkey == NULL) {
goto error;
}
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) {
goto error;
}
#ifdef HAVE_LIBCRYPTO
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
ED25519_KEY_LEN);
#else
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
2 * ED25519_KEY_LEN);
#endif
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
ED25519_KEY_LEN);
return SSH_OK;
error:
SAFE_FREE(key->ed25519_privkey);
SAFE_FREE(key->ed25519_pubkey);
return SSH_ERROR;
}
/**
* @internal
*
* @brief Compare ed25519 keys if they are equal.
*
* @param[in] k1 The first key to compare.
*
* @param[in] k2 The second key to compare.
*
* @param[in] what What part or type of the key do you want to compare.
*
* @return 0 if equal, 1 if not.
*/
int pki_ed25519_key_cmp(const ssh_key k1,
const ssh_key k2,
enum ssh_keycmp_e what)
{
int cmp;
switch(what) {
case SSH_KEY_CMP_PRIVATE:
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
return 1;
}
#ifdef HAVE_LIBCRYPTO
/* In OpenSSL implementation, the private key is the original private
* seed, without the public key. */
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey,
2 * ED25519_KEY_LEN);
#endif
if (cmp != 0) {
return 1;
}
FALL_THROUGH;
case SSH_KEY_CMP_PUBLIC:
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
return 1;
}
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
if (cmp != 0) {
return 1;
}
break;
case SSH_KEY_CMP_CERTIFICATE:
/* handled globally */
return 1;
}
return 0;
}
/**
* @internal
*
* @brief Duplicate an Ed25519 key
*
* @param[out] new Pre-initialized ssh_key structure
*
* @param[in] key Key to copy
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key)
{
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
if (key->ed25519_privkey != NULL) {
#ifdef HAVE_LIBCRYPTO
/* In OpenSSL implementation, the private key is the original private
* seed, without the public key. */
new_key->ed25519_privkey = malloc(ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
#endif
if (new_key->ed25519_privkey == NULL) {
return SSH_ERROR;
}
#ifdef HAVE_LIBCRYPTO
memcpy(new_key->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN);
#else
memcpy(new_key->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN);
#endif
}
if (key->ed25519_pubkey != NULL) {
new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (new_key->ed25519_pubkey == NULL) {
SAFE_FREE(new_key->ed25519_privkey);
return SSH_ERROR;
}
memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
}
return SSH_OK;
}
/**
* @internal
*
* @brief Outputs an Ed25519 public key in a blob buffer.
*
* @param[out] buffer Output buffer
*
* @param[in] key Key to output
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
{
int rc;
if (key->ed25519_pubkey == NULL){
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dP",
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
return rc;
}
/** @internal
* @brief exports a ed25519 private key to a string blob.
* @param[in] privkey private key to convert
* @param[out] buffer buffer to write the blob in.
* @returns SSH_OK on success
*/
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey)
{
int rc;
if (privkey->type != SSH_KEYTYPE_ED25519) {
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
return SSH_ERROR;
}
if (privkey->ed25519_privkey == NULL ||
privkey->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dPdPP",
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey,
(uint32_t)(2 * ED25519_KEY_LEN),
(size_t)ED25519_KEY_LEN, privkey->ed25519_privkey,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey);
return rc;
}
/**
* @internal
*

File diff suppressed because it is too large Load Diff

View File

@@ -380,19 +380,11 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
mbedtls_mpi Q;
#endif
new = ssh_key_new();
new = pki_key_dup_common_init(key, demote);
if (new == NULL) {
return NULL;
}
new->type = key->type;
new->type_c = key->type_c;
if (demote) {
new->flags = SSH_KEY_FLAG_PUBLIC;
} else {
new->flags = key->flags;
}
#if MBEDTLS_VERSION_MAJOR > 2
mbedtls_mpi_init(&N);
mbedtls_mpi_init(&E);
@@ -512,6 +504,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521:
case SSH_KEYTYPE_SK_ECDSA:
new->ecdsa_nid = key->ecdsa_nid;
new->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
@@ -522,7 +515,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
mbedtls_ecdsa_init(new->ecdsa);
if (demote && ssh_key_is_private(key)) {
if ((demote && ssh_key_is_private(key)) ||
is_sk_key_type(key->type)) {
rc = mbedtls_ecp_copy(&new->ecdsa->MBEDTLS_PRIVATE(Q),
&key->ecdsa->MBEDTLS_PRIVATE(Q));
if (rc != 0) {
@@ -540,6 +534,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
break;
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
rc = pki_ed25519_key_dup(new, key);
if (rc != SSH_OK) {
goto fail;
@@ -768,7 +763,8 @@ int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what)
goto cleanup;
}
if (what == SSH_KEY_CMP_PRIVATE) {
if (what == SSH_KEY_CMP_PRIVATE &&
k1->type != SSH_KEYTYPE_SK_ECDSA) {
if (mbedtls_mpi_cmp_mpi(&ecdsa1->MBEDTLS_PRIVATE(d),
&ecdsa2->MBEDTLS_PRIVATE(d)))
{
@@ -864,7 +860,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 +873,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 +913,260 @@ 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 && key->type != SSH_KEYTYPE_SK_ECDSA) {
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 (type == SSH_KEY_PRIVATE &&
key->type == SSH_KEYTYPE_SK_ECDSA) {
rc = pki_buffer_pack_sk_priv_data(buffer, key);
if (rc != SSH_OK) {
goto out;
}
} else if (type == SSH_KEY_PUBLIC &&
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;
goto out;
}
}
break;
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
if (type == SSH_KEY_PUBLIC) {
} else {
if (key->type == SSH_KEYTYPE_SK_ED25519) {
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
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;
}
rc = pki_buffer_pack_sk_priv_data(buffer, key);
if (rc == SSH_ERROR) {
goto out;
}
} else {
rc = pki_ed25519_private_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
goto out;
}
}
break;
default:
goto fail;
}
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)
@@ -1249,6 +1234,11 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
case SSH_KEYTYPE_ED25519:
sig_blob = pki_ed25519_signature_to_blob(sig);
break;
case SSH_KEYTYPE_SK_ECDSA:
case SSH_KEYTYPE_SK_ED25519:
/* For SK keys, signature data is already in raw_sig */
sig_blob = ssh_string_copy(sig->raw_sig);
break;
default:
SSH_LOG(SSH_LOG_TRACE, "Unknown signature key type: %s",
sig->type_c);
@@ -1832,7 +1822,6 @@ int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
mbedtls_ecp_point Q;
key->ecdsa_nid = nid;
key->type_c = pki_key_ecdsa_nid_to_name(nid);
key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
if (key->ecdsa == NULL) {
@@ -1900,7 +1889,6 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
mbedtls_ecp_point Q;
key->ecdsa_nid = nid;
key->type_c = pki_key_ecdsa_nid_to_name(nid);
key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
if (key->ecdsa == NULL) {

View File

@@ -61,24 +61,24 @@
*/
struct ssh_poll_handle_struct {
ssh_poll_ctx ctx;
ssh_session session;
union {
socket_t fd;
size_t idx;
} x;
short events;
uint32_t lock_cnt;
ssh_poll_callback cb;
void *cb_data;
ssh_poll_ctx ctx;
ssh_session session;
union {
socket_t fd;
size_t idx;
} x;
short events;
uint32_t lock_cnt;
ssh_poll_callback cb;
void *cb_data;
};
struct ssh_poll_ctx_struct {
ssh_poll_handle *pollptrs;
ssh_pollfd_t *pollfds;
size_t polls_allocated;
size_t polls_used;
size_t chunk_size;
ssh_poll_handle *pollptrs;
ssh_pollfd_t *pollfds;
size_t polls_allocated;
size_t polls_used;
size_t chunk_size;
};
#ifdef HAVE_POLL
@@ -96,7 +96,7 @@ void ssh_poll_cleanup(void)
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout)
{
return poll((struct pollfd *) fds, nfds, timeout);
return poll((struct pollfd *)fds, nfds, timeout);
}
#else /* HAVE_POLL */
@@ -249,14 +249,15 @@ static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout)
}
#endif
// we use the readfds to get POLLHUP and POLLERR, which are provided even when not requested
FD_SET (fds[i].fd, &readfds);
// we use the readfds to get POLLHUP and POLLERR, which are provided
// even when not requested
FD_SET(fds[i].fd, &readfds);
if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
FD_SET (fds[i].fd, &writefds);
FD_SET(fds[i].fd, &writefds);
}
if (fds[i].events & (POLLPRI | POLLRDBAND)) {
FD_SET (fds[i].fd, &exceptfds);
FD_SET(fds[i].fd, &exceptfds);
}
if (fds[i].fd > max_fd) {
@@ -297,11 +298,12 @@ static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout)
fds[i].revents = 0;
if (FD_ISSET(fds[i].fd, &readfds)) {
fds[i].revents = bsd_socket_compute_revents(fds[i].fd,
fds[i].events);
fds[i].revents =
bsd_socket_compute_revents(fds[i].fd, fds[i].events);
}
if (FD_ISSET(fds[i].fd, &writefds)) {
fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
fds[i].revents |=
fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
}
if (FD_ISSET(fds[i].fd, &exceptfds)) {
@@ -319,22 +321,26 @@ static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout)
return rc;
}
void ssh_poll_init(void) {
void ssh_poll_init(void)
{
ssh_poll_emu = bsd_poll;
}
void ssh_poll_cleanup(void) {
void ssh_poll_cleanup(void)
{
ssh_poll_emu = bsd_poll;
}
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout)
{
return (ssh_poll_emu)(fds, nfds, timeout);
}
#endif /* HAVE_POLL */
/**
* @brief Allocate a new poll object, which could be used within a poll context.
* @brief Allocate a new poll object, which could be used within a poll
* context.
*
* @param[in] fd Socket that will be polled.
* @param[in] events Poll events that will be monitored for the socket.
@@ -354,7 +360,7 @@ int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
ssh_poll_handle
ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb, void *userdata)
{
ssh_poll_handle p;
ssh_poll_handle p = NULL;
p = malloc(sizeof(struct ssh_poll_handle_struct));
if (p == NULL) {
@@ -370,7 +376,6 @@ ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb, void *userdata)
return p;
}
/**
* @brief Free a poll object.
*
@@ -433,8 +438,8 @@ void ssh_poll_set_events(ssh_poll_handle p, short events)
}
/**
* @brief Set the file descriptor of a poll object. The FD will also be propagated
* to an associated poll context.
* @brief Set the file descriptor of a poll object. The FD will also be
* propagated to an associated poll context.
*
* @param p Pointer to an already allocated poll object.
* @param fd New file descriptor.
@@ -496,7 +501,9 @@ socket_t ssh_poll_get_fd(ssh_poll_handle p)
* @param userdata Userdata to be passed to the callback function. NULL if
* not needed.
*/
void ssh_poll_set_callback(ssh_poll_handle p, ssh_poll_callback cb, void *userdata)
void ssh_poll_set_callback(ssh_poll_handle p,
ssh_poll_callback cb,
void *userdata)
{
if (cb != NULL) {
p->cb = cb;
@@ -542,7 +549,7 @@ ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size)
void ssh_poll_ctx_free(ssh_poll_ctx ctx)
{
if (ctx->polls_allocated > 0) {
while (ctx->polls_used > 0){
while (ctx->polls_used > 0) {
ssh_poll_handle p = ctx->pollptrs[0];
/*
* The free function calls ssh_poll_ctx_remove() and decrements
@@ -560,29 +567,38 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx)
static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size)
{
ssh_poll_handle *pollptrs = NULL;
ssh_pollfd_t *pollfds = NULL;
ssh_poll_handle *pollptrs = NULL;
ssh_pollfd_t *pollfds = NULL;
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * new_size);
if (pollptrs == NULL) {
return -1;
}
ctx->pollptrs = pollptrs;
pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
if (pollfds == NULL) {
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * ctx->polls_allocated);
pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * new_size);
if (pollptrs == NULL) {
return -1;
/* Fail, but keep the old value to be freed later */
return SSH_ERROR;
}
ctx->pollptrs = pollptrs;
return -1;
}
ctx->pollfds = pollfds;
ctx->polls_allocated = new_size;
pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
if (pollfds == NULL) {
if (ctx->polls_allocated == 0) {
/* This was initial allocation -- just free what we allocated above
* and fail */
SAFE_FREE(ctx->pollptrs);
return SSH_ERROR;
}
/* Try to realloc the pollptrs back to the original size */
pollptrs = realloc(ctx->pollptrs,
sizeof(ssh_poll_handle) * ctx->polls_allocated);
if (pollptrs == NULL) {
return SSH_ERROR;
}
ctx->pollptrs = pollptrs;
return SSH_ERROR;
}
return 0;
ctx->pollfds = pollfds;
ctx->polls_allocated = new_size;
return SSH_OK;
}
/**
@@ -595,27 +611,27 @@ static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size)
*/
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p)
{
socket_t fd;
socket_t fd;
if (p->ctx != NULL) {
/* already attached to a context */
return -1;
}
if (p->ctx != NULL) {
/* already attached to a context */
return -1;
}
if (ctx->polls_used == ctx->polls_allocated &&
ssh_poll_ctx_resize(ctx, ctx->polls_allocated + ctx->chunk_size) < 0) {
return -1;
}
if (ctx->polls_used == ctx->polls_allocated &&
ssh_poll_ctx_resize(ctx, ctx->polls_allocated + ctx->chunk_size) < 0) {
return -1;
}
fd = p->x.fd;
p->x.idx = ctx->polls_used++;
ctx->pollptrs[p->x.idx] = p;
ctx->pollfds[p->x.idx].fd = fd;
ctx->pollfds[p->x.idx].events = p->events;
ctx->pollfds[p->x.idx].revents = 0;
p->ctx = ctx;
fd = p->x.fd;
p->x.idx = ctx->polls_used++;
ctx->pollptrs[p->x.idx] = p;
ctx->pollfds[p->x.idx].fd = fd;
ctx->pollfds[p->x.idx].events = p->events;
ctx->pollfds[p->x.idx].revents = 0;
p->ctx = ctx;
return 0;
return 0;
}
/**
@@ -626,20 +642,17 @@ int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p)
*
* @return 0 on success, < 0 on error
*/
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s)
int ssh_poll_ctx_add_socket(ssh_poll_ctx ctx, ssh_socket s)
{
ssh_poll_handle p = NULL;
int ret;
p = ssh_socket_get_poll_handle(s);
if (p == NULL) {
return -1;
}
ret = ssh_poll_ctx_add(ctx,p);
return ret;
return ssh_poll_ctx_add(ctx, p);
}
/**
* @brief Remove a poll object from a poll context.
*
@@ -648,25 +661,25 @@ int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s)
*/
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p)
{
size_t i;
size_t i;
i = p->x.idx;
p->x.fd = ctx->pollfds[i].fd;
p->ctx = NULL;
i = p->x.idx;
p->x.fd = ctx->pollfds[i].fd;
p->ctx = NULL;
ctx->polls_used--;
ctx->polls_used--;
/* fill the empty poll slot with the last one */
if (ctx->polls_used > 0 && ctx->polls_used != i) {
ctx->pollfds[i] = ctx->pollfds[ctx->polls_used];
ctx->pollptrs[i] = ctx->pollptrs[ctx->polls_used];
ctx->pollptrs[i]->x.idx = i;
}
/* fill the empty poll slot with the last one */
if (ctx->polls_used > 0 && ctx->polls_used != i) {
ctx->pollfds[i] = ctx->pollfds[ctx->polls_used];
ctx->pollptrs[i] = ctx->pollptrs[ctx->polls_used];
ctx->pollptrs[i]->x.idx = i;
}
/* this will always leave at least chunk_size polls allocated */
if (ctx->polls_allocated - ctx->polls_used > ctx->chunk_size) {
ssh_poll_ctx_resize(ctx, ctx->polls_allocated - ctx->chunk_size);
}
/* this will always leave at least chunk_size polls allocated */
if (ctx->polls_allocated - ctx->polls_used > ctx->chunk_size) {
ssh_poll_ctx_resize(ctx, ctx->polls_allocated - ctx->chunk_size);
}
}
/**
@@ -689,7 +702,7 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout)
{
int rc;
size_t i, used;
ssh_poll_handle p;
ssh_poll_handle p = NULL;
socket_t fd;
int revents;
struct ssh_timestamp ts;
@@ -744,7 +757,8 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout)
if (ret == -2) {
return -1;
}
/* the poll was removed, reload the used counter and start again */
/* the poll was removed, reload the used counter and start again
*/
used = ctx->polls_used;
i = 0;
} else {
@@ -770,8 +784,9 @@ int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout)
*/
ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session)
{
if(session->default_poll_ctx != NULL)
if (session->default_poll_ctx != NULL) {
return session->default_poll_ctx;
}
/* 2 is enough for the default one */
session->default_poll_ctx = ssh_poll_ctx_new(2);
return session->default_poll_ctx;
@@ -781,7 +796,7 @@ ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session)
struct ssh_event_fd_wrapper {
ssh_event_callback cb;
void * userdata;
void *userdata;
};
struct ssh_event_struct {
@@ -810,14 +825,14 @@ ssh_event ssh_event_new(void)
ZERO_STRUCTP(event);
event->ctx = ssh_poll_ctx_new(2);
if(event->ctx == NULL) {
if (event->ctx == NULL) {
free(event);
return NULL;
}
#ifdef WITH_SERVER
event->sessions = ssh_list_new();
if(event->sessions == NULL) {
if (event->sessions == NULL) {
ssh_poll_ctx_free(event->ctx);
free(event);
return NULL;
@@ -827,9 +842,10 @@ ssh_event ssh_event_new(void)
return event;
}
static int
ssh_event_fd_wrapper_callback(ssh_poll_handle p, socket_t fd, int revents,
void *userdata)
static int ssh_event_fd_wrapper_callback(ssh_poll_handle p,
socket_t fd,
int revents,
void *userdata)
{
struct ssh_event_fd_wrapper *pw = (struct ssh_event_fd_wrapper *)userdata;
@@ -857,19 +873,22 @@ ssh_event_fd_wrapper_callback(ssh_poll_handle p, socket_t fd, int revents,
* @returns SSH_OK on success
* SSH_ERROR on failure
*/
int
ssh_event_add_fd(ssh_event event, socket_t fd, short events,
ssh_event_callback cb, void *userdata)
int ssh_event_add_fd(ssh_event event,
socket_t fd,
short events,
ssh_event_callback cb,
void *userdata)
{
ssh_poll_handle p;
ssh_poll_handle p = NULL;
struct ssh_event_fd_wrapper *pw = NULL;
int rc;
if(event == NULL || event->ctx == NULL || cb == NULL
|| fd == SSH_INVALID_SOCKET) {
if (event == NULL || event->ctx == NULL || cb == NULL ||
fd == SSH_INVALID_SOCKET) {
return SSH_ERROR;
}
pw = malloc(sizeof(struct ssh_event_fd_wrapper));
if(pw == NULL) {
if (pw == NULL) {
return SSH_ERROR;
}
@@ -878,12 +897,13 @@ ssh_event_add_fd(ssh_event event, socket_t fd, short events,
/* pw is freed by ssh_event_remove_fd */
p = ssh_poll_new(fd, events, ssh_event_fd_wrapper_callback, pw);
if(p == NULL) {
if (p == NULL) {
free(pw);
return SSH_ERROR;
}
if(ssh_poll_ctx_add(event->ctx, p) < 0) {
rc = ssh_poll_ctx_add(event->ctx, p);
if (rc < 0) {
free(pw);
ssh_poll_free(p);
return SSH_ERROR;
@@ -915,7 +935,7 @@ int ssh_event_add_poll(ssh_event event, ssh_poll_handle p)
*/
void ssh_event_remove_poll(ssh_event event, ssh_poll_handle p)
{
ssh_poll_ctx_remove(event->ctx,p);
ssh_poll_ctx_remove(event->ctx, p);
}
/**
@@ -930,15 +950,16 @@ void ssh_event_remove_poll(ssh_event event, ssh_poll_handle p)
*/
int ssh_event_add_session(ssh_event event, ssh_session session)
{
ssh_poll_handle p;
ssh_poll_handle p = NULL;
#ifdef WITH_SERVER
struct ssh_iterator *iterator = NULL;
#endif
int rc;
if(event == NULL || event->ctx == NULL || session == NULL) {
if (event == NULL || event->ctx == NULL || session == NULL) {
return SSH_ERROR;
}
if(session->default_poll_ctx == NULL) {
if (session->default_poll_ctx == NULL) {
return SSH_ERROR;
}
while (session->default_poll_ctx->polls_used > 0) {
@@ -948,7 +969,10 @@ int ssh_event_add_session(ssh_event event, ssh_session session)
* session->default_poll_ctx->polls_used
*/
ssh_poll_ctx_remove(session->default_poll_ctx, p);
ssh_poll_ctx_add(event->ctx, p);
rc = ssh_poll_ctx_add(event->ctx, p);
if (rc != SSH_OK) {
return rc;
}
/* associate the pollhandler with a session so we can put it back
* at ssh_event_free()
*/
@@ -956,14 +980,14 @@ int ssh_event_add_session(ssh_event event, ssh_session session)
}
#ifdef WITH_SERVER
iterator = ssh_list_get_iterator(event->sessions);
while(iterator != NULL) {
if((ssh_session)iterator->data == session) {
while (iterator != NULL) {
if ((ssh_session)iterator->data == session) {
/* allow only one instance of this session */
return SSH_OK;
}
iterator = iterator->next;
}
if(ssh_list_append(event->sessions, session) == SSH_ERROR) {
if (ssh_list_append(event->sessions, session) == SSH_ERROR) {
return SSH_ERROR;
}
#endif
@@ -1031,17 +1055,17 @@ int ssh_event_remove_fd(ssh_event event, socket_t fd)
register size_t i, used;
int rc = SSH_ERROR;
if(event == NULL || event->ctx == NULL) {
if (event == NULL || event->ctx == NULL) {
return SSH_ERROR;
}
used = event->ctx->polls_used;
for (i = 0; i < used; i++) {
if(fd == event->ctx->pollfds[i].fd) {
if (fd == event->ctx->pollfds[i].fd) {
ssh_poll_handle p = event->ctx->pollptrs[i];
if (p->session != NULL){
/* we cannot free that handle, it's owned by its session */
continue;
if (p->session != NULL) {
/* we cannot free that handle, it's owned by its session */
continue;
}
if (p->cb == ssh_event_fd_wrapper_callback) {
struct ssh_event_fd_wrapper *pw = p->cb_data;
@@ -1075,7 +1099,7 @@ int ssh_event_remove_fd(ssh_event event, socket_t fd)
*/
int ssh_event_remove_session(ssh_event event, ssh_session session)
{
ssh_poll_handle p;
ssh_poll_handle p = NULL;
register size_t i, used;
int rc = SSH_ERROR;
#ifdef WITH_SERVER
@@ -1096,7 +1120,10 @@ int ssh_event_remove_session(ssh_event event, ssh_session session)
*/
ssh_poll_ctx_remove(event->ctx, p);
p->session = NULL;
ssh_poll_ctx_add(session->default_poll_ctx, p);
rc = ssh_poll_ctx_add(session->default_poll_ctx, p);
if (rc != SSH_OK) {
return rc;
}
rc = SSH_OK;
/*
* Restart the loop!
@@ -1104,7 +1131,6 @@ int ssh_event_remove_session(ssh_event event, ssh_session session)
*/
used = event->ctx->polls_used;
i = 0;
}
}
#ifdef WITH_SERVER
@@ -1145,7 +1171,7 @@ int ssh_event_remove_connector(ssh_event event, ssh_connector connector)
void ssh_event_free(ssh_event event)
{
size_t used, i;
ssh_poll_handle p;
ssh_poll_handle p = NULL;
if (event == NULL) {
return;

View File

@@ -230,11 +230,13 @@ static int ssh_server_send_extensions(ssh_session session)
}
rc = ssh_buffer_pack(session->out_buffer,
"bdss",
"bdssss",
SSH2_MSG_EXT_INFO,
1, /* nr. of extensions */
2, /* nr. of extensions */
"server-sig-algs",
hostkey_algorithms);
hostkey_algorithms,
"publickey-hostbound@openssh.com",
"0");
if (rc != SSH_OK) {
goto error;
}
@@ -483,8 +485,8 @@ static size_t callback_receive_banner(const void *data, size_t len, void *user)
ssh_pcap_context_write(session->pcap_ctx,
SSH_PCAP_DIR_IN,
buffer,
i + 1,
i + 1);
(uint32_t)(i + 1),
(uint32_t)(i + 1));
}
#endif
if (buffer[i] == '\r') {
@@ -523,6 +525,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

@@ -26,6 +26,10 @@
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock2.h>
#endif
#include "libssh/priv.h"
#include "libssh/libssh.h"
#include "libssh/crypto.h"
@@ -409,10 +413,10 @@ const char* ssh_get_clientbanner(ssh_session session) {
* @return Returns the server banner string or NULL.
*/
const char* ssh_get_serverbanner(ssh_session session) {
if(!session) {
return NULL;
}
return session->serverbanner;
if (!session) {
return NULL;
}
return session->serverbanner;
}
/**
@@ -429,28 +433,34 @@ const char* ssh_get_kex_algo(ssh_session session) {
}
switch (session->current_crypto->kex_type) {
case SSH_KEX_DH_GROUP1_SHA1:
return "diffie-hellman-group1-sha1";
case SSH_KEX_DH_GROUP14_SHA1:
return "diffie-hellman-group14-sha1";
case SSH_KEX_DH_GROUP14_SHA256:
return "diffie-hellman-group14-sha256";
case SSH_KEX_DH_GROUP16_SHA512:
return "diffie-hellman-group16-sha512";
case SSH_KEX_DH_GROUP18_SHA512:
return "diffie-hellman-group18-sha512";
case SSH_KEX_ECDH_SHA2_NISTP256:
return "ecdh-sha2-nistp256";
case SSH_KEX_ECDH_SHA2_NISTP384:
return "ecdh-sha2-nistp384";
case SSH_KEX_ECDH_SHA2_NISTP521:
return "ecdh-sha2-nistp521";
case SSH_KEX_CURVE25519_SHA256:
return "curve25519-sha256";
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
return "curve25519-sha256@libssh.org";
default:
break;
case SSH_KEX_DH_GROUP1_SHA1:
return "diffie-hellman-group1-sha1";
case SSH_KEX_DH_GROUP14_SHA1:
return "diffie-hellman-group14-sha1";
case SSH_KEX_DH_GROUP14_SHA256:
return "diffie-hellman-group14-sha256";
case SSH_KEX_DH_GROUP16_SHA512:
return "diffie-hellman-group16-sha512";
case SSH_KEX_DH_GROUP18_SHA512:
return "diffie-hellman-group18-sha512";
case SSH_KEX_ECDH_SHA2_NISTP256:
return "ecdh-sha2-nistp256";
case SSH_KEX_ECDH_SHA2_NISTP384:
return "ecdh-sha2-nistp384";
case SSH_KEX_ECDH_SHA2_NISTP521:
return "ecdh-sha2-nistp521";
case SSH_KEX_CURVE25519_SHA256:
return "curve25519-sha256";
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
return "curve25519-sha256@libssh.org";
case SSH_KEX_SNTRUP761X25519_SHA512_OPENSSH_COM:
return "sntrup761x25519-sha512@openssh.com";
#ifdef WITH_GEX
case SSH_KEX_DH_GEX_SHA1:
return "diffie-hellman-group-exchange-sha1";
case SSH_KEX_DH_GEX_SHA256:
return "diffie-hellman-group-exchange-sha256";
#endif /* WITH_GEX */
}
return NULL;
@@ -734,7 +744,10 @@ int ssh_handle_packets(ssh_session session, int timeout)
ssh_set_error_oom(session);
return SSH_ERROR;
}
ssh_poll_ctx_add(ctx, spoll);
rc = ssh_poll_ctx_add(ctx, spoll);
if (rc != SSH_OK) {
return SSH_ERROR;
}
}
if (timeout == SSH_TIMEOUT_USER) {
@@ -936,16 +949,41 @@ int ssh_get_version(ssh_session session) {
* @param user is a pointer to session
*/
void ssh_socket_exception_callback(int code, int errno_code, void *user){
ssh_session session=(ssh_session)user;
ssh_session session = (ssh_session)user;
SSH_LOG(SSH_LOG_RARE,"Socket exception callback: %d (%d)",code, errno_code);
SSH_LOG(SSH_LOG_RARE,
"Socket exception callback: %d (%d)",
code,
errno_code);
session->session_state = SSH_SESSION_STATE_ERROR;
if (errno_code == 0 && code == SSH_SOCKET_EXCEPTION_EOF) {
ssh_set_error(session, SSH_FATAL, "Socket error: disconnected");
#ifdef _WIN32
} else if (errno_code == WSAENETDOWN) {
ssh_set_error(session, SSH_FATAL, "Socket error: network down");
} else if (errno_code == WSAENETUNREACH) {
ssh_set_error(session, SSH_FATAL, "Socket error: network unreachable");
} else if (errno_code == WSAENETRESET) {
ssh_set_error(session, SSH_FATAL, "Socket error: network reset");
} else if (errno_code == WSAECONNABORTED) {
ssh_set_error(session, SSH_FATAL, "Socket error: connection aborted");
} else if (errno_code == WSAECONNRESET) {
ssh_set_error(session,
SSH_FATAL,
"Socket error: connection reset by peer");
} else if (errno_code == WSAETIMEDOUT) {
ssh_set_error(session, SSH_FATAL, "Socket error: connection timed out");
} else if (errno_code == WSAECONNREFUSED) {
ssh_set_error(session, SSH_FATAL, "Socket error: connection refused");
} else if (errno_code == WSAEHOSTUNREACH) {
ssh_set_error(session, SSH_FATAL, "Socket error: host unreachable");
#endif
} else {
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
ssh_set_error(session, SSH_FATAL, "Socket error: %s",
ssh_strerror(errno_code, err_msg, SSH_ERRNO_MSG_MAX));
ssh_set_error(session,
SSH_FATAL,
"Socket error: %s",
ssh_strerror(errno_code, err_msg, SSH_ERRNO_MSG_MAX));
}
session->ssh_connection_callback(session);
@@ -1232,110 +1270,108 @@ int ssh_get_publickey_hash(const ssh_key key,
}
switch (type) {
case SSH_PUBLICKEY_HASH_SHA1:
{
SHACTX ctx = NULL;
case SSH_PUBLICKEY_HASH_SHA1: {
SHACTX ctx = NULL;
h = calloc(1, SHA_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = sha1_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
rc = sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
if (rc != SSH_OK) {
free(h);
sha1_ctx_free(ctx);
goto out;
}
rc = sha1_final(h, ctx);
if (rc != SSH_OK) {
free(h);
goto out;
}
*hlen = SHA_DIGEST_LEN;
h = calloc(1, SHA_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
break;
case SSH_PUBLICKEY_HASH_SHA256:
{
SHA256CTX ctx = NULL;
h = calloc(1, SHA256_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = sha256_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
rc = sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
if (rc != SSH_OK) {
free(h);
sha256_ctx_free(ctx);
goto out;
}
rc = sha256_final(h, ctx);
if (rc != SSH_OK) {
free(h);
goto out;
}
*hlen = SHA256_DIGEST_LEN;
ctx = sha1_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
break;
case SSH_PUBLICKEY_HASH_MD5:
{
MD5CTX ctx = NULL;
/* In FIPS mode, we cannot use MD5 */
if (ssh_fips_mode()) {
SSH_LOG(SSH_LOG_TRACE, "In FIPS mode MD5 is not allowed."
"Try using SSH_PUBLICKEY_HASH_SHA256");
rc = SSH_ERROR;
goto out;
}
h = calloc(1, MD5_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = md5_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
rc = md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
if (rc != SSH_OK) {
free(h);
md5_ctx_free(ctx);
goto out;
}
rc = md5_final(h, ctx);
if (rc != SSH_OK) {
free(h);
goto out;
}
*hlen = MD5_DIGEST_LEN;
rc = sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
if (rc != SSH_OK) {
free(h);
sha1_ctx_free(ctx);
goto out;
}
rc = sha1_final(h, ctx);
if (rc != SSH_OK) {
free(h);
goto out;
}
*hlen = SHA_DIGEST_LEN;
break;
}
case SSH_PUBLICKEY_HASH_SHA256: {
SHA256CTX ctx = NULL;
h = calloc(1, SHA256_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = sha256_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
rc = sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
if (rc != SSH_OK) {
free(h);
sha256_ctx_free(ctx);
goto out;
}
rc = sha256_final(h, ctx);
if (rc != SSH_OK) {
free(h);
goto out;
}
*hlen = SHA256_DIGEST_LEN;
break;
}
case SSH_PUBLICKEY_HASH_MD5: {
MD5CTX ctx = NULL;
/* In FIPS mode, we cannot use MD5 */
if (ssh_fips_mode()) {
SSH_LOG(SSH_LOG_TRACE,
"In FIPS mode MD5 is not allowed."
"Try using SSH_PUBLICKEY_HASH_SHA256");
rc = SSH_ERROR;
goto out;
}
h = calloc(1, MD5_DIGEST_LEN);
if (h == NULL) {
rc = -1;
goto out;
}
ctx = md5_init();
if (ctx == NULL) {
free(h);
rc = -1;
goto out;
}
rc = md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
if (rc != SSH_OK) {
free(h);
md5_ctx_free(ctx);
goto out;
}
rc = md5_final(h, ctx);
if (rc != SSH_OK) {
free(h);
goto out;
}
*hlen = MD5_DIGEST_LEN;
break;
}
default:
rc = -1;
goto out;

1107
src/sftp.c

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,7 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
sftp_session sftp = NULL;
ssh_buffer buffer = NULL;
sftp_aio aio_handle = NULL;
uint32_t id;
uint32_t id, read_len;
int rc;
if (file == NULL ||
@@ -73,10 +73,12 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
return SSH_ERROR;
}
/* Apply a cap on the length a user is allowed to read */
if (len > sftp->limits->max_read_length) {
len = sftp->limits->max_read_length;
}
/* Apply a cap on the length a user is allowed to read
*
* The limits are in theory uint64, but packet contain data length in uint32
* so in practice, the limit will never be larger than UINT32_MAX
*/
read_len = (uint32_t)MIN(sftp->limits->max_read_length, len);
if (aio == NULL) {
ssh_set_error(sftp->session, SSH_FATAL,
@@ -100,7 +102,7 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
id,
file->handle,
file->offset,
len);
read_len);
if (rc != SSH_OK) {
ssh_set_error_oom(sftp->session);
@@ -119,7 +121,7 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
aio_handle->file = file;
aio_handle->id = id;
aio_handle->len = len;
aio_handle->len = read_len;
rc = sftp_packet_write(sftp, SSH_FXP_READ, buffer);
SSH_BUFFER_FREE(buffer);
@@ -129,9 +131,9 @@ ssize_t sftp_aio_begin_read(sftp_file file, size_t len, sftp_aio *aio)
}
/* Assume we read len bytes from the file */
file->offset += len;
file->offset += read_len;
*aio = aio_handle;
return len;
return read_len;
}
ssize_t sftp_aio_wait_read(sftp_aio *aio,
@@ -202,21 +204,15 @@ ssize_t sftp_aio_wait_read(sftp_aio *aio,
}
/* handle an existing request */
while (msg == NULL) {
if (file->nonblocking) {
if (ssh_channel_poll(sftp->channel, 0) == 0) {
/* we cannot block */
return SSH_AGAIN;
}
}
rc = sftp_recv_response_msg(sftp, (*aio)->id, !file->nonblocking, &msg);
if (rc == SSH_ERROR) {
SFTP_AIO_FREE(*aio);
return SSH_ERROR;
}
if (sftp_read_and_dispatch(sftp) < 0) {
/* something nasty has happened */
SFTP_AIO_FREE(*aio);
return SSH_ERROR;
}
msg = sftp_dequeue(sftp, (*aio)->id);
if (rc == SSH_AGAIN) {
/* return without freeing the (*aio) */
return SSH_AGAIN;
}
/*
@@ -315,7 +311,7 @@ ssize_t sftp_aio_begin_write(sftp_file file,
sftp_session sftp = NULL;
ssh_buffer buffer = NULL;
sftp_aio aio_handle = NULL;
uint32_t id;
uint32_t id, write_len;
int rc;
if (file == NULL ||
@@ -341,10 +337,12 @@ ssize_t sftp_aio_begin_write(sftp_file file,
return SSH_ERROR;
}
/* Apply a cap on the length a user is allowed to write */
if (len > sftp->limits->max_write_length) {
len = sftp->limits->max_write_length;
}
/* Apply a cap on the length a user is allowed to write
*
* The limits are in theory uint64, but packet contain data length in uint32
* so in practice, the limit will never be larger than UINT32_MAX
*/
write_len = (uint32_t)MIN(sftp->limits->max_write_length, len);
if (aio == NULL) {
ssh_set_error(sftp->session, SSH_FATAL,
@@ -367,8 +365,9 @@ ssize_t sftp_aio_begin_write(sftp_file file,
id,
file->handle,
file->offset,
len, /* len of datastring */
len, buf);
write_len, /* len of datastring */
(size_t)write_len,
buf);
if (rc != SSH_OK) {
ssh_set_error_oom(sftp->session);
@@ -387,7 +386,7 @@ ssize_t sftp_aio_begin_write(sftp_file file,
aio_handle->file = file;
aio_handle->id = id;
aio_handle->len = len;
aio_handle->len = write_len;
rc = sftp_packet_write(sftp, SSH_FXP_WRITE, buffer);
SSH_BUFFER_FREE(buffer);
@@ -397,9 +396,9 @@ ssize_t sftp_aio_begin_write(sftp_file file,
}
/* Assume we wrote len bytes to the file */
file->offset += len;
file->offset += write_len;
*aio = aio_handle;
return len;
return write_len;
}
ssize_t sftp_aio_wait_write(sftp_aio *aio)
@@ -410,6 +409,7 @@ ssize_t sftp_aio_wait_write(sftp_aio *aio)
sftp_session sftp = NULL;
sftp_message msg = NULL;
sftp_status_message status = NULL;
int rc;
/*
* This function releases the memory of the structure
@@ -446,21 +446,15 @@ ssize_t sftp_aio_wait_write(sftp_aio *aio)
return SSH_ERROR;
}
while (msg == NULL) {
if (file->nonblocking) {
if (ssh_channel_poll(sftp->channel, 0) == 0) {
/* we cannot block */
return SSH_AGAIN;
}
}
rc = sftp_recv_response_msg(sftp, (*aio)->id, !file->nonblocking, &msg);
if (rc == SSH_ERROR) {
SFTP_AIO_FREE(*aio);
return SSH_ERROR;
}
if (sftp_read_and_dispatch(sftp) < 0) {
/* something nasty has happened */
SFTP_AIO_FREE(*aio);
return SSH_ERROR;
}
msg = sftp_dequeue(sftp, (*aio)->id);
if (rc == SSH_AGAIN) {
/* Return without freeing the (*aio) */
return SSH_AGAIN;
}
/*

View File

@@ -418,6 +418,9 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp,
(attr->extended_type = ssh_buffer_get_ssh_string(buf)) &&
(attr->extended_data = ssh_buffer_get_ssh_string(buf))) {
attr->extended_count--;
/* just ignore the extensions -- we can't interpret them */
SSH_STRING_FREE(attr->extended_type);
SSH_STRING_FREE(attr->extended_data);
}
if (attr->extended_count) {
@@ -859,6 +862,94 @@ int sftp_read_and_dispatch(sftp_session sftp)
return 0;
}
int sftp_recv_response_msg(sftp_session sftp,
uint32_t id,
bool blocking,
sftp_message *msg_ptr)
{
sftp_message msg = NULL;
int rc;
if (sftp == NULL) {
return SSH_ERROR;
}
if (msg_ptr == NULL) {
ssh_set_error_invalid(sftp->session);
sftp_set_error(sftp, SSH_FX_FAILURE);
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_PACKET,
"Trying to receive response of request id %" PRIu32 " in %s mode",
id,
blocking ? "blocking" : "non-blocking");
/*
* We deliberately check the queue first for the response before
* polling/blocking on the channel. The reason for this approach is
* explained by the following example (And a similar scenario can occur when
* the async sftp aio API is used, because it provides the control of which
* responses to receive (and in what order) to the user via the
* sftp_aio_wait_*() functions)
*
* Its possible that while this function is trying to receive some
* specific response (based on request id), other responses have already
* arrived (or may arrive) before that specific response on the channel. In
* that case, this function would collect those other responses from the
* channel, add them to the sftp response queue (using
* sftp_read_and_dipatch()) and finally provide the caller with the
* required specific response.
*
* Now, whenever the caller will call this function again to get one of
* those other responses, it won't be on the channel, instead it would be
* present in the queue.
*
* Assuming that no new response ever comes on the channel, if we don't
* check the queue first and instead:
* - (In non blocking mode) poll on the channel, then we'd always get 0
* bytes of data and return SSH_AGAIN.
* - (In blocking mode) wait on the channel, then
* sftp_read_and_dispatch() would block infinitely by default if the
* user has not set any timeout.
*
* Hence checking the queue for the response first and if not found there,
* polling/blocking on the channel is advised.
*/
while (msg == NULL) {
/*
* Before trying to poll/block on the channel for data, probe the queue
* to check whether the response is already present in it.
*/
msg = sftp_dequeue(sftp, id);
if (msg != NULL) {
break;
}
if (!blocking) {
rc = ssh_channel_poll(sftp->channel, 0);
if (rc == SSH_ERROR) {
sftp_set_error(sftp, SSH_FX_FAILURE);
return SSH_ERROR;
}
if (rc == 0) {
/* nothing available and we cannot block */
return SSH_AGAIN;
}
}
rc = sftp_read_and_dispatch(sftp);
if (rc == -1) {
/* something nasty has happened */
return SSH_ERROR;
}
}
*msg_ptr = msg;
return SSH_OK;
}
sftp_status_message parse_status_msg(sftp_message msg)
{
sftp_status_message status = NULL;

View File

@@ -787,8 +787,8 @@ stat_to_filexfer_attrib(const struct stat *z_st, struct sftp_attributes_struct *
z_attr->permissions = z_st->st_mode;
z_attr->flags |= (uint32_t)SSH_FILEXFER_ATTR_ACMODTIME;
z_attr->atime = z_st->st_atime;
z_attr->mtime = z_st->st_mtime;
z_attr->atime = (uint32_t)z_st->st_atime;
z_attr->mtime = (uint32_t)z_st->st_mtime;
}
static void
@@ -820,7 +820,7 @@ struct sftp_handle
char *name;
};
SSH_SFTP_CALLBACK(process_unsupposed);
SSH_SFTP_CALLBACK(process_unsupported);
SSH_SFTP_CALLBACK(process_open);
SSH_SFTP_CALLBACK(process_read);
SSH_SFTP_CALLBACK(process_write);
@@ -844,9 +844,9 @@ const struct sftp_message_handler message_handlers[] = {
{"read", NULL, SSH_FXP_READ, process_read},
{"write", NULL, SSH_FXP_WRITE, process_write},
{"lstat", NULL, SSH_FXP_LSTAT, process_lstat},
{"fstat", NULL, SSH_FXP_FSTAT, process_unsupposed},
{"fstat", NULL, SSH_FXP_FSTAT, process_unsupported},
{"setstat", NULL, SSH_FXP_SETSTAT, process_setstat},
{"fsetstat", NULL, SSH_FXP_FSETSTAT, process_unsupposed},
{"fsetstat", NULL, SSH_FXP_FSETSTAT, process_unsupported},
{"opendir", NULL, SSH_FXP_OPENDIR, process_opendir},
{"readdir", NULL, SSH_FXP_READDIR, process_readdir},
{"remove", NULL, SSH_FXP_REMOVE, process_remove},
@@ -854,7 +854,7 @@ const struct sftp_message_handler message_handlers[] = {
{"rmdir", NULL, SSH_FXP_RMDIR, process_rmdir},
{"realpath", NULL, SSH_FXP_REALPATH, process_realpath},
{"stat", NULL, SSH_FXP_STAT, process_stat},
{"rename", NULL, SSH_FXP_RENAME, process_unsupposed},
{"rename", NULL, SSH_FXP_RENAME, process_unsupported},
{"readlink", NULL, SSH_FXP_READLINK, process_readlink},
{"symlink", NULL, SSH_FXP_SYMLINK, process_symlink},
{"init", NULL, SSH_FXP_INIT, sftp_reply_version},
@@ -882,17 +882,26 @@ process_open(sftp_client_message client_msg)
SSH_LOG(SSH_LOG_PROTOCOL, "Processing open: filename %s, mode=0%o" PRIu32,
filename, mode);
if (((msg_flag & (uint32_t)SSH_FXF_READ) == SSH_FXF_READ) &&
((msg_flag & (uint32_t)SSH_FXF_WRITE) == SSH_FXF_WRITE)) {
file_flag = O_RDWR; // file must exist
if ((msg_flag & (uint32_t)SSH_FXF_CREAT) == SSH_FXF_CREAT)
file_flag |= O_CREAT;
} else if ((msg_flag & (uint32_t)SSH_FXF_WRITE) == SSH_FXF_WRITE) {
file_flag = O_WRONLY;
if ((msg_flag & (uint32_t)SSH_FXF_APPEND) == SSH_FXF_APPEND)
if ((msg_flag & (uint32_t)SSH_FXF_WRITE) == SSH_FXF_WRITE) {
if ((msg_flag & (uint32_t)SSH_FXF_READ) == SSH_FXF_READ) {
/* Both read and write */
file_flag = O_RDWR;
} else {
/* Only write */
file_flag = O_WRONLY;
}
if ((msg_flag & (uint32_t)SSH_FXF_APPEND) == SSH_FXF_APPEND) {
file_flag |= O_APPEND;
if ((msg_flag & (uint32_t)SSH_FXF_CREAT) == SSH_FXF_CREAT)
}
if ((msg_flag & (uint32_t)SSH_FXF_CREAT) == SSH_FXF_CREAT) {
file_flag |= O_CREAT;
}
if ((msg_flag & (uint32_t)SSH_FXF_TRUNC) == SSH_FXF_TRUNC) {
file_flag |= O_TRUNC;
}
} else if ((msg_flag & (uint32_t)SSH_FXF_READ) == SSH_FXF_READ) {
file_flag = O_RDONLY;
} else {
@@ -1632,7 +1641,7 @@ process_remove(sftp_client_message client_msg)
}
static int
process_unsupposed(sftp_client_message client_msg)
process_unsupported(sftp_client_message client_msg)
{
sftp_reply_status(client_msg, SSH_FX_OP_UNSUPPORTED,
"Operation not supported");

522
src/sntrup761.c Normal file
View File

@@ -0,0 +1,522 @@
/*
* sntrup761.c - SNTRUP761x25519 ECDH functions for key exchange
* sntrup761x25519-sha512@openssh.com - based on curve25519.c.
*
* This file is part of the SSH Library
*
* Copyright (c) 2013 by Aris Adamantiadis <aris@badcode.be>
* Copyright (c) 2023 Simon Josefsson <simon@josefsson.org>
* Copyright (c) 2025 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, version 2.1 of the License.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/sntrup761.h"
#ifdef HAVE_SNTRUP761
#include "libssh/bignum.h"
#include "libssh/buffer.h"
#include "libssh/crypto.h"
#include "libssh/dh.h"
#include "libssh/pki.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/ssh2.h"
void crypto_hash_sha512(unsigned char *out,
const unsigned char *in,
unsigned long long inlen)
{
sha512(in, inlen, out);
}
#ifndef HAVE_LIBGCRYPT
static void crypto_random(void *ctx, size_t length, uint8_t *dst)
{
int *err = ctx;
*err = ssh_get_random(dst, length, 1);
}
#endif /* HAVE_LIBGCRYPT */
static SSH_PACKET_CALLBACK(ssh_packet_client_sntrup761x25519_reply);
static ssh_packet_callback dh_client_callbacks[] = {
ssh_packet_client_sntrup761x25519_reply,
};
static struct ssh_packet_callbacks_struct ssh_sntrup761x25519_client_callbacks =
{
.start = SSH2_MSG_KEX_ECDH_REPLY,
.n_callbacks = 1,
.callbacks = dh_client_callbacks,
.user = NULL,
};
static int ssh_sntrup761x25519_init(ssh_session session)
{
int rc;
rc = ssh_curve25519_init(session);
if (rc != SSH_OK) {
return rc;
}
if (!session->server) {
#ifdef HAVE_LIBGCRYPT
gcry_error_t err;
err = gcry_kem_keypair(GCRY_KEM_SNTRUP761,
session->next_crypto->sntrup761_client_pubkey,
SNTRUP761_PUBLICKEY_SIZE,
session->next_crypto->sntrup761_privkey,
SNTRUP761_SECRETKEY_SIZE);
if (err) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate sntrup761 key: %s",
gpg_strerror(err));
return SSH_ERROR;
}
#else
sntrup761_keypair(session->next_crypto->sntrup761_client_pubkey,
session->next_crypto->sntrup761_privkey,
&rc,
crypto_random);
if (rc != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to generate sntrup761 key: PRNG failure");
return SSH_ERROR;
}
#endif /* HAVE_LIBGCRYPT */
}
return SSH_OK;
}
/** @internal
* @brief Starts sntrup761x25519-sha512@openssh.com key exchange
*/
int ssh_client_sntrup761x25519_init(ssh_session session)
{
int rc;
rc = ssh_sntrup761x25519_init(session);
if (rc != SSH_OK) {
return rc;
}
rc = ssh_buffer_pack(session->out_buffer,
"bdPP",
SSH2_MSG_KEX_ECDH_INIT,
CURVE25519_PUBKEY_SIZE + SNTRUP761_PUBLICKEY_SIZE,
(size_t)SNTRUP761_PUBLICKEY_SIZE,
session->next_crypto->sntrup761_client_pubkey,
(size_t)CURVE25519_PUBKEY_SIZE,
session->next_crypto->curve25519_client_pubkey);
if (rc != SSH_OK) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
/* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_sntrup761x25519_client_callbacks);
session->dh_handshake_state = DH_STATE_INIT_SENT;
rc = ssh_packet_send(session);
return rc;
}
void ssh_client_sntrup761x25519_remove_callbacks(ssh_session session)
{
ssh_packet_remove_callbacks(session, &ssh_sntrup761x25519_client_callbacks);
}
static int ssh_sntrup761x25519_build_k(ssh_session session)
{
unsigned char ssk[SNTRUP761_SIZE + CURVE25519_PUBKEY_SIZE];
unsigned char *k = ssk + SNTRUP761_SIZE;
unsigned char hss[SHA512_DIGEST_LEN];
int rc;
rc = ssh_curve25519_create_k(session, k);
if (rc != SSH_OK) {
return SSH_ERROR;
}
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("Curve25519 shared secret", k, CURVE25519_PUBKEY_SIZE);
#endif
#ifdef HAVE_LIBGCRYPT
if (session->server) {
gcry_error_t err;
err = gcry_kem_encap(GCRY_KEM_SNTRUP761,
session->next_crypto->sntrup761_client_pubkey,
SNTRUP761_PUBLICKEY_SIZE,
session->next_crypto->sntrup761_ciphertext,
SNTRUP761_CIPHERTEXT_SIZE,
ssk,
SNTRUP761_SIZE,
NULL,
0);
if (err) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to encapsulate sntrup761 shared secret: %s",
gpg_strerror(err));
return SSH_ERROR;
}
} else {
gcry_error_t err;
err = gcry_kem_decap(GCRY_KEM_SNTRUP761,
session->next_crypto->sntrup761_privkey,
SNTRUP761_SECRETKEY_SIZE,
session->next_crypto->sntrup761_ciphertext,
SNTRUP761_CIPHERTEXT_SIZE,
ssk,
SNTRUP761_SIZE,
NULL,
0);
if (err) {
SSH_LOG(SSH_LOG_TRACE,
"Failed to decapsulate sntrup761 shared secret: %s",
gpg_strerror(err));
return SSH_ERROR;
}
}
#else
if (session->server) {
sntrup761_enc(session->next_crypto->sntrup761_ciphertext,
ssk,
session->next_crypto->sntrup761_client_pubkey,
&rc,
crypto_random);
if (rc != 1) {
return SSH_ERROR;
}
} else {
sntrup761_dec(ssk,
session->next_crypto->sntrup761_ciphertext,
session->next_crypto->sntrup761_privkey);
}
#endif /* HAVE_LIBGCRYPT */
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("server cipher text",
session->next_crypto->sntrup761_ciphertext,
SNTRUP761_CIPHERTEXT_SIZE);
ssh_log_hexdump("kem key", ssk, SNTRUP761_SIZE);
#endif
sha512(ssk, sizeof ssk, hss);
bignum_bin2bn(hss, sizeof hss, &session->next_crypto->shared_secret);
if (session->next_crypto->shared_secret == NULL) {
return SSH_ERROR;
}
#ifdef DEBUG_CRYPTO
ssh_print_bignum("Shared secret key", session->next_crypto->shared_secret);
#endif
return 0;
}
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
*/
static SSH_PACKET_CALLBACK(ssh_packet_client_sntrup761x25519_reply)
{
ssh_string q_s_string = NULL;
ssh_string pubkey_blob = NULL;
ssh_string signature = NULL;
int rc;
(void)type;
(void)user;
ssh_client_sntrup761x25519_remove_callbacks(session);
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "No public key in packet");
goto error;
}
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
SSH_STRING_FREE(pubkey_blob);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL, "Failed to import next public key");
goto error;
}
q_s_string = ssh_buffer_get_ssh_string(packet);
if (q_s_string == NULL) {
ssh_set_error(session, SSH_FATAL, "No sntrup761x25519 Q_S in packet");
goto error;
}
if (ssh_string_len(q_s_string) != (SNTRUP761_CIPHERTEXT_SIZE + CURVE25519_PUBKEY_SIZE)) {
ssh_set_error(session,
SSH_FATAL,
"Incorrect size for server sntrup761x25519 ciphertext+key: %d",
(int)ssh_string_len(q_s_string));
SSH_STRING_FREE(q_s_string);
goto error;
}
memcpy(session->next_crypto->sntrup761_ciphertext,
ssh_string_data(q_s_string),
SNTRUP761_CIPHERTEXT_SIZE);
memcpy(session->next_crypto->curve25519_server_pubkey,
(char *)ssh_string_data(q_s_string) + SNTRUP761_CIPHERTEXT_SIZE,
CURVE25519_PUBKEY_SIZE);
SSH_STRING_FREE(q_s_string);
signature = ssh_buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature = NULL; /* ownership changed */
/* TODO: verify signature now instead of waiting for NEWKEYS */
if (ssh_sntrup761x25519_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent");
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
return SSH_PACKET_USED;
error:
session->session_state = SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
}
#ifdef WITH_SERVER
static SSH_PACKET_CALLBACK(ssh_packet_server_sntrup761x25519_init);
static ssh_packet_callback dh_server_callbacks[] = {
ssh_packet_server_sntrup761x25519_init,
};
static struct ssh_packet_callbacks_struct ssh_sntrup761x25519_server_callbacks =
{
.start = SSH2_MSG_KEX_ECDH_INIT,
.n_callbacks = 1,
.callbacks = dh_server_callbacks,
.user = NULL,
};
/** @internal
* @brief sets up the sntrup761x25519-sha512@openssh.com kex callbacks
*/
void ssh_server_sntrup761x25519_init(ssh_session session)
{
/* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_sntrup761x25519_server_callbacks);
}
/** @brief Parse a SSH_MSG_KEXDH_INIT packet (server) and send a
* SSH_MSG_KEXDH_REPLY
*/
static SSH_PACKET_CALLBACK(ssh_packet_server_sntrup761x25519_init)
{
/* ECDH/SNTRUP761 keys */
ssh_string q_c_string = NULL;
ssh_string q_s_string = NULL;
ssh_string server_pubkey_blob = NULL;
/* SSH host keys (rsa, ed25519 and ecdsa) */
ssh_key privkey = NULL;
enum ssh_digest_e digest = SSH_DIGEST_AUTO;
ssh_string sig_blob = NULL;
int rc;
(void)type;
(void)user;
ssh_packet_remove_callbacks(session, &ssh_sntrup761x25519_server_callbacks);
/* Extract the client pubkey from the init packet */
q_c_string = ssh_buffer_get_ssh_string(packet);
if (q_c_string == NULL) {
ssh_set_error(session, SSH_FATAL, "No sntrup761x25519 Q_C in packet");
goto error;
}
if (ssh_string_len(q_c_string) != (SNTRUP761_PUBLICKEY_SIZE + CURVE25519_PUBKEY_SIZE)) {
ssh_set_error(session,
SSH_FATAL,
"Incorrect size for server sntrup761x25519 public key: %zu",
ssh_string_len(q_c_string));
goto error;
}
memcpy(session->next_crypto->sntrup761_client_pubkey,
ssh_string_data(q_c_string),
SNTRUP761_PUBLICKEY_SIZE);
memcpy(session->next_crypto->curve25519_client_pubkey,
((char *)ssh_string_data(q_c_string)) + SNTRUP761_PUBLICKEY_SIZE,
CURVE25519_PUBKEY_SIZE);
SSH_STRING_FREE(q_c_string);
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("client public key sntrup761",
session->next_crypto->sntrup761_client_pubkey,
SNTRUP761_PUBLICKEY_SIZE);
ssh_log_hexdump("client public key c25519",
session->next_crypto->curve25519_client_pubkey,
CURVE25519_PUBKEY_SIZE);
#endif
/* Build server's key pair */
rc = ssh_sntrup761x25519_init(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Failed to generate sntrup761 keys");
goto error;
}
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_REPLY);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
/* build k and session_id */
rc = ssh_sntrup761x25519_build_k(session);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error;
}
/* privkey is not allocated */
rc = ssh_get_key_params(session, &privkey, &digest);
if (rc == SSH_ERROR) {
goto error;
}
rc = ssh_make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
goto error;
}
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != 0) {
ssh_set_error(session, SSH_FATAL, "Could not export server public key");
goto error;
}
/* add host's public key */
rc = ssh_buffer_add_ssh_string(session->out_buffer, server_pubkey_blob);
SSH_STRING_FREE(server_pubkey_blob);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
/* add ecdh public key */
rc = ssh_buffer_add_u32(session->out_buffer,
ntohl(SNTRUP761_CIPHERTEXT_SIZE
+ CURVE25519_PUBKEY_SIZE));
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
rc = ssh_buffer_add_data(session->out_buffer,
session->next_crypto->sntrup761_ciphertext,
SNTRUP761_CIPHERTEXT_SIZE);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
rc = ssh_buffer_add_data(session->out_buffer,
session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("server public key c25519",
session->next_crypto->curve25519_server_pubkey,
CURVE25519_PUBKEY_SIZE);
#endif
/* add signature blob */
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey, digest);
if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
goto error;
}
rc = ssh_buffer_add_ssh_string(session->out_buffer, sig_blob);
SSH_STRING_FREE(sig_blob);
if (rc < 0) {
ssh_set_error_oom(session);
goto error;
}
#ifdef DEBUG_CRYPTO
ssh_log_hexdump("ECDH_REPLY:",
ssh_buffer_get(session->out_buffer),
ssh_buffer_get_len(session->out_buffer));
#endif
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEX_ECDH_REPLY sent");
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
return SSH_ERROR;
}
/* Send the MSG_NEWKEYS */
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
goto error;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent");
return SSH_PACKET_USED;
error:
SSH_STRING_FREE(q_c_string);
SSH_STRING_FREE(q_s_string);
ssh_buffer_reinit(session->out_buffer);
session->session_state = SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
}
#endif /* WITH_SERVER */
#endif /* HAVE_SNTRUP761 */

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