Compare commits

..

72 Commits

Author SHA1 Message Date
Jakub Jelen
d18bd23358 Bump version to 0.9.8
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
5dfe742737 Generate new 2k certificate key working in FIPS
The original key had 2018 bits, which falls short for current security
requirements

Steps I used:

$ ssh-keygen -f tests/keys/certauth/id_rsa -t rsa -b 2048 -C libssh_torture_auth -N ''
$ ssh-keygen -s tests/keys/user_ca -I torture_auth_carlos -n alice ./tests/keys/certauth/id_rsa.pub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 8b9b45066b)
2023-12-18 17:57:27 +01:00
Jakub Jelen
aef4a47000 CVE-2023-6918: tests: Code coverage for ssh_get_pubkey_hash()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
9276027c68 CVE-2023-6918: kdf: Detect context init failures
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
a45a3c940d CVE-2023-6918: Systematically check return values when calculating digests
with all crypto backends

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
882d9cb5c8 CVE-2023-6918: Remove unused evp functions and types
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
93c1dbd69f CVE-2023-6918: kdf: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
768d1ed30c CVE-2023-48795: tests: Adjust calculation to strict kex
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
03bbbc9e4c CVE-2023-48795: Strip extensions from both kex lists for matching
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Aris Adamantiadis
fd49482555 CVE-2023-48795: Server side mitigations
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Aris Adamantiadis
87b93be5a2 CVE-2023-48795: client side mitigation
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
6a8a18c73e CVE-2023-6004: torture_misc: Add tests for ipv6 link-local
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
cdaec0d627 CVE-2023-6004: misc: Add ipv6 link-local check for an ip address
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
a0dbe0d556 CVE-2023-6004: torture_misc: Add test for ssh_is_ipaddr
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
8cf4f4bfda CVE-2023-6004: torture_proxycommand: Add test for proxycommand injection
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
4d7ae19e9c CVE-2023-6004: config_parser: Check for valid syntax of a hostname if it is a domain name
This prevents code injection.
The domain name syntax checker is based on RFC1035.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
234ecdf4d9 CVE-2023-6004: torture_misc: Add test for ssh_check_hostname_syntax
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
efb24b6472 CVE-2023-6004: misc: Add function to check allowed characters of a hostname
The hostname can be a domain name or an ip address. The colon has to be
allowed because of IPv6 even it is prohibited in domain names.

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
a5b8bd0d88 CVE-2023-6004: options: Simplify the hostname parsing in ssh_options_set
Using ssh_config_parse_uri can simplify the parsing of the host
parsing inside the function of ssh_options_set

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
c3234e5f94 CVE-2023-6004: config_parser: Allow multiple '@' in usernames
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Norbert Pocs
11bd6e6ad9 CVE-2023-6004: torture_config: Allow multiple '@' in usernames
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
2023-12-18 17:57:27 +01:00
Jakub Jelen
8b8584ce5f channels: Avoid out-of-bounds writes
CID 1470005

Thanks coverity

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
(cherry picked from commit 9c19ba7f33)
(cherry picked from commit d58a4cbd4047ea3aa9d41a820e1978b5f0c49ea5)
2023-12-18 17:57:23 +01:00
Jakub Jelen
2dffb97007 session: Avoid potential null dereference on low-memory conditions
CID 1500478

Thanks coverity

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
(cherry picked from commit ebea7d9023)
(cherry picked from commit 1c6e7dd3c33e0681964631c1ebc619160a09a4bd)
2023-12-18 17:57:18 +01:00
Jakub Jelen
70fef935b2 Bump version to 0.9.7
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:41:53 +02:00
Norbert Pocs
b3d19cc31d CVE-2023-2283:pki_crypto: Remove unnecessary NULL check
Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:41:08 +02:00
Norbert Pocs
05de7cb6ac CVE-2023-2283:pki_crypto: Fix possible authentication bypass
The return value is changed by the call to pki_key_check_hash_compatible
causing the possibility of returning SSH_OK if memory allocation error
happens later in the function.

The assignment of SSH_ERROR if the verification fails is no longer needed,
because the value of the variable is already SSH_ERROR.

Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:41:03 +02:00
Jakub Jelen
b733df6ddc CVE-2023-1667:tests: Client coverage for key exchange with kex guessing
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:51 +02:00
Jakub Jelen
18576cf98f CVE-2023-1667:kex: Add support for sending first_kex_packet_follows flag
This is not completely straightforward as it requires us to do some state
shuffling.

We introduce internal flag that can turn this on in client side, so far for
testing only as we do not want to universally enable this. We also repurpose the
server flag indicating the guess was wrong also for the client to make desired
decisions.

If we found out our guess was wrong, we need to hope the server was able to
figure out this much, we need to revert the DH FSM state, drop the callbacks
from the "wrong" key exchange method and initiate the right one.

The server side is already tested by the pkd_hello_i1, which is executing tests
against dropbrear clients, which is using this flag by default out of the box.

Tested manually also with the pkd_hello --rekey to make sure the server is able
to handle the rekeying with all key exchange methods.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:48 +02:00
Jakub Jelen
0c855d2949 CVE-2023-1667:kex: Correctly handle last fields of KEXINIT also in the client side
Previously, the last two fields of KEXINIT were considered as always zero for
the key exchange. This was true for the sending side, but might have not been
true for the received KEXINIT from the peer.

This moves the construction of these two fields closer to their reading or
writing, instead of hardcoding them on the last possible moment before they go
as input to the hashing function.

This also allows accepting the first_kex_packet_follows on the client side, even
though there is no kex algorithm now that would allow this.

It also avoid memory leaks in case the server_set_kex() or ssh_set_client_kex()
gets called multiple times, ensuring the algorithms will not change under our
hands.

It also makes use of a new flag to track if we sent KEXINIT.

Previously, this was tracked only implicitly by the content of the
session->next_crypto->{server,client}_kex (local kex). If it was not set, we
considered it was not send. But given that we need to check the local kex even
before sending it when we receive first_kex_packet_follows flag in the KEXINIT,
this can no longer be used.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:47 +02:00
Jakub Jelen
aaa3d4fc7d CVE-2023-1667:dh: Expose the callback cleanup functions
These will be helpful when we already sent the first key exchange packet, but we
found out that our guess was wrong and we need to initiate different key
exchange method with different callbacks.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:41 +02:00
Jakub Jelen
c4f05c28aa CVE-2023-1667:kex: Factor out the kex mapping to internal enum
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:39 +02:00
Jakub Jelen
abcf9699aa CVE-2023-1667:kex: Remove needless function argument
The information if the session is client or server session is already part of
the session structure so this argument only duplicated information.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:37 +02:00
Jakub Jelen
6887a5bb20 CVE-2023-1667:packet: Do not allow servers to initiate handshake
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:36 +02:00
Jakub Jelen
85ddd8b34e CVE-2023-1667:packet_cb: Log more verbose error if signature verification fails
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-05-04 13:40:23 +02:00
Jakub Jelen
4637c87f2d token: Add missing whitespace
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:52 +02:00
Jakub Jelen
d1e1aea0b6 kex: Reformat ssh_kex_select_methods
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:50 +02:00
Jakub Jelen
e9741edcde client: Reformat ssh_client_connection_callback
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:48 +02:00
Jakub Jelen
1529bbd7ac wrapper: Reformat crypto_new
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:45 +02:00
Jakub Jelen
27e39655c5 Reformat struct ssh_session_struct
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:43 +02:00
Jakub Jelen
1b5e183544 server: Reformat ssh_server_connection_callback
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:41 +02:00
Jakub Jelen
fef76366db Reformat ssh_packet_kexinit()
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:38 +02:00
Jakub Jelen
cef34a78ef kex: Reformat ssh_send_kex
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:36 +02:00
Jakub Jelen
cf1c67ddb4 packet: Reformat callback handling functions
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:34 +02:00
Jakub Jelen
e72f58811f server: Reformat callback_receive_banner
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:32 +02:00
Jakub Jelen
b923d25fef server: Reformat ssh_handle_key_exchange
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:30 +02:00
Jakub Jelen
545724b7df packet: Fix indentation
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:28 +02:00
Jakub Jelen
9844dd5f79 kex: Clarify the comment
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:25 +02:00
Jakub Jelen
cd8ef68b84 gssapi: Free mic_buffer on all code paths (GHSL-2023-042)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:22 +02:00
Jakub Jelen
cee5f9f69c gssapi: Release output_token on error path (GHSL-2023-041)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:20 +02:00
Jakub Jelen
acfa6e3cac gssapi: Release actual_mechs on exit (GHSL-2023-040)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:17 +02:00
Jakub Jelen
3f92520c74 gssapi: Free output token on exit path (GHSL-2023-039)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:15 +02:00
Jakub Jelen
587166577f gssapi: Free mic_token_buffer on before return (GHSL-2023-038)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:12 +02:00
Jakub Jelen
6a7c1f4e5d gssapi: Release output_token (GHSL-2023-037)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:10 +02:00
Jakub Jelen
dd899b7591 gssapi: Avoid memory leaks of selected OID (GHSL-2023-036)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:07 +02:00
Jakub Jelen
6c85771200 gssapi: Release buffer on error path (GHSL-2023-035)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:05 +02:00
Jakub Jelen
2830726c53 gssapi: Free both_supported on error paths (GHSL-2023-033)
Thanks Phil Turnbull from GitHub

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:51:02 +02:00
Jakub Jelen
e8c959084f kex: Avoid NULL pointer dereference (GHSL-2023-032)
Thanks Phil Turnbull from Github

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:59 +02:00
Anderson Toshiyuki Sasaki
a94ac4c080 tests: Verify error returned by kill
Verify the error code returned by kill() in torture_terminate_process().
The error code is raised when killing the process failed.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit c8222dc1f6)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:22 +02:00
Anderson Toshiyuki Sasaki
7f20bbca62 tests: Use a common function to start sshd
In torture_reload_sshd_server(), instead of trying to use SIGHUP to
reload the configuration file, kill the original process and create a
new one with the new configuration.  With this change, both
torture_setup_sshd_server() and torture_reload_sshd_server() need to
start sshd, with the only difference in the configuration setup.  The
shared code to start the sshd server was moved to a new introduced
internal function torture_start_sshd_server().

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 35224092eb)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:22 +02:00
Jakub Jelen
761ba97145 tests: Give server more time to start
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 12d5c136f2)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:22 +02:00
Jakub Jelen
5d8c346225 ci: Test FIPS mode only on CentOS 8
CentOS 9 FIPS mode is too different for this libssh version and Fedora
FIPS mode is not maintained.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:19 +02:00
Jakub Jelen
754048b419 ci: Add CentOS 8 and 9 to CI
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:17 +02:00
Jakub Jelen
7b44e23e6f tests: Skip ciphers not supported by OpenSSH
This is a problem in recent Fedora, as the 0.9 branch still supports
blowfish, while OpenSSH dropped this support in 7.6.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:14 +02:00
Jakub Jelen
c26414972a ci: Sync VS targets with master
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:50:11 +02:00
Jakub Jelen
31a33fd2fd tests: Send a bit more to make sure rekey is completed
This was for some reason failing on CentOS 7 in 0.10 branch so bringing this to
the master too.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-28 11:49:15 +02:00
Jakub Jelen
3beac46361 tests: Update to unbreak agent_cert test for CentOS 8
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 2ba5a5e976)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-17 18:11:30 +02:00
Jakub Jelen
fea290212a tests: Skip the workaround forcing SHA1 signatures
In certificate authentication with OpenSSH 8.0, the SHA2 signatures were
not accepted correctly [1]. This was not an issue up until the OpenSSH
8.8p1, which does no longer allow SHA1 signatures by default so this
broke the CI and tests against the new OpenSSH [2].

Fixes !107

[1] https://bugzilla.mindrot.org/show_bug.cgi?id=3016
[2] https://gitlab.com/libssh/libssh-mirror/-/issues/107

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 86ee3f5a00)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-17 18:11:30 +02:00
Jakub Jelen
81320d35f3 examples: Fix build issue with new clang 15
The error was  the following

/builds/libssh/libssh-mirror/examples/sshnetcat.c:241:18: error: a function
declaration without a prototype is deprecated in all versions of C
[-Werror,-Wstrict-prototypes]
void cleanup_pcap(){
                 ^
                  void

and similar

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 22f0f0dd60)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-17 18:11:29 +02:00
Andreas Schneider
cb8245a0e4 misc: Fix expanding port numbers
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 648baf0f3c)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-17 18:11:29 +02:00
Andreas Schneider
fd1add66cf misc: Fix format truncation in ssh_path_expand_escape()
error: ‘%u’ directive output may be truncated writing between 1 and 10
bytes into a region of size 6.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit 20406e51c9)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-17 15:52:36 +02:00
Andreas Schneider
ea075e3f2e tests: Fix rekey test so it passes on build systems
The test failed on Fedora Koji and openSUSE Build Service on i686 only. Probably
the rekey on the server needs longer here to collect enough entropy. So we need
to try harder before we stop :-)

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
(cherry picked from commit b3b3fbfa1d)

Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-04-17 15:34:54 +02:00
Andreas Schneider
6b89f4d206 cpack: Do not package .cache directory used by clangd 2021-08-26 15:11:07 +02:00
61 changed files with 2998 additions and 1120 deletions

1
.gitignore vendored
View File

@@ -5,6 +5,7 @@
*~$
cscope.*
compile_commands.json
/.cache
/.clangd
tags
/build

View File

@@ -2,6 +2,8 @@ variables:
BUILD_IMAGES_PROJECT: libssh/build-images
FEDORA_BUILD: buildenv-fedora
CENTOS7_BUILD: buildenv-centos7
CENTOS8_BUILD: buildenv-c8s
CENTOS9_BUILD: buildenv-c9s
TUMBLEWEED_BUILD: buildenv-tumbleweed
MINGW_BUILD: buildenv-mingw
@@ -25,6 +27,47 @@ centos7/openssl_1.0.x/x86_64:
paths:
- obj/
centos8/openssl_1.1.1/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD
script:
- mkdir -p obj && cd obj && cmake
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DPICKY_DEVELOPER=ON
-DWITH_BLOWFISH_CIPHER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
centos9/openssl_3.0.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS9_BUILD
script:
- export OPENSSL_ENABLE_SHA1_SIGNATURES=1
- mkdir -p obj && cd obj && cmake
-DCMAKE_BUILD_TYPE=RelWithDebInfo
-DPICKY_DEVELOPER=ON
-DWITH_BLOWFISH_CIPHER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON -DCLIENT_TESTING=ON -DSERVER_TESTING=ON .. &&
make -j$(nproc) && ctest --output-on-failure
tags:
- shared
except:
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
fedora/openssl_1.1.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
script:
@@ -47,8 +90,8 @@ fedora/openssl_1.1.x/x86_64:
paths:
- obj/
fedora/openssl_1.1.x/x86_64/fips:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$FEDORA_BUILD
centos8/openssl_1.1.1/x86_64/fips:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$CENTOS8_BUILD
script:
- echo 1 > /etc/system-fips
- update-crypto-policies --set FIPS
@@ -469,47 +512,34 @@ tumbleweed/static-analysis:
variables:
ErrorActionPreference: STOP
script:
- $env:VCPKG_DEFAULT_TRIPLET="x64-windows"
- mkdir -p obj; if ($?) {cd obj}; if (! $?) {exit 1}
- cmake
-A x64
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_TOOLCHAIN_FILE"
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON ..
- cmake --build .
- ctest --output-on-failure
- cmake --build .
- ctest --output-on-failure
tags:
- windows
- shared-windows
- windows
- shared-windows
except:
- tags
- tags
artifacts:
expire_in: 1 week
when: on_failure
paths:
- obj/
before_script:
- choco install --no-progress -y cmake
- $env:Path += ';C:\Program Files\CMake\bin'
- If (!(test-path .vcpkg\archives)) { mkdir -p .vcpkg\archives }
- $env:VCPKG_DEFAULT_BINARY_CACHE="$PWD\.vcpkg\archives"
- echo $env:VCPKG_DEFAULT_BINARY_CACHE
- $env:VCPKG_DEFAULT_TRIPLET="$TRIPLET-windows"
- vcpkg install cmocka
- vcpkg install openssl
- vcpkg install zlib
- vcpkg integrate install
- mkdir -p obj; if ($?) {cd obj}; if (! $?) {exit 1}
- cmake
-A $PLATFORM
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON ..
# The Windows runners are broken for last month
# https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/gcp/windows-containers/-/issues/40
allow_failure: true
- If (!(test-path .vcpkg\archives)) { mkdir -p .vcpkg\archives }
- $env:VCPKG_DEFAULT_BINARY_CACHE="$PWD\.vcpkg\archives"
- echo $env:VCPKG_DEFAULT_BINARY_CACHE
- $env:VCPKG_DEFAULT_TRIPLET="$TRIPLET-windows"
- vcpkg install cmocka
- vcpkg install openssl
- vcpkg install zlib
- vcpkg integrate install
- mkdir -p obj; if ($?) {cd obj}; if (! $?) {exit 1}
- cmake
-A $PLATFORM
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
-DPICKY_DEVELOPER=ON
-DWITH_SFTP=ON -DWITH_SERVER=ON -DWITH_ZLIB=ON -DWITH_PCAP=ON
-DUNIT_TESTING=ON ..
visualstudio/x86_64:
extends: .vs

View File

@@ -10,7 +10,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
include(DefineCMakeDefaults)
include(DefineCompilerFlags)
project(libssh VERSION 0.9.6 LANGUAGES C)
project(libssh VERSION 0.9.8 LANGUAGES C)
# global needed variable
set(APPLICATION_NAME ${PROJECT_NAME})
@@ -22,7 +22,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.8.7")
set(LIBRARY_VERSION "4.8.9")
set(LIBRARY_SOVERSION "4")
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked

View File

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

View File

@@ -1,5 +1,17 @@
ChangeLog
==========
version 0.9.8 (released 2023-12-18)
* Fix CVE-2023-6004: Command injection using proxycommand
* Fix CVE-2023-48795: Potential downgrade attack using strict kex
* Fix CVE-2023-6918: Missing checks for return values of MD functions
* Allow @ in usernames when parsing from URI composes
version 0.9.7 (released 2023-05-04)
* Fix CVE-2023-1667: a NULL dereference during rekeying with algorithm guessing
* Fix CVE-2023-2283: a possible authorization bypass in
pki_verify_data_signature under low-memory conditions.
* Fix several memory leaks in GSSAPI handling code
* Build and test related backports
version 0.9.6 (released 2021-08-26)
* CVE-2021-3634: Fix possible heap-buffer overflow when rekeying with

View File

@@ -233,9 +233,10 @@ void set_pcap(ssh_session session){
}
void cleanup_pcap(void);
void cleanup_pcap(){
void cleanup_pcap(void)
{
ssh_pcap_file_free(pcap);
pcap=NULL;
pcap = NULL;
}
#endif

View File

@@ -48,6 +48,7 @@ typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
int ssh_client_curve25519_init(ssh_session session);
void ssh_client_curve25519_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_curve25519_init(ssh_session session);

View File

@@ -24,6 +24,7 @@
#define SRC_DH_GEX_H_
int ssh_client_dhgex_init(ssh_session session);
void ssh_client_dhgex_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_dhgex_init(ssh_session session);

View File

@@ -63,8 +63,10 @@ int ssh_dh_get_current_server_publickey_blob(ssh_session session,
ssh_key ssh_dh_get_next_server_publickey(ssh_session session);
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob);
int dh_handshake(ssh_session session);
int ssh_client_dh_init(ssh_session session);
void ssh_client_dh_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_dh_init(ssh_session session);
#endif /* WITH_SERVER */

View File

@@ -45,6 +45,7 @@
extern struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks;
/* Backend-specific functions. */
int ssh_client_ecdh_init(ssh_session session);
void ssh_client_ecdh_remove_callbacks(ssh_session session);
int ecdh_build_k(ssh_session session);
#ifdef WITH_SERVER

View File

@@ -33,9 +33,10 @@ struct ssh_kex_struct {
SSH_PACKET_CALLBACK(ssh_packet_kexinit);
int ssh_send_kex(ssh_session session, int server_kex);
int ssh_send_kex(ssh_session session);
void ssh_list_kex(struct ssh_kex_struct *kex);
int ssh_set_client_kex(ssh_session session);
int ssh_kex_append_extensions(ssh_session session, struct ssh_kex_struct *pkex);
int ssh_kex_select_methods(ssh_session session);
int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name);
char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list);

View File

@@ -39,11 +39,6 @@ typedef EVP_MD_CTX* SHA384CTX;
typedef EVP_MD_CTX* SHA512CTX;
typedef EVP_MD_CTX* MD5CTX;
typedef HMAC_CTX* HMACCTX;
#ifdef HAVE_ECC
typedef EVP_MD_CTX *EVPCTX;
#else
typedef void *EVPCTX;
#endif
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH

View File

@@ -32,7 +32,6 @@ typedef gcry_md_hd_t SHA384CTX;
typedef gcry_md_hd_t SHA512CTX;
typedef gcry_md_hd_t MD5CTX;
typedef gcry_md_hd_t HMACCTX;
typedef gcry_md_hd_t EVPCTX;
#define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define MD5_DIGEST_LEN 16

View File

@@ -41,7 +41,6 @@ typedef mbedtls_md_context_t *SHA384CTX;
typedef mbedtls_md_context_t *SHA512CTX;
typedef mbedtls_md_context_t *MD5CTX;
typedef mbedtls_md_context_t *HMACCTX;
typedef mbedtls_md_context_t *EVPCTX;
#define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH

View File

@@ -97,4 +97,6 @@ int ssh_mkdirs(const char *pathname, mode_t mode);
int ssh_quote_file_name(const char *file_name, char *buf, size_t buf_len);
int ssh_newline_vis(const char *string, char *buf, size_t buf_len);
int ssh_check_hostname_syntax(const char *hostname);
#endif /* MISC_H_ */

View File

@@ -63,6 +63,7 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info);
SSH_PACKET_CALLBACK(ssh_packet_kexdh_init);
#endif
int ssh_packet_send_newkeys(ssh_session session);
int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum);
int ssh_packet_parse_type(ssh_session session);
//int packet_flush(ssh_session session, int enforce_blocking);

View File

@@ -75,6 +75,17 @@ enum ssh_pending_call_e {
/* Client successfully authenticated */
#define SSH_SESSION_FLAG_AUTHENTICATED 2
/* The KEXINIT message can be sent first by either of the parties so this flag
* indicates that the message was already sent to make sure it is sent and avoid
* sending it twice during key exchange to simplify the state machine. */
#define SSH_SESSION_FLAG_KEXINIT_SENT 4
/* The current SSH2 session implements the "strict KEX" feature and should behave
* differently on SSH2_MSG_NEWKEYS. */
#define SSH_SESSION_FLAG_KEX_STRICT 0x0010
/* Unexpected packets have been sent while the session was still unencrypted */
#define SSH_SESSION_FLAG_KEX_TAINTED 0x0020
/* codes to use with ssh_handle_packets*() */
/* Infinite timeout */
#define SSH_TIMEOUT_INFINITE -1
@@ -131,10 +142,8 @@ struct ssh_session_struct {
/* Extensions negotiated using RFC 8308 */
uint32_t extensions;
ssh_string banner; /* that's the issue banner from
the server */
char *discon_msg; /* disconnect message from
the remote host */
ssh_string banner; /* that's the issue banner from the server */
char *discon_msg; /* disconnect message from the remote host */
ssh_buffer in_buffer;
PACKET in_packet;
ssh_buffer out_buffer;
@@ -158,25 +167,33 @@ struct ssh_session_struct {
uint32_t current_method;
} auth;
/* Sending this flag before key exchange to save one round trip during the
* key exchange. This might make sense on high-latency connections.
* So far internal only for testing. Usable only on the client side --
* there is no key exchange method that would start with server message */
bool send_first_kex_follows;
/*
* RFC 4253, 7.1: if the first_kex_packet_follows flag was set in
* the received SSH_MSG_KEXINIT, but the guess was wrong, this
* field will be set such that the following guessed packet will
* be ignored. Once that packet has been received and ignored,
* this field is cleared.
* be ignored on the receiving side. Once that packet has been received and
* ignored, this field is cleared.
* On the sending side, this is set after we got peer KEXINIT message and we
* need to resend the initial message of the negotiated KEX algorithm.
*/
int first_kex_follows_guess_wrong;
bool first_kex_follows_guess_wrong;
ssh_buffer in_hashbuf;
ssh_buffer out_hashbuf;
struct ssh_crypto_struct *current_crypto;
struct ssh_crypto_struct *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
/* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
struct ssh_crypto_struct *next_crypto;
struct ssh_list *channels; /* linked list of channels */
int maxchannel;
ssh_agent agent; /* ssh agent */
/* keyb interactive data */
/* keyboard interactive data */
struct ssh_kbdint_struct *kbdint;
struct ssh_gssapi_struct *gssapi;
@@ -193,7 +210,8 @@ struct ssh_session_struct {
/* auths accepted by server */
struct ssh_list *ssh_message_list; /* list of delayed SSH messages */
int (*ssh_message_callback)( struct ssh_session_struct *session, ssh_message msg, void *userdata);
int (*ssh_message_callback)(struct ssh_session_struct *session,
ssh_message msg, void *userdata);
void *ssh_message_callback_data;
ssh_server_callbacks server_callbacks;
void (*ssh_connection_callback)( struct ssh_session_struct *session);
@@ -219,7 +237,7 @@ struct ssh_session_struct {
char *custombanner;
unsigned long timeout; /* seconds */
unsigned long timeout_usec;
unsigned int port;
uint16_t port;
socket_t fd;
int StrictHostKeyChecking;
char compressionlevel;

View File

@@ -67,37 +67,38 @@ struct ssh_crypto_struct;
typedef struct ssh_mac_ctx_struct *ssh_mac_ctx;
MD5CTX md5_init(void);
void md5_update(MD5CTX c, const void *data, unsigned long len);
void md5_final(unsigned char *md,MD5CTX c);
void md5_ctx_free(MD5CTX);
int md5_update(MD5CTX c, const void *data, unsigned long len);
int md5_final(unsigned char *md,MD5CTX c);
SHACTX sha1_init(void);
void sha1_update(SHACTX c, const void *data, unsigned long len);
void sha1_final(unsigned char *md,SHACTX c);
void sha1(const unsigned char *digest,int len,unsigned char *hash);
void sha1_ctx_free(SHACTX);
int sha1_update(SHACTX c, const void *data, unsigned long len);
int sha1_final(unsigned char *md,SHACTX c);
int sha1(const unsigned char *digest,int len,unsigned char *hash);
SHA256CTX sha256_init(void);
void sha256_update(SHA256CTX c, const void *data, unsigned long len);
void sha256_final(unsigned char *md,SHA256CTX c);
void sha256(const unsigned char *digest, int len, unsigned char *hash);
void sha256_ctx_free(SHA256CTX);
int sha256_update(SHA256CTX c, const void *data, unsigned long len);
int sha256_final(unsigned char *md,SHA256CTX c);
int sha256(const unsigned char *digest, int len, unsigned char *hash);
SHA384CTX sha384_init(void);
void sha384_update(SHA384CTX c, const void *data, unsigned long len);
void sha384_final(unsigned char *md,SHA384CTX c);
void sha384(const unsigned char *digest, int len, unsigned char *hash);
void sha384_ctx_free(SHA384CTX);
int sha384_update(SHA384CTX c, const void *data, unsigned long len);
int sha384_final(unsigned char *md,SHA384CTX c);
int sha384(const unsigned char *digest, int len, unsigned char *hash);
SHA512CTX sha512_init(void);
void sha512_update(SHA512CTX c, const void *data, unsigned long len);
void sha512_final(unsigned char *md,SHA512CTX c);
void sha512(const unsigned char *digest, int len, unsigned char *hash);
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen);
EVPCTX evp_init(int nid);
void evp_update(EVPCTX ctx, const void *data, unsigned long len);
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen);
void sha512_ctx_free(SHA512CTX);
int sha512_update(SHA512CTX c, const void *data, unsigned long len);
int sha512_final(unsigned char *md,SHA512CTX c);
int sha512(const unsigned char *digest, int len, unsigned char *hash);
HMACCTX hmac_init(const void *key,int len, enum ssh_hmac_e type);
void hmac_update(HMACCTX c, const void *data, unsigned long len);
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
size_t hmac_digest_len(enum ssh_hmac_e type);
int ssh_kdf(struct ssh_crypto_struct *crypto,

View File

@@ -1 +1 @@
4.8.7
4.8.9

View File

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

View File

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

View File

@@ -9,13 +9,6 @@ set(LIBSSH_LINK_LIBRARIES
${LIBSSH_REQUIRED_LIBRARIES}
)
if (WIN32)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
ws2_32
)
endif (WIN32)
if (OPENSSL_CRYPTO_LIBRARIES)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
@@ -93,6 +86,16 @@ if (MINGW AND Threads_FOUND)
)
endif()
# This needs to be last for mingw to build
# https://gitlab.com/libssh/libssh-mirror/-/issues/84
if (WIN32)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
iphlpapi
ws2_32
)
endif (WIN32)
if (BUILD_STATIC_LIB)
set(LIBSSH_STATIC_LIBRARY
ssh_static

View File

@@ -3403,9 +3403,15 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
firstround=0;
} while(1);
memcpy(readchans, rchans, (count_ptrs(rchans) + 1) * sizeof(ssh_channel ));
memcpy(writechans, wchans, (count_ptrs(wchans) + 1) * sizeof(ssh_channel ));
memcpy(exceptchans, echans, (count_ptrs(echans) + 1) * sizeof(ssh_channel ));
if (readchans != &dummy) {
memcpy(readchans, rchans, (count_ptrs(rchans) + 1) * sizeof(ssh_channel));
}
if (writechans != &dummy) {
memcpy(writechans, wchans, (count_ptrs(wchans) + 1) * sizeof(ssh_channel));
}
if (exceptchans != &dummy) {
memcpy(exceptchans, echans, (count_ptrs(echans) + 1) * sizeof(ssh_channel));
}
SAFE_FREE(rchans);
SAFE_FREE(wchans);
SAFE_FREE(echans);

View File

@@ -243,10 +243,13 @@ end:
* @warning this function returning is no proof that DH handshake is
* completed
*/
static int dh_handshake(ssh_session session) {
int dh_handshake(ssh_session session)
{
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);
switch (session->dh_handshake_state) {
case DH_STATE_INIT:
switch(session->next_crypto->kex_type){
@@ -386,95 +389,101 @@ static void ssh_client_connection_callback(ssh_session session)
{
int rc;
switch(session->session_state) {
case SSH_SESSION_STATE_NONE:
case SSH_SESSION_STATE_CONNECTING:
break;
case SSH_SESSION_STATE_SOCKET_CONNECTED:
ssh_set_fd_towrite(session);
ssh_send_banner(session, 0);
SSH_LOG(SSH_LOG_DEBUG, "session_state=%d", session->session_state);
break;
case SSH_SESSION_STATE_BANNER_RECEIVED:
if (session->serverbanner == NULL) {
goto error;
}
set_status(session, 0.4f);
SSH_LOG(SSH_LOG_PROTOCOL,
"SSH server banner: %s", session->serverbanner);
switch (session->session_state) {
case SSH_SESSION_STATE_NONE:
case SSH_SESSION_STATE_CONNECTING:
break;
case SSH_SESSION_STATE_SOCKET_CONNECTED:
ssh_set_fd_towrite(session);
ssh_send_banner(session, 0);
/* Here we analyze the different protocols the server allows. */
rc = ssh_analyze_banner(session, 0);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"No version of SSH protocol usable (banner: %s)",
session->serverbanner);
goto error;
}
break;
case SSH_SESSION_STATE_BANNER_RECEIVED:
if (session->serverbanner == NULL) {
goto error;
}
set_status(session, 0.4f);
SSH_LOG(SSH_LOG_PROTOCOL,
"SSH server banner: %s", session->serverbanner);
ssh_packet_register_socket_callback(session, session->socket);
/* Here we analyze the different protocols the server allows. */
rc = ssh_analyze_banner(session, 0);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"No version of SSH protocol usable (banner: %s)",
session->serverbanner);
goto error;
}
ssh_packet_set_default_callbacks(session);
session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
ssh_packet_register_socket_callback(session, session->socket);
ssh_packet_set_default_callbacks(session);
session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
rc = ssh_set_client_kex(session);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_send_kex(session);
if (rc < 0) {
goto error;
}
set_status(session, 0.5f);
break;
case SSH_SESSION_STATE_INITIAL_KEX:
/* TODO: This state should disappear in favor of get_key handle */
break;
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session, 0.6f);
ssh_list_kex(&session->next_crypto->server_kex);
if ((session->flags & SSH_SESSION_FLAG_KEXINIT_SENT) == 0) {
/* in rekeying state if next_crypto client_kex might be empty */
rc = ssh_set_client_kex(session);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_send_kex(session, 0);
rc = ssh_send_kex(session);
if (rc < 0) {
goto error;
}
set_status(session, 0.5f);
break;
case SSH_SESSION_STATE_INITIAL_KEX:
/* TODO: This state should disappear in favor of get_key handle */
break;
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f);
ssh_list_kex(&session->next_crypto->server_kex);
if (session->next_crypto->client_kex.methods[0] == NULL) {
/* in rekeying state if next_crypto client_kex is empty */
rc = ssh_set_client_kex(session);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_send_kex(session, 0);
if (rc < 0) {
goto error;
}
}
if (ssh_kex_select_methods(session) == SSH_ERROR)
goto error;
set_status(session,0.8f);
session->session_state=SSH_SESSION_STATE_DH;
if (dh_handshake(session) == SSH_ERROR) {
goto error;
}
FALL_THROUGH;
case SSH_SESSION_STATE_DH:
if(session->dh_handshake_state==DH_STATE_FINISHED){
set_status(session,1.0f);
session->connected = 1;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
else
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
}
break;
case SSH_SESSION_STATE_AUTHENTICATING:
break;
case SSH_SESSION_STATE_ERROR:
}
if (ssh_kex_select_methods(session) == SSH_ERROR)
goto error;
default:
ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
set_status(session, 0.8f);
session->session_state = SSH_SESSION_STATE_DH;
/* If the init packet was already sent in previous step, this will be no
* operation */
if (dh_handshake(session) == SSH_ERROR) {
goto error;
}
FALL_THROUGH;
case SSH_SESSION_STATE_DH:
if (session->dh_handshake_state == DH_STATE_FINISHED) {
set_status(session, 1.0f);
session->connected = 1;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
else
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
}
break;
case SSH_SESSION_STATE_AUTHENTICATING:
break;
case SSH_SESSION_STATE_ERROR:
goto error;
default:
ssh_set_error(session, SSH_FATAL, "Invalid state %d",
session->session_state);
}
return;
error:
ssh_socket_close(session->socket);
session->alive = 0;
session->session_state=SSH_SESSION_STATE_ERROR;
session->session_state = SSH_SESSION_STATE_ERROR;
}

View File

@@ -30,6 +30,7 @@
#include "libssh/config_parser.h"
#include "libssh/priv.h"
#include "libssh/misc.h"
char *ssh_config_get_cmd(char **str)
{
@@ -139,6 +140,7 @@ int ssh_config_parse_uri(const char *tok,
{
char *endp = NULL;
long port_n;
int rc;
/* Sanitize inputs */
if (username != NULL) {
@@ -152,7 +154,7 @@ int ssh_config_parse_uri(const char *tok,
}
/* Username part (optional) */
endp = strchr(tok, '@');
endp = strrchr(tok, '@');
if (endp != NULL) {
/* Zero-length username is not valid */
if (tok == endp) {
@@ -196,6 +198,14 @@ int ssh_config_parse_uri(const char *tok,
if (*hostname == NULL) {
goto error;
}
/* if not an ip, check syntax */
rc = ssh_is_ipaddr(*hostname);
if (rc == 0) {
rc = ssh_check_hostname_syntax(*hostname);
if (rc != SSH_OK) {
goto error;
}
}
}
/* Skip also the closing bracket */
if (*endp == ']') {

View File

@@ -136,7 +136,7 @@ static int getai(const char *host, int port, struct addrinfo **ai)
#endif
}
if (ssh_is_ipaddr(host)) {
if (ssh_is_ipaddr(host) == 1) {
/* this is an IP address */
SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host);
hints.ai_flags |= AI_NUMERICHOST;

View File

@@ -172,6 +172,11 @@ int ssh_client_curve25519_init(ssh_session session)
return rc;
}
void ssh_client_curve25519_remove_callbacks(ssh_session session)
{
ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
}
static int ssh_curve25519_build_k(ssh_session session)
{
ssh_curve25519_pubkey k;
@@ -285,7 +290,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
(void)type;
(void)user;
ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
ssh_client_curve25519_remove_callbacks(session);
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
@@ -330,16 +335,10 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=ssh_packet_send(session);
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
return SSH_PACKET_USED;
@@ -497,18 +496,13 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){
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);
/* Send the MSG_NEWKEYS */
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return SSH_PACKET_USED;
error:

View File

@@ -238,6 +238,11 @@ error:
return SSH_PACKET_USED;
}
void ssh_client_dhgex_remove_callbacks(ssh_session session)
{
ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
}
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
{
struct ssh_crypto_struct *crypto=session->next_crypto;
@@ -248,7 +253,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
(void)user;
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received");
ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
ssh_client_dhgex_remove_callbacks(session);
rc = ssh_buffer_unpack(packet,
"SBS",
&pubkey_blob, &server_pubkey,
@@ -282,15 +287,10 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc = ssh_packet_send(session);
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
return SSH_PACKET_USED;

View File

@@ -342,6 +342,11 @@ error:
return SSH_ERROR;
}
void ssh_client_dh_remove_callbacks(ssh_session session)
{
ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
}
SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
struct ssh_crypto_struct *crypto=session->next_crypto;
ssh_string pubkey_blob = NULL;
@@ -351,7 +356,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
(void)type;
(void)user;
ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
ssh_client_dh_remove_callbacks(session);
rc = ssh_buffer_unpack(packet, "SBS", &pubkey_blob, &server_pubkey,
&crypto->dh_server_signature);
@@ -381,16 +386,10 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=ssh_packet_send(session);
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
return SSH_PACKET_USED;
error:
@@ -527,15 +526,12 @@ int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet)
}
SSH_LOG(SSH_LOG_DEBUG, "Sent KEX_DH_[GEX]_REPLY");
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
ssh_buffer_reinit(session->out_buffer);
goto error;
}
session->dh_handshake_state=DH_STATE_NEWKEYS_SENT;
if (ssh_packet_send(session) == SSH_ERROR) {
/* Send the MSG_NEWKEYS */
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent");
return SSH_OK;
error:

View File

@@ -43,6 +43,11 @@ struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks = {
.user = NULL
};
void ssh_client_ecdh_remove_callbacks(ssh_session session)
{
ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
}
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
@@ -55,7 +60,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
(void)type;
(void)user;
ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
ssh_client_ecdh_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");
@@ -88,16 +93,10 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
}
/* Send the MSG_NEWKEYS */
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
goto error;
}
rc=ssh_packet_send(session);
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
return SSH_PACKET_USED;

View File

@@ -323,18 +323,12 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
goto 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){
/* Send the MSG_NEWKEYS */
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
return SSH_PACKET_USED;
error:

View File

@@ -372,17 +372,13 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
goto out;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
/* Send the MSG_NEWKEYS */
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc != SSH_OK) {
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto out;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = ssh_packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
out:
gcry_sexp_release(param);
gcry_sexp_release(key);

View File

@@ -300,16 +300,13 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){
goto out;
}
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
rc = SSH_ERROR;
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
/* Send the MSG_NEWKEYS */
rc = ssh_packet_send_newkeys(session);
if (rc == SSH_ERROR) {
goto out;
}
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
rc = ssh_packet_send(session);
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
out:
mbedtls_ecp_group_free(&grp);
if (rc == SSH_ERROR) {

View File

@@ -223,6 +223,7 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
"indicate mechs",
maj_stat,
min_stat);
gss_release_oid_set(&min_stat, &both_supported);
return SSH_ERROR;
}
@@ -259,8 +260,10 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
return SSH_OK;
}
/* from now we have room for context */
if (ssh_gssapi_init(session) == SSH_ERROR)
if (ssh_gssapi_init(session) == SSH_ERROR) {
gss_release_oid_set(&min_stat, &both_supported);
return SSH_ERROR;
}
name_buf.value = service_name;
name_buf.length = strlen(name_buf.value) + 1;
@@ -272,6 +275,7 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n
"importing name",
maj_stat,
min_stat);
gss_release_oid_set(&min_stat, &both_supported);
return -1;
}
@@ -338,6 +342,7 @@ static char *ssh_gssapi_name_to_char(gss_name_t name){
min_stat);
ptr = malloc(buffer.length + 1);
if (ptr == NULL) {
gss_release_buffer(&min_stat, &buffer);
return NULL;
}
memcpy(ptr, buffer.value, buffer.length);
@@ -421,6 +426,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
"Gssapi error",
maj_stat,
min_stat);
gss_release_buffer(&min_stat, &output_token);
ssh_auth_reply_default(session,0);
ssh_gssapi_free(session);
session->gssapi=NULL;
@@ -438,6 +444,9 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){
(size_t)output_token.length, output_token.value);
ssh_packet_send(session);
}
gss_release_buffer(&min_stat, &output_token);
if(maj_stat == GSS_S_COMPLETE){
session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC;
}
@@ -638,7 +647,7 @@ fail:
static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
{
OM_uint32 maj_stat, min_stat, lifetime;
gss_OID_set actual_mechs;
gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
gss_buffer_desc namebuf;
gss_name_t client_id = GSS_C_NO_NAME;
gss_OID oid;
@@ -700,6 +709,7 @@ static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
ret = SSH_OK;
end:
gss_release_oid_set(&min_stat, &actual_mechs);
gss_release_name(&min_stat, &client_id);
return ret;
}
@@ -713,7 +723,7 @@ end:
*/
int ssh_gssapi_auth_mic(ssh_session session){
size_t i;
gss_OID_set selected; /* oid selected for authentication */
gss_OID_set selected = GSS_C_NO_OID_SET; /* oid selected for authentication */
ssh_string *oids = NULL;
int rc;
size_t n_oids = 0;
@@ -790,6 +800,8 @@ out:
SSH_STRING_FREE(oids[i]);
}
free(oids);
gss_release_oid_set(&min_stat, &selected);
if (rc != SSH_ERROR) {
return SSH_AUTH_AGAIN;
}
@@ -893,6 +905,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){
ssh_packet_send(session);
session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN;
}
gss_release_buffer(&min_stat, &output_token);
return SSH_PACKET_USED;
error:
@@ -921,9 +935,11 @@ static int ssh_gssapi_send_mic(ssh_session session){
maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT,
&mic_buf, &mic_token_buf);
SSH_BUFFER_FREE(mic_buffer);
if (GSS_ERROR(maj_stat)){
SSH_BUFFER_FREE(mic_buffer);
ssh_gssapi_log_error(SSH_LOG_PROTOCOL,
ssh_gssapi_log_error(SSH_LOG_DEBUG,
"generating MIC",
maj_stat,
min_stat);
@@ -935,8 +951,10 @@ static int ssh_gssapi_send_mic(ssh_session session){
SSH2_MSG_USERAUTH_GSSAPI_MIC,
mic_token_buf.length,
(size_t)mic_token_buf.length, mic_token_buf.value);
gss_release_buffer(&min_stat, &mic_token_buf);
if (rc != SSH_OK) {
SSH_BUFFER_FREE(mic_buffer);
ssh_set_error_oom(session);
return SSH_ERROR;
}
@@ -1005,6 +1023,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){
ssh_packet_send(session);
}
gss_release_buffer(&min_stat, &output_token);
if (maj_stat == GSS_S_COMPLETE) {
ssh_gssapi_send_mic(session);
session->auth.state = SSH_AUTH_STATE_GSSAPI_MIC_SENT;

View File

@@ -269,7 +269,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL,
*
* @see ssh_init()
*/
bool is_ssh_initialized() {
bool is_ssh_initialized(void) {
bool is_initialized = false;

146
src/kdf.c
View File

@@ -58,65 +58,102 @@ static ssh_mac_ctx ssh_mac_ctx_init(enum ssh_kdf_digest type)
}
ctx->digest_type = type;
switch(type){
switch (type) {
case SSH_KDF_SHA1:
ctx->ctx.sha1_ctx = sha1_init();
if (ctx->ctx.sha1_ctx == NULL) {
goto err;
}
return ctx;
case SSH_KDF_SHA256:
ctx->ctx.sha256_ctx = sha256_init();
if (ctx->ctx.sha256_ctx == NULL) {
goto err;
}
return ctx;
case SSH_KDF_SHA384:
ctx->ctx.sha384_ctx = sha384_init();
if (ctx->ctx.sha384_ctx == NULL) {
goto err;
}
return ctx;
case SSH_KDF_SHA512:
ctx->ctx.sha512_ctx = sha512_init();
if (ctx->ctx.sha512_ctx == NULL) {
goto err;
}
return ctx;
default:
SAFE_FREE(ctx);
return NULL;
}
err:
SAFE_FREE(ctx);
return NULL;
}
static void ssh_mac_update(ssh_mac_ctx ctx, const void *data, size_t len)
static void ssh_mac_ctx_free(ssh_mac_ctx ctx)
{
switch(ctx->digest_type){
case SSH_KDF_SHA1:
sha1_update(ctx->ctx.sha1_ctx, data, len);
break;
case SSH_KDF_SHA256:
sha256_update(ctx->ctx.sha256_ctx, data, len);
break;
case SSH_KDF_SHA384:
sha384_update(ctx->ctx.sha384_ctx, data, len);
break;
case SSH_KDF_SHA512:
sha512_update(ctx->ctx.sha512_ctx, data, len);
break;
if (ctx == NULL) {
return;
}
}
static void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
{
switch(ctx->digest_type){
switch (ctx->digest_type) {
case SSH_KDF_SHA1:
sha1_final(md,ctx->ctx.sha1_ctx);
sha1_ctx_free(ctx->ctx.sha1_ctx);
break;
case SSH_KDF_SHA256:
sha256_final(md,ctx->ctx.sha256_ctx);
sha256_ctx_free(ctx->ctx.sha256_ctx);
break;
case SSH_KDF_SHA384:
sha384_final(md,ctx->ctx.sha384_ctx);
sha384_ctx_free(ctx->ctx.sha384_ctx);
break;
case SSH_KDF_SHA512:
sha512_final(md,ctx->ctx.sha512_ctx);
sha512_ctx_free(ctx->ctx.sha512_ctx);
break;
}
SAFE_FREE(ctx);
}
static int ssh_mac_update(ssh_mac_ctx ctx, const void *data, size_t len)
{
switch (ctx->digest_type) {
case SSH_KDF_SHA1:
return sha1_update(ctx->ctx.sha1_ctx, data, len);
case SSH_KDF_SHA256:
return sha256_update(ctx->ctx.sha256_ctx, data, len);
case SSH_KDF_SHA384:
return sha384_update(ctx->ctx.sha384_ctx, data, len);
case SSH_KDF_SHA512:
return sha512_update(ctx->ctx.sha512_ctx, data, len);
}
return SSH_ERROR;
}
static int ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
{
int rc = SSH_ERROR;
switch (ctx->digest_type) {
case SSH_KDF_SHA1:
rc = sha1_final(md, ctx->ctx.sha1_ctx);
break;
case SSH_KDF_SHA256:
rc = sha256_final(md, ctx->ctx.sha256_ctx);
break;
case SSH_KDF_SHA384:
rc = sha384_final(md, ctx->ctx.sha384_ctx);
break;
case SSH_KDF_SHA512:
rc = sha512_final(md, ctx->ctx.sha512_ctx);
break;
}
SAFE_FREE(ctx);
return rc;
}
int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
unsigned char *key, size_t key_len,
int key_type, unsigned char *output,
unsigned char *key,
size_t key_len,
int key_type,
unsigned char *output,
size_t requested_len)
{
/* Can't use VLAs with Visual Studio, so allocate the biggest
@@ -125,6 +162,7 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
size_t output_len = crypto->digest_len;
char letter = key_type;
ssh_mac_ctx ctx;
int rc;
if (DIGEST_MAX_LEN < crypto->digest_len) {
return -1;
@@ -135,11 +173,30 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
return -1;
}
ssh_mac_update(ctx, key, key_len);
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
ssh_mac_update(ctx, &letter, 1);
ssh_mac_update(ctx, crypto->session_id, crypto->session_id_len);
ssh_mac_final(digest, ctx);
rc = ssh_mac_update(ctx, key, key_len);
if (rc != SSH_OK) {
ssh_mac_ctx_free(ctx);
return -1;
}
rc = ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
if (rc != SSH_OK) {
ssh_mac_ctx_free(ctx);
return -1;
}
rc = ssh_mac_update(ctx, &letter, 1);
if (rc != SSH_OK) {
ssh_mac_ctx_free(ctx);
return -1;
}
rc = ssh_mac_update(ctx, crypto->session_id, crypto->session_id_len);
if (rc != SSH_OK) {
ssh_mac_ctx_free(ctx);
return -1;
}
rc = ssh_mac_final(digest, ctx);
if (rc != SSH_OK) {
return -1;
}
if (requested_len < output_len) {
output_len = requested_len;
@@ -151,10 +208,25 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
if (ctx == NULL) {
return -1;
}
ssh_mac_update(ctx, key, key_len);
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
ssh_mac_update(ctx, output, output_len);
ssh_mac_final(digest, ctx);
rc = ssh_mac_update(ctx, key, key_len);
if (rc != SSH_OK) {
ssh_mac_ctx_free(ctx);
return -1;
}
rc = ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
if (rc != SSH_OK) {
ssh_mac_ctx_free(ctx);
return -1;
}
rc = ssh_mac_update(ctx, output, output_len);
if (rc != SSH_OK) {
ssh_mac_ctx_free(ctx);
return -1;
}
rc = ssh_mac_final(digest, ctx);
if (rc != SSH_OK) {
return -1;
}
if (requested_len < output_len + crypto->digest_len) {
memcpy(output + output_len, digest, requested_len - output_len);
} else {

559
src/kex.c
View File

@@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdbool.h>
#include "libssh/libssh.h"
#include "libssh/priv.h"
#include "libssh/buffer.h"
#include "libssh/dh.h"
@@ -162,6 +163,9 @@
/* RFC 8308 */
#define KEX_EXTENSION_CLIENT "ext-info-c"
/* Strict kex mitigation against CVE-2023-48795 */
#define KEX_STRICT_CLIENT "kex-strict-c-v00@openssh.com"
#define KEX_STRICT_SERVER "kex-strict-s-v00@openssh.com"
/* Allowed algorithms in FIPS mode */
#define FIPS_ALLOWED_CIPHERS "aes256-gcm@openssh.com,"\
@@ -305,6 +309,10 @@ static int cmp_first_kex_algo(const char *client_str,
int is_wrong = 1;
if (client_str == NULL || server_str == NULL) {
return is_wrong;
}
colon = strchr(client_str, ',');
if (colon == NULL) {
client_kex_len = strlen(client_str);
@@ -331,6 +339,7 @@ static int cmp_first_kex_algo(const char *client_str,
SSH_PACKET_CALLBACK(ssh_packet_kexinit)
{
int i, ok;
struct ssh_crypto_struct *crypto = session->next_crypto;
int server_kex = session->server;
ssh_string str = NULL;
char *strings[SSH_KEX_METHODS] = {0};
@@ -344,35 +353,67 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
(void)type;
(void)user;
SSH_LOG(SSH_LOG_TRACE, "KEXINIT received");
if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED) {
SSH_LOG(SSH_LOG_INFO, "Initiating key re-exchange");
if (session->dh_handshake_state == DH_STATE_FINISHED) {
SSH_LOG(SSH_LOG_DEBUG, "Peer initiated key re-exchange");
/* Reset the sent flag if the re-kex was initiated by the peer */
session->flags &= ~SSH_SESSION_FLAG_KEXINIT_SENT;
} else if (session->flags & SSH_SESSION_FLAG_KEXINIT_SENT &&
session->dh_handshake_state == DH_STATE_INIT_SENT) {
/* This happens only when we are sending our-guessed first kex
* packet right after our KEXINIT packet. */
SSH_LOG(SSH_LOG_DEBUG, "Received peer kexinit answer.");
} else if (session->session_state != SSH_SESSION_STATE_INITIAL_KEX) {
ssh_set_error(session, SSH_FATAL,
"SSH_KEXINIT received in wrong state");
goto error;
}
} else if (session->session_state != SSH_SESSION_STATE_INITIAL_KEX) {
ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
ssh_set_error(session, SSH_FATAL,
"SSH_KEXINIT received in wrong state");
goto error;
}
if (server_kex) {
len = ssh_buffer_get_data(packet,session->next_crypto->client_kex.cookie, 16);
#ifdef WITH_SERVER
len = ssh_buffer_get_data(packet, crypto->client_kex.cookie, 16);
if (len != 16) {
ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
ssh_set_error(session, SSH_FATAL,
"ssh_packet_kexinit: no cookie in packet");
goto error;
}
ok = ssh_hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie);
ok = ssh_hashbufin_add_cookie(session, crypto->client_kex.cookie);
if (ok < 0) {
ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
ssh_set_error(session, SSH_FATAL,
"ssh_packet_kexinit: adding cookie failed");
goto error;
}
ok = server_set_kex(session);
if (ok == SSH_ERROR) {
goto error;
}
#endif
} else {
len = ssh_buffer_get_data(packet,session->next_crypto->server_kex.cookie, 16);
len = ssh_buffer_get_data(packet, crypto->server_kex.cookie, 16);
if (len != 16) {
ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
ssh_set_error(session, SSH_FATAL,
"ssh_packet_kexinit: no cookie in packet");
goto error;
}
ok = ssh_hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie);
ok = ssh_hashbufin_add_cookie(session, crypto->server_kex.cookie);
if (ok < 0) {
ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
ssh_set_error(session, SSH_FATAL,
"ssh_packet_kexinit: adding cookie failed");
goto error;
}
ok = ssh_set_client_kex(session);
if (ok == SSH_ERROR) {
goto error;
}
}
@@ -385,7 +426,8 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
rc = ssh_buffer_add_ssh_string(session->in_hashbuf, str);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer");
ssh_set_error(session, SSH_FATAL,
"Error adding string in hash buffer");
goto error;
}
@@ -398,14 +440,14 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
str = NULL;
}
/* copy the server kex info into an array of strings */
/* copy the peer kex info into an array of strings */
if (server_kex) {
for (i = 0; i < SSH_KEX_METHODS; i++) {
session->next_crypto->client_kex.methods[i] = strings[i];
crypto->client_kex.methods[i] = strings[i];
}
} else { /* client */
for (i = 0; i < SSH_KEX_METHODS; i++) {
session->next_crypto->server_kex.methods[i] = strings[i];
crypto->server_kex.methods[i] = strings[i];
}
}
@@ -419,30 +461,69 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
* that its value is included when computing the session ID (see
* 'make_sessionid').
*/
rc = ssh_buffer_get_u8(packet, &first_kex_packet_follows);
if (rc != 1) {
goto error;
}
rc = ssh_buffer_add_u8(session->in_hashbuf, first_kex_packet_follows);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_u32(session->in_hashbuf, kexinit_reserved);
if (rc < 0) {
goto error;
}
/*
* Remember whether 'first_kex_packet_follows' was set and the client
* guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message
* must be ignored on the server side.
* Client needs to start the Key exchange over with the correct method
*/
if (first_kex_packet_follows || session->send_first_kex_follows) {
char **client_methods = crypto->client_kex.methods;
char **server_methods = crypto->server_kex.methods;
session->first_kex_follows_guess_wrong =
cmp_first_kex_algo(client_methods[SSH_KEX],
server_methods[SSH_KEX]) ||
cmp_first_kex_algo(client_methods[SSH_HOSTKEYS],
server_methods[SSH_HOSTKEYS]);
SSH_LOG(SSH_LOG_DEBUG, "The initial guess was %s.",
session->first_kex_follows_guess_wrong ? "wrong" : "right");
}
/*
* handle the "strict KEX" feature. If supported by peer, then set up the
* flag and verify packet sequence numbers.
*/
if (server_kex) {
rc = ssh_buffer_get_u8(packet, &first_kex_packet_follows);
if (rc != 1) {
goto error;
ok = ssh_match_group(crypto->client_kex.methods[SSH_KEX],
KEX_STRICT_CLIENT);
if (ok) {
SSH_LOG(SSH_LOG_DEBUG, "Client supports strict kex, enabling.");
session->flags |= SSH_SESSION_FLAG_KEX_STRICT;
}
rc = ssh_buffer_add_u8(session->in_hashbuf, first_kex_packet_follows);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_u32(session->in_hashbuf, kexinit_reserved);
if (rc < 0) {
goto error;
} else {
/* client kex */
ok = ssh_match_group(crypto->server_kex.methods[SSH_KEX],
KEX_STRICT_SERVER);
if (ok) {
SSH_LOG(SSH_LOG_DEBUG, "Server supports strict kex, enabling.");
session->flags |= SSH_SESSION_FLAG_KEX_STRICT;
}
}
if (server_kex) {
/*
* If client sent a ext-info-c message in the kex list, it supports
* RFC 8308 extension negotiation.
*/
ok = ssh_match_group(session->next_crypto->client_kex.methods[SSH_KEX],
ok = ssh_match_group(crypto->client_kex.methods[SSH_KEX],
KEX_EXTENSION_CLIENT);
if (ok) {
const char *hostkeys = NULL;
const char *hostkeys = NULL, *wanted_hostkeys = NULL;
/* The client supports extension negotiation */
session->extensions |= SSH_EXT_NEGOTIATION;
@@ -452,14 +533,14 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
* by the client and enable the respective extensions to provide
* correct signature in the next packet if RSA is negotiated
*/
hostkeys = session->next_crypto->client_kex.methods[SSH_HOSTKEYS];
hostkeys = crypto->client_kex.methods[SSH_HOSTKEYS];
wanted_hostkeys = session->opts.wanted_methods[SSH_HOSTKEYS];
ok = ssh_match_group(hostkeys, "rsa-sha2-512");
if (ok) {
/* Check if rsa-sha2-512 is allowed by config */
if (session->opts.wanted_methods[SSH_HOSTKEYS] != NULL) {
char *is_allowed =
ssh_find_matching(session->opts.wanted_methods[SSH_HOSTKEYS],
"rsa-sha2-512");
if (wanted_hostkeys != NULL) {
char *is_allowed = ssh_find_matching(wanted_hostkeys,
"rsa-sha2-512");
if (is_allowed != NULL) {
session->extensions |= SSH_EXT_SIG_RSA_SHA512;
}
@@ -469,10 +550,9 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
ok = ssh_match_group(hostkeys, "rsa-sha2-256");
if (ok) {
/* Check if rsa-sha2-256 is allowed by config */
if (session->opts.wanted_methods[SSH_HOSTKEYS] != NULL) {
char *is_allowed =
ssh_find_matching(session->opts.wanted_methods[SSH_HOSTKEYS],
"rsa-sha2-256");
if (wanted_hostkeys != NULL) {
char *is_allowed = ssh_find_matching(wanted_hostkeys,
"rsa-sha2-256");
if (is_allowed != NULL) {
session->extensions |= SSH_EXT_SIG_RSA_SHA256;
}
@@ -488,7 +568,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
(session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
session->extensions &= ~(SSH_EXT_SIG_RSA_SHA256 | SSH_EXT_SIG_RSA_SHA512);
rsa_sig_ext = ssh_find_matching("rsa-sha2-512,rsa-sha2-256",
session->next_crypto->client_kex.methods[SSH_HOSTKEYS]);
hostkeys);
if (rsa_sig_ext == NULL) {
goto error; /* should never happen */
} else if (strcmp(rsa_sig_ext, "rsa-sha2-512") == 0) {
@@ -507,24 +587,16 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
session->extensions & SSH_EXT_SIG_RSA_SHA256 ? "SHA256" : "",
session->extensions & SSH_EXT_SIG_RSA_SHA512 ? " SHA512" : "");
}
/*
* Remember whether 'first_kex_packet_follows' was set and the client
* guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message
* must be ignored.
*/
if (first_kex_packet_follows) {
session->first_kex_follows_guess_wrong =
cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_KEX],
session->next_crypto->server_kex.methods[SSH_KEX]) ||
cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_HOSTKEYS],
session->next_crypto->server_kex.methods[SSH_HOSTKEYS]);
}
}
/* Note, that his overwrites authenticated state in case of rekeying */
session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED;
session->dh_handshake_state = DH_STATE_INIT;
/* if we already sent our initial key exchange packet, do not reset the
* DH state. We will know if we were right with our guess only in
* dh_handshake_state() */
if (session->send_first_kex_follows == false) {
session->dh_handshake_state = DH_STATE_INIT;
}
session->ssh_connection_callback(session);
return SSH_PACKET_USED;
@@ -666,11 +738,14 @@ int ssh_set_client_kex(ssh_session session)
{
struct ssh_kex_struct *client = &session->next_crypto->client_kex;
const char *wanted;
char *kex = NULL;
char *kex_tmp = NULL;
int ok;
int i;
size_t kex_len, len;
/* Skip if already set, for example for the rekey or when we do the guessing
* it could have been already used to make some protocol decisions. */
if (client->methods[0] != NULL) {
return SSH_OK;
}
ok = ssh_get_random(client->cookie, 16, 0);
if (!ok) {
@@ -678,8 +753,6 @@ int ssh_set_client_kex(ssh_session session)
return SSH_ERROR;
}
memset(client->methods, 0, SSH_KEX_METHODS * sizeof(char **));
/* Set the list of allowed algorithms in order of preference, if it hadn't
* been set yet. */
for (i = 0; i < SSH_KEX_METHODS; i++) {
@@ -715,23 +788,52 @@ int ssh_set_client_kex(ssh_session session)
return SSH_OK;
}
/* Here we append ext-info-c to the list of kex algorithms */
kex = client->methods[SSH_KEX];
ok = ssh_kex_append_extensions(session, client);
if (ok != SSH_OK){
return ok;
}
return SSH_OK;
}
int ssh_kex_append_extensions(ssh_session session, struct ssh_kex_struct *pkex)
{
char *kex = NULL;
char *kex_tmp = NULL;
size_t kex_len, len;
/* Here we append ext-info-c and kex-strict-c-v00@openssh.com for client
* and kex-strict-s-v00@openssh.com for server to the list of kex algorithms
*/
kex = pkex->methods[SSH_KEX];
len = strlen(kex);
if (len + strlen(KEX_EXTENSION_CLIENT) + 2 < len) {
if (session->server) {
/* Comma, nul byte */
kex_len = len + 1 + strlen(KEX_STRICT_SERVER) + 1;
} else {
/* Comma, comma, nul byte */
kex_len = len + 1 + strlen(KEX_EXTENSION_CLIENT) + 1 +
strlen(KEX_STRICT_CLIENT) + 1;
}
if (kex_len >= MAX_PACKET_LEN) {
/* Overflow */
return SSH_ERROR;
}
kex_len = len + strlen(KEX_EXTENSION_CLIENT) + 2; /* comma, NULL */
kex_tmp = realloc(kex, kex_len);
if (kex_tmp == NULL) {
free(kex);
ssh_set_error_oom(session);
return SSH_ERROR;
}
snprintf(kex_tmp + len, kex_len - len, ",%s", KEX_EXTENSION_CLIENT);
client->methods[SSH_KEX] = kex_tmp;
if (session->server){
snprintf(kex_tmp + len, kex_len - len, ",%s", KEX_STRICT_SERVER);
} else {
snprintf(kex_tmp + len,
kex_len - len,
",%s,%s",
KEX_EXTENSION_CLIENT,
KEX_STRICT_CLIENT);
}
pkex->methods[SSH_KEX] = kex_tmp;
return SSH_OK;
}
@@ -749,70 +851,141 @@ static const char *ssh_find_aead_hmac(const char *cipher)
return NULL;
}
static enum ssh_key_exchange_e
kex_select_kex_type(const char *kex)
{
if (strcmp(kex, "diffie-hellman-group1-sha1") == 0) {
return SSH_KEX_DH_GROUP1_SHA1;
} else if (strcmp(kex, "diffie-hellman-group14-sha1") == 0) {
return SSH_KEX_DH_GROUP14_SHA1;
} else if (strcmp(kex, "diffie-hellman-group14-sha256") == 0) {
return SSH_KEX_DH_GROUP14_SHA256;
} else if (strcmp(kex, "diffie-hellman-group16-sha512") == 0) {
return SSH_KEX_DH_GROUP16_SHA512;
} else if (strcmp(kex, "diffie-hellman-group18-sha512") == 0) {
return SSH_KEX_DH_GROUP18_SHA512;
#ifdef WITH_GEX
} else if (strcmp(kex, "diffie-hellman-group-exchange-sha1") == 0) {
return SSH_KEX_DH_GEX_SHA1;
} else if (strcmp(kex, "diffie-hellman-group-exchange-sha256") == 0) {
return SSH_KEX_DH_GEX_SHA256;
#endif /* WITH_GEX */
} else if (strcmp(kex, "ecdh-sha2-nistp256") == 0) {
return SSH_KEX_ECDH_SHA2_NISTP256;
} else if (strcmp(kex, "ecdh-sha2-nistp384") == 0) {
return SSH_KEX_ECDH_SHA2_NISTP384;
} else if (strcmp(kex, "ecdh-sha2-nistp521") == 0) {
return SSH_KEX_ECDH_SHA2_NISTP521;
} else if (strcmp(kex, "curve25519-sha256@libssh.org") == 0) {
return SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
} else if (strcmp(kex, "curve25519-sha256") == 0) {
return SSH_KEX_CURVE25519_SHA256;
}
/* should not happen. We should be getting only valid names at this stage */
return 0;
}
/** @internal
* @brief Reverts guessed callbacks set during the dh_handshake()
* @param session session handle
* @returns void
*/
static void revert_kex_callbacks(ssh_session session)
{
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:
ssh_client_dh_remove_callbacks(session);
break;
#ifdef WITH_GEX
case SSH_KEX_DH_GEX_SHA1:
case SSH_KEX_DH_GEX_SHA256:
ssh_client_dhgex_remove_callbacks(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:
ssh_client_ecdh_remove_callbacks(session);
break;
#endif
#ifdef HAVE_CURVE25519
case SSH_KEX_CURVE25519_SHA256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
ssh_client_curve25519_remove_callbacks(session);
break;
#endif
}
}
/** @brief Select the different methods on basis of client's and
* server's kex messages, and watches out if a match is possible.
*/
int ssh_kex_select_methods (ssh_session session)
{
struct ssh_kex_struct *server = &session->next_crypto->server_kex;
struct ssh_kex_struct *client = &session->next_crypto->client_kex;
struct ssh_crypto_struct *crypto = session->next_crypto;
struct ssh_kex_struct *server = &crypto->server_kex;
struct ssh_kex_struct *client = &crypto->client_kex;
char *ext_start = NULL;
const char *aead_hmac = NULL;
enum ssh_key_exchange_e kex_type;
int i;
/* Here we should drop the ext-info-c from the list so we avoid matching.
/* Here we should drop the extensions from the list so we avoid matching.
* it. We added it to the end, so we can just truncate the string here */
ext_start = strstr(client->methods[SSH_KEX], ","KEX_EXTENSION_CLIENT);
if (ext_start != NULL) {
ext_start[0] = '\0';
if (session->client) {
ext_start = strstr(client->methods[SSH_KEX], "," KEX_EXTENSION_CLIENT);
if (ext_start != NULL) {
ext_start[0] = '\0';
}
}
if (session->server) {
ext_start = strstr(server->methods[SSH_KEX], "," KEX_STRICT_SERVER);
if (ext_start != NULL) {
ext_start[0] = '\0';
}
}
for (i = 0; i < SSH_KEX_METHODS; i++) {
session->next_crypto->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]);
crypto->kex_methods[i] = ssh_find_matching(server->methods[i],
client->methods[i]);
if (i == SSH_MAC_C_S || i == SSH_MAC_S_C) {
aead_hmac = ssh_find_aead_hmac(session->next_crypto->kex_methods[i-2]);
aead_hmac = ssh_find_aead_hmac(crypto->kex_methods[i - 2]);
if (aead_hmac) {
free(session->next_crypto->kex_methods[i]);
session->next_crypto->kex_methods[i] = strdup(aead_hmac);
free(crypto->kex_methods[i]);
crypto->kex_methods[i] = strdup(aead_hmac);
}
}
if (session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){
ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]",
ssh_kex_descriptions[i],server->methods[i],client->methods[i]);
if (crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S) {
ssh_set_error(session, SSH_FATAL,
"kex error : no match for method %s: server [%s], "
"client [%s]", ssh_kex_descriptions[i],
server->methods[i], client->methods[i]);
return SSH_ERROR;
} else if ((i >= SSH_LANG_C_S) && (session->next_crypto->kex_methods[i] == NULL)) {
} else if ((i >= SSH_LANG_C_S) && (crypto->kex_methods[i] == NULL)) {
/* we can safely do that for languages */
session->next_crypto->kex_methods[i] = strdup("");
crypto->kex_methods[i] = strdup("");
}
}
if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha1") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha256") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA256;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group16-sha512") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP16_SHA512;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group18-sha512") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP18_SHA512;
#ifdef WITH_GEX
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha1") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA1;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha256") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA256;
#endif /* WITH_GEX */
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp384") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP384;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp521") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP521;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
} else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256") == 0){
session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256;
/* We can not set this value directly as the old value is needed to revert
* callbacks if we are client */
kex_type = kex_select_kex_type(crypto->kex_methods[SSH_KEX]);
if (session->client && session->first_kex_follows_guess_wrong) {
SSH_LOG(SSH_LOG_DEBUG, "Our guess was wrong. Restarting the KEX");
/* We need to remove the wrong callbacks and start kex again */
revert_kex_callbacks(session);
session->dh_handshake_state = DH_STATE_INIT;
session->first_kex_follows_guess_wrong = false;
}
crypto->kex_type = kex_type;
SSH_LOG(SSH_LOG_INFO, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
session->next_crypto->kex_methods[SSH_KEX],
session->next_crypto->kex_methods[SSH_HOSTKEYS],
@@ -830,63 +1003,116 @@ int ssh_kex_select_methods (ssh_session session)
/* this function only sends the predefined set of kex methods */
int ssh_send_kex(ssh_session session, int server_kex)
int ssh_send_kex(ssh_session session)
{
struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex :
&session->next_crypto->client_kex);
ssh_string str = NULL;
int i;
int rc;
struct ssh_kex_struct *kex = (session->server ?
&session->next_crypto->server_kex :
&session->next_crypto->client_kex);
ssh_string str = NULL;
int i;
int rc;
int first_kex_packet_follows = 0;
rc = ssh_buffer_pack(session->out_buffer,
"bP",
SSH2_MSG_KEXINIT,
16,
kex->cookie); /* cookie */
if (rc != SSH_OK)
goto error;
if (ssh_hashbufout_add_cookie(session) < 0) {
goto error;
}
ssh_list_kex(kex);
for (i = 0; i < SSH_KEX_METHODS; i++) {
str = ssh_string_from_char(kex->methods[i]);
if (str == NULL) {
goto error;
/* Only client can initiate the handshake methods we implement. If we
* already received the peer mechanisms, there is no point in guessing */
if (session->client &&
session->session_state != SSH_SESSION_STATE_KEXINIT_RECEIVED &&
session->send_first_kex_follows) {
first_kex_packet_follows = 1;
}
if (ssh_buffer_add_ssh_string(session->out_hashbuf, str) < 0) {
goto error;
SSH_LOG(SSH_LOG_TRACE,
"Sending KEXINIT packet, first_kex_packet_follows = %d",
first_kex_packet_follows);
rc = ssh_buffer_pack(session->out_buffer,
"bP",
SSH2_MSG_KEXINIT,
16,
kex->cookie); /* cookie */
if (rc != SSH_OK)
goto error;
if (ssh_hashbufout_add_cookie(session) < 0) {
goto error;
}
if (ssh_buffer_add_ssh_string(session->out_buffer, str) < 0) {
goto error;
ssh_list_kex(kex);
for (i = 0; i < SSH_KEX_METHODS; i++) {
str = ssh_string_from_char(kex->methods[i]);
if (str == NULL) {
goto error;
}
rc = ssh_buffer_add_ssh_string(session->out_hashbuf, str);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_ssh_string(session->out_buffer, str);
if (rc < 0) {
goto error;
}
SSH_STRING_FREE(str);
str = NULL;
}
SSH_STRING_FREE(str);
str = NULL;
}
rc = ssh_buffer_pack(session->out_buffer,
"bd",
0,
0);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_buffer_pack(session->out_buffer,
"bd",
first_kex_packet_follows,
0);
if (rc != SSH_OK) {
goto error;
}
if (ssh_packet_send(session) == SSH_ERROR) {
return -1;
}
/* Prepare also the first_kex_packet_follows and reserved to 0 */
rc = ssh_buffer_add_u8(session->out_hashbuf, first_kex_packet_follows);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_u32(session->out_hashbuf, 0);
if (rc < 0) {
goto error;
}
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
return -1;
}
session->flags |= SSH_SESSION_FLAG_KEXINIT_SENT;
SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_KEXINIT sent");
/* If we indicated that we are sending the guessed key exchange packet,
* do it now. The packet is simple, but we need to do some preparations */
if (first_kex_packet_follows) {
char *list = kex->methods[SSH_KEX];
char *colon = strchr(list, ',');
size_t kex_name_len = colon ? (size_t)(colon - list) : strlen(list);
char *kex_name = calloc(kex_name_len + 1, 1);
if (kex_name == NULL) {
ssh_set_error_oom(session);
goto error;
}
snprintf(kex_name, kex_name_len + 1, "%.*s", (int)kex_name_len, list);
SSH_LOG(SSH_LOG_TRACE, "Sending the first kex packet for %s", kex_name);
session->next_crypto->kex_type = kex_select_kex_type(kex_name);
free(kex_name);
/* run the first step of the DH handshake */
session->dh_handshake_state = DH_STATE_INIT;
if (dh_handshake(session) == SSH_ERROR) {
goto error;
}
}
return 0;
SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_KEXINIT sent");
return 0;
error:
ssh_buffer_reinit(session->out_buffer);
ssh_buffer_reinit(session->out_hashbuf);
SSH_STRING_FREE(str);
ssh_buffer_reinit(session->out_buffer);
ssh_buffer_reinit(session->out_hashbuf);
SSH_STRING_FREE(str);
return -1;
return -1;
}
/*
@@ -929,7 +1155,7 @@ int ssh_send_rekex(ssh_session session)
}
session->dh_handshake_state = DH_STATE_INIT;
rc = ssh_send_kex(session, session->server);
rc = ssh_send_kex(session);
if (rc < 0) {
SSH_LOG(SSH_LOG_PACKET, "Failed to send kex");
return rc;
@@ -1006,33 +1232,6 @@ int ssh_make_sessionid(ssh_session session)
client_hash = session->in_hashbuf;
}
/*
* Handle the two final fields for the KEXINIT message (RFC 4253 7.1):
*
* boolean first_kex_packet_follows
* uint32 0 (reserved for future extension)
*/
rc = ssh_buffer_add_u8(server_hash, 0);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_u32(server_hash, 0);
if (rc < 0) {
goto error;
}
/* These fields are handled for the server case in ssh_packet_kexinit. */
if (session->client) {
rc = ssh_buffer_add_u8(client_hash, 0);
if (rc < 0) {
goto error;
}
rc = ssh_buffer_add_u32(client_hash, 0);
if (rc < 0) {
goto error;
}
}
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != SSH_OK) {
goto error;

View File

@@ -126,82 +126,48 @@ SHACTX sha1_init(void)
return c;
}
void sha1_update(SHACTX c, const void *data, unsigned long len)
void sha1_ctx_free(SHACTX c)
{
EVP_DigestUpdate(c, data, len);
}
void sha1_final(unsigned char *md, SHACTX c)
{
unsigned int mdlen = 0;
EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
}
void sha1(const unsigned char *digest, int len, unsigned char *hash)
int sha1_update(SHACTX c, const void *data, unsigned long len)
{
int rc = EVP_DigestUpdate(c, data, len);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha1_final(unsigned char *md, SHACTX c)
{
unsigned int mdlen = 0;
int rc = EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha1(const unsigned char *digest, int len, unsigned char *hash)
{
SHACTX c = sha1_init();
if (c != NULL) {
sha1_update(c, digest, len);
sha1_final(hash, c);
int rc;
if (c == NULL) {
return SSH_ERROR;
}
}
#ifdef HAVE_OPENSSL_ECC
static const EVP_MD *nid_to_evpmd(int nid)
{
switch (nid) {
case NID_X9_62_prime256v1:
return EVP_sha256();
case NID_secp384r1:
return EVP_sha384();
case NID_secp521r1:
return EVP_sha512();
default:
return NULL;
rc = sha1_update(c, digest, len);
if (rc != SSH_OK) {
sha1_ctx_free(c);
return SSH_ERROR;
}
return NULL;
return sha1_final(hash, c);
}
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen)
{
const EVP_MD *evp_md = nid_to_evpmd(nid);
EVP_MD_CTX *md = EVP_MD_CTX_new();
EVP_DigestInit(md, evp_md);
EVP_DigestUpdate(md, digest, len);
EVP_DigestFinal(md, hash, hlen);
EVP_MD_CTX_free(md);
}
EVPCTX evp_init(int nid)
{
const EVP_MD *evp_md = nid_to_evpmd(nid);
EVPCTX ctx = EVP_MD_CTX_new();
if (ctx == NULL) {
return NULL;
}
EVP_DigestInit(ctx, evp_md);
return ctx;
}
void evp_update(EVPCTX ctx, const void *data, unsigned long len)
{
EVP_DigestUpdate(ctx, data, len);
}
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
{
EVP_DigestFinal(ctx, md, mdlen);
EVP_MD_CTX_free(ctx);
}
#endif
SHA256CTX sha256_init(void)
{
int rc;
@@ -218,26 +184,46 @@ SHA256CTX sha256_init(void)
return c;
}
void sha256_update(SHA256CTX c, const void *data, unsigned long len)
void sha256_ctx_free(SHA256CTX c)
{
EVP_DigestUpdate(c, data, len);
}
void sha256_final(unsigned char *md, SHA256CTX c)
{
unsigned int mdlen = 0;
EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
}
void sha256(const unsigned char *digest, int len, unsigned char *hash)
int sha256_update(SHA256CTX c, const void *data, unsigned long len)
{
int rc = EVP_DigestUpdate(c, data, len);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha256_final(unsigned char *md, SHA256CTX c)
{
unsigned int mdlen = 0;
int rc = EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha256(const unsigned char *digest, int len, unsigned char *hash)
{
SHA256CTX c = sha256_init();
if (c != NULL) {
sha256_update(c, digest, len);
sha256_final(hash, c);
int rc;
if (c == NULL) {
return SSH_ERROR;
}
rc = sha256_update(c, digest, len);
if (rc != SSH_OK) {
sha256_ctx_free(c);
return SSH_ERROR;
}
return sha256_final(hash, c);
}
SHA384CTX sha384_init(void)
@@ -256,26 +242,47 @@ SHA384CTX sha384_init(void)
return c;
}
void sha384_update(SHA384CTX c, const void *data, unsigned long len)
void
sha384_ctx_free(SHA384CTX c)
{
EVP_DigestUpdate(c, data, len);
}
void sha384_final(unsigned char *md, SHA384CTX c)
{
unsigned int mdlen = 0;
EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
}
void sha384(const unsigned char *digest, int len, unsigned char *hash)
int sha384_update(SHA384CTX c, const void *data, unsigned long len)
{
int rc = EVP_DigestUpdate(c, data, len);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha384_final(unsigned char *md, SHA384CTX c)
{
unsigned int mdlen = 0;
int rc = EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha384(const unsigned char *digest, int len, unsigned char *hash)
{
SHA384CTX c = sha384_init();
if (c != NULL) {
sha384_update(c, digest, len);
sha384_final(hash, c);
int rc;
if (c == NULL) {
return SSH_ERROR;
}
rc = sha384_update(c, digest, len);
if (rc != SSH_OK) {
sha384_ctx_free(c);
return SSH_ERROR;
}
return sha384_final(hash, c);
}
SHA512CTX sha512_init(void)
@@ -294,26 +301,46 @@ SHA512CTX sha512_init(void)
return c;
}
void sha512_update(SHA512CTX c, const void *data, unsigned long len)
void sha512_ctx_free(SHA512CTX c)
{
EVP_DigestUpdate(c, data, len);
}
void sha512_final(unsigned char *md, SHA512CTX c)
{
unsigned int mdlen = 0;
EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
}
void sha512(const unsigned char *digest, int len, unsigned char *hash)
int sha512_update(SHA512CTX c, const void *data, unsigned long len)
{
int rc = EVP_DigestUpdate(c, data, len);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha512_final(unsigned char *md, SHA512CTX c)
{
unsigned int mdlen = 0;
int rc = EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha512(const unsigned char *digest, int len, unsigned char *hash)
{
SHA512CTX c = sha512_init();
if (c != NULL) {
sha512_update(c, digest, len);
sha512_final(hash, c);
int rc;
if (c == NULL) {
return SSH_ERROR;
}
rc = sha512_update(c, digest, len);
if (rc != SSH_OK) {
sha512_ctx_free(c);
return SSH_ERROR;
}
return sha512_final(hash, c);
}
MD5CTX md5_init(void)
@@ -332,19 +359,33 @@ MD5CTX md5_init(void)
return c;
}
void md5_update(MD5CTX c, const void *data, unsigned long len)
void md5_ctx_free(MD5CTX c)
{
EVP_DigestUpdate(c, data, len);
}
void md5_final(unsigned char *md, MD5CTX c)
{
unsigned int mdlen = 0;
EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
}
int md5_update(MD5CTX c, const void *data, unsigned long len)
{
int rc = EVP_DigestUpdate(c, data, len);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
int md5_final(unsigned char *md, MD5CTX c)
{
unsigned int mdlen = 0;
int rc = EVP_DigestFinal(c, md, &mdlen);
EVP_MD_CTX_destroy(c);
if (rc != 1) {
return SSH_ERROR;
}
return SSH_OK;
}
#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
static const EVP_MD *sshkdf_digest_to_md(enum ssh_kdf_digest digest_type)
{

View File

@@ -68,72 +68,37 @@ SHACTX sha1_init(void) {
return ctx;
}
void sha1_update(SHACTX c, const void *data, unsigned long len) {
void
sha1_ctx_free(SHACTX c)
{
gcry_md_close(c);
}
int sha1_update(SHACTX c, const void *data, unsigned long len) {
gcry_md_write(c, data, len);
return SSH_OK;
}
void sha1_final(unsigned char *md, SHACTX c) {
gcry_md_final(c);
memcpy(md, gcry_md_read(c, 0), SHA_DIGEST_LEN);
gcry_md_close(c);
int sha1_final(unsigned char *md, SHACTX c)
{
unsigned char *tmp = NULL;
gcry_md_final(c);
tmp = gcry_md_read(c, 0);
if (tmp == NULL) {
gcry_md_close(c);
return SSH_ERROR;
}
memcpy(md, tmp, SHA_DIGEST_LEN);
gcry_md_close(c);
return SSH_OK;
}
void sha1(const unsigned char *digest, int len, unsigned char *hash) {
int sha1(const unsigned char *digest, int len, unsigned char *hash) {
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
return SSH_OK;
}
#ifdef HAVE_GCRYPT_ECC
static int nid_to_md_algo(int nid)
{
switch (nid) {
case NID_gcrypt_nistp256:
return GCRY_MD_SHA256;
case NID_gcrypt_nistp384:
return GCRY_MD_SHA384;
case NID_gcrypt_nistp521:
return GCRY_MD_SHA512;
}
return GCRY_MD_NONE;
}
void evp(int nid, unsigned char *digest, int len,
unsigned char *hash, unsigned int *hlen)
{
int algo = nid_to_md_algo(nid);
/* Note: What gcrypt calls 'hash' is called 'digest' here and
vice-versa. */
gcry_md_hash_buffer(algo, hash, digest, len);
*hlen = gcry_md_get_algo_dlen(algo);
}
EVPCTX evp_init(int nid)
{
gcry_error_t err;
int algo = nid_to_md_algo(nid);
EVPCTX ctx;
err = gcry_md_open(&ctx, algo, 0);
if (err) {
return NULL;
}
return ctx;
}
void evp_update(EVPCTX ctx, const void *data, unsigned long len)
{
gcry_md_write(ctx, data, len);
}
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
{
int algo = gcry_md_get_algo(ctx);
*mdlen = gcry_md_get_algo_dlen(algo);
memcpy(md, gcry_md_read(ctx, algo), *mdlen);
gcry_md_close(ctx);
}
#endif
SHA256CTX sha256_init(void) {
SHA256CTX ctx = NULL;
@@ -142,18 +107,35 @@ SHA256CTX sha256_init(void) {
return ctx;
}
void sha256_update(SHACTX c, const void *data, unsigned long len) {
void
sha256_ctx_free(SHA256CTX c)
{
gcry_md_close(c);
}
int sha256_update(SHACTX c, const void *data, unsigned long len) {
gcry_md_write(c, data, len);
return SSH_OK;
}
void sha256_final(unsigned char *md, SHACTX c) {
gcry_md_final(c);
memcpy(md, gcry_md_read(c, 0), SHA256_DIGEST_LEN);
gcry_md_close(c);
int sha256_final(unsigned char *md, SHACTX c)
{
unsigned char *tmp = NULL;
gcry_md_final(c);
tmp = gcry_md_read(c, 0);
if (tmp == NULL) {
gcry_md_close(c);
return SSH_ERROR;
}
memcpy(md, tmp, SHA256_DIGEST_LEN);
gcry_md_close(c);
return SSH_OK;
}
void sha256(const unsigned char *digest, int len, unsigned char *hash){
int sha256(const unsigned char *digest, int len, unsigned char *hash){
gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len);
return SSH_OK;
}
SHA384CTX sha384_init(void) {
@@ -163,18 +145,35 @@ SHA384CTX sha384_init(void) {
return ctx;
}
void sha384_update(SHACTX c, const void *data, unsigned long len) {
void
sha384_ctx_free(SHA384CTX c)
{
gcry_md_close(c);
}
int sha384_update(SHACTX c, const void *data, unsigned long len) {
gcry_md_write(c, data, len);
return SSH_OK;
}
void sha384_final(unsigned char *md, SHACTX c) {
gcry_md_final(c);
memcpy(md, gcry_md_read(c, 0), SHA384_DIGEST_LEN);
gcry_md_close(c);
int sha384_final(unsigned char *md, SHACTX c)
{
unsigned char *tmp = NULL;
gcry_md_final(c);
tmp = gcry_md_read(c, 0);
if (tmp == NULL) {
gcry_md_close(c);
return SSH_ERROR;
}
memcpy(md, tmp, SHA384_DIGEST_LEN);
gcry_md_close(c);
return SSH_OK;
}
void sha384(const unsigned char *digest, int len, unsigned char *hash) {
int sha384(const unsigned char *digest, int len, unsigned char *hash) {
gcry_md_hash_buffer(GCRY_MD_SHA384, hash, digest, len);
return SSH_OK;
}
SHA512CTX sha512_init(void) {
@@ -184,18 +183,35 @@ SHA512CTX sha512_init(void) {
return ctx;
}
void sha512_update(SHACTX c, const void *data, unsigned long len) {
void
sha512_ctx_free(SHA512CTX c)
{
gcry_md_close(c);
}
int sha512_update(SHACTX c, const void *data, unsigned long len) {
gcry_md_write(c, data, len);
return SSH_OK;
}
void sha512_final(unsigned char *md, SHACTX c) {
gcry_md_final(c);
memcpy(md, gcry_md_read(c, 0), SHA512_DIGEST_LEN);
gcry_md_close(c);
int sha512_final(unsigned char *md, SHACTX c)
{
unsigned char *tmp = NULL;
gcry_md_final(c);
tmp = gcry_md_read(c, 0);
if (tmp == NULL) {
gcry_md_close(c);
return SSH_ERROR;
}
memcpy(md, tmp, SHA512_DIGEST_LEN);
gcry_md_close(c);
return SSH_OK;
}
void sha512(const unsigned char *digest, int len, unsigned char *hash) {
int sha512(const unsigned char *digest, int len, unsigned char *hash) {
gcry_md_hash_buffer(GCRY_MD_SHA512, hash, digest, len);
return SSH_OK;
}
MD5CTX md5_init(void) {
@@ -205,14 +221,30 @@ MD5CTX md5_init(void) {
return c;
}
void md5_update(MD5CTX c, const void *data, unsigned long len) {
gcry_md_write(c,data,len);
void
md5_ctx_free(MD5CTX c)
{
gcry_md_close(c);
}
void md5_final(unsigned char *md, MD5CTX c) {
gcry_md_final(c);
memcpy(md, gcry_md_read(c, 0), MD5_DIGEST_LEN);
gcry_md_close(c);
int md5_update(MD5CTX c, const void *data, unsigned long len) {
gcry_md_write(c,data,len);
return SSH_OK;
}
int md5_final(unsigned char *md, MD5CTX c)
{
unsigned char *tmp = NULL;
gcry_md_final(c);
tmp = gcry_md_read(c, 0);
if (tmp == NULL) {
gcry_md_close(c);
return SSH_ERROR;
}
memcpy(md, tmp, MD5_DIGEST_LEN);
gcry_md_close(c);
return SSH_OK;
}
int ssh_kdf(struct ssh_crypto_struct *crypto,

View File

@@ -82,99 +82,46 @@ SHACTX sha1_init(void)
return ctx;
}
void sha1_update(SHACTX c, const void *data, unsigned long len)
void
sha1_ctx_free(SHACTX c)
{
mbedtls_md_update(c, data, len);
}
void sha1_final(unsigned char *md, SHACTX c)
{
mbedtls_md_finish(c, md);
mbedtls_md_free(c);
SAFE_FREE(c);
}
void sha1(const unsigned char *digest, int len, unsigned char *hash)
int sha1_update(SHACTX c, const void *data, unsigned long len)
{
int rc = mbedtls_md_update(c, data, len);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha1_final(unsigned char *md, SHACTX c)
{
int rc = mbedtls_md_finish(c, md);
sha1_ctx_free(c);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha1(const unsigned char *digest, int len, unsigned char *hash)
{
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
if (md_info != NULL) {
mbedtls_md(md_info, digest, len, hash);
}
}
static mbedtls_md_type_t nid_to_md_algo(int nid)
{
switch (nid) {
case NID_mbedtls_nistp256:
return MBEDTLS_MD_SHA256;
case NID_mbedtls_nistp384:
return MBEDTLS_MD_SHA384;
case NID_mbedtls_nistp521:
return MBEDTLS_MD_SHA512;
}
return MBEDTLS_MD_NONE;
}
void evp(int nid, unsigned char *digest, int len,
unsigned char *hash, unsigned int *hlen)
{
mbedtls_md_type_t algo = nid_to_md_algo(nid);
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(algo);
if (md_info != NULL) {
*hlen = mbedtls_md_get_size(md_info);
mbedtls_md(md_info, digest, len, hash);
}
}
EVPCTX evp_init(int nid)
{
EVPCTX ctx = NULL;
int rc;
mbedtls_md_type_t algo = nid_to_md_algo(nid);
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(algo);
if (md_info == NULL) {
return NULL;
return SSH_ERROR;
}
ctx = malloc(sizeof(mbedtls_md_context_t));
if (ctx == NULL) {
return NULL;
}
mbedtls_md_init(ctx);
rc = mbedtls_md_setup(ctx, md_info, 0);
rc = mbedtls_md(md_info, digest, len, hash);
if (rc != 0) {
SAFE_FREE(ctx);
return NULL;
return SSH_ERROR;
}
rc = mbedtls_md_starts(ctx);
if (rc != 0) {
SAFE_FREE(ctx);
return NULL;
}
return ctx;
}
void evp_update(EVPCTX ctx, const void *data, unsigned long len)
{
mbedtls_md_update(ctx, data, len);
}
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
{
*mdlen = mbedtls_md_get_size(ctx->md_info);
mbedtls_md_finish(ctx, md);
mbedtls_md_free(ctx);
SAFE_FREE(ctx);
return SSH_OK;
}
SHA256CTX sha256_init(void)
@@ -210,25 +157,46 @@ SHA256CTX sha256_init(void)
return ctx;
}
void sha256_update(SHA256CTX c, const void *data, unsigned long len)
void
sha256_ctx_free(SHA256CTX c)
{
mbedtls_md_update(c, data, len);
}
void sha256_final(unsigned char *md, SHA256CTX c)
{
mbedtls_md_finish(c, md);
mbedtls_md_free(c);
SAFE_FREE(c);
}
void sha256(const unsigned char *digest, int len, unsigned char *hash)
int sha256_update(SHA256CTX c, const void *data, unsigned long len)
{
int rc = mbedtls_md_update(c, data, len);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha256_final(unsigned char *md, SHA256CTX c)
{
int rc = mbedtls_md_finish(c, md);
sha256_ctx_free(c);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha256(const unsigned char *digest, int len, unsigned char *hash)
{
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
if (md_info != NULL) {
mbedtls_md(md_info, digest, len, hash);
int rc;
if (md_info == NULL) {
return SSH_ERROR;
}
rc = mbedtls_md(md_info, digest, len, hash);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
SHA384CTX sha384_init(void)
@@ -264,25 +232,46 @@ SHA384CTX sha384_init(void)
return ctx;
}
void sha384_update(SHA384CTX c, const void *data, unsigned long len)
void
sha384_ctx_free(SHA384CTX c)
{
mbedtls_md_update(c, data, len);
}
void sha384_final(unsigned char *md, SHA384CTX c)
{
mbedtls_md_finish(c, md);
mbedtls_md_free(c);
SAFE_FREE(c);
}
void sha384(const unsigned char *digest, int len, unsigned char *hash)
int sha384_update(SHA384CTX c, const void *data, unsigned long len)
{
int rc = mbedtls_md_update(c, data, len);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha384_final(unsigned char *md, SHA384CTX c)
{
int rc = mbedtls_md_finish(c, md);
sha384_ctx_free(c);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha384(const unsigned char *digest, int len, unsigned char *hash)
{
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
if (md_info != NULL) {
mbedtls_md(md_info, digest, len, hash);
int rc;
if (md_info == NULL) {
return SSH_ERROR;
}
rc = mbedtls_md(md_info, digest, len, hash);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
SHA512CTX sha512_init(void)
@@ -317,25 +306,46 @@ SHA512CTX sha512_init(void)
return ctx;
}
void sha512_update(SHA512CTX c, const void *data, unsigned long len)
void
sha512_ctx_free(SHA512CTX c)
{
mbedtls_md_update(c, data, len);
}
void sha512_final(unsigned char *md, SHA512CTX c)
{
mbedtls_md_finish(c, md);
mbedtls_md_free(c);
SAFE_FREE(c);
}
void sha512(const unsigned char *digest, int len, unsigned char *hash)
int sha512_update(SHA512CTX c, const void *data, unsigned long len)
{
int rc = mbedtls_md_update(c, data, len);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha512_final(unsigned char *md, SHA512CTX c)
{
int rc = mbedtls_md_finish(c, md);
sha512_ctx_free(c);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int sha512(const unsigned char *digest, int len, unsigned char *hash)
{
const mbedtls_md_info_t *md_info =
mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
if (md_info != NULL) {
mbedtls_md(md_info, digest, len, hash);
int rc;
if (md_info == NULL) {
return SSH_ERROR;
}
rc = mbedtls_md(md_info, digest, len, hash);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
MD5CTX md5_init(void)
@@ -370,18 +380,32 @@ MD5CTX md5_init(void)
return ctx;
}
void md5_update(MD5CTX c, const void *data, unsigned long len) {
mbedtls_md_update(c, data, len);
}
void md5_final(unsigned char *md, MD5CTX c)
void
md5_ctx_free(MD5CTX c)
{
mbedtls_md_finish(c, md);
mbedtls_md_free(c);
SAFE_FREE(c);
}
int md5_update(MD5CTX c, const void *data, unsigned long len)
{
int rc = mbedtls_md_update(c, data, len);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int md5_final(unsigned char *md, MD5CTX c)
{
int rc = mbedtls_md_finish(c, md);
md5_ctx_free(c);
if (rc != 0) {
return SSH_ERROR;
}
return SSH_OK;
}
int ssh_kdf(struct ssh_crypto_struct *crypto,
unsigned char *key, size_t key_len,
int key_type, unsigned char *output,

View File

@@ -32,6 +32,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#endif /* _WIN32 */
@@ -59,6 +60,7 @@
#include <ws2tcpip.h>
#include <shlobj.h>
#include <direct.h>
#include <netioapi.h>
#ifdef HAVE_IO_H
#include <io.h>
@@ -94,6 +96,8 @@
#define ZLIB_STRING ""
#endif
#define ARPA_DOMAIN_MAX_LEN 63
/**
* @defgroup libssh_misc The SSH helper functions.
* @ingroup libssh
@@ -214,22 +218,37 @@ int ssh_is_ipaddr_v4(const char *str) {
int ssh_is_ipaddr(const char *str) {
int rc = SOCKET_ERROR;
char *s = strdup(str);
if (strchr(str, ':')) {
if (s == NULL) {
return -1;
}
if (strchr(s, ':')) {
struct sockaddr_storage ss;
int sslen = sizeof(ss);
char *network_interface = strchr(s, '%');
/* TODO link-local (IP:v6:addr%ifname). */
rc = WSAStringToAddressA((LPSTR) str,
/* link-local (IP:v6:addr%ifname). */
if (network_interface != NULL) {
rc = if_nametoindex(network_interface + 1);
if (rc == 0) {
free(s);
return 0;
}
*network_interface = '\0';
}
rc = WSAStringToAddressA((LPSTR) s,
AF_INET6,
NULL,
(struct sockaddr*)&ss,
&sslen);
if (rc == 0) {
free(s);
return 1;
}
}
free(s);
return ssh_is_ipaddr_v4(str);
}
#else /* _WIN32 */
@@ -333,17 +352,32 @@ int ssh_is_ipaddr_v4(const char *str) {
int ssh_is_ipaddr(const char *str) {
int rc = -1;
char *s = strdup(str);
if (strchr(str, ':')) {
if (s == NULL) {
return -1;
}
if (strchr(s, ':')) {
struct in6_addr dest6;
char *network_interface = strchr(s, '%');
/* TODO link-local (IP:v6:addr%ifname). */
rc = inet_pton(AF_INET6, str, &dest6);
/* link-local (IP:v6:addr%ifname). */
if (network_interface != NULL) {
rc = if_nametoindex(network_interface + 1);
if (rc == 0) {
free(s);
return 0;
}
*network_interface = '\0';
}
rc = inet_pton(AF_INET6, s, &dest6);
if (rc > 0) {
free(s);
return 1;
}
}
free(s);
return ssh_is_ipaddr_v4(str);
}
@@ -1164,14 +1198,13 @@ char *ssh_path_expand_escape(ssh_session session, const char *s) {
x = strdup(session->opts.username);
break;
case 'p':
if (session->opts.port < 65536) {
char tmp[6];
{
char tmp[6];
snprintf(tmp,
sizeof(tmp),
"%u",
session->opts.port > 0 ? session->opts.port : 22);
x = strdup(tmp);
snprintf(tmp, sizeof(tmp), "%hu",
(uint16_t)(session->opts.port > 0 ? session->opts.port
: 22));
x = strdup(tmp);
}
break;
default:
@@ -1735,4 +1768,70 @@ int ssh_newline_vis(const char *string, char *buf, size_t buf_len)
return out - buf;
}
/**
* @brief Checks syntax of a domain name
*
* The check is made based on the RFC1035 section 2.3.1
* Allowed characters are: hyphen, period, digits (0-9) and letters (a-zA-Z)
*
* The label should be no longer than 63 characters
* The label should start with a letter and end with a letter or number
* The label in this implementation can start with a number to allow virtual
* URLs to pass. Note that this will make IPv4 addresses to pass
* this check too.
*
* @param hostname The domain name to be checked, has to be null terminated
*
* @return SSH_OK if the hostname passes syntax check
* SSH_ERROR otherwise or if hostname is NULL or empty string
*/
int ssh_check_hostname_syntax(const char *hostname)
{
char *it = NULL, *s = NULL, *buf = NULL;
size_t it_len;
char c;
if (hostname == NULL || strlen(hostname) == 0) {
return SSH_ERROR;
}
/* strtok_r writes into the string, keep the input clean */
s = strdup(hostname);
if (s == NULL) {
return SSH_ERROR;
}
it = strtok_r(s, ".", &buf);
/* if the token has 0 length */
if (it == NULL) {
free(s);
return SSH_ERROR;
}
do {
it_len = strlen(it);
if (it_len > ARPA_DOMAIN_MAX_LEN ||
/* the first char must be a letter, but some virtual urls start
* with a number */
isalnum(it[0]) == 0 ||
isalnum(it[it_len - 1]) == 0) {
free(s);
return SSH_ERROR;
}
while (*it != '\0') {
c = *it;
/* the "." is allowed too, but tokenization removes it from the
* string */
if (isalnum(c) == 0 && c != '-') {
free(s);
return SSH_ERROR;
}
it++;
}
} while ((it = strtok_r(NULL, ".", &buf)) != NULL);
free(s);
return SSH_OK;
}
/** @} */

View File

@@ -36,6 +36,7 @@
#include "libssh/session.h"
#include "libssh/misc.h"
#include "libssh/options.h"
#include "libssh/config_parser.h"
#ifdef WITH_SERVER
#include "libssh/server.h"
#include "libssh/bind.h"
@@ -490,33 +491,24 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session);
return -1;
} else {
q = strdup(value);
if (q == NULL) {
ssh_set_error_oom(session);
char *username = NULL, *hostname = NULL, *port = NULL;
rc = ssh_config_parse_uri(value, &username, &hostname, &port);
if (rc != SSH_OK) {
return -1;
}
p = strchr(q, '@');
SAFE_FREE(session->opts.host);
if (p) {
*p = '\0';
session->opts.host = strdup(p + 1);
if (session->opts.host == NULL) {
SAFE_FREE(q);
ssh_set_error_oom(session);
return -1;
}
if (port != NULL) {
SAFE_FREE(username);
SAFE_FREE(hostname);
SAFE_FREE(port);
return -1;
}
if (username != NULL) {
SAFE_FREE(session->opts.username);
session->opts.username = strdup(q);
SAFE_FREE(q);
if (session->opts.username == NULL) {
ssh_set_error_oom(session);
return -1;
}
} else {
session->opts.host = q;
session->opts.username = username;
}
if (hostname != NULL) {
SAFE_FREE(session->opts.host);
session->opts.host = hostname;
}
}
break;

View File

@@ -366,6 +366,11 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
* - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
* */
if (!session->server) {
rc = SSH_PACKET_DENIED;
break;
}
if (session->session_state != SSH_SESSION_STATE_DH) {
rc = SSH_PACKET_DENIED;
break;
@@ -1304,6 +1309,19 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
}
#endif /* WITH_ZLIB */
payloadsize = ssh_buffer_get_len(session->in_buffer);
if (session->recv_seq == UINT32_MAX) {
/* Overflowing sequence numbers is always fishy */
if (crypto == NULL) {
/* don't allow sequence number overflow when unencrypted */
ssh_set_error(session,
SSH_FATAL,
"Incoming sequence number overflow");
goto error;
} else {
SSH_LOG(SSH_LOG_WARNING,
"Incoming sequence number overflow");
}
}
session->recv_seq++;
if (crypto != NULL) {
struct ssh_cipher_struct *cipher = NULL;
@@ -1326,7 +1344,19 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
SSH_LOG(SSH_LOG_PACKET,
"packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]",
session->in_packet.type, packet_len, padding, compsize, payloadsize);
if (crypto == NULL) {
/* In strict kex, only a few packets are allowed. Taint the session
* if we received packets that are normally allowed but to be
* refused if we are in strict kex when KEX is over.
*/
uint8_t type = session->in_packet.type;
if (type != SSH2_MSG_KEXINIT && type != SSH2_MSG_NEWKEYS &&
(type < SSH2_MSG_KEXDH_INIT ||
type > SSH2_MSG_KEX_DH_GEX_REQUEST)) {
session->flags |= SSH_SESSION_FLAG_KEX_TAINTED;
}
}
/* Check if the packet is expected */
filter_result = ssh_packet_incoming_filter(session);
@@ -1342,6 +1372,9 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user)
session->in_packet.type);
goto error;
case SSH_PACKET_UNKNOWN:
if (crypto == NULL) {
session->flags |= SSH_SESSION_FLAG_KEX_TAINTED;
}
ssh_packet_send_unimplemented(session, session->recv_seq - 1);
break;
}
@@ -1410,18 +1443,23 @@ static void ssh_packet_socket_controlflow_callback(int code, void *userdata)
}
}
void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){
session->socket_callbacks.data=ssh_packet_socket_callback;
session->socket_callbacks.connected=NULL;
session->socket_callbacks.controlflow = ssh_packet_socket_controlflow_callback;
session->socket_callbacks.userdata=session;
ssh_socket_set_callbacks(s,&session->socket_callbacks);
void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s)
{
struct ssh_socket_callbacks_struct *callbacks = &session->socket_callbacks;
callbacks->data = ssh_packet_socket_callback;
callbacks->connected = NULL;
callbacks->controlflow = ssh_packet_socket_controlflow_callback;
callbacks->userdata = session;
ssh_socket_set_callbacks(s, callbacks);
}
/** @internal
* @brief sets the callbacks for the packet layer
*/
void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
void
ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks)
{
if (session->packet_callbacks == NULL) {
session->packet_callbacks = ssh_list_new();
if (session->packet_callbacks == NULL) {
@@ -1435,8 +1473,11 @@ void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callback
/** @internal
* @brief remove the callbacks from the packet layer
*/
void ssh_packet_remove_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
void
ssh_packet_remove_callbacks(ssh_session session, ssh_packet_callbacks callbacks)
{
struct ssh_iterator *it = NULL;
it = ssh_list_find(session->packet_callbacks, callbacks);
if (it != NULL) {
ssh_list_remove(session->packet_callbacks, it);
@@ -1446,12 +1487,15 @@ void ssh_packet_remove_callbacks(ssh_session session, ssh_packet_callbacks callb
/** @internal
* @brief sets the default packet handlers
*/
void ssh_packet_set_default_callbacks(ssh_session session){
session->default_packet_callbacks.start=1;
session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback);
session->default_packet_callbacks.user=session;
session->default_packet_callbacks.callbacks=default_packet_handlers;
ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
void ssh_packet_set_default_callbacks(ssh_session session)
{
struct ssh_packet_callbacks_struct *c = &session->default_packet_callbacks;
c->start = 1;
c->n_callbacks = sizeof(default_packet_handlers) / sizeof(ssh_packet_callback);
c->user = session;
c->callbacks = default_packet_handlers;
ssh_packet_set_callbacks(session, c);
}
/** @internal
@@ -1505,9 +1549,35 @@ void ssh_packet_process(ssh_session session, uint8_t type)
SSH_LOG(SSH_LOG_RARE, "Failed to send unimplemented: %s",
ssh_get_error(session));
}
if (session->current_crypto == NULL) {
session->flags |= SSH_SESSION_FLAG_KEX_TAINTED;
}
}
}
/** @internal
* @brief sends a SSH_MSG_NEWKEYS when enabling the new negotiated ciphers
* @param session the SSH session
* @return SSH_ERROR on error, else SSH_OK
*/
int ssh_packet_send_newkeys(ssh_session session)
{
int rc;
/* Send the MSG_NEWKEYS */
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
return rc;
}
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
return rc;
}
SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent");
return rc;
}
/** @internal
* @brief sends a SSH_MSG_UNIMPLEMENTED answer to an unhandled packet
* @param session the SSH session
@@ -1813,6 +1883,10 @@ int ssh_packet_send(ssh_session session)
if (rc == SSH_OK && type == SSH2_MSG_NEWKEYS) {
struct ssh_iterator *it;
if (session->flags & SSH_SESSION_FLAG_KEX_STRICT) {
/* reset packet sequence number when running in strict kex mode */
session->send_seq = 0;
}
for (it = ssh_list_get_iterator(session->out_queue);
it != NULL;
it = ssh_list_get_iterator(session->out_queue)) {
@@ -1926,7 +2000,7 @@ ssh_packet_set_newkeys(ssh_session session,
memcpy(session->next_crypto->session_id,
session->current_crypto->session_id,
session_id_len);
session->next_crypto->session_id_len = session_id_len;
session->next_crypto->session_id_len = session_id_len;
return SSH_OK;
}

View File

@@ -110,6 +110,18 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
goto error;
}
if (session->flags & SSH_SESSION_FLAG_KEX_STRICT) {
/* reset packet sequence number when running in strict kex mode */
session->recv_seq = 0;
/* Check that we aren't tainted */
if (session->flags & SSH_SESSION_FLAG_KEX_TAINTED) {
ssh_set_error(session,
SSH_FATAL,
"Received unexpected packets in strict KEX mode.");
goto error;
}
}
if(session->server){
/* server things are done in server.c */
session->dh_handshake_state=DH_STATE_FINISHED;
@@ -156,6 +168,9 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
session->next_crypto->digest_len);
SSH_SIGNATURE_FREE(sig);
if (rc == SSH_ERROR) {
ssh_set_error(session,
SSH_FATAL,
"Failed to verify server hostkey signature");
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL,"Signature verified and valid");

View File

@@ -2291,8 +2291,12 @@ int pki_verify_data_signature(ssh_signature signature,
unsigned char *raw_sig_data = NULL;
unsigned int raw_sig_len;
/* Function return code
* Do not change this variable throughout the function until the signature
* is successfully verified!
*/
int rc = SSH_ERROR;
int evp_rc;
int ok;
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
signature == NULL || (signature->raw_sig == NULL
@@ -2307,8 +2311,8 @@ int pki_verify_data_signature(ssh_signature signature,
}
/* Check if public key and hash type are compatible */
rc = pki_key_check_hash_compatible(pubkey, signature->hash_type);
if (rc != SSH_OK) {
ok = pki_key_check_hash_compatible(pubkey, signature->hash_type);
if (ok != SSH_OK) {
return SSH_ERROR;
}
@@ -2351,8 +2355,8 @@ int pki_verify_data_signature(ssh_signature signature,
}
/* Verify the signature */
evp_rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
if (evp_rc != 1){
ok = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
if (ok != 1){
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestVerifyInit() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -2360,35 +2364,31 @@ int pki_verify_data_signature(ssh_signature signature,
}
#ifdef HAVE_OPENSSL_EVP_DIGESTVERIFY
evp_rc = EVP_DigestVerify(ctx, raw_sig_data, raw_sig_len, input, input_len);
ok = EVP_DigestVerify(ctx, raw_sig_data, raw_sig_len, input, input_len);
#else
evp_rc = EVP_DigestVerifyUpdate(ctx, input, input_len);
if (evp_rc != 1) {
ok = EVP_DigestVerifyUpdate(ctx, input, input_len);
if (ok != 1) {
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestVerifyUpdate() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
evp_rc = EVP_DigestVerifyFinal(ctx, raw_sig_data, raw_sig_len);
ok = EVP_DigestVerifyFinal(ctx, raw_sig_data, raw_sig_len);
#endif
if (evp_rc == 1) {
SSH_LOG(SSH_LOG_TRACE, "Signature valid");
rc = SSH_OK;
} else {
if (ok != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Signature invalid: %s",
ERR_error_string(ERR_get_error(), NULL));
rc = SSH_ERROR;
goto out;
}
SSH_LOG(SSH_LOG_TRACE, "Signature valid");
rc = SSH_OK;
out:
if (ctx != NULL) {
EVP_MD_CTX_free(ctx);
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(pkey);
return rc;
}

View File

@@ -92,7 +92,11 @@ int server_set_kex(ssh_session session)
size_t len;
int ok;
ZERO_STRUCTP(server);
/* Skip if already set, for example for the rekey or when we do the guessing
* it could have been already used to make some protocol decisions. */
if (server->methods[0] != NULL) {
return SSH_OK;
}
ok = ssh_get_random(server->cookie, 16, 0);
if (!ok) {
@@ -191,7 +195,13 @@ int server_set_kex(ssh_session session)
}
}
return 0;
/* Do not append the extensions during rekey */
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) {
return SSH_OK;
}
rc = ssh_kex_append_extensions(session, server);
return rc;
}
int ssh_server_init_kex(ssh_session session) {
@@ -335,117 +345,121 @@ ssh_get_key_params(ssh_session session,
* @brief A function to be called each time a step has been done in the
* connection.
*/
static void ssh_server_connection_callback(ssh_session session){
static void ssh_server_connection_callback(ssh_session session)
{
int rc;
switch(session->session_state){
case SSH_SESSION_STATE_NONE:
case SSH_SESSION_STATE_CONNECTING:
case SSH_SESSION_STATE_SOCKET_CONNECTED:
break;
case SSH_SESSION_STATE_BANNER_RECEIVED:
if (session->clientbanner == NULL) {
goto error;
}
set_status(session, 0.4f);
SSH_LOG(SSH_LOG_PROTOCOL,
"SSH client banner: %s", session->clientbanner);
switch (session->session_state) {
case SSH_SESSION_STATE_NONE:
case SSH_SESSION_STATE_CONNECTING:
case SSH_SESSION_STATE_SOCKET_CONNECTED:
break;
case SSH_SESSION_STATE_BANNER_RECEIVED:
if (session->clientbanner == NULL) {
goto error;
}
set_status(session, 0.4f);
SSH_LOG(SSH_LOG_PROTOCOL,
"SSH client banner: %s", session->clientbanner);
/* Here we analyze the different protocols the server allows. */
rc = ssh_analyze_banner(session, 1);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"No version of SSH protocol usable (banner: %s)",
session->clientbanner);
/* Here we analyze the different protocols the server allows. */
rc = ssh_analyze_banner(session, 1);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"No version of SSH protocol usable (banner: %s)",
session->clientbanner);
goto error;
}
/* from now, the packet layer is handling incoming packets */
session->socket_callbacks.data = ssh_packet_socket_callback;
ssh_packet_register_socket_callback(session, session->socket);
ssh_packet_set_default_callbacks(session);
set_status(session, 0.5f);
session->session_state = SSH_SESSION_STATE_INITIAL_KEX;
if (ssh_send_kex(session) < 0) {
goto error;
}
break;
case SSH_SESSION_STATE_INITIAL_KEX:
/* TODO: This state should disappear in favor of get_key handle */
break;
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session, 0.6f);
if ((session->flags & SSH_SESSION_FLAG_KEXINIT_SENT) == 0) {
if (server_set_kex(session) == SSH_ERROR)
goto error;
/* We are in a rekeying, so we need to send the server kex */
if (ssh_send_kex(session) < 0)
goto error;
}
ssh_list_kex(&session->next_crypto->client_kex); // log client kex
if (ssh_kex_select_methods(session) < 0) {
goto error;
}
if (crypt_set_algorithms_server(session) == SSH_ERROR)
goto error;
set_status(session, 0.8f);
session->session_state = SSH_SESSION_STATE_DH;
break;
case SSH_SESSION_STATE_DH:
if (session->dh_handshake_state == DH_STATE_FINISHED) {
rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_IN);
if (rc != SSH_OK) {
goto error;
}
/* from now, the packet layer is handling incoming packets */
session->socket_callbacks.data=ssh_packet_socket_callback;
ssh_packet_register_socket_callback(session, session->socket);
ssh_packet_set_default_callbacks(session);
set_status(session, 0.5f);
session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
if (ssh_send_kex(session, 1) < 0) {
goto error;
}
break;
case SSH_SESSION_STATE_INITIAL_KEX:
/* TODO: This state should disappear in favor of get_key handle */
break;
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f);
if(session->next_crypto->server_kex.methods[0]==NULL){
if(server_set_kex(session) == SSH_ERROR)
goto error;
/* We are in a rekeying, so we need to send the server kex */
if(ssh_send_kex(session, 1) < 0)
goto error;
}
ssh_list_kex(&session->next_crypto->client_kex); // log client kex
if (ssh_kex_select_methods(session) < 0) {
goto error;
}
if (crypt_set_algorithms_server(session) == SSH_ERROR)
goto error;
set_status(session,0.8f);
session->session_state=SSH_SESSION_STATE_DH;
break;
case SSH_SESSION_STATE_DH:
if(session->dh_handshake_state==DH_STATE_FINISHED){
rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_IN);
if (rc != SSH_OK) {
goto error;
}
/*
* If the client supports extension negotiation, we will send
* our supported extensions now. This is the first message after
* sending NEWKEYS message and after turning on crypto.
*/
if (session->extensions & SSH_EXT_NEGOTIATION &&
session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
/*
* If the client supports extension negotiation, we will send
* our supported extensions now. This is the first message after
* sending NEWKEYS message and after turning on crypto.
* Only send an SSH_MSG_EXT_INFO message the first time the
* client undergoes NEWKEYS. It is unexpected for this message
* to be sent upon rekey, and may cause clients to log error
* messages.
*
* The session_state can not be used for this purpose because it
* is re-set to SSH_SESSION_STATE_KEXINIT_RECEIVED during rekey.
* So, use the connected flag which transitions from non-zero
* below.
*
* See also:
* - https://bugzilla.mindrot.org/show_bug.cgi?id=2929
*/
if (session->extensions & SSH_EXT_NEGOTIATION &&
session->session_state != SSH_SESSION_STATE_AUTHENTICATED) {
/*
* Only send an SSH_MSG_EXT_INFO message the first time the client
* undergoes NEWKEYS. It is unexpected for this message to be sent
* upon rekey, and may cause clients to log error messages.
*
* The session_state can not be used for this purpose because it is
* re-set to SSH_SESSION_STATE_KEXINIT_RECEIVED during rekey. So,
* use the connected flag which transitions from non-zero below.
*
* See also:
* - https://bugzilla.mindrot.org/show_bug.cgi?id=2929
*/
if (session->connected == 0) {
ssh_server_send_extensions(session);
}
if (session->connected == 0) {
ssh_server_send_extensions(session);
}
set_status(session,1.0f);
session->connected = 1;
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
}
break;
case SSH_SESSION_STATE_AUTHENTICATING:
break;
case SSH_SESSION_STATE_ERROR:
goto error;
default:
ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state);
set_status(session, 1.0f);
session->connected = 1;
session->session_state = SSH_SESSION_STATE_AUTHENTICATING;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
}
break;
case SSH_SESSION_STATE_AUTHENTICATING:
break;
case SSH_SESSION_STATE_ERROR:
goto error;
default:
ssh_set_error(session, SSH_FATAL, "Invalid state %d",
session->session_state);
}
return;
error:
ssh_socket_close(session->socket);
session->alive = 0;
session->session_state=SSH_SESSION_STATE_ERROR;
session->session_state = SSH_SESSION_STATE_ERROR;
}
/**
@@ -459,16 +473,17 @@ error:
* @param user is a pointer to session
* @returns Number of bytes processed, or zero if the banner is not complete.
*/
static int callback_receive_banner(const void *data, size_t len, void *user) {
char *buffer = (char *) data;
ssh_session session = (ssh_session) user;
static int callback_receive_banner(const void *data, size_t len, void *user)
{
char *buffer = (char *)data;
ssh_session session = (ssh_session)user;
char *str = NULL;
size_t i;
int ret=0;
for (i = 0; i < len; i++) {
#ifdef WITH_PCAP
if(session->pcap_ctx && buffer[i] == '\n') {
if (session->pcap_ctx && buffer[i] == '\n') {
ssh_pcap_context_write(session->pcap_ctx,
SSH_PCAP_DIR_IN,
buffer,
@@ -477,11 +492,11 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
}
#endif
if (buffer[i] == '\r') {
buffer[i]='\0';
buffer[i] = '\0';
}
if (buffer[i] == '\n') {
buffer[i]='\0';
buffer[i] = '\0';
str = strdup(buffer);
/* number of bytes read */
@@ -494,10 +509,11 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
return ret;
}
if(i > 127) {
if (i > 127) {
/* Too big banner */
session->session_state = SSH_SESSION_STATE_ERROR;
ssh_set_error(session, SSH_FATAL, "Receiving banner: too large banner");
ssh_set_error(session, SSH_FATAL,
"Receiving banner: too large banner");
return 0;
}
@@ -525,10 +541,14 @@ void ssh_set_auth_methods(ssh_session session, int auth_methods)
}
/* Do the banner and key exchange */
int ssh_handle_key_exchange(ssh_session session) {
int ssh_handle_key_exchange(ssh_session session)
{
int rc;
if (session->session_state != SSH_SESSION_STATE_NONE)
goto pending;
if (session->session_state != SSH_SESSION_STATE_NONE) {
goto pending;
}
rc = ssh_send_banner(session, 1);
if (rc < 0) {
return SSH_ERROR;
@@ -539,27 +559,28 @@ int ssh_handle_key_exchange(ssh_session session) {
session->ssh_connection_callback = ssh_server_connection_callback;
session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED;
ssh_socket_set_callbacks(session->socket,&session->socket_callbacks);
session->socket_callbacks.data=callback_receive_banner;
session->socket_callbacks.exception=ssh_socket_exception_callback;
session->socket_callbacks.userdata=session;
session->socket_callbacks.data = callback_receive_banner;
session->socket_callbacks.exception = ssh_socket_exception_callback;
session->socket_callbacks.userdata = session;
rc = server_set_kex(session);
if (rc < 0) {
return SSH_ERROR;
}
pending:
pending:
rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER,
ssh_server_kex_termination,session);
ssh_server_kex_termination,session);
SSH_LOG(SSH_LOG_PACKET, "ssh_handle_key_exchange: current state : %d",
session->session_state);
if (rc != SSH_OK)
return rc;
session->session_state);
if (rc != SSH_OK) {
return rc;
}
if (session->session_state == SSH_SESSION_STATE_ERROR ||
session->session_state == SSH_SESSION_STATE_DISCONNECTED) {
return SSH_ERROR;
return SSH_ERROR;
}
return SSH_OK;
return SSH_OK;
}
/* messages */

View File

@@ -643,6 +643,10 @@ int ssh_handle_packets(ssh_session session, int timeout) {
}
spoll = ssh_socket_get_poll_handle(session->socket);
if (spoll == NULL) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
ssh_poll_add_events(spoll, POLLIN);
ctx = ssh_poll_get_ctx(spoll);
@@ -997,7 +1001,18 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash)
*hash = NULL;
if (session->current_crypto == NULL ||
session->current_crypto->server_pubkey == NULL) {
ssh_set_error(session,SSH_FATAL,"No current cryptographic context");
ssh_set_error(session, SSH_FATAL, "No current cryptographic context");
return SSH_ERROR;
}
rc = ssh_get_server_publickey(session, &pubkey);
if (rc != SSH_OK) {
return SSH_ERROR;
}
rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
ssh_key_free(pubkey);
if (rc != SSH_OK) {
return SSH_ERROR;
}
@@ -1012,24 +1027,20 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash)
return SSH_ERROR;
}
rc = ssh_get_server_publickey(session, &pubkey);
rc = md5_update(ctx,
ssh_string_data(pubkey_blob),
ssh_string_len(pubkey_blob));
if (rc != SSH_OK) {
md5_final(h, ctx);
md5_ctx_free(ctx);
SAFE_FREE(h);
return SSH_ERROR;
return rc;
}
rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob);
ssh_key_free(pubkey);
if (rc != SSH_OK) {
md5_final(h, ctx);
SAFE_FREE(h);
return SSH_ERROR;
}
md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob));
SSH_STRING_FREE(pubkey_blob);
md5_final(h, ctx);
rc = md5_final(h, ctx);
if (rc != SSH_OK) {
SAFE_FREE(h);
return rc;
}
*hash = h;
@@ -1149,8 +1160,17 @@ int ssh_get_publickey_hash(const ssh_key key,
goto out;
}
sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
sha1_final(h, ctx);
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;
}
@@ -1172,8 +1192,17 @@ int ssh_get_publickey_hash(const ssh_key key,
goto out;
}
sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
sha256_final(h, ctx);
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;
}
@@ -1203,8 +1232,17 @@ int ssh_get_publickey_hash(const ssh_key key,
goto out;
}
md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob));
md5_final(h, ctx);
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;
}

View File

@@ -87,7 +87,7 @@ struct ssh_tokens_st *ssh_tokenize(const char *chain, char separator)
return NULL;
}
tokens->buffer= strdup(chain);
tokens->buffer = strdup(chain);
if (tokens->buffer == NULL) {
goto error;
}

View File

@@ -147,15 +147,16 @@ static void cipher_free(struct ssh_cipher_struct *cipher) {
SAFE_FREE(cipher);
}
struct ssh_crypto_struct *crypto_new(void) {
struct ssh_crypto_struct *crypto;
struct ssh_crypto_struct *crypto_new(void)
{
struct ssh_crypto_struct *crypto;
crypto = malloc(sizeof(struct ssh_crypto_struct));
if (crypto == NULL) {
return NULL;
}
ZERO_STRUCTP(crypto);
return crypto;
crypto = malloc(sizeof(struct ssh_crypto_struct));
if (crypto == NULL) {
return NULL;
}
ZERO_STRUCTP(crypto);
return crypto;
}
void crypto_free(struct ssh_crypto_struct *crypto)

View File

@@ -200,7 +200,8 @@ static int agent_teardown(void **state)
assert_non_null(ssh_agent_pidfile);
/* kill agent pid */
torture_terminate_process(ssh_agent_pidfile);
rc = torture_terminate_process(ssh_agent_pidfile);
assert_return_code(rc, errno);
unlink(ssh_agent_pidfile);
@@ -551,6 +552,7 @@ static void torture_auth_cert(void **state) {
static void torture_auth_agent_cert(void **state)
{
#if OPENSSH_VERSION_MAJOR < 8 || (OPENSSH_VERSION_MAJOR == 8 && OPENSSH_VERSION_MINOR == 0)
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
int rc;
@@ -570,6 +572,7 @@ static void torture_auth_agent_cert(void **state)
"ssh-rsa-cert-v01@openssh.com");
assert_int_equal(rc, SSH_OK);
}
#endif /* OPENSSH_VERSION_MAJOR < 8.1 */
/* Setup loads a different key, tests are exactly the same. */
torture_auth_agent(state);
@@ -577,6 +580,7 @@ static void torture_auth_agent_cert(void **state)
static void torture_auth_agent_cert_nonblocking(void **state)
{
#if OPENSSH_VERSION_MAJOR < 8 || (OPENSSH_VERSION_MAJOR == 8 && OPENSSH_VERSION_MINOR == 0)
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
int rc;
@@ -596,6 +600,7 @@ static void torture_auth_agent_cert_nonblocking(void **state)
"ssh-rsa-cert-v01@openssh.com");
assert_int_equal(rc, SSH_OK);
}
#endif /* OPENSSH_VERSION_MAJOR < 8.1 */
torture_auth_agent_nonblocking(state);
}

View File

@@ -161,6 +161,56 @@ static void torture_options_set_proxycommand_ssh_stderr(void **state)
assert_int_equal(rc & O_RDWR, O_RDWR);
}
static void torture_options_proxycommand_injection(void **state)
{
struct torture_state *s = *state;
struct passwd *pwd = NULL;
const char *malicious_host = "`echo foo > mfile`";
const char *command = "nc %h %p";
char *current_dir = NULL;
char *malicious_file_path = NULL;
int mfp_len;
int verbosity = torture_libssh_verbosity();
struct stat sb;
int rc;
pwd = getpwnam("bob");
assert_non_null(pwd);
rc = setuid(pwd->pw_uid);
assert_return_code(rc, errno);
s->ssh.session = ssh_new();
assert_non_null(s->ssh.session);
ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
// if we would be checking the rc, this should fail
ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, malicious_host);
ssh_options_set(s->ssh.session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROXYCOMMAND, command);
assert_int_equal(rc, 0);
rc = ssh_connect(s->ssh.session);
assert_ssh_return_code_equal(s->ssh.session, rc, SSH_ERROR);
current_dir = torture_get_current_working_dir();
assert_non_null(current_dir);
mfp_len = strlen(current_dir) + 6;
malicious_file_path = malloc(mfp_len);
assert_non_null(malicious_file_path);
rc = snprintf(malicious_file_path, mfp_len,
"%s/mfile", current_dir);
assert_int_equal(rc, mfp_len);
free(current_dir);
rc = stat(malicious_file_path, &sb);
assert_int_not_equal(rc, 0);
// cleanup
remove(malicious_file_path);
free(malicious_file_path);
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -176,6 +226,9 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh_stderr,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_options_proxycommand_injection,
NULL,
session_teardown),
};

View File

@@ -38,6 +38,8 @@
#include <fcntl.h>
#include <pwd.h>
#define KEX_RETRY 32
static uint64_t bytes = 2048; /* 2KB (more than the authentication phase) */
static int sshd_setup(void **state)
@@ -146,6 +148,29 @@ static void torture_rekey_default(void **state)
ssh_disconnect(s->ssh.session);
}
static void sanity_check_session(void **state)
{
struct torture_state *s = *state;
struct ssh_crypto_struct *c = NULL;
c = s->ssh.session->current_crypto;
assert_non_null(c);
assert_int_equal(c->in_cipher->max_blocks,
bytes / c->in_cipher->blocksize);
assert_int_equal(c->out_cipher->max_blocks,
bytes / c->out_cipher->blocksize);
/* when strict kex is used, the newkeys reset the sequence number */
if ((s->ssh.session->flags & SSH_SESSION_FLAG_KEX_STRICT) != 0) {
assert_int_equal(c->out_cipher->packets, s->ssh.session->send_seq);
assert_int_equal(c->in_cipher->packets, s->ssh.session->recv_seq);
} else {
/* Otherwise we have less encrypted packets than transferred
* (first are not encrypted) */
assert_true(c->out_cipher->packets < s->ssh.session->send_seq);
assert_true(c->in_cipher->packets < s->ssh.session->recv_seq);
}
}
/* We lower the rekey limits manually and check that the rekey
* really happens when sending data
*/
@@ -164,16 +189,10 @@ static void torture_rekey_send(void **state)
rc = ssh_connect(s->ssh.session);
assert_ssh_return_code(s->ssh.session, rc);
/* The blocks limit is set correctly */
c = s->ssh.session->current_crypto;
assert_int_equal(c->in_cipher->max_blocks,
bytes / c->in_cipher->blocksize);
assert_int_equal(c->out_cipher->max_blocks,
bytes / c->out_cipher->blocksize);
/* We should have less encrypted packets than transfered (first are not encrypted) */
assert_true(c->out_cipher->packets < s->ssh.session->send_seq);
assert_true(c->in_cipher->packets < s->ssh.session->recv_seq);
sanity_check_session(state);
/* Copy the initial secret hash = session_id so we know we changed keys later */
c = s->ssh.session->current_crypto;
assert_non_null(c);
secret_hash = malloc(c->digest_len);
assert_non_null(secret_hash);
memcpy(secret_hash, c->secret_hash, c->digest_len);
@@ -190,10 +209,11 @@ static void torture_rekey_send(void **state)
rc = ssh_userauth_publickey_auto(s->ssh.session, NULL, NULL);
assert_int_equal(rc, SSH_AUTH_SUCCESS);
/* send ignore packets of up to 1KB to trigger rekey */
/* send ignore packets of up to 1KB to trigger rekey. Send little bit more
* to make sure it completes with all different ciphers */
memset(data, 0, sizeof(data));
memset(data, 'A', 128);
for (i = 0; i < 16; i++) {
for (i = 0; i < KEX_RETRY; i++) {
ssh_send_ignore(s->ssh.session, data);
ssh_handle_packets(s->ssh.session, 50);
}
@@ -269,14 +289,10 @@ static void torture_rekey_recv(void **state)
sftp_file file;
mode_t mask;
/* The blocks limit is set correctly */
c = s->ssh.session->current_crypto;
assert_int_equal(c->in_cipher->max_blocks, bytes / c->in_cipher->blocksize);
assert_int_equal(c->out_cipher->max_blocks, bytes / c->out_cipher->blocksize);
/* We should have less encrypted packets than transfered (first are not encrypted) */
assert_true(c->out_cipher->packets < s->ssh.session->send_seq);
assert_true(c->in_cipher->packets < s->ssh.session->recv_seq);
sanity_check_session(state);
/* Copy the initial secret hash = session_id so we know we changed keys later */
c = s->ssh.session->current_crypto;
assert_non_null(c);
secret_hash = malloc(c->digest_len);
assert_non_null(secret_hash);
memcpy(secret_hash, c->secret_hash, c->digest_len);
@@ -461,15 +477,10 @@ static void torture_rekey_different_kex(void **state)
assert_ssh_return_code(s->ssh.session, rc);
/* The blocks limit is set correctly */
c = s->ssh.session->current_crypto;
assert_int_equal(c->in_cipher->max_blocks,
bytes / c->in_cipher->blocksize);
assert_int_equal(c->out_cipher->max_blocks,
bytes / c->out_cipher->blocksize);
/* We should have less encrypted packets than transfered (first are not encrypted) */
assert_true(c->out_cipher->packets < s->ssh.session->send_seq);
assert_true(c->in_cipher->packets < s->ssh.session->recv_seq);
sanity_check_session(state);
/* Copy the initial secret hash = session_id so we know we changed keys later */
c = s->ssh.session->current_crypto;
assert_non_null(c);
secret_hash = malloc(c->digest_len);
assert_non_null(secret_hash);
memcpy(secret_hash, c->secret_hash, c->digest_len);
@@ -496,9 +507,15 @@ static void torture_rekey_different_kex(void **state)
* to make sure the rekey it completes with all different ciphers (paddings */
memset(data, 0, sizeof(data));
memset(data, 'A', 128);
for (i = 0; i < 20; i++) {
for (i = 0; i < KEX_RETRY; i++) {
ssh_send_ignore(s->ssh.session, data);
ssh_handle_packets(s->ssh.session, 50);
ssh_handle_packets(s->ssh.session, 100);
c = s->ssh.session->current_crypto;
/* SHA256 len */
if (c->digest_len != 32) {
break;
}
}
/* The rekey limit was restored in the new crypto to the same value */
@@ -568,9 +585,15 @@ static void torture_rekey_server_different_kex(void **state)
* to make sure the rekey it completes with all different ciphers (paddings */
memset(data, 0, sizeof(data));
memset(data, 'A', 128);
for (i = 0; i < 25; i++) {
for (i = 0; i < KEX_RETRY; i++) {
ssh_send_ignore(s->ssh.session, data);
ssh_handle_packets(s->ssh.session, 50);
ssh_handle_packets(s->ssh.session, 100);
c = s->ssh.session->current_crypto;
/* SHA256 len */
if (c->digest_len != 32) {
break;
}
}
/* Check that the secret hash is different than initially */
@@ -651,6 +674,92 @@ static void torture_rekey_server_recv(void **state)
#endif /* WITH_SFTP */
static void setup_server_for_good_guess(void *state)
{
const char *default_sshd_config = "KexAlgorithms curve25519-sha256";
const char *fips_sshd_config = "KexAlgorithms ecdh-sha2-nistp256";
const char *sshd_config = default_sshd_config;
if (ssh_fips_mode()) {
sshd_config = fips_sshd_config;
}
/* This sets an only supported kex algorithm that we do not have as a first
* option */
torture_update_sshd_config(state, sshd_config);
}
static void torture_rekey_guess_send(void **state)
{
struct torture_state *s = *state;
setup_server_for_good_guess(state);
/* Make the client send the first_kex_packet_follows flag during key
* exchange as well as during the rekey */
s->ssh.session->send_first_kex_follows = true;
torture_rekey_send(state);
}
static void torture_rekey_guess_wrong_send(void **state)
{
struct torture_state *s = *state;
const char *sshd_config = "KexAlgorithms diffie-hellman-group14-sha256";
/* This sets an only supported kex algorithm that we do not have as a first
* option */
torture_update_sshd_config(state, sshd_config);
/* Make the client send the first_kex_packet_follows flag during key
* exchange as well as during the rekey */
s->ssh.session->send_first_kex_follows = true;
torture_rekey_send(state);
}
#ifdef WITH_SFTP
static void torture_rekey_guess_recv(void **state)
{
struct torture_state *s = *state;
int rc;
setup_server_for_good_guess(state);
/* Make the client send the first_kex_packet_follows flag during key
* exchange as well as during the rekey */
s->ssh.session->send_first_kex_follows = true;
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_REKEY_DATA, &bytes);
assert_ssh_return_code(s->ssh.session, rc);
session_setup_sftp(state);
torture_rekey_recv(state);
}
static void torture_rekey_guess_wrong_recv(void **state)
{
struct torture_state *s = *state;
const char *sshd_config = "KexAlgorithms diffie-hellman-group14-sha256";
int rc;
/* This sets an only supported kex algorithm that we do not have as a first
* option */
torture_update_sshd_config(state, sshd_config);
/* Make the client send the first_kex_packet_follows flag during key
* exchange as well as during the rekey */
s->ssh.session->send_first_kex_follows = true;
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_REKEY_DATA, &bytes);
assert_ssh_return_code(s->ssh.session, rc);
session_setup_sftp(state);
torture_rekey_recv(state);
}
#endif /* WITH_SFTP */
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -671,19 +780,34 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_rekey_different_kex,
session_setup,
session_teardown),
/* Note, that this modifies the sshd_config */
/* TODO verify the two rekey are possible and the states are not broken after rekey */
cmocka_unit_test_setup_teardown(torture_rekey_server_different_kex,
session_setup,
session_teardown),
/* Note, that these tests modify the sshd_config so follow-up tests
* might get unexpected behavior if they do not update the server with
* torture_update_sshd_config() too */
cmocka_unit_test_setup_teardown(torture_rekey_server_send,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_rekey_guess_send,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_rekey_guess_wrong_send,
session_setup,
session_teardown),
#ifdef WITH_SFTP
cmocka_unit_test_setup_teardown(torture_rekey_server_recv,
session_setup_sftp_server,
session_teardown),
#endif /* WITH_SFTP */
cmocka_unit_test_setup_teardown(torture_rekey_server_different_kex,
cmocka_unit_test_setup_teardown(torture_rekey_guess_recv,
session_setup,
session_teardown),
/* TODO verify the two rekey are possible and the states are not broken after rekey */
cmocka_unit_test_setup_teardown(torture_rekey_guess_wrong_recv,
session_setup,
session_teardown),
#endif /* WITH_SFTP */
};
ssh_init();

View File

@@ -118,12 +118,47 @@ static void torture_channel_read_error(void **state) {
ssh_channel_free(channel);
}
static void torture_pubkey_hash(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
char *hash = NULL;
char *hexa = NULL;
int rc = 0;
/* bad arguments */
rc = ssh_get_pubkey_hash(session, NULL);
assert_int_equal(rc, SSH_ERROR);
rc = ssh_get_pubkey_hash(NULL, (unsigned char **)&hash);
assert_int_equal(rc, SSH_ERROR);
/* deprecated, but should be covered by tests! */
rc = ssh_get_pubkey_hash(session, (unsigned char **)&hash);
if (ssh_fips_mode()) {
/* When in FIPS mode, expect the call to fail */
assert_int_equal(rc, SSH_ERROR);
} else {
assert_int_equal(rc, MD5_DIGEST_LEN);
hexa = ssh_get_hexa((unsigned char *)hash, rc);
SSH_STRING_FREE_CHAR(hash);
assert_string_equal(hexa,
"ee:80:7f:61:f9:d5:be:f1:96:86:cc:96:7a:db:7a:7b");
SSH_STRING_FREE_CHAR(hexa);
}
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(torture_channel_read_error,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_pubkey_hash,
session_setup,
session_teardown),
};
ssh_init();

View File

@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEiwIBAAKB/QMTSsCQqarOIauonYgjAt8E+lgSWBU/43ITyDDzLM4IS4wCcqXB
1Fagz386FU1B2AcUqlPZ1+7RlaXkqgKr4nGHv00U/GG+YAUgUAw1G12kI4cvrnWr
FIXwcq+VTJNej5pHxEqcRLw7ZBorpqm2UsY5KLr5R3uMNap7koj1Hbt9lKsvfDn6
HjM4qY0ygx8hxf/4wCzIh5V4k9/UAMkqI2CM9c3yEE2aWh/4MDOnAFj+0T2sMAo8
jyOZ6v+W7hmEtsUc9mEv+5B+hhVeYO/RwxketJAQRPYDSPSi1mjtv9fnzGk15q/l
Hb2V/HP/pyIpao19A4daR0a4ia9Hk4UCAwEAAQKB/QKEaPxjrKzlWoQSWRdUaQY5
Idyy7yw9hiMa9BK1COh/u66XVlY86Fwb9puR5Fu/WF67WIuX1PpizJXkLBBRtuDs
lvY2BjrPQ/MONtc3JPYp4vbFXYxtAzh6zrTPhMVfcjV7Jr1XWZ+lEVOmhR2G4gvk
P2WDozIKWub3jMLTt4afgHCGaKfKEUpKjFkiAalz8oLVv8qV1FVPPDT2PWeKMuE3
XfoN7YUaP6+aPlNnjIv/3BDsrPsiKZ+AKXcERdPvVQa/LypzW08cqC6sIJKWVmQI
3KgoYs9VvbDXfQ8jKfcsTApZkSDaLX6tf3Ei+76R0lbV4L1rpypa25qj9YECfwHP
N+v/6yObJFL5/1rEuT7CFbfP8g5J8qUVufcPRKv//ChluLuWNxgLJmIv2ZffWwhe
GKHlT98QPgFvsMSOyLeut4beZYKDSeVNvEt9eCBjOax2jOBGo3hv8j/Fs8yAfZOV
Ardv2qUszubM+DVwjJzb3vaZyEesRucJISqkJeUCfwGzGdMp0LXrZ7aaQGgHj/P2
DKGq0E2gnj/EBapatjxKm4hMRn/vkTWjCDCryTnvJqkW/00tr4GqWXoeilBFD270
RcvbOe9LQmGlHIYzgwc5nfLDBQyeNnHRmkeD9LQRUfdTdHj4jf+35pHlsVUT0Rnl
IMNoRA6V07bySFdI3SECfiF+1rbrxuhaCRIA0Ax3pL0eGuuTgksAm8VlbCMTgSiC
kF1CrXXgSAHOZb02C9Bf4cwEFfjh/KxM/4eXDa+Rfg7JQJxmVLivqEAlxIOvIxBp
xDnSWAljmrrllozyQnBsJDbbOm6BLf5+e5wIuryHvnP7vHNEU0J24g/78PxrrQJ/
AVD4OzYzUfESzbUBFJBmyIZSmhJ0aOpwJOpniNvgLymI8zI/l22uhF/TQ/6HRbsV
sfcBmoA7YKzRx2ZHsIsLvN6p/4u1fsJGkuERCk5yt/HDhfPLwU321IeEeMaVia+w
T1/u4JF/SADhLTU69az3UJrHmQ7zRmh7I0DZDeB8gQJ+XqIqutPeerNtbqMjXGW8
TdpqZAzAQAv6dPgaH0W0OzJe2hP9uy0D84H5f8Im/irJh/AXo/QL3obXqopyeLf0
HfcUUnEZEBPlqsirZFtPClD+HL6Orf1je0oVV/aQssPkQl6/aXBNd+kS27U3NBML
LmRhC4+Q+/M5MlRggLtn
-----END RSA PRIVATE KEY-----
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEA0DehrU/ohoimMKojFXdo1uEAcqx4fS87AjDUz8t4s436ppP+0+U3
+qrhOCE/mXZvXewjTHltmEtCHNSbsWhYTjwrEQUDRNOVahn2PEQTcX/9itvsv9PX79Imbv
ZsLR0f1FsmorkWpnDQmuga7hYBFBj4sV+VML5ieoK2OraUEq46ILsxqRgUTetkErlzX7S2
SPE7vNM0ahmA+HNBuKNUD+BOtCzkqN54flGA9TZ7kapC7xqiRHK+ZzahQ2PFR4BxbVP1uT
DsanbjKOpBC4hISao3hi4iUnyj0gJ8itmkhQS+oI/2KWSGW01/k9W7jOUXDSt7LGUTSW6s
ILYHzmefCwAAA9B/6IFvf+iBbwAAAAdzc2gtcnNhAAABAQDQN6GtT+iGiKYwqiMVd2jW4Q
ByrHh9LzsCMNTPy3izjfqmk/7T5Tf6quE4IT+Zdm9d7CNMeW2YS0Ic1JuxaFhOPCsRBQNE
05VqGfY8RBNxf/2K2+y/09fv0iZu9mwtHR/UWyaiuRamcNCa6BruFgEUGPixX5UwvmJ6gr
Y6tpQSrjoguzGpGBRN62QSuXNftLZI8Tu80zRqGYD4c0G4o1QP4E60LOSo3nh+UYD1NnuR
qkLvGqJEcr5nNqFDY8VHgHFtU/W5MOxqduMo6kELiEhJqjeGLiJSfKPSAnyK2aSFBL6gj/
YpZIZbTX+T1buM5RcNK3ssZRNJbqwgtgfOZ58LAAAAAwEAAQAAAQEAxjzxFU0LGWtortSN
apaxnkPCZWuHm8gn6kILm3shg/IdPhORfrSxw1qF6ybcooN8LHPyd5D0oxaj70cMpK+vw2
zNo/qdzh2UF9x375Dw4hL1lgslMM3EvXPbW7IJ9DnSYCAYfLyzr+ug8JsjaKJSjIvp2xYh
uLLKl9FzJhtGhzDaJr9FCbSmd5R7Telz4En0Lwo/VxYvyzCoRwzhVUVqJZpdtF7/1du4tT
agfPzPYY9zM9muR7AawtzMc4UFvMzl1OtjOHYtqSMVBZx44fRpXT3/fy7A98+7erd0zTWj
s6gaz6I8VmRPk4iTdBH4KBzC8dGZQNMrY9SQ/ZANet8eYQAAAIBI8hS6bX00NpNXwOaEqr
jZKf/u1W71KHpYBAY1w3xanGqPVOX5PEsFH6NLjqSLF75Bk22pvJvZ8EAaoISyvLSqqO5t
1vvjCjVKALSaVIFDcA20NpCXRugmVT1HeQNKHCTt3yOoraL8Sh9wlRbxLmlxgISYS6uH6e
dEPa6qFshMVwAAAIEA7RFx7+mZJfrSJUu9pYiZJc6+Ns2WrSA2mgI+mIhWqreDK4Kw0a5g
akqD0mb9oPHySnf3lCe+17yqNxH2fcX0G3B5LxiRnFVNm2wC4ZGvb+yMU2+0uSI/Sf8L1N
sfWm+z4VC93Qhe0fIpuk8JAMNOwCvFcEFu5rr9sxHtPWjWtj0AAACBAODYXjs6jqsvW+3P
e0efFp9kIezi8CejSxVXX0/zmWMCpTw1laiUmK41coKTKBSDZcNgrsF/ns1uCrPg6C2u/y
evF8J+DeqU3vo1QhnRAJA2fLZk1Dr/GfAsp9mS9w6FdIQiQjQ0f/X9rYgAr9x4qMogYgrG
zkb7k6FUoGgD7sbnAAAAE2xpYnNzaF90b3J0dXJlX2F1dGgBAgMEBQYH
-----END OPENSSH PRIVATE KEY-----

View File

@@ -1 +1 @@
ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgHZLan4ufbTFWr8Hl/8JvZTLYa0eNNm2qov9zPlK7qfwAAAADAQABAAAA/QMTSsCQqarOIauonYgjAt8E+lgSWBU/43ITyDDzLM4IS4wCcqXB1Fagz386FU1B2AcUqlPZ1+7RlaXkqgKr4nGHv00U/GG+YAUgUAw1G12kI4cvrnWrFIXwcq+VTJNej5pHxEqcRLw7ZBorpqm2UsY5KLr5R3uMNap7koj1Hbt9lKsvfDn6HjM4qY0ygx8hxf/4wCzIh5V4k9/UAMkqI2CM9c3yEE2aWh/4MDOnAFj+0T2sMAo8jyOZ6v+W7hmEtsUc9mEv+5B+hhVeYO/RwxketJAQRPYDSPSi1mjtv9fnzGk15q/lHb2V/HP/pyIpao19A4daR0a4ia9Hk4UAAAAAAAAAAAAAAAEAAAATdG9ydHVyZV9hdXRoX2NhcmxvcwAAAAkAAAAFYWxpY2UAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBAKcDafm8fNluz8a9GQaWgk1XUJcchLleeubTke6xQlJbI+rcjWIIwd1gDuh7Mdr0YIVhsh6dpg/L4bpRJBGNhDPxK8BmjTpIU14lKxrWQAirHN09P2QGtGtgrf09lA+xhV9E+pkF2Zz6PCt/P3sgUQnJcwjjsWhMaSASrt67fPanH+10hnfgjkevkMMHGJxmLiOW7JFQkd9I+gHHKEXs6Q9fhtiStzr3WN4hAPG5uXrnRZgseAV9p3TFPMEgUTpdRvnkOnkCBF169KiyjU97QgoXHExWk/rrgsJtgrTou/qRyi18WWm9S1HXLHyNOgZxKirmxLNPC9dIcJBD1kDWG8UAAAEPAAAAB3NzaC1yc2EAAAEAhNLOXT0jyz/Web0HUyrtPCvUZsLkDyBWCNoNTfsxGVoYsE4WCpNwqQO1A4NT5AtIE+R7rn9wfjvXM7sYh6hJyq3HVEWhts1SkQVU7sQBrImTIrj2cWKR3gmQ+ehsgNFGhcFZTK77ugw1fMfzZRvKVTkRWhe6v92wQOtkoINtf3f1fK6xY+vLwAA/E4VdaRJmhwAaNpy3PfMAJytkCLjcjUSWHYDha4hs98/EBPduGNNNiZdyG7lcpSvvq9HBDxzOiHBa/We9m38/Dk4TNVkZ/wrtBFQxH75if6SgGa/feGJrKQHBru7sPh8dO4R1AmZaoLmRzMnzZOtB0oEXmBqHmw== libssh_torture_auth
ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgllK1Wz9hM1kUks5QXU/vXbDmzpQWMtFWObMvi9ymg38AAAADAQABAAABAQDQN6GtT+iGiKYwqiMVd2jW4QByrHh9LzsCMNTPy3izjfqmk/7T5Tf6quE4IT+Zdm9d7CNMeW2YS0Ic1JuxaFhOPCsRBQNE05VqGfY8RBNxf/2K2+y/09fv0iZu9mwtHR/UWyaiuRamcNCa6BruFgEUGPixX5UwvmJ6grY6tpQSrjoguzGpGBRN62QSuXNftLZI8Tu80zRqGYD4c0G4o1QP4E60LOSo3nh+UYD1NnuRqkLvGqJEcr5nNqFDY8VHgHFtU/W5MOxqduMo6kELiEhJqjeGLiJSfKPSAnyK2aSFBL6gj/YpZIZbTX+T1buM5RcNK3ssZRNJbqwgtgfOZ58LAAAAAAAAAAAAAAABAAAAE3RvcnR1cmVfYXV0aF9jYXJsb3MAAAAJAAAABWFsaWNlAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCnA2n5vHzZbs/GvRkGloJNV1CXHIS5Xnrm05HusUJSWyPq3I1iCMHdYA7oezHa9GCFYbIenaYPy+G6USQRjYQz8SvAZo06SFNeJSsa1kAIqxzdPT9kBrRrYK39PZQPsYVfRPqZBdmc+jwrfz97IFEJyXMI47FoTGkgEq7eu3z2px/tdIZ34I5Hr5DDBxicZi4jluyRUJHfSPoBxyhF7OkPX4bYkrc691jeIQDxubl650WYLHgFfad0xTzBIFE6XUb55Dp5AgRdevSoso1Pe0IKFxxMVpP664LCbYK06Lv6kcotfFlpvUtR1yx8jToGcSoq5sSzTwvXSHCQQ9ZA1hvFAAABFAAAAAxyc2Etc2hhMi01MTIAAAEAeI9eUAWyL5DVWBj0vU2kKdGxMXQx1Y8R68DXwXhnxfLwilJPa6IFg+g988lpF5aZzvAiX6TgDtJAhzfuBU+ZREGfdclUQIpz3xwDG76Gmg/DpQHdmqU76n2Na32s6+4SsSmWWKx6cPPdjbCRS0VMSrMohLuDyPGMoC7RjLfDDxqW5TIbMtqQdOiPl/0PpR73Q0FjB50Ec12buQDkExlEOi2Y+yB830vuTJN3ds7bx6NXM1Jjftg/8D0SzNRAIYDQFnpyXKO6kNrN66o48E3mrnVHXuFBTf+kpdYrK+1LKQVk/hVLBHr+NuVmQltL0zcjJfiXj7i5ZqcsqR1UAU5hKg== libssh_torture_auth

View File

@@ -1 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAA/QMTSsCQqarOIauonYgjAt8E+lgSWBU/43ITyDDzLM4IS4wCcqXB1Fagz386FU1B2AcUqlPZ1+7RlaXkqgKr4nGHv00U/GG+YAUgUAw1G12kI4cvrnWrFIXwcq+VTJNej5pHxEqcRLw7ZBorpqm2UsY5KLr5R3uMNap7koj1Hbt9lKsvfDn6HjM4qY0ygx8hxf/4wCzIh5V4k9/UAMkqI2CM9c3yEE2aWh/4MDOnAFj+0T2sMAo8jyOZ6v+W7hmEtsUc9mEv+5B+hhVeYO/RwxketJAQRPYDSPSi1mjtv9fnzGk15q/lHb2V/HP/pyIpao19A4daR0a4ia9Hk4U= libssh_torture_auth
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQN6GtT+iGiKYwqiMVd2jW4QByrHh9LzsCMNTPy3izjfqmk/7T5Tf6quE4IT+Zdm9d7CNMeW2YS0Ic1JuxaFhOPCsRBQNE05VqGfY8RBNxf/2K2+y/09fv0iZu9mwtHR/UWyaiuRamcNCa6BruFgEUGPixX5UwvmJ6grY6tpQSrjoguzGpGBRN62QSuXNftLZI8Tu80zRqGYD4c0G4o1QP4E60LOSo3nh+UYD1NnuRqkLvGqJEcr5nNqFDY8VHgHFtU/W5MOxqduMo6kELiEhJqjeGLiJSfKPSAnyK2aSFBL6gj/YpZIZbTX+T1buM5RcNK3ssZRNJbqwgtgfOZ58L libssh_torture_auth

View File

@@ -22,7 +22,7 @@
#include "pkd_keyutil.h"
#include "pkd_util.h"
void setup_rsa_key() {
void setup_rsa_key(void) {
int rc = 0;
if (access(LIBSSH_RSA_TESTKEY, F_OK) != 0) {
rc = system_checked(OPENSSH_KEYGEN " -t rsa -q -N \"\" -f "
@@ -31,7 +31,7 @@ void setup_rsa_key() {
assert_int_equal(rc, 0);
}
void setup_ed25519_key() {
void setup_ed25519_key(void) {
int rc = 0;
if (access(LIBSSH_ED25519_TESTKEY, F_OK) != 0) {
rc = system_checked(OPENSSH_KEYGEN " -t ed25519 -q -N \"\" -f "
@@ -41,7 +41,7 @@ void setup_ed25519_key() {
}
#ifdef HAVE_DSA
void setup_dsa_key() {
void setup_dsa_key(void) {
int rc = 0;
if (access(LIBSSH_DSA_TESTKEY, F_OK) != 0) {
rc = system_checked(OPENSSH_KEYGEN " -t dsa -q -N \"\" -f "
@@ -51,7 +51,7 @@ void setup_dsa_key() {
}
#endif
void setup_ecdsa_keys() {
void setup_ecdsa_keys(void) {
int rc = 0;
if (access(LIBSSH_ECDSA_256_TESTKEY, F_OK) != 0) {
@@ -71,27 +71,27 @@ void setup_ecdsa_keys() {
}
}
void cleanup_rsa_key() {
void cleanup_rsa_key(void) {
cleanup_key(LIBSSH_RSA_TESTKEY);
}
void cleanup_ed25519_key() {
void cleanup_ed25519_key(void) {
cleanup_key(LIBSSH_ED25519_TESTKEY);
}
#ifdef HAVE_DSA
void cleanup_dsa_key() {
void cleanup_dsa_key(void) {
cleanup_key(LIBSSH_DSA_TESTKEY);
}
#endif
void cleanup_ecdsa_keys() {
void cleanup_ecdsa_keys(void) {
cleanup_key(LIBSSH_ECDSA_256_TESTKEY);
cleanup_key(LIBSSH_ECDSA_384_TESTKEY);
cleanup_key(LIBSSH_ECDSA_521_TESTKEY);
}
void setup_openssh_client_keys() {
void setup_openssh_client_keys(void) {
int rc = 0;
if (access(OPENSSH_CA_TESTKEY, F_OK) != 0) {
@@ -184,7 +184,7 @@ void setup_openssh_client_keys() {
}
}
void cleanup_openssh_client_keys() {
void cleanup_openssh_client_keys(void) {
cleanup_key(OPENSSH_CA_TESTKEY);
cleanup_key(OPENSSH_RSA_TESTKEY);
cleanup_file(OPENSSH_RSA_TESTKEY "-sha256-cert.pub");
@@ -199,7 +199,7 @@ void cleanup_openssh_client_keys() {
}
}
void setup_dropbear_client_rsa_key() {
void setup_dropbear_client_rsa_key(void) {
int rc = 0;
if (access(DROPBEAR_RSA_TESTKEY, F_OK) != 0) {
rc = system_checked(DROPBEAR_KEYGEN " -t rsa -f "
@@ -208,6 +208,6 @@ void setup_dropbear_client_rsa_key() {
assert_int_equal(rc, 0);
}
void cleanup_dropbear_client_rsa_key() {
void cleanup_dropbear_client_rsa_key(void) {
unlink(DROPBEAR_RSA_TESTKEY);
}

View File

@@ -285,9 +285,7 @@ static int stop_server(void **state)
assert_non_null(s);
rc = torture_terminate_process(s->srv_pidfile);
if (rc != 0) {
fprintf(stderr, "XXXXXX Failed to terminate sshd\n");
}
assert_return_code(rc, errno);
unlink(s->srv_pidfile);
@@ -513,6 +511,12 @@ static void torture_server_config_ciphers(void **state)
/* Try each algorithm individually */
j = 0;
while(tokens->tokens[j] != NULL) {
char *cmp = strstr(OPENSSH_CIPHERS, tokens->tokens[j]);
if (cmp == NULL) {
/* This cipher is not supported by the OpenSSH. Skip it */
j++;
continue;
}
snprintf(config_content,
sizeof(config_content),
"HostKey %s\nCiphers %s\n",

View File

@@ -250,8 +250,12 @@ int torture_terminate_process(const char *pidfile)
rc = kill(pid, 0);
if (rc != 0) {
is_running = 0;
break;
/* Process not found */
if (errno == ESRCH) {
is_running = 0;
rc = 0;
break;
}
}
}
@@ -260,7 +264,7 @@ int torture_terminate_process(const char *pidfile)
"WARNING: The process with pid %u is still running!\n", pid);
}
return 0;
return rc;
}
ssh_session torture_ssh_session(struct torture_state *s,
@@ -856,21 +860,16 @@ static int torture_wait_for_daemon(unsigned int seconds)
return 1;
}
void torture_setup_sshd_server(void **state, bool pam)
static int torture_start_sshd_server(void **state)
{
struct torture_state *s;
struct torture_state *s = *state;
char sshd_start_cmd[1024];
int rc;
torture_setup_socket_dir(state);
torture_setup_create_sshd_config(state, pam);
/* Set the default interface for the server */
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
setenv("PAM_WRAPPER", "1", 1);
s = *state;
snprintf(sshd_start_cmd, sizeof(sshd_start_cmd),
SSHD_EXECUTABLE " -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log",
s->srv_config, s->socket_dir, s->socket_dir);
@@ -882,7 +881,20 @@ void torture_setup_sshd_server(void **state, bool pam)
unsetenv("PAM_WRAPPER");
/* Wait until the sshd is ready to accept connections */
rc = torture_wait_for_daemon(5);
rc = torture_wait_for_daemon(15);
assert_int_equal(rc, 0);
return SSH_OK;
}
void torture_setup_sshd_server(void **state, bool pam)
{
int rc;
torture_setup_socket_dir(state);
torture_setup_create_sshd_config(state, pam);
rc = torture_start_sshd_server(state);
assert_int_equal(rc, 0);
}
@@ -922,29 +934,12 @@ static int
torture_reload_sshd_server(void **state)
{
struct torture_state *s = *state;
pid_t pid;
int rc;
/* read the pidfile */
pid = torture_read_pidfile(s->srv_pidfile);
assert_int_not_equal(pid, -1);
rc = torture_terminate_process(s->srv_pidfile);
assert_return_code(rc, errno);
kill(pid, SIGHUP);
/* 10 ms */
usleep(10 * 1000);
rc = kill(pid, 0);
if (rc != 0) {
fprintf(stderr,
"ERROR: SSHD process %u died during reload!\n", pid);
return SSH_ERROR;
}
/* Wait until the sshd is ready to accept connections */
rc = torture_wait_for_daemon(5);
assert_int_equal(rc, 0);
return SSH_OK;
return torture_start_sshd_server(state);
}
/* @brief: Updates SSHD server configuration with more options and
@@ -980,9 +975,7 @@ void torture_teardown_sshd_server(void **state)
int rc;
rc = torture_terminate_process(s->srv_pidfile);
if (rc != 0) {
fprintf(stderr, "XXXXXX Failed to terminate sshd\n");
}
assert_return_code(rc, errno);
torture_teardown_socket_dir(state);
}

View File

@@ -671,6 +671,32 @@ static void torture_config_proxyjump(void **state) {
assert_string_equal(session->opts.ProxyCommand,
"ssh -W [%h]:%p 2620:52:0::fed");
/* Multiple @ is allowed in second jump */
torture_write_file(LIBSSH_TESTCONFIG11,
"Host allowed-hostname\n"
"\tProxyJump localhost,user@principal.com@jumpbox:22\n"
"");
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "allowed-hostname");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code(session, ret);
assert_string_equal(session->opts.ProxyCommand,
"ssh -J user@principal.com@jumpbox:22 -W [%h]:%p localhost");
/* Multiple @ is allowed */
torture_write_file(LIBSSH_TESTCONFIG11,
"Host allowed-hostname\n"
"\tProxyJump user@principal.com@jumpbox:22\n"
"");
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "allowed-hostname");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code(session, ret);
assert_string_equal(session->opts.ProxyCommand,
"ssh -l user@principal.com -p 22 -W [%h]:%p jumpbox");
/* In this part, we try various other config files and strings. */
/* Try to create some invalid configurations */
/* Non-numeric port */
torture_write_file(LIBSSH_TESTCONFIG11,
@@ -682,16 +708,6 @@ static void torture_config_proxyjump(void **state) {
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
/* Too many @ */
torture_write_file(LIBSSH_TESTCONFIG11,
"Host bad-hostname\n"
"\tProxyJump user@principal.com@jumpbox:22\n"
"");
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
/* Braces mismatch in hostname */
torture_write_file(LIBSSH_TESTCONFIG11,
"Host mismatch\n"
@@ -752,16 +768,6 @@ static void torture_config_proxyjump(void **state) {
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
/* Too many @ in second jump */
torture_write_file(LIBSSH_TESTCONFIG11,
"Host bad-hostname\n"
"\tProxyJump localhost,user@principal.com@jumpbox:22\n"
"");
torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
/* Braces mismatch in second jump */
torture_write_file(LIBSSH_TESTCONFIG11,
"Host mismatch\n"

View File

@@ -17,7 +17,14 @@
#include "misc.c"
#include "error.c"
#ifdef _WIN32
#include <netioapi.h>
#else
#include <net/if.h>
#endif
#define TORTURE_TEST_DIR "/usr/local/bin/truc/much/.."
#define TORTURE_IPV6_LOCAL_LINK "fe80::98e1:82ff:fe8d:28b3%%%s"
const char template[] = "temp_dir_XXXXXX";
@@ -656,6 +663,116 @@ static void torture_ssh_newline_vis(UNUSED_PARAM(void **state))
assert_string_equal(buffer, "a\\nb\\n");
}
static void torture_ssh_check_hostname_syntax(void **state)
{
int rc;
(void)state;
rc = ssh_check_hostname_syntax("duckduckgo.com");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("www.libssh.org");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("Some-Thing.com");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("amazon.a23456789012345678901234567890123456789012345678901234567890123");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("amazon.a23456789012345678901234567890123456789012345678901234567890123.a23456789012345678901234567890123456789012345678901234567890123.ok");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("amazon.a23456789012345678901234567890123456789012345678901234567890123.a23456789012345678901234567890123456789012345678901234567890123.a23456789012345678901234567890123456789012345678901234567890123");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("lavabo-inter.innocentes-manus-meas");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("localhost");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("a");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("a-0.b-b");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax("libssh.");
assert_int_equal(rc, SSH_OK);
rc = ssh_check_hostname_syntax(NULL);
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("/");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("@");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("[");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("`");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("{");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("&");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("|");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("\"");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("`");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax(" ");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("*the+giant&\"rooks\".c0m");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("!www.libssh.org");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("--.--");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("libssh.a234567890123456789012345678901234567890123456789012345678901234");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("libssh.a234567890123456789012345678901234567890123456789012345678901234.a234567890123456789012345678901234567890123456789012345678901234");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("libssh-");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("fe80::9656:d028:8652:66b6");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax(".");
assert_int_equal(rc, SSH_ERROR);
rc = ssh_check_hostname_syntax("..");
assert_int_equal(rc, SSH_ERROR);
}
static void torture_ssh_is_ipaddr(void **state) {
int rc;
char *interf = malloc(64);
char *test_interf = malloc(128);
(void)state;
assert_non_null(interf);
assert_non_null(test_interf);
rc = ssh_is_ipaddr("201.255.3.69");
assert_int_equal(rc, 1);
rc = ssh_is_ipaddr("::1");
assert_int_equal(rc, 1);
rc = ssh_is_ipaddr("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
assert_int_equal(rc, 1);
if_indextoname(1, interf);
assert_non_null(interf);
rc = sprintf(test_interf, TORTURE_IPV6_LOCAL_LINK, interf);
/* the "%%s" is not written */
assert_int_equal(rc, strlen(interf) + strlen(TORTURE_IPV6_LOCAL_LINK) - 3);
rc = ssh_is_ipaddr(test_interf);
assert_int_equal(rc, 1);
free(interf);
free(test_interf);
rc = ssh_is_ipaddr("..");
assert_int_equal(rc, 0);
rc = ssh_is_ipaddr(":::");
assert_int_equal(rc, 0);
rc = ssh_is_ipaddr("1.1.1.1.1");
assert_int_equal(rc, 0);
rc = ssh_is_ipaddr("1.1");
assert_int_equal(rc, 0);
rc = ssh_is_ipaddr("caesar");
assert_int_equal(rc, 0);
rc = ssh_is_ipaddr("::xa:1");
assert_int_equal(rc, 0);
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -678,6 +795,8 @@ int torture_run_tests(void) {
cmocka_unit_test(torture_ssh_newline_vis),
cmocka_unit_test(torture_ssh_mkdirs),
cmocka_unit_test(torture_ssh_quote_file_name),
cmocka_unit_test(torture_ssh_check_hostname_syntax),
cmocka_unit_test(torture_ssh_is_ipaddr),
};
ssh_init();