Compare commits

..

25 Commits

Author SHA1 Message Date
Jakub Jelen
5dc10ff63c tests: Increase test coverage for IPv6 address parsing as hostnames
This was an issue in cockpit:

https://github.com/cockpit-project/cockpit/issues/19772

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 6f6e453d7b)
2023-12-22 13:14:35 +01:00
Jakub Jelen
72f59157e6 Fix regression in IPv6 addresses in hostname parsing
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit 4f997aee7c)
2023-12-22 13:10:59 +01:00
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
45 changed files with 1739 additions and 604 deletions

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.7 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.8")
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

@@ -1,5 +1,10 @@
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

View File

@@ -26,6 +26,8 @@
#ifndef CONFIG_PARSER_H_
#define CONFIG_PARSER_H_
#include <stdbool.h>
char *ssh_config_get_cmd(char **str);
char *ssh_config_get_token(char **str);
@@ -45,13 +47,16 @@ int ssh_config_get_yesno(char **str, int notfound);
* be stored or NULL if we do not care about the result.
* @param[out] port Pointer to the location, where the new port will
* be stored or NULL if we do not care about the result.
* @param[in] ignore_port Set to true if the we should not attempt to parse
* port number.
*
* @returns SSH_OK if the provided string is in format of SSH URI,
* SSH_ERROR on failure
*/
int ssh_config_parse_uri(const char *tok,
char **username,
char **hostname,
char **port);
char **username,
char **hostname,
char **port,
bool ignore_port);
#endif /* LIBSSH_CONFIG_H_ */

View File

@@ -36,6 +36,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit);
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

@@ -80,6 +80,12 @@ enum ssh_pending_call_e {
* 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

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.8
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

@@ -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

@@ -324,7 +324,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
}
if (parse_entry) {
/* We actually care only about the first item */
rv = ssh_config_parse_uri(cp, &username, &hostname, &port);
rv = ssh_config_parse_uri(cp, &username, &hostname, &port, false);
/* The rest of the list needs to be passed on */
if (endp != NULL) {
next = strdup(endp + 1);
@@ -335,7 +335,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
}
} else {
/* The rest is just sanity-checked to avoid failures later */
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL);
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL, false);
}
if (rv != SSH_OK) {
goto out;

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)
{
@@ -133,12 +134,14 @@ int ssh_config_get_yesno(char **str, int notfound)
}
int ssh_config_parse_uri(const char *tok,
char **username,
char **hostname,
char **port)
char **username,
char **hostname,
char **port,
bool ignore_port)
{
char *endp = NULL;
long port_n;
int rc;
/* Sanitize inputs */
if (username != NULL) {
@@ -152,7 +155,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) {
@@ -180,12 +183,17 @@ int ssh_config_parse_uri(const char *tok,
if (endp == NULL) {
goto error;
}
} else {
/* Hostnames or aliases expand to the last colon or to the end */
} else if (!ignore_port) {
/* Hostnames or aliases expand to the last colon (if port is requested)
* or to the end */
endp = strrchr(tok, ':');
if (endp == NULL) {
endp = strchr(tok, '\0');
}
} else {
/* If no port is requested, expand to the end of line
* (to accommodate the IPv6 addresses) */
endp = strchr(tok, '\0');
}
if (tok == endp) {
/* Zero-length hostnames are not valid */
@@ -196,6 +204,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

@@ -335,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;
@@ -502,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

@@ -287,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

@@ -386,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:
@@ -532,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

@@ -93,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) {

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 {

View File

@@ -163,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,"\
@@ -491,6 +494,27 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
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) {
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;
}
} 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
@@ -714,11 +738,8 @@ 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. */
@@ -767,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;
}
@@ -886,11 +936,19 @@ int ssh_kex_select_methods (ssh_session session)
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++) {

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);
}
@@ -1734,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,18 @@ 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;
rc = ssh_config_parse_uri(value, &username, &hostname, NULL, true);
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 (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

@@ -1309,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;
@@ -1331,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);
@@ -1347,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;
}
@@ -1521,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
@@ -1829,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)) {

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;

View File

@@ -195,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) {

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

@@ -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

@@ -148,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
*/
@@ -166,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);
@@ -272,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);
@@ -464,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);

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

@@ -2,6 +2,7 @@
#define LIBSSH_STATIC
#include <errno.h>
#include "torture.h"
#include "libssh/options.h"
#include "libssh/session.h"
@@ -671,6 +672,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 +709,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 +769,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"
@@ -991,6 +998,53 @@ static void torture_config_match_pattern(void **state)
}
static void torture_config_parse_uri(void **state)
{
char *username = NULL;
char *hostname = NULL;
char *port = NULL;
int rc;
(void)state; /* unused */
rc = ssh_config_parse_uri("localhost", &username, &hostname, &port, false);
assert_return_code(rc, errno);
assert_null(username);
assert_string_equal(hostname, "localhost");
SAFE_FREE(hostname);
assert_null(port);
rc = ssh_config_parse_uri("1.2.3.4", &username, &hostname, &port, false);
assert_return_code(rc, errno);
assert_null(username);
assert_string_equal(hostname, "1.2.3.4");
SAFE_FREE(hostname);
assert_null(port);
rc = ssh_config_parse_uri("1.2.3.4:2222", &username, &hostname, &port, false);
assert_return_code(rc, errno);
assert_null(username);
assert_string_equal(hostname, "1.2.3.4");
SAFE_FREE(hostname);
assert_string_equal(port, "2222");
SAFE_FREE(port);
rc = ssh_config_parse_uri("[1:2:3::4]:2222", &username, &hostname, &port, false);
assert_return_code(rc, errno);
assert_null(username);
assert_string_equal(hostname, "1:2:3::4");
SAFE_FREE(hostname);
assert_string_equal(port, "2222");
SAFE_FREE(port);
/* do not want port */
rc = ssh_config_parse_uri("1:2:3::4", &username, &hostname, NULL, true);
assert_return_code(rc, errno);
assert_null(username);
assert_string_equal(hostname, "1:2:3::4");
SAFE_FREE(hostname);
}
int torture_run_tests(void) {
int rc;
@@ -1006,6 +1060,7 @@ int torture_run_tests(void) {
cmocka_unit_test(torture_config_rekey),
cmocka_unit_test(torture_config_pubkeyacceptedkeytypes),
cmocka_unit_test(torture_config_match_pattern),
cmocka_unit_test(torture_config_parse_uri),
};

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();

View File

@@ -59,12 +59,34 @@ static void torture_options_set_host(void **state) {
assert_non_null(session->opts.host);
assert_string_equal(session->opts.host, "localhost");
/* IPv4 address */
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "127.1.1.1");
assert_true(rc == 0);
assert_non_null(session->opts.host);
assert_string_equal(session->opts.host, "127.1.1.1");
assert_null(session->opts.username);
/* IPv6 address */
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "::1");
assert_true(rc == 0);
assert_non_null(session->opts.host);
assert_string_equal(session->opts.host, "::1");
assert_null(session->opts.username);
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "guru@meditation");
assert_true(rc == 0);
assert_non_null(session->opts.host);
assert_string_equal(session->opts.host, "meditation");
assert_non_null(session->opts.username);
assert_string_equal(session->opts.username, "guru");
/* more @ in uri is OK -- it should go to the username */
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "at@login@hostname");
assert_true(rc == 0);
assert_non_null(session->opts.host);
assert_string_equal(session->opts.host, "hostname");
assert_non_null(session->opts.username);
assert_string_equal(session->opts.username, "at@login");
}
static void torture_options_set_ciphers(void **state) {