diff options
author | George Hazan <george.hazan@gmail.com> | 2023-06-09 21:40:16 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2023-06-09 21:40:16 +0300 |
commit | 927f00cc19b7239a1fe12abe30b472d61b753d8d (patch) | |
tree | 68a190dd83dc2dcceb82464a1953f2701af2a109 /libs | |
parent | 1b241cad53b8c3c5300409fe681de18e636dcf3d (diff) |
fixes #3551 (Update libssh2 to 1.11.0)
Diffstat (limited to 'libs')
61 files changed, 8846 insertions, 9983 deletions
diff --git a/libs/libssh2/include/libssh2.h b/libs/libssh2/include/libssh2.h index d33df03c31..fb760dd2fb 100644 --- a/libs/libssh2/include/libssh2.h +++ b/libs/libssh2/include/libssh2.h @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2009, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2009-2015 Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson <simon@josefsson.org> +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson <simon@josefsson.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,27 +35,29 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIBSSH2_H #define LIBSSH2_H 1 -#define LIBSSH2_COPYRIGHT "2004-2019 The libssh2 project and its contributors." +#define LIBSSH2_COPYRIGHT "The libssh2 project and its contributors." /* We use underscore instead of dash when appending DEV in dev versions just to make the BANNER define (used by src/session.c) be a valid SSH banner. Release versions have no appended strings and may of course not have dashes either. */ -#define LIBSSH2_VERSION "1.9.0" +#define LIBSSH2_VERSION "1.11.1_DEV" /* The numeric version number is also available "in parts" by using these defines: */ -#define LIBSSH2_VERSION_MAJOR 1 -#define LIBSSH2_VERSION_MINOR 9 -#define LIBSSH2_VERSION_PATCH 0 +#define LIBSSH2_VERSION_MAJOR 1 +#define LIBSSH2_VERSION_MINOR 11 +#define LIBSSH2_VERSION_PATCH 1 /* This is the numeric version of the libssh2 version number, meant for easier - parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will + parsing and comparisons by programs. The LIBSSH2_VERSION_NUM define will always follow this syntax: 0xXXYYZZ @@ -69,7 +71,7 @@ and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. */ -#define LIBSSH2_VERSION_NUM 0x010900 +#define LIBSSH2_VERSION_NUM 0x010b01 /* * This is the date and time when the full source package was created. The @@ -80,14 +82,19 @@ * * "Mon Feb 12 11:35:33 UTC 2007" */ -#define LIBSSH2_TIMESTAMP "Thu Jun 20 06:19:26 UTC 2019" +#define LIBSSH2_TIMESTAMP "DEV" #ifndef RC_INVOKED #ifdef __cplusplus extern "C" { #endif -#ifdef _WIN32 + +#if defined(_WIN32) || defined(WIN32) +#define LIBSSH2_WIN32 +#endif + +#ifdef LIBSSH2_WIN32 # include <basetsd.h> # include <winsock2.h> #endif @@ -100,7 +107,7 @@ extern "C" { /* Allow alternate API prefix from CFLAGS or calling app */ #ifndef LIBSSH2_API # ifdef LIBSSH2_WIN32 -# ifdef _WINDLL +# if defined(LIBSSH2_EXPORTS) || defined(DLL_EXPORT) || defined(_WINDLL) # ifdef LIBSSH2_LIBRARY # define LIBSSH2_API __declspec(dllexport) # else @@ -118,16 +125,6 @@ extern "C" { # include <sys/uio.h> #endif -#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) -# include <sys/bsdskt.h> -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned int uint32_t; -typedef int int32_t; -typedef unsigned long long uint64_t; -typedef long long int64_t; -#endif - #ifdef _MSC_VER typedef unsigned char uint8_t; typedef unsigned short int uint16_t; @@ -147,13 +144,13 @@ typedef unsigned long long libssh2_uint64_t; typedef long long libssh2_int64_t; #endif -#ifdef WIN32 +#ifdef LIBSSH2_WIN32 typedef SOCKET libssh2_socket_t; #define LIBSSH2_INVALID_SOCKET INVALID_SOCKET -#else /* !WIN32 */ +#else /* !LIBSSH2_WIN32 */ typedef int libssh2_socket_t; #define LIBSSH2_INVALID_SOCKET -1 -#endif /* WIN32 */ +#endif /* LIBSSH2_WIN32 */ /* * Determine whether there is small or large file support on windows. @@ -179,7 +176,7 @@ typedef int libssh2_socket_t; # undef LIBSSH2_USE_WIN32_LARGE_FILES #endif -#if defined(_WIN32) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) && \ +#if defined(LIBSSH2_WIN32) && !defined(LIBSSH2_USE_WIN32_LARGE_FILES) && \ !defined(LIBSSH2_USE_WIN32_SMALL_FILES) # define LIBSSH2_USE_WIN32_SMALL_FILES #endif @@ -190,8 +187,6 @@ typedef int libssh2_socket_t; #ifdef LIBSSH2_USE_WIN32_LARGE_FILES # include <io.h> -# include <sys/types.h> -# include <sys/stat.h> # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%I64d" typedef struct _stati64 libssh2_struct_stat; typedef __int64 libssh2_struct_stat_size; @@ -202,8 +197,6 @@ typedef __int64 libssh2_struct_stat_size; */ #ifdef LIBSSH2_USE_WIN32_SMALL_FILES -# include <sys/types.h> -# include <sys/stat.h> # ifndef _WIN32_WCE # define LIBSSH2_STRUCT_STAT_SIZE_FORMAT "%d" typedef struct _stat libssh2_struct_stat; @@ -233,12 +226,6 @@ typedef off_t libssh2_struct_stat_size; #define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER #define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n" -/* Default generate and safe prime sizes for - diffie-hellman-group-exchange-sha1 */ -#define LIBSSH2_DH_GEX_MINGROUP 1024 -#define LIBSSH2_DH_GEX_OPTGROUP 1536 -#define LIBSSH2_DH_GEX_MAXGROUP 2048 - /* Defaults for pty requests */ #define LIBSSH2_TERM_WIDTH 80 #define LIBSSH2_TERM_HEIGHT 24 @@ -270,8 +257,8 @@ typedef off_t libssh2_struct_stat_size; typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT { - char *text; - unsigned int length; + unsigned char *text; + size_t length; unsigned char echo; } LIBSSH2_USERAUTH_KBDINT_PROMPT; @@ -281,48 +268,88 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE unsigned int length; } LIBSSH2_USERAUTH_KBDINT_RESPONSE; +typedef struct _LIBSSH2_SK_SIG_INFO { + uint8_t flags; + uint32_t counter; + unsigned char *sig_r; + size_t sig_r_len; + unsigned char *sig_s; + size_t sig_s_len; +} LIBSSH2_SK_SIG_INFO; + /* 'publickey' authentication callback */ #define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \ - int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ - const unsigned char *data, size_t data_len, void **abstract) + int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ + const unsigned char *data, size_t data_len, void **abstract) /* 'keyboard-interactive' authentication callback */ #define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \ - void name_(const char *name, int name_len, const char *instruction, \ - int instruction_len, int num_prompts, \ - const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \ - LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) + void name_(const char *name, int name_len, const char *instruction, \ + int instruction_len, int num_prompts, \ + const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \ + LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) + +/* SK authentication callback */ +#define LIBSSH2_USERAUTH_SK_SIGN_FUNC(name) \ + int name(LIBSSH2_SESSION *session, LIBSSH2_SK_SIG_INFO *sig_info, \ + const unsigned char *data, size_t data_len, \ + int algorithm, uint8_t flags, \ + const char *application, const unsigned char *key_handle, \ + size_t handle_len, \ + void **abstract) + +/* Flags for SK authentication */ +#define LIBSSH2_SK_PRESENCE_REQUIRED 0x01 +#define LIBSSH2_SK_VERIFICATION_REQUIRED 0x04 /* Callbacks for special SSH packets */ #define LIBSSH2_IGNORE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ + void **abstract) #define LIBSSH2_DEBUG_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int always_display, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, int always_display, \ + const char *message, int message_len, \ + const char *language, int language_len, \ + void **abstract) #define LIBSSH2_DISCONNECT_FUNC(name) \ - void name(LIBSSH2_SESSION *session, int reason, const char *message, \ - int message_len, const char *language, int language_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, int reason, \ + const char *message, int message_len, \ + const char *language, int language_len, \ + void **abstract) #define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) \ - void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ - void **abstract) + void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ + void **abstract) #define LIBSSH2_MACERROR_FUNC(name) \ - int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ - void **abstract) + int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ + void **abstract) #define LIBSSH2_X11_OPEN_FUNC(name) \ - void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ - const char *shost, int sport, void **abstract) + void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ + const char *shost, int sport, void **abstract) + +#define LIBSSH2_AUTHAGENT_FUNC(name) \ + void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ + void **abstract) + +#define LIBSSH2_ADD_IDENTITIES_FUNC(name) \ + void name(LIBSSH2_SESSION *session, void *buffer, \ + const char *agent_path, void **abstract) + +#define LIBSSH2_AUTHAGENT_SIGN_FUNC(name) \ + int name(LIBSSH2_SESSION* session, \ + unsigned char *blob, unsigned int blen, \ + const unsigned char *data, unsigned int dlen, \ + unsigned char **signature, unsigned int *sigLen, \ + const char *agentPath, \ + void **abstract) #define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \ - void name(LIBSSH2_SESSION *session, void **session_abstract, \ - LIBSSH2_CHANNEL *channel, void **channel_abstract) + void name(LIBSSH2_SESSION *session, void **session_abstract, \ + LIBSSH2_CHANNEL *channel, void **channel_abstract) /* I/O callbacks */ #define LIBSSH2_RECV_FUNC(name) \ @@ -335,13 +362,16 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE int flags, void **abstract) /* libssh2_session_callback_set() constants */ -#define LIBSSH2_CALLBACK_IGNORE 0 -#define LIBSSH2_CALLBACK_DEBUG 1 -#define LIBSSH2_CALLBACK_DISCONNECT 2 -#define LIBSSH2_CALLBACK_MACERROR 3 -#define LIBSSH2_CALLBACK_X11 4 -#define LIBSSH2_CALLBACK_SEND 5 -#define LIBSSH2_CALLBACK_RECV 6 +#define LIBSSH2_CALLBACK_IGNORE 0 +#define LIBSSH2_CALLBACK_DEBUG 1 +#define LIBSSH2_CALLBACK_DISCONNECT 2 +#define LIBSSH2_CALLBACK_MACERROR 3 +#define LIBSSH2_CALLBACK_X11 4 +#define LIBSSH2_CALLBACK_SEND 5 +#define LIBSSH2_CALLBACK_RECV 6 +#define LIBSSH2_CALLBACK_AUTHAGENT 7 +#define LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES 8 +#define LIBSSH2_CALLBACK_AUTHAGENT_SIGN 9 /* libssh2_session_method_pref() constants */ #define LIBSSH2_METHOD_KEX 0 @@ -354,10 +384,12 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE #define LIBSSH2_METHOD_COMP_SC 7 #define LIBSSH2_METHOD_LANG_CS 8 #define LIBSSH2_METHOD_LANG_SC 9 +#define LIBSSH2_METHOD_SIGN_ALGO 10 /* flags */ #define LIBSSH2_FLAG_SIGPIPE 1 #define LIBSSH2_FLAG_COMPRESS 2 +#define LIBSSH2_FLAG_QUOTE_PATHS 3 typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION; typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL; @@ -365,6 +397,25 @@ typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER; typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS; typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT; +/* SK signature callback */ +typedef struct _LIBSSH2_PRIVKEY_SK { + int algorithm; + uint8_t flags; + const char *application; + const unsigned char *key_handle; + size_t handle_len; + LIBSSH2_USERAUTH_SK_SIGN_FUNC((*sign_callback)); + void **orig_abstract; +} LIBSSH2_PRIVKEY_SK; + +int +libssh2_sign_sk(LIBSSH2_SESSION *session, + unsigned char **sig, + size_t *sig_len, + const unsigned char *data, + size_t data_len, + void **abstract); + typedef struct _LIBSSH2_POLLFD { unsigned char type; /* LIBSSH2_POLLFD_* below */ @@ -503,6 +554,9 @@ typedef struct _LIBSSH2_POLLFD { #define LIBSSH2_ERROR_KNOWN_HOSTS -46 #define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47 #define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48 +#define LIBSSH2_ERROR_RANDGEN -49 +#define LIBSSH2_ERROR_MISSING_USERAUTH_BANNER -50 +#define LIBSSH2_ERROR_ALGO_UNSUPPORTED -51 /* this is a define to provide the old (<= 1.2.7) name */ #define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV @@ -545,7 +599,7 @@ LIBSSH2_API void libssh2_free(LIBSSH2_SESSION *session, void *ptr); * * Fills algs with a list of supported acryptographic algorithms. Returns a * non-negative number (number of supported algorithms) on success or a - * negative number (an eror code) on failure. + * negative number (an error code) on failure. * * NOTE: on success, algs must be deallocated (by calling libssh2_free) when * not needed anymore @@ -578,8 +632,8 @@ LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, const char *description, const char *lang); #define libssh2_session_disconnect(session, description) \ - libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ - (description), "") + libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ + (description), "") LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session); @@ -611,6 +665,8 @@ LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session); LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len); +LIBSSH2_API int libssh2_userauth_banner(LIBSSH2_SESSION *session, + char **banner); LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); LIBSSH2_API int @@ -620,12 +676,13 @@ libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *password, unsigned int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC - ((*passwd_change_cb))); + ((*passwd_change_cb))); #define libssh2_userauth_password(session, username, password) \ - libssh2_userauth_password_ex((session), (username), \ - (unsigned int)strlen(username), \ - (password), (unsigned int)strlen(password), NULL) + libssh2_userauth_password_ex((session), (username), \ + (unsigned int)strlen(username), \ + (password), (unsigned int)strlen(password), \ + NULL) LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, @@ -635,11 +692,11 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *privatekey, const char *passphrase); -#define libssh2_userauth_publickey_fromfile(session, username, publickey, \ - privatekey, passphrase) \ - libssh2_userauth_publickey_fromfile_ex((session), (username), \ +#define libssh2_userauth_publickey_fromfile(session, username, publickey, \ + privatekey, passphrase) \ + libssh2_userauth_publickey_fromfile_ex((session), (username), \ (unsigned int)strlen(username), \ - (publickey), \ + (publickey), \ (privatekey), (passphrase)) LIBSSH2_API int @@ -648,7 +705,7 @@ libssh2_userauth_publickey(LIBSSH2_SESSION *session, const unsigned char *pubkeydata, size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), + ((*sign_callback)), void **abstract); LIBSSH2_API int @@ -663,16 +720,16 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *local_username, unsigned int local_username_len); -#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ +#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ privatekey, passphrase, hostname) \ - libssh2_userauth_hostbased_fromfile_ex((session), (username), \ - (unsigned int)strlen(username), \ - (publickey), \ - (privatekey), (passphrase), \ - (hostname), \ - (unsigned int)strlen(hostname), \ - (username), \ - (unsigned int)strlen(username)) + libssh2_userauth_hostbased_fromfile_ex((session), (username), \ + (unsigned int)strlen(username), \ + (publickey), \ + (privatekey), (passphrase), \ + (hostname), \ + (unsigned int)strlen(hostname), \ + (username), \ + (unsigned int)strlen(username)) LIBSSH2_API int libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, @@ -688,21 +745,34 @@ libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, * response_callback is provided with filled by library prompts array, * but client must allocate and fill individual responses. Responses * array is already allocated. Responses data will be freed by libssh2 - * after callback return, but before subsequent callback invokation. + * after callback return, but before subsequent callback invocation. */ LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, unsigned int username_len, - LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC( - (*response_callback))); + LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC + ((*response_callback))); -#define libssh2_userauth_keyboard_interactive(session, username, \ - response_callback) \ - libssh2_userauth_keyboard_interactive_ex((session), (username), \ +#define libssh2_userauth_keyboard_interactive(session, username, \ + response_callback) \ + libssh2_userauth_keyboard_interactive_ex((session), (username), \ (unsigned int)strlen(username), \ (response_callback)) +LIBSSH2_API int +libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session, + const char *username, + size_t username_len, + const unsigned char *pubkeydata, + size_t pubkeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase, + LIBSSH2_USERAUTH_SK_SIGN_FUNC + ((*sign_callback)), + void **abstract); + LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout); @@ -718,7 +788,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, #define SSH_EXTENDED_DATA_STDERR 1 -/* Returned by any function that would block during a read/write opperation */ +/* Returned by any function that would block during a read/write operation */ #define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN LIBSSH2_API LIBSSH2_CHANNEL * @@ -728,22 +798,27 @@ libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, const char *message, unsigned int message_len); #define libssh2_channel_open_session(session) \ - libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ - LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ - LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) + libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ + LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) LIBSSH2_API LIBSSH2_CHANNEL * libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, int port, const char *shost, int sport); #define libssh2_channel_direct_tcpip(session, host, port) \ - libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) + libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) + +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION * session, + const char *socket_path, + const char *shost, int sport); LIBSSH2_API LIBSSH2_LISTENER * libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, int port, int *bound_port, int queue_maxsize); #define libssh2_channel_forward_listen(session, port) \ - libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) + libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); @@ -761,6 +836,8 @@ LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, (unsigned int)strlen(varname), (value), \ (unsigned int)strlen(value)) +LIBSSH2_API int libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel); + LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, unsigned int term_len, @@ -782,7 +859,7 @@ LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, int width_px, int height_px); #define libssh2_channel_request_pty_size(channel, width, height) \ - libssh2_channel_request_pty_size_ex((channel), (width), (height), 0, 0) + libssh2_channel_request_pty_size_ex((channel), (width), (height), 0, 0) LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, @@ -790,7 +867,13 @@ LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, const char *auth_cookie, int screen_number); #define libssh2_channel_x11_req(channel, screen_number) \ - libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) + libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) + +LIBSSH2_API int libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len); +#define libssh2_channel_signal(channel, signame) \ + libssh2_channel_signal_ex((channel), signame, strlen(signame)) LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, @@ -798,23 +881,25 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *message, unsigned int message_len); #define libssh2_channel_shell(channel) \ - libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ - NULL, 0) + libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ + NULL, 0) #define libssh2_channel_exec(channel, command) \ - libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ - (command), (unsigned int)strlen(command)) + libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ + (command), (unsigned int)strlen(command)) #define libssh2_channel_subsystem(channel, subsystem) \ - libssh2_channel_process_startup((channel), "subsystem", \ - sizeof("subsystem") - 1, (subsystem), \ - (unsigned int)strlen(subsystem)) + libssh2_channel_process_startup((channel), "subsystem", \ + sizeof("subsystem") - 1, (subsystem), \ + (unsigned int)strlen(subsystem)) LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen); #define libssh2_channel_read(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), 0, (buf), (buflen)) + libssh2_channel_read_ex((channel), 0, \ + (buf), (buflen)) #define libssh2_channel_read_stderr(channel, buf, buflen) \ - libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) + libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, \ + (buf), (buflen)) LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended); @@ -824,9 +909,9 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial); #define libssh2_channel_window_read(channel) \ - libssh2_channel_window_read_ex((channel), NULL, NULL) + libssh2_channel_window_read_ex((channel), NULL, NULL) -/* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */ +/* libssh2_channel_receive_window_adjust() is DEPRECATED, do not use! */ LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, @@ -843,16 +928,17 @@ LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, size_t buflen); #define libssh2_channel_write(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), 0, (buf), (buflen)) -#define libssh2_channel_write_stderr(channel, buf, buflen) \ - libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, \ + libssh2_channel_write_ex((channel), 0, \ + (buf), (buflen)) +#define libssh2_channel_write_stderr(channel, buf, buflen) \ + libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, \ (buf), (buflen)) LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial); #define libssh2_channel_window_write(channel) \ - libssh2_channel_window_write_ex((channel), NULL) + libssh2_channel_window_write_ex((channel), NULL) LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking); @@ -865,7 +951,11 @@ LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session, long timeout); LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session); -/* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */ +LIBSSH2_API void libssh2_session_set_read_timeout(LIBSSH2_SESSION* session, + long timeout); +LIBSSH2_API long libssh2_session_get_read_timeout(LIBSSH2_SESSION* session); + +/* libssh2_channel_handle_extended_data() is DEPRECATED, do not use! */ LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode); LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, @@ -879,9 +969,8 @@ LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, * (FIFO) from the standard data channel */ /* DEPRECATED */ -#define libssh2_channel_ignore_extended_data(channel, ignore) \ - libssh2_channel_handle_extended_data((channel), \ - (ignore) ? \ +#define libssh2_channel_ignore_extended_data(channel, ignore) \ + libssh2_channel_handle_extended_data((channel), (ignore) ? \ LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : \ LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL) @@ -891,7 +980,7 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid); #define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0) #define libssh2_channel_flush_stderr(channel) \ - libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) + libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel, @@ -912,7 +1001,7 @@ LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel); LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb); -/* Use libssh2_scp_recv2 for large (> 2GB) file support on windows */ +/* Use libssh2_scp_recv2() for large (> 2GB) file support on windows */ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, libssh2_struct_stat *sb); @@ -925,8 +1014,9 @@ libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, libssh2_int64_t size, time_t mtime, time_t atime); #define libssh2_scp_send(session, path, mode, size) \ - libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) + libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) +/* DEPRECATED */ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, unsigned int *dest_len, const char *src, unsigned int src_len); @@ -934,8 +1024,22 @@ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, LIBSSH2_API const char *libssh2_version(int req_version_num); +typedef enum { + libssh2_no_crypto = 0, + libssh2_openssl, + libssh2_gcrypt, + libssh2_mbedtls, + libssh2_wincng, + libssh2_os400qc3 +} libssh2_crypto_engine_t; + +LIBSSH2_API +libssh2_crypto_engine_t libssh2_crypto_engine(void); + #define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */ #define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */ +#define HAVE_LIBSSH2_CRYPTOENGINE_API 0x011100 /* libssh2_crypto_engine + since 1.11 */ struct libssh2_knownhost { unsigned int magic; /* magic stored by the library */ @@ -946,7 +1050,7 @@ struct libssh2_knownhost { }; /* - * libssh2_knownhost_init + * libssh2_knownhost_init() * * Init a collection of known hosts. Returns the pointer to a collection. * @@ -955,7 +1059,7 @@ LIBSSH2_API LIBSSH2_KNOWNHOSTS * libssh2_knownhost_init(LIBSSH2_SESSION *session); /* - * libssh2_knownhost_add + * libssh2_knownhost_add() * * Add a host and its associated key to the collection of known hosts. * @@ -987,7 +1091,7 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session); #define LIBSSH2_KNOWNHOST_KEYENC_RAW (1<<16) #define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16) -/* type of key (3 bits) */ +/* type of key (4 bits) */ #define LIBSSH2_KNOWNHOST_KEY_MASK (15<<18) #define LIBSSH2_KNOWNHOST_KEY_SHIFT 18 #define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18) @@ -1007,7 +1111,7 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost **store); /* - * libssh2_knownhost_addc + * libssh2_knownhost_addc() * * Add a host and its associated key to the collection of known hosts. * @@ -1025,8 +1129,8 @@ libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, * If 'sha1' is selected as type, the salt must be provided to the salt * argument. This too base64 encoded. * - * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If - * a custom type is used, salt is ignored and you must provide the host + * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. + * If a custom type is used, salt is ignored and you must provide the host * pre-hashed when checking for it in the libssh2_knownhost_check() function. * * The keylen parameter may be omitted (zero) if the key is provided as a @@ -1042,7 +1146,7 @@ libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost **store); /* - * libssh2_knownhost_check + * libssh2_knownhost_check() * * Check a host and its associated key against the collection of known hosts. * @@ -1081,7 +1185,7 @@ libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost **knownhost); /* - * libssh2_knownhost_del + * libssh2_knownhost_del() * * Remove a host from the collection of known hosts. The 'entry' struct is * retrieved by a call to libssh2_knownhost_check(). @@ -1092,7 +1196,7 @@ libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, struct libssh2_knownhost *entry); /* - * libssh2_knownhost_free + * libssh2_knownhost_free() * * Free an entire collection of known hosts. * @@ -1113,7 +1217,7 @@ libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, const char *line, size_t len, int type); /* - * libssh2_knownhost_readfile + * libssh2_knownhost_readfile() * * Add hosts+key pairs from a given file. * @@ -1149,7 +1253,7 @@ libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, int type); /* - * libssh2_knownhost_writefile + * libssh2_knownhost_writefile() * * Write hosts+key pairs to a given file. * @@ -1165,7 +1269,7 @@ libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, * libssh2_knownhost_get() * * Traverse the internal list of known hosts. Pass NULL to 'prev' to get - * the first one. Or pass a poiner to the previously returned one to get the + * the first one. Or pass a pointer to the previously returned one to get the * next. * * Returns: @@ -1189,7 +1293,7 @@ struct libssh2_agent_publickey { }; /* - * libssh2_agent_init + * libssh2_agent_init() * * Init an ssh-agent handle. Returns the pointer to the handle. * @@ -1221,7 +1325,7 @@ libssh2_agent_list_identities(LIBSSH2_AGENT *agent); * libssh2_agent_get_identity() * * Traverse the internal list of public keys. Pass NULL to 'prev' to get - * the first one. Or pass a poiner to the previously returned one to get the + * the first one. Or pass a pointer to the previously returned one to get the * next. * * Returns: @@ -1231,8 +1335,8 @@ libssh2_agent_list_identities(LIBSSH2_AGENT *agent); */ LIBSSH2_API int libssh2_agent_get_identity(LIBSSH2_AGENT *agent, - struct libssh2_agent_publickey **store, - struct libssh2_agent_publickey *prev); + struct libssh2_agent_publickey **store, + struct libssh2_agent_publickey *prev); /* * libssh2_agent_userauth() @@ -1243,8 +1347,25 @@ libssh2_agent_get_identity(LIBSSH2_AGENT *agent, */ LIBSSH2_API int libssh2_agent_userauth(LIBSSH2_AGENT *agent, - const char *username, - struct libssh2_agent_publickey *identity); + const char *username, + struct libssh2_agent_publickey *identity); + +/* + * libssh2_agent_sign() + * + * Sign a payload using a system-installed ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_sign(LIBSSH2_AGENT *agent, + struct libssh2_agent_publickey *identity, + unsigned char **sig, + size_t *s_len, + const unsigned char *data, + size_t d_len, + const char *method, + unsigned int method_len); /* * libssh2_agent_disconnect() @@ -1317,15 +1438,15 @@ LIBSSH2_API int libssh2_keepalive_send(LIBSSH2_SESSION *session, enabled */ LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask); -#define LIBSSH2_TRACE_TRANS (1<<1) -#define LIBSSH2_TRACE_KEX (1<<2) -#define LIBSSH2_TRACE_AUTH (1<<3) -#define LIBSSH2_TRACE_CONN (1<<4) -#define LIBSSH2_TRACE_SCP (1<<5) -#define LIBSSH2_TRACE_SFTP (1<<6) -#define LIBSSH2_TRACE_ERROR (1<<7) -#define LIBSSH2_TRACE_PUBLICKEY (1<<8) -#define LIBSSH2_TRACE_SOCKET (1<<9) +#define LIBSSH2_TRACE_TRANS (1<<1) +#define LIBSSH2_TRACE_KEX (1<<2) +#define LIBSSH2_TRACE_AUTH (1<<3) +#define LIBSSH2_TRACE_CONN (1<<4) +#define LIBSSH2_TRACE_SCP (1<<5) +#define LIBSSH2_TRACE_SFTP (1<<6) +#define LIBSSH2_TRACE_ERROR (1<<7) +#define LIBSSH2_TRACE_PUBLICKEY (1<<8) +#define LIBSSH2_TRACE_SOCKET (1<<9) typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*, void *, diff --git a/libs/libssh2/include/libssh2_publickey.h b/libs/libssh2/include/libssh2_publickey.h index 5dbdcf9253..566acd6533 100644 --- a/libs/libssh2/include/libssh2_publickey.h +++ b/libs/libssh2/include/libssh2_publickey.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org> +/* Copyright (C) Sara Golemon <sarag@libssh2.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -41,6 +41,8 @@ * * For more information on the publickey subsystem, * refer to IETF draft: secsh-publickey + * + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIBSSH2_PUBLICKEY_H @@ -72,9 +74,9 @@ typedef struct _libssh2_publickey_list { /* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */ #define libssh2_publickey_attribute(name, value, mandatory) \ - { (name), strlen(name), (value), strlen(value), (mandatory) }, + { (name), strlen(name), (value), strlen(value), (mandatory) }, #define libssh2_publickey_attribute_fast(name, value, mandatory) \ - { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, + { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, #ifdef __cplusplus extern "C" { @@ -92,10 +94,12 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, unsigned long blob_len, char overwrite, unsigned long num_attrs, const libssh2_publickey_attribute attrs[]); -#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ - num_attrs, attrs) \ - libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \ - (overwrite), (num_attrs), (attrs)) +#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ + num_attrs, attrs) \ + libssh2_publickey_add_ex((pkey), \ + (name), strlen(name), \ + (blob), (blob_len), \ + (overwrite), (num_attrs), (attrs)) LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, @@ -103,7 +107,9 @@ LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *blob, unsigned long blob_len); #define libssh2_publickey_remove(pkey, name, blob, blob_len) \ - libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len)) + libssh2_publickey_remove_ex((pkey), \ + (name), strlen(name), \ + (blob), (blob_len)) LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, @@ -119,4 +125,4 @@ LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey); } /* extern "C" */ #endif -#endif /* ifndef: LIBSSH2_PUBLICKEY_H */ +#endif /* LIBSSH2_PUBLICKEY_H */ diff --git a/libs/libssh2/include/libssh2_sftp.h b/libs/libssh2/include/libssh2_sftp.h index 4a750b3e37..8b41f1d7f1 100644 --- a/libs/libssh2/include/libssh2_sftp.h +++ b/libs/libssh2/include/libssh2_sftp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org> +/* Copyright (C) Sara Golemon <sarag@libssh2.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -33,6 +33,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIBSSH2_SFTP_H @@ -40,7 +42,7 @@ #include "libssh2.h" -#ifndef WIN32 +#ifndef LIBSSH2_WIN32 #include <unistd.h> #endif @@ -165,19 +167,19 @@ struct _LIBSSH2_SFTP_STATVFS { /* macros to check for specific file types, added in 1.2.5 */ #define LIBSSH2_SFTP_S_ISLNK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) #define LIBSSH2_SFTP_S_ISREG(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) #define LIBSSH2_SFTP_S_ISDIR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) #define LIBSSH2_SFTP_S_ISCHR(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) #define LIBSSH2_SFTP_S_ISBLK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) #define LIBSSH2_SFTP_S_ISFIFO(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) #define LIBSSH2_SFTP_S_ISSOCK(m) \ - (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) /* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */ @@ -189,32 +191,32 @@ struct _LIBSSH2_SFTP_STATVFS { #define LIBSSH2_FXF_EXCL 0x00000020 /* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */ -#define LIBSSH2_FX_OK 0 -#define LIBSSH2_FX_EOF 1 -#define LIBSSH2_FX_NO_SUCH_FILE 2 -#define LIBSSH2_FX_PERMISSION_DENIED 3 -#define LIBSSH2_FX_FAILURE 4 -#define LIBSSH2_FX_BAD_MESSAGE 5 -#define LIBSSH2_FX_NO_CONNECTION 6 -#define LIBSSH2_FX_CONNECTION_LOST 7 -#define LIBSSH2_FX_OP_UNSUPPORTED 8 -#define LIBSSH2_FX_INVALID_HANDLE 9 -#define LIBSSH2_FX_NO_SUCH_PATH 10 -#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11 -#define LIBSSH2_FX_WRITE_PROTECT 12 -#define LIBSSH2_FX_NO_MEDIA 13 -#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14 -#define LIBSSH2_FX_QUOTA_EXCEEDED 15 -#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */ -#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16 -#define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */ -#define LIBSSH2_FX_LOCK_CONFLICT 17 -#define LIBSSH2_FX_DIR_NOT_EMPTY 18 -#define LIBSSH2_FX_NOT_A_DIRECTORY 19 -#define LIBSSH2_FX_INVALID_FILENAME 20 -#define LIBSSH2_FX_LINK_LOOP 21 - -/* Returned by any function that would block during a read/write opperation */ +#define LIBSSH2_FX_OK 0UL +#define LIBSSH2_FX_EOF 1UL +#define LIBSSH2_FX_NO_SUCH_FILE 2UL +#define LIBSSH2_FX_PERMISSION_DENIED 3UL +#define LIBSSH2_FX_FAILURE 4UL +#define LIBSSH2_FX_BAD_MESSAGE 5UL +#define LIBSSH2_FX_NO_CONNECTION 6UL +#define LIBSSH2_FX_CONNECTION_LOST 7UL +#define LIBSSH2_FX_OP_UNSUPPORTED 8UL +#define LIBSSH2_FX_INVALID_HANDLE 9UL +#define LIBSSH2_FX_NO_SUCH_PATH 10UL +#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11UL +#define LIBSSH2_FX_WRITE_PROTECT 12UL +#define LIBSSH2_FX_NO_MEDIA 13UL +#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14UL +#define LIBSSH2_FX_QUOTA_EXCEEDED 15UL +#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16UL /* Initial mis-spelling */ +#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16UL +#define LIBSSH2_FX_LOCK_CONFlICT 17UL /* Initial mis-spelling */ +#define LIBSSH2_FX_LOCK_CONFLICT 17UL +#define LIBSSH2_FX_DIR_NOT_EMPTY 18UL +#define LIBSSH2_FX_NOT_A_DIRECTORY 19UL +#define LIBSSH2_FX_INVALID_FILENAME 20UL +#define LIBSSH2_FX_LINK_LOOP 21UL + +/* Returned by any function that would block during a read/write operation */ #define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN /* SFTP API */ @@ -230,12 +232,25 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, unsigned int filename_len, unsigned long flags, long mode, int open_type); -#define libssh2_sftp_open(sftp, filename, flags, mode) \ - libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \ - (mode), LIBSSH2_SFTP_OPENFILE) +#define libssh2_sftp_open(sftp, filename, flags, mode) \ + libssh2_sftp_open_ex((sftp), \ + (filename), (unsigned int)strlen(filename), \ + (flags), (mode), LIBSSH2_SFTP_OPENFILE) #define libssh2_sftp_opendir(sftp, path) \ - libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \ - LIBSSH2_SFTP_OPENDIR) + libssh2_sftp_open_ex((sftp), \ + (path), (unsigned int)strlen(path), \ + 0, 0, LIBSSH2_SFTP_OPENDIR) +LIBSSH2_API LIBSSH2_SFTP_HANDLE * +libssh2_sftp_open_ex_r(LIBSSH2_SFTP *sftp, + const char *filename, + size_t filename_len, + unsigned long flags, + long mode, int open_type, + LIBSSH2_SFTP_ATTRIBUTES *attrs); +#define libssh2_sftp_open_r(sftp, filename, flags, mode, attrs) \ + libssh2_sftp_open_ex_r((sftp), (filename), strlen(filename), \ + (flags), (mode), LIBSSH2_SFTP_OPENFILE, \ + (attrs)) LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen); @@ -245,7 +260,7 @@ LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \ char *longentry, size_t longentry_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs); -#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ +#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \ (attrs)) @@ -281,8 +296,9 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, unsigned int dest_filename_len, long flags); #define libssh2_sftp_rename(sftp, sourcefile, destfile) \ - libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \ - (destfile), strlen(destfile), \ + libssh2_sftp_rename_ex((sftp), \ + (sourcefile), (unsigned int)strlen(sourcefile), \ + (destfile), (unsigned int)strlen(destfile), \ LIBSSH2_SFTP_RENAME_OVERWRITE | \ LIBSSH2_SFTP_RENAME_ATOMIC | \ LIBSSH2_SFTP_RENAME_NATIVE) @@ -305,13 +321,13 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode); #define libssh2_sftp_mkdir(sftp, path, mode) \ - libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode)) + libssh2_sftp_mkdir_ex((sftp), (path), (unsigned int)strlen(path), (mode)) LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len); #define libssh2_sftp_rmdir(sftp, path) \ - libssh2_sftp_rmdir_ex((sftp), (path), strlen(path)) + libssh2_sftp_rmdir_ex((sftp), (path), (unsigned int)strlen(path)) LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, @@ -319,14 +335,14 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs); #define libssh2_sftp_stat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \ - (attrs)) + libssh2_sftp_stat_ex((sftp), (path), (unsigned int)strlen(path), \ + LIBSSH2_SFTP_STAT, (attrs)) #define libssh2_sftp_lstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \ - (attrs)) + libssh2_sftp_stat_ex((sftp), (path), (unsigned int)strlen(path), \ + LIBSSH2_SFTP_LSTAT, (attrs)) #define libssh2_sftp_setstat(sftp, path, attrs) \ - libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \ - (attrs)) + libssh2_sftp_stat_ex((sftp), (path), (unsigned int)strlen(path), \ + LIBSSH2_SFTP_SETSTAT, (attrs)) LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, @@ -335,13 +351,19 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, unsigned int target_len, int link_type); #define libssh2_sftp_symlink(sftp, orig, linkpath) \ - libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \ - strlen(linkpath), LIBSSH2_SFTP_SYMLINK) + libssh2_sftp_symlink_ex((sftp), \ + (orig), (unsigned int)strlen(orig), \ + (linkpath), (unsigned int)strlen(linkpath), \ + LIBSSH2_SFTP_SYMLINK) #define libssh2_sftp_readlink(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ - LIBSSH2_SFTP_READLINK) + libssh2_sftp_symlink_ex((sftp), \ + (path), (unsigned int)strlen(path), \ + (target), (maxlen), \ + LIBSSH2_SFTP_READLINK) #define libssh2_sftp_realpath(sftp, path, target, maxlen) \ - libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ + libssh2_sftp_symlink_ex((sftp), \ + (path), (unsigned int)strlen(path), \ + (target), (maxlen), \ LIBSSH2_SFTP_REALPATH) #ifdef __cplusplus diff --git a/libs/libssh2/libssh2.vcxproj b/libs/libssh2/libssh2.vcxproj index 2eedb85e66..3d69cf0fd9 100644 --- a/libs/libssh2/libssh2.vcxproj +++ b/libs/libssh2/libssh2.vcxproj @@ -37,7 +37,7 @@ </PropertyGroup> <ItemDefinitionGroup> <ClCompile> - <PreprocessorDefinitions>LIBSSH2_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> <DisableSpecificWarnings>4244;4310;4702;%(DisableSpecificWarnings)</DisableSpecificWarnings> <AdditionalIncludeDirectories>$(ProjectDir).\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> @@ -49,6 +49,9 @@ <ClCompile Include="src\agent.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> + <ClCompile Include="src\agent_win.c"> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + </ClCompile> <ClCompile Include="src\bcrypt_pbkdf.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> @@ -64,6 +67,9 @@ <ClCompile Include="src\crypt.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> + <ClCompile Include="src\crypto.c"> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + </ClCompile> <ClCompile Include="src\global.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> @@ -85,15 +91,9 @@ <ClCompile Include="src\mac.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> - <ClCompile Include="src\mbedtls.c"> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> <ClCompile Include="src\misc.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> - <ClCompile Include="src\openssl.c"> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> <ClCompile Include="src\packet.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> @@ -118,13 +118,12 @@ <ClCompile Include="src\userauth.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> - <ClCompile Include="src\version.c"> + <ClCompile Include="src\userauth_kbd_packet.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> - <ClCompile Include="src\wincng.c"> + <ClCompile Include="src\version.c"> <PrecompiledHeader>NotUsing</PrecompiledHeader> </ClCompile> - <ClInclude Include="src\blf.h" /> <ClInclude Include="src\channel.h" /> <ClInclude Include="src\comp.h" /> <ClInclude Include="src\crypto.h" /> @@ -132,7 +131,6 @@ <ClInclude Include="src\libssh2_config.h" /> <ClInclude Include="src\libssh2_priv.h" /> <ClInclude Include="src\mac.h" /> - <ClInclude Include="src\mbedtls.h" /> <ClInclude Include="src\misc.h" /> <ClInclude Include="src\openssl.h" /> <ClInclude Include="src\packet.h" /> @@ -140,6 +138,6 @@ <ClInclude Include="src\sftp.h" /> <ClInclude Include="src\transport.h" /> <ClInclude Include="src\userauth.h" /> - <ClInclude Include="src\wincng.h" /> + <ClInclude Include="src\userauth_kbd_packet.h" /> </ItemGroup> </Project>
\ No newline at end of file diff --git a/libs/libssh2/libssh2.vcxproj.filters b/libs/libssh2/libssh2.vcxproj.filters index 13f4f31e9b..37987969d3 100644 --- a/libs/libssh2/libssh2.vcxproj.filters +++ b/libs/libssh2/libssh2.vcxproj.filters @@ -41,15 +41,9 @@ <ClCompile Include="src\mac.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="src\mbedtls.c"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="src\misc.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="src\openssl.c"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="src\packet.c"> <Filter>Source Files</Filter> </ClCompile> @@ -77,14 +71,17 @@ <ClCompile Include="src\version.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="src\wincng.c"> + <ClCompile Include="src\agent_win.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="src\crypto.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="src\userauth_kbd_packet.c"> <Filter>Source Files</Filter> </ClCompile> </ItemGroup> <ItemGroup> - <ClInclude Include="src\blf.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="src\channel.h"> <Filter>Header Files</Filter> </ClInclude> @@ -106,9 +103,6 @@ <ClInclude Include="src\mac.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="src\mbedtls.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="src\misc.h"> <Filter>Header Files</Filter> </ClInclude> @@ -130,7 +124,7 @@ <ClInclude Include="src\userauth.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="src\wincng.h"> + <ClInclude Include="src\userauth_kbd_packet.h"> <Filter>Header Files</Filter> </ClInclude> </ItemGroup> diff --git a/libs/libssh2/src/CMakeLists.txt b/libs/libssh2/src/CMakeLists.txt index 2eaf4cc2cf..3a2077d06b 100644 --- a/libs/libssh2/src/CMakeLists.txt +++ b/libs/libssh2/src/CMakeLists.txt @@ -1,4 +1,5 @@ -# Copyright (c) 2014 Alexander Lamaison <alexander.lamaison@gmail.com> +# Copyright (C) Alexander Lamaison <alexander.lamaison@gmail.com> +# Copyright (C) Viktor Szakats # # Redistribution and use in source and binary forms, # with or without modification, are permitted provided @@ -32,208 +33,22 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY # OF SUCH DAMAGE. +# +# SPDX-License-Identifier: BSD-3-Clause -include(CheckFunctionExists) -include(CheckSymbolExists) -include(CheckFunctionExistsMayNeedLibrary) -include(CheckIncludeFiles) -include(CheckTypeSize) -include(CheckSymbolExists) -include(CheckNonblockingSocketSupport) -include(SocketLibraries) - -## Cryptography backend choice - -set(CRYPTO_BACKEND - "" - CACHE - STRING - "The backend to use for cryptography: OpenSSL, Libgcrypt or WinCNG, mbedTLS -or empty to try any available") - -# If the crypto backend was given, rather than searching for the first -# we are able to find, the find_package commands must abort configuration -# and report to the user. if(CRYPTO_BACKEND) - set(SPECIFIC_CRYPTO_REQUIREMENT REQUIRED) -endif() - -if(CRYPTO_BACKEND STREQUAL "OpenSSL" OR NOT CRYPTO_BACKEND) - - find_package(OpenSSL ${SPECIFIC_CRYPTO_REQUIREMENT}) - - if(OPENSSL_FOUND) - set(CRYPTO_BACKEND "OpenSSL") - set(CRYPTO_SOURCES openssl.c openssl.h) - list(APPEND PRIVATE_COMPILE_DEFINITIONS LIBSSH2_OPENSSL) - list(APPEND PRIVATE_INCLUDE_DIRECTORIES ${OPENSSL_INCLUDE_DIR}) - list(APPEND LIBRARIES ${OPENSSL_LIBRARIES}) - list(APPEND PC_REQUIRES_PRIVATE libssl libcrypto) - - if (WIN32) - # Statically linking to OpenSSL requires crypt32 for some Windows APIs. - # This should really be handled by FindOpenSSL.cmake. - list(APPEND LIBRARIES crypt32) - list(APPEND PC_LIBS -lcrypt32) - - find_file(DLL_LIBEAY32 - NAMES libeay32.dll crypto.dll libcrypto-1_1.dll libcrypto-1_1-x64.dll - HINTS ${_OPENSSL_ROOT_HINTS} PATHS ${_OPENSSL_ROOT_PATHS} - PATH_SUFFIXES bin) - if (NOT DLL_LIBEAY32) - message(WARNING - "Unable to find OpenSSL crypto (aka libeay32) DLL, executables may not run") - endif() - - find_file(DLL_SSLEAY32 - NAMES ssleay32.dll ssl.dll libssl-1_1.dll libssl-1_1-x64.dll - HINTS ${_OPENSSL_ROOT_HINTS} PATHS ${_OPENSSL_ROOT_PATHS} - PATH_SUFFIXES bin) - if (NOT DLL_SSLEAY32) - message(WARNING - "Unable to find OpenSSL ssl (aka ssleay32) DLL, executables may not run") - endif() - - if(DLL_LIBEAY32 AND DLL_SSLEAY32) - list(APPEND _RUNTIME_DEPENDENCIES ${DLL_LIBEAY32} ${DLL_SSLEAY32}) - endif() - endif() - - # Not all OpenSSL have AES-CTR functions. - set(SAVE_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES}) - check_function_exists(EVP_aes_128_ctr HAVE_EVP_AES_128_CTR) - set(CMAKE_REQUIRED_LIBRARIES ${SAVE_CMAKE_REQUIRED_LIBRARIES}) - endif() -endif() - -if(CRYPTO_BACKEND STREQUAL "Libgcrypt" OR NOT CRYPTO_BACKEND) - - find_package(Libgcrypt ${SPECIFIC_CRYPTO_REQUIREMENT}) - - if(LIBGCRYPT_FOUND) - set(CRYPTO_BACKEND "Libgcrypt") - set(CRYPTO_SOURCES libgcrypt.c libgcrypt.h) - list(APPEND PRIVATE_COMPILE_DEFINITIONS LIBSSH2_LIBGCRYPT) - list(APPEND PRIVATE_INCLUDE_DIRECTORIES ${LIBGCRYPT_INCLUDE_DIRS}) - list(APPEND LIBRARIES ${LIBGCRYPT_LIBRARIES}) - list(APPEND PC_LIBS -lgcrypt) - endif() -endif() - -if(CRYPTO_BACKEND STREQUAL "WinCNG" OR NOT CRYPTO_BACKEND) - - # The check actually compiles the header. This requires windows.h. - check_include_files("windows.h;bcrypt.h" HAVE_BCRYPT_H) - - if(HAVE_BCRYPT_H) - set(CRYPTO_BACKEND "WinCNG") - set(CRYPTO_SOURCES wincng.c wincng.h) - list(APPEND PRIVATE_COMPILE_DEFINITIONS LIBSSH2_WINCNG) - - set(HAVE_LIBCRYPT32 TRUE) - list(APPEND LIBRARIES bcrypt) - list(APPEND PC_LIBS -lbcrypt) - - check_include_files(ntdef.h HAVE_NTDEF_H) - check_include_files(ntstatus.h HAVE_NTSTATUS_H) - - # Reading keys from files is optional and depends on Wincrypt - check_include_files("windows.h;wincrypt.h" HAVE_WINCRYPT_H) - - if(HAVE_WINCRYPT_H) - list(APPEND LIBRARIES crypt32) - list(APPEND PC_LIBS -lcrypt32) - endif() - - elseif(${SPECIFIC_CRYPTO_REQUIREMENT} STREQUAL ${REQUIRED}) - message(FATAL_ERROR "WinCNG not available") - endif() -endif() - -if(CRYPTO_BACKEND STREQUAL "mbedTLS" OR NOT CRYPTO_BACKEND) - - find_package(mbedTLS ${SPECIFIC_CRYPTO_REQUIREMENT}) - - if(MBEDTLS_FOUND) - set(CRYPTO_BACKEND "mbedTLS") - set(CRYPTO_SOURCES mbedtls.c mbedtls.h) - list(APPEND PRIVATE_COMPILE_DEFINITIONS LIBSSH2_MBEDTLS) - list(APPEND PRIVATE_INCLUDE_DIRECTORIES ${MBEDTLS_INCLUDE_DIR}) - list(APPEND LIBRARIES ${MBEDTLS_LIBRARIES}) - list(APPEND PC_LIBS -lmbedcrypto) - link_directories(${MBEDTLS_LIBRARY_DIR}) - endif() -endif() - -if(NOT CRYPTO_BACKEND) + list(APPEND PRIVATE_COMPILE_DEFINITIONS ${CRYPTO_BACKEND_DEFINE}) + list(APPEND PRIVATE_INCLUDE_DIRECTORIES ${CRYPTO_BACKEND_INCLUDE_DIR}) +else() message(FATAL_ERROR "No suitable cryptography backend found.") endif() -## Library definition - -include(GNUInstallDirs) -set(SOURCES - ${CRYPTO_SOURCES} - agent.c - blf.h - bcrypt_pbkdf.c - blowfish.c - channel.c - channel.h - comp.c - comp.h - crypt.c - crypto.h - global.c - hostkey.c - keepalive.c - kex.c - knownhost.c - libssh2_priv.h - mac.c - mac.h - misc.c - misc.h - packet.c - packet.h - pem.c - publickey.c - scp.c - session.c - session.h - sftp.c - sftp.h - transport.c - transport.h - userauth.c - userauth.h - version.c) - -if(WIN32) - list(APPEND SOURCES ${PROJECT_SOURCE_DIR}/win32/libssh2.rc) -endif() - -add_library(libssh2 ${SOURCES}) -# we want it to be called libssh2 on all platforms -set_target_properties(libssh2 PROPERTIES PREFIX "") - -target_compile_definitions(libssh2 PRIVATE ${PRIVATE_COMPILE_DEFINITIONS}) -target_include_directories(libssh2 - PRIVATE "${PROJECT_SOURCE_DIR}/include/" ${PRIVATE_INCLUDE_DIRECTORIES} - PUBLIC - $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> - $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>) - ## Options option(CLEAR_MEMORY "Enable clearing of memory before being freed" ON) -if(CLEAR_MEMORY) - add_definitions(-DLIBSSH2_CLEAR_MEMORY) -endif(CLEAR_MEMORY) - -add_feature_info("Shared library" BUILD_SHARED_LIBS - "creating libssh2 as a shared library (.so/.dll)") +if(NOT CLEAR_MEMORY) + list(APPEND libssh2_DEFINITIONS LIBSSH2_NO_CLEAR_MEMORY) +endif() option(ENABLE_ZLIB_COMPRESSION "Use zlib for compression") add_feature_info(Compression ENABLE_ZLIB_COMPRESSION @@ -241,129 +56,81 @@ add_feature_info(Compression ENABLE_ZLIB_COMPRESSION if(ENABLE_ZLIB_COMPRESSION) find_package(ZLIB REQUIRED) - target_include_directories(libssh2 PRIVATE ${ZLIB_INCLUDE_DIRS}) + list(APPEND libssh2_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS}) list(APPEND LIBRARIES ${ZLIB_LIBRARIES}) list(APPEND PC_REQUIRES_PRIVATE zlib) if(ZLIB_FOUND) - target_compile_definitions(libssh2 PRIVATE LIBSSH2_HAVE_ZLIB=1) + list(APPEND libssh2_DEFINITIONS LIBSSH2_HAVE_ZLIB) endif() endif() -option(ENABLE_CRYPT_NONE "Permit \"none\" cipher -- NOT RECOMMENDED") -add_feature_info("\"none\" cipher" ENABLE_CRYPT_NONE "") -if(ENABLE_CRYPT_NONE) - target_compile_definitions(libssh2 PRIVATE LIBSSH2_CRYPT_NONE=1) -endif() +list(APPEND LIBRARIES ${SOCKET_LIBRARIES}) -option(ENABLE_MAC_NONE "Permit \"none\" MAC -- NOT RECOMMMENDED") -add_feature_info("\"none\" MAC" ENABLE_MAC_NONE "") -if(ENABLE_MAC_NONE) - target_compile_definitions(libssh2 PRIVATE LIBSSH2_MAC_NONE=1) +if(WIN32) + list(APPEND PC_LIBS -lws2_32) endif() -option(ENABLE_GEX_NEW - "Enable diffie-hellman-group-exchange-sha1 method" ON) -add_feature_info("diffie-hellman-group-exchange-sha1" ENABLE_GEX_NEW - "\"new\" diffie-hellman-group-exchange-sha1 method") -if(ENABLE_GEX_NEW) - target_compile_definitions(libssh2 PRIVATE LIBSSH2_DH_GEX_NEW=1) -endif() +# to find generated header +list(APPEND libssh2_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) -# Enable debugging logging by default if the user configured a debug build -if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(DEBUG_LOGGING_DEFAULT ON) -else() - set(DEBUG_LOGGING_DEFAULT OFF) +if(MSVC) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Zi /Od") + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /DEBUG") endif() -option(ENABLE_DEBUG_LOGGING "log execution with debug trace" - ${DEBUG_LOGGING_DEFAULT}) -add_feature_info(Logging ENABLE_DEBUG_LOGGING - "Logging of execution with debug trace") -if(ENABLE_DEBUG_LOGGING) - target_compile_definitions(libssh2 PRIVATE LIBSSH2DEBUG) -endif() - -## Platform checks -check_include_files(unistd.h HAVE_UNISTD_H) -check_include_files(inttypes.h HAVE_INTTYPES_H) -check_include_files(stdlib.h HAVE_STDLIB_H) -check_include_files(sys/select.h HAVE_SYS_SELECT_H) -check_include_files(sys/uio.h HAVE_SYS_UIO_H) -check_include_files(sys/socket.h HAVE_SYS_SOCKET_H) -check_include_files(sys/ioctl.h HAVE_SYS_IOCTL_H) -check_include_files(sys/time.h HAVE_SYS_TIME_H) -check_include_files(sys/un.h HAVE_SYS_UN_H) -check_include_files(windows.h HAVE_WINDOWS_H) -check_include_files(ws2tcpip.h HAVE_WS2TCPIP_H) -check_include_files(winsock2.h HAVE_WINSOCK2_H) +## Sources -check_type_size("long long" LONGLONG) +include(GNUInstallDirs) +transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") +# Get 'CSOURCES' and 'HHEADERS' variables +include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) +set(SOURCES ${CSOURCES} ${HHEADERS}) -if(HAVE_SYS_TIME_H) - check_symbol_exists(gettimeofday sys/time.h HAVE_GETTIMEOFDAY) -else() - check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) -endif() -if(HAVE_STDLIB_H) - check_symbol_exists(strtoll stdlib.h HAVE_STRTOLL) -else() - check_function_exists(strtoll HAVE_STRTOLL) -endif() -if (NOT HAVE_STRTOLL) - # Try _strtoi64 if strtoll isn't available - check_symbol_exists(_strtoi64 stdlib.h HAVE_STRTOI64) -endif() -check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF) -check_symbol_exists(memset_s string.h HAVE_MEMSET_S) +## Library definition -if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Interix") - # poll() does not work on these platforms - # - # Interix: "does provide poll(), but the implementing developer must - # have been in a bad mood, because poll() only works on the /proc - # filesystem here" - # - # Mac OS X's poll has funny behaviors, like: - # not being able to do poll on no filedescriptors (10.3?) - # not being able to poll on some files (like anything in /dev) - # not having reliable timeout support - # inconsistent return of POLLHUP where other implementations give POLLIN - message("poll use is disabled on this platform") -else() - check_function_exists(poll HAVE_POLL) +# Ensure that the static library and import library filenames are different, +# when building both static and shared library. On Windows, with certain +# toolchains (e.g. MSVC) these libraries get the same by default, overwriting +# each other. MinGW is not affected. +if(WIN32 AND BUILD_STATIC_LIBS AND BUILD_SHARED_LIBS AND + NOT STATIC_LIB_SUFFIX AND NOT IMPORT_LIB_SUFFIX AND + CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX) + set(STATIC_LIB_SUFFIX "_static") endif() -append_needed_socket_libraries(LIBRARIES) - -# Non-blocking socket support tests. Must be after library tests to -# link correctly -set(SAVE_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) -set(CMAKE_REQUIRED_LIBRARIES ${LIBRARIES}) -check_nonblocking_socket_support() -set(CMAKE_REQUIRED_LIBRARIES ${SAVE_CMAKE_REQUIRED_LIBRARIES}) - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/libssh2_config_cmake.h.in - ${CMAKE_CURRENT_BINARY_DIR}/libssh2_config.h) -# to find generated header -target_include_directories(libssh2 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - -# Check for the OS. -# Daniel's note: this should not be necessary and we need to work to -# get this removed. -if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_compile_definitions(libssh2 PRIVATE LIBSSH2_WIN32) -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - target_compile_definitions(libssh2 PRIVATE LIBSSH2_DARWIN) +# we want it to be called libssh2 on all platforms +if(BUILD_STATIC_LIBS) + list(APPEND libssh2_export ${LIB_STATIC}) + add_library(${LIB_STATIC} STATIC ${SOURCES}) + target_compile_definitions(${LIB_STATIC} PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} ${libssh2_DEFINITIONS}) + target_link_libraries(${LIB_STATIC} PRIVATE ${LIBRARIES}) + set_target_properties(${LIB_STATIC} PROPERTIES PREFIX "" OUTPUT_NAME "libssh2") + set_target_properties(${LIB_STATIC} PROPERTIES SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}") + + target_include_directories(${LIB_STATIC} + PRIVATE "${PROJECT_SOURCE_DIR}/include/" ${libssh2_INCLUDE_DIRS} ${PRIVATE_INCLUDE_DIRECTORIES} + PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>) endif() +if(BUILD_SHARED_LIBS) + list(APPEND libssh2_export ${LIB_SHARED}) + add_library(${LIB_SHARED} SHARED ${SOURCES}) + if(WIN32) + set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libssh2.rc) + endif() + target_compile_definitions(${LIB_SHARED} PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} ${libssh2_DEFINITIONS} ${LIB_SHARED_DEFINITIONS}) + target_compile_options(${LIB_SHARED} PRIVATE ${LIB_SHARED_C_FLAGS}) + target_link_libraries(${LIB_SHARED} PRIVATE ${LIBRARIES}) + set_target_properties(${LIB_SHARED} PROPERTIES PREFIX "" IMPORT_PREFIX "" OUTPUT_NAME "libssh2") + set_target_properties(${LIB_SHARED} PROPERTIES IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}") + set_target_properties(${LIB_SHARED} PROPERTIES POSITION_INDEPENDENT_CODE ON) -if(CMAKE_VERSION VERSION_LESS "2.8.12") - # Fall back to over-linking dependencies - target_link_libraries(libssh2 ${LIBRARIES}) -else() - target_link_libraries(libssh2 PRIVATE ${LIBRARIES}) + target_include_directories(${LIB_SHARED} + PRIVATE "${PROJECT_SOURCE_DIR}/include/" ${libssh2_INCLUDE_DIRS} ${PRIVATE_INCLUDE_DIRECTORIES} + PUBLIC + $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>) endif() ## Installation @@ -374,14 +141,21 @@ install(FILES ${PROJECT_SOURCE_DIR}/include/libssh2_sftp.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -install(TARGETS libssh2 - EXPORT Libssh2Config - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - +if(BUILD_STATIC_LIBS) + install(TARGETS ${LIB_STATIC} + EXPORT Libssh2Config + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() if(BUILD_SHARED_LIBS) - list(APPEND _RUNTIME_DEPENDENCIES $<TARGET_FILE:libssh2>) + install(TARGETS ${LIB_SHARED} + EXPORT Libssh2Config + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + list(APPEND _RUNTIME_DEPENDENCIES $<TARGET_FILE:${LIB_SHARED}>) endif() set(RUNTIME_DEPENDENCIES ${_RUNTIME_DEPENDENCIES} CACHE INTERNAL @@ -392,11 +166,11 @@ set(RUNTIME_DEPENDENCIES ${_RUNTIME_DEPENDENCIES} CACHE INTERNAL ## During package installation, install Libssh2Config.cmake install(EXPORT Libssh2Config NAMESPACE Libssh2:: - DESTINATION lib/cmake/libssh2) + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libssh2) ## During build, register directly from build tree # create Libssh2Config.cmake -export(TARGETS libssh2 NAMESPACE Libssh2:: FILE Libssh2Config.cmake) +export(TARGETS ${libssh2_export} NAMESPACE Libssh2:: FILE Libssh2Config.cmake) export(PACKAGE Libssh2) # register it ## Export a .pc file for client projects not using CMaek @@ -406,16 +180,32 @@ endif() if(PC_LIBS) string(REPLACE ";" " " PC_LIBS "${PC_LIBS}") endif() -configure_file(libssh2.pc.in libssh2.pc @ONLY) +set(LIBSSH2VER ${LIBSSH2_VERSION}) +set(LIBSREQUIRED ${PC_REQUIRES_PRIVATE}) +set(LIBS ${PC_LIBS}) +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix "\${prefix}") +set(libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}") +set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") +configure_file(${CMAKE_SOURCE_DIR}/libssh2.pc.in libssh2.pc @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libssh2.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) ## Versioning -set_target_properties(libssh2 PROPERTIES - SOVERSION 1 - VERSION 1.0.1) +set(LIBSSH2_SOVERSION 1) +set(LIBSSH2_VERSION 1.0.1) +if(BUILD_STATIC_LIBS) + set_target_properties(${LIB_STATIC} PROPERTIES + SOVERSION ${LIBSSH2_SOVERSION} + VERSION ${LIBSSH2_VERSION}) +endif() +if(BUILD_SHARED_LIBS) + set_target_properties(${LIB_SHARED} PROPERTIES + SOVERSION ${LIBSSH2_SOVERSION} + VERSION ${LIBSSH2_VERSION}) +endif() include(CMakePackageConfigHelpers) write_basic_package_version_file( @@ -424,4 +214,4 @@ write_basic_package_version_file( COMPATIBILITY SameMajorVersion) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/Libssh2ConfigVersion.cmake - DESTINATION lib/cmake/libssh2) + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libssh2) diff --git a/libs/libssh2/src/Makefile.am b/libs/libssh2/src/Makefile.am index 31d58ed573..bd7b8de8ea 100644 --- a/libs/libssh2/src/Makefile.am +++ b/libs/libssh2/src/Makefile.am @@ -1,34 +1,23 @@ -# $Id: Makefile.am,v 1.21 2009/05/07 17:21:56 bagder Exp $ +# Copyright (C) The libssh2 project and its contributors. +# SPDX-License-Identifier: BSD-3-Clause AUTOMAKE_OPTIONS = foreign nostdinc -# Get the CRYPTO_CSOURCES, CRYPTO_HHEADERS and CRYPTO_LTLIBS defines -if OPENSSL -include ../Makefile.OpenSSL.inc -endif -if LIBGCRYPT -include ../Makefile.libgcrypt.inc -endif -if WINCNG -include ../Makefile.WinCNG.inc -endif -if MBEDTLS -include ../Makefile.mbedTLS.inc -endif - -# Makefile.inc provides the CSOURCES and HHEADERS defines -include ../Makefile.inc +# Get the CSOURCES, HHEADERS and EXTRA_DIST defines +include Makefile.inc libssh2_la_SOURCES = $(CSOURCES) $(HHEADERS) +if HAVE_WINDRES +libssh2_la_SOURCES += libssh2.rc +endif -EXTRA_DIST = libssh2_config.h.in libssh2_config_cmake.h.in libssh2.pc.in -EXTRA_DIST += CMakeLists.txt NMakefile +EXTRA_DIST += libssh2_config.h.in libssh2_config_cmake.h.in CMakeLists.txt lib_LTLIBRARIES = libssh2.la # srcdir/include for the shipped headers # builddir/src for the generated config header when building out of the source # tree -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/src +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/include VERSION=-version-info 1:1:0 @@ -61,5 +50,9 @@ VERSION=-version-info 1:1:0 # libssh2_la_LDFLAGS = $(VERSION) -no-undefined \ - -export-symbols-regex '^libssh2_.*' \ - $(CRYPTO_LTLIBS) $(LTLIBZ) + -export-symbols-regex '^libssh2_.*' + +if HAVE_WINDRES +.rc.lo: + $(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@ +endif diff --git a/libs/libssh2/src/Makefile.in b/libs/libssh2/src/Makefile.in deleted file mode 100644 index c00d9dbaec..0000000000 --- a/libs/libssh2/src/Makefile.in +++ /dev/null @@ -1,881 +0,0 @@ -# Makefile.in generated by automake 1.16.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2018 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/autobuild.m4 \ - $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ - $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = libssh2_config.h \ - $(top_builddir)/example/libssh2_config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(libdir)" -LTLIBRARIES = $(lib_LTLIBRARIES) -libssh2_la_LIBADD = -am__libssh2_la_SOURCES_DIST = channel.c comp.c crypt.c hostkey.c kex.c \ - mac.c misc.c packet.c publickey.c scp.c session.c sftp.c \ - userauth.c transport.c version.c knownhost.c agent.c \ - libgcrypt.c mbedtls.c openssl.c wincng.c pem.c keepalive.c \ - global.c blowfish.c bcrypt_pbkdf.c libssh2_priv.h libgcrypt.h \ - mbedtls.h openssl.h wincng.h transport.h channel.h comp.h \ - mac.h misc.h packet.h userauth.h session.h sftp.h crypto.h \ - blf.h -@LIBGCRYPT_FALSE@@MBEDTLS_FALSE@@OPENSSL_FALSE@@WINCNG_TRUE@am__objects_1 = wincng.lo -@LIBGCRYPT_FALSE@@MBEDTLS_FALSE@@OPENSSL_TRUE@am__objects_1 = \ -@LIBGCRYPT_FALSE@@MBEDTLS_FALSE@@OPENSSL_TRUE@ openssl.lo -@LIBGCRYPT_FALSE@@MBEDTLS_TRUE@am__objects_1 = mbedtls.lo -@LIBGCRYPT_TRUE@am__objects_1 = libgcrypt.lo -am__objects_2 = channel.lo comp.lo crypt.lo hostkey.lo kex.lo mac.lo \ - misc.lo packet.lo publickey.lo scp.lo session.lo sftp.lo \ - userauth.lo transport.lo version.lo knownhost.lo agent.lo \ - $(am__objects_1) pem.lo keepalive.lo global.lo blowfish.lo \ - bcrypt_pbkdf.lo -am__objects_3 = -am__objects_4 = $(am__objects_3) -am_libssh2_la_OBJECTS = $(am__objects_2) $(am__objects_4) -libssh2_la_OBJECTS = $(am_libssh2_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -libssh2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libssh2_la_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__maybe_remake_depfiles = depfiles -am__depfiles_remade = ./$(DEPDIR)/agent.Plo \ - ./$(DEPDIR)/bcrypt_pbkdf.Plo ./$(DEPDIR)/blowfish.Plo \ - ./$(DEPDIR)/channel.Plo ./$(DEPDIR)/comp.Plo \ - ./$(DEPDIR)/crypt.Plo ./$(DEPDIR)/global.Plo \ - ./$(DEPDIR)/hostkey.Plo ./$(DEPDIR)/keepalive.Plo \ - ./$(DEPDIR)/kex.Plo ./$(DEPDIR)/knownhost.Plo \ - ./$(DEPDIR)/libgcrypt.Plo ./$(DEPDIR)/mac.Plo \ - ./$(DEPDIR)/mbedtls.Plo ./$(DEPDIR)/misc.Plo \ - ./$(DEPDIR)/openssl.Plo ./$(DEPDIR)/packet.Plo \ - ./$(DEPDIR)/pem.Plo ./$(DEPDIR)/publickey.Plo \ - ./$(DEPDIR)/scp.Plo ./$(DEPDIR)/session.Plo \ - ./$(DEPDIR)/sftp.Plo ./$(DEPDIR)/transport.Plo \ - ./$(DEPDIR)/userauth.Plo ./$(DEPDIR)/version.Plo \ - ./$(DEPDIR)/wincng.Plo -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(libssh2_la_SOURCES) -DIST_SOURCES = $(am__libssh2_la_SOURCES_DIST) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ - $(LISP)libssh2_config.h.in -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -am__DIST_COMMON = $(srcdir)/../Makefile.OpenSSL.inc \ - $(srcdir)/../Makefile.WinCNG.inc $(srcdir)/../Makefile.inc \ - $(srcdir)/../Makefile.libgcrypt.inc \ - $(srcdir)/../Makefile.mbedTLS.inc $(srcdir)/Makefile.in \ - $(srcdir)/libssh2_config.h.in $(top_srcdir)/depcomp -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GREP = @GREP@ -HAVE_LIBBCRYPT = @HAVE_LIBBCRYPT@ -HAVE_LIBCRYPT32 = @HAVE_LIBCRYPT32@ -HAVE_LIBGCRYPT = @HAVE_LIBGCRYPT@ -HAVE_LIBMBEDCRYPTO = @HAVE_LIBMBEDCRYPTO@ -HAVE_LIBSSL = @HAVE_LIBSSL@ -HAVE_LIBZ = @HAVE_LIBZ@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBBCRYPT = @LIBBCRYPT@ -LIBBCRYPT_PREFIX = @LIBBCRYPT_PREFIX@ -LIBCRYPT32 = @LIBCRYPT32@ -LIBCRYPT32_PREFIX = @LIBCRYPT32_PREFIX@ -LIBGCRYPT = @LIBGCRYPT@ -LIBGCRYPT_PREFIX = @LIBGCRYPT_PREFIX@ -LIBMBEDCRYPTO = @LIBMBEDCRYPTO@ -LIBMBEDCRYPTO_PREFIX = @LIBMBEDCRYPTO_PREFIX@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBSREQUIRED = @LIBSREQUIRED@ -LIBSSH2VER = @LIBSSH2VER@ -LIBSSL = @LIBSSL@ -LIBSSL_PREFIX = @LIBSSL_PREFIX@ -LIBTOOL = @LIBTOOL@ -LIBZ = @LIBZ@ -LIBZ_PREFIX = @LIBZ_PREFIX@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBBCRYPT = @LTLIBBCRYPT@ -LTLIBCRYPT32 = @LTLIBCRYPT32@ -LTLIBGCRYPT = @LTLIBGCRYPT@ -LTLIBMBEDCRYPTO = @LTLIBMBEDCRYPTO@ -LTLIBOBJS = @LTLIBOBJS@ -LTLIBSSL = @LTLIBSSL@ -LTLIBZ = @LTLIBZ@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SSHD = @SSHD@ -STRIP = @STRIP@ -VERSION = -version-info 1:1:0 -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ - -# $Id: Makefile.am,v 1.21 2009/05/07 17:21:56 bagder Exp $ -AUTOMAKE_OPTIONS = foreign nostdinc -@LIBGCRYPT_TRUE@CRYPTO_CSOURCES = libgcrypt.c -@MBEDTLS_TRUE@CRYPTO_CSOURCES = mbedtls.c -@OPENSSL_TRUE@CRYPTO_CSOURCES = openssl.c -@WINCNG_TRUE@CRYPTO_CSOURCES = wincng.c -@LIBGCRYPT_TRUE@CRYPTO_HHEADERS = libgcrypt.h -@MBEDTLS_TRUE@CRYPTO_HHEADERS = mbedtls.h -@OPENSSL_TRUE@CRYPTO_HHEADERS = openssl.h -@WINCNG_TRUE@CRYPTO_HHEADERS = wincng.h -@LIBGCRYPT_TRUE@CRYPTO_LTLIBS = $(LTLIBGCRYPT) -@MBEDTLS_TRUE@CRYPTO_LTLIBS = $(LTLIBMBEDCRYPTO) -@OPENSSL_TRUE@CRYPTO_LTLIBS = $(LTLIBSSL) -@WINCNG_TRUE@CRYPTO_LTLIBS = $(LTLIBBCRYPT) $(LTLIBCRYPT32) -CSOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \ - packet.c publickey.c scp.c session.c sftp.c userauth.c transport.c \ - version.c knownhost.c agent.c $(CRYPTO_CSOURCES) pem.c keepalive.c global.c \ - blowfish.c bcrypt_pbkdf.c - -HHEADERS = libssh2_priv.h $(CRYPTO_HHEADERS) transport.h channel.h comp.h \ - mac.h misc.h packet.h userauth.h session.h sftp.h crypto.h blf.h - - -# Get the CRYPTO_CSOURCES, CRYPTO_HHEADERS and CRYPTO_LTLIBS defines - -# Makefile.inc provides the CSOURCES and HHEADERS defines -libssh2_la_SOURCES = $(CSOURCES) $(HHEADERS) -EXTRA_DIST = libssh2_config.h.in libssh2_config_cmake.h.in \ - libssh2.pc.in CMakeLists.txt NMakefile -lib_LTLIBRARIES = libssh2.la - -# srcdir/include for the shipped headers -# builddir/src for the generated config header when building out of the source -# tree -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/src - -# This flag accepts an argument of the form current[:revision[:age]]. So, -# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to -# 1. -# -# If either revision or age are omitted, they default to 0. Also note that age -# must be less than or equal to the current interface number. -# -# Here are a set of rules to help you update your library version information: -# -# 1.Start with version information of 0:0:0 for each libtool library. -# -# 2.Update the version information only immediately before a public release of -# your software. More frequent updates are unnecessary, and only guarantee -# that the current interface number gets larger faster. -# -# 3.If the library source code has changed at all since the last update, then -# increment revision (c:r+1:a) -# -# 4.If any interfaces have been added, removed, or changed since the last -# update, increment current, and set revision to 0. (c+1:r=0:a) -# -# 5.If any interfaces have been added since the last public release, then -# increment age. (c:r:a+1) -# -# 6.If any interfaces have been removed since the last public release, then -# set age to 0. (c:r:a=0) -# -libssh2_la_LDFLAGS = $(VERSION) -no-undefined \ - -export-symbols-regex '^libssh2_.*' \ - $(CRYPTO_LTLIBS) $(LTLIBZ) - -all: libssh2_config.h - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../Makefile.OpenSSL.inc $(srcdir)/../Makefile.libgcrypt.inc $(srcdir)/../Makefile.WinCNG.inc $(srcdir)/../Makefile.mbedTLS.inc $(srcdir)/../Makefile.inc $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign src/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ - esac; -$(srcdir)/../Makefile.OpenSSL.inc $(srcdir)/../Makefile.libgcrypt.inc $(srcdir)/../Makefile.WinCNG.inc $(srcdir)/../Makefile.mbedTLS.inc $(srcdir)/../Makefile.inc $(am__empty): - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -libssh2_config.h: stamp-h1 - @test -f $@ || rm -f stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 - -stamp-h1: $(srcdir)/libssh2_config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status src/libssh2_config.h -$(srcdir)/libssh2_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f libssh2_config.h stamp-h1 - -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -libssh2.la: $(libssh2_la_OBJECTS) $(libssh2_la_DEPENDENCIES) $(EXTRA_libssh2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libssh2_la_LINK) -rpath $(libdir) $(libssh2_la_OBJECTS) $(libssh2_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/agent.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bcrypt_pbkdf.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blowfish.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/channel.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/comp.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypt.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hostkey.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keepalive.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kex.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/knownhost.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgcrypt.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbedtls.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pem.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/publickey.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scp.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sftp.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/userauth.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wincng.Plo@am__quote@ # am--include-marker - -$(am__depfiles_remade): - @$(MKDIR_P) $(@D) - @echo '# dummy' >$@-t && $(am__mv) $@-t $@ - -am--depfiles: $(am__depfiles_remade) - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) distdir-am - -distdir-am: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) libssh2_config.h -installdirs: - for dir in "$(DESTDIR)$(libdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ - mostlyclean-am - -distclean: distclean-am - -rm -f ./$(DEPDIR)/agent.Plo - -rm -f ./$(DEPDIR)/bcrypt_pbkdf.Plo - -rm -f ./$(DEPDIR)/blowfish.Plo - -rm -f ./$(DEPDIR)/channel.Plo - -rm -f ./$(DEPDIR)/comp.Plo - -rm -f ./$(DEPDIR)/crypt.Plo - -rm -f ./$(DEPDIR)/global.Plo - -rm -f ./$(DEPDIR)/hostkey.Plo - -rm -f ./$(DEPDIR)/keepalive.Plo - -rm -f ./$(DEPDIR)/kex.Plo - -rm -f ./$(DEPDIR)/knownhost.Plo - -rm -f ./$(DEPDIR)/libgcrypt.Plo - -rm -f ./$(DEPDIR)/mac.Plo - -rm -f ./$(DEPDIR)/mbedtls.Plo - -rm -f ./$(DEPDIR)/misc.Plo - -rm -f ./$(DEPDIR)/openssl.Plo - -rm -f ./$(DEPDIR)/packet.Plo - -rm -f ./$(DEPDIR)/pem.Plo - -rm -f ./$(DEPDIR)/publickey.Plo - -rm -f ./$(DEPDIR)/scp.Plo - -rm -f ./$(DEPDIR)/session.Plo - -rm -f ./$(DEPDIR)/sftp.Plo - -rm -f ./$(DEPDIR)/transport.Plo - -rm -f ./$(DEPDIR)/userauth.Plo - -rm -f ./$(DEPDIR)/version.Plo - -rm -f ./$(DEPDIR)/wincng.Plo - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-hdr distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f ./$(DEPDIR)/agent.Plo - -rm -f ./$(DEPDIR)/bcrypt_pbkdf.Plo - -rm -f ./$(DEPDIR)/blowfish.Plo - -rm -f ./$(DEPDIR)/channel.Plo - -rm -f ./$(DEPDIR)/comp.Plo - -rm -f ./$(DEPDIR)/crypt.Plo - -rm -f ./$(DEPDIR)/global.Plo - -rm -f ./$(DEPDIR)/hostkey.Plo - -rm -f ./$(DEPDIR)/keepalive.Plo - -rm -f ./$(DEPDIR)/kex.Plo - -rm -f ./$(DEPDIR)/knownhost.Plo - -rm -f ./$(DEPDIR)/libgcrypt.Plo - -rm -f ./$(DEPDIR)/mac.Plo - -rm -f ./$(DEPDIR)/mbedtls.Plo - -rm -f ./$(DEPDIR)/misc.Plo - -rm -f ./$(DEPDIR)/openssl.Plo - -rm -f ./$(DEPDIR)/packet.Plo - -rm -f ./$(DEPDIR)/pem.Plo - -rm -f ./$(DEPDIR)/publickey.Plo - -rm -f ./$(DEPDIR)/scp.Plo - -rm -f ./$(DEPDIR)/session.Plo - -rm -f ./$(DEPDIR)/sftp.Plo - -rm -f ./$(DEPDIR)/transport.Plo - -rm -f ./$(DEPDIR)/userauth.Plo - -rm -f ./$(DEPDIR)/version.Plo - -rm -f ./$(DEPDIR)/wincng.Plo - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-libLTLIBRARIES - -.MAKE: all install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ - clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \ - ctags ctags-am distclean distclean-compile distclean-generic \ - distclean-hdr distclean-libtool distclean-tags distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-libLTLIBRARIES \ - install-man install-pdf install-pdf-am install-ps \ - install-ps-am install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ - uninstall-am uninstall-libLTLIBRARIES - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/libs/libssh2/src/Makefile.inc b/libs/libssh2/src/Makefile.inc new file mode 100644 index 0000000000..a1876daceb --- /dev/null +++ b/libs/libssh2/src/Makefile.inc @@ -0,0 +1,55 @@ +# Copyright (C) The libssh2 project and its contributors. +# SPDX-License-Identifier: BSD-3-Clause +CSOURCES = \ + agent.c \ + bcrypt_pbkdf.c \ + channel.c \ + comp.c \ + crypt.c \ + crypto.c \ + global.c \ + hostkey.c \ + keepalive.c \ + kex.c \ + knownhost.c \ + mac.c \ + misc.c \ + packet.c \ + pem.c \ + publickey.c \ + scp.c \ + session.c \ + sftp.c \ + transport.c \ + userauth.c \ + userauth_kbd_packet.c \ + version.c + +HHEADERS = \ + channel.h \ + comp.h \ + crypto.h \ + libgcrypt.h \ + libssh2_priv.h \ + libssh2_setup.h \ + mac.h \ + mbedtls.h \ + misc.h \ + openssl.h \ + os400qc3.h \ + packet.h \ + session.h \ + sftp.h \ + transport.h \ + userauth.h \ + userauth_kbd_packet.h \ + wincng.h + +EXTRA_DIST = \ + agent_win.c \ + blowfish.c \ + libgcrypt.c \ + mbedtls.c \ + openssl.c \ + os400qc3.c \ + wincng.c diff --git a/libs/libssh2/src/NMakefile b/libs/libssh2/src/NMakefile deleted file mode 100644 index 0c4853f1df..0000000000 --- a/libs/libssh2/src/NMakefile +++ /dev/null @@ -1,30 +0,0 @@ -!include "win32/config.mk" - -!include "win32/objects.mk" - -CFLAGS=$(CFLAGS) - -AR = lib -ARFLAGS = -nologo /LTCG - -RESOURCE=$(INTDIR)\libssh2.res -DLL=libssh2$(SUFFIX).dll -STATICLIB=$(INTDIR)\libssh2.lib - -!if "$(BUILD_STATIC_LIB)" == "" -all: $(DLL) -!else -all: $(STATICLIB) -!endif - -$(DLL): $(OBJECTS) $(RESOURCE) - $(CC) -o $(DLL) $(DLLFLAGS) $(OBJECTS) $(RESOURCE) $(LIBS) - -$(STATICLIB): $(OBJECTS) - $(AR) $(ARFLAGS) -out:$@ $(OBJECTS) - -$(RESOURCE): win32\libssh2.rc - $(RC) $(RCFLAGS) /Fo"$@" $? - -!include "win32/rules.mk" - diff --git a/libs/libssh2/src/agent.c b/libs/libssh2/src/agent.c index 03e7415a84..d99a319550 100644 --- a/libs/libssh2/src/agent.c +++ b/libs/libssh2/src/agent.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 2009 by Daiki Ueno - * Copyright (C) 2010-2014 by Daniel Stenberg + * Copyright (C) Daiki Ueno + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,11 +35,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include "misc.h" + #include <errno.h> +#include <stdlib.h> /* for getenv() */ + #ifdef HAVE_SYS_UN_H #include <sys/un.h> #else @@ -48,6 +52,11 @@ support them. */ #undef PF_UNIX #endif + +#if defined(WIN32) && !defined(LIBSSH2_WINDOWS_UWP) +#define HAVE_WIN32_AGENTS +#endif + #include "userauth.h" #include "session.h" @@ -90,6 +99,10 @@ #define SSH_AGENT_CONSTRAIN_LIFETIME 1 #define SSH_AGENT_CONSTRAIN_CONFIRM 2 +/* Signature request methods */ +#define SSH_AGENT_RSA_SHA2_256 2 +#define SSH_AGENT_RSA_SHA2_512 4 + /* non-blocking mode on agent connection is not yet implemented, but for future use. */ typedef enum { @@ -107,6 +120,7 @@ typedef struct agent_transaction_ctx { unsigned char *response; size_t response_len; agent_nonblocking_states state; + size_t send_recv_total; } *agent_transaction_ctx_t; typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent); @@ -122,9 +136,9 @@ struct agent_publickey { }; struct agent_ops { - agent_connect_func connect; - agent_transact_func transact; - agent_disconnect_func disconnect; + const agent_connect_func connect; + const agent_transact_func transact; + const agent_disconnect_func disconnect; }; struct _LIBSSH2_AGENT @@ -140,8 +154,16 @@ struct _LIBSSH2_AGENT struct list_head head; /* list of public keys */ char *identity_agent_path; /* Path to a custom identity agent socket */ + +#ifdef HAVE_WIN32_AGENTS + OVERLAPPED overlapped; + HANDLE pipe; + BOOL pending_io; +#endif }; +#include "agent_win.c" + #ifdef PF_UNIX static int agent_connect_unix(LIBSSH2_AGENT *agent) @@ -163,10 +185,10 @@ agent_connect_unix(LIBSSH2_AGENT *agent) "failed creating socket"); s_un.sun_family = AF_UNIX; - strncpy(s_un.sun_path, path, sizeof s_un.sun_path); + strncpy(s_un.sun_path, path, sizeof(s_un.sun_path)); s_un.sun_path[sizeof(s_un.sun_path)-1] = 0; /* make sure there's a trailing zero */ - if(connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) { + if(connect(agent->fd, (struct sockaddr*)(&s_un), sizeof(s_un)) != 0) { close(agent->fd); return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed connecting with agent"); @@ -175,6 +197,40 @@ agent_connect_unix(LIBSSH2_AGENT *agent) return LIBSSH2_ERROR_NONE; } +#define RECV_SEND_ALL(func, socket, buffer, length, flags, abstract) \ + do { \ + size_t finished = 0; \ + \ + while(finished < length) { \ + ssize_t rc; \ + rc = func(socket, \ + (char *)buffer + finished, length - finished, \ + flags, abstract); \ + if(rc < 0) \ + return rc; \ + \ + finished += rc; \ + } \ + \ + return finished; \ + } while(0) + +static ssize_t _send_all(LIBSSH2_SEND_FUNC(func), libssh2_socket_t socket, + const void *buffer, size_t length, + int flags, void **abstract) +{ + RECV_SEND_ALL(func, socket, buffer, length, flags, abstract); +} + +static ssize_t _recv_all(LIBSSH2_RECV_FUNC(func), libssh2_socket_t socket, + void *buffer, size_t length, + int flags, void **abstract) +{ + RECV_SEND_ALL(func, socket, buffer, length, flags, abstract); +} + +#undef RECV_SEND_ALL + static int agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) { @@ -183,8 +239,10 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Send the length of the request */ if(transctx->state == agent_NB_state_request_created) { - _libssh2_htonu32(buf, transctx->request_len); - rc = LIBSSH2_SEND_FD(agent->session, agent->fd, buf, sizeof buf, 0); + _libssh2_htonu32(buf, (uint32_t)transctx->request_len); + rc = (int)_send_all(agent->session->send, agent->fd, + buf, sizeof(buf), 0, + &agent->session->abstract); if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; else if(rc < 0) @@ -195,8 +253,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Send the request body */ if(transctx->state == agent_NB_state_request_length_sent) { - rc = LIBSSH2_SEND_FD(agent->session, agent->fd, transctx->request, - transctx->request_len, 0); + rc = (int)_send_all(agent->session->send, agent->fd, + transctx->request, transctx->request_len, 0, + &agent->session->abstract); if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; else if(rc < 0) @@ -207,7 +266,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Receive the length of a response */ if(transctx->state == agent_NB_state_request_sent) { - rc = LIBSSH2_RECV_FD(agent->session, agent->fd, buf, sizeof buf, 0); + rc = (int)_recv_all(agent->session->recv, agent->fd, + buf, sizeof(buf), 0, + &agent->session->abstract); if(rc < 0) { if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -225,8 +286,9 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Receive the response body */ if(transctx->state == agent_NB_state_response_length_received) { - rc = LIBSSH2_RECV_FD(agent->session, agent->fd, transctx->response, - transctx->response_len, 0); + rc = (int)_recv_all(agent->session->recv, agent->fd, + transctx->response, transctx->response_len, 0, + &agent->session->abstract); if(rc < 0) { if(rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -252,14 +314,14 @@ agent_disconnect_unix(LIBSSH2_AGENT *agent) return LIBSSH2_ERROR_NONE; } -struct agent_ops agent_ops_unix = { +static struct agent_ops agent_ops_unix = { agent_connect_unix, agent_transact_unix, agent_disconnect_unix }; #endif /* PF_UNIX */ -#ifdef WIN32 +#ifdef HAVE_WIN32_AGENTS /* Code to talk to Pageant was taken from PuTTY. * * Portions copyright Robert de Bath, Joris van Rantwijk, Delian @@ -290,7 +352,7 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) HANDLE filemap; unsigned char *p; unsigned char *p2; - int id; + LRESULT id; COPYDATASTRUCT cds; if(!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN) @@ -303,16 +365,16 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) "found no pageant"); snprintf(mapname, sizeof(mapname), - "PageantRequest%08x%c", (unsigned)GetCurrentThreadId(), '\0'); + "PageantRequest%08x", (unsigned)GetCurrentThreadId()); filemap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, PAGEANT_MAX_MSGLEN, mapname); + 0, PAGEANT_MAX_MSGLEN, mapname); - if(filemap == NULL || filemap == INVALID_HANDLE_VALUE) + if(!filemap || filemap == INVALID_HANDLE_VALUE) return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed setting up pageant filemap"); p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); - if(p == NULL || p2 == NULL) { + if(!p || !p2) { CloseHandle(filemap); return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed to open pageant filemap for writing"); @@ -322,7 +384,7 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) transctx->request_len); cds.dwData = PAGEANT_COPYDATA_ID; - cds.cbData = 1 + strlen(mapname); + cds.cbData = (DWORD)(1 + strlen(mapname)); cds.lpData = mapname; id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); @@ -357,20 +419,21 @@ agent_disconnect_pageant(LIBSSH2_AGENT *agent) return 0; } -struct agent_ops agent_ops_pageant = { +static struct agent_ops agent_ops_pageant = { agent_connect_pageant, agent_transact_pageant, agent_disconnect_pageant }; -#endif /* WIN32 */ +#endif /* HAVE_WIN32_AGENTS */ static struct { const char *name; struct agent_ops *ops; } supported_backends[] = { -#ifdef WIN32 +#ifdef HAVE_WIN32_AGENTS {"Pageant", &agent_ops_pageant}, -#endif /* WIN32 */ + {"OpenSSH", &agent_ops_openssh}, +#endif /* HAVE_WIN32_AGENTS */ #ifdef PF_UNIX {"Unix", &agent_ops_unix}, #endif /* PF_UNIX */ @@ -388,6 +451,9 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, ssize_t method_len; unsigned char *s; int rc; + unsigned char *method_name = NULL; + uint32_t sign_flags = 0; + ssize_t plain_len; /* Create a request to sign the data */ if(transctx->state == agent_NB_state_init) { @@ -404,9 +470,21 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, _libssh2_store_str(&s, (const char *)data, data_len); /* flags */ - _libssh2_store_u32(&s, 0); + if(session->userauth_pblc_method_len > 0 && + session->userauth_pblc_method) { + if(session->userauth_pblc_method_len == 12 && + !memcmp(session->userauth_pblc_method, "rsa-sha2-512", 12)) { + sign_flags = SSH_AGENT_RSA_SHA2_512; + } + else if(session->userauth_pblc_method_len == 12 && + !memcmp(session->userauth_pblc_method, "rsa-sha2-256", 12)) { + sign_flags = SSH_AGENT_RSA_SHA2_256; + } + } + _libssh2_store_u32(&s, sign_flags); transctx->request_len = s - transctx->request; + transctx->send_recv_total = 0; transctx->state = agent_NB_state_request_created; } @@ -461,8 +539,32 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } + + /* method name */ + method_name = LIBSSH2_ALLOC(session, method_len); + if(!method_name) { + rc = LIBSSH2_ERROR_ALLOC; + goto error; + } + memcpy(method_name, s, method_len); s += method_len; + plain_len = plain_method((char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + + /* check to see if we match requested */ + if(((size_t)method_len != session->userauth_pblc_method_len && + method_len != plain_len) || + memcmp(method_name, session->userauth_pblc_method, method_len)) { + _libssh2_debug((session, + LIBSSH2_TRACE_KEX, + "Agent sign method %.*s", + method_len, method_name)); + + rc = LIBSSH2_ERROR_ALGO_UNSUPPORTED; + goto error; + } + /* Read the signature */ len -= 4; if(len < 0) { @@ -484,13 +586,19 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, } memcpy(*sig, s, *sig_len); - error: +error: + + if(method_name) + LIBSSH2_FREE(session, method_name); + LIBSSH2_FREE(session, transctx->request); transctx->request = NULL; LIBSSH2_FREE(session, transctx->response); transctx->response = NULL; + transctx->state = agent_NB_state_init; + return _libssh2_error(session, rc, "agent sign failure"); } @@ -507,6 +615,7 @@ agent_list_identities(LIBSSH2_AGENT *agent) if(transctx->state == agent_NB_state_init) { transctx->request = &c; transctx->request_len = 1; + transctx->send_recv_total = 0; transctx->state = agent_NB_state_request_created; } @@ -522,7 +631,9 @@ agent_list_identities(LIBSSH2_AGENT *agent) rc = agent->ops->transact(agent, transctx); if(rc) { - goto error; + LIBSSH2_FREE(agent->session, transctx->response); + transctx->response = NULL; + return rc; } transctx->request = NULL; @@ -550,7 +661,7 @@ agent_list_identities(LIBSSH2_AGENT *agent) while(num_identities--) { struct agent_publickey *identity; - ssize_t comment_len; + size_t comment_len; /* Read the length of the blob */ len -= 4; @@ -558,7 +669,7 @@ agent_list_identities(LIBSSH2_AGENT *agent) rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } - identity = LIBSSH2_ALLOC(agent->session, sizeof *identity); + identity = LIBSSH2_ALLOC(agent->session, sizeof(*identity)); if(!identity) { rc = LIBSSH2_ERROR_ALLOC; goto error; @@ -595,14 +706,14 @@ agent_list_identities(LIBSSH2_AGENT *agent) comment_len = _libssh2_ntohu32(s); s += 4; - /* Read the comment */ - len -= comment_len; - if(len < 0) { + if(comment_len > (size_t)len) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; LIBSSH2_FREE(agent->session, identity->external.blob); LIBSSH2_FREE(agent->session, identity); goto error; } + /* Read the comment */ + len -= comment_len; identity->external.comment = LIBSSH2_ALLOC(agent->session, comment_len + 1); @@ -618,7 +729,7 @@ agent_list_identities(LIBSSH2_AGENT *agent) _libssh2_list_add(&agent->head, &identity->node); } - error: +error: LIBSSH2_FREE(agent->session, transctx->response); transctx->response = NULL; @@ -643,7 +754,7 @@ agent_free_identities(LIBSSH2_AGENT *agent) #define AGENT_PUBLICKEY_MAGIC 0x3bdefed2 /* - * agent_publickey_to_external() + * agent_publickey_to_external * * Copies data from the internal to the external representation struct. * @@ -670,7 +781,7 @@ libssh2_agent_init(LIBSSH2_SESSION *session) { LIBSSH2_AGENT *agent; - agent = LIBSSH2_CALLOC(session, sizeof *agent); + agent = LIBSSH2_CALLOC(session, sizeof(*agent)); if(!agent) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for agent connection"); @@ -681,11 +792,17 @@ libssh2_agent_init(LIBSSH2_SESSION *session) agent->identity_agent_path = NULL; _libssh2_list_init(&agent->head); +#ifdef HAVE_WIN32_AGENTS + agent->pipe = INVALID_HANDLE_VALUE; + memset(&agent->overlapped, 0, sizeof(OVERLAPPED)); + agent->pending_io = FALSE; +#endif + return agent; } /* - * libssh2_agent_connect() + * libssh2_agent_connect * * Connect to an ssh-agent. * @@ -705,7 +822,7 @@ libssh2_agent_connect(LIBSSH2_AGENT *agent) } /* - * libssh2_agent_list_identities() + * libssh2_agent_list_identities * * Request ssh-agent to list identities. * @@ -714,14 +831,14 @@ libssh2_agent_connect(LIBSSH2_AGENT *agent) LIBSSH2_API int libssh2_agent_list_identities(LIBSSH2_AGENT *agent) { - memset(&agent->transctx, 0, sizeof agent->transctx); + memset(&agent->transctx, 0, sizeof(agent->transctx)); /* Abandon the last fetched identities */ agent_free_identities(agent); return agent_list_identities(agent); } /* - * libssh2_agent_get_identity() + * libssh2_agent_get_identity * * Traverse the internal list of public keys. Pass NULL to 'prev' to get * the first one. Or pass a pointer to the previously returned one to get the @@ -758,7 +875,7 @@ libssh2_agent_get_identity(LIBSSH2_AGENT *agent, } /* - * libssh2_agent_userauth() + * libssh2_agent_userauth * * Do publickey user authentication with the help of ssh-agent. * @@ -773,7 +890,7 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent, int rc; if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) { - memset(&agent->transctx, 0, sizeof agent->transctx); + memset(&agent->transctx, 0, sizeof(agent->transctx)); agent->identity = identity->node; } @@ -788,7 +905,58 @@ libssh2_agent_userauth(LIBSSH2_AGENT *agent, } /* - * libssh2_agent_disconnect() + * libssh2_agent_sign + * + * Sign a payload using a system-installed ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_sign(LIBSSH2_AGENT *agent, + struct libssh2_agent_publickey *identity, + unsigned char **sig, + size_t *s_len, + const unsigned char *data, + size_t d_len, + const char *method, + unsigned int method_len) +{ + void *abstract = agent; + int rc; + uint32_t methodLen; + + if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) { + memset(&agent->transctx, 0, sizeof(agent->transctx)); + agent->identity = identity->node; + } + + if(identity->blob_len < sizeof(uint32_t)) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + + methodLen = _libssh2_ntohu32(identity->blob); + + if(identity->blob_len < sizeof(uint32_t) + methodLen) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + + agent->session->userauth_pblc_method_len = method_len; + agent->session->userauth_pblc_method = LIBSSH2_ALLOC(agent->session, + method_len); + + memcpy(agent->session->userauth_pblc_method, method, methodLen); + + rc = agent_sign(agent->session, sig, s_len, data, d_len, &abstract); + + LIBSSH2_FREE(agent->session, agent->session->userauth_pblc_method); + agent->session->userauth_pblc_method = NULL; + agent->session->userauth_pblc_method_len = 0; + + return rc; +} + +/* + * libssh2_agent_disconnect * * Close a connection to an ssh-agent. * @@ -803,7 +971,7 @@ libssh2_agent_disconnect(LIBSSH2_AGENT *agent) } /* - * libssh2_agent_free() + * libssh2_agent_free * * Free an ssh-agent handle. This function also frees the internal * collection of public keys. @@ -816,7 +984,7 @@ libssh2_agent_free(LIBSSH2_AGENT *agent) libssh2_agent_disconnect(agent); } - if(agent->identity_agent_path != NULL) + if(agent->identity_agent_path) LIBSSH2_FREE(agent->session, agent->identity_agent_path); agent_free_identities(agent); @@ -824,7 +992,7 @@ libssh2_agent_free(LIBSSH2_AGENT *agent) } /* - * libssh2_agent_set_identity_path() + * libssh2_agent_set_identity_path * * Allows a custom agent socket path beyond SSH_AUTH_SOCK env * @@ -849,7 +1017,7 @@ libssh2_agent_set_identity_path(LIBSSH2_AGENT *agent, const char *path) } /* - * libssh2_agent_get_identity_path() + * libssh2_agent_get_identity_path * * Returns the custom agent socket path if set * diff --git a/libs/libssh2/src/agent_win.c b/libs/libssh2/src/agent_win.c new file mode 100644 index 0000000000..3764fe4337 --- /dev/null +++ b/libs/libssh2/src/agent_win.c @@ -0,0 +1,349 @@ +/* + * Copyright (C) Daiki Ueno + * Copyright (C) Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause + */ + +#ifdef HAVE_WIN32_AGENTS /* Compile this via agent.c */ + +#include <stdlib.h> /* for getenv() */ + +/* Code to talk to OpenSSH was taken and modified from the Win32 port of + * Portable OpenSSH by the PowerShell team. Commit + * 8ab565c53f3619d6a1f5ac229e212cad8a52852c of + * https://github.com/PowerShell/openssh-portable.git was used as the base, + * specifically the following files: + * + * - contrib\win32\win32compat\fileio.c + * - Structure of agent_connect_openssh from ssh_get_authentication_socket + * - Structure of agent_transact_openssh from ssh_request_reply + * - contrib\win32\win32compat\wmain_common.c + * - Windows equivalent functions for common Unix functions, inlined into + * this implementation + * - fileio_connect replacing connect + * - fileio_read replacing read + * - fileio_write replacing write + * - fileio_close replacing close + * + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (C) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * Functions for connecting the local authentication agent. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + * + * SSH2 implementation, + * Copyright (C) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Copyright (C) 2015 Microsoft Corp. + * All rights reserved + * + * Microsoft openssh win32 port + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define WIN32_OPENSSH_AGENT_SOCK "\\\\.\\pipe\\openssh-ssh-agent" + +static int +agent_connect_openssh(LIBSSH2_AGENT *agent) +{ + int ret = LIBSSH2_ERROR_NONE; + const char *path; + HANDLE pipe = INVALID_HANDLE_VALUE; + HANDLE event = NULL; + + path = agent->identity_agent_path; + if(!path) { + path = getenv("SSH_AUTH_SOCK"); + if(!path) + path = WIN32_OPENSSH_AGENT_SOCK; + } + + for(;;) { + pipe = CreateFileA( + path, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + /* Non-blocking mode for agent connections is not implemented at + * the point this was implemented. The code for Win32 OpenSSH + * should support non-blocking IO, but the code calling it doesn't + * support it as of yet. + * When non-blocking IO is implemented for the surrounding code, + * uncomment the following line to enable support within the Win32 + * OpenSSH code. + */ + /* FILE_FLAG_OVERLAPPED | */ + SECURITY_SQOS_PRESENT | + SECURITY_IDENTIFICATION, + NULL + ); + + if(pipe != INVALID_HANDLE_VALUE) + break; + if(GetLastError() != ERROR_PIPE_BUSY) + break; + + /* Wait up to 1 second for a pipe instance to become available */ + if(!WaitNamedPipeA(path, 1000)) + break; + } + + if(pipe == INVALID_HANDLE_VALUE) { + ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "unable to connect to agent pipe"); + goto cleanup; + } + + if(SetHandleInformation(pipe, HANDLE_FLAG_INHERIT, 0) == FALSE) { + ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "unable to set handle information of agent pipe"); + goto cleanup; + } + + event = CreateEventA(NULL, TRUE, FALSE, NULL); + if(!event) { + ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "unable to create async I/O event"); + goto cleanup; + } + + agent->pipe = pipe; + pipe = INVALID_HANDLE_VALUE; + agent->overlapped.hEvent = event; + event = NULL; + agent->fd = 0; /* Mark as the connection has been established */ + +cleanup: + if(event) + CloseHandle(event); + if(pipe != INVALID_HANDLE_VALUE) + CloseHandle(pipe); + return ret; +} + +#define RECV_SEND_ALL(func, agent, buffer, length, total) \ + DWORD bytes_transfered; \ + BOOL ret; \ + DWORD err; \ + int rc; \ + \ + while(*total < length) { \ + if(!agent->pending_io) \ + ret = func(agent->pipe, (char *)buffer + *total, \ + (DWORD)(length - *total), &bytes_transfered, \ + &agent->overlapped); \ + else \ + ret = GetOverlappedResult(agent->pipe, &agent->overlapped, \ + &bytes_transfered, FALSE); \ + \ + *total += bytes_transfered; \ + if(!ret) { \ + err = GetLastError(); \ + if((!agent->pending_io && ERROR_IO_PENDING == err) \ + || (agent->pending_io && ERROR_IO_INCOMPLETE == err)) { \ + agent->pending_io = TRUE; \ + return LIBSSH2_ERROR_EAGAIN; \ + } \ + \ + return LIBSSH2_ERROR_SOCKET_NONE; \ + } \ + agent->pending_io = FALSE; \ + } \ + \ + rc = (int)*total; \ + *total = 0; \ + return rc; + +static int +win32_openssh_send_all(LIBSSH2_AGENT *agent, void *buffer, size_t length, + size_t *send_recv_total) +{ + RECV_SEND_ALL(WriteFile, agent, buffer, length, send_recv_total) +} + +static int +win32_openssh_recv_all(LIBSSH2_AGENT *agent, void *buffer, size_t length, + size_t *send_recv_total) +{ + RECV_SEND_ALL(ReadFile, agent, buffer, length, send_recv_total) +} + +#undef RECV_SEND_ALL + +static int +agent_transact_openssh(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) +{ + unsigned char buf[4]; + int rc; + + /* Send the length of the request */ + if(transctx->state == agent_NB_state_request_created) { + _libssh2_htonu32(buf, (uint32_t)transctx->request_len); + rc = win32_openssh_send_all(agent, buf, sizeof(buf), + &transctx->send_recv_total); + if(rc == LIBSSH2_ERROR_EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + else if(rc < 0) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, + "agent send failed"); + transctx->state = agent_NB_state_request_length_sent; + } + + /* Send the request body */ + if(transctx->state == agent_NB_state_request_length_sent) { + rc = win32_openssh_send_all(agent, transctx->request, + transctx->request_len, + &transctx->send_recv_total); + if(rc == LIBSSH2_ERROR_EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + else if(rc < 0) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, + "agent send failed"); + transctx->state = agent_NB_state_request_sent; + } + + /* Receive the length of the body */ + if(transctx->state == agent_NB_state_request_sent) { + rc = win32_openssh_recv_all(agent, buf, sizeof(buf), + &transctx->send_recv_total); + if(rc == LIBSSH2_ERROR_EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + else if(rc < 0) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV, + "agent recv failed"); + + transctx->response_len = _libssh2_ntohu32(buf); + transctx->response = LIBSSH2_ALLOC(agent->session, + transctx->response_len); + if(!transctx->response) + return LIBSSH2_ERROR_ALLOC; + + transctx->state = agent_NB_state_response_length_received; + } + + /* Receive the response body */ + if(transctx->state == agent_NB_state_response_length_received) { + rc = win32_openssh_recv_all(agent, transctx->response, + transctx->response_len, + &transctx->send_recv_total); + if(rc == LIBSSH2_ERROR_EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + else if(rc < 0) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV, + "agent recv failed"); + transctx->state = agent_NB_state_response_received; + } + + return LIBSSH2_ERROR_NONE; +} + +static int +agent_disconnect_openssh(LIBSSH2_AGENT *agent) +{ + if(!CancelIo(agent->pipe)) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "failed to cancel pending IO of agent pipe"); + if(!CloseHandle(agent->overlapped.hEvent)) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "failed to close handle to async I/O event"); + agent->overlapped.hEvent = NULL; + /* let queued APCs (if any) drain */ + SleepEx(0, TRUE); + if(!CloseHandle(agent->pipe)) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "failed to close handle to agent pipe"); + + agent->pipe = INVALID_HANDLE_VALUE; + agent->fd = LIBSSH2_INVALID_SOCKET; + + return LIBSSH2_ERROR_NONE; +} + +static struct agent_ops agent_ops_openssh = { + agent_connect_openssh, + agent_transact_openssh, + agent_disconnect_openssh +}; + +#endif /* HAVE_WIN32_AGENTS */ diff --git a/libs/libssh2/src/bcrypt_pbkdf.c b/libs/libssh2/src/bcrypt_pbkdf.c index e92969a00c..d088587873 100644 --- a/libs/libssh2/src/bcrypt_pbkdf.c +++ b/libs/libssh2/src/bcrypt_pbkdf.c @@ -1,6 +1,6 @@ /* $OpenBSD: bcrypt_pbkdf.c,v 1.4 2013/07/29 00:55:53 tedu Exp $ */ /* - * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org> + * Copyright (C) Ted Unangst <tedu@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -13,21 +13,18 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: MIT */ +#include "libssh2_priv.h" #ifndef HAVE_BCRYPT_PBKDF -#include "libssh2_priv.h" #include <stdlib.h> -#include <sys/types.h> -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif - -#include "blf.h" -#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b)) +#define LIBSSH2_BCRYPT_PBKDF_C +#include "blowfish.c" /* * pkcs #5 pbkdf2 implementation using the "bcrypt" hash @@ -36,7 +33,7 @@ * function with the following modifications: * 1. The input password and salt are preprocessed with SHA512. * 2. The output length is expanded to 256 bits. - * 3. Subsequently the magic string to be encrypted is lengthened and modifed + * 3. Subsequently the magic string to be encrypted is lengthened and modified * to "OxychromaticBlowfishSwatDynamite" * 4. The hash function is defined to perform 64 rounds of initial state * expansion. (More rounds are performed by iterating the hash.) @@ -60,12 +57,15 @@ static void bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) { blf_ctx state; - uint8_t ciphertext[BCRYPT_HASHSIZE] = - "OxychromaticBlowfishSwatDynamite"; + uint8_t ciphertext[BCRYPT_HASHSIZE] = { + 'O', 'x', 'y', 'c', 'h', 'r', 'o', 'm', 'a', 't', 'i', 'c', + 'B', 'l', 'o', 'w', 'f', 'i', 's', 'h', + 'S', 'w', 'a', 't', + 'D', 'y', 'n', 'a', 'm', 'i', 't', 'e' }; uint32_t cdata[BCRYPT_BLOCKS]; int i; uint16_t j; - size_t shalen = SHA512_DIGEST_LENGTH; + uint16_t shalen = SHA512_DIGEST_LENGTH; /* key expansion */ Blowfish_initstate(&state); @@ -81,11 +81,11 @@ bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext), &j); for(i = 0; i < 64; i++) - blf_enc(&state, cdata, sizeof(cdata) / sizeof(uint64_t)); + blf_enc(&state, cdata, BCRYPT_BLOCKS / 2); /* copy out */ for(i = 0; i < BCRYPT_BLOCKS; i++) { - out[4 * i + 3] = (cdata[i] >> 24) & 0xff; + out[4 * i + 3] = (uint8_t)((cdata[i] >> 24) & 0xff); out[4 * i + 2] = (cdata[i] >> 16) & 0xff; out[4 * i + 1] = (cdata[i] >> 8) & 0xff; out[4 * i + 0] = cdata[i] & 0xff; @@ -97,7 +97,7 @@ bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out) _libssh2_explicit_zero(&state, sizeof(state)); } -int +static int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, uint8_t *key, size_t keylen, unsigned int rounds) @@ -119,7 +119,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, keylen > sizeof(out) * sizeof(out) || saltlen > 1<<20) return -1; countsalt = calloc(1, saltlen + 4); - if(countsalt == NULL) + if(!countsalt) return -1; stride = (keylen + sizeof(out) - 1) / sizeof(out); amt = (keylen + stride - 1) / stride; @@ -127,19 +127,19 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, memcpy(countsalt, salt, saltlen); /* collapse password */ - libssh2_sha512_init(&ctx); + (void)libssh2_sha512_init(&ctx); libssh2_sha512_update(ctx, pass, passlen); libssh2_sha512_final(ctx, sha2pass); /* generate key, sizeof(out) at a time */ for(count = 1; keylen > 0; count++) { - countsalt[saltlen + 0] = (count >> 24) & 0xff; + countsalt[saltlen + 0] = (uint8_t)((count >> 24) & 0xff); countsalt[saltlen + 1] = (count >> 16) & 0xff; countsalt[saltlen + 2] = (count >> 8) & 0xff; countsalt[saltlen + 3] = count & 0xff; /* first round, salt is salt */ - libssh2_sha512_init(&ctx); + (void)libssh2_sha512_init(&ctx); libssh2_sha512_update(ctx, countsalt, saltlen + 4); libssh2_sha512_final(ctx, sha2salt); @@ -148,7 +148,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, for(i = 1; i < rounds; i++) { /* subsequent rounds, salt is previous output */ - libssh2_sha512_init(&ctx); + (void)libssh2_sha512_init(&ctx); libssh2_sha512_update(ctx, tmpout, sizeof(tmpout)); libssh2_sha512_final(ctx, sha2salt); @@ -158,9 +158,9 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, } /* - * pbkdf2 deviation: ouput the key material non-linearly. + * pbkdf2 deviation: output the key material non-linearly. */ - amt = MINIMUM(amt, keylen); + amt = LIBSSH2_MIN(amt, keylen); for(i = 0; i < amt; i++) { size_t dest = i * stride + (count - 1); if(dest >= origkeylen) { @@ -178,3 +178,22 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, return 0; } #endif /* HAVE_BCRYPT_PBKDF */ + +/* Wrapper */ + +int _libssh2_bcrypt_pbkdf(const char *pass, + size_t passlen, + const uint8_t *salt, + size_t saltlen, + uint8_t *key, + size_t keylen, + unsigned int rounds) +{ + return bcrypt_pbkdf(pass, + passlen, + salt, + saltlen, + key, + keylen, + rounds); +} diff --git a/libs/libssh2/src/blf.h b/libs/libssh2/src/blf.h deleted file mode 100644 index 1a85e6eef0..0000000000 --- a/libs/libssh2/src/blf.h +++ /dev/null @@ -1,90 +0,0 @@ -/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */ -/* - * Blowfish - a fast block cipher designed by Bruce Schneier - * - * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Niels Provos. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _BLF_H_ -#define _BLF_H_ - -#if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) - -/* Schneier specifies a maximum key length of 56 bytes. - * This ensures that every key bit affects every cipher - * bit. However, the subkeys can hold up to 72 bytes. - * Warning: For normal blowfish encryption only 56 bytes - * of the key affect all cipherbits. - */ - -#define BLF_N 16 /* Number of Subkeys */ -#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ -#define BLF_MAXUTILIZED ((BLF_N + 2)*4) /* 576 bits */ - -/* Blowfish context */ -typedef struct BlowfishContext { - uint32_t S[4][256]; /* S-Boxes */ - uint32_t P[BLF_N + 2]; /* Subkeys */ -} blf_ctx; - -/* Raw access to customized Blowfish - * blf_key is just: - * Blowfish_initstate( state ) - * Blowfish_expand0state( state, key, keylen ) - */ - -void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *); -void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *); -void Blowfish_initstate(blf_ctx *); -void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t); -void Blowfish_expandstate -(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t); - -/* Standard Blowfish */ - -void blf_key(blf_ctx *, const uint8_t *, uint16_t); -void blf_enc(blf_ctx *, uint32_t *, uint16_t); -void blf_dec(blf_ctx *, uint32_t *, uint16_t); - -void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t); -void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t); - -void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); -void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); - -/* Converts uint8_t to uint32_t */ -uint32_t Blowfish_stream2word(const uint8_t *, uint16_t, uint16_t *); - -/* bcrypt with pbkd */ -int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, - size_t saltlen, - uint8_t *key, size_t keylen, unsigned int rounds); - -#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */ -#endif /* _BLF_H */ diff --git a/libs/libssh2/src/blowfish.c b/libs/libssh2/src/blowfish.c index 4aefc66ac7..5de54f5963 100644 --- a/libs/libssh2/src/blowfish.c +++ b/libs/libssh2/src/blowfish.c @@ -1,7 +1,8 @@ /* $OpenBSD: blowfish.c,v 1.18 2004/11/02 17:23:26 hshoexer Exp $ */ /* - * Blowfish block cipher for OpenBSD - * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> + * Blowfish for OpenBSD - a fast block cipher designed by Bruce Schneier + * + * Copyright (C) Niels Provos <provos@physnet.uni-hamburg.de> * All rights reserved. * * Implementation advice by David Mazieres <dm@lcs.mit.edu>. @@ -14,10 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Niels Provos. - * 4. The name of the author may not be used to endorse or promote products + * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR @@ -30,6 +28,8 @@ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* @@ -39,38 +39,81 @@ * Bruce Schneier. */ +#if defined(LIBSSH2_BCRYPT_PBKDF_C) || defined(_DEBUG_BLOWFISH) #if !defined(HAVE_BCRYPT_PBKDF) && (!defined(HAVE_BLOWFISH_INITSTATE) || \ !defined(HAVE_BLOWFISH_EXPAND0STATE) || \ !defined(HAVE_BLF_ENC)) -#if 0 -#include <stdio.h> /* used for debugging */ +#ifdef _DEBUG_BLOWFISH +#include <stdio.h> #include <string.h> +#include <inttypes.h> +#endif + +/* Schneier specifies a maximum key length of 56 bytes. + * This ensures that every key bit affects every cipher + * bit. However, the subkeys can hold up to 72 bytes. + * Warning: For normal blowfish encryption only 56 bytes + * of the key affect all cipherbits. + */ + +#define BLF_N 16 /* Number of Subkeys */ +#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ +#define BLF_MAXUTILIZED ((BLF_N + 2)*4) /* 576 bits */ + +/* Blowfish context */ +typedef struct BlowfishContext { + uint32_t S[4][256]; /* S-Boxes */ + uint32_t P[BLF_N + 2]; /* Subkeys */ +} blf_ctx; + +/* Raw access to customized Blowfish + * blf_key is just: + * Blowfish_initstate( state ) + * Blowfish_expand0state( state, key, keylen ) + */ + +static void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *); +#ifdef _DEBUG_BLOWFISH +static void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *); +#endif +static void Blowfish_initstate(blf_ctx *); +static void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t); +static void Blowfish_expandstate +(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t); + +/* Standard Blowfish */ + +#ifdef _DEBUG_BLOWFISH +static void blf_key(blf_ctx *, const uint8_t *, uint16_t); +#endif +static void blf_enc(blf_ctx *, uint32_t *, uint16_t); +#ifdef _DEBUG_BLOWFISH +static void blf_dec(blf_ctx *, uint32_t *, uint16_t); #endif -#include <sys/types.h> +#if 0 +static void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t); +static void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t); -#include "libssh2.h" -#include "blf.h" +static void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); +static void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t); +#endif -#undef inline -#ifdef __GNUC__ -#define inline __inline -#else /* !__GNUC__ */ -#define inline -#endif /* !__GNUC__ */ +/* Converts uint8_t to uint32_t */ +static uint32_t Blowfish_stream2word(const uint8_t *, uint16_t, uint16_t *); /* Function for Feistel Networks */ -#define F(s, x) ((((s)[ (((x)>>24)&0xFF)] \ - + (s)[0x100 + (((x)>>16)&0xFF)]) \ - ^ (s)[0x200 + (((x)>> 8)&0xFF)]) \ - + (s)[0x300 + ( (x) &0xFF)]) +#define F(s, x) ((((s)[ (((x) >> 24) & 0xFF)] \ + + (s)[0x100 + (((x) >> 16) & 0xFF)]) \ + ^ (s)[0x200 + (((x) >> 8) & 0xFF)]) \ + + (s)[0x300 + ( (x) & 0xFF)]) #define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n]) -void +static void Blowfish_encipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) { uint32_t Xl; @@ -95,7 +138,8 @@ Blowfish_encipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) *xr = Xl; } -void +#ifdef _DEBUG_BLOWFISH +static void Blowfish_decipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) { uint32_t Xl; @@ -119,8 +163,9 @@ Blowfish_decipher(blf_ctx *c, uint32_t *xl, uint32_t *xr) *xl = Xr ^ p[0]; *xr = Xl; } +#endif -void +static void Blowfish_initstate(blf_ctx *c) { /* P-box and S-box tables initialized with digits of Pi */ @@ -399,7 +444,7 @@ Blowfish_initstate(blf_ctx *c) *c = initstate; } -uint32_t +static uint32_t Blowfish_stream2word(const uint8_t *data, uint16_t databytes, uint16_t *current) { @@ -420,12 +465,12 @@ Blowfish_stream2word(const uint8_t *data, uint16_t databytes, return temp; } -void +static void Blowfish_expand0state(blf_ctx *c, const uint8_t *key, uint16_t keybytes) { - uint16_t i; + int i; + int k; uint16_t j; - uint16_t k; uint32_t temp; uint32_t datal; uint32_t datar; @@ -457,14 +502,13 @@ Blowfish_expand0state(blf_ctx *c, const uint8_t *key, uint16_t keybytes) } } - -void +static void Blowfish_expandstate(blf_ctx *c, const uint8_t *data, uint16_t databytes, const uint8_t *key, uint16_t keybytes) { - uint16_t i; + int i; + int k; uint16_t j; - uint16_t k; uint32_t temp; uint32_t datal; uint32_t datar; @@ -501,7 +545,8 @@ Blowfish_expandstate(blf_ctx *c, const uint8_t *data, uint16_t databytes, } -void +#ifdef _DEBUG_BLOWFISH +static void blf_key(blf_ctx *c, const uint8_t *k, uint16_t len) { /* Initialize S-boxes and subkeys with Pi */ @@ -510,8 +555,9 @@ blf_key(blf_ctx *c, const uint8_t *k, uint16_t len) /* Transform S-boxes and subkeys with key */ Blowfish_expand0state(c, k, len); } +#endif -void +static void blf_enc(blf_ctx *c, uint32_t *data, uint16_t blocks) { uint32_t *d; @@ -524,7 +570,8 @@ blf_enc(blf_ctx *c, uint32_t *data, uint16_t blocks) } } -void +#ifdef _DEBUG_BLOWFISH +static void blf_dec(blf_ctx *c, uint32_t *data, uint16_t blocks) { uint32_t *d; @@ -536,8 +583,10 @@ blf_dec(blf_ctx *c, uint32_t *data, uint16_t blocks) d += 2; } } +#endif -void +#if 0 +static void blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -547,11 +596,11 @@ blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_encipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -559,7 +608,7 @@ blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len) } } -void +static void blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -569,11 +618,11 @@ blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -581,7 +630,7 @@ blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len) } } -void +static void blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -593,11 +642,11 @@ blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_encipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -606,7 +655,7 @@ blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len) } } -void +static void blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len) { uint32_t l, r; @@ -619,11 +668,11 @@ blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; @@ -635,31 +684,31 @@ blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len) l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); - data[0] = l >> 24 & 0xff; + data[0] = (uint8_t)(l >> 24 & 0xff); data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; - data[4] = r >> 24 & 0xff; + data[4] = (uint8_t)(r >> 24 & 0xff); data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; for(j = 0; j < 8; j++) data[j] ^= iva[j]; } +#endif -#if 0 -void +#ifdef _DEBUG_BLOWFISH +static void report(uint32_t data[], uint16_t len) { - uint16_t i; + int i; for(i = 0; i < len; i += 2) - printf("Block %0hd: %08lx %08lx.\n", - i / 2, data[i], data[i + 1]); + printf("Block %d: 0x%08lx 0x%08lx.\n", + i / 2, (unsigned long)data[i], (unsigned long)data[i + 1]); } -void +int main(void) { - blf_ctx c; char key[] = "AAAAA"; char key2[] = "abcdefghijklmnopqrstuvwxyz"; @@ -682,12 +731,15 @@ main(void) report(data, 10); /* Second test */ - blf_key(&c, (uint8_t *) key2, strlen(key2)); + blf_key(&c, (uint8_t *) key2, (uint16_t)strlen(key2)); blf_enc(&c, data2, 1); printf("\nShould read as: 0x324ed0fe 0xf413a203.\n"); report(data2, 2); blf_dec(&c, data2, 1); + printf("\nShould read as: 0x424c4f57 0x46495348.\n"); report(data2, 2); + + return 0; } #endif @@ -695,3 +747,5 @@ main(void) (!defined(HAVE_BLOWFISH_INITSTATE) || \ !defined(HAVE_BLOWFISH_EXPAND0STATE) || \ '!defined(HAVE_BLF_ENC)) */ + +#endif /* defined(LIBSSH2_BCRYPT_PBKDF_C) || defined(_DEBUG_BLOWFISH) */ diff --git a/libs/libssh2/src/channel.c b/libs/libssh2/src/channel.c index 7bbeeb88f6..c35658a04e 100644 --- a/libs/libssh2/src/channel.c +++ b/libs/libssh2/src/channel.c @@ -1,7 +1,6 @@ -/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net> - * Copyright (c) 2008-2019 by Daniel Stenberg - * +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Mikhail Gusarov <dottedmag@dottedmag.net> + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,16 +35,19 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#include <fcntl.h> #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif + #include <assert.h> #include "channel.h" @@ -81,8 +83,8 @@ _libssh2_channel_nextid(LIBSSH2_SESSION * session) * told... */ session->next_channel = id + 1; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Allocated new channel ID#%lu", - id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Allocated new channel ID#%lu", id)); return id; } @@ -154,9 +156,9 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, memset(&session->open_packet_requirev_state, 0, sizeof(session->open_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Opening Channel - win %d pack %d", window_size, - packet_size); + packet_size)); session->open_channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); if(!session->open_channel) { @@ -236,6 +238,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, return NULL; } else if(rc) { + _libssh2_error(session, rc, "Unexpected error"); goto channel_error; } @@ -261,7 +264,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, _libssh2_ntohu32(session->open_data + 9); session->open_channel->local.packet_size = _libssh2_ntohu32(session->open_data + 13); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Connection Established - ID: %lu/%lu win: %lu/%lu" " pack: %lu/%lu", session->open_channel->local.id, @@ -269,7 +272,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, session->open_channel->local.window_size, session->open_channel->remote.window_size, session->open_channel->local.packet_size, - session->open_channel->remote.packet_size); + session->open_channel->remote.packet_size)); LIBSSH2_FREE(session, session->open_packet); session->open_packet = NULL; LIBSSH2_FREE(session, session->open_data); @@ -307,7 +310,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, } } - channel_error: +channel_error: if(session->open_data) { LIBSSH2_FREE(session, session->open_data); @@ -326,14 +329,14 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, /* Clear out packets meant for this channel */ _libssh2_htonu32(channel_id, session->open_channel->local.id); while((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, - &session->open_data, - &session->open_data_len, 1, - channel_id, 4) >= 0)) { + &session->open_data, + &session->open_data_len, 1, + channel_id, 4) >= 0) + || + (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, + &session->open_data, + &session->open_data_len, 1, + channel_id, 4) >= 0)) { LIBSSH2_FREE(session, session->open_data); session->open_data = NULL; } @@ -389,9 +392,9 @@ channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host, session->direct_message_len = session->direct_host_len + session->direct_shost_len + 16; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Requesting direct-tcpip session from %s:%d to %s:%d", - shost, sport, host, port); + shost, sport, host, port)); s = session->direct_message = LIBSSH2_ALLOC(session, session->direct_message_len); @@ -452,6 +455,85 @@ libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, } /* + * libssh2_channel_direct_streamlocal_ex + * + * Tunnel TCP/IP connect through the SSH session to direct UNIX socket + */ +static LIBSSH2_CHANNEL * +channel_direct_streamlocal(LIBSSH2_SESSION * session, const char *socket_path, + const char *shost, int sport) +{ + LIBSSH2_CHANNEL *channel; + unsigned char *s; + + if(session->direct_state == libssh2_NB_state_idle) { + session->direct_host_len = strlen(socket_path); + session->direct_shost_len = strlen(shost); + session->direct_message_len = + session->direct_host_len + session->direct_shost_len + 12; + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Requesting direct-streamlocal session to %s", + socket_path)); + + s = session->direct_message = + LIBSSH2_ALLOC(session, session->direct_message_len); + if(!session->direct_message) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for direct-streamlocal connection"); + return NULL; + } + _libssh2_store_str(&s, socket_path, session->direct_host_len); + _libssh2_store_str(&s, shost, session->direct_shost_len); + _libssh2_store_u32(&s, sport); + } + + channel = + _libssh2_channel_open(session, "direct-streamlocal@openssh.com", + sizeof("direct-streamlocal@openssh.com") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, + session->direct_message, + session->direct_message_len); + + if(!channel && + libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { + /* The error code is still set to LIBSSH2_ERROR_EAGAIN, set our state + to created to avoid re-creating the package on next invoke */ + session->direct_state = libssh2_NB_state_created; + return NULL; + } + /* by default we set (keep?) idle state... */ + session->direct_state = libssh2_NB_state_idle; + + LIBSSH2_FREE(session, session->direct_message); + session->direct_message = NULL; + + return channel; +} + +/* + * libssh2_channel_direct_streamlocal_ex + * + * Tunnel TCP/IP connect through the SSH session to direct UNIX socket + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION * session, + const char *socket_path, + const char *shost, int sport) +{ + LIBSSH2_CHANNEL *ptr; + + if(!session) + return NULL; + + BLOCK_ADJUST_ERRNO(ptr, session, + channel_direct_streamlocal(session, + socket_path, shost, sport)); + return ptr; +} + +/* * channel_forward_listen * * Bind a port on the remote host and listen for connections @@ -469,19 +551,20 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host, host = "0.0.0.0"; if(session->fwdLstn_state == libssh2_NB_state_idle) { - session->fwdLstn_host_len = strlen(host); + session->fwdLstn_host_len = (uint32_t)strlen(host); /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */ session->fwdLstn_packet_len = - session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14; + session->fwdLstn_host_len + + (uint32_t)(sizeof("tcpip-forward") - 1) + 14; /* Zero the whole thing out */ memset(&session->fwdLstn_packet_requirev_state, 0, sizeof(session->fwdLstn_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Requesting tcpip-forward session for %s:%d", host, - port); + port)); s = session->fwdLstn_packet = LIBSSH2_ALLOC(session, session->fwdLstn_packet_len); @@ -566,10 +649,10 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host, listener->host[session->fwdLstn_host_len] = 0; if(data_len >= 5 && !port) { listener->port = _libssh2_ntohu32(data + 1); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Dynamic tcpip-forward port " "allocated: %d", - listener->port); + listener->port)); } else listener->port = port; @@ -646,9 +729,9 @@ int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) int retcode = 0; if(listener->chanFwdCncl_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Cancelling tcpip-forward session for %s:%d", - listener->host, listener->port); + listener->host, listener->port)); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { @@ -817,10 +900,10 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel, memset(&channel->setenv_packet_requirev_state, 0, sizeof(channel->setenv_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Setting remote environment variable: %s=%s on " "channel %lu/%lu", - varname, value, channel->local.id, channel->remote.id); + varname, value, channel->local.id, channel->remote.id)); s = channel->setenv_packet = LIBSSH2_ALLOC(session, channel->setenv_packet_len); @@ -876,7 +959,9 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel, } if(rc) { channel->setenv_state = libssh2_NB_state_idle; - return rc; + return _libssh2_error(session, rc, + "Failed getting response for " + "channel-setenv"); } else if(data_len < 1) { channel->setenv_state = libssh2_NB_state_idle; @@ -950,9 +1035,9 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel, memset(&channel->reqPTY_packet_requirev_state, 0, sizeof(channel->reqPTY_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Allocating tty on channel %lu/%lu", channel->local.id, - channel->remote.id); + channel->remote.id)); s = channel->reqPTY_packet; @@ -1021,6 +1106,164 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel, "channel request-pty"); } +/** + * channel_request_auth_agent + * The actual re-entrant method which requests an auth agent. + * */ +static int channel_request_auth_agent(LIBSSH2_CHANNEL *channel, + const char *request_str, + int request_str_len) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char *s; + static const unsigned char reply_codes[3] = + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; + int rc; + + if(channel->req_auth_agent_state == libssh2_NB_state_idle) { + /* Only valid options are "auth-agent-req" and + * "auth-agent-req_at_openssh.com" so we make sure it is not + * actually longer than the longest possible. */ + if(request_str_len > 26) { + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "request_str length too large"); + } + + /* + * Length: 24 or 36 = packet_type(1) + channel(4) + req_len(4) + + * request_str (variable) + want_reply (1) */ + channel->req_auth_agent_packet_len = 10 + request_str_len; + + /* Zero out the requireev state to reset */ + memset(&channel->req_auth_agent_requirev_state, 0, + sizeof(channel->req_auth_agent_requirev_state)); + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Requesting auth agent on channel %lu/%lu", + channel->local.id, channel->remote.id)); + + /* + * byte SSH_MSG_CHANNEL_REQUEST + * uint32 recipient channel + * string "auth-agent-req" + * boolean want reply + * */ + s = channel->req_auth_agent_packet; + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, (char *)request_str, request_str_len); + *(s++) = 0x01; + + channel->req_auth_agent_state = libssh2_NB_state_created; + } + + if(channel->req_auth_agent_state == libssh2_NB_state_created) { + /* Send the packet, we can use sizeof() on the packet because it + * is always completely filled; there are no variable length fields. */ + rc = _libssh2_transport_send(session, channel->req_auth_agent_packet, + channel->req_auth_agent_packet_len, + NULL, 0); + + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending auth-agent request"); + return rc; + } + else if(rc) { + channel->req_auth_agent_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send auth-agent request"); + } + _libssh2_htonu32(channel->req_auth_agent_local_channel, + channel->local.id); + channel->req_auth_agent_state = libssh2_NB_state_sent; + } + + if(channel->req_auth_agent_state == libssh2_NB_state_sent) { + unsigned char *data; + size_t data_len; + unsigned char code; + + rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, + 1, channel->req_auth_agent_local_channel, + 4, + &channel->req_auth_agent_requirev_state); + if(rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if(rc) { + channel->req_auth_agent_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Failed to request auth-agent"); + } + + code = data[0]; + + LIBSSH2_FREE(session, data); + channel->req_auth_agent_state = libssh2_NB_state_idle; + + if(code == SSH_MSG_CHANNEL_SUCCESS) + return 0; + } + + return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, + "Unable to complete request for auth-agent"); +} + +/* + * libssh2_channel_request_auth_agent + * + * Requests that agent forwarding be enabled for the session. The + * request must be sent over a specific channel, which starts the agent + * listener on the remote side. Once the channel is closed, the agent + * listener continues to exist. + */ +LIBSSH2_API int +libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + rc = LIBSSH2_ERROR_CHANNEL_UNKNOWN; + + /* The current RFC draft for agent forwarding says you're supposed to + * send "auth-agent-req," but most SSH servers out there right now + * actually expect "auth-agent-req@openssh.com", so we try that + * first. */ + if(channel->req_auth_agent_try_state == libssh2_NB_state_idle) { + BLOCK_ADJUST(rc, channel->session, + channel_request_auth_agent(channel, + "auth-agent-req@openssh.com", + 26)); + + /* If we failed (but not with EAGAIN), then we move onto + * the next step to try another request type. */ + if(rc != LIBSSH2_ERROR_NONE && + rc != LIBSSH2_ERROR_EAGAIN) + channel->req_auth_agent_try_state = libssh2_NB_state_sent; + } + + if(channel->req_auth_agent_try_state == libssh2_NB_state_sent) { + BLOCK_ADJUST(rc, channel->session, + channel_request_auth_agent(channel, + "auth-agent-req", 14)); + + /* If we failed without an EAGAIN, then move on with this + * state machine. */ + if(rc != LIBSSH2_ERROR_NONE && + rc != LIBSSH2_ERROR_EAGAIN) + channel->req_auth_agent_try_state = libssh2_NB_state_sent1; + } + + /* If things are good, reset the try state. */ + if(rc == LIBSSH2_ERROR_NONE) + channel->req_auth_agent_try_state = libssh2_NB_state_idle; + + return rc; +} + /* * libssh2_channel_request_pty_ex * Duh... Request a PTY @@ -1059,10 +1302,10 @@ channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width, memset(&channel->reqPTY_packet_requirev_state, 0, sizeof(channel->reqPTY_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "changing tty size on channel %lu/%lu", - channel->local.id, - channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "changing tty size on channel %lu/%lu", + channel->local.id, + channel->remote.id)); s = channel->reqPTY_packet; @@ -1148,13 +1391,13 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, memset(&channel->reqX11_packet_requirev_state, 0, sizeof(channel->reqX11_packet_requirev_state)); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Requesting x11-req for channel %lu/%lu: single=%d " "proto=%s cookie=%s screen=%d", channel->local.id, channel->remote.id, single_connection, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", - auth_cookie ? auth_cookie : "<random>", screen_number); + auth_cookie ? auth_cookie : "<random>", screen_number)); s = channel->reqX11_packet = LIBSSH2_ALLOC(session, channel->reqX11_packet_len); @@ -1173,7 +1416,7 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, _libssh2_store_str(&s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len); - _libssh2_store_u32(&s, cookie_len); + _libssh2_store_u32(&s, (uint32_t)cookie_len); if(auth_cookie) { memcpy(s, auth_cookie, cookie_len); } @@ -1185,7 +1428,11 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, border */ unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) + 1]; - _libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); + if(_libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2)) { + return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN, + "Unable to get random bytes " + "for x11-req cookie"); + } for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) { snprintf((char *)&s[i*2], 3, "%02X", buffer[i]); } @@ -1302,10 +1549,10 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, if(message) channel->process_packet_len += + 4; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "starting request(%s) on channel %lu/%lu, message=%s", request, channel->local.id, channel->remote.id, - message ? message : "<null>"); + message ? message : "<null>")); s = channel->process_packet = LIBSSH2_ALLOC(session, channel->process_packet_len); if(!channel->process_packet) @@ -1319,7 +1566,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, *(s++) = 0x01; if(message) - _libssh2_store_u32(&s, message_len); + _libssh2_store_u32(&s, (uint32_t)message_len); channel->process_state = libssh2_NB_state_created; } @@ -1410,7 +1657,7 @@ LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking) { if(channel) - (void) _libssh2_session_set_blocking(channel->session, blocking); + (void)_libssh2_session_set_blocking(channel->session, blocking); } /* @@ -1434,8 +1681,8 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) if(packet->data_len < 1) { packet = next; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -1471,11 +1718,11 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) size_t bytes_to_flush = packet->data_len - packet->data_head; - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, "Flushing %d bytes of data from stream " "%lu on channel %lu/%lu", bytes_to_flush, packet_stream_id, - channel->local.id, channel->remote.id); + channel->local.id, channel->remote.id)); /* It's one of the streams we wanted to flush */ channel->flush_refund_bytes += packet->data_len - 13; @@ -1495,20 +1742,20 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) } channel->read_avail -= channel->flush_flush_bytes; - channel->remote.window_size -= channel->flush_flush_bytes; + channel->remote.window_size -= (uint32_t)channel->flush_flush_bytes; if(channel->flush_refund_bytes) { int rc = _libssh2_channel_receive_window_adjust(channel, - channel->flush_refund_bytes, - 1, NULL); + (uint32_t)channel->flush_refund_bytes, + 1, NULL); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; } channel->flush_state = libssh2_NB_state_idle; - return channel->flush_flush_bytes; + return (int)channel->flush_flush_bytes; } /* @@ -1577,7 +1824,7 @@ libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, *exitsignal = LIBSSH2_ALLOC(session, namelen + 1); if(!*exitsignal) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for signal name"); + "Unable to allocate memory for signal name"); } memcpy(*exitsignal, channel->exit_signal, namelen); (*exitsignal)[namelen] = '\0'; @@ -1634,10 +1881,10 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, if(!force && (adjustment + channel->adjust_queue < LIBSSH2_CHANNEL_MINADJUST)) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, "Queueing %lu bytes for receive window adjustment " "for channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); + adjustment, channel->local.id, channel->remote.id)); channel->adjust_queue += adjustment; return 0; } @@ -1653,10 +1900,10 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; _libssh2_htonu32(&channel->adjust_adjust[1], channel->remote.id); _libssh2_htonu32(&channel->adjust_adjust[5], adjustment); - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, "Adjusting window %lu bytes for data on " "channel %lu/%lu", - adjustment, channel->local.id, channel->remote.id); + adjustment, channel->local.id, channel->remote.id)); channel->adjust_state = libssh2_NB_state_created; } @@ -1708,7 +1955,8 @@ libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, return (unsigned long)LIBSSH2_ERROR_BAD_USE; BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, + _libssh2_channel_receive_window_adjust(channel, + (uint32_t)adj, force, &window)); /* stupid - but this is how it was made to work before and this is just @@ -1739,8 +1987,9 @@ libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, return LIBSSH2_ERROR_BAD_USE; BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, adj, force, - window)); + _libssh2_channel_receive_window_adjust(channel, + (uint32_t)adj, + force, window)); return rc; } @@ -1748,10 +1997,10 @@ int _libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) { if(channel->extData2_state == libssh2_NB_state_idle) { - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, "Setting channel %lu/%lu handle_extended_data" " mode to %d", - channel->local.id, channel->remote.id, ignore_mode); + channel->local.id, channel->remote.id, ignore_mode)); channel->remote.extended_data_ignore_mode = (char)ignore_mode; channel->extData2_state = libssh2_NB_state_created; @@ -1772,7 +2021,7 @@ _libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) } /* - * libssh2_channel_handle_extended_data2() + * libssh2_channel_handle_extended_data2 * */ LIBSSH2_API int @@ -1831,19 +2080,19 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, LIBSSH2_PACKET *read_packet; LIBSSH2_PACKET *read_next; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "channel_read() wants %d bytes from channel %lu/%lu " "stream #%d", (int) buflen, channel->local.id, channel->remote.id, - stream_id); + stream_id)); /* expand the receiving window first if it has become too narrow */ if((channel->read_state == libssh2_NB_state_jump1) || (channel->remote.window_size < - channel->remote.window_size_initial / 4 * 3 + buflen) ) { + channel->remote.window_size_initial / 4 * 3 + buflen)) { - uint32_t adjustment = channel->remote.window_size_initial + buflen - - channel->remote.window_size; + uint32_t adjustment = (uint32_t)(channel->remote.window_size_initial + + buflen - channel->remote.window_size); if(adjustment < LIBSSH2_CHANNEL_MINADJUST) adjustment = LIBSSH2_CHANNEL_MINADJUST; @@ -1884,8 +2133,13 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, if(readpkt->data_len < 5) { read_packet = read_next; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + + if(readpkt->data_len != 1 || + readpkt->data[0] != SSH_MSG_REQUEST_FAILURE) { + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); + } + continue; } @@ -1923,11 +2177,11 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, unlink_packet = TRUE; } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "channel_read() got %d of data from %lu/%lu/%d%s", bytes_want, channel->local.id, channel->remote.id, stream_id, - unlink_packet?" [ul]":""); + unlink_packet?" [ul]":"")); /* copy data from this struct to the target buffer */ memcpy(&buf[bytes_read], @@ -1966,7 +2220,7 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, } channel->read_avail -= bytes_read; - channel->remote.window_size -= bytes_read; + channel->remote.window_size -= (uint32_t)bytes_read; return bytes_read; } @@ -1989,7 +2243,7 @@ LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen) { - int rc; + ssize_t rc; unsigned long recv_window; if(!channel) @@ -1999,8 +2253,8 @@ libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, if(buflen > recv_window) { BLOCK_ADJUST(rc, channel->session, - _libssh2_channel_receive_window_adjust(channel, buflen, - 1, NULL)); + _libssh2_channel_receive_window_adjust(channel, + (uint32_t)buflen, 1, NULL)); } BLOCK_ADJUST(rc, channel->session, @@ -2023,7 +2277,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) uint32_t read_local_id; read_packet = _libssh2_list_first(&session->packets); - if(read_packet == NULL) + if(!read_packet) return 0; while(read_packet) { @@ -2032,8 +2286,8 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) if(read_packet->data_len < 5) { read_packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -2061,7 +2315,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) && (channel->local.id == read_local_id) && (channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) { - return (read_packet->data_len - read_packet->data_head); + return read_packet->data_len - read_packet->data_head; } read_packet = next_packet; @@ -2101,15 +2355,15 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, if(channel->write_state == libssh2_NB_state_idle) { unsigned char *s = channel->write_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN, "Writing %d bytes on channel %lu/%lu, stream #%d", (int) buflen, channel->local.id, channel->remote.id, - stream_id); + stream_id)); if(channel->local.close) return _libssh2_error(channel->session, LIBSSH2_ERROR_CHANNEL_CLOSED, - "We've already closed this channel"); + "We have already closed this channel"); else if(channel->local.eof) return _libssh2_error(channel->session, LIBSSH2_ERROR_CHANNEL_EOF_SENT, @@ -2136,7 +2390,7 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, */ session->socket_block_directions = LIBSSH2_SESSION_BLOCK_INBOUND; - return (rc == LIBSSH2_ERROR_EAGAIN?rc:0); + return rc == LIBSSH2_ERROR_EAGAIN ? rc : 0; } channel->write_bufwrite = buflen; @@ -2150,30 +2404,30 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, /* Don't exceed the remote end's limits */ /* REMEMBER local means local as the SOURCE of the data */ if(channel->write_bufwrite > channel->local.window_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Splitting write block due to %lu byte " "window_size on %lu/%lu/%d", channel->local.window_size, channel->local.id, - channel->remote.id, stream_id); + channel->remote.id, stream_id)); channel->write_bufwrite = channel->local.window_size; } if(channel->write_bufwrite > channel->local.packet_size) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Splitting write block due to %lu byte " "packet_size on %lu/%lu/%d", channel->local.packet_size, channel->local.id, - channel->remote.id, stream_id); + channel->remote.id, stream_id)); channel->write_bufwrite = channel->local.packet_size; } /* store the size here only, the buffer is passed in as-is to _libssh2_transport_send() */ - _libssh2_store_u32(&s, channel->write_bufwrite); + _libssh2_store_u32(&s, (uint32_t)channel->write_bufwrite); channel->write_packet_len = s - channel->write_packet; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Sending %d bytes on channel %lu/%lu, stream_id=%d", (int) channel->write_bufwrite, channel->local.id, - channel->remote.id, stream_id); + channel->remote.id, stream_id)); channel->write_state = libssh2_NB_state_created; } @@ -2192,7 +2446,7 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, "Unable to send channel data"); } /* Shrink local window size */ - channel->local.window_size -= channel->write_bufwrite; + channel->local.window_size -= (uint32_t)channel->write_bufwrite; wrote += channel->write_bufwrite; @@ -2245,9 +2499,9 @@ static int channel_send_eof(LIBSSH2_CHANNEL *channel) unsigned char packet[5]; /* packet_type(1) + channelno(4) */ int rc; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Sending EOF on channel %lu/%lu", - channel->local.id, channel->remote.id); + channel->local.id, channel->remote.id)); packet[0] = SSH_MSG_CHANNEL_EOF; _libssh2_htonu32(packet + 1, channel->remote.id); rc = _libssh2_transport_send(session, packet, 5, NULL, 0); @@ -2306,8 +2560,8 @@ libssh2_channel_eof(LIBSSH2_CHANNEL * channel) if(packet->data_len < 1) { packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -2335,9 +2589,9 @@ static int channel_wait_eof(LIBSSH2_CHANNEL *channel) int rc; if(channel->wait_eof_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Awaiting EOF for channel %lu/%lu", channel->local.id, - channel->remote.id); + channel->remote.id)); channel->wait_eof_state = libssh2_NB_state_created; } @@ -2364,7 +2618,7 @@ static int channel_wait_eof(LIBSSH2_CHANNEL *channel) else if(rc < 0) { channel->wait_eof_state = libssh2_NB_state_idle; return _libssh2_error(session, rc, - "_libssh2_transport_read() bailed out!"); + "_libssh2_transport_read() bailed out"); } } while(1); @@ -2409,7 +2663,7 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel) return rc; } _libssh2_error(session, rc, - "Unable to send EOF, but closing channel anyway"); + "Unable to send EOF, but closing channel anyway"); } } @@ -2417,8 +2671,8 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel) late for us to wait for it. Continue closing! */ if(channel->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu", - channel->local.id, channel->remote.id); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu", + channel->local.id, channel->remote.id)); channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE; _libssh2_htonu32(channel->close_packet + 1, channel->remote.id); @@ -2486,7 +2740,7 @@ libssh2_channel_close(LIBSSH2_CHANNEL *channel) if(!channel) return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel) ); + BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel)); return rc; } @@ -2507,9 +2761,9 @@ static int channel_wait_closed(LIBSSH2_CHANNEL *channel) } if(channel->wait_closed_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Awaiting close of channel %lu/%lu", channel->local.id, - channel->remote.id); + channel->remote.id)); channel->wait_closed_state = libssh2_NB_state_created; } @@ -2570,9 +2824,9 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) assert(session); if(channel->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Freeing channel %lu/%lu resources", channel->local.id, - channel->remote.id); + channel->remote.id)); channel->free_state = libssh2_NB_state_created; } @@ -2604,10 +2858,10 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) /* Clear out packets meant for this channel */ _libssh2_htonu32(channel_id, channel->local.id); while((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, &data, - &data_len, 1, channel_id, 4) >= 0) - || - (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, - &data_len, 1, channel_id, 4) >= 0)) { + &data_len, 1, channel_id, 4) >= 0) + || + (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, + &data_len, 1, channel_id, 4) >= 0)) { LIBSSH2_FREE(session, data); } @@ -2667,7 +2921,7 @@ libssh2_channel_free(LIBSSH2_CHANNEL *channel) */ LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, - unsigned long *read_avail, + /* FIXME: -> size_t */ unsigned long *read_avail, unsigned long *window_size_initial) { if(!channel) @@ -2689,8 +2943,8 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, if(packet->data_len < 1) { packet = next_packet; - _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR, - "Unexpected packet length"); + _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR, + "Unexpected packet length")); continue; } @@ -2707,7 +2961,7 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, packet = next_packet; } - *read_avail = bytes_queued; + *read_avail = (unsigned long)bytes_queued; } return channel->remote.window_size; @@ -2736,3 +2990,87 @@ libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, return channel->local.window_size; } + +/* A signal can be delivered to the remote process/service using the + following message. Some systems may not implement signals, in which + case they SHOULD ignore this message. + + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string "signal" + boolean FALSE + string signal name (without the "SIG" prefix) + + 'signal name' values will be encoded as discussed in the passage + describing SSH_MSG_CHANNEL_REQUEST messages using "exit-signal" in + this section. + */ +static int channel_signal(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len) +{ + LIBSSH2_SESSION *session = channel->session; + int retcode = LIBSSH2_ERROR_PROTO; + + if(channel->sendsignal_state == libssh2_NB_state_idle) { + unsigned char *s; + + /* 20 = packet_type(1) + channel(4) + + signal_len + sizeof(signal) - 1 + want_reply(1) + + signame_len_len(4) */ + channel->sendsignal_packet_len = 20 + signame_len; + + s = channel->sendsignal_packet = + LIBSSH2_ALLOC(session, channel->sendsignal_packet_len); + if(!channel->sendsignal_packet) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "signal request"); + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, "signal", sizeof("signal") - 1); + *(s++) = 0x00; /* Don't reply */ + _libssh2_store_str(&s, signame, signame_len); + + channel->sendsignal_state = libssh2_NB_state_created; + } + + if(channel->sendsignal_state == libssh2_NB_state_created) { + int rc; + + rc = _libssh2_transport_send(session, channel->sendsignal_packet, + channel->sendsignal_packet_len, + NULL, 0); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, "Would block sending signal request"); + return rc; + } + else if(rc) { + LIBSSH2_FREE(session, channel->sendsignal_packet); + channel->sendsignal_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, "Unable to send signal packet"); + } + LIBSSH2_FREE(session, channel->sendsignal_packet); + retcode = LIBSSH2_ERROR_NONE; + } + + channel->sendsignal_state = libssh2_NB_state_idle; + + return retcode; +} + +LIBSSH2_API int +libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel, + const char *signame, + size_t signame_len) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + channel_signal(channel, signame, signame_len)); + return rc; +} diff --git a/libs/libssh2/src/channel.h b/libs/libssh2/src/channel.h index dc0ee3764f..6d03550164 100644 --- a/libs/libssh2/src/channel.h +++ b/libs/libssh2/src/channel.h @@ -1,6 +1,6 @@ #ifndef __LIBSSH2_CHANNEL_H #define __LIBSSH2_CHANNEL_H -/* Copyright (c) 2008-2010 by Daniel Stenberg +/* Copyright (C) Daniel Stenberg * * All rights reserved. * @@ -36,6 +36,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* @@ -138,4 +140,3 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel); int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); #endif /* __LIBSSH2_CHANNEL_H */ - diff --git a/libs/libssh2/src/comp.c b/libs/libssh2/src/comp.c index fec82a74ba..55ddb85a48 100644 --- a/libs/libssh2/src/comp.c +++ b/libs/libssh2/src/comp.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2007, 2019, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2010-2014, Daniel Stenberg <daniel@haxx.se> +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg <daniel@haxx.se> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,11 +34,15 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" + #ifdef LIBSSH2_HAVE_ZLIB -# include <zlib.h> +#include <zlib.h> +#undef compress /* dodge name clash with ZLIB macro */ #endif #include "comp.h" @@ -60,12 +64,12 @@ comp_method_none_comp(LIBSSH2_SESSION *session, size_t src_len, void **abstract) { - (void) session; - (void) abstract; - (void) dest; - (void) dest_len; - (void) src; - (void) src_len; + (void)session; + (void)abstract; + (void)dest; + (void)dest_len; + (void)src; + (void)src_len; return 0; } @@ -83,9 +87,9 @@ comp_method_none_decomp(LIBSSH2_SESSION * session, const unsigned char *src, size_t src_len, void **abstract) { - (void) session; - (void) payload_limit; - (void) abstract; + (void)session; + (void)payload_limit; + (void)abstract; *dest = (unsigned char *) src; *dest_len = src_len; return 0; @@ -162,8 +166,8 @@ comp_method_zlib_init(LIBSSH2_SESSION * session, int compr, if(status != Z_OK) { LIBSSH2_FREE(session, strm); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "unhandled zlib error %d", status)); return LIBSSH2_ERROR_COMPRESS; } *abstract = strm; @@ -188,11 +192,11 @@ comp_method_zlib_comp(LIBSSH2_SESSION *session, void **abstract) { z_stream *strm = *abstract; - int out_maxlen = *dest_len; + uInt out_maxlen = (uInt)*dest_len; int status; strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; + strm->avail_in = (uInt)src_len; strm->next_out = dest; strm->avail_out = out_maxlen; @@ -203,9 +207,9 @@ comp_method_zlib_comp(LIBSSH2_SESSION *session, return 0; } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "unhandled zlib compression error %d, avail_out", - status, strm->avail_out); + status, strm->avail_out)); return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compression failure"); } @@ -226,17 +230,17 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, /* A short-term alloc of a full data chunk is better than a series of reallocs */ char *out; - size_t out_maxlen = src_len; + size_t out_maxlen; if(src_len <= SIZE_MAX / 4) - out_maxlen = src_len * 4; + out_maxlen = (uInt)src_len * 4; else out_maxlen = payload_limit; /* If strm is null, then we have not yet been initialized. */ - if(strm == NULL) + if(!strm) return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS, - "decompression uninitialized");; + "decompression uninitialized"); /* In practice they never come smaller than this */ if(out_maxlen < 25) @@ -246,10 +250,11 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, out_maxlen = payload_limit; strm->next_in = (unsigned char *) src; - strm->avail_in = src_len; - strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen); + strm->avail_in = (uInt)src_len; + strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, + (uInt)out_maxlen); out = (char *) strm->next_out; - strm->avail_out = out_maxlen; + strm->avail_out = (uInt)out_maxlen; if(!strm->next_out) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate decompression buffer"); @@ -275,8 +280,8 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, else { /* error state */ LIBSSH2_FREE(session, out); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unhandled zlib error %d", status); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "unhandled zlib error %d", status)); return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, "decompression failure"); } @@ -298,7 +303,7 @@ comp_method_zlib_decomp(LIBSSH2_SESSION * session, } out = newout; strm->next_out = (unsigned char *) out + out_ofs; - strm->avail_out = out_maxlen - out_ofs; + strm->avail_out = (uInt)(out_maxlen - out_ofs); } *dest = (unsigned char *) out; diff --git a/libs/libssh2/src/comp.h b/libs/libssh2/src/comp.h index 8edc150299..cce113b2bc 100644 --- a/libs/libssh2/src/comp.h +++ b/libs/libssh2/src/comp.h @@ -1,7 +1,6 @@ #ifndef __LIBSSH2_COMP_H #define __LIBSSH2_COMP_H - -/* Copyright (C) 2009-2010 by Daniel Stenberg +/* Copyright (C) Daniel Stenberg * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -36,6 +35,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" diff --git a/libs/libssh2/src/crypt.c b/libs/libssh2/src/crypt.c index 8d493b4847..2fb661fd60 100644 --- a/libs/libssh2/src/crypt.c +++ b/libs/libssh2/src/crypt.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2009, 2010 Simon Josefsson <simon@josefsson.org> - * Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> +/* Copyright (C) Simon Josefsson <simon@josefsson.org> + * Copyright (C) Sara Golemon <sarag@libssh2.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,18 +34,29 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#ifdef LIBSSH2_CRYPT_NONE - +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_CRYPT_NONE_INSECURE) /* crypt_none_crypt - * Minimalist cipher: VERY secure *wink* + * Minimalist cipher: no encryption. DO NOT USE. + * + * The SSH2 Transport allows for unencrypted data transmission using + * the "none" cipher. Because this is such a huge security hole, it is + * typically disabled on SSH2 implementations and is disabled in libssh2 + * by default as well. + * + * Enabling this option will allow for "none" as a negotiable method, + * however it still requires that the method be advertised by the remote + * end and that no more-preferable methods are available. + * */ static int crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf, - void **abstract) + void **abstract, int firstlast) { /* Do nothing to the data! */ return 0; @@ -62,7 +73,7 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = { crypt_none_crypt, NULL }; -#endif /* LIBSSH2_CRYPT_NONE */ +#endif /* defined(LIBSSH2DEBUG) && defined(LIBSSH2_CRYPT_NONE_INSECURE) */ struct crypt_ctx { @@ -97,12 +108,12 @@ crypt_init(LIBSSH2_SESSION * session, static int crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block, - size_t blocksize, void **abstract) + size_t blocksize, void **abstract, int firstlast) { struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; (void) session; return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block, - blocksize); + blocksize, firstlast); } static int @@ -117,6 +128,34 @@ crypt_dtor(LIBSSH2_SESSION * session, void **abstract) return 0; } +#if LIBSSH2_AES_GCM +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_gcm = { + "aes256-gcm@openssh.com", + "", + 16, /* blocksize */ + 12, /* initial value length */ + 32, /* secret length -- 32*8 == 256bit */ + LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC | LIBSSH2_CRYPT_FLAG_PKTLEN_AAD, + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes256gcm +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_gcm = { + "aes128-gcm@openssh.com", + "", + 16, /* blocksize */ + 12, /* initial value length */ + 16, /* secret length -- 16*8 == 128bit */ + LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC | LIBSSH2_CRYPT_FLAG_PKTLEN_AAD, + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes128gcm +}; +#endif + #if LIBSSH2_AES_CTR static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { "aes128-ctr", @@ -158,7 +197,7 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = { }; #endif -#if LIBSSH2_AES +#if LIBSSH2_AES_CBC static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { "aes128-cbc", "DEK-Info: AES-128-CBC", @@ -212,7 +251,7 @@ static const LIBSSH2_CRYPT_METHOD &crypt_dtor, _libssh2_cipher_aes256 }; -#endif /* LIBSSH2_AES */ +#endif /* LIBSSH2_AES_CBC */ #if LIBSSH2_BLOWFISH static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { @@ -260,7 +299,8 @@ crypt_init_arcfour128(LIBSSH2_SESSION * session, size_t discard = 1536; for(; discard; discard -= 8) _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block, - method->blocksize); + method->blocksize, MIDDLE_BLOCK); + /* Not all middle, but here it doesn't matter */ } return rc; @@ -310,18 +350,24 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { }; #endif +/* These are the crypt methods that are available to be negotiated. Methods + towards the start are chosen in preference to ones further down the list. */ static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { +#if LIBSSH2_AES_GCM + &libssh2_crypt_method_aes256_gcm, + &libssh2_crypt_method_aes128_gcm, +#endif /* LIBSSH2_AES_GCM */ #if LIBSSH2_AES_CTR - &libssh2_crypt_method_aes128_ctr, - &libssh2_crypt_method_aes192_ctr, - &libssh2_crypt_method_aes256_ctr, -#endif /* LIBSSH2_AES */ -#if LIBSSH2_AES + &libssh2_crypt_method_aes256_ctr, + &libssh2_crypt_method_aes192_ctr, + &libssh2_crypt_method_aes128_ctr, +#endif /* LIBSSH2_AES_CTR */ +#if LIBSSH2_AES_CBC &libssh2_crypt_method_aes256_cbc, &libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */ &libssh2_crypt_method_aes192_cbc, &libssh2_crypt_method_aes128_cbc, -#endif /* LIBSSH2_AES */ +#endif /* LIBSSH2_AES_CBC */ #if LIBSSH2_BLOWFISH &libssh2_crypt_method_blowfish_cbc, #endif /* LIBSSH2_BLOWFISH */ @@ -335,7 +381,7 @@ static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { #if LIBSSH2_3DES &libssh2_crypt_method_3des_cbc, #endif /* LIBSSH2_DES */ -#ifdef LIBSSH2_CRYPT_NONE +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_CRYPT_NONE_INSECURE) &libssh2_crypt_method_none, #endif NULL diff --git a/libs/libssh2/src/crypto.c b/libs/libssh2/src/crypto.c new file mode 100644 index 0000000000..b3b1afcb13 --- /dev/null +++ b/libs/libssh2/src/crypto.c @@ -0,0 +1,19 @@ +/* Copyright (C) Viktor Szakats + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define LIBSSH2_CRYPTO_C +#include "libssh2_priv.h" + +#if defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL) +#include "openssl.c" +#elif defined(LIBSSH2_LIBGCRYPT) +#include "libgcrypt.c" +#elif defined(LIBSSH2_MBEDTLS) +#include "mbedtls.c" +#elif defined(LIBSSH2_OS400QC3) +#include "os400qc3.c" +#elif defined(LIBSSH2_WINCNG) +#include "wincng.c" +#endif diff --git a/libs/libssh2/src/crypto.h b/libs/libssh2/src/crypto.h index 8b1e004028..561cd96e2b 100644 --- a/libs/libssh2/src/crypto.h +++ b/libs/libssh2/src/crypto.h @@ -1,6 +1,9 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2010-2019 Daniel Stenberg +#ifndef __LIBSSH2_CRYPTO_H +#define __LIBSSH2_CRYPTO_H +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -34,28 +37,87 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef LIBSSH2_CRYPTO_H -#define LIBSSH2_CRYPTO_H -#ifdef LIBSSH2_OPENSSL +#if defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL) #include "openssl.h" +#elif defined(LIBSSH2_LIBGCRYPT) +#include "libgcrypt.h" +#elif defined(LIBSSH2_MBEDTLS) +#include "mbedtls.h" +#elif defined(LIBSSH2_OS400QC3) +#include "os400qc3.h" +#elif defined(LIBSSH2_WINCNG) +#include "wincng.h" +#else +#error "no cryptography backend selected" #endif -#ifdef LIBSSH2_LIBGCRYPT -#include "libgcrypt.h" +#ifdef LIBSSH2_NO_MD5 +#undef LIBSSH2_MD5 +#define LIBSSH2_MD5 0 #endif -#ifdef LIBSSH2_WINCNG -#include "wincng.h" +#ifdef LIBSSH2_NO_HMAC_RIPEMD +#undef LIBSSH2_HMAC_RIPEMD +#define LIBSSH2_HMAC_RIPEMD 0 #endif -#ifdef LIBSSH2_OS400QC3 -#include "os400qc3.h" +#ifdef LIBSSH2_NO_DSA +#undef LIBSSH2_DSA +#define LIBSSH2_DSA 0 #endif -#ifdef LIBSSH2_MBEDTLS -#include "mbedtls.h" +#ifdef LIBSSH2_NO_RSA +#undef LIBSSH2_RSA +#define LIBSSH2_RSA 0 +#endif + +#ifdef LIBSSH2_NO_RSA_SHA1 +#undef LIBSSH2_RSA_SHA1 +#define LIBSSH2_RSA_SHA1 0 +#endif + +#ifdef LIBSSH2_NO_ECDSA +#undef LIBSSH2_ECDSA +#define LIBSSH2_ECDSA 0 +#endif + +#ifdef LIBSSH2_NO_ED25519 +#undef LIBSSH2_ED25519 +#define LIBSSH2_ED25519 0 +#endif + +#ifdef LIBSSH2_NO_AES_CTR +#undef LIBSSH2_AES_CTR +#define LIBSSH2_AES_CTR 0 +#endif + +#ifdef LIBSSH2_NO_AES_CBC +#undef LIBSSH2_AES_CBC +#define LIBSSH2_AES_CBC 0 +#endif + +#ifdef LIBSSH2_NO_BLOWFISH +#undef LIBSSH2_BLOWFISH +#define LIBSSH2_BLOWFISH 0 +#endif + +#ifdef LIBSSH2_NO_RC4 +#undef LIBSSH2_RC4 +#define LIBSSH2_RC4 0 +#endif + +#ifdef LIBSSH2_NO_CAST +#undef LIBSSH2_CAST +#define LIBSSH2_CAST 0 +#endif + +#ifdef LIBSSH2_NO_3DES +#undef LIBSSH2_3DES +#define LIBSSH2_3DES 0 #endif #define LIBSSH2_ED25519_KEY_LEN 32 @@ -83,16 +145,31 @@ int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, const char *filename, unsigned const char *passphrase); +#if LIBSSH2_RSA_SHA1 int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len); + size_t sig_len, + const unsigned char *m, size_t m_len); int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, libssh2_rsa_ctx * rsactx, const unsigned char *hash, size_t hash_len, unsigned char **signature, size_t *signature_len); +#endif +#if LIBSSH2_RSA_SHA2 +int _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session, + libssh2_rsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len); +int _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsa, + size_t hash_len, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, size_t m_len); +#endif int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, const char *filedata, @@ -117,10 +194,10 @@ int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, unsigned const char *passphrase); int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, const unsigned char *sig, - const unsigned char *m, unsigned long m_len); + const unsigned char *m, size_t m_len); int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, - unsigned long hash_len, unsigned char *sig); + size_t hash_len, unsigned char *sig); int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, LIBSSH2_SESSION * session, const char *filedata, @@ -134,6 +211,7 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ecdsactx, const unsigned char *k, size_t k_len, libssh2_curve_type type); + int _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, LIBSSH2_SESSION * session, @@ -141,6 +219,16 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, unsigned const char *passphrase); int +_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase); + +int _libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, const unsigned char *r, size_t r_len, const unsigned char *s, size_t s_len, @@ -160,7 +248,7 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, int _libssh2_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ec_ctx, - const unsigned char *hash, unsigned long hash_len, + const unsigned char *hash, size_t hash_len, unsigned char **signature, size_t *signature_len); int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, @@ -169,8 +257,18 @@ int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, size_t filedata_len, unsigned const char *passphrase); +int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase); + libssh2_curve_type -_libssh2_ecdsa_key_get_curve_type(_libssh2_ec_key *key); +_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx); int _libssh2_ecdsa_curve_type_from_name(const char *name, @@ -181,8 +279,8 @@ _libssh2_ecdsa_curve_type_from_name(const char *name, #if LIBSSH2_ED25519 int -_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_ed25519_ctx **ctx, - uint8_t **out_public_key, uint8_t **out_private_key); +_libssh2_curve25519_new(LIBSSH2_SESSION *session, uint8_t **out_public_key, + uint8_t **out_private_key); int _libssh2_curve25519_gen_k(_libssh2_bn **k, @@ -199,10 +297,20 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx, const char *filename, const uint8_t *passphrase); int +_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filename, + const uint8_t *passphrase); + +int _libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx, LIBSSH2_SESSION *session, const unsigned char *raw_pub_key, - const uint8_t key_len); + const size_t key_len); int _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, @@ -216,6 +324,17 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx, size_t filedata_len, unsigned const char *passphrase); +int +_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase); + #endif /* LIBSSH2_ED25519 */ @@ -226,7 +345,8 @@ int _libssh2_cipher_init(_libssh2_cipher_ctx * h, int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blocksize); + int encrypt, unsigned char *block, size_t blocksize, + int firstlast); int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, unsigned char **method, @@ -245,4 +365,37 @@ int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, size_t privatekeydata_len, const char *passphrase); -#endif + +int _libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase); + +/** + * @function _libssh2_supported_key_sign_algorithms + * @abstract Returns supported algorithms used for upgrading public + * key signing RFC 8332 + * @discussion Based on the incoming key_method value, this function + * will return supported algorithms that can upgrade the key method + * @related _libssh2_key_sign_algorithm() + * @param key_method current key method, usually the default key sig method + * @param key_method_len length of the key method buffer + * @result comma separated list of supported upgrade options per RFC 8332, if + * there is no upgrade option return NULL + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len); + +#endif /* __LIBSSH2_CRYPTO_H */ diff --git a/libs/libssh2/src/global.c b/libs/libssh2/src/global.c index f88eb33da3..a8bc38078f 100644 --- a/libs/libssh2/src/global.c +++ b/libs/libssh2/src/global.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2010 Lars Nordin <Lars.Nordin@SDlabs.se> - * Copyright (C) 2010 Simon Josefsson <simon@josefsson.org> +/* Copyright (C) Lars Nordin <Lars.Nordin@SDlabs.se> + * Copyright (C) Simon Josefsson <simon@josefsson.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -62,7 +64,8 @@ libssh2_exit(void) _libssh2_initialized--; - if(!(_libssh2_init_flags & LIBSSH2_INIT_NO_CRYPTO)) { + if(_libssh2_initialized == 0 && + !(_libssh2_init_flags & LIBSSH2_INIT_NO_CRYPTO)) { libssh2_crypto_exit(); } @@ -73,5 +76,5 @@ void _libssh2_init_if_needed(void) { if(_libssh2_initialized == 0) - (void)libssh2_init (0); + (void)libssh2_init(0); } diff --git a/libs/libssh2/src/hostkey.c b/libs/libssh2/src/hostkey.c index a8bd42b7a0..56eee369f5 100644 --- a/libs/libssh2/src/hostkey.c +++ b/libs/libssh2/src/hostkey.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2009-2019 by Daniel Stenberg +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,10 +34,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include "misc.h" /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H @@ -64,8 +65,8 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, void **abstract) { libssh2_rsa_ctx *rsactx; - unsigned char *e, *n; - size_t e_len, n_len; + unsigned char *e, *n, *type; + size_t e_len, n_len, type_len; struct string_buf buf; if(*abstract) { @@ -74,8 +75,8 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, } if(hostkey_data_len < 19) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } @@ -83,8 +84,31 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, buf.dataptr = buf.data; buf.len = hostkey_data_len; - if(_libssh2_match_string(&buf, "ssh-rsa")) + if(_libssh2_get_string(&buf, &type, &type_len)) { + return -1; + } + + /* we accept one of 3 header types */ +#if LIBSSH2_RSA_SHA1 + if(type_len == 7 && strncmp("ssh-rsa", (char *)type, 7) == 0) { + /* ssh-rsa */ + } + else +#endif +#if LIBSSH2_RSA_SHA2 + if(type_len == 12 && strncmp("rsa-sha2-256", (char *)type, 12) == 0) { + /* rsa-sha2-256 */ + } + else if(type_len == 12 && strncmp("rsa-sha2-512", (char *)type, 12) == 0) { + /* rsa-sha2-512 */ + } + else +#endif + { + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "unexpected rsa type: %.*s", type_len, type)); return -1; + } if(_libssh2_get_string(&buf, &e, &e_len)) return -1; @@ -92,8 +116,14 @@ hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, if(_libssh2_get_string(&buf, &n, &n_len)) return -1; - if(_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) { + if(!_libssh2_eob(&buf)) + return -1; + + if(_libssh2_rsa_new(&rsactx, + e, (unsigned long)e_len, + n, (unsigned long)n_len, + NULL, 0, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, NULL, 0)) { return -1; } @@ -163,6 +193,7 @@ hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session, return 0; } +#if LIBSSH2_RSA_SHA1 /* * hostkey_method_ssh_rsa_sign * @@ -176,7 +207,7 @@ hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session, size_t m_len, void **abstract) { libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; + (void)session; /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */ if(sig_len < 15) @@ -211,7 +242,7 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, unsigned char hash[SHA_DIGEST_LENGTH]; libssh2_sha1_ctx ctx; - libssh2_sha1_init(&ctx); + (void)libssh2_sha1_init(&ctx); for(i = 0; i < veccount; i++) { libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); } @@ -226,6 +257,151 @@ hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, return 0; #endif } +#endif + +/* + * hostkey_method_ssh_rsa_sha2_256_sig_verify + * + * Verify signature created by remote + */ +#if LIBSSH2_RSA_SHA2 + +static int +hostkey_method_ssh_rsa_sha2_256_sig_verify(LIBSSH2_SESSION * session, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len, void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + (void)session; + + /* Skip past keyname_len(4) + keyname(12){"rsa-sha2-256"} + + signature_len(4) */ + if(sig_len < 20) + return -1; + + sig += 20; + sig_len -= 20; + return _libssh2_rsa_sha2_verify(rsactx, SHA256_DIGEST_LENGTH, sig, sig_len, + m, m_len); +} + +/* + * hostkey_method_ssh_rsa_sha2_256_signv + * + * Construct a signature from an array of vectors + */ + +static int +hostkey_method_ssh_rsa_sha2_256_signv(LIBSSH2_SESSION * session, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + +#ifdef _libssh2_rsa_sha2_256_signv + return _libssh2_rsa_sha2_256_signv(session, signature, signature_len, + veccount, datavec, rsactx); +#else + int ret; + int i; + unsigned char hash[SHA256_DIGEST_LENGTH]; + libssh2_sha256_ctx ctx; + + if(!libssh2_sha256_init(&ctx)) { + return -1; + } + for(i = 0; i < veccount; i++) { + libssh2_sha256_update(ctx, datavec[i].iov_base, datavec[i].iov_len); + } + libssh2_sha256_final(ctx, hash); + + ret = _libssh2_rsa_sha2_sign(session, rsactx, hash, SHA256_DIGEST_LENGTH, + signature, signature_len); + if(ret) { + return -1; + } + + return 0; +#endif +} + +/* + * hostkey_method_ssh_rsa_sha2_512_sig_verify + * + * Verify signature created by remote + */ + +static int +hostkey_method_ssh_rsa_sha2_512_sig_verify(LIBSSH2_SESSION * session, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len, void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + (void)session; + + /* Skip past keyname_len(4) + keyname(12){"rsa-sha2-512"} + + signature_len(4) */ + if(sig_len < 20) + return -1; + + sig += 20; + sig_len -= 20; + return _libssh2_rsa_sha2_verify(rsactx, SHA512_DIGEST_LENGTH, sig, + sig_len, m, m_len); +} + + +/* + * hostkey_method_ssh_rsa_sha2_512_signv + * + * Construct a signature from an array of vectors + */ +static int +hostkey_method_ssh_rsa_sha2_512_signv(LIBSSH2_SESSION * session, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + +#ifdef _libssh2_rsa_sha2_512_signv + return _libssh2_rsa_sha2_512_signv(session, signature, signature_len, + veccount, datavec, rsactx); +#else + int ret; + int i; + unsigned char hash[SHA512_DIGEST_LENGTH]; + libssh2_sha512_ctx ctx; + + if(!libssh2_sha512_init(&ctx)) { + return -1; + } + for(i = 0; i < veccount; i++) { + libssh2_sha512_update(ctx, datavec[i].iov_base, datavec[i].iov_len); + } + libssh2_sha512_final(ctx, hash); + + ret = _libssh2_rsa_sha2_sign(session, rsactx, hash, SHA512_DIGEST_LENGTH, + signature, signature_len); + if(ret) { + return -1; + } + + return 0; +#endif +} + +#endif /* LIBSSH2_RSA_SHA2 */ + /* * hostkey_method_ssh_rsa_dtor @@ -236,7 +412,7 @@ static int hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); - (void) session; + (void)session; _libssh2_rsa_free(rsactx); @@ -245,13 +421,11 @@ hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract) return 0; } -#ifdef OPENSSL_NO_MD5 -#define MD5_DIGEST_LENGTH 16 -#endif +#if LIBSSH2_RSA_SHA1 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { "ssh-rsa", - MD5_DIGEST_LENGTH, + SHA_DIGEST_LENGTH, hostkey_method_ssh_rsa_init, hostkey_method_ssh_rsa_initPEM, hostkey_method_ssh_rsa_initPEMFromMemory, @@ -260,6 +434,53 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { NULL, /* encrypt */ hostkey_method_ssh_rsa_dtor, }; + +#endif /* LIBSSH2_RSA_SHA1 */ + +#if LIBSSH2_RSA_SHA2 + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_256 = { + "rsa-sha2-256", + SHA256_DIGEST_LENGTH, + hostkey_method_ssh_rsa_init, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + hostkey_method_ssh_rsa_sha2_256_sig_verify, + hostkey_method_ssh_rsa_sha2_256_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_sha2_512 = { + "rsa-sha2-512", + SHA512_DIGEST_LENGTH, + hostkey_method_ssh_rsa_init, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + hostkey_method_ssh_rsa_sha2_512_sig_verify, + hostkey_method_ssh_rsa_sha2_512_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +#endif /* LIBSSH2_RSA_SHA2 */ + +#if LIBSSH2_RSA_SHA1 + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa_cert = { + "ssh-rsa-cert-v01@openssh.com", + SHA_DIGEST_LENGTH, + NULL, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_initPEMFromMemory, + NULL, + hostkey_method_ssh_rsa_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; + +#endif /* LIBSSH2_RSA_SHA1 */ + #endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA @@ -292,8 +513,8 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, } if(hostkey_data_len < 27) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } @@ -305,7 +526,7 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, return -1; if(_libssh2_get_string(&buf, &p, &p_len)) - return -1; + return -1; if(_libssh2_get_string(&buf, &q, &q_len)) return -1; @@ -316,8 +537,15 @@ hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, if(_libssh2_get_string(&buf, &y, &y_len)) return -1; - if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len, - g, g_len, y, y_len, NULL, 0)) { + if(!_libssh2_eob(&buf)) + return -1; + + if(_libssh2_dsa_new(&dsactx, + p, (unsigned long)p_len, + q, (unsigned long)q_len, + g, (unsigned long)g_len, + y, (unsigned long)y_len, + NULL, 0)) { return -1; } @@ -438,7 +666,7 @@ hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session, *signature_len = 2 * SHA_DIGEST_LENGTH; - libssh2_sha1_init(&ctx); + (void)libssh2_sha1_init(&ctx); for(i = 0; i < veccount; i++) { libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); } @@ -461,7 +689,7 @@ static int hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); - (void) session; + (void)session; _libssh2_dsa_free(dsactx); @@ -472,7 +700,7 @@ hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract) static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = { "ssh-dss", - MD5_DIGEST_LENGTH, + SHA_DIGEST_LENGTH, hostkey_method_ssh_dss_init, hostkey_method_ssh_dss_initPEM, hostkey_method_ssh_dss_initPEMFromMemory, @@ -500,9 +728,9 @@ hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, - const unsigned char *hostkey_data, - size_t hostkey_data_len, - void **abstract) + const unsigned char *hostkey_data, + size_t hostkey_data_len, + void **abstract) { libssh2_ecdsa_ctx *ecdsactx = NULL; unsigned char *type_str, *domain, *public_key; @@ -510,14 +738,14 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, libssh2_curve_type type; struct string_buf buf; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ecdsa_dtor(session, abstract); *abstract = NULL; } if(hostkey_data_len < 39) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } @@ -561,11 +789,14 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, if(_libssh2_get_string(&buf, &public_key, &key_len)) return -1; + if(!_libssh2_eob(&buf)) + return -1; + if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, public_key, key_len, type)) return -1; - if(abstract != NULL) + if(abstract) *abstract = ecdsactx; return 0; @@ -578,14 +809,14 @@ hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) + const char *privkeyfile, + unsigned const char *passphrase, + void **abstract) { libssh2_ecdsa_ctx *ec_ctx = NULL; int ret; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ecdsa_dtor(session, abstract); *abstract = NULL; } @@ -593,7 +824,7 @@ hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session, ret = _libssh2_ecdsa_new_private(&ec_ctx, session, privkeyfile, passphrase); - if(abstract != NULL) + if(abstract) *abstract = ec_ctx; return ret; @@ -606,15 +837,15 @@ hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session, - const char *privkeyfiledata, - size_t privkeyfiledata_len, - unsigned const char *passphrase, - void **abstract) + const char *privkeyfiledata, + size_t privkeyfiledata_len, + unsigned const char *passphrase, + void **abstract) { libssh2_ecdsa_ctx *ec_ctx = NULL; int ret; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ecdsa_dtor(session, abstract); *abstract = NULL; } @@ -627,7 +858,7 @@ hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session, return -1; } - if(abstract != NULL) + if(abstract) *abstract = ec_ctx; return 0; @@ -647,11 +878,11 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, { unsigned char *r, *s, *name; size_t r_len, s_len, name_len; - unsigned int len; + uint32_t len; struct string_buf buf; libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract); - (void) session; + (void)session; if(sig_len < 35) return -1; @@ -662,14 +893,14 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, buf.dataptr = buf.data; buf.len = sig_len; - if(_libssh2_get_string(&buf, &name, &name_len) || name_len != 19) + if(_libssh2_get_string(&buf, &name, &name_len) || name_len != 19) return -1; if(_libssh2_get_u32(&buf, &len) != 0 || len < 8) return -1; if(_libssh2_get_string(&buf, &r, &r_len)) - return -1; + return -1; if(_libssh2_get_string(&buf, &s, &s_len)) return -1; @@ -679,11 +910,11 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, #define LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(digest_type) \ - { \ + do { \ unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ libssh2_sha##digest_type##_ctx ctx; \ int i; \ - libssh2_sha##digest_type##_init(&ctx); \ + (void)libssh2_sha##digest_type##_init(&ctx); \ for(i = 0; i < veccount; i++) { \ libssh2_sha##digest_type##_update(ctx, datavec[i].iov_base, \ datavec[i].iov_len); \ @@ -692,7 +923,7 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, ret = _libssh2_ecdsa_sign(session, ec_ctx, hash, \ SHA##digest_type##_DIGEST_LENGTH, \ signature, signature_len); \ - } + } while(0) /* @@ -709,7 +940,7 @@ hostkey_method_ssh_ecdsa_signv(LIBSSH2_SESSION * session, void **abstract) { libssh2_ecdsa_ctx *ec_ctx = (libssh2_ecdsa_ctx *) (*abstract); - libssh2_curve_type type = _libssh2_ecdsa_key_get_curve_type(ec_ctx); + libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ec_ctx); int ret = 0; if(type == LIBSSH2_EC_CURVE_NISTP256) { @@ -737,9 +968,9 @@ static int hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_ecdsa_ctx *keyctx = (libssh2_ecdsa_ctx *) (*abstract); - (void) session; + (void)session; - if(keyctx != NULL) + if(keyctx) _libssh2_ecdsa_free(keyctx); *abstract = NULL; @@ -783,6 +1014,42 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp521 = { hostkey_method_ssh_ecdsa_dtor, }; +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp256_cert = { + "ecdsa-sha2-nistp256-cert-v01@openssh.com", + SHA256_DIGEST_LENGTH, + NULL, + hostkey_method_ssh_ecdsa_initPEM, + hostkey_method_ssh_ecdsa_initPEMFromMemory, + NULL, + hostkey_method_ssh_ecdsa_signv, + NULL, /* encrypt */ + hostkey_method_ssh_ecdsa_dtor, +}; + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp384_cert = { + "ecdsa-sha2-nistp384-cert-v01@openssh.com", + SHA384_DIGEST_LENGTH, + NULL, + hostkey_method_ssh_ecdsa_initPEM, + hostkey_method_ssh_ecdsa_initPEMFromMemory, + NULL, + hostkey_method_ssh_ecdsa_signv, + NULL, /* encrypt */ + hostkey_method_ssh_ecdsa_dtor, +}; + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp521_cert = { + "ecdsa-sha2-nistp521-cert-v01@openssh.com", + SHA512_DIGEST_LENGTH, + NULL, + hostkey_method_ssh_ecdsa_initPEM, + hostkey_method_ssh_ecdsa_initPEMFromMemory, + NULL, + hostkey_method_ssh_ecdsa_signv, + NULL, /* encrypt */ + hostkey_method_ssh_ecdsa_dtor, +}; + #endif /* LIBSSH2_ECDSA */ #if LIBSSH2_ED25519 @@ -805,9 +1072,10 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, size_t hostkey_data_len, void **abstract) { - const unsigned char *s; - unsigned long len, key_len; + size_t key_len; + unsigned char *key; libssh2_ed25519_ctx *ctx = NULL; + struct string_buf buf; if(*abstract) { hostkey_method_ssh_ed25519_dtor(session, abstract); @@ -815,26 +1083,26 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, } if(hostkey_data_len < 19) { - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, - "host key length too short"); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, + "host key length too short")); return -1; } - s = hostkey_data; - len = _libssh2_ntohu32(s); - s += 4; + buf.data = (unsigned char *)hostkey_data; + buf.dataptr = buf.data; + buf.len = hostkey_data_len; - if(len != 11 || strncmp((char *) s, "ssh-ed25519", 11) != 0) { + if(_libssh2_match_string(&buf, "ssh-ed25519")) return -1; - } - - s += 11; /* public key */ - key_len = _libssh2_ntohu32(s); - s += 4; + if(_libssh2_get_string(&buf, &key, &key_len)) + return -1; + + if(!_libssh2_eob(&buf)) + return -1; - if(_libssh2_ed25519_new_public(&ctx, session, s, key_len) != 0) { + if(_libssh2_ed25519_new_public(&ctx, session, key, key_len) != 0) { return -1; } @@ -850,9 +1118,9 @@ hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ed25519_initPEM(LIBSSH2_SESSION * session, - const char *privkeyfile, - unsigned const char *passphrase, - void **abstract) + const char *privkeyfile, + unsigned const char *passphrase, + void **abstract) { libssh2_ed25519_ctx *ec_ctx = NULL; int ret; @@ -888,7 +1156,7 @@ hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session, libssh2_ed25519_ctx *ed_ctx = NULL; int ret; - if(abstract != NULL && *abstract) { + if(abstract && *abstract) { hostkey_method_ssh_ed25519_dtor(session, abstract); *abstract = NULL; } @@ -901,7 +1169,7 @@ hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session, return -1; } - if(abstract != NULL) + if(abstract) *abstract = ed_ctx; return 0; @@ -920,7 +1188,7 @@ hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session, size_t m_len, void **abstract) { libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract); - (void) session; + (void)session; if(sig_len < 19) return -1; @@ -943,11 +1211,11 @@ hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session, */ static int hostkey_method_ssh_ed25519_signv(LIBSSH2_SESSION * session, - unsigned char **signature, - size_t *signature_len, - int veccount, - const struct iovec datavec[], - void **abstract) + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) { libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract); @@ -969,7 +1237,7 @@ static int hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session, void **abstract) { libssh2_ed25519_ctx *keyctx = (libssh2_ed25519_ctx*) (*abstract); - (void) session; + (void)session; if(keyctx) _libssh2_ed25519_free(keyctx); @@ -991,7 +1259,19 @@ static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519 = { hostkey_method_ssh_ed25519_dtor, }; -#endif /*LIBSSH2_ED25519*/ +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519_cert = { + "ssh-ed25519-cert-v01@openssh.com", + SHA256_DIGEST_LENGTH, + hostkey_method_ssh_ed25519_init, + hostkey_method_ssh_ed25519_initPEM, + hostkey_method_ssh_ed25519_initPEMFromMemory, + hostkey_method_ssh_ed25519_sig_verify, + hostkey_method_ssh_ed25519_signv, + NULL, /* encrypt */ + hostkey_method_ssh_ed25519_dtor, +}; + +#endif /* LIBSSH2_ED25519 */ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { @@ -999,12 +1279,23 @@ static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { &hostkey_method_ecdsa_ssh_nistp256, &hostkey_method_ecdsa_ssh_nistp384, &hostkey_method_ecdsa_ssh_nistp521, + &hostkey_method_ecdsa_ssh_nistp256_cert, + &hostkey_method_ecdsa_ssh_nistp384_cert, + &hostkey_method_ecdsa_ssh_nistp521_cert, #endif #if LIBSSH2_ED25519 &hostkey_method_ssh_ed25519, + &hostkey_method_ssh_ed25519_cert, #endif #if LIBSSH2_RSA +#if LIBSSH2_RSA_SHA2 + &hostkey_method_ssh_rsa_sha2_512, + &hostkey_method_ssh_rsa_sha2_256, +#endif /* LIBSSH2_RSA_SHA2 */ +#if LIBSSH2_RSA_SHA1 &hostkey_method_ssh_rsa, + &hostkey_method_ssh_rsa_cert, +#endif /* LIBSSH2_RSA_SHA1 */ #endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA &hostkey_method_ssh_dss, @@ -1107,7 +1398,7 @@ static int hostkey_type(const unsigned char *hostkey, size_t len) } /* - * libssh2_session_hostkey() + * libssh2_session_hostkey * * Returns the server key and length. * diff --git a/libs/libssh2/src/keepalive.c b/libs/libssh2/src/keepalive.c index 2151b17100..54fddb060f 100644 --- a/libs/libssh2/src/keepalive.c +++ b/libs/libssh2/src/keepalive.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2010 Simon Josefsson - * Author: Simon Josefsson +/* Copyright (C) Simon Josefsson + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -34,6 +34,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -42,9 +43,9 @@ /* Keep-alive stuff. */ LIBSSH2_API void -libssh2_keepalive_config (LIBSSH2_SESSION *session, - int want_reply, - unsigned interval) +libssh2_keepalive_config(LIBSSH2_SESSION *session, + int want_reply, + unsigned interval) { if(interval == 1) session->keepalive_interval = 2; @@ -54,8 +55,8 @@ libssh2_keepalive_config (LIBSSH2_SESSION *session, } LIBSSH2_API int -libssh2_keepalive_send (LIBSSH2_SESSION *session, - int *seconds_to_next) +libssh2_keepalive_send(LIBSSH2_SESSION *session, + int *seconds_to_next) { time_t now; diff --git a/libs/libssh2/src/kex.c b/libs/libssh2/src/kex.c index cb1663937d..8972d44bb3 100644 --- a/libs/libssh2/src/kex.c +++ b/libs/libssh2/src/kex.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2010-2019, Daniel Stenberg <daniel@haxx.se> +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg <daniel@haxx.se> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -42,792 +44,201 @@ #include "comp.h" #include "mac.h" +#include <assert.h> + +/* define SHA1_DIGEST_LENGTH for the macro below */ +#ifndef SHA1_DIGEST_LENGTH +#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH +#endif + /* TODO: Switch this to an inline and handle alloc() failures */ /* Helper macro called from kex_method_diffie_hellman_group1_sha1_key_exchange */ -#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \ - { \ - libssh2_sha1_ctx hash; \ - unsigned long len = 0; \ - if(!(value)) { \ - value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \ - } \ - if(value) \ - while(len < (unsigned long)reqlen) { \ - libssh2_sha1_init(&hash); \ - libssh2_sha1_update(hash, exchange_state->k_value, \ - exchange_state->k_value_len); \ - libssh2_sha1_update(hash, exchange_state->h_sig_comp, \ - SHA_DIGEST_LENGTH); \ - if(len > 0) { \ - libssh2_sha1_update(hash, value, len); \ - } \ - else { \ - libssh2_sha1_update(hash, (version), 1); \ - libssh2_sha1_update(hash, session->session_id, \ - session->session_id_len); \ - } \ - libssh2_sha1_final(hash, (value) + len); \ - len += SHA_DIGEST_LENGTH; \ - } \ - } \ - - -#define LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(value, reqlen, version) \ - { \ - if(type == LIBSSH2_EC_CURVE_NISTP256) { \ + +#define LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(value, reqlen, version) \ + do { \ + if(type == LIBSSH2_EC_CURVE_NISTP256) { \ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, value, reqlen, version); \ - } \ - else if(type == LIBSSH2_EC_CURVE_NISTP384) { \ + } \ + else if(type == LIBSSH2_EC_CURVE_NISTP384) { \ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(384, value, reqlen, version); \ - } \ - else if(type == LIBSSH2_EC_CURVE_NISTP521) { \ + } \ + else if(type == LIBSSH2_EC_CURVE_NISTP521) { \ LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(512, value, reqlen, version); \ - } \ - } \ - - -#define LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(digest_type, value, \ - reqlen, version) \ -{ \ - libssh2_sha##digest_type##_ctx hash; \ - unsigned long len = 0; \ - if(!(value)) { \ - value = LIBSSH2_ALLOC(session, \ - reqlen + SHA##digest_type##_DIGEST_LENGTH); \ - } \ - if(value) \ - while(len < (unsigned long)reqlen) { \ - libssh2_sha##digest_type##_init(&hash); \ - libssh2_sha##digest_type##_update(hash, \ - exchange_state->k_value, \ + } \ + } while(0) + +#define LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(digest_type, value, \ + reqlen, version) \ +do { \ + libssh2_sha##digest_type##_ctx hash; \ + size_t len = 0; \ + if(!(value)) { \ + value = LIBSSH2_ALLOC(session, \ + reqlen + SHA##digest_type##_DIGEST_LENGTH); \ + } \ + if(value) \ + while(len < (size_t)reqlen) { \ + (void)libssh2_sha##digest_type##_init(&hash); \ + libssh2_sha##digest_type##_update(hash, \ + exchange_state->k_value, \ exchange_state->k_value_len); \ - libssh2_sha##digest_type##_update(hash, \ - exchange_state->h_sig_comp, \ + libssh2_sha##digest_type##_update(hash, \ + exchange_state->h_sig_comp, \ SHA##digest_type##_DIGEST_LENGTH); \ - if(len > 0) { \ - libssh2_sha##digest_type##_update(hash, value, len); \ - } \ - else { \ - libssh2_sha##digest_type##_update(hash, (version), 1); \ - libssh2_sha##digest_type##_update(hash, session->session_id, \ + if(len > 0) { \ + libssh2_sha##digest_type##_update(hash, value, len); \ + } \ + else { \ + libssh2_sha##digest_type##_update(hash, (version), 1); \ + libssh2_sha##digest_type##_update(hash, session->session_id,\ session->session_id_len); \ - } \ - libssh2_sha##digest_type##_final(hash, (value) + len); \ - len += SHA##digest_type##_DIGEST_LENGTH; \ - } \ -} - - -/* - * diffie_hellman_sha1 - * - * Diffie Hellman Key Exchange, Group Agnostic + } \ + libssh2_sha##digest_type##_final(hash, (value) + len); \ + len += SHA##digest_type##_DIGEST_LENGTH; \ + } \ +} while(0) + +/*! + * @note The following are wrapper functions used by diffie_hellman_sha_algo(). + * TODO: Switch backend SHA macros to functions to allow function pointers + * @discussion Ideally these would be function pointers but the backend macros + * don't allow it so we have to wrap them up in helper functions */ -static int diffie_hellman_sha1(LIBSSH2_SESSION *session, - _libssh2_bn *g, - _libssh2_bn *p, - int group_order, - unsigned char packet_type_init, - unsigned char packet_type_reply, - unsigned char *midhash, - unsigned long midhash_len, - kmdhgGPshakex_state_t *exchange_state) -{ - int ret = 0; - int rc; - libssh2_sha1_ctx exchange_hash_ctx; - - if(exchange_state->state == libssh2_NB_state_idle) { - /* Setup initial values */ - exchange_state->e_packet = NULL; - exchange_state->s_packet = NULL; - exchange_state->k_value = NULL; - exchange_state->ctx = _libssh2_bn_ctx_new(); - libssh2_dh_init(&exchange_state->x); - exchange_state->e = _libssh2_bn_init(); /* g^x mod p */ - exchange_state->f = _libssh2_bn_init_from_bin(); /* g^(Random from - server) mod p */ - exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod - p */ - - /* Zero the whole thing out */ - memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t)); - - /* Generate x and e */ - rc = libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p, - group_order, exchange_state->ctx); - if(rc) - goto clean_exit; - - /* Send KEX init */ - /* packet_type(1) + String Length(4) + leading 0(1) */ - exchange_state->e_packet_len = - _libssh2_bn_bytes(exchange_state->e) + 6; - if(_libssh2_bn_bits(exchange_state->e) % 8) { - /* Leading 00 not needed */ - exchange_state->e_packet_len--; - } - - exchange_state->e_packet = - LIBSSH2_ALLOC(session, exchange_state->e_packet_len); - if(!exchange_state->e_packet) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Out of memory error"); - goto clean_exit; - } - exchange_state->e_packet[0] = packet_type_init; - _libssh2_htonu32(exchange_state->e_packet + 1, - exchange_state->e_packet_len - 5); - if(_libssh2_bn_bits(exchange_state->e) % 8) { - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 5); - } - else { - exchange_state->e_packet[5] = 0; - _libssh2_bn_to_bin(exchange_state->e, - exchange_state->e_packet + 6); - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", - (int) packet_type_init); - exchange_state->state = libssh2_NB_state_created; +static void _libssh2_sha_algo_ctx_init(int sha_algo, void *ctx) +{ + if(sha_algo == 512) { + (void)libssh2_sha512_init((libssh2_sha512_ctx*)ctx); } - - if(exchange_state->state == libssh2_NB_state_created) { - rc = _libssh2_transport_send(session, exchange_state->e_packet, - exchange_state->e_packet_len, - NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send KEX init message"); - goto clean_exit; - } - exchange_state->state = libssh2_NB_state_sent; + else if(sha_algo == 384) { + (void)libssh2_sha384_init((libssh2_sha384_ctx*)ctx); } - - if(exchange_state->state == libssh2_NB_state_sent) { - if(session->burn_optimistic_kexinit) { - /* The first KEX packet to come along will be the guess initially - * sent by the server. That guess turned out to be wrong so we - * need to silently ignore it */ - int burn_type; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Waiting for badly guessed KEX packet " - "(to be ignored)"); - burn_type = - _libssh2_packet_burn(session, &exchange_state->burn_state); - if(burn_type == LIBSSH2_ERROR_EAGAIN) { - return burn_type; - } - else if(burn_type <= 0) { - /* Failed to receive a packet */ - ret = burn_type; - goto clean_exit; - } - session->burn_optimistic_kexinit = 0; - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Burnt packet of type: %02x", - (unsigned int) burn_type); - } - - exchange_state->state = libssh2_NB_state_sent1; + else if(sha_algo == 256) { + (void)libssh2_sha256_init((libssh2_sha256_ctx*)ctx); } + else if(sha_algo == 1) { + (void)libssh2_sha1_init((libssh2_sha1_ctx*)ctx); + } + else { + assert(0); + } +} - if(exchange_state->state == libssh2_NB_state_sent1) { - /* Wait for KEX reply */ - struct string_buf buf; - size_t host_key_len; - - rc = _libssh2_packet_require(session, packet_type_reply, - &exchange_state->s_packet, - &exchange_state->s_packet_len, 0, NULL, - 0, &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - if(rc) { - ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, - "Timed out waiting for KEX reply"); - goto clean_exit; - } - - /* Parse KEXDH_REPLY */ - if(exchange_state->s_packet_len < 5) { - ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet length"); - goto clean_exit; - } - - buf.data = exchange_state->s_packet; - buf.len = exchange_state->s_packet_len; - buf.dataptr = buf.data; - buf.dataptr++; /* advance past type */ - - if(session->server_hostkey) - LIBSSH2_FREE(session, session->server_hostkey); - - if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), - &host_key_len)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Could not copy host key"); - goto clean_exit; - } - - session->server_hostkey_len = (uint32_t)host_key_len; - -#if LIBSSH2_MD5 - { - libssh2_md5_ctx fingerprint_ctx; - - if(libssh2_md5_init(&fingerprint_ctx)) { - libssh2_md5_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_md5_final(fingerprint_ctx, - session->server_hostkey_md5); - session->server_hostkey_md5_valid = TRUE; - } - else { - session->server_hostkey_md5_valid = FALSE; - } - } -#ifdef LIBSSH2DEBUG - { - char fingerprint[50], *fprint = fingerprint; - int i; - for(i = 0; i < 16; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ -#endif /* ! LIBSSH2_MD5 */ - - { - libssh2_sha1_ctx fingerprint_ctx; - - if(libssh2_sha1_init(&fingerprint_ctx)) { - libssh2_sha1_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha1_final(fingerprint_ctx, - session->server_hostkey_sha1); - session->server_hostkey_sha1_valid = TRUE; - } - else { - session->server_hostkey_sha1_valid = FALSE; - } - } +static void _libssh2_sha_algo_ctx_update(int sha_algo, void *ctx, + void *data, size_t len) +{ + if(sha_algo == 512) { + libssh2_sha512_ctx *_ctx = (libssh2_sha512_ctx*)ctx; + libssh2_sha512_update(*_ctx, data, len); + } + else if(sha_algo == 384) { + libssh2_sha384_ctx *_ctx = (libssh2_sha384_ctx*)ctx; + libssh2_sha384_update(*_ctx, data, len); + } + else if(sha_algo == 256) { + libssh2_sha256_ctx *_ctx = (libssh2_sha256_ctx*)ctx; + libssh2_sha256_update(*_ctx, data, len); + } + else if(sha_algo == 1) { + libssh2_sha1_ctx *_ctx = (libssh2_sha1_ctx*)ctx; + libssh2_sha1_update(*_ctx, data, len); + } + else { #ifdef LIBSSH2DEBUG - { - char fingerprint[64], *fprint = fingerprint; - int i; - - for(i = 0; i < 20; i++, fprint += 3) { - snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); - } - *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); - } -#endif /* LIBSSH2DEBUG */ - - { - libssh2_sha256_ctx fingerprint_ctx; + assert(0); +#endif + } +} - if(libssh2_sha256_init(&fingerprint_ctx)) { - libssh2_sha256_update(fingerprint_ctx, session->server_hostkey, - session->server_hostkey_len); - libssh2_sha256_final(fingerprint_ctx, - session->server_hostkey_sha256); - session->server_hostkey_sha256_valid = TRUE; - } - else { - session->server_hostkey_sha256_valid = FALSE; - } - } +static void _libssh2_sha_algo_ctx_final(int sha_algo, void *ctx, + void *hash) +{ + if(sha_algo == 512) { + libssh2_sha512_ctx *_ctx = (libssh2_sha512_ctx*)ctx; + libssh2_sha512_final(*_ctx, hash); + } + else if(sha_algo == 384) { + libssh2_sha384_ctx *_ctx = (libssh2_sha384_ctx*)ctx; + libssh2_sha384_final(*_ctx, hash); + } + else if(sha_algo == 256) { + libssh2_sha256_ctx *_ctx = (libssh2_sha256_ctx*)ctx; + libssh2_sha256_final(*_ctx, hash); + } + else if(sha_algo == 1) { + libssh2_sha1_ctx *_ctx = (libssh2_sha1_ctx*)ctx; + libssh2_sha1_final(*_ctx, hash); + } + else { #ifdef LIBSSH2DEBUG - { - char *base64Fingerprint = NULL; - _libssh2_base64_encode(session, - (const char *) - session->server_hostkey_sha256, - SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA256 Fingerprint: %s", - base64Fingerprint); - LIBSSH2_FREE(session, base64Fingerprint); - } - } -#endif /* LIBSSH2DEBUG */ - - - if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); - goto clean_exit; - } - - if(_libssh2_get_string(&buf, &(exchange_state->f_value), - &(exchange_state->f_value_len))) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get f value"); - goto clean_exit; - } - - _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len, - exchange_state->f_value); - - if(_libssh2_get_string(&buf, &(exchange_state->h_sig), - &(exchange_state->h_sig_len))) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get h sig"); - goto clean_exit; - } - - /* Compute the shared secret */ - libssh2_dh_secret(&exchange_state->x, exchange_state->k, - exchange_state->f, p, exchange_state->ctx); - exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5; - if(_libssh2_bn_bits(exchange_state->k) % 8) { - /* don't need leading 00 */ - exchange_state->k_value_len--; - } - exchange_state->k_value = - LIBSSH2_ALLOC(session, exchange_state->k_value_len); - if(!exchange_state->k_value) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); - goto clean_exit; - } - _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); - if(_libssh2_bn_bits(exchange_state->k) % 8) { - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); - } - else { - exchange_state->k_value[4] = 0; - _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); - } - - exchange_state->exchange_hash = (void *)&exchange_hash_ctx; - libssh2_sha1_init(&exchange_hash_ctx); - - if(session->local.banner) { - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->local.banner) - 2); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->local.banner, - strlen((char *) session->local.banner) - 2); - } - else { - _libssh2_htonu32(exchange_state->h_sig_comp, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - (const unsigned char *) - LIBSSH2_SSH_DEFAULT_BANNER, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - } - - _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->remote.banner)); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->remote.banner, - strlen((char *) session->remote.banner)); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->local.kexinit_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->local.kexinit, - session->local.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->remote.kexinit_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->remote.kexinit, - session->remote.kexinit_len); - - _libssh2_htonu32(exchange_state->h_sig_comp, - session->server_hostkey_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - session->server_hostkey, - session->server_hostkey_len); - - if(packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { - /* diffie-hellman-group-exchange hashes additional fields */ -#ifdef LIBSSH2_DH_GEX_NEW - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_MINGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 4, - LIBSSH2_DH_GEX_OPTGROUP); - _libssh2_htonu32(exchange_state->h_sig_comp + 8, - LIBSSH2_DH_GEX_MAXGROUP); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 12); -#else - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_OPTGROUP); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); + assert(0); #endif - } - - if(midhash) { - libssh2_sha1_update(exchange_hash_ctx, midhash, - midhash_len); - } - - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->e_packet + 1, - exchange_state->e_packet_len - 1); - - _libssh2_htonu32(exchange_state->h_sig_comp, - exchange_state->f_value_len); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->f_value, - exchange_state->f_value_len); - - libssh2_sha1_update(exchange_hash_ctx, - exchange_state->k_value, - exchange_state->k_value_len); - - libssh2_sha1_final(exchange_hash_ctx, - exchange_state->h_sig_comp); - - if(session->hostkey-> - sig_verify(session, exchange_state->h_sig, - exchange_state->h_sig_len, exchange_state->h_sig_comp, - 20, &session->server_hostkey_abstract)) { - ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); - goto clean_exit; - } - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message"); - exchange_state->c = SSH_MSG_NEWKEYS; - - exchange_state->state = libssh2_NB_state_sent2; } +} - if(exchange_state->state == libssh2_NB_state_sent2) { - rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); - goto clean_exit; - } - - exchange_state->state = libssh2_NB_state_sent3; +static void _libssh2_sha_algo_value_hash(int sha_algo, + LIBSSH2_SESSION *session, + kmdhgGPshakex_state_t *exchange_state, + unsigned char **data, size_t data_len, + const unsigned char *version) +{ + if(sha_algo == 512) { + LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(512, *data, data_len, version); } - - if(exchange_state->state == libssh2_NB_state_sent3) { - rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS, - &exchange_state->tmp, - &exchange_state->tmp_len, 0, NULL, 0, - &exchange_state->req_state); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; - } - else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); - goto clean_exit; - } - /* The first key exchange has been performed, - switch to active crypt/comp/mac mode */ - session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); - - /* This will actually end up being just packet_type(1) - for this packet type anyway */ - LIBSSH2_FREE(session, exchange_state->tmp); - - if(!session->session_id) { - session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH); - if(!session->session_id) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for " - "SHA digest"); - goto clean_exit; - } - memcpy(session->session_id, exchange_state->h_sig_comp, - SHA_DIGEST_LENGTH); - session->session_id_len = SHA_DIGEST_LENGTH; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); - } - - /* Cleanup any existing cipher */ - if(session->local.crypt->dtor) { - session->local.crypt->dtor(session, - &session->local.crypt_abstract); - } - - /* Calculate IV/Secret/Key for each direction */ - if(session->local.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, - session->local.crypt-> - iv_len, - (const unsigned char *) - "A"); - if(!iv) { - ret = -1; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, - session->local.crypt-> - secret_len, - (const unsigned char *) - "C"); - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->local.crypt-> - init(session, session->local.crypt, iv, &free_iv, secret, - &free_secret, 1, &session->local.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->local.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->local.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); - - if(session->remote.crypt->dtor) { - /* Cleanup any existing cipher */ - session->remote.crypt->dtor(session, - &session->remote.crypt_abstract); - } - - if(session->remote.crypt->init) { - unsigned char *iv = NULL, *secret = NULL; - int free_iv = 0, free_secret = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, - session->remote.crypt-> - iv_len, - (const unsigned char *) - "B"); - if(!iv) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, - session->remote.crypt-> - secret_len, - (const unsigned char *) - "D"); - if(!secret) { - LIBSSH2_FREE(session, iv); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - if(session->remote.crypt-> - init(session, session->remote.crypt, iv, &free_iv, secret, - &free_secret, 0, &session->remote.crypt_abstract)) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - - if(free_iv) { - _libssh2_explicit_zero(iv, session->remote.crypt->iv_len); - LIBSSH2_FREE(session, iv); - } - - if(free_secret) { - _libssh2_explicit_zero(secret, - session->remote.crypt->secret_len); - LIBSSH2_FREE(session, secret); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); - - if(session->local.mac->dtor) { - session->local.mac->dtor(session, &session->local.mac_abstract); - } - - if(session->local.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, - session->local.mac-> - key_len, - (const unsigned char *) - "E"); - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->local.mac->init(session, key, &free_key, - &session->local.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->local.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); - - if(session->remote.mac->dtor) { - session->remote.mac->dtor(session, &session->remote.mac_abstract); - } - - if(session->remote.mac->init) { - unsigned char *key = NULL; - int free_key = 0; - - LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, - session->remote.mac-> - key_len, - (const unsigned char *) - "F"); - if(!key) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - session->remote.mac->init(session, key, &free_key, - &session->remote.mac_abstract); - - if(free_key) { - _libssh2_explicit_zero(key, session->remote.mac->key_len); - LIBSSH2_FREE(session, key); - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); - - /* Initialize compression for each direction */ - - /* Cleanup any existing compression */ - if(session->local.comp && session->local.comp->dtor) { - session->local.comp->dtor(session, 1, - &session->local.comp_abstract); - } - - if(session->local.comp && session->local.comp->init) { - if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); - - if(session->remote.comp && session->remote.comp->dtor) { - session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); - } - - if(session->remote.comp && session->remote.comp->init) { - if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { - ret = LIBSSH2_ERROR_KEX_FAILURE; - goto clean_exit; - } - } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - + else if(sha_algo == 384) { + LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(384, *data, data_len, version); } - - clean_exit: - libssh2_dh_dtor(&exchange_state->x); - _libssh2_bn_free(exchange_state->e); - exchange_state->e = NULL; - _libssh2_bn_free(exchange_state->f); - exchange_state->f = NULL; - _libssh2_bn_free(exchange_state->k); - exchange_state->k = NULL; - _libssh2_bn_ctx_free(exchange_state->ctx); - exchange_state->ctx = NULL; - - if(exchange_state->e_packet) { - LIBSSH2_FREE(session, exchange_state->e_packet); - exchange_state->e_packet = NULL; + else if(sha_algo == 256) { + LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, *data, data_len, version); } - - if(exchange_state->s_packet) { - LIBSSH2_FREE(session, exchange_state->s_packet); - exchange_state->s_packet = NULL; + else if(sha_algo == 1) { + LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(1, *data, data_len, version); } - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; + else { +#ifdef LIBSSH2DEBUG + assert(0); +#endif } - - exchange_state->state = libssh2_NB_state_idle; - - return ret; } -/* - * diffie_hellman_sha256 - * - * Diffie Hellman Key Exchange, Group Agnostic +/*! + * @function diffie_hellman_sha_algo + * @abstract Diffie Hellman Key Exchange, Group Agnostic, + * SHA Algorithm Agnostic + * @result 0 on success, error code on failure */ -static int diffie_hellman_sha256(LIBSSH2_SESSION *session, - _libssh2_bn *g, - _libssh2_bn *p, - int group_order, - unsigned char packet_type_init, - unsigned char packet_type_reply, - unsigned char *midhash, - unsigned long midhash_len, - kmdhgGPshakex_state_t *exchange_state) +static int diffie_hellman_sha_algo(LIBSSH2_SESSION *session, + _libssh2_bn *g, + _libssh2_bn *p, + int group_order, + int sha_algo_value, + void *exchange_hash_ctx, + unsigned char packet_type_init, + unsigned char packet_type_reply, + unsigned char *midhash, + size_t midhash_len, + kmdhgGPshakex_state_t *exchange_state) { int ret = 0; int rc; - libssh2_sha256_ctx exchange_hash_ctx; + + int digest_len = 0; + + if(sha_algo_value == 512) + digest_len = SHA512_DIGEST_LENGTH; + else if(sha_algo_value == 384) + digest_len = SHA384_DIGEST_LENGTH; + else if(sha_algo_value == 256) + digest_len = SHA256_DIGEST_LENGTH; + else if(sha_algo_value == 1) + digest_len = SHA1_DIGEST_LENGTH; + else { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "sha algo value is unimplemented"); + goto clean_exit; + } if(exchange_state->state == libssh2_NB_state_idle) { /* Setup initial values */ @@ -846,10 +257,19 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t)); /* Generate x and e */ + if(_libssh2_bn_bits(p) > LIBSSH2_DH_MAX_MODULUS_BITS) { + ret = _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "dh modulus value is too large"); + goto clean_exit; + } + rc = libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p, group_order, exchange_state->ctx); - if(rc) + if(rc) { + ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, + "dh key pair generation failed"); goto clean_exit; + } /* Send KEX init */ /* packet_type(1) + String Length(4) + leading 0(1) */ @@ -869,7 +289,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, } exchange_state->e_packet[0] = packet_type_init; _libssh2_htonu32(exchange_state->e_packet + 1, - exchange_state->e_packet_len - 5); + (uint32_t)(exchange_state->e_packet_len - 5)); if(_libssh2_bn_bits(exchange_state->e) % 8) { _libssh2_bn_to_bin(exchange_state->e, exchange_state->e_packet + 5); @@ -880,8 +300,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, exchange_state->e_packet + 6); } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", - (int) packet_type_init); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", + (int) packet_type_init)); exchange_state->state = libssh2_NB_state_created; } @@ -907,9 +327,9 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, * need to silently ignore it */ int burn_type; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Waiting for badly guessed KEX packet " - "(to be ignored)"); + "(to be ignored)")); burn_type = _libssh2_packet_burn(session, &exchange_state->burn_state); if(burn_type == LIBSSH2_ERROR_EAGAIN) { @@ -922,9 +342,9 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, } session->burn_optimistic_kexinit = 0; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Burnt packet of type: %02x", - (unsigned int) burn_type); + (unsigned int) burn_type)); } exchange_state->state = libssh2_NB_state_sent1; @@ -934,6 +354,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, /* Wait for KEX reply */ struct string_buf buf; size_t host_key_len; + int err; rc = _libssh2_packet_require(session, packet_type_reply, &exchange_state->s_packet, @@ -951,7 +372,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, /* Parse KEXDH_REPLY */ if(exchange_state->s_packet_len < 5) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected packet length"); + "Unexpected packet length DH-SHA"); goto clean_exit; } @@ -995,8 +416,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's MD5 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ #endif /* ! LIBSSH2_MD5 */ @@ -1019,13 +440,12 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, { char fingerprint[64], *fprint = fingerprint; int i; - for(i = 0; i < 20; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's SHA1 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ @@ -1050,27 +470,29 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, (const char *) session->server_hostkey_sha256, SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + if(base64Fingerprint) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Server's SHA256 Fingerprint: %s", - base64Fingerprint); + base64Fingerprint)); LIBSSH2_FREE(session, base64Fingerprint); } } #endif /* LIBSSH2DEBUG */ + if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { + session->server_hostkey_len, + &session->server_hostkey_abstract)) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); + "Unable to initialize hostkey importer " + "DH-SHA"); goto clean_exit; } if(_libssh2_get_string(&buf, &(exchange_state->f_value), &(exchange_state->f_value_len))) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get f value"); + "Unable to get DH-SHA f value"); goto clean_exit; } @@ -1080,7 +502,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, if(_libssh2_get_string(&buf, &(exchange_state->h_sig), &(exchange_state->h_sig_len))) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to get h sig"); + "Unable to get DH-SHA h sig"); goto clean_exit; } @@ -1096,11 +518,11 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, LIBSSH2_ALLOC(session, exchange_state->k_value_len); if(!exchange_state->k_value) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); + "Unable to allocate buffer for DH-SHA K"); goto clean_exit; } _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); + (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); } @@ -1110,116 +532,115 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, } exchange_state->exchange_hash = (void *)&exchange_hash_ctx; - libssh2_sha256_init(&exchange_hash_ctx); + _libssh2_sha_algo_ctx_init(sha_algo_value, exchange_hash_ctx); if(session->local.banner) { _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->local.banner) - 2); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->local.banner, - strlen((char *) session->local.banner) - 2); + (uint32_t)(strlen((char *) session->local.banner) - 2)); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + session->local.banner, + strlen((char *) session->local.banner) - 2); } else { _libssh2_htonu32(exchange_state->h_sig_comp, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - (const unsigned char *) - LIBSSH2_SSH_DEFAULT_BANNER, - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + (unsigned char *) + LIBSSH2_SSH_DEFAULT_BANNER, + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); } _libssh2_htonu32(exchange_state->h_sig_comp, - strlen((char *) session->remote.banner)); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->remote.banner, - strlen((char *) session->remote.banner)); + (uint32_t)strlen((char *) session->remote.banner)); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + session->remote.banner, + strlen((char *) session->remote.banner)); _libssh2_htonu32(exchange_state->h_sig_comp, - session->local.kexinit_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->local.kexinit, - session->local.kexinit_len); + (uint32_t)session->local.kexinit_len); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + session->local.kexinit, + session->local.kexinit_len); _libssh2_htonu32(exchange_state->h_sig_comp, - session->remote.kexinit_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->remote.kexinit, - session->remote.kexinit_len); + (uint32_t)session->remote.kexinit_len); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + session->remote.kexinit, + session->remote.kexinit_len); _libssh2_htonu32(exchange_state->h_sig_comp, session->server_hostkey_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - session->server_hostkey, - session->server_hostkey_len); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + session->server_hostkey, + session->server_hostkey_len); if(packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { /* diffie-hellman-group-exchange hashes additional fields */ -#ifdef LIBSSH2_DH_GEX_NEW _libssh2_htonu32(exchange_state->h_sig_comp, LIBSSH2_DH_GEX_MINGROUP); _libssh2_htonu32(exchange_state->h_sig_comp + 4, LIBSSH2_DH_GEX_OPTGROUP); _libssh2_htonu32(exchange_state->h_sig_comp + 8, LIBSSH2_DH_GEX_MAXGROUP); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 12); -#else - _libssh2_htonu32(exchange_state->h_sig_comp, - LIBSSH2_DH_GEX_OPTGROUP); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); -#endif + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 12); } if(midhash) { - libssh2_sha256_update(exchange_hash_ctx, midhash, - midhash_len); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + midhash, midhash_len); } - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->e_packet + 1, - exchange_state->e_packet_len - 1); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->e_packet + 1, + exchange_state->e_packet_len - 1); _libssh2_htonu32(exchange_state->h_sig_comp, - exchange_state->f_value_len); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->h_sig_comp, 4); - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->f_value, - exchange_state->f_value_len); - - libssh2_sha256_update(exchange_hash_ctx, - exchange_state->k_value, - exchange_state->k_value_len); - - libssh2_sha256_final(exchange_hash_ctx, - exchange_state->h_sig_comp); - - if(session->hostkey-> - sig_verify(session, exchange_state->h_sig, - exchange_state->h_sig_len, exchange_state->h_sig_comp, - SHA256_DIGEST_LENGTH, - &session->server_hostkey_abstract)) { + (uint32_t)exchange_state->f_value_len); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->f_value, + exchange_state->f_value_len); + + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->k_value, + exchange_state->k_value_len); + + _libssh2_sha_algo_ctx_final(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp); + + err = session->hostkey->sig_verify(session, + exchange_state->h_sig, + exchange_state->h_sig_len, + exchange_state->h_sig_comp, + digest_len, + &session->server_hostkey_abstract); + + if(err) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Failed hostkey sig_verify(): %s: %d", + session->hostkey->name, err)); ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); + "Unable to verify hostkey signature " + "DH-SHA"); goto clean_exit; } - - - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sending NEWKEYS message")); exchange_state->c = SSH_MSG_NEWKEYS; exchange_state->state = libssh2_NB_state_sent2; @@ -1232,7 +653,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, } else if(rc) { ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); + "Unable to send NEWKEYS message DH-SHA"); goto clean_exit; } @@ -1248,20 +669,23 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, return rc; } else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); + ret = _libssh2_error(session, rc, + "Timed out waiting for NEWKEYS DH-SHA"); goto clean_exit; } + /* The first key exchange has been performed, switch to active crypt/comp/mac mode */ session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Received NEWKEYS message DH-SHA")); /* This will actually end up being just packet_type(1) for this packet type anyway */ LIBSSH2_FREE(session, exchange_state->tmp); if(!session->session_id) { - session->session_id = LIBSSH2_ALLOC(session, SHA256_DIGEST_LENGTH); + session->session_id = LIBSSH2_ALLOC(session, digest_len); if(!session->session_id) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate buffer for " @@ -1269,10 +693,10 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, goto clean_exit; } memcpy(session->session_id, exchange_state->h_sig_comp, - SHA256_DIGEST_LENGTH); - session->session_id_len = SHA256_DIGEST_LENGTH; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); + digest_len); + session->session_id_len = digest_len; + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "session_id calculated")); } /* Cleanup any existing cipher */ @@ -1286,18 +710,20 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, unsigned char *iv = NULL, *secret = NULL; int free_iv = 0, free_secret = 0; - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv, - session->local.crypt-> - iv_len, - (const unsigned char *)"A"); + _libssh2_sha_algo_value_hash(sha_algo_value, session, + exchange_state, &iv, + session->local.crypt->iv_len, + (const unsigned char *)"A"); + if(!iv) { ret = -1; goto clean_exit; } - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret, - session->local.crypt-> - secret_len, - (const unsigned char *)"C"); + _libssh2_sha_algo_value_hash(sha_algo_value, session, + exchange_state, &secret, + session->local.crypt->secret_len, + (const unsigned char *)"C"); + if(!secret) { LIBSSH2_FREE(session, iv); ret = LIBSSH2_ERROR_KEX_FAILURE; @@ -1323,8 +749,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server IV and Key calculated")); if(session->remote.crypt->dtor) { /* Cleanup any existing cipher */ @@ -1336,18 +762,18 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, unsigned char *iv = NULL, *secret = NULL; int free_iv = 0, free_secret = 0; - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, iv, - session->remote.crypt-> - iv_len, - (const unsigned char *)"B"); + _libssh2_sha_algo_value_hash(sha_algo_value, session, + exchange_state, &iv, + session->remote.crypt->iv_len, + (const unsigned char *)"B"); if(!iv) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, secret, - session->remote.crypt-> - secret_len, - (const unsigned char *)"D"); + _libssh2_sha_algo_value_hash(sha_algo_value, session, + exchange_state, &secret, + session->remote.crypt->secret_len, + (const unsigned char *)"D"); if(!secret) { LIBSSH2_FREE(session, iv); ret = LIBSSH2_ERROR_KEX_FAILURE; @@ -1373,8 +799,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client IV and Key calculated")); if(session->local.mac->dtor) { session->local.mac->dtor(session, &session->local.mac_abstract); @@ -1384,10 +810,10 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, unsigned char *key = NULL; int free_key = 0; - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key, - session->local.mac-> - key_len, - (const unsigned char *)"E"); + _libssh2_sha_algo_value_hash(sha_algo_value, session, + exchange_state, &key, + session->local.mac->key_len, + (const unsigned char *)"E"); if(!key) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; @@ -1400,8 +826,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server HMAC Key calculated")); if(session->remote.mac->dtor) { session->remote.mac->dtor(session, &session->remote.mac_abstract); @@ -1411,10 +837,10 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, unsigned char *key = NULL; int free_key = 0; - LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, key, - session->remote.mac-> - key_len, - (const unsigned char *)"F"); + _libssh2_sha_algo_value_hash(sha_algo_value, session, + exchange_state, &key, + session->remote.mac->key_len, + (const unsigned char *)"F"); if(!key) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; @@ -1427,8 +853,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client HMAC Key calculated")); /* Initialize compression for each direction */ @@ -1440,13 +866,13 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, if(session->local.comp && session->local.comp->init) { if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { + &session->local.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server compression initialized")); if(session->remote.comp && session->remote.comp->dtor) { session->remote.comp->dtor(session, 0, @@ -1455,17 +881,17 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, if(session->remote.comp && session->remote.comp->init) { if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { + &session->remote.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client compression initialized")); } - clean_exit: +clean_exit: libssh2_dh_dtor(&exchange_state->x); _libssh2_bn_free(exchange_state->e); exchange_state->e = NULL; @@ -1526,6 +952,7 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, }; int ret; + libssh2_sha1_ctx exchange_hash_ctx; if(key_state->state == libssh2_NB_state_idle) { /* g == 2 */ @@ -1537,14 +964,16 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, _libssh2_bn_set_word(key_state->g, 2); _libssh2_bn_from_bin(key_state->p, 128, p_value); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group1 Key Exchange"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group1 Key Exchange")); key_state->state = libssh2_NB_state_created; } - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, 128, - SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, - NULL, 0, &key_state->exchange_state); + + ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, 128, 1, + (void *)&exchange_hash_ctx, + SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, + NULL, 0, &key_state->exchange_state); if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } @@ -1559,14 +988,28 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, } - -/* kex_method_diffie_hellman_group14_sha1_key_exchange - * Diffie-Hellman Group14 Key Exchange using SHA1 +/* kex_method_diffie_hellman_group14_key_exchange + * Diffie-Hellman Group14 Key Exchange with hash function callback */ +typedef int (*diffie_hellman_hash_func_t)(LIBSSH2_SESSION *, + _libssh2_bn *, + _libssh2_bn *, + int, + int, + void *, + unsigned char, + unsigned char, + unsigned char *, + size_t, + kmdhgGPshakex_state_t *); static int -kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, - key_exchange_state_low_t - * key_state) +kex_method_diffie_hellman_group14_key_exchange(LIBSSH2_SESSION *session, + key_exchange_state_low_t + * key_state, + int sha_algo_value, + void *exchange_hash_ctx, + diffie_hellman_hash_func_t + hashfunc) { static const unsigned char p_value[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -1614,14 +1057,137 @@ kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, _libssh2_bn_set_word(key_state->g, 2); _libssh2_bn_from_bin(key_state->p, 256, p_value); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group14 Key Exchange"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group14 Key Exchange")); + + key_state->state = libssh2_NB_state_created; + } + ret = hashfunc(session, key_state->g, key_state->p, + 256, sha_algo_value, exchange_hash_ctx, SSH_MSG_KEXDH_INIT, + SSH_MSG_KEXDH_REPLY, NULL, 0, &key_state->exchange_state); + if(ret == LIBSSH2_ERROR_EAGAIN) { + return ret; + } + + key_state->state = libssh2_NB_state_idle; + _libssh2_bn_free(key_state->p); + key_state->p = NULL; + _libssh2_bn_free(key_state->g); + key_state->g = NULL; + + return ret; +} + + + +/* kex_method_diffie_hellman_group14_sha1_key_exchange + * Diffie-Hellman Group14 Key Exchange using SHA1 + */ +static int +kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, + key_exchange_state_low_t + * key_state) +{ + libssh2_sha1_ctx ctx; + return kex_method_diffie_hellman_group14_key_exchange(session, + key_state, 1, + &ctx, + diffie_hellman_sha_algo); +} + + + +/* kex_method_diffie_hellman_group14_sha256_key_exchange + * Diffie-Hellman Group14 Key Exchange using SHA256 + */ +static int +kex_method_diffie_hellman_group14_sha256_key_exchange(LIBSSH2_SESSION *session, + key_exchange_state_low_t + * key_state) +{ + libssh2_sha256_ctx ctx; + return kex_method_diffie_hellman_group14_key_exchange(session, + key_state, 256, + &ctx, + diffie_hellman_sha_algo); +} + +/* kex_method_diffie_hellman_group16_sha512_key_exchange +* Diffie-Hellman Group16 Key Exchange using SHA512 +*/ +static int +kex_method_diffie_hellman_group16_sha512_key_exchange(LIBSSH2_SESSION *session, + key_exchange_state_low_t + * key_state) +{ + static const unsigned char p_value[512] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, + 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, + 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, + 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, + 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, + 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, + 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, + 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, + 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, + 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, + 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, + 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, + 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, + 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, + 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, + 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, + 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, + 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, + 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, + 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, + 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, + 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + int ret; + libssh2_sha512_ctx exchange_hash_ctx; + + if(key_state->state == libssh2_NB_state_idle) { + key_state->p = _libssh2_bn_init_from_bin(); /* SSH2 defined value + (p_value) */ + key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ + + /* g == 2 */ + /* Initialize P and G */ + _libssh2_bn_set_word(key_state->g, 2); + _libssh2_bn_from_bin(key_state->p, 512, p_value); + + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group16 Key Exchange")); key_state->state = libssh2_NB_state_created; } - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, - 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, - NULL, 0, &key_state->exchange_state); + + ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, 512, + 512, (void *)&exchange_hash_ctx, + SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, + NULL, 0, &key_state->exchange_state); if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } @@ -1635,15 +1201,146 @@ kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, return ret; } +/* kex_method_diffie_hellman_group16_sha512_key_exchange +* Diffie-Hellman Group18 Key Exchange using SHA512 +*/ +static int +kex_method_diffie_hellman_group18_sha512_key_exchange(LIBSSH2_SESSION *session, + key_exchange_state_low_t + * key_state) +{ + static const unsigned char p_value[1024] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, + 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, + 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, + 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, + 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, + 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, + 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, + 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, + 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, + 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, + 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, + 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, + 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, + 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, + 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, + 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, + 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, + 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, + 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, + 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, + 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, + 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, + 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, 0xC1, 0xD4, 0xDC, 0xB2, + 0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, + 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F, + 0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, + 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, 0xDA, 0x3E, 0xDB, 0xEB, + 0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, + 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51, + 0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, + 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0, 0x32, 0xEA, 0x15, + 0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, + 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, + 0x90, 0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, + 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D, 0x45, 0xB7, + 0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, + 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2, + 0x0F, 0x80, 0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, + 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA, 0x3D, + 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, + 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7, + 0x6E, 0x3C, 0x04, 0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, + 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E, + 0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, + 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8, 0xBE, 0xC4, 0xD0, + 0x73, 0xB9, 0x31, 0xBA, 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, + 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, 0x25, 0x76, 0xF6, 0x93, + 0x6B, 0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, + 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F, 0x16, 0xCB, + 0xE3, 0x9D, 0x65, 0x2D, 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, + 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, 0x13, 0xEB, 0x57, 0xA8, + 0x1A, 0x23, 0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, + 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B, 0x7F, + 0xA2, 0xC0, 0x87, 0xE8, 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, + 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, 0x6D, 0x2A, 0x13, 0xF8, + 0x3F, 0x44, 0xF8, 0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, + 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5, + 0x08, 0x46, 0x85, 0x1D, 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, + 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, 0xFA, 0xF3, 0x6B, 0xC3, + 0x1E, 0xCF, 0xA2, 0x68, 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, + 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E, + 0xD5, 0xEE, 0x38, 0x2B, 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, + 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, 0x9E, 0x30, 0x50, 0xE2, + 0x76, 0x56, 0x94, 0xDF, 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, + 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF + }; + int ret; + libssh2_sha512_ctx exchange_hash_ctx; + if(key_state->state == libssh2_NB_state_idle) { + key_state->p = _libssh2_bn_init_from_bin(); /* SSH2 defined value + (p_value) */ + key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ + + /* g == 2 */ + /* Initialize P and G */ + _libssh2_bn_set_word(key_state->g, 2); + _libssh2_bn_from_bin(key_state->p, 1024, p_value); + + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group18 Key Exchange")); + + key_state->state = libssh2_NB_state_created; + } + + ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, 1024, + 512, (void *)&exchange_hash_ctx, + SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, + NULL, 0, &key_state->exchange_state); + if(ret == LIBSSH2_ERROR_EAGAIN) { + return ret; + } + + key_state->state = libssh2_NB_state_idle; + _libssh2_bn_free(key_state->p); + key_state->p = NULL; + _libssh2_bn_free(key_state->g); + key_state->g = NULL; + + return ret; +} /* kex_method_diffie_hellman_group_exchange_sha1_key_exchange * Diffie-Hellman Group Exchange Key Exchange using SHA1 * Negotiates random(ish) group for secret derivation */ static int -kex_method_diffie_hellman_group_exchange_sha1_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +kex_method_diffie_hellman_group_exchange_sha1_key_exchange( + LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state) { int ret = 0; int rc; @@ -1652,23 +1349,13 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange key_state->p = _libssh2_bn_init_from_bin(); key_state->g = _libssh2_bn_init_from_bin(); /* Ask for a P and G pair */ -#ifdef LIBSSH2_DH_GEX_NEW key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); key_state->request_len = 13; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(New Method)"); -#else - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); - key_state->request_len = 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(Old Method)"); -#endif + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group-Exchange SHA1")); key_state->state = libssh2_NB_state_created; } @@ -1708,10 +1395,11 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange size_t p_len, g_len; unsigned char *p, *g; struct string_buf buf; + libssh2_sha1_ctx exchange_hash_ctx; if(key_state->data_len < 9) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected key length DH-SHA1"); goto dh_gex_clean_exit; } @@ -1723,25 +1411,27 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange if(_libssh2_get_bignum_bytes(&buf, &p, &p_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA1 p"); goto dh_gex_clean_exit; } if(_libssh2_get_bignum_bytes(&buf, &g, &g_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA1 g"); goto dh_gex_clean_exit; } _libssh2_bn_from_bin(key_state->p, p_len, p); _libssh2_bn_from_bin(key_state->g, g_len, g); - ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len, - SSH_MSG_KEX_DH_GEX_INIT, - SSH_MSG_KEX_DH_GEX_REPLY, - key_state->data + 1, - key_state->data_len - 1, - &key_state->exchange_state); + ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, + (int)p_len, 1, + (void *)&exchange_hash_ctx, + SSH_MSG_KEX_DH_GEX_INIT, + SSH_MSG_KEX_DH_GEX_REPLY, + key_state->data + 1, + key_state->data_len - 1, + &key_state->exchange_state); if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } @@ -1749,7 +1439,7 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange LIBSSH2_FREE(session, key_state->data); } - dh_gex_clean_exit: +dh_gex_clean_exit: key_state->state = libssh2_NB_state_idle; _libssh2_bn_free(key_state->g); key_state->g = NULL; @@ -1766,8 +1456,9 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange * Negotiates random(ish) group for secret derivation */ static int -kex_method_diffie_hellman_group_exchange_sha256_key_exchange -(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +kex_method_diffie_hellman_group_exchange_sha256_key_exchange( + LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state) { int ret = 0; int rc; @@ -1776,23 +1467,13 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange key_state->p = _libssh2_bn_init(); key_state->g = _libssh2_bn_init(); /* Ask for a P and G pair */ -#ifdef LIBSSH2_DH_GEX_NEW key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); key_state->request_len = 13; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(New Method SHA256)"); -#else - key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; - _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); - key_state->request_len = 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating Diffie-Hellman Group-Exchange " - "(Old Method SHA256)"); -#endif + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group-Exchange SHA256")); key_state->state = libssh2_NB_state_created; } @@ -1833,10 +1514,11 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange unsigned char *p, *g; size_t p_len, g_len; struct string_buf buf; + libssh2_sha256_ctx exchange_hash_ctx; if(key_state->data_len < 9) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected key length DH-SHA256"); goto dh_gex_clean_exit; } @@ -1848,25 +1530,27 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange if(_libssh2_get_bignum_bytes(&buf, &p, &p_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA256 p"); goto dh_gex_clean_exit; } if(_libssh2_get_bignum_bytes(&buf, &g, &g_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected value"); + "Unexpected value DH-SHA256 g"); goto dh_gex_clean_exit; } _libssh2_bn_from_bin(key_state->p, p_len, p); _libssh2_bn_from_bin(key_state->g, g_len, g); - ret = diffie_hellman_sha256(session, key_state->g, key_state->p, p_len, - SSH_MSG_KEX_DH_GEX_INIT, - SSH_MSG_KEX_DH_GEX_REPLY, - key_state->data + 1, - key_state->data_len - 1, - &key_state->exchange_state); + ret = diffie_hellman_sha_algo(session, key_state->g, key_state->p, + (int)p_len, 256, + (void *)&exchange_hash_ctx, + SSH_MSG_KEX_DH_GEX_INIT, + SSH_MSG_KEX_DH_GEX_REPLY, + key_state->data + 1, + key_state->data_len - 1, + &key_state->exchange_state); if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } @@ -1874,7 +1558,7 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange LIBSSH2_FREE(session, key_state->data); } - dh_gex_clean_exit: +dh_gex_clean_exit: key_state->state = libssh2_NB_state_idle; _libssh2_bn_free(key_state->g); key_state->g = NULL; @@ -1885,6 +1569,115 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange } +/* LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY + * + * Macro that create and verifies EC SHA hash with a given digest bytes + * + * Payload format: + * + * string V_C, client's identification string (CR and LF excluded) + * string V_S, server's identification string (CR and LF excluded) + * string I_C, payload of the client's SSH_MSG_KEXINIT + * string I_S, payload of the server's SSH_MSG_KEXINIT + * string K_S, server's public host key + * string Q_C, client's ephemeral public key octet string + * string Q_S, server's ephemeral public key octet string + * mpint K, shared secret + * + */ + +#define LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(digest_type) \ +do { \ + libssh2_sha##digest_type##_ctx ctx; \ + exchange_state->exchange_hash = (void *)&ctx; \ + (void)libssh2_sha##digest_type##_init(&ctx); \ + if(session->local.banner) { \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)(strlen((char *) session->local.banner) - 2)); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + (char *) session->local.banner, \ + strlen((char *) \ + session->local.banner) \ + - 2); \ + } \ + else { \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + LIBSSH2_SSH_DEFAULT_BANNER, \ + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) \ + - 1); \ + } \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)strlen((char *) session->remote.banner)); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + session->remote.banner, \ + strlen((char *) \ + session->remote.banner)); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)session->local.kexinit_len); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + session->local.kexinit, \ + session->local.kexinit_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)session->remote.kexinit_len); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + session->remote.kexinit, \ + session->remote.kexinit_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + session->server_hostkey_len); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + session->server_hostkey, \ + session->server_hostkey_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)public_key_len); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + public_key, \ + public_key_len); \ + \ + _libssh2_htonu32(exchange_state->h_sig_comp, \ + (uint32_t)server_public_key_len); \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->h_sig_comp, 4); \ + libssh2_sha##digest_type##_update(ctx, \ + server_public_key, \ + server_public_key_len); \ + \ + libssh2_sha##digest_type##_update(ctx, \ + exchange_state->k_value, \ + exchange_state->k_value_len); \ + \ + libssh2_sha##digest_type##_final(ctx, exchange_state->h_sig_comp); \ + \ + if(session->hostkey-> \ + sig_verify(session, exchange_state->h_sig, \ + exchange_state->h_sig_len, exchange_state->h_sig_comp, \ + SHA##digest_type##_DIGEST_LENGTH, \ + &session->server_hostkey_abstract)) { \ + rc = -1; \ + } \ +} while(0) + + #if LIBSSH2_ECDSA /* kex_session_ecdh_curve_type @@ -1894,10 +1687,9 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange static int kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type) { - int ret = 0; libssh2_curve_type type; - if(name == NULL) + if(!name) return -1; if(strcmp(name, "ecdh-sha2-nistp256") == 0) @@ -1907,126 +1699,17 @@ kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type) else if(strcmp(name, "ecdh-sha2-nistp521") == 0) type = LIBSSH2_EC_CURVE_NISTP521; else { - ret = -1; + return -1; } - if(ret == 0 && out_type) { + if(out_type) { *out_type = type; } - return ret; + return 0; } -/* LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY - * - * Macro that create and verifies EC SHA hash with a given digest bytes - * - * Payload format: - * - * string V_C, client's identification string (CR and LF excluded) - * string V_S, server's identification string (CR and LF excluded) - * string I_C, payload of the client's SSH_MSG_KEXINIT - * string I_S, payload of the server's SSH_MSG_KEXINIT - * string K_S, server's public host key - * string Q_C, client's ephemeral public key octet string - * string Q_S, server's ephemeral public key octet string - * mpint K, shared secret - * - */ - -#define LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(digest_type) \ -{ \ - libssh2_sha##digest_type##_ctx ctx; \ - exchange_state->exchange_hash = (void *)&ctx; \ - libssh2_sha##digest_type##_init(&ctx); \ - if(session->local.banner) { \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - strlen((char *) session->local.banner) - 2); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - (char *) session->local.banner, \ - strlen((char *) \ - session->local.banner) \ - - 2); \ - } \ - else { \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - LIBSSH2_SSH_DEFAULT_BANNER, \ - sizeof(LIBSSH2_SSH_DEFAULT_BANNER) \ - - 1); \ - } \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - strlen((char *) session->remote.banner)); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->remote.banner, \ - strlen((char *) \ - session->remote.banner)); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->local.kexinit_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->local.kexinit, \ - session->local.kexinit_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->remote.kexinit_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->remote.kexinit, \ - session->remote.kexinit_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - session->server_hostkey_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - session->server_hostkey, \ - session->server_hostkey_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - public_key_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - public_key, \ - public_key_len); \ - \ - _libssh2_htonu32(exchange_state->h_sig_comp, \ - server_public_key_len); \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->h_sig_comp, 4); \ - libssh2_sha##digest_type##_update(ctx, \ - server_public_key, \ - server_public_key_len); \ - \ - libssh2_sha##digest_type##_update(ctx, \ - exchange_state->k_value, \ - exchange_state->k_value_len); \ - \ - libssh2_sha##digest_type##_final(ctx, exchange_state->h_sig_comp); \ - \ - if(session->hostkey-> \ - sig_verify(session, exchange_state->h_sig, \ - exchange_state->h_sig_len, exchange_state->h_sig_comp, \ - SHA##digest_type##_DIGEST_LENGTH, \ - &session->server_hostkey_abstract)) { \ - rc = -1; \ - } \ -} \ - - /* ecdh_sha2_nistp * Elliptic Curve Diffie Hellman Key Exchange */ @@ -2042,7 +1725,7 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, if(data_len < 5) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Host key data is too short"); + "Host key data is too short"); return ret; } @@ -2058,26 +1741,24 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, /* parse INIT reply data */ /* host key K_S */ - unsigned char *s = data + 1; /* Advance past packet type */ unsigned char *server_public_key; size_t server_public_key_len; - size_t host_sig_len; + struct string_buf buf; - session->server_hostkey_len = - _libssh2_ntohu32((const unsigned char *)s); - s += 4; + buf.data = data; + buf.len = data_len; + buf.dataptr = buf.data; + buf.dataptr++; /* Advance past packet type */ - session->server_hostkey = LIBSSH2_ALLOC(session, - session->server_hostkey_len); - if(!session->server_hostkey) { + if(_libssh2_copy_string(session, &buf, &(session->server_hostkey), + &server_public_key_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for a copy " - "of the host key"); + "of the host ECDH key"); goto clean_exit; } - memcpy(session->server_hostkey, s, session->server_hostkey_len); - s += session->server_hostkey_len; + session->server_hostkey_len = (uint32_t)server_public_key_len; #if LIBSSH2_MD5 { @@ -2102,8 +1783,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's MD5 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ #endif /* ! LIBSSH2_MD5 */ @@ -2126,13 +1807,12 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, { char fingerprint[64], *fprint = fingerprint; int i; - for(i = 0; i < 20; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's SHA1 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ @@ -2158,42 +1838,44 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, (const char *) session->server_hostkey_sha256, SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + if(base64Fingerprint) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Server's SHA256 Fingerprint: %s", - base64Fingerprint); + base64Fingerprint)); LIBSSH2_FREE(session, base64Fingerprint); } } #endif /* LIBSSH2DEBUG */ if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { + session->server_hostkey_len, + &session->server_hostkey_abstract)) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); + "Unable to initialize hostkey importer " + "ECDH"); goto clean_exit; } /* server public key Q_S */ - server_public_key_len = _libssh2_ntohu32((const unsigned char *)s); - s += 4; - - server_public_key = s; - s += server_public_key_len; + if(_libssh2_get_string(&buf, &server_public_key, + &server_public_key_len)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unexpected key length ECDH"); + goto clean_exit; + } /* server signature */ - host_sig_len = _libssh2_ntohu32((const unsigned char *)s); - s += 4; - - exchange_state->h_sig = s; - exchange_state->h_sig_len = host_sig_len; - s += host_sig_len; + if(_libssh2_get_string(&buf, &exchange_state->h_sig, + &(exchange_state->h_sig_len))) { + ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, + "Unexpected ECDH server sig length"); + goto clean_exit; + } /* Compute the shared secret K */ rc = _libssh2_ecdh_gen_k(&exchange_state->k, private_key, server_public_key, server_public_key_len); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to create ECDH shared secret"); goto clean_exit; @@ -2208,11 +1890,11 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_ALLOC(session, exchange_state->k_value_len); if(!exchange_state->k_value) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate buffer for K"); + "Unable to allocate buffer for ECDH K"); goto clean_exit; } _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); + (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); } @@ -2236,9 +1918,10 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, break; } - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); + "Unable to verify hostkey signature " + "ECDH"); goto clean_exit; } @@ -2253,7 +1936,7 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } else if(rc) { ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); + "Unable to send NEWKEYS message ECDH"); goto clean_exit; } @@ -2269,17 +1952,19 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, return rc; } else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); + ret = _libssh2_error(session, rc, + "Timed out waiting for NEWKEYS ECDH"); goto clean_exit; } /* The first key exchange has been performed, - switch to active crypt/comp/mac mode */ + switch to active crypt/comp/mac mode */ session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Received NEWKEYS message ECDH")); /* This will actually end up being just packet_type(1) - for this packet type anyway */ + for this packet type anyway */ LIBSSH2_FREE(session, exchange_state->tmp); if(!session->session_id) { @@ -2307,9 +1992,9 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } memcpy(session->session_id, exchange_state->h_sig_comp, digest_length); - session->session_id_len = digest_length; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); + session->session_id_len = (uint32_t)digest_length; + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "session_id calculated")); } /* Cleanup any existing cipher */ @@ -2332,8 +2017,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } LIBSSH2_KEX_METHOD_EC_SHA_VALUE_HASH(secret, - session->local.crypt-> - secret_len, "C"); + session->local.crypt-> + secret_len, "C"); if(!secret) { LIBSSH2_FREE(session, iv); @@ -2360,8 +2045,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server IV and Key calculated")); if(session->remote.crypt->dtor) { /* Cleanup any existing cipher */ @@ -2410,8 +2095,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client IV and Key calculated")); if(session->local.mac->dtor) { session->local.mac->dtor(session, &session->local.mac_abstract); @@ -2437,8 +2122,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server HMAC Key calculated")); if(session->remote.mac->dtor) { session->remote.mac->dtor(session, &session->remote.mac_abstract); @@ -2464,8 +2149,8 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client HMAC Key calculated")); /* Initialize compression for each direction */ @@ -2477,13 +2162,13 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, if(session->local.comp && session->local.comp->init) { if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { + &session->local.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server compression initialized")); if(session->remote.comp && session->remote.comp->dtor) { session->remote.comp->dtor(session, 0, @@ -2492,14 +2177,13 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, if(session->remote.comp && session->remote.comp->init) { if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { + &session->remote.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); - + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client compression initialized")); } clean_exit: @@ -2519,10 +2203,9 @@ clean_exit: /* kex_method_ecdh_key_exchange * * Elliptic Curve Diffie Hellman Key Exchange - * supports SHA256/384/512 hashes based on negotated ecdh method + * supports SHA256/384/512 hashes based on negotiated ecdh method * */ - static int kex_method_ecdh_key_exchange (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) @@ -2541,7 +2224,7 @@ kex_method_ecdh_key_exchange if(key_state->state == libssh2_NB_state_created) { rc = kex_session_ecdh_curve_type(session->kex->name, &type); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, -1, "Unknown KEX nistp curve type"); goto ecdh_clean_exit; @@ -2551,7 +2234,7 @@ kex_method_ecdh_key_exchange &key_state->public_key_oct, &key_state->public_key_oct_len, type); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, rc, "Unable to create private key"); goto ecdh_clean_exit; @@ -2563,8 +2246,8 @@ kex_method_ecdh_key_exchange key_state->public_key_oct_len); key_state->request_len = key_state->public_key_oct_len + 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating ECDH SHA2 NISTP256"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating ECDH SHA2 NISTP256")); key_state->state = libssh2_NB_state_sent; } @@ -2602,7 +2285,13 @@ kex_method_ecdh_key_exchange if(key_state->state == libssh2_NB_state_sent2) { - (void)kex_session_ecdh_curve_type(session->kex->name, &type); + rc = kex_session_ecdh_curve_type(session->kex->name, &type); + + if(rc) { + ret = _libssh2_error(session, -1, + "Unknown KEX nistp curve type"); + goto ecdh_clean_exit; + } ret = ecdh_sha2_nistp(session, type, key_state->data, key_state->data_len, @@ -2635,7 +2324,7 @@ ecdh_clean_exit: return ret; } -#endif /*LIBSSH2_ECDSA*/ +#endif /* LIBSSH2_ECDSA */ #if LIBSSH2_ED25519 @@ -2643,7 +2332,6 @@ ecdh_clean_exit: /* curve25519_sha256 * Elliptic Curve Key Exchange */ - static int curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, size_t data_len, @@ -2676,7 +2364,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(data_len < 5) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected curve25519 key length 1"); goto clean_exit; } @@ -2687,7 +2375,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(_libssh2_get_string(&buf, &server_host_key, &hostkey_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected curve25519 key length 2"); goto clean_exit; } @@ -2697,7 +2385,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(!session->server_hostkey) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for a copy " - "of the host key"); + "of the host curve25519 key"); goto clean_exit; } @@ -2727,8 +2415,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's MD5 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's MD5 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ #endif /* ! LIBSSH2_MD5 */ @@ -2751,13 +2439,12 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, { char fingerprint[64], *fprint = fingerprint; int i; - for(i = 0; i < 20; i++, fprint += 3) { snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); } *(--fprint) = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server's SHA1 Fingerprint: %s", fingerprint); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server's SHA1 Fingerprint: %s", fingerprint)); } #endif /* LIBSSH2DEBUG */ @@ -2783,20 +2470,21 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, (const char *) session->server_hostkey_sha256, SHA256_DIGEST_LENGTH, &base64Fingerprint); - if(base64Fingerprint != NULL) { - _libssh2_debug(session, LIBSSH2_TRACE_KEX, + if(base64Fingerprint) { + _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Server's SHA256 Fingerprint: %s", - base64Fingerprint); + base64Fingerprint)); LIBSSH2_FREE(session, base64Fingerprint); } } #endif /* LIBSSH2DEBUG */ if(session->hostkey->init(session, session->server_hostkey, - session->server_hostkey_len, - &session->server_hostkey_abstract)) { + session->server_hostkey_len, + &session->server_hostkey_abstract)) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, - "Unable to initialize hostkey importer"); + "Unable to initialize hostkey importer " + "curve25519"); goto clean_exit; } @@ -2804,7 +2492,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(_libssh2_get_string(&buf, &server_public_key, &server_public_key_len)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Unexpected key length"); + "Unexpected curve25519 key length"); goto clean_exit; } @@ -2826,9 +2514,9 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, /* Compute the shared secret K */ rc = _libssh2_curve25519_gen_k(&exchange_state->k, private_key, server_public_key); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, - "Unable to create ECDH shared secret"); + "Unable to create curve25519 shared secret"); goto clean_exit; } @@ -2845,7 +2533,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, goto clean_exit; } _libssh2_htonu32(exchange_state->k_value, - exchange_state->k_value_len - 4); + (uint32_t)(exchange_state->k_value_len - 4)); if(_libssh2_bn_bits(exchange_state->k) % 8) { _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); } @@ -2857,9 +2545,10 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, /*/ verify hash */ LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY(256); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, - "Unable to verify hostkey signature"); + "Unable to verify hostkey signature " + "curve25519"); goto clean_exit; } @@ -2874,7 +2563,7 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, } else if(rc) { ret = _libssh2_error(session, rc, - "Unable to send NEWKEYS message"); + "Unable to send NEWKEYS message curve25519"); goto clean_exit; } @@ -2890,18 +2579,19 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, return rc; } else if(rc) { - ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); + ret = _libssh2_error(session, rc, + "Timed out waiting for NEWKEYS curve25519"); goto clean_exit; } - /* The first key exchange has been performed, switch to active - crypt/comp/mac mode */ - + /* The first key exchange has been performed, + switch to active crypt/comp/mac mode */ session->state |= LIBSSH2_STATE_NEWKEYS; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Received NEWKEYS message curve25519")); - /* This will actually end up being just packet_type(1) for this packet - type anyway */ + /* This will actually end up being just packet_type(1) + for this packet type anyway */ LIBSSH2_FREE(session, exchange_state->tmp); if(!session->session_id) { @@ -2910,21 +2600,21 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, session->session_id = LIBSSH2_ALLOC(session, digest_length); if(!session->session_id) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allxcocate buffer for " + "Unable to allocate buffer for " "SHA digest"); goto clean_exit; } memcpy(session->session_id, exchange_state->h_sig_comp, digest_length); - session->session_id_len = digest_length; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "session_id calculated"); + session->session_id_len = (uint32_t)digest_length; + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "session_id calculated")); } /* Cleanup any existing cipher */ if(session->local.crypt->dtor) { session->local.crypt->dtor(session, - &session->local.crypt_abstract); + &session->local.crypt_abstract); } /* Calculate IV/Secret/Key for each direction */ @@ -2969,8 +2659,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server IV and Key calculated")); if(session->remote.crypt->dtor) { /* Cleanup any existing cipher */ @@ -3019,8 +2709,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, secret); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client IV and Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client IV and Key calculated")); if(session->local.mac->dtor) { session->local.mac->dtor(session, &session->local.mac_abstract); @@ -3046,8 +2736,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server HMAC Key calculated")); if(session->remote.mac->dtor) { session->remote.mac->dtor(session, &session->remote.mac_abstract); @@ -3073,8 +2763,8 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, LIBSSH2_FREE(session, key); } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client HMAC Key calculated"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client HMAC Key calculated")); /* Initialize compression for each direction */ @@ -3086,28 +2776,28 @@ curve25519_sha256(LIBSSH2_SESSION *session, unsigned char *data, if(session->local.comp && session->local.comp->init) { if(session->local.comp->init(session, 1, - &session->local.comp_abstract)) { + &session->local.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Client to Server compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Client to Server compression initialized")); if(session->remote.comp && session->remote.comp->dtor) { session->remote.comp->dtor(session, 0, - &session->remote.comp_abstract); + &session->remote.comp_abstract); } if(session->remote.comp && session->remote.comp->init) { if(session->remote.comp->init(session, 0, - &session->remote.comp_abstract)) { + &session->remote.comp_abstract)) { ret = LIBSSH2_ERROR_KEX_FAILURE; goto clean_exit; } } - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Server to Client compression initialized"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Server to Client compression initialized")); } clean_exit: @@ -3129,7 +2819,6 @@ clean_exit: * Elliptic Curve X25519 Key Exchange with SHA256 hash * */ - static int kex_method_curve25519_key_exchange (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) @@ -3147,20 +2836,20 @@ kex_method_curve25519_key_exchange unsigned char *s = NULL; rc = strcmp(session->kex->name, "curve25519-sha256@libssh.org"); - if(rc != 0) + if(rc) rc = strcmp(session->kex->name, "curve25519-sha256"); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, -1, "Unknown KEX curve25519 curve type"); goto clean_exit; } - rc = _libssh2_curve25519_new(session, NULL, + rc = _libssh2_curve25519_new(session, &key_state->curve25519_public_key, &key_state->curve25519_private_key); - if(rc != 0) { + if(rc) { ret = _libssh2_error(session, rc, "Unable to create private key"); goto clean_exit; @@ -3172,8 +2861,8 @@ kex_method_curve25519_key_exchange LIBSSH2_ED25519_KEY_LEN); key_state->request_len = LIBSSH2_ED25519_KEY_LEN + 5; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, - "Initiating curve25519 SHA2"); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Initiating curve25519 SHA2")); key_state->state = libssh2_NB_state_sent; } @@ -3245,7 +2934,7 @@ clean_exit: } -#endif /*LIBSSH2_ED25519*/ +#endif /* LIBSSH2_ED25519 */ #define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001 @@ -3263,6 +2952,24 @@ static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha1 = { LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, }; +static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha256 = { + "diffie-hellman-group14-sha256", + kex_method_diffie_hellman_group14_sha256_key_exchange, + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, +}; + +static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group16_sha512 = { + "diffie-hellman-group16-sha512", + kex_method_diffie_hellman_group16_sha512_key_exchange, + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, +}; + +static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group18_sha512 = { + "diffie-hellman-group18-sha512", + kex_method_diffie_hellman_group18_sha512_key_exchange, + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, +}; + static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group_exchange_sha1 = { "diffie-hellman-group-exchange-sha1", @@ -3315,20 +3022,35 @@ kex_method_ssh_curve25519_sha256 = { }; #endif +/* this kex method signals that client can receive extensions + * as described in https://datatracker.ietf.org/doc/html/rfc8308 +*/ + +static const LIBSSH2_KEX_METHOD +kex_method_extension_negotiation = { + "ext-info-c", + NULL, + 0, +}; + static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = { +#if LIBSSH2_ED25519 + &kex_method_ssh_curve25519_sha256, + &kex_method_ssh_curve25519_sha256_libssh, +#endif #if LIBSSH2_ECDSA &kex_method_ecdh_sha2_nistp256, &kex_method_ecdh_sha2_nistp384, &kex_method_ecdh_sha2_nistp521, #endif -#if LIBSSH2_ED25519 - &kex_method_ssh_curve25519_sha256, - &kex_method_ssh_curve25519_sha256_libssh, -#endif &kex_method_diffie_helman_group_exchange_sha256, - &kex_method_diffie_helman_group_exchange_sha1, + &kex_method_diffie_helman_group16_sha512, + &kex_method_diffie_helman_group18_sha512, + &kex_method_diffie_helman_group14_sha256, &kex_method_diffie_helman_group14_sha1, &kex_method_diffie_helman_group1_sha1, + &kex_method_diffie_helman_group_exchange_sha1, + &kex_method_extension_negotiation, NULL }; @@ -3338,6 +3060,7 @@ typedef struct _LIBSSH2_COMMON_METHOD } LIBSSH2_COMMON_METHOD; /* kex_method_strlen + * * Calculate the length of a particular method list's resulting string * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 * (because the last coma isn't used) @@ -3365,8 +3088,8 @@ kex_method_strlen(LIBSSH2_COMMON_METHOD ** method) /* kex_method_list * Generate formatted preference list in buf */ -static size_t -kex_method_list(unsigned char *buf, size_t list_strlen, +static uint32_t +kex_method_list(unsigned char *buf, uint32_t list_strlen, LIBSSH2_COMMON_METHOD ** method) { _libssh2_htonu32(buf, list_strlen); @@ -3377,7 +3100,7 @@ kex_method_list(unsigned char *buf, size_t list_strlen, } while(*method && (*method)->name) { - int mlen = strlen((*method)->name); + uint32_t mlen = (uint32_t)strlen((*method)->name); memcpy(buf, (*method)->name, mlen); buf += mlen; *(buf++) = ','; @@ -3390,20 +3113,22 @@ kex_method_list(unsigned char *buf, size_t list_strlen, #define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) \ - ((prefvar) ? strlen(prefvar) : \ - kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar))) - -#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \ - if(prefvar) { \ - _libssh2_htonu32((buf), (prefvarlen)); \ - buf += 4; \ - memcpy((buf), (prefvar), (prefvarlen)); \ - buf += (prefvarlen); \ - } \ - else { \ - buf += kex_method_list((buf), (prefvarlen), \ - (LIBSSH2_COMMON_METHOD**)(defaultvar)); \ - } + (uint32_t)((prefvar) ? strlen(prefvar) : \ + kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar))) + +#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \ + do { \ + if(prefvar) { \ + _libssh2_htonu32((buf), (prefvarlen)); \ + buf += 4; \ + memcpy((buf), (prefvar), (prefvarlen)); \ + buf += (prefvarlen); \ + } \ + else { \ + buf += kex_method_list((buf), (prefvarlen), \ + (LIBSSH2_COMMON_METHOD**)(defaultvar)); \ + } \ + } while(0) /* kexinit * Send SSH_MSG_KEXINIT packet @@ -3413,15 +3138,16 @@ static int kexinit(LIBSSH2_SESSION * session) /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) + reserved(4) + length longs(40) */ size_t data_len = 62; - size_t kex_len, hostkey_len = 0; - size_t crypt_cs_len, crypt_sc_len; - size_t comp_cs_len, comp_sc_len; - size_t mac_cs_len, mac_sc_len; - size_t lang_cs_len, lang_sc_len; unsigned char *data, *s; int rc; if(session->kexinit_state == libssh2_NB_state_idle) { + uint32_t kex_len, hostkey_len; + uint32_t crypt_cs_len, crypt_sc_len; + uint32_t comp_cs_len, comp_sc_len; + uint32_t mac_cs_len, mac_sc_len; + uint32_t lang_cs_len, lang_sc_len; + kex_len = LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods); hostkey_len = @@ -3451,8 +3177,8 @@ static int kexinit(LIBSSH2_SESSION * session) LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL); data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len + - comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len + - lang_cs_len + lang_sc_len; + comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len + + lang_cs_len + lang_sc_len; s = data = LIBSSH2_ALLOC(session, data_len); if(!data) { @@ -3462,7 +3188,11 @@ static int kexinit(LIBSSH2_SESSION * session) *(s++) = SSH_MSG_KEXINIT; - _libssh2_random(s, 16); + if(_libssh2_random(s, 16)) { + return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN, + "Unable to get random bytes " + "for KEXINIT cookie"); + } s += 16; /* Ennumerating through these lists twice is probably (certainly?) @@ -3504,25 +3234,35 @@ static int kexinit(LIBSSH2_SESSION * session) /* Funnily enough, they'll all "appear" to be '\0' terminated */ unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */ - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent KEX: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent KEX: %s", p)); p += kex_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent HOSTKEY: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent HOSTKEY: %s", p)); p += hostkey_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent CRYPT_CS: %s", p)); p += crypt_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent CRYPT_SC: %s", p)); p += crypt_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent MAC_CS: %s", p)); p += mac_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent MAC_SC: %s", p)); p += mac_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent COMP_CS: %s", p)); p += comp_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent COMP_SC: %s", p)); p += comp_sc_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_CS: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent LANG_CS: %s", p)); p += lang_cs_len + 4; - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_SC: %s", p); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Sent LANG_SC: %s", p)); p += lang_sc_len + 4; } #endif /* LIBSSH2DEBUG */ @@ -3565,31 +3305,48 @@ static int kexinit(LIBSSH2_SESSION * session) /* kex_agree_instr * Kex specific variant of strstr() - * Needle must be precede by BOL or ',', and followed by ',' or EOL + * Needle must be preceded by BOL or ',', and followed by ',' or EOL */ static unsigned char * -kex_agree_instr(unsigned char *haystack, unsigned long haystack_len, - const unsigned char *needle, unsigned long needle_len) +kex_agree_instr(unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) { unsigned char *s; + unsigned char *end_haystack; + size_t left; + + if(!haystack || !needle) { + return NULL; + } /* Haystack too short to bother trying */ - if(haystack_len < needle_len) { + if(haystack_len < needle_len || needle_len == 0) { return NULL; } + s = haystack; + end_haystack = &haystack[haystack_len]; + left = end_haystack - s; + /* Needle at start of haystack */ if((strncmp((char *) haystack, (char *) needle, needle_len) == 0) && (needle_len == haystack_len || haystack[needle_len] == ',')) { return haystack; } - s = haystack; /* Search until we run out of comas or we run out of haystack, whichever comes first */ - while((s = (unsigned char *) strchr((char *) s, ',')) - && ((haystack_len - (s - haystack)) > needle_len)) { - s++; + /* !checksrc! disable EQUALSNULL 1 */ + while((s = (unsigned char *) memchr((char *) s, ',', left)) != NULL) { + /* Advance buffer past coma if we can */ + left = end_haystack - s; + if((left >= 1) && (left <= haystack_len) && (left > needle_len)) { + s++; + } + else { + return NULL; + } + /* Needle at X position */ if((strncmp((char *) s, (char *) needle, needle_len) == 0) && (((s - haystack) + needle_len) == haystack_len @@ -3625,8 +3382,8 @@ kex_get_method_by_name(const char *name, size_t name_len, * Agree on a Hostkey which works with this kex */ static int kex_agree_hostkey(LIBSSH2_SESSION * session, - unsigned long kex_flags, - unsigned char *hostkey, unsigned long hostkey_len) + size_t kex_flags, + unsigned char *hostkey, size_t hostkey_len) { const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods(); unsigned char *s; @@ -3702,8 +3459,8 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session, * Agree on a Key Exchange method and a hostkey encoding type */ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, - unsigned long kex_len, unsigned char *hostkey, - unsigned long hostkey_len) + size_t kex_len, unsigned char *hostkey, + size_t hostkey_len) { const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods; unsigned char *s; @@ -3730,7 +3487,7 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, * Can we agree on a hostkey that works with this kex? */ if(kex_agree_hostkey(session, method->flags, hostkey, - hostkey_len) == 0) { + hostkey_len) == 0) { session->kex = method; if(session->burn_optimistic_kexinit && (kex == q)) { /* Server sent an optimistic packet, and client agrees @@ -3756,7 +3513,7 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, * Can we agree on a hostkey that works with this kex? */ if(kex_agree_hostkey(session, (*kexp)->flags, hostkey, - hostkey_len) == 0) { + hostkey_len) == 0) { session->kex = *kexp; if(session->burn_optimistic_kexinit && (kex == s)) { /* Server sent an optimistic packet, and client agrees @@ -3780,12 +3537,12 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, static int kex_agree_crypt(LIBSSH2_SESSION * session, libssh2_endpoint_data *endpoint, unsigned char *crypt, - unsigned long crypt_len) + size_t crypt_len) { const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods(); unsigned char *s; - (void) session; + (void)session; if(endpoint->crypt_prefs) { s = (unsigned char *) endpoint->crypt_prefs; @@ -3836,11 +3593,20 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session, */ static int kex_agree_mac(LIBSSH2_SESSION * session, libssh2_endpoint_data * endpoint, unsigned char *mac, - unsigned long mac_len) + size_t mac_len) { const LIBSSH2_MAC_METHOD **macp = _libssh2_mac_methods(); + const LIBSSH2_MAC_METHOD *override; unsigned char *s; - (void) session; + (void)session; + + override = _libssh2_mac_override(endpoint->crypt); + if(override) { + /* This crypto method has its own hmac method built-in, so a separate + * negotiation (and use) of a separate hmac method is unnecessary */ + endpoint->mac = override; + return 0; + } if(endpoint->mac_prefs) { s = (unsigned char *) endpoint->mac_prefs; @@ -3889,11 +3655,11 @@ static int kex_agree_mac(LIBSSH2_SESSION * session, */ static int kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_data *endpoint, unsigned char *comp, - unsigned long comp_len) + size_t comp_len) { const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session); unsigned char *s; - (void) session; + (void)session; if(endpoint->comp_prefs) { s = (unsigned char *) endpoint->comp_prefs; @@ -3937,124 +3703,116 @@ static int kex_agree_comp(LIBSSH2_SESSION *session, } - /* TODO: When in server mode we need to turn this logic on its head * The Client gets to make the final call on "agreed methods" */ -/* - * kex_string_pair() extracts a string from the packet and makes sure it fits - * within the given packet. - */ -static int kex_string_pair(unsigned char **sp, /* parsing position */ - unsigned char *data, /* start pointer to packet */ - size_t data_len, /* size of total packet */ - size_t *lenp, /* length of the string */ - unsigned char **strp) /* pointer to string start */ -{ - unsigned char *s = *sp; - *lenp = _libssh2_ntohu32(s); - - /* the length of the string must fit within the current pointer and the - end of the packet */ - if(*lenp > (data_len - (s - data) -4)) - return 1; - *strp = s + 4; - s += 4 + *lenp; - - *sp = s; - return 0; -} - /* kex_agree_methods * Decide which specific method to use of the methods offered by each party */ static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data, - unsigned data_len) + size_t data_len) { unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc, *mac_cs, *mac_sc; size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len; size_t comp_sc_len, mac_cs_len, mac_sc_len; - unsigned char *s = data; + struct string_buf buf; + + if(data_len < 17) + return -1; - /* Skip packet_type, we know it already */ - s++; + buf.data = (unsigned char *)data; + buf.len = data_len; + buf.dataptr = buf.data; + buf.dataptr++; /* advance past packet type */ /* Skip cookie, don't worry, it's preserved in the kexinit field */ - s += 16; + buf.dataptr += 16; /* Locate each string */ - if(kex_string_pair(&s, data, data_len, &kex_len, &kex)) + if(_libssh2_get_string(&buf, &kex, &kex_len)) return -1; - if(kex_string_pair(&s, data, data_len, &hostkey_len, &hostkey)) + if(_libssh2_get_string(&buf, &hostkey, &hostkey_len)) return -1; - if(kex_string_pair(&s, data, data_len, &crypt_cs_len, &crypt_cs)) + if(_libssh2_get_string(&buf, &crypt_cs, &crypt_cs_len)) return -1; - if(kex_string_pair(&s, data, data_len, &crypt_sc_len, &crypt_sc)) + if(_libssh2_get_string(&buf, &crypt_sc, &crypt_sc_len)) return -1; - if(kex_string_pair(&s, data, data_len, &mac_cs_len, &mac_cs)) + if(_libssh2_get_string(&buf, &mac_cs, &mac_cs_len)) return -1; - if(kex_string_pair(&s, data, data_len, &mac_sc_len, &mac_sc)) + if(_libssh2_get_string(&buf, &mac_sc, &mac_sc_len)) return -1; - if(kex_string_pair(&s, data, data_len, &comp_cs_len, &comp_cs)) + if(_libssh2_get_string(&buf, &comp_cs, &comp_cs_len)) return -1; - if(kex_string_pair(&s, data, data_len, &comp_sc_len, &comp_sc)) + if(_libssh2_get_string(&buf, &comp_sc, &comp_sc_len)) return -1; /* If the server sent an optimistic packet, assume that it guessed wrong. * If the guess is determined to be right (by kex_agree_kex_hostkey) * This flag will be reset to zero so that it's not ignored */ - session->burn_optimistic_kexinit = *(s++); - /* Next uint32 in packet is all zeros (reserved) */ + if(_libssh2_check_length(&buf, 1)) { + session->burn_optimistic_kexinit = *(buf.dataptr++); + } + else { + return -1; + } - if(data_len < (unsigned) (s - data)) - return -1; /* short packet */ + /* Next uint32 in packet is all zeros (reserved) */ if(kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) { return -1; } if(kex_agree_crypt(session, &session->local, crypt_cs, crypt_cs_len) - || kex_agree_crypt(session, &session->remote, crypt_sc, - crypt_sc_len)) { + || kex_agree_crypt(session, &session->remote, crypt_sc, crypt_sc_len)) { return -1; } - if(kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) || - kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) { + /* This must happen after kex_agree_crypt since some MACs depend on the + negotiated crypto method */ + if(kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) + || kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) { return -1; } - if(kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) || - kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) { + if(kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) + || kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) { return -1; } #if 0 if(libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len) - || libssh2_kex_agree_lang(session, &session->remote, lang_sc, - lang_sc_len)) { + || libssh2_kex_agree_lang(session, &session->remote, lang_sc, + lang_sc_len)) { return -1; } #endif - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on KEX method: %s", - session->kex->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on HOSTKEY method: %s", - session->hostkey->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_CS method: %s", - session->local.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_SC method: %s", - session->remote.crypt->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_CS method: %s", - session->local.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_SC method: %s", - session->remote.mac->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_CS method: %s", - session->local.comp->name); - _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_SC method: %s", - session->remote.comp->name); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on KEX method: %s", + session->kex->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on HOSTKEY method: %s", + session->hostkey->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on CRYPT_CS method: %s", + session->local.crypt->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on CRYPT_SC method: %s", + session->remote.crypt->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on MAC_CS method: %s", + session->local.mac->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on MAC_SC method: %s", + session->remote.mac->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on COMP_CS method: %s", + session->local.comp->name)); + _libssh2_debug((session, LIBSSH2_TRACE_KEX, + "Agreed on COMP_SC method: %s", + session->remote.comp->name)); return 0; } @@ -4151,7 +3909,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, session->remote.kexinit_len = key_state->data_len; if(kex_agree_methods(session, key_state->data, - key_state->data_len)) + key_state->data_len)) rc = LIBSSH2_ERROR_KEX_FAILURE; key_state->state = libssh2_NB_state_sent2; @@ -4205,50 +3963,48 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, const char *prefs) { char **prefvar, *s, *newprefs; - int prefs_len = strlen(prefs); + size_t prefs_len = strlen(prefs); const LIBSSH2_COMMON_METHOD **mlist; switch(method_type) { case LIBSSH2_METHOD_KEX: prefvar = &session->kex_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_kex_methods; break; case LIBSSH2_METHOD_HOSTKEY: prefvar = &session->hostkey_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_hostkey_methods(); break; case LIBSSH2_METHOD_CRYPT_CS: prefvar = &session->local.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_crypt_methods(); break; case LIBSSH2_METHOD_CRYPT_SC: prefvar = &session->remote.crypt_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_crypt_methods(); break; case LIBSSH2_METHOD_MAC_CS: prefvar = &session->local.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_mac_methods(); break; case LIBSSH2_METHOD_MAC_SC: prefvar = &session->remote.mac_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_mac_methods(); break; case LIBSSH2_METHOD_COMP_CS: prefvar = &session->local.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_comp_methods(session); break; case LIBSSH2_METHOD_COMP_SC: prefvar = &session->remote.comp_prefs; - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_comp_methods(session); break; case LIBSSH2_METHOD_LANG_CS: @@ -4261,6 +4017,11 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, mlist = NULL; break; + case LIBSSH2_METHOD_SIGN_ALGO: + prefvar = &session->sign_algo_prefs; + mlist = NULL; + break; + default: return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type"); @@ -4275,12 +4036,12 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, while(s && *s && mlist) { char *p = strchr(s, ','); - int method_len = p ? (p - s) : (int) strlen(s); + size_t method_len = (p ? (size_t)(p - s) : strlen(s)); if(!kex_get_method_by_name(s, method_len, mlist)) { /* Strip out unsupported method */ if(p) { - memcpy(s, p + 1, strlen(s) - method_len); + memmove(s, p + 1, strlen(s) - method_len); } else { if(s > newprefs) { @@ -4296,7 +4057,7 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, } } - if(strlen(newprefs) == 0) { + if(!*newprefs) { LIBSSH2_FREE(session, newprefs); return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, "The requested method(s) are not currently " @@ -4312,7 +4073,7 @@ libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, } /* - * libssh2_session_supported_algs() + * libssh2_session_supported_algs * returns a number of returned algorithms (a positive number) on success, * a negative number on failure */ @@ -4327,33 +4088,37 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, const LIBSSH2_COMMON_METHOD **mlist; /* to prevent coredumps due to dereferencing of NULL */ - if(NULL == algs) + if(!algs) return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, "algs must not be NULL"); switch(method_type) { case LIBSSH2_METHOD_KEX: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_kex_methods; break; case LIBSSH2_METHOD_HOSTKEY: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_hostkey_methods(); break; case LIBSSH2_METHOD_CRYPT_CS: case LIBSSH2_METHOD_CRYPT_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)libssh2_crypt_methods(); break; case LIBSSH2_METHOD_MAC_CS: case LIBSSH2_METHOD_MAC_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_mac_methods(); break; case LIBSSH2_METHOD_COMP_CS: case LIBSSH2_METHOD_COMP_SC: - mlist = (const LIBSSH2_COMMON_METHOD **) - _libssh2_comp_methods(session); + mlist = (const LIBSSH2_COMMON_METHOD **)_libssh2_comp_methods(session); + break; + + case LIBSSH2_METHOD_SIGN_ALGO: + /* no built-in supported list due to backend support */ + mlist = NULL; break; default: @@ -4362,7 +4127,7 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, } /* switch */ /* weird situation */ - if(NULL == mlist) + if(!mlist) return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "No algorithm found"); @@ -4371,7 +4136,7 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, supported algorithms (needed to allocate the proper size of array) and the second time to actually copy the pointers. Typically this function will not be called often (typically at the beginning of a session) and - the number of algorithms (i.e. niumber of iterations in one loop) will + the number of algorithms (i.e. number of iterations in one loop) will not be high (typically it will not exceed 20) for quite a long time. So double looping really shouldn't be an issue and it is definitely a @@ -4379,28 +4144,28 @@ LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, */ /* count the number of supported algorithms */ - for(i = 0, ialg = 0; NULL != mlist[i]; i++) { + for(i = 0, ialg = 0; mlist[i]; i++) { /* do not count fields with NULL name */ if(mlist[i]->name) ialg++; } /* weird situation, no algorithm found */ - if(0 == ialg) + if(ialg == 0) return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "No algorithm found"); /* allocate buffer */ *algs = (const char **) LIBSSH2_ALLOC(session, ialg*sizeof(const char *)); - if(NULL == *algs) { + if(!*algs) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Memory allocation failed"); } - /* Past this point *algs must be deallocated in case of an error!! */ + /* Past this point *algs must be deallocated in case of an error! */ /* copy non-NULL pointers only */ - for(i = 0, j = 0; NULL != mlist[i] && j < ialg; i++) { - if(NULL == mlist[i]->name) { + for(i = 0, j = 0; mlist[i] && j < ialg; i++) { + if(!mlist[i]->name) { /* maybe a weird situation but if it occurs, do not include NULL pointers */ continue; diff --git a/libs/libssh2/src/knownhost.c b/libs/libssh2/src/knownhost.c index b9dc47a80a..1caab14789 100644 --- a/libs/libssh2/src/knownhost.c +++ b/libs/libssh2/src/knownhost.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2019 by Daniel Stenberg + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,10 +34,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include "misc.h" struct known_host { struct list_node node; @@ -111,7 +112,7 @@ libssh2_knownhost_init(LIBSSH2_SESSION *session) #define KNOWNHOST_MAGIC 0xdeadcafe /* - * knownhost_to_external() + * knownhost_to_external * * Copies data from the internal to the external representation struct. * @@ -123,7 +124,7 @@ static struct libssh2_knownhost *knownhost_to_external(struct known_host *node) ext->magic = KNOWNHOST_MAGIC; ext->node = node; ext->name = ((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == - LIBSSH2_KNOWNHOST_TYPE_PLAIN)? node->name:NULL; + LIBSSH2_KNOWNHOST_TYPE_PLAIN) ? node->name : NULL; ext->key = node->key; ext->typemask = node->typemask; @@ -142,7 +143,7 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, size_t hostlen = strlen(host); int rc; char *ptr; - unsigned int ptrlen; + size_t ptrlen; /* make sure we have a key type set */ if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) @@ -170,15 +171,15 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, entry->name_len = hostlen; break; case LIBSSH2_KNOWNHOST_TYPE_SHA1: - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - host, hostlen); + rc = _libssh2_base64_decode(hosts->session, &ptr, &ptrlen, + host, hostlen); if(rc) goto error; entry->name = ptr; entry->name_len = ptrlen; - rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, - salt, strlen(salt)); + rc = _libssh2_base64_decode(hosts->session, &ptr, &ptrlen, + salt, strlen(salt)); if(rc) goto error; entry->salt = ptr; @@ -252,7 +253,7 @@ knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, *store = knownhost_to_external(entry); return LIBSSH2_ERROR_NONE; - error: +error: free_host(hosts->session, entry); return rc; } @@ -727,7 +728,7 @@ static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * hostline() + * hostline * * Parse a single known_host line pre-split into host and key. * @@ -822,7 +823,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, } /* Figure out host format */ - if((hostlen >2) && memcmp(host, "|1|", 3)) { + if((hostlen > 2) && memcmp(host, "|1|", 3)) { /* old style plain text: [name]([,][name])* for the sake of simplicity, we add them as separate hosts with the @@ -841,7 +842,7 @@ static int hostline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * libssh2_knownhost_readline() + * libssh2_knownhost_readline * * Pass in a line of a file of 'type'. * @@ -955,7 +956,7 @@ libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, { FILE *file; int num = 0; - char buf[2048]; + char buf[4092]; if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) return _libssh2_error(hosts->session, @@ -983,7 +984,7 @@ libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, } /* - * knownhost_writeline() + * knownhost_writeline * * Ask libssh2 to convert a known host to an output line for storage. * @@ -1157,7 +1158,7 @@ knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * libssh2_knownhost_writeline() + * libssh2_knownhost_writeline * * Ask libssh2 to convert a known host to an output line for storage. * @@ -1183,7 +1184,7 @@ libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, } /* - * libssh2_knownhost_writefile() + * libssh2_knownhost_writefile * * Write hosts+key pairs to the given file. */ @@ -1194,7 +1195,7 @@ libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, struct known_host *node; FILE *file; int rc = LIBSSH2_ERROR_NONE; - char buffer[2048]; + char buffer[4092]; /* we only support this single file type for now, bail out on all other attempts */ @@ -1234,7 +1235,7 @@ libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, /* - * libssh2_knownhost_get() + * libssh2_knownhost_get * * Traverse the internal list of known hosts. Pass NULL to 'prev' to get * the first one. diff --git a/libs/libssh2/src/libgcrypt.c b/libs/libssh2/src/libgcrypt.c index 0aff176a61..e463d9e347 100644 --- a/libs/libssh2/src/libgcrypt.c +++ b/libs/libssh2/src/libgcrypt.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2008, 2009, Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,14 +34,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include "libssh2_priv.h" - -#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */ - -#include <string.h> +#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */ +#if LIBSSH2_RSA int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, const unsigned char *edata, @@ -61,17 +60,17 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, const unsigned char *coeffdata, unsigned long coefflen) { int rc; - (void) e1data; - (void) e1len; - (void) e2data; - (void) e2len; + + (void)e1data; + (void)e1len; + (void)e2data; + (void)e2len; if(ddata) { - rc = gcry_sexp_build - (rsa, NULL, - "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))", - nlen, ndata, elen, edata, dlen, ddata, plen, pdata, - qlen, qdata, coefflen, coeffdata); + rc = gcry_sexp_build(rsa, NULL, + "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))", + nlen, ndata, elen, edata, dlen, ddata, plen, pdata, + qlen, qdata, coefflen, coeffdata); } else { rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))", @@ -85,11 +84,12 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, return 0; } +#if LIBSSH2_RSA_SHA1 int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) + size_t sig_len, + const unsigned char *m, size_t m_len) { unsigned char hash[SHA_DIGEST_LENGTH]; gcry_sexp_t s_sig, s_hash; @@ -100,12 +100,12 @@ _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, rc = gcry_sexp_build(&s_hash, NULL, "(data (flags pkcs1) (hash sha1 %b))", SHA_DIGEST_LENGTH, hash); - if(rc != 0) { + if(rc) { return -1; } rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig); - if(rc != 0) { + if(rc) { gcry_sexp_release(s_hash); return -1; } @@ -116,7 +116,10 @@ _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, return (rc == 0) ? 0 : -1; } +#endif +#endif +#if LIBSSH2_DSA int _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, const unsigned char *p, @@ -132,10 +135,9 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, int rc; if(x_len) { - rc = gcry_sexp_build - (dsactx, NULL, - "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", - p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); + rc = gcry_sexp_build(dsactx, NULL, + "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", + p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); } else { rc = gcry_sexp_build(dsactx, NULL, @@ -150,16 +152,23 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, return 0; } +#endif +#if LIBSSH2_RSA int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, const char *filedata, size_t filedata_len, unsigned const char *passphrase) { + (void)rsa; + (void)filedata; + (void)filedata_len; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); + "Unable to extract private key from memory: " + "Method unimplemented in libgcrypt backend"); } int @@ -169,7 +178,7 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, { FILE *fp; unsigned char *data, *save_data; - unsigned int datalen; + size_t datalen; int ret; unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff; unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen; @@ -195,83 +204,91 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, ret = -1; goto fail; } -/* First read Version field (should be 0). */ + + /* First read Version field (should be 0). */ ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if(ret != 0 || (nlen != 1 && *n != '\0')) { + if(ret || (nlen != 1 && *n != '\0')) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } if(_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen, - q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) { + q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) { ret = -1; goto fail; } ret = 0; - fail: +fail: LIBSSH2_FREE(session, save_data); return ret; } +#endif +#if LIBSSH2_DSA int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, LIBSSH2_SESSION * session, const char *filedata, size_t filedata_len, unsigned const char *passphrase) { + (void)dsa; + (void)filedata; + (void)filedata_len; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unimplemented in libgcrypt backend"); + "Unable to extract private key from memory: " + "Method unimplemented in libgcrypt backend"); } int @@ -281,7 +298,7 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, { FILE *fp; unsigned char *data, *save_data; - unsigned int datalen; + size_t datalen; int ret; unsigned char *p, *q, *g, *y, *x; unsigned int plen, qlen, glen, ylen, xlen; @@ -308,44 +325,44 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, goto fail; } -/* First read Version field (should be 0). */ + /* First read Version field (should be 0). */ ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0 || (plen != 1 && *p != '\0')) { + if(ret || (plen != 1 && *p != '\0')) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen); - if(ret != 0) { + if(ret) { ret = -1; goto fail; } - if(datalen != 0) { + if(datalen) { ret = -1; goto fail; } @@ -357,11 +374,14 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, ret = 0; - fail: +fail: LIBSSH2_FREE(session, save_data); return ret; } +#endif +#if LIBSSH2_RSA +#if LIBSSH2_RSA_SHA1 int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, libssh2_rsa_ctx * rsactx, @@ -380,8 +400,8 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, } if(gcry_sexp_build(&data, NULL, - "(data (flags pkcs1) (hash sha1 %b))", - hash_len, hash)) { + "(data (flags pkcs1) (hash sha1 %b))", + hash_len, hash)) { return -1; } @@ -389,7 +409,7 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, gcry_sexp_release(data); - if(rc != 0) { + if(rc) { return -1; } @@ -421,11 +441,14 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, return rc; } +#endif +#endif +#if LIBSSH2_DSA int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, - unsigned long hash_len, unsigned char *sig) + size_t hash_len, unsigned char *sig) { unsigned char zhash[SHA_DIGEST_LENGTH + 1]; gcry_sexp_t sig_sexp; @@ -442,7 +465,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, zhash[0] = 0; if(gcry_sexp_build(&data, NULL, "(data (value %b))", - hash_len + 1, zhash)) { + (int)(hash_len + 1), zhash)) { return -1; } @@ -450,13 +473,13 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, gcry_sexp_release(data); - if(ret != 0) { + if(ret) { return -1; } memset(sig, 0, 40); -/* Extract R. */ + /* Extract R. */ data = gcry_sexp_find_token(sig_sexp, "r", 0); if(!data) @@ -478,7 +501,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, gcry_sexp_release(data); -/* Extract S. */ + /* Extract S. */ data = gcry_sexp_find_token(sig_sexp, "s", 0); if(!data) @@ -499,10 +522,10 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, memcpy(sig + 20 + (20 - size), tmp, size); goto out; - err: +err: ret = -1; - out: +out: if(sig_sexp) { gcry_sexp_release(sig_sexp); } @@ -515,7 +538,7 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, const unsigned char *sig, - const unsigned char *m, unsigned long m_len) + const unsigned char *m, size_t m_len) { unsigned char hash[SHA_DIGEST_LENGTH + 1]; gcry_sexp_t s_sig, s_hash; @@ -525,12 +548,12 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, hash[0] = 0; if(gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))", - SHA_DIGEST_LENGTH + 1, hash)) { + SHA_DIGEST_LENGTH + 1, hash)) { return -1; } if(gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))", - 20, sig, 20, sig + 20)) { + 20, sig, 20, sig + 20)) { gcry_sexp_release(s_hash); return -1; } @@ -541,6 +564,7 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, return (rc == 0) ? 0 : -1; } +#endif int _libssh2_cipher_init(_libssh2_cipher_ctx * h, @@ -550,9 +574,9 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, int ret; int cipher = _libssh2_gcry_cipher(algo); int mode = _libssh2_gcry_mode(algo); - int keylen = gcry_cipher_get_algo_keylen(cipher); + size_t keylen = gcry_cipher_get_algo_keylen(cipher); - (void) encrypt; + (void)encrypt; ret = gcry_cipher_open(h, cipher, mode, 0); if(ret) { @@ -566,7 +590,7 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, } if(mode != GCRY_CIPHER_MODE_STREAM) { - int blklen = gcry_cipher_get_algo_blklen(cipher); + size_t blklen = gcry_cipher_get_algo_blklen(cipher); if(mode == GCRY_CIPHER_MODE_CTR) ret = gcry_cipher_setctr(*h, iv, blklen); else @@ -583,11 +607,14 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blklen) + int encrypt, unsigned char *block, size_t blklen, + int firstlast) { - int cipher = _libssh2_gcry_cipher(algo); int ret; + (void)algo; + (void)firstlast; + if(encrypt) { ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen); } @@ -607,6 +634,14 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, size_t privatekeydata_len, const char *passphrase) { + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)privatekeydata; + (void)privatekeydata_len; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, "Unable to extract public key from private " "key in memory: " @@ -622,9 +657,49 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, const char *privatekey, const char *passphrase) { + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)privatekey; + (void)passphrase; + + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key from private key file: " + "Method unimplemented in libgcrypt backend"); +} + +int +_libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)algorithm; + (void)flags; + (void)application; + (void)key_handle; + (void)handle_len; + (void)privatekeydata; + (void)privatekeydata_len; + (void)passphrase; + return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key from private key file: " - "Method unimplemented in libgcrypt backend"); + "Unable to extract public SK key from private key file: " + "Method unimplemented in libgcrypt backend"); } void _libssh2_init_aes_ctr(void) @@ -664,4 +739,22 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) *dhctx = NULL; } -#endif /* LIBSSH2_LIBGCRYPT */ +/* _libssh2_supported_key_sign_algorithms + * + * Return supported key hash algo upgrades, see crypto.h + * + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len) +{ + (void)session; + (void)key_method; + (void)key_method_len; + + return NULL; +} + +#endif /* LIBSSH2_CRYPTO_C */ diff --git a/libs/libssh2/src/libgcrypt.h b/libs/libssh2/src/libgcrypt.h index ec88aded62..77a1b8aba3 100644 --- a/libs/libssh2/src/libgcrypt.h +++ b/libs/libssh2/src/libgcrypt.h @@ -1,6 +1,8 @@ +#ifndef __LIBSSH2_LIBGCRYPT_H +#define __LIBSSH2_LIBGCRYPT_H /* - * Copyright (C) 2008, 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007, The Written Word, Inc. + * Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,8 +37,12 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +#define LIBSSH2_CRYPTO_ENGINE libssh2_gcrypt + #include <gcrypt.h> #define LIBSSH2_MD5 1 @@ -45,17 +51,20 @@ #define LIBSSH2_HMAC_SHA256 1 #define LIBSSH2_HMAC_SHA512 1 -#define LIBSSH2_AES 1 +#define LIBSSH2_AES_CBC 1 #define LIBSSH2_AES_CTR 1 +#define LIBSSH2_AES_GCM 1 #define LIBSSH2_BLOWFISH 1 #define LIBSSH2_RC4 1 #define LIBSSH2_CAST 1 #define LIBSSH2_3DES 1 #define LIBSSH2_RSA 1 +#define LIBSSH2_RSA_SHA1 1 +#define LIBSSH2_RSA_SHA2 1 #define LIBSSH2_DSA 1 -#define LIBSSH2_ECDSA 0 -#define LIBSSH2_ED25519 0 +#define LIBSSH2_ECDSA 1 +#define LIBSSH2_ED25519 1 #define MD5_DIGEST_LENGTH 16 #define SHA_DIGEST_LENGTH 20 @@ -65,8 +74,8 @@ #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) -#define _libssh2_random(buf, len) \ - (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1) +#define _libssh2_random(buf, len) \ + (gcry_randomize((buf), (len), GCRY_STRONG_RANDOM), 0) #define libssh2_prepare_iovec(vec, len) /* Empty. */ @@ -74,94 +83,94 @@ /* returns 0 in case of failure */ #define libssh2_sha1_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA1, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA1, 0)) #define libssh2_sha1_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + gcry_md_write(ctx, (unsigned char *) data, len) #define libssh2_sha1_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close(ctx) + memcpy(out, gcry_md_read(ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close(ctx) #define libssh2_sha1(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA1, out, message, len) + gcry_md_hash_buffer(GCRY_MD_SHA1, out, message, len) #define libssh2_sha256_ctx gcry_md_hd_t #define libssh2_sha256_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA256, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA256, 0)) #define libssh2_sha256_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + gcry_md_write(ctx, (unsigned char *) data, len) #define libssh2_sha256_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA256_DIGEST_LENGTH), gcry_md_close(ctx) + memcpy(out, gcry_md_read(ctx, 0), SHA256_DIGEST_LENGTH), gcry_md_close(ctx) #define libssh2_sha256(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA256, out, message, len) + gcry_md_hash_buffer(GCRY_MD_SHA256, out, message, len) #define libssh2_sha384_ctx gcry_md_hd_t #define libssh2_sha384_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA384, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA384, 0)) #define libssh2_sha384_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + gcry_md_write(ctx, (unsigned char *) data, len) #define libssh2_sha384_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA384_DIGEST_LENGTH), gcry_md_close(ctx) + memcpy(out, gcry_md_read(ctx, 0), SHA384_DIGEST_LENGTH), gcry_md_close(ctx) #define libssh2_sha384(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA384, out, message, len) + gcry_md_hash_buffer(GCRY_MD_SHA384, out, message, len) #define libssh2_sha512_ctx gcry_md_hd_t #define libssh2_sha512_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA512, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_SHA512, 0)) #define libssh2_sha512_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + gcry_md_write(ctx, (unsigned char *) data, len) #define libssh2_sha512_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), SHA512_DIGEST_LENGTH), gcry_md_close(ctx) + memcpy(out, gcry_md_read(ctx, 0), SHA512_DIGEST_LENGTH), gcry_md_close(ctx) #define libssh2_sha512(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_SHA512, out, message, len) + gcry_md_hash_buffer(GCRY_MD_SHA512, out, message, len) #define libssh2_md5_ctx gcry_md_hd_t /* returns 0 in case of failure */ #define libssh2_md5_init(ctx) \ - (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_MD5, 0)) + (GPG_ERR_NO_ERROR == gcry_md_open(ctx, GCRY_MD_MD5, 0)) #define libssh2_md5_update(ctx, data, len) \ - gcry_md_write(ctx, (unsigned char *) data, len) + gcry_md_write(ctx, (unsigned char *) data, len) #define libssh2_md5_final(ctx, out) \ - memcpy(out, gcry_md_read(ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close(ctx) + memcpy(out, gcry_md_read(ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close(ctx) #define libssh2_md5(message, len, out) \ - gcry_md_hash_buffer(GCRY_MD_MD5, out, message, len) + gcry_md_hash_buffer(GCRY_MD_MD5, out, message, len) #define libssh2_hmac_ctx gcry_md_hd_t #define libssh2_hmac_ctx_init(ctx) #define libssh2_hmac_sha1_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \ + gcry_md_open(ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \ gcry_md_setkey(*ctx, key, keylen) #define libssh2_hmac_md5_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \ + gcry_md_open(ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \ gcry_md_setkey(*ctx, key, keylen) #define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \ + gcry_md_open(ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \ gcry_md_setkey(*ctx, key, keylen) #define libssh2_hmac_sha256_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC), \ + gcry_md_open(ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC), \ gcry_md_setkey(*ctx, key, keylen) #define libssh2_hmac_sha512_init(ctx, key, keylen) \ - gcry_md_open(ctx, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC), \ + gcry_md_open(ctx, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC), \ gcry_md_setkey(*ctx, key, keylen) #define libssh2_hmac_update(ctx, data, datalen) \ - gcry_md_write(ctx, (unsigned char *) data, datalen) + gcry_md_write(ctx, (unsigned char *) data, datalen) #define libssh2_hmac_final(ctx, data) \ - memcpy(data, gcry_md_read(ctx, 0), \ - gcry_md_get_algo_dlen(gcry_md_get_algo(ctx))) -#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx); + memcpy(data, gcry_md_read(ctx, 0), \ + gcry_md_get_algo_dlen(gcry_md_get_algo(ctx))) +#define libssh2_hmac_cleanup(ctx) gcry_md_close(*ctx) -#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM) +#define libssh2_crypto_init() gcry_control(GCRYCTL_DISABLE_SECMEM) #define libssh2_crypto_exit() #define libssh2_rsa_ctx struct gcry_sexp -#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx) +#define _libssh2_rsa_free(rsactx) gcry_sexp_release(rsactx) #define libssh2_dsa_ctx struct gcry_sexp -#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx) +#define _libssh2_dsa_free(dsactx) gcry_sexp_release(dsactx) #if LIBSSH2_ECDSA #else @@ -176,25 +185,25 @@ #define _libssh2_gcry_mode(m) (m & 0xFF) #define _libssh2_cipher_aes256ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) #define _libssh2_cipher_aes192ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) #define _libssh2_cipher_aes128ctr \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) #define _libssh2_cipher_aes256 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_aes192 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_aes128 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_blowfish \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_arcfour \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM) + _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM) #define _libssh2_cipher_cast5 \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_3des \ - _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC) + _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx)) @@ -204,26 +213,35 @@ #define _libssh2_bn_ctx_new() 0 #define _libssh2_bn_ctx_free(bnctx) ((void)0) #define _libssh2_bn_init() gcry_mpi_new(0) -#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a - new bignum */ +#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a + new bignum */ #define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) \ +#define _libssh2_bn_from_bin(bn, len, val) \ gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL) -#define _libssh2_bn_to_bin(bn, val) \ +#define _libssh2_bn_to_bin(bn, val) \ gcry_mpi_print(GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn) -#define _libssh2_bn_bytes(bn) \ - (gcry_mpi_get_nbits (bn) / 8 + \ - ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1)) -#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn) +#define _libssh2_bn_bytes(bn) \ + (gcry_mpi_get_nbits(bn) / 8 + \ + ((gcry_mpi_get_nbits(bn) % 8 == 0) ? 0 : 1)) +#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits(bn) #define _libssh2_bn_free(bn) gcry_mpi_release(bn) +/* Default generate and safe prime sizes for + diffie-hellman-group-exchange-sha1 */ +#define LIBSSH2_DH_GEX_MINGROUP 2048 +#define LIBSSH2_DH_GEX_OPTGROUP 4096 +#define LIBSSH2_DH_GEX_MAXGROUP 8192 + +#define LIBSSH2_DH_MAX_MODULUS_BITS 16384 + #define _libssh2_dh_ctx struct gcry_mpi * #define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) #define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) + _libssh2_dh_key_pair(dhctx, public, g, p, group_order) #define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) + _libssh2_dh_secret(dhctx, secret, f, p) #define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) +extern void _libssh2_init_aes_ctr(void); extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, _libssh2_bn *g, _libssh2_bn *p, @@ -232,3 +250,4 @@ extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, _libssh2_bn *f, _libssh2_bn *p); extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); +#endif /* __LIBSSH2_LIBGCRYPT_H */ diff --git a/libs/libssh2/src/libssh2.pc.in b/libs/libssh2/src/libssh2.pc.in deleted file mode 100644 index c070988b93..0000000000 --- a/libs/libssh2/src/libssh2.pc.in +++ /dev/null @@ -1,17 +0,0 @@ -########################################################################### -# libssh2 installation details -########################################################################### - -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ -includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ - -Name: @PROJECT_NAME@ -URL: @PROJECT_URL@ -Description: @PROJECT_DESCRIPTION@ -Version: @LIBSSH2_VERSION@ -Requires.private: @PC_REQUIRES_PRIVATE@ -Libs: -L${libdir} -lssh2 @PC_LIBS@ -Libs.private: @PC_LIBS@ -Cflags: -I${includedir}
\ No newline at end of file diff --git a/libs/libssh2/src/libssh2.rc b/libs/libssh2/src/libssh2.rc new file mode 100644 index 0000000000..4862d78eef --- /dev/null +++ b/libs/libssh2/src/libssh2.rc @@ -0,0 +1,48 @@ +/*************************************************************************** +* libssh2 Windows resource file +* Copyright (C) The libssh2 project and its contributors. +* +* SPDX-License-Identifier: BSD-3-Clause +***************************************************************************/ +#include <winver.h> +#include "libssh2.h" + +LANGUAGE 0, 0 + +#define RC_VERSION LIBSSH2_VERSION_MAJOR, LIBSSH2_VERSION_MINOR, LIBSSH2_VERSION_PATCH, 0 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RC_VERSION + PRODUCTVERSION RC_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#if defined(LIBSSH2DEBUG) || defined(_DEBUG) + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0 +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* 0x0409: en-US, 1200/0x04b0: UTF-16LE */ + BEGIN + VALUE "CompanyName", "The libssh2 library, https://www.libssh2.org/\0" + VALUE "FileDescription", "libssh2 Shared Library\0" + VALUE "FileVersion", LIBSSH2_VERSION "\0" + VALUE "InternalName", "libssh2\0" + VALUE "OriginalFilename", "libssh2.dll\0" + VALUE "ProductName", "The libssh2 library\0" + VALUE "ProductVersion", LIBSSH2_VERSION "\0" + VALUE "LegalCopyright", "Copyright (C) " LIBSSH2_COPYRIGHT "\0" + VALUE "License", "https://www.libssh2.org/license.html\0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 0x04b0 /* 0x0409: en-US, 1200/0x04b0: UTF-16LE */ + END +END diff --git a/libs/libssh2/src/libssh2_config.h b/libs/libssh2/src/libssh2_config.h index c2e98356a4..c62f637693 100644 --- a/libs/libssh2/src/libssh2_config.h +++ b/libs/libssh2/src/libssh2_config.h @@ -25,6 +25,7 @@ #define HAVE_SELECT #define LIBSSH2_OPENSSL +#define LIBSSH2_CRYPTO_C #ifdef _MSC_VER #if _MSC_VER < 1900 diff --git a/libs/libssh2/src/libssh2_config_cmake.h.in b/libs/libssh2/src/libssh2_config_cmake.h.in index 62723ede84..515bfafb48 100644 --- a/libs/libssh2/src/libssh2_config_cmake.h.in +++ b/libs/libssh2/src/libssh2_config_cmake.h.in @@ -1,5 +1,6 @@ -/* Copyright (c) 2014 Alexander Lamaison <alexander.lamaison@gmail.com> - * Copyright (c) 1999-2011 Douglas Gilbert. All rights reserved. +/* Copyright (C) Alexander Lamaison <alexander.lamaison@gmail.com> + * Copyright (C) Douglas Gilbert + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -33,73 +34,44 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* Headers */ #cmakedefine HAVE_UNISTD_H #cmakedefine HAVE_INTTYPES_H -#cmakedefine HAVE_STDLIB_H #cmakedefine HAVE_SYS_SELECT_H #cmakedefine HAVE_SYS_UIO_H #cmakedefine HAVE_SYS_SOCKET_H #cmakedefine HAVE_SYS_IOCTL_H #cmakedefine HAVE_SYS_TIME_H #cmakedefine HAVE_SYS_UN_H -#cmakedefine HAVE_WINDOWS_H -#cmakedefine HAVE_WS2TCPIP_H -#cmakedefine HAVE_WINSOCK2_H -#cmakedefine HAVE_NTDEF_H -#cmakedefine HAVE_NTSTATUS_H - -/* Libraries */ -#cmakedefine HAVE_LIBCRYPT32 -/* Types */ -#cmakedefine HAVE_LONGLONG +/* for example and tests */ +#cmakedefine HAVE_SYS_PARAM_H +#cmakedefine HAVE_ARPA_INET_H +#cmakedefine HAVE_NETINET_IN_H /* Functions */ #cmakedefine HAVE_GETTIMEOFDAY -#cmakedefine HAVE_INET_ADDR -#cmakedefine HAVE_POLL -#cmakedefine HAVE_SELECT -#cmakedefine HAVE_SOCKET #cmakedefine HAVE_STRTOLL #cmakedefine HAVE_STRTOI64 #cmakedefine HAVE_SNPRINTF +#cmakedefine HAVE_EXPLICIT_BZERO +#cmakedefine HAVE_EXPLICIT_MEMSET +#cmakedefine HAVE_MEMSET_S -/* OpenSSL functions */ -#cmakedefine HAVE_EVP_AES_128_CTR +#cmakedefine HAVE_POLL +#cmakedefine HAVE_SELECT /* Socket non-blocking support */ #cmakedefine HAVE_O_NONBLOCK #cmakedefine HAVE_FIONBIO -#cmakedefine HAVE_IOCTLSOCKET #cmakedefine HAVE_IOCTLSOCKET_CASE #cmakedefine HAVE_SO_NONBLOCK -#cmakedefine HAVE_DISABLED_NONBLOCKING - -/* snprintf not in Visual Studio CRT and _snprintf dangerously incompatible. - We provide a safe wrapper if snprintf not found */ -#ifndef HAVE_SNPRINTF -#include <stdio.h> -#include <stdarg.h> -/* Want safe, 'n += snprintf(b + n ...)' like function. If cp_max_len is 1 -* then assume cp is pointing to a null char and do nothing. Returns number -* number of chars placed in cp excluding the trailing null char. So for -* cp_max_len > 0 the return value is always < cp_max_len; for cp_max_len -* <= 0 the return value is 0 (and no chars are written to cp). */ -static int snprintf(char * cp, int cp_max_len, const char * fmt, ...) -{ - va_list args; - int n; - - if (cp_max_len < 2) - return 0; - va_start(args, fmt); - n = vsnprintf(cp, cp_max_len, fmt, args); - va_end(args); - return (n < cp_max_len) ? n : (cp_max_len - 1); -} -#define HAVE_SNPRINTF +/* attribute to export symbol */ +#if defined(LIBSSH2_EXPORTS) && defined(LIBSSH2_LIBRARY) +#cmakedefine LIBSSH2_API ${LIBSSH2_API} #endif diff --git a/libs/libssh2/src/libssh2_priv.h b/libs/libssh2/src/libssh2_priv.h index 33c5ad3f87..96af134279 100644 --- a/libs/libssh2/src/libssh2_priv.h +++ b/libs/libssh2/src/libssh2_priv.h @@ -1,6 +1,8 @@ -/* Copyright (c) 2004-2008, 2010, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2009-2014 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson +#ifndef __LIBSSH2_PRIV_H +#define __LIBSSH2_PRIV_H +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,28 +37,21 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef LIBSSH2_PRIV_H -#define LIBSSH2_PRIV_H 1 +/* Header used by 'src' */ #define LIBSSH2_LIBRARY -#include "libssh2_config.h" -#ifdef HAVE_WINDOWS_H -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include <windows.h> -#undef WIN32_LEAN_AND_MEAN -#endif - -#ifdef HAVE_WS2TCPIP_H -#include <ws2tcpip.h> -#endif +/* platform/compiler-specific setup */ +#include "libssh2_setup.h" #include <stdio.h> +#include <string.h> #include <time.h> +#include <limits.h> /* The following CPP block should really only be in session.c and packet.c. However, AIX have #define's for 'events' and 'revents' and we are using @@ -67,15 +62,8 @@ */ #ifdef HAVE_POLL # include <poll.h> -#else -# if defined(HAVE_SELECT) && !defined(WIN32) -# ifdef HAVE_SYS_SELECT_H +#elif defined(HAVE_SELECT) && defined(HAVE_SYS_SELECT_H) # include <sys/select.h> -# else -# include <sys/time.h> -# include <sys/types.h> -# endif -# endif #endif /* Needed for struct iovec on some platforms */ @@ -84,10 +72,10 @@ #endif #ifdef HAVE_SYS_SOCKET_H -# include <sys/socket.h> +#include <sys/socket.h> #endif #ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> +#include <sys/ioctl.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> @@ -96,7 +84,7 @@ #include "libssh2.h" #include "libssh2_publickey.h" #include "libssh2_sftp.h" -#include "misc.h" /* for the linked list stuff */ +#include "misc.h" #ifndef FALSE #define FALSE 0 @@ -105,29 +93,42 @@ #define TRUE 1 #endif -#ifdef _MSC_VER +/* Use local implementation when not available */ +#if !defined(HAVE_SNPRINTF) +#undef snprintf +#define snprintf _libssh2_snprintf +#define LIBSSH2_SNPRINTF +int _libssh2_snprintf(char *cp, size_t cp_max_len, const char *fmt, ...); +#endif + +#if !defined(HAVE_GETTIMEOFDAY) +#define HAVE_GETTIMEOFDAY +#undef gettimeofday +#define gettimeofday _libssh2_gettimeofday +#define LIBSSH2_GETTIMEOFDAY +int _libssh2_gettimeofday(struct timeval *tp, void *tzp); +#elif defined(HAVE_SYS_TIME_H) +#include <sys/time.h> +#endif + /* "inline" keyword is valid only with C++ engine! */ +#ifdef __GNUC__ +#undef inline +#define inline __inline__ +#elif defined(_MSC_VER) +#undef inline #define inline __inline #endif -/* Provide iovec / writev on WIN32 platform. */ -#ifdef WIN32 +/* 3DS doesn't seem to have iovec */ +#if defined(WIN32) || defined(_3DS) struct iovec { size_t iov_len; void *iov_base; }; -static inline int writev(int sock, struct iovec *iov, int nvecs) -{ - DWORD ret; - if(WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) { - return ret; - } - return -1; -} - -#endif /* WIN32 */ +#endif #ifdef __OS400__ /* Force parameter type. */ @@ -136,13 +137,6 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #include "crypto.h" -#ifdef HAVE_WINSOCK2_H - -#include <winsock2.h> -#include <ws2tcpip.h> - -#endif - #ifndef SIZE_MAX #if _WIN64 #define SIZE_MAX 0xFFFFFFFFFFFFFFFF @@ -155,6 +149,9 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #define UINT_MAX 0xFFFFFFFF #endif +#define LIBSSH2_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define LIBSSH2_MIN(x, y) ((x) < (y) ? (x) : (y)) + /* RFC4253 section 6.1 Maximum Packet Length says: * * "All implementations MUST be able to process packets with @@ -166,33 +163,51 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #define MAX_SHA_DIGEST_LEN SHA512_DIGEST_LENGTH #define LIBSSH2_ALLOC(session, count) \ - session->alloc((count), &(session)->abstract) + session->alloc((count), &(session)->abstract) #define LIBSSH2_CALLOC(session, count) _libssh2_calloc(session, count) #define LIBSSH2_REALLOC(session, ptr, count) \ - ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : \ - session->alloc((count), &(session)->abstract)) + ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : \ + session->alloc((count), &(session)->abstract)) #define LIBSSH2_FREE(session, ptr) \ - session->free((ptr), &(session)->abstract) + session->free((ptr), &(session)->abstract) #define LIBSSH2_IGNORE(session, data, datalen) \ - session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract) + session->ssh_msg_ignore((session), (data), (int)(datalen), \ + &(session)->abstract) #define LIBSSH2_DEBUG(session, always_display, message, message_len, \ - language, language_len) \ - session->ssh_msg_debug((session), (always_display), (message), \ - (message_len), (language), (language_len), \ + language, language_len) \ + session->ssh_msg_debug((session), (always_display), \ + (message), (int)(message_len), \ + (language), (int)(language_len), \ &(session)->abstract) #define LIBSSH2_DISCONNECT(session, reason, message, message_len, \ - language, language_len) \ - session->ssh_msg_disconnect((session), (reason), (message), \ - (message_len), (language), (language_len), \ + language, language_len) \ + session->ssh_msg_disconnect((session), (reason), \ + (message), (int)(message_len), \ + (language), (int)(language_len), \ &(session)->abstract) -#define LIBSSH2_MACERROR(session, data, datalen) \ - session->macerror((session), (data), (datalen), &(session)->abstract) -#define LIBSSH2_X11_OPEN(channel, shost, sport) \ +#define LIBSSH2_MACERROR(session, data, datalen) \ + session->macerror((session), (data), (int)(datalen), &(session)->abstract) +#define LIBSSH2_X11_OPEN(channel, shost, sport) \ channel->session->x11(((channel)->session), (channel), \ (shost), (sport), (&(channel)->session->abstract)) -#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ +#define LIBSSH2_AUTHAGENT(channel) \ + channel->session->authagent(((channel)->session), (channel), \ + (&(channel)->session->abstract)) + +#define LIBSSH2_ADD_IDENTITIES(session, buffer, agentPath) \ + session->addLocalIdentities((session), (buffer), \ + (agentPath), (&(session->abstract))) + +#define LIBSSH2_AUTHAGENT_SIGN(session, blob, blen, \ + data, dlen, sig, sigLen, \ + agentPath) \ + session->agentSignCallback((session), (blob), (blen), \ + (data), (dlen), (sig), (sigLen), \ + (agentPath), (&(session->abstract))) + +#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ channel->close_cb((session), &(session)->abstract, \ (channel), &(channel)->abstract) @@ -201,9 +216,9 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #define LIBSSH2_RECV_FD(session, fd, buffer, length, flags) \ (session->recv)(fd, buffer, length, flags, &session->abstract) -#define LIBSSH2_SEND(session, buffer, length, flags) \ +#define LIBSSH2_SEND(session, buffer, length, flags) \ LIBSSH2_SEND_FD(session, session->socket_fd, buffer, length, flags) -#define LIBSSH2_RECV(session, buffer, length, flags) \ +#define LIBSSH2_RECV(session, buffer, length, flags) \ LIBSSH2_RECV_FD(session, session->socket_fd, buffer, length, flags) typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD; @@ -231,7 +246,9 @@ typedef enum libssh2_NB_state_jump3, libssh2_NB_state_jump4, libssh2_NB_state_jump5, - libssh2_NB_state_end + libssh2_NB_state_error_closing, + libssh2_NB_state_end, + libssh2_NB_state_jumpauthagent } libssh2_nonblocking_states; typedef struct packet_require_state_t @@ -337,6 +354,24 @@ typedef struct packet_x11_open_state_t LIBSSH2_CHANNEL *channel; } packet_x11_open_state_t; +#define AuthAgentUnavail "Auth Agent unavailable" + +typedef struct packet_authagent_state_t +{ + libssh2_nonblocking_states state; + unsigned char packet[17 + (sizeof(AuthAgentUnavail) - 1)]; + uint32_t sender_channel; + uint32_t initial_window_size; + uint32_t packet_size; + LIBSSH2_CHANNEL *channel; +} packet_authagent_state_t; + +typedef enum +{ + libssh2_requires_size_decryption = (1 << 0), + libssh2_requires_size_field_in_packet = (1 << 1) +} libssh2_crypt_flags; + struct _LIBSSH2_PACKET { struct list_node node; /* linked list header */ @@ -379,7 +414,7 @@ struct _LIBSSH2_CHANNEL /* Amount of bytes to be refunded to receive window (but not yet sent) */ uint32_t adjust_queue; /* Data immediately available for reading */ - uint32_t read_avail; + size_t read_avail; LIBSSH2_SESSION *session; @@ -452,6 +487,18 @@ struct _LIBSSH2_CHANNEL /* State variables used in libssh2_channel_handle_extended_data2() */ libssh2_nonblocking_states extData2_state; + /* State variables used in libssh2_channel_request_auth_agent() */ + libssh2_nonblocking_states req_auth_agent_try_state; + libssh2_nonblocking_states req_auth_agent_state; + unsigned char req_auth_agent_packet[36]; + size_t req_auth_agent_packet_len; + unsigned char req_auth_agent_local_channel[4]; + packet_requirev_state_t req_auth_agent_requirev_state; + + /* State variables used in libssh2_channel_signal_ex() */ + libssh2_nonblocking_states sendsignal_state; + unsigned char *sendsignal_packet; + size_t sendsignal_packet_len; }; struct _LIBSSH2_LISTENER @@ -499,7 +546,7 @@ typedef struct _libssh2_endpoint_data char *lang_prefs; } libssh2_endpoint_data; -#define PACKETBUFSIZE (1024*16) +#define PACKETBUFSIZE MAX_SSH_PACKET_LEN struct transportpacket { @@ -522,14 +569,15 @@ struct transportpacket packet_length + padding_length + 4 + mac_length. */ unsigned char *payload; /* this is a pointer to a LIBSSH2_ALLOC() - area to which we write decrypted data */ + area to which we write incoming packet data + which is not yet decrypted in etm mode. */ unsigned char *wptr; /* write pointer into the payload to where we are currently writing decrypted data */ /* ------------- for outgoing data --------------- */ unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */ - int ototal_num; /* size of outbuf in number of bytes */ + ssize_t ototal_num; /* size of outbuf in number of bytes */ const unsigned char *odata; /* original pointer to the data */ size_t olen; /* original size of the data we stored in outbuf */ @@ -567,26 +615,31 @@ struct _LIBSSH2_PUBLICKEY #define LIBSSH2_SCP_RESPONSE_BUFLEN 256 struct flags { - int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */ - int compress; /* LIBSSH2_FLAG_COMPRESS */ + int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */ + int compress; /* LIBSSH2_FLAG_COMPRESS */ + int quote_paths; /* LIBSSH2_FLAG_QUOTE_PATHS */ }; struct _LIBSSH2_SESSION { /* Memory management callbacks */ void *abstract; - LIBSSH2_ALLOC_FUNC((*alloc)); - LIBSSH2_REALLOC_FUNC((*realloc)); - LIBSSH2_FREE_FUNC((*free)); + + LIBSSH2_ALLOC_FUNC((*alloc)); + LIBSSH2_REALLOC_FUNC((*realloc)); + LIBSSH2_FREE_FUNC((*free)); /* Other callbacks */ - LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore)); - LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); - LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); - LIBSSH2_MACERROR_FUNC((*macerror)); - LIBSSH2_X11_OPEN_FUNC((*x11)); - LIBSSH2_SEND_FUNC((*send)); - LIBSSH2_RECV_FUNC((*recv)); + LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore)); + LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); + LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); + LIBSSH2_MACERROR_FUNC((*macerror)); + LIBSSH2_X11_OPEN_FUNC((*x11)); + LIBSSH2_AUTHAGENT_FUNC((*authagent)); + LIBSSH2_ADD_IDENTITIES_FUNC((*addLocalIdentities)); + LIBSSH2_AUTHAGENT_SIGN_FUNC((*agentSignCallback)); + LIBSSH2_SEND_FUNC((*send)); + LIBSSH2_RECV_FUNC((*recv)); /* Method preferences -- NULL yields "load order" */ char *kex_prefs; @@ -599,7 +652,7 @@ struct _LIBSSH2_SESSION /* Agreed Key Exchange Method */ const LIBSSH2_KEX_METHOD *kex; - unsigned int burn_optimistic_kexinit:1; + unsigned int burn_optimistic_kexinit; unsigned char *session_id; uint32_t session_id_len; @@ -622,13 +675,19 @@ struct _LIBSSH2_SESSION #if LIBSSH2_MD5 unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH]; int server_hostkey_md5_valid; -#endif /* ! LIBSSH2_MD5 */ +#endif /* ! LIBSSH2_MD5 */ unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH]; int server_hostkey_sha1_valid; unsigned char server_hostkey_sha256[SHA256_DIGEST_LENGTH]; int server_hostkey_sha256_valid; + /* public key algorithms accepted as comma separated list */ + char *server_sign_algorithms; + + /* key signing algorithm preferences -- NULL yields server order */ + char *sign_algo_prefs; + /* (remote as source of data -- packet_read ) */ libssh2_endpoint_data remote; @@ -702,6 +761,7 @@ struct _LIBSSH2_SESSION libssh2_nonblocking_states userauth_list_state; unsigned char *userauth_list_data; size_t userauth_list_data_len; + char *userauth_banner; packet_requirev_state_t userauth_list_packet_requirev_state; /* State variables used in libssh2_userauth_password_ex() */ @@ -742,10 +802,10 @@ struct _LIBSSH2_SESSION size_t userauth_kybd_data_len; unsigned char *userauth_kybd_packet; size_t userauth_kybd_packet_len; - unsigned int userauth_kybd_auth_name_len; - char *userauth_kybd_auth_name; - unsigned userauth_kybd_auth_instruction_len; - char *userauth_kybd_auth_instruction; + size_t userauth_kybd_auth_name_len; + unsigned char *userauth_kybd_auth_name; + size_t userauth_kybd_auth_instruction_len; + unsigned char *userauth_kybd_auth_instruction; unsigned int userauth_kybd_num_prompts; int userauth_kybd_auth_failure; LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts; @@ -792,6 +852,7 @@ struct _LIBSSH2_SESSION states */ packet_queue_listener_state_t packAdd_Qlstn_state; packet_x11_open_state_t packAdd_x11open_state; + packet_authagent_state_t packAdd_authagent_state; /* State variables used in fullpacket() */ libssh2_nonblocking_states fullpacket_state; @@ -805,8 +866,8 @@ struct _LIBSSH2_SESSION LIBSSH2_CHANNEL *sftpInit_channel; unsigned char sftpInit_buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */ - int sftpInit_sent; /* number of bytes from the buffer that have been - sent */ + size_t sftpInit_sent; /* number of bytes from the buffer that have been + sent */ /* State variables used in libssh2_scp_recv() / libssh_scp_recv2() */ libssh2_nonblocking_states scpRecv_state; @@ -815,17 +876,7 @@ struct _LIBSSH2_SESSION unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; size_t scpRecv_response_len; long scpRecv_mode; -#if defined(HAVE_LONGLONG) && defined(HAVE_STRTOLL) - /* we have the type and we can parse such numbers */ - long long scpRecv_size; -#define scpsize_strtol strtoll -#elif defined(HAVE_STRTOI64) - __int64 scpRecv_size; -#define scpsize_strtol _strtoi64 -#else - long scpRecv_size; -#define scpsize_strtol strtol -#endif + libssh2_int64_t scpRecv_size; long scpRecv_mtime; long scpRecv_atime; LIBSSH2_CHANNEL *scpRecv_channel; @@ -842,6 +893,9 @@ struct _LIBSSH2_SESSION int keepalive_interval; int keepalive_want_reply; time_t keepalive_last_sent; + + /* Configurable timeout for packets. Replaces LIBSSH2_READ_TIMEOUT */ + long packet_read_timeout; }; /* session.state bits */ @@ -852,9 +906,9 @@ struct _LIBSSH2_SESSION /* session.flag helpers */ #ifdef MSG_NOSIGNAL -#define LIBSSH2_SOCKET_SEND_FLAGS(session) \ +#define LIBSSH2_SOCKET_SEND_FLAGS(session) \ (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) -#define LIBSSH2_SOCKET_RECV_FLAGS(session) \ +#define LIBSSH2_SOCKET_RECV_FLAGS(session) \ (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) #else /* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */ @@ -882,7 +936,7 @@ struct _LIBSSH2_KEX_METHOD struct _LIBSSH2_HOSTKEY_METHOD { const char *name; - unsigned long hash_len; + size_t hash_len; int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data, size_t hostkey_data_len, void **abstract); @@ -923,12 +977,36 @@ struct _LIBSSH2_CRYPT_METHOD int *free_iv, unsigned char *secret, int *free_secret, int encrypt, void **abstract); int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block, - size_t blocksize, void **abstract); + size_t blocksize, void **abstract, int firstlast); int (*dtor) (LIBSSH2_SESSION * session, void **abstract); - _libssh2_cipher_type(algo); + _libssh2_cipher_type(algo); }; +/* Bit flags for _LIBSSH2_CRYPT_METHOD */ + +/* Crypto method has integrated message authentication */ +#define LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC 1 +/* Crypto method does not encrypt the packet length */ +#define LIBSSH2_CRYPT_FLAG_PKTLEN_AAD 2 + +/* Convenience macros for accessing crypt flags */ +/* Local crypto flags */ +#define CRYPT_FLAG_L(session, flag) ((session)->local.crypt && \ + ((session)->local.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag)) +/* Remote crypto flags */ +#define CRYPT_FLAG_R(session, flag) ((session)->remote.crypt && \ + ((session)->remote.crypt->flags & LIBSSH2_CRYPT_FLAG_##flag)) + +/* Values for firstlast */ +#define FIRST_BLOCK 1 +#define MIDDLE_BLOCK 0 +#define LAST_BLOCK 2 + +/* Convenience macros for accessing firstlast */ +#define IS_FIRST(firstlast) (firstlast & FIRST_BLOCK) +#define IS_LAST(firstlast) (firstlast & LAST_BLOCK) + struct _LIBSSH2_COMP_METHOD { const char *name; @@ -952,23 +1030,12 @@ struct _LIBSSH2_COMP_METHOD }; #ifdef LIBSSH2DEBUG -void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, - ...); -#else -#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ - defined(__GNUC__) -/* C99 supported and also by older GCC */ -#define _libssh2_debug(x,y,z,...) do {} while (0) +void +_libssh2_debug_low(LIBSSH2_SESSION * session, int context, const char *format, + ...); +#define _libssh2_debug(x) _libssh2_debug_low x #else -/* no gcc and not C99, do static and hopefully inline */ -static inline void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) -{ - (void)session; - (void)context; - (void)format; -} -#endif +#define _libssh2_debug(x) do {} while(0) #endif #define LIBSSH2_SOCKET_UNKNOWN 1 @@ -995,6 +1062,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) #define SSH_MSG_DEBUG 4 #define SSH_MSG_SERVICE_REQUEST 5 #define SSH_MSG_SERVICE_ACCEPT 6 +#define SSH_MSG_EXT_INFO 7 #define SSH_MSG_KEXINIT 20 #define SSH_MSG_NEWKEYS 21 @@ -1058,8 +1126,8 @@ ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, size_t length, int flags, void **abstract); -#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when - waiting for more data to arrive */ +#define LIBSSH2_DEFAULT_READ_TIMEOUT 60 /* generic timeout in seconds used when + waiting for more data to arrive */ int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, @@ -1069,7 +1137,6 @@ int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void); const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void); -/* misc.c */ int _libssh2_bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, @@ -1083,12 +1150,12 @@ int _libssh2_pem_parse(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const unsigned char *passphrase, - FILE * fp, unsigned char **data, unsigned int *datalen); + FILE * fp, unsigned char **data, size_t *datalen); int _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const char *filedata, size_t filedata_len, - unsigned char **data, unsigned int *datalen); + unsigned char **data, size_t *datalen); /* OpenSSL keys */ int _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, @@ -1100,37 +1167,39 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, const char *filedata, size_t filedata_len, struct string_buf **decrypted_buf); -int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen); -int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, +int _libssh2_pem_decode_sequence(unsigned char **data, size_t *datalen); +int _libssh2_pem_decode_integer(unsigned char **data, size_t *datalen, unsigned char **i, unsigned int *ilen); /* global.c */ void _libssh2_init_if_needed(void); +/* Utility function for certificate auth */ +size_t plain_method(char *method, size_t method_len); #define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0])) /* define to output the libssh2_int64_t type in a *printf() */ -#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__) +#if defined(__BORLANDC__) || defined(_MSC_VER) #define LIBSSH2_INT64_T_FORMAT "I64d" #else #define LIBSSH2_INT64_T_FORMAT "lld" #endif /* In Windows the default file mode is text but an application can override it. -Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 -*/ + Therefore we specify it explicitly. https://github.com/curl/curl/pull/258 + */ #if defined(WIN32) || defined(MSDOS) #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "wt" #define FOPEN_APPENDTEXT "at" #elif defined(__CYGWIN__) /* Cygwin has specific behavior we need to address when WIN32 is not defined. -https://cygwin.com/cygwin-ug-net/using-textbinary.html -For write we want our output to have line endings of LF and be compatible with -other Cygwin utilities. For read we want to handle input that may have line -endings either CRLF or LF so 't' is appropriate. -*/ + https://cygwin.com/cygwin-ug-net/using-textbinary.html + For write we want our output to have line endings of LF and be compatible + with other Cygwin utilities. For read we want to handle input that may have + line endings either CRLF or LF so 't' is appropriate. + */ #define FOPEN_READTEXT "rt" #define FOPEN_WRITETEXT "w" #define FOPEN_APPENDTEXT "a" @@ -1140,4 +1209,4 @@ endings either CRLF or LF so 't' is appropriate. #define FOPEN_APPENDTEXT "a" #endif -#endif /* LIBSSH2_H */ +#endif /* __LIBSSH2_PRIV_H */ diff --git a/libs/libssh2/src/libssh2_setup.h b/libs/libssh2/src/libssh2_setup.h new file mode 100644 index 0000000000..8e56a06042 --- /dev/null +++ b/libs/libssh2/src/libssh2_setup.h @@ -0,0 +1,108 @@ +/* Copyright (C) Viktor Szakats + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef LIBSSH2_SETUP_H +#define LIBSSH2_SETUP_H + +/* Header for platform/compiler-specific initialization. + Used by 'src', 'example', 'tests' */ + +#if defined(_WIN32) && !defined(WIN32) +#define WIN32 +#endif + +/* Define mingw-w64 version macros, eg __MINGW{32,64}_{MINOR,MAJOR}_VERSION */ +#ifdef __MINGW32__ +#include <_mingw.h> +#endif + +/* Configuration provided by build tools (autotools and CMake), + and via platform-specific directories for os400 and vms */ +#if defined(HAVE_CONFIG_H) || defined(__OS400__) || defined(__VMS) + +#include "libssh2_config.h" + +/* Hand-crafted configuration for platforms which lack config tool. + Keep this synced with root CMakeLists.txt */ +#elif defined(WIN32) + +#define HAVE_SELECT +#define HAVE_SNPRINTF + +#ifdef __MINGW32__ +# define HAVE_UNISTD_H +# define HAVE_INTTYPES_H +# define HAVE_SYS_TIME_H +# define HAVE_SYS_PARAM_H +# define HAVE_GETTIMEOFDAY +# define HAVE_STRTOLL +#elif defined(_MSC_VER) +# if _MSC_VER >= 1800 +# define HAVE_INTTYPES_H +# define HAVE_STRTOLL +# else +# define HAVE_STRTOI64 +# endif +# if _MSC_VER < 1900 +# undef HAVE_SNPRINTF +# endif +#endif + +#endif /* defined(HAVE_CONFIG_H) */ + +/* Below applies to both auto-detected and hand-crafted configs */ + +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOGDI +#define NOGDI +#endif +#ifndef NONLS +#define NONLS +#endif + +#ifdef __MINGW32__ +# ifdef __MINGW64_VERSION_MAJOR +/* Number of bits in a file offset, on hosts where this is settable. */ +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# endif +#elif defined(_MSC_VER) +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS /* for fopen(), getenv() */ +# endif +# if !defined(LIBSSH2_LIBRARY) || defined(LIBSSH2_TESTS) + /* apply to examples and tests only */ +# ifndef _CRT_NONSTDC_NO_DEPRECATE +# define _CRT_NONSTDC_NO_DEPRECATE /* for strdup(), write() */ +# endif +# ifndef _WINSOCK_DEPRECATED_NO_WARNINGS +# define _WINSOCK_DEPRECATED_NO_WARNINGS /* for inet_addr() */ +# endif + /* we cannot access our internal snprintf() implementation in examples and + tests when linking to a shared libssh2. */ +# if _MSC_VER < 1900 +# undef HAVE_SNPRINTF +# define HAVE_SNPRINTF +# define snprintf _snprintf +# endif +# endif +# if _MSC_VER < 1500 +# define vsnprintf _vsnprintf +# endif +# if _MSC_VER < 1900 +# define strdup _strdup +/* Silence bogus warning C4127: conditional expression is constant */ +# pragma warning(disable:4127) +# endif +#endif + +#endif /* WIN32 */ + +#endif /* LIBSSH2_SETUP_H */ diff --git a/libs/libssh2/src/mac.c b/libs/libssh2/src/mac.c index 5ac71df4ce..db6f57a44e 100644 --- a/libs/libssh2/src/mac.c +++ b/libs/libssh2/src/mac.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> +/* Copyright (C) Sara Golemon <sarag@libssh2.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -33,20 +33,33 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include "mac.h" -#ifdef LIBSSH2_MAC_NONE +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_MAC_NONE_INSECURE) /* mac_none_MAC - * Minimalist MAC: No MAC + * + * Minimalist MAC: No MAC. DO NOT USE. + * + * The SSH2 Transport allows implementations to forego a message + * authentication code. While this is less of a security risk than using + * a "none" cipher, it is still not recommended as disabling MAC hashes + * removes a layer of security. + * + * Enabling this option will allow for "none" as a negotiable method, + * however it still requires that the method be advertised by the remote + * end and that no more-preferable methods are available. + * */ static int mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t packet_len, const unsigned char *addtl, + size_t addtl_len, void **abstract) { return 0; } @@ -60,9 +73,10 @@ static LIBSSH2_MAC_METHOD mac_method_none = { 0, NULL, mac_none_MAC, - NULL + NULL, + 0 }; -#endif /* LIBSSH2_MAC_NONE */ +#endif /* defined(LIBSSH2DEBUG) && defined(LIBSSH2_MAC_NONE_INSECURE) */ /* mac_method_common_init * Initialize simple mac methods @@ -73,7 +87,7 @@ mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key, { *abstract = key; *free_key = 0; - (void) session; + (void)session; return 0; } @@ -102,15 +116,15 @@ mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract) */ static int mac_method_hmac_sha2_512_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + size_t packet_len, + const unsigned char *addtl, + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + (void)session; _libssh2_htonu32(seqno_buf, seqno); @@ -127,8 +141,6 @@ mac_method_hmac_sha2_512_hash(LIBSSH2_SESSION * session, return 0; } - - static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = { "hmac-sha2-512", 64, @@ -136,7 +148,19 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = { mac_method_common_init, mac_method_hmac_sha2_512_hash, mac_method_common_dtor, + 0 }; + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512_etm = { + "hmac-sha2-512-etm@openssh.com", + 64, + 64, + mac_method_common_init, + mac_method_hmac_sha2_512_hash, + mac_method_common_dtor, + 1 +}; + #endif @@ -147,15 +171,15 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = { */ static int mac_method_hmac_sha2_256_hash(LIBSSH2_SESSION * session, - unsigned char *buf, uint32_t seqno, - const unsigned char *packet, - uint32_t packet_len, - const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + size_t packet_len, + const unsigned char *addtl, + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + (void)session; _libssh2_htonu32(seqno_buf, seqno); @@ -181,7 +205,19 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_256 = { mac_method_common_init, mac_method_hmac_sha2_256_hash, mac_method_common_dtor, + 0 }; + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_256_etm = { + "hmac-sha2-256-etm@openssh.com", + 32, + 32, + mac_method_common_init, + mac_method_hmac_sha2_256_hash, + mac_method_common_dtor, + 1 +}; + #endif @@ -194,13 +230,13 @@ static int mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + (void)session; _libssh2_htonu32(seqno_buf, seqno); @@ -226,6 +262,17 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = { mac_method_common_init, mac_method_hmac_sha1_hash, mac_method_common_dtor, + 0 +}; + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_etm = { + "hmac-sha1-etm@openssh.com", + 20, + 20, + mac_method_common_init, + mac_method_hmac_sha1_hash, + mac_method_common_dtor, + 1 }; /* mac_method_hmac_sha1_96_hash @@ -235,9 +282,9 @@ static int mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { unsigned char temp[SHA_DIGEST_LENGTH]; @@ -257,6 +304,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = { mac_method_common_init, mac_method_hmac_sha1_96_hash, mac_method_common_dtor, + 0 }; #if LIBSSH2_MD5 @@ -267,13 +315,13 @@ static int mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + (void)session; _libssh2_htonu32(seqno_buf, seqno); @@ -299,6 +347,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = { mac_method_common_init, mac_method_hmac_md5_hash, mac_method_common_dtor, + 0 }; /* mac_method_hmac_md5_96_hash @@ -308,9 +357,9 @@ static int mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract) + size_t addtl_len, void **abstract) { unsigned char temp[MD5_DIGEST_LENGTH]; mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, @@ -328,6 +377,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = { mac_method_common_init, mac_method_hmac_md5_96_hash, mac_method_common_dtor, + 0 }; #endif /* LIBSSH2_MD5 */ @@ -339,14 +389,14 @@ static int mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, + size_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, + size_t addtl_len, void **abstract) { libssh2_hmac_ctx ctx; unsigned char seqno_buf[4]; - (void) session; + (void)session; _libssh2_htonu32(seqno_buf, seqno); @@ -372,6 +422,7 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160 = { mac_method_common_init, mac_method_hmac_ripemd160_hash, mac_method_common_dtor, + 0 }; static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = { @@ -381,17 +432,21 @@ static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = { mac_method_common_init, mac_method_hmac_ripemd160_hash, mac_method_common_dtor, + 0 }; #endif /* LIBSSH2_HMAC_RIPEMD */ static const LIBSSH2_MAC_METHOD *mac_methods[] = { #if LIBSSH2_HMAC_SHA256 &mac_method_hmac_sha2_256, + &mac_method_hmac_sha2_256_etm, #endif #if LIBSSH2_HMAC_SHA512 &mac_method_hmac_sha2_512, + &mac_method_hmac_sha2_512_etm, #endif &mac_method_hmac_sha1, + &mac_method_hmac_sha1_etm, &mac_method_hmac_sha1_96, #if LIBSSH2_MD5 &mac_method_hmac_md5, @@ -401,9 +456,9 @@ static const LIBSSH2_MAC_METHOD *mac_methods[] = { &mac_method_hmac_ripemd160, &mac_method_hmac_ripemd160_openssh_com, #endif /* LIBSSH2_HMAC_RIPEMD */ -#ifdef LIBSSH2_MAC_NONE +#if defined(LIBSSH2DEBUG) && defined(LIBSSH2_MAC_NONE_INSECURE) &mac_method_none, -#endif /* LIBSSH2_MAC_NONE */ +#endif NULL }; @@ -412,3 +467,33 @@ _libssh2_mac_methods(void) { return mac_methods; } + +#if LIBSSH2_AES_GCM +/* Stub for aes256-gcm@openssh.com crypto type, which has an integrated + HMAC method. This must not be added to mac_methods[] since it cannot be + negotiated separately. */ +static const LIBSSH2_MAC_METHOD mac_method_hmac_aesgcm = { + "INTEGRATED-AES-GCM", /* made up name for display only */ + 16, + 16, + NULL, + NULL, + NULL, + 0 +}; +#endif /* LIBSSH2_AES_GCM */ + +/* See if the negotiated crypto method has its own authentication scheme that + * obviates the need for a separate negotiated hmac method */ +const LIBSSH2_MAC_METHOD * +_libssh2_mac_override(const LIBSSH2_CRYPT_METHOD *crypt) +{ +#if LIBSSH2_AES_GCM + if(!strcmp(crypt->name, "aes256-gcm@openssh.com") || + !strcmp(crypt->name, "aes128-gcm@openssh.com")) + return &mac_method_hmac_aesgcm; +#else + (void) crypt; +#endif /* LIBSSH2_AES_GCM */ + return NULL; +} diff --git a/libs/libssh2/src/mac.h b/libs/libssh2/src/mac.h index 66d3e61011..696f835aa6 100644 --- a/libs/libssh2/src/mac.h +++ b/libs/libssh2/src/mac.h @@ -1,7 +1,7 @@ #ifndef __LIBSSH2_MAC_H #define __LIBSSH2_MAC_H - -/* Copyright (C) 2009-2010 by Daniel Stenberg +/* Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -36,6 +36,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -55,13 +56,17 @@ struct _LIBSSH2_MAC_METHOD void **abstract); int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf, uint32_t seqno, const unsigned char *packet, - uint32_t packet_len, const unsigned char *addtl, - uint32_t addtl_len, void **abstract); + size_t packet_len, const unsigned char *addtl, + size_t addtl_len, void **abstract); int (*dtor) (LIBSSH2_SESSION * session, void **abstract); + + int etm; /* encrypt-then-mac */ }; typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD; const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void); +const LIBSSH2_MAC_METHOD *_libssh2_mac_override( + const LIBSSH2_CRYPT_METHOD *crypt); #endif /* __LIBSSH2_MAC_H */ diff --git a/libs/libssh2/src/mbedtls.c b/libs/libssh2/src/mbedtls.c deleted file mode 100644 index 8bbcfd8d0d..0000000000 --- a/libs/libssh2/src/mbedtls.c +++ /dev/null @@ -1,733 +0,0 @@ -/* Copyright (c) 2016, Art <https://github.com/wildart> - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#ifdef LIBSSH2_MBEDTLS /* compile only if we build with mbedtls */ - -/*******************************************************************/ -/* - * mbedTLS backend: Global context handles - */ - -static mbedtls_entropy_context _libssh2_mbedtls_entropy; -static mbedtls_ctr_drbg_context _libssh2_mbedtls_ctr_drbg; - -/*******************************************************************/ -/* - * mbedTLS backend: Generic functions - */ - -void -_libssh2_mbedtls_init(void) -{ - int ret; - - mbedtls_entropy_init(&_libssh2_mbedtls_entropy); - mbedtls_ctr_drbg_init(&_libssh2_mbedtls_ctr_drbg); - - ret = mbedtls_ctr_drbg_seed(&_libssh2_mbedtls_ctr_drbg, - mbedtls_entropy_func, - &_libssh2_mbedtls_entropy, NULL, 0); - if(ret != 0) - mbedtls_ctr_drbg_free(&_libssh2_mbedtls_ctr_drbg); -} - -void -_libssh2_mbedtls_free(void) -{ - mbedtls_ctr_drbg_free(&_libssh2_mbedtls_ctr_drbg); - mbedtls_entropy_free(&_libssh2_mbedtls_entropy); -} - -int -_libssh2_mbedtls_random(unsigned char *buf, int len) -{ - int ret; - ret = mbedtls_ctr_drbg_random(&_libssh2_mbedtls_ctr_drbg, buf, len); - return ret == 0 ? 0 : -1; -} - -static void -_libssh2_mbedtls_safe_free(void *buf, int len) -{ -#ifndef LIBSSH2_CLEAR_MEMORY - (void)len; -#endif - - if(!buf) - return; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(len > 0) - memset(buf, 0, len); -#endif - - mbedtls_free(buf); -} - -int -_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(algo), - unsigned char *iv, - unsigned char *secret, - int encrypt) -{ - const mbedtls_cipher_info_t *cipher_info; - int ret, op; - - if(!ctx) - return -1; - - op = encrypt == 0 ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT; - - cipher_info = mbedtls_cipher_info_from_type(algo); - if(!cipher_info) - return -1; - - mbedtls_cipher_init(ctx); - ret = mbedtls_cipher_setup(ctx, cipher_info); - if(!ret) - ret = mbedtls_cipher_setkey(ctx, secret, cipher_info->key_bitlen, op); - - if(!ret) - ret = mbedtls_cipher_set_iv(ctx, iv, cipher_info->iv_size); - - return ret == 0 ? 0 : -1; -} - -int -_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(algo), - int encrypt, - unsigned char *block, - size_t blocklen) -{ - int ret; - unsigned char *output; - size_t osize, olen, finish_olen; - - (void) encrypt; - (void) algo; - - osize = blocklen + mbedtls_cipher_get_block_size(ctx); - - output = (unsigned char *)mbedtls_calloc(osize, sizeof(char)); - if(output) { - ret = mbedtls_cipher_reset(ctx); - - if(!ret) - ret = mbedtls_cipher_update(ctx, block, blocklen, output, &olen); - - if(!ret) - ret = mbedtls_cipher_finish(ctx, output + olen, &finish_olen); - - if(!ret) { - olen += finish_olen; - memcpy(block, output, olen); - } - - _libssh2_mbedtls_safe_free(output, osize); - } - else - ret = -1; - - return ret == 0 ? 0 : -1; -} - -void -_libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx) -{ - mbedtls_cipher_free(ctx); -} - - -int -_libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, - const unsigned char *key, unsigned long keylen) -{ - const mbedtls_md_info_t *md_info; - int ret, hmac; - - md_info = mbedtls_md_info_from_type(mdtype); - if(!md_info) - return 0; - - hmac = key == NULL ? 0 : 1; - - mbedtls_md_init(ctx); - ret = mbedtls_md_setup(ctx, md_info, hmac); - if(!ret) { - if(hmac) - ret = mbedtls_md_hmac_starts(ctx, key, keylen); - else - ret = mbedtls_md_starts(ctx); - } - - return ret == 0 ? 1 : 0; -} - -int -_libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash) -{ - int ret; - - ret = mbedtls_md_finish(ctx, hash); - mbedtls_md_free(ctx); - - return ret == 0 ? 0 : -1; -} - -int -_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, - mbedtls_md_type_t mdtype, unsigned char *hash) -{ - const mbedtls_md_info_t *md_info; - int ret; - - md_info = mbedtls_md_info_from_type(mdtype); - if(!md_info) - return 0; - - ret = mbedtls_md(md_info, data, datalen, hash); - - return ret == 0 ? 0 : -1; -} - -/*******************************************************************/ -/* - * mbedTLS backend: BigNumber functions - */ - -_libssh2_bn * -_libssh2_mbedtls_bignum_init(void) -{ - _libssh2_bn *bignum; - - bignum = (_libssh2_bn *)mbedtls_calloc(1, sizeof(_libssh2_bn)); - if(bignum) { - mbedtls_mpi_init(bignum); - } - - return bignum; -} - -void -_libssh2_mbedtls_bignum_free(_libssh2_bn *bn) -{ - if(bn) { - mbedtls_mpi_free(bn); - mbedtls_free(bn); - } -} - -static int -_libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom) -{ - size_t len; - int err; - int i; - - if(!bn || bits <= 0) - return -1; - - len = (bits + 7) >> 3; - err = mbedtls_mpi_fill_random(bn, len, mbedtls_ctr_drbg_random, - &_libssh2_mbedtls_ctr_drbg); - if(err) - return -1; - - /* Zero unsued bits above the most significant bit*/ - for(i = len*8 - 1; bits <= i; --i) { - err = mbedtls_mpi_set_bit(bn, i, 0); - if(err) - return -1; - } - - /* If `top` is -1, the most significant bit of the random number can be - zero. If top is 0, the most significant bit of the random number is - set to 1, and if top is 1, the two most significant bits of the number - will be set to 1, so that the product of two such random numbers will - always have 2*bits length. - */ - for(i = 0; i <= top; ++i) { - err = mbedtls_mpi_set_bit(bn, bits-i-1, 1); - if(err) - return -1; - } - - /* make odd by setting first bit in least significant byte */ - if(bottom) { - err = mbedtls_mpi_set_bit(bn, 0, 1); - if(err) - return -1; - } - - return 0; -} - - -/*******************************************************************/ -/* - * mbedTLS backend: RSA functions - */ - -int -_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen) -{ - int ret; - libssh2_rsa_ctx *ctx; - - ctx = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx)); - if(ctx != NULL) { - mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V15, 0); - } - else - return -1; - - /* !checksrc! disable ASSIGNWITHINCONDITION 1 */ - if((ret = mbedtls_mpi_read_binary(&(ctx->E), edata, elen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->N), ndata, nlen) ) != 0) { - ret = -1; - } - - if(!ret) { - ctx->len = mbedtls_mpi_size(&(ctx->N)); - } - - if(!ret && ddata) { - /* !checksrc! disable ASSIGNWITHINCONDITION 1 */ - if((ret = mbedtls_mpi_read_binary(&(ctx->D), ddata, dlen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->P), pdata, plen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->Q), qdata, qlen) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->DP), e1data, e1len) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->DQ), e2data, e2len) ) != 0 || - (ret = mbedtls_mpi_read_binary(&(ctx->QP), coeffdata, coefflen) ) - != 0) { - ret = -1; - } - ret = mbedtls_rsa_check_privkey(ctx); - } - else if(!ret) { - ret = mbedtls_rsa_check_pubkey(ctx); - } - - if(ret && ctx) { - _libssh2_mbedtls_rsa_free(ctx); - ctx = NULL; - } - *rsa = ctx; - return ret; -} - -int -_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ - int ret; - mbedtls_pk_context pkey; - mbedtls_rsa_context *pk_rsa; - - *rsa = (libssh2_rsa_ctx *) LIBSSH2_ALLOC(session, sizeof(libssh2_rsa_ctx)); - if(*rsa == NULL) - return -1; - - mbedtls_rsa_init(*rsa, MBEDTLS_RSA_PKCS_V15, 0); - mbedtls_pk_init(&pkey); - - ret = mbedtls_pk_parse_keyfile(&pkey, filename, (char *)passphrase); - if(ret != 0 || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { - mbedtls_pk_free(&pkey); - mbedtls_rsa_free(*rsa); - LIBSSH2_FREE(session, *rsa); - *rsa = NULL; - return -1; - } - - pk_rsa = mbedtls_pk_rsa(pkey); - mbedtls_rsa_copy(*rsa, pk_rsa); - mbedtls_pk_free(&pkey); - - return 0; -} - -int -_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ - int ret; - mbedtls_pk_context pkey; - mbedtls_rsa_context *pk_rsa; - void *filedata_nullterm; - size_t pwd_len; - - *rsa = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx)); - if(*rsa == NULL) - return -1; - - /* - mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'" - private-key from memory will fail if the last byte is not a null byte - */ - filedata_nullterm = mbedtls_calloc(filedata_len + 1, 1); - if(filedata_nullterm == NULL) { - return -1; - } - memcpy(filedata_nullterm, filedata, filedata_len); - - mbedtls_pk_init(&pkey); - - pwd_len = passphrase != NULL ? strlen((const char *)passphrase) : 0; - ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)filedata_nullterm, - filedata_len + 1, - passphrase, pwd_len); - _libssh2_mbedtls_safe_free(filedata_nullterm, filedata_len); - - if(ret != 0 || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) { - mbedtls_pk_free(&pkey); - mbedtls_rsa_free(*rsa); - LIBSSH2_FREE(session, *rsa); - *rsa = NULL; - return -1; - } - - pk_rsa = mbedtls_pk_rsa(pkey); - mbedtls_rsa_copy(*rsa, pk_rsa); - mbedtls_pk_free(&pkey); - - return 0; -} - -int -_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len) -{ - unsigned char hash[SHA_DIGEST_LENGTH]; - int ret; - - ret = _libssh2_mbedtls_hash(m, m_len, MBEDTLS_MD_SHA1, hash); - if(ret) - return -1; /* failure */ - - ret = mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, - MBEDTLS_MD_SHA1, SHA_DIGEST_LENGTH, - hash, sig); - - return (ret == 0) ? 0 : -1; -} - -int -_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len) -{ - int ret; - unsigned char *sig; - unsigned int sig_len; - - (void)hash_len; - - sig_len = rsa->len; - sig = LIBSSH2_ALLOC(session, sig_len); - if(!sig) { - return -1; - } - - ret = mbedtls_rsa_pkcs1_sign(rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, - MBEDTLS_MD_SHA1, SHA_DIGEST_LENGTH, - hash, sig); - if(ret) { - LIBSSH2_FREE(session, sig); - return -1; - } - - *signature = sig; - *signature_len = sig_len; - - return (ret == 0) ? 0 : -1; -} - -void -_libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *ctx) -{ - mbedtls_rsa_free(ctx); - mbedtls_free(ctx); -} - -static unsigned char * -gen_publickey_from_rsa(LIBSSH2_SESSION *session, - mbedtls_rsa_context *rsa, - size_t *keylen) -{ - int e_bytes, n_bytes; - unsigned long len; - unsigned char *key; - unsigned char *p; - - e_bytes = mbedtls_mpi_size(&rsa->E); - n_bytes = mbedtls_mpi_size(&rsa->N); - - /* Key form is "ssh-rsa" + e + n. */ - len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; - - key = LIBSSH2_ALLOC(session, len); - if(!key) { - return NULL; - } - - /* Process key encoding. */ - p = key; - - _libssh2_htonu32(p, 7); /* Key type. */ - p += 4; - memcpy(p, "ssh-rsa", 7); - p += 7; - - _libssh2_htonu32(p, e_bytes); - p += 4; - mbedtls_mpi_write_binary(&rsa->E, p, e_bytes); - - _libssh2_htonu32(p, n_bytes); - p += 4; - mbedtls_mpi_write_binary(&rsa->N, p, n_bytes); - - *keylen = (size_t)(p - key); - return key; -} - -static int -_libssh2_mbedtls_pub_priv_key(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - mbedtls_pk_context *pkey) -{ - unsigned char *key = NULL, *mth = NULL; - size_t keylen = 0, mthlen = 0; - int ret; - mbedtls_rsa_context *rsa; - - if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_RSA) { - mbedtls_pk_free(pkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Key type not supported"); - } - - /* write method */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-rsa", mthlen); - } - else { - ret = -1; - } - - rsa = mbedtls_pk_rsa(*pkey); - key = gen_publickey_from_rsa(session, rsa, &keylen); - if(key == NULL) { - ret = -1; - } - - /* write output */ - if(ret) { - if(mth) - LIBSSH2_FREE(session, mth); - if(key) - LIBSSH2_FREE(session, key); - } - else { - *method = mth; - *method_len = mthlen; - *pubkeydata = key; - *pubkeydata_len = keylen; - } - - return ret; -} - -int -_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ - mbedtls_pk_context pkey; - char buf[1024]; - int ret; - - mbedtls_pk_init(&pkey); - ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase); - if(ret != 0) { - mbedtls_strerror(ret, (char *)buf, sizeof(buf)); - mbedtls_pk_free(&pkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf); - } - - ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len, - pubkeydata, pubkeydata_len, &pkey); - - mbedtls_pk_free(&pkey); - - return ret; -} - -int -_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ - mbedtls_pk_context pkey; - char buf[1024]; - int ret; - void *privatekeydata_nullterm; - size_t pwd_len; - - /* - mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'" - private-key from memory will fail if the last byte is not a null byte - */ - privatekeydata_nullterm = mbedtls_calloc(privatekeydata_len + 1, 1); - if(privatekeydata_nullterm == NULL) { - return -1; - } - memcpy(privatekeydata_nullterm, privatekeydata, privatekeydata_len); - - mbedtls_pk_init(&pkey); - - pwd_len = passphrase != NULL ? strlen((const char *)passphrase) : 0; - ret = mbedtls_pk_parse_key(&pkey, - (unsigned char *)privatekeydata_nullterm, - privatekeydata_len + 1, - (const unsigned char *)passphrase, pwd_len); - _libssh2_mbedtls_safe_free(privatekeydata_nullterm, privatekeydata_len); - - if(ret != 0) { - mbedtls_strerror(ret, (char *)buf, sizeof(buf)); - mbedtls_pk_free(&pkey); - return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf); - } - - ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len, - pubkeydata, pubkeydata_len, &pkey); - - mbedtls_pk_free(&pkey); - - return ret; -} - -void _libssh2_init_aes_ctr(void) -{ - /* no implementation */ -} - - -/*******************************************************************/ -/* - * mbedTLS backend: Diffie-Hellman functions - */ - -void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx) -{ - *dhctx = _libssh2_mbedtls_bignum_init(); /* Random from client */ -} - -int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order) -{ - /* Generate x and e */ - _libssh2_mbedtls_bignum_random(*dhctx, group_order * 8 - 1, 0, -1); - mbedtls_mpi_exp_mod(public, g, *dhctx, p, NULL); - return 0; -} - -int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p) -{ - /* Compute the shared secret */ - mbedtls_mpi_exp_mod(secret, f, *dhctx, p, NULL); - return 0; -} - -void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - _libssh2_mbedtls_bignum_free(*dhctx); - *dhctx = NULL; -} - -#endif /* LIBSSH2_MBEDTLS */ diff --git a/libs/libssh2/src/mbedtls.h b/libs/libssh2/src/mbedtls.h deleted file mode 100644 index 88b0e54d66..0000000000 --- a/libs/libssh2/src/mbedtls.h +++ /dev/null @@ -1,447 +0,0 @@ -/* Copyright (c) 2016, Art <https://github.com/wildart> - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include <stdlib.h> -#include <string.h> - -#include <mbedtls/platform.h> -#include <mbedtls/md.h> -#include <mbedtls/rsa.h> -#include <mbedtls/bignum.h> -#include <mbedtls/cipher.h> -#include <mbedtls/entropy.h> -#include <mbedtls/ctr_drbg.h> -#include <mbedtls/pk.h> -#include <mbedtls/error.h> - -/* Define which features are supported. */ -#define LIBSSH2_MD5 1 - -#define LIBSSH2_HMAC_RIPEMD 1 -#define LIBSSH2_HMAC_SHA256 1 -#define LIBSSH2_HMAC_SHA512 1 - -#define LIBSSH2_AES 1 -#define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 1 -#define LIBSSH2_RC4 1 -#define LIBSSH2_CAST 0 -#define LIBSSH2_3DES 1 - -#define LIBSSH2_RSA 1 -#define LIBSSH2_DSA 0 -#define LIBSSH2_ECDSA 0 -#define LIBSSH2_ED25519 0 - -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 -#define SHA256_DIGEST_LENGTH 32 -#define SHA384_DIGEST_LENGTH 48 -#define SHA512_DIGEST_LENGTH 64 - -#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) - -#if LIBSSH2_ECDSA -#else -#define _libssh2_ec_key void -#endif - -/*******************************************************************/ -/* - * mbedTLS backend: Generic functions - */ - -#define libssh2_crypto_init() \ - _libssh2_mbedtls_init() -#define libssh2_crypto_exit() \ - _libssh2_mbedtls_free() - -#define _libssh2_random(buf, len) \ - _libssh2_mbedtls_random(buf, len) - -#define libssh2_prepare_iovec(vec, len) /* Empty. */ - - -/*******************************************************************/ -/* - * mbedTLS backend: HMAC functions - */ - -#define libssh2_hmac_ctx mbedtls_md_context_t - -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_cleanup(pctx) \ - mbedtls_md_free(pctx) -#define libssh2_hmac_update(ctx, data, datalen) \ - mbedtls_md_hmac_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, hash) \ - mbedtls_md_hmac_finish(&ctx, hash) - -#define libssh2_hmac_sha1_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, key, keylen) -#define libssh2_hmac_md5_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, key, keylen) -#define libssh2_hmac_ripemd160_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_RIPEMD160, key, keylen) -#define libssh2_hmac_sha256_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, key, keylen) -#define libssh2_hmac_sha384_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, key, keylen) -#define libssh2_hmac_sha512_init(pctx, key, keylen) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, key, keylen) - - -/*******************************************************************/ -/* - * mbedTLS backend: SHA1 functions - */ - -#define libssh2_sha1_ctx mbedtls_md_context_t - -#define libssh2_sha1_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, NULL, 0) -#define libssh2_sha1_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha1_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha1(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA1, hash) - -/*******************************************************************/ -/* - * mbedTLS backend: SHA256 functions - */ - -#define libssh2_sha256_ctx mbedtls_md_context_t - -#define libssh2_sha256_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, NULL, 0) -#define libssh2_sha256_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha256_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha256(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA256, hash) - - -/*******************************************************************/ -/* - * mbedTLS backend: SHA384 functions - */ - -#define libssh2_sha384_ctx mbedtls_md_context_t - -#define libssh2_sha384_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, NULL, 0) -#define libssh2_sha384_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha384_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha384(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA384, hash) - - -/*******************************************************************/ -/* - * mbedTLS backend: SHA512 functions - */ - -#define libssh2_sha512_ctx mbedtls_md_context_t - -#define libssh2_sha512_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, NULL, 0) -#define libssh2_sha512_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha512_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_sha512(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA512, hash) - - -/*******************************************************************/ -/* - * mbedTLS backend: MD5 functions - */ - -#define libssh2_md5_ctx mbedtls_md_context_t - -#define libssh2_md5_init(pctx) \ - _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, NULL, 0) -#define libssh2_md5_update(ctx, data, datalen) \ - mbedtls_md_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_md5_final(ctx, hash) \ - _libssh2_mbedtls_hash_final(&ctx, hash) -#define libssh2_md5(data, datalen, hash) \ - _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_MD5, hash) - -/*******************************************************************/ -/* - * mbedTLS backend: RSA structure - */ - -#define libssh2_rsa_ctx mbedtls_rsa_context - -#define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) \ - _libssh2_mbedtls_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) - -#define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \ - _libssh2_mbedtls_rsa_new_private(rsactx, s, filename, passphrase) - -#define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) \ - _libssh2_mbedtls_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) - -#define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \ - _libssh2_mbedtls_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) - -#define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \ - _libssh2_mbedtls_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) - -#define _libssh2_rsa_free(rsactx) \ - _libssh2_mbedtls_rsa_free(rsactx) - -/* - * mbedTLS backend: Key functions - */ - -#define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \ - _libssh2_mbedtls_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) -#define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) \ - _libssh2_mbedtls_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) - - - /*******************************************************************/ -/* - * mbedTLS backend: Cipher Context structure - */ -#define _libssh2_cipher_ctx mbedtls_cipher_context_t - -#define _libssh2_cipher_type(algo) mbedtls_cipher_type_t algo - -#define _libssh2_cipher_aes256ctr MBEDTLS_CIPHER_AES_256_CTR -#define _libssh2_cipher_aes192ctr MBEDTLS_CIPHER_AES_192_CTR -#define _libssh2_cipher_aes128ctr MBEDTLS_CIPHER_AES_128_CTR -#define _libssh2_cipher_aes256 MBEDTLS_CIPHER_AES_256_CBC -#define _libssh2_cipher_aes192 MBEDTLS_CIPHER_AES_192_CBC -#define _libssh2_cipher_aes128 MBEDTLS_CIPHER_AES_128_CBC -#define _libssh2_cipher_blowfish MBEDTLS_CIPHER_BLOWFISH_CBC -#define _libssh2_cipher_arcfour MBEDTLS_CIPHER_ARC4_128 -#define _libssh2_cipher_cast5 MBEDTLS_CIPHER_NULL -#define _libssh2_cipher_3des MBEDTLS_CIPHER_DES_EDE3_CBC - -/* - * mbedTLS backend: Cipher functions - */ - -#define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \ - _libssh2_mbedtls_cipher_init(ctx, type, iv, secret, encrypt) -#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \ - _libssh2_mbedtls_cipher_crypt(ctx, type, encrypt, block, blocklen) -#define _libssh2_cipher_dtor(ctx) \ - _libssh2_mbedtls_cipher_dtor(ctx) - - -/*******************************************************************/ -/* - * mbedTLS backend: BigNumber Support - */ - -#define _libssh2_bn_ctx int /* not used */ -#define _libssh2_bn_ctx_new() 0 /* not used */ -#define _libssh2_bn_ctx_free(bnctx) ((void)0) /* not used */ - -#define _libssh2_bn mbedtls_mpi - -#define _libssh2_bn_init() \ - _libssh2_mbedtls_bignum_init() -#define _libssh2_bn_init_from_bin() \ - _libssh2_mbedtls_bignum_init() -#define _libssh2_bn_set_word(bn, word) \ - mbedtls_mpi_lset(bn, word) -#define _libssh2_bn_from_bin(bn, len, bin) \ - mbedtls_mpi_read_binary(bn, bin, len) -#define _libssh2_bn_to_bin(bn, bin) \ - mbedtls_mpi_write_binary(bn, bin, mbedtls_mpi_size(bn)) -#define _libssh2_bn_bytes(bn) \ - mbedtls_mpi_size(bn) -#define _libssh2_bn_bits(bn) \ - mbedtls_mpi_bitlen(bn) -#define _libssh2_bn_free(bn) \ - _libssh2_mbedtls_bignum_free(bn) - - -/*******************************************************************/ -/* - * mbedTLS backend: Diffie-Hellman support. - */ - -#define _libssh2_dh_ctx mbedtls_mpi * -#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) -#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) -#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) -#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) - - -/*******************************************************************/ -/* - * mbedTLS backend: forward declarations - */ -void -_libssh2_mbedtls_init(void); - -void -_libssh2_mbedtls_free(void); - -int -_libssh2_mbedtls_random(unsigned char *buf, int len); - -int -_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt); -int -_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen); -void -_libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx); - -int -_libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, - const unsigned char *key, unsigned long keylen); - -int -_libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash); -int -_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, - mbedtls_md_type_t mdtype, unsigned char *hash); - -_libssh2_bn * -_libssh2_mbedtls_bignum_init(void); - -void -_libssh2_mbedtls_bignum_free(_libssh2_bn *bn); - -int -_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen); - -int -_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); - -int -_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); -void -_libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *rsa); - -int -_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); -int -_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase); - -extern void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx); -extern int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order); -extern int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p); -extern void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); diff --git a/libs/libssh2/src/misc.c b/libs/libssh2/src/misc.c index bd084c854f..b386e3d667 100644 --- a/libs/libssh2/src/misc.c +++ b/libs/libssh2/src/misc.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2009-2019 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,43 +35,66 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include "misc.h" -#include "blf.h" - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif +#include <errno.h> +#include <assert.h> -#if defined(HAVE_DECL_SECUREZEROMEMORY) && HAVE_DECL_SECUREZEROMEMORY -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif +#ifdef WIN32 +/* Force parameter type. */ +#define recv(s, b, l, f) recv((s), (b), (int)(l), (f)) +#define send(s, b, l, f) send((s), (b), (int)(l), (f)) #endif -#include <stdio.h> -#include <errno.h> +/* snprintf not in Visual Studio CRT and _snprintf dangerously incompatible. + We provide a safe wrapper if snprintf not found */ +#ifdef LIBSSH2_SNPRINTF +#include <stdarg.h> + +/* Want safe, 'n += snprintf(b + n ...)' like function. If cp_max_len is 1 +* then assume cp is pointing to a null char and do nothing. Returns number +* number of chars placed in cp excluding the trailing null char. So for +* cp_max_len > 0 the return value is always < cp_max_len; for cp_max_len +* <= 0 the return value is 0 (and no chars are written to cp). */ +int _libssh2_snprintf(char *cp, size_t cp_max_len, const char *fmt, ...) +{ + va_list args; + int n; + + if(cp_max_len < 2) + return 0; + va_start(args, fmt); + n = vsnprintf(cp, cp_max_len, fmt, args); + va_end(args); + return (n < (int)cp_max_len) ? n : (int)(cp_max_len - 1); +} +#endif int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, const char *errmsg, int errflags) { + if(!session) { + if(errmsg) + fprintf(stderr, "Session is NULL, error: %s\n", errmsg); + return errcode; + } + if(session->err_flags & LIBSSH2_ERR_FLAG_DUP) LIBSSH2_FREE(session, (char *)session->err_msg); session->err_code = errcode; session->err_flags = 0; - if((errmsg != NULL) && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) { + if(errmsg && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) { size_t len = strlen(errmsg); char *copy = LIBSSH2_ALLOC(session, len + 1); if(copy) { @@ -91,8 +114,8 @@ int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode, /* if this is EAGAIN and we're in non-blocking mode, don't generate a debug output for this */ return errcode; - _libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, - session->err_msg); + _libssh2_debug((session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, + session->err_msg)); #endif return errcode; @@ -135,25 +158,22 @@ _libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, { ssize_t rc; - (void) abstract; + (void)abstract; rc = recv(sock, buffer, length, flags); #ifdef WIN32 if(rc < 0) return -wsa2errno(); -#elif defined(__VMS) - if(rc < 0) { - if(errno == EWOULDBLOCK) - return -EAGAIN; - else - return -errno; - } #else if(rc < 0) { /* Sometimes the first recv() function call sets errno to ENOENT on Solaris and HP-UX */ if(errno == ENOENT) return -EAGAIN; +#ifdef EWOULDBLOCK /* For VMS and other special unixes */ + else if(errno == EWOULDBLOCK) + return -EAGAIN; +#endif else return -errno; } @@ -171,32 +191,33 @@ _libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length, { ssize_t rc; - (void) abstract; + (void)abstract; rc = send(sock, buffer, length, flags); #ifdef WIN32 if(rc < 0) return -wsa2errno(); -#elif defined(__VMS) +#else if(rc < 0) { +#ifdef EWOULDBLOCK /* For VMS and other special unixes */ if(errno == EWOULDBLOCK) return -EAGAIN; - else - return -errno; - } -#else - if(rc < 0) +#endif return -errno; + } #endif return rc; } /* libssh2_ntohu32 */ -unsigned int +uint32_t _libssh2_ntohu32(const unsigned char *buf) { - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return ((uint32_t)buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | ((uint32_t)buf[3]); } @@ -205,14 +226,14 @@ _libssh2_ntohu32(const unsigned char *buf) libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf) { - unsigned long msl, lsl; - - msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16) - | ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3]; - lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16) - | ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7]; - - return ((libssh2_uint64_t)msl <<32) | lsl; + return ((libssh2_uint64_t)buf[0] << 56) + | ((libssh2_uint64_t)buf[1] << 48) + | ((libssh2_uint64_t)buf[2] << 40) + | ((libssh2_uint64_t)buf[3] << 32) + | ((libssh2_uint64_t)buf[4] << 24) + | ((libssh2_uint64_t)buf[5] << 16) + | ((libssh2_uint64_t)buf[6] << 8) + | ((libssh2_uint64_t)buf[7]); } /* _libssh2_htonu32 @@ -220,7 +241,7 @@ _libssh2_ntohu64(const unsigned char *buf) void _libssh2_htonu32(unsigned char *buf, uint32_t value) { - buf[0] = (value >> 24) & 0xFF; + buf[0] = (unsigned char)((value >> 24) & 0xFF); buf[1] = (value >> 16) & 0xFF; buf[2] = (value >> 8) & 0xFF; buf[3] = value & 0xFF; @@ -236,13 +257,50 @@ void _libssh2_store_u32(unsigned char **buf, uint32_t value) /* _libssh2_store_str */ -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len) +int _libssh2_store_str(unsigned char **buf, const char *str, size_t len) { - _libssh2_store_u32(buf, (uint32_t)len); - if(len) { - memcpy(*buf, str, len); - *buf += len; + uint32_t len_stored = (uint32_t)len; + + _libssh2_store_u32(buf, len_stored); + if(len_stored) { + memcpy(*buf, str, len_stored); + *buf += len_stored; + } + + assert(len_stored == len); + return len_stored == len; +} + +/* _libssh2_store_bignum2_bytes + */ +int _libssh2_store_bignum2_bytes(unsigned char **buf, + const unsigned char *bytes, + size_t len) +{ + uint32_t len_stored; + uint32_t extraByte; + const unsigned char *p; + + for(p = bytes; len > 0 && *p == 0; --len, ++p) {} + + extraByte = (len > 0 && (p[0] & 0x80) != 0); + len_stored = (uint32_t)len; + if(extraByte && len_stored == 0xffffffff) + len_stored--; + _libssh2_store_u32(buf, len_stored + extraByte); + + if(extraByte) { + *buf[0] = 0; + *buf += 1; + } + + if(len_stored) { + memcpy(*buf, p, len_stored); + *buf += len_stored; } + + assert(len_stored == len); + return len_stored == len; } /* Base64 Conversion */ @@ -268,26 +326,46 @@ static const short base64_reverse_table[256] = { /* libssh2_base64_decode * - * Decode a base64 chunk and store it into a newly alloc'd buffer + * Legacy public function. DEPRECATED. */ LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, unsigned int *datalen, const char *src, unsigned int src_len) { - unsigned char *s, *d; + int rc; + size_t dlen; + + rc = _libssh2_base64_decode(session, data, &dlen, src, src_len); + + if(datalen) + *datalen = (unsigned int)dlen; + + return rc; +} + +/* _libssh2_base64_decode + * + * Decode a base64 chunk and store it into a newly alloc'd buffer + */ +int _libssh2_base64_decode(LIBSSH2_SESSION *session, + char **data, size_t *datalen, + const char *src, size_t src_len) +{ + unsigned char *d; + const char *s; short v; - int i = 0, len = 0; + ssize_t i = 0, len = 0; - *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1); + *data = LIBSSH2_ALLOC(session, ((src_len / 4) * 3) + 1); d = (unsigned char *) *data; if(!d) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for base64 decoding"); } - for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) { - v = base64_reverse_table[*s]; + for(s = src; s < (src + src_len); s++) { + v = base64_reverse_table[(unsigned char)*s]; if(v < 0) continue; switch(i % 4) { @@ -295,15 +373,15 @@ libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, d[len] = (unsigned char)(v << 2); break; case 1: - d[len++] |= v >> 4; + d[len++] |= (unsigned char)(v >> 4); d[len] = (unsigned char)(v << 4); break; case 2: - d[len++] |= v >> 2; + d[len++] |= (unsigned char)(v >> 2); d[len] = (unsigned char)(v << 6); break; case 3: - d[len++] |= v; + d[len++] |= (unsigned char)v; break; } i++; @@ -322,10 +400,10 @@ libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, /* ---- Base64 Encoding/Decoding Table --- */ static const char table64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* - * _libssh2_base64_encode() + * _libssh2_base64_encode * * Returns the length of the newly created base64 string. The third argument * is a pointer to an allocated area holding the base64 data. If something @@ -346,11 +424,11 @@ size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, *outptr = NULL; /* set to NULL in case of failure before we reach the end */ - if(0 == insize) + if(insize == 0) insize = strlen(indata); base64data = output = LIBSSH2_ALLOC(session, insize * 4 / 3 + 4); - if(NULL == output) + if(!output) return 0; while(insize > 0) { @@ -374,22 +452,22 @@ size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, switch(inputparts) { case 1: /* only one byte read */ - snprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); + output[0] = table64[obuf[0]]; + output[1] = table64[obuf[1]]; + output[2] = '='; + output[3] = '='; break; case 2: /* two bytes read */ - snprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); + output[0] = table64[obuf[0]]; + output[1] = table64[obuf[1]]; + output[2] = table64[obuf[2]]; + output[3] = '='; break; default: - snprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]]); + output[0] = table64[obuf[0]]; + output[1] = table64[obuf[1]]; + output[2] = table64[obuf[2]]; + output[3] = table64[obuf[3]]; break; } output += 4; @@ -427,13 +505,14 @@ libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context, } void -_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) +_libssh2_debug_low(LIBSSH2_SESSION * session, int context, const char *format, + ...) { char buffer[1536]; int len, msglen, buflen = sizeof(buffer); va_list vargs; struct timeval now; - static int firstsec; + static long firstsec; static const char *const contexts[] = { "Unknown", "Transport", @@ -463,7 +542,7 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) } } - _libssh2_gettimeofday(&now, NULL); + gettimeofday(&now, NULL); if(!firstsec) { firstsec = now.tv_sec; } @@ -494,8 +573,8 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION * session, int bitmask) { - (void) session; - (void) bitmask; + (void)session; + (void)bitmask; return 0; } @@ -503,9 +582,9 @@ LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context, libssh2_trace_handler_func callback) { - (void) session; - (void) handler_context; - (void) callback; + (void)session; + (void)handler_context; + (void)callback; return 0; } #endif @@ -602,10 +681,10 @@ void _libssh2_list_insert(struct list_node *after, /* insert before this */ #endif -/* this define is defined in misc.h for the correct platforms */ -#ifdef LIBSSH2_GETTIMEOFDAY_WIN32 +/* Defined in libssh2_priv.h for the correct platforms */ +#ifdef LIBSSH2_GETTIMEOFDAY /* - * gettimeofday + * _libssh2_gettimeofday * Implementation according to: * The Open Group Base Specifications Issue 6 * IEEE Std 1003.1, 2004 Edition @@ -626,27 +705,31 @@ void _libssh2_list_insert(struct list_node *after, /* insert before this */ * Danny Smith <dannysmith@users.sourceforge.net> */ -/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000) - -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp) +int _libssh2_gettimeofday(struct timeval *tp, void *tzp) { - union { - unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; (void)tzp; if(tp) { +#ifdef WIN32 + /* Offset between 1601-01-01 and 1970-01-01 in 100 nanosec units */ + #define _WIN32_FT_OFFSET (116444736000000000) + + union { + libssh2_uint64_t ns100; /* time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } _now; GetSystemTimeAsFileTime(&_now.ft); tp->tv_usec = (long)((_now.ns100 / 10) % 1000000); - tp->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000); + tp->tv_sec = (long)((_now.ns100 - _WIN32_FT_OFFSET) / 10000000); +#else + /* Platforms without a native implementation or local replacement */ + tp->tv_usec = 0; + tp->tv_sec = 0; +#endif } /* Always return 0 as per Open Group Base Specifications Issue 6. Do not set errno on error. */ return 0; } - - #endif void *_libssh2_calloc(LIBSSH2_SESSION* session, size_t size) @@ -689,34 +772,23 @@ void _libssh2_aes_ctr_increment(unsigned char *ctr, } } -#ifdef WIN32 -static void * (__cdecl * const volatile memset_libssh)(void *, int, size_t) = - memset; -#else +#ifdef LIBSSH2_MEMZERO static void * (* const volatile memset_libssh)(void *, int, size_t) = memset; -#endif -void _libssh2_explicit_zero(void *buf, size_t size) +void _libssh2_memzero(void *buf, size_t size) { -#if defined(HAVE_DECL_SECUREZEROMEMORY) && HAVE_DECL_SECUREZEROMEMORY - SecureZeroMemory(buf, size); - (void)memset_libssh; /* Silence unused variable warning */ -#elif defined(HAVE_MEMSET_S) - (void)memset_s(buf, size, 0, size); - (void)memset_libssh; /* Silence unused variable warning */ -#else memset_libssh(buf, 0, size); -#endif } +#endif /* String buffer */ -struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session) +struct string_buf *_libssh2_string_buf_new(LIBSSH2_SESSION *session) { struct string_buf *ret; ret = _libssh2_calloc(session, sizeof(*ret)); - if(ret == NULL) + if(!ret) return NULL; return ret; @@ -724,16 +796,39 @@ struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session) void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf) { - if(buf == NULL) + if(!buf) return; - if(buf->data != NULL) + if(buf->data) LIBSSH2_FREE(session, buf->data); LIBSSH2_FREE(session, buf); buf = NULL; } +int _libssh2_get_byte(struct string_buf *buf, unsigned char *out) +{ + if(!_libssh2_check_length(buf, 1)) { + return -1; + } + + *out = buf->dataptr[0]; + buf->dataptr += 1; + return 0; +} + +int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out) +{ + if(!_libssh2_check_length(buf, 1)) { + return -1; + } + + + *out = buf->dataptr[0] == 0 ? 0 : 1; + buf->dataptr += 1; + return 0; +} + int _libssh2_get_u32(struct string_buf *buf, uint32_t *out) { if(!_libssh2_check_length(buf, 4)) { @@ -771,7 +866,7 @@ int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf, size_t *outlen) { uint32_t data_len; - if(_libssh2_get_u32(buf, &data_len) != 0) { + if(!buf || _libssh2_get_u32(buf, &data_len) != 0) { return -1; } if(!_libssh2_check_length(buf, data_len)) { @@ -796,12 +891,18 @@ int _libssh2_copy_string(LIBSSH2_SESSION *session, struct string_buf *buf, return -1; } - *outbuf = LIBSSH2_ALLOC(session, str_len); - if(*outbuf) { - memcpy(*outbuf, str, str_len); + if(str_len) { + *outbuf = LIBSSH2_ALLOC(session, str_len); + if(*outbuf) { + memcpy(*outbuf, str, str_len); + } + else { + return -1; + } } else { - return -1; + *outlen = 0; + *outbuf = NULL; } if(outlen) @@ -850,25 +951,11 @@ int _libssh2_check_length(struct string_buf *buf, size_t len) { unsigned char *endp = &buf->data[buf->len]; size_t left = endp - buf->dataptr; - return ((len <= left) && (left <= buf->len)); -} - -/* Wrappers */ - -int _libssh2_bcrypt_pbkdf(const char *pass, - size_t passlen, - const uint8_t *salt, - size_t saltlen, - uint8_t *key, - size_t keylen, - unsigned int rounds) -{ - /* defined in bcrypt_pbkdf.c */ - return bcrypt_pbkdf(pass, - passlen, - salt, - saltlen, - key, - keylen, - rounds); + return (len <= left) && (left <= buf->len); +} + +int _libssh2_eob(struct string_buf *buf) +{ + unsigned char *endp = &buf->data[buf->len]; + return buf->dataptr >= endp; } diff --git a/libs/libssh2/src/misc.h b/libs/libssh2/src/misc.h index 5481e666ca..bf3e3c3623 100644 --- a/libs/libssh2/src/misc.h +++ b/libs/libssh2/src/misc.h @@ -1,7 +1,6 @@ #ifndef __LIBSSH2_MISC_H #define __LIBSSH2_MISC_H -/* Copyright (c) 2009-2019 by Daniel Stenberg - * +/* Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,8 +35,31 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +#ifdef LIBSSH2_NO_CLEAR_MEMORY +#define _libssh2_explicit_zero(buf, size) do { \ + (void)(buf); \ + (void)(size); \ + } while(0) +#else +#ifdef WIN32 +#define _libssh2_explicit_zero(buf, size) SecureZeroMemory(buf, size) +#elif defined(HAVE_EXPLICIT_BZERO) +#define _libssh2_explicit_zero(buf, size) explicit_bzero(buf, size) +#elif defined(HAVE_EXPLICIT_MEMSET) +#define _libssh2_explicit_zero(buf, size) (void)explicit_memset(buf, 0, size) +#elif defined(HAVE_MEMSET_S) +#define _libssh2_explicit_zero(buf, size) (void)memset_s(buf, size, 0, size) +#else +#define LIBSSH2_MEMZERO +void _libssh2_memzero(void *buf, size_t size); +#define _libssh2_explicit_zero(buf, size) _libssh2_memzero(buf, size) +#endif +#endif + struct list_head { struct list_node *last; struct list_node *first; @@ -77,20 +99,27 @@ void *_libssh2_list_prev(struct list_node *node); /* remove this node from the list */ void _libssh2_list_remove(struct list_node *entry); +int _libssh2_base64_decode(LIBSSH2_SESSION *session, + char **data, size_t *datalen, + const char *src, size_t src_len); size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, const char *inp, size_t insize, char **outptr); -unsigned int _libssh2_ntohu32(const unsigned char *buf); +uint32_t _libssh2_ntohu32(const unsigned char *buf); libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf); void _libssh2_htonu32(unsigned char *buf, uint32_t val); void _libssh2_store_u32(unsigned char **buf, uint32_t value); -void _libssh2_store_str(unsigned char **buf, const char *str, size_t len); +int _libssh2_store_str(unsigned char **buf, const char *str, size_t len); +int _libssh2_store_bignum2_bytes(unsigned char **buf, + const unsigned char *bytes, + size_t len); void *_libssh2_calloc(LIBSSH2_SESSION *session, size_t size); -void _libssh2_explicit_zero(void *buf, size_t size); -struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session); +struct string_buf *_libssh2_string_buf_new(LIBSSH2_SESSION *session); void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf); +int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out); +int _libssh2_get_byte(struct string_buf *buf, unsigned char *out); int _libssh2_get_u32(struct string_buf *buf, uint32_t *out); int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out); int _libssh2_match_string(struct string_buf *buf, const char *match); @@ -101,19 +130,7 @@ int _libssh2_copy_string(LIBSSH2_SESSION* session, struct string_buf *buf, int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf, size_t *outlen); int _libssh2_check_length(struct string_buf *buf, size_t requested_len); - -#if defined(LIBSSH2_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -/* provide a private one */ -#undef HAVE_GETTIMEOFDAY -int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp); -#define HAVE_LIBSSH2_GETTIMEOFDAY -#define LIBSSH2_GETTIMEOFDAY_WIN32 /* enable the win32 implementation */ -#else -#ifdef HAVE_GETTIMEOFDAY -#define _libssh2_gettimeofday(x,y) gettimeofday(x,y) -#define HAVE_LIBSSH2_GETTIMEOFDAY -#endif -#endif +int _libssh2_eob(struct string_buf *buf); void _libssh2_xor_data(unsigned char *output, const unsigned char *input1, diff --git a/libs/libssh2/src/openssl.c b/libs/libssh2/src/openssl.c index 04d5ec2ffd..2dc2340c3b 100644 --- a/libs/libssh2/src/openssl.c +++ b/libs/libssh2/src/openssl.c @@ -1,8 +1,7 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org> - * - * Author: Simon Josefsson +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. + * Copyright (C) Sara Golemon <sarag@libssh2.org> + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -36,14 +35,14 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include "libssh2_priv.h" - -#ifdef LIBSSH2_OPENSSL /* compile only if we build with openssl */ +#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */ -#include <string.h> -#include "misc.h" +#include <stdlib.h> +#include <assert.h> #ifndef EVP_MAX_BLOCK_LENGTH #define EVP_MAX_BLOCK_LENGTH 32 @@ -56,6 +55,24 @@ read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session, size_t filedata_len, unsigned const char *passphrase); +static int +_libssh2_sk_pub_openssh_keyfilememory(LIBSSH2_SESSION *session, + void **key_ctx, + const char *key_type, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + unsigned const char *passphrase); + +#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA static unsigned char * write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) { @@ -73,7 +90,19 @@ write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) return p + bn_bytes; } +#endif + +int +_libssh2_openssl_random(void *buf, size_t len) +{ + if(len > INT_MAX) { + return -1; + } + + return RAND_bytes(buf, (int)len) == 1 ? 0 : -1; +} +#if LIBSSH2_RSA int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, const unsigned char *edata, @@ -102,29 +131,29 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, BIGNUM * iqmp = 0; e = BN_new(); - BN_bin2bn(edata, elen, e); + BN_bin2bn(edata, (int) elen, e); n = BN_new(); - BN_bin2bn(ndata, nlen, n); + BN_bin2bn(ndata, (int) nlen, n); if(ddata) { d = BN_new(); - BN_bin2bn(ddata, dlen, d); + BN_bin2bn(ddata, (int) dlen, d); p = BN_new(); - BN_bin2bn(pdata, plen, p); + BN_bin2bn(pdata, (int) plen, p); q = BN_new(); - BN_bin2bn(qdata, qlen, q); + BN_bin2bn(qdata, (int) qlen, q); dmp1 = BN_new(); - BN_bin2bn(e1data, e1len, dmp1); + BN_bin2bn(e1data, (int) e1len, dmp1); dmq1 = BN_new(); - BN_bin2bn(e2data, e2len, dmq1); + BN_bin2bn(e2data, (int) e2len, dmq1); iqmp = BN_new(); - BN_bin2bn(coeffdata, coefflen, iqmp); + BN_bin2bn(coeffdata, (int) coefflen, iqmp); } *rsa = RSA_new(); @@ -154,21 +183,67 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, } int -_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, +_libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, + size_t hash_len, const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, unsigned long m_len) + size_t sig_len, + const unsigned char *m, size_t m_len) { - unsigned char hash[SHA_DIGEST_LENGTH]; int ret; + int nid_type; + unsigned char *hash = malloc(hash_len); + if(!hash) + return -1; + + if(hash_len == SHA_DIGEST_LENGTH) { + nid_type = NID_sha1; + ret = _libssh2_sha1(m, m_len, hash); + } + else if(hash_len == SHA256_DIGEST_LENGTH) { + nid_type = NID_sha256; + ret = _libssh2_sha256(m, m_len, hash); + + } + else if(hash_len == SHA512_DIGEST_LENGTH) { + nid_type = NID_sha512; + ret = _libssh2_sha512(m, m_len, hash); + } + else { +/* silence: + warning C4701: potentially uninitialized local variable 'nid_type' used */ +#if defined(_MSC_VER) + nid_type = 0; +#endif + ret = -1; /* unsupported digest */ + } - if(_libssh2_sha1(m, m_len, hash)) + if(ret) { + free(hash); return -1; /* failure */ - ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, - (unsigned char *) sig, sig_len, rsactx); + } + + ret = RSA_verify(nid_type, hash, (unsigned int) hash_len, + (unsigned char *) sig, + (unsigned int) sig_len, rsactx); + + free(hash); + return (ret == 1) ? 0 : -1; } +#if LIBSSH2_RSA_SHA1 +int +_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, size_t m_len) +{ + return _libssh2_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, sig, sig_len, m, + m_len); +} +#endif +#endif + #if LIBSSH2_DSA int _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, @@ -189,20 +264,20 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, BIGNUM * priv_key = NULL; p_bn = BN_new(); - BN_bin2bn(p, p_len, p_bn); + BN_bin2bn(p, (int) p_len, p_bn); q_bn = BN_new(); - BN_bin2bn(q, q_len, q_bn); + BN_bin2bn(q, (int) q_len, q_bn); g_bn = BN_new(); - BN_bin2bn(g, g_len, g_bn); + BN_bin2bn(g, (int) g_len, g_bn); pub_key = BN_new(); - BN_bin2bn(y, y_len, pub_key); + BN_bin2bn(y, (int) y_len, pub_key); if(x_len) { priv_key = BN_new(); - BN_bin2bn(x, x_len, priv_key); + BN_bin2bn(x, (int) x_len, priv_key); } *dsactx = DSA_new(); @@ -227,7 +302,7 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, const unsigned char *sig, - const unsigned char *m, unsigned long m_len) + const unsigned char *m, size_t m_len) { unsigned char hash[SHA_DIGEST_LENGTH]; DSA_SIG * dsasig; @@ -259,16 +334,16 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, #if LIBSSH2_ECDSA -/* _libssh2_ecdsa_key_get_curve_type +/* _libssh2_ecdsa_get_curve_type * * returns key curve type that maps to libssh2_curve_type * */ libssh2_curve_type -_libssh2_ecdsa_key_get_curve_type(_libssh2_ec_key *key) +_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx) { - const EC_GROUP *group = EC_KEY_get0_group(key); + const EC_GROUP *group = EC_KEY_get0_group(ec_ctx); return EC_GROUP_get_curve_name(group); } @@ -282,10 +357,9 @@ int _libssh2_ecdsa_curve_type_from_name(const char *name, libssh2_curve_type *out_type) { - int ret = 0; libssh2_curve_type type; - if(name == NULL || strlen(name) != 19) + if(!name || strlen(name) != 19) return -1; if(strcmp(name, "ecdsa-sha2-nistp256") == 0) @@ -295,14 +369,14 @@ _libssh2_ecdsa_curve_type_from_name(const char *name, else if(strcmp(name, "ecdsa-sha2-nistp521") == 0) type = LIBSSH2_EC_CURVE_NISTP521; else { - ret = -1; + return -1; } - if(ret == 0 && out_type) { + if(out_type) { *out_type = type; } - return ret; + return 0; } /* _libssh2_ecdsa_curve_name_with_octal_new @@ -328,51 +402,50 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx, ret = EC_POINT_oct2point(ec_group, point, k, k_len, NULL); ret = EC_KEY_set_public_key(ec_key, point); - if(point != NULL) + if(point) EC_POINT_free(point); - if(ec_ctx != NULL) + if(ec_ctx) *ec_ctx = ec_key; } return (ret == 1) ? 0 : -1; } -#define LIBSSH2_ECDSA_VERIFY(digest_type) \ -{ \ - unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ - libssh2_sha##digest_type(m, m_len, hash); \ - ret = ECDSA_do_verify(hash, SHA##digest_type##_DIGEST_LENGTH, \ - ecdsa_sig, ec_key); \ - \ -} +#define LIBSSH2_ECDSA_VERIFY(digest_type) \ + do { \ + unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ + libssh2_sha##digest_type(m, m_len, hash); \ + ret = ECDSA_do_verify(hash, SHA##digest_type##_DIGEST_LENGTH, \ + ecdsa_sig, ec_key); \ + } while(0) int _libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, - const unsigned char *r, size_t r_len, - const unsigned char *s, size_t s_len, - const unsigned char *m, size_t m_len) + const unsigned char *r, size_t r_len, + const unsigned char *s, size_t s_len, + const unsigned char *m, size_t m_len) { int ret = 0; EC_KEY *ec_key = (EC_KEY*)ctx; - libssh2_curve_type type = _libssh2_ecdsa_key_get_curve_type(ec_key); + libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ec_key); #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new(); BIGNUM *pr = BN_new(); BIGNUM *ps = BN_new(); - BN_bin2bn(r, r_len, pr); - BN_bin2bn(s, s_len, ps); + BN_bin2bn(r, (int) r_len, pr); + BN_bin2bn(s, (int) s_len, ps); ECDSA_SIG_set0(ecdsa_sig, pr, ps); #else ECDSA_SIG ecdsa_sig_; ECDSA_SIG *ecdsa_sig = &ecdsa_sig_; ecdsa_sig_.r = BN_new(); - BN_bin2bn(r, r_len, ecdsa_sig_.r); + BN_bin2bn(r, (int) r_len, ecdsa_sig_.r); ecdsa_sig_.s = BN_new(); - BN_bin2bn(s, s_len, ecdsa_sig_.s); + BN_bin2bn(s, (int) s_len, ecdsa_sig_.s); #endif if(type == LIBSSH2_EC_CURVE_NISTP256) { @@ -404,9 +477,26 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, unsigned char *iv, unsigned char *secret, int encrypt) { #ifdef HAVE_OPAQUE_STRUCTS +#if LIBSSH2_AES_GCM + const int is_aesgcm = (algo == EVP_aes_128_gcm) || + (algo == EVP_aes_256_gcm); +#endif /* LIBSSH2_AES_GCM */ + int rc; + *h = EVP_CIPHER_CTX_new(); - return !EVP_CipherInit(*h, algo(), secret, iv, encrypt); + rc = !EVP_CipherInit(*h, algo(), secret, iv, encrypt); +#if LIBSSH2_AES_GCM + if(is_aesgcm) { + /* Sets both fixed and invocation_counter parts of IV */ + rc |= !EVP_CIPHER_CTX_ctrl(*h, EVP_CTRL_AEAD_SET_IV_FIXED, -1, iv); + } +#endif /* LIBSSH2_AES_GCM */ + + return rc; #else +# if LIBSSH2_AES_GCM +# error AES-GCM is only supported with opaque structs in use +# endif /* LIBSSH2_AES_GCM */ EVP_CIPHER_CTX_init(h); return !EVP_CipherInit(h, algo(), secret, iv, encrypt); #endif @@ -415,229 +505,116 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, _libssh2_cipher_type(algo), - int encrypt, unsigned char *block, size_t blocksize) + int encrypt, unsigned char *block, size_t blocksize, + int firstlast) { unsigned char buf[EVP_MAX_BLOCK_LENGTH]; - int ret; - (void) algo; - (void) encrypt; + int ret = 1; + int rc = 1; -#ifdef HAVE_OPAQUE_STRUCTS - ret = EVP_Cipher(*ctx, buf, block, blocksize); +#if LIBSSH2_AES_GCM + const int is_aesgcm = (algo == EVP_aes_128_gcm) || + (algo == EVP_aes_256_gcm); + char lastiv[1]; #else - ret = EVP_Cipher(ctx, buf, block, blocksize); -#endif - if(ret == 1) { - memcpy(block, buf, blocksize); - } - return ret == 1 ? 0 : 1; -} - -#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) - -#include <openssl/aes.h> -#include <openssl/evp.h> - -typedef struct -{ - AES_KEY key; - EVP_CIPHER_CTX *aes_ctx; - unsigned char ctr[AES_BLOCK_SIZE]; -} aes_ctr_ctx; - -static int -aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, - const unsigned char *iv, int enc) /* init key */ -{ - /* - * variable "c" is leaked from this scope, but is later freed - * in aes_ctr_cleanup - */ - aes_ctr_ctx *c; - const EVP_CIPHER *aes_cipher; - (void) enc; + const int is_aesgcm = 0; +#endif /* LIBSSH2_AES_GCM */ + /* length of AES-GCM Authentication Tag */ + const int authlen = is_aesgcm ? 16 : 0; + /* length of AAD, only on the first block */ + const int aadlen = (is_aesgcm && IS_FIRST(firstlast)) ? 4 : 0; + /* size of AT, if present */ + const int authenticationtag = IS_LAST(firstlast) ? authlen : 0; + /* length to encrypt */ + const int cryptlen = (unsigned int)blocksize - aadlen - authenticationtag; + + (void)algo; + + assert(blocksize <= sizeof(buf)); + assert(cryptlen >= 0); + +#if LIBSSH2_AES_GCM + /* First block */ + if(IS_FIRST(firstlast)) { + /* Increments invocation_counter portion of IV */ + if(is_aesgcm) { + ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_IV_GEN, 1, lastiv); + } - switch(EVP_CIPHER_CTX_key_length(ctx)) { - case 16: - aes_cipher = EVP_aes_128_ecb(); - break; - case 24: - aes_cipher = EVP_aes_192_ecb(); - break; - case 32: - aes_cipher = EVP_aes_256_ecb(); - break; - default: - return 0; + if(aadlen) { + /* Include the 4 byte packet length as AAD */ + ret = EVP_Cipher(*ctx, NULL, block, aadlen); + } } - c = malloc(sizeof(*c)); - if(c == NULL) - return 0; - -#ifdef HAVE_OPAQUE_STRUCTS - c->aes_ctx = EVP_CIPHER_CTX_new(); -#else - c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX)); -#endif - if(c->aes_ctx == NULL) { - free(c); - return 0; + /* Last portion of block to encrypt/decrypt */ + if(IS_LAST(firstlast)) { + if(is_aesgcm && !encrypt) { + /* set tag on decryption */ + ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_SET_TAG, authlen, + block + blocksize - authlen); + } } - - if(EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) { -#ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER_CTX_free(c->aes_ctx); #else - free(c->aes_ctx); -#endif - free(c); - return 0; - } - - EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0); - - memcpy(c->ctr, iv, AES_BLOCK_SIZE); - - EVP_CIPHER_CTX_set_app_data(ctx, c); - - return 1; -} - -static int -aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, - const unsigned char *in, - size_t inl) /* encrypt/decrypt data */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - unsigned char b1[AES_BLOCK_SIZE]; - int outlen = 0; - - if(inl != 16) /* libssh2 only ever encrypt one block */ - return 0; - - if(c == NULL) { - return 0; - } + (void)encrypt; + (void)firstlast; +#endif /* LIBSSH2_AES_GCM */ -/* - To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each - blocks of length L), the encryptor first encrypts <X> with <cipher> - to obtain a block B1. The block B1 is then XORed with P1 to generate - the ciphertext block C1. The counter X is then incremented -*/ - - if(EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, - c->ctr, AES_BLOCK_SIZE) != 1) { - return 0; - } - - _libssh2_xor_data(out, in, b1, AES_BLOCK_SIZE); - _libssh2_aes_ctr_increment(c->ctr, AES_BLOCK_SIZE); - - return 1; -} - -static int -aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */ -{ - aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); - - if(c == NULL) { - return 1; - } - - if(c->aes_ctx != NULL) { + if(cryptlen > 0) { #ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER_CTX_free(c->aes_ctx); + ret = EVP_Cipher(*ctx, buf + aadlen, block + aadlen, cryptlen); #else - _libssh2_cipher_dtor(c->aes_ctx); - free(c->aes_ctx); + ret = EVP_Cipher(ctx, buf + aadlen, block + aadlen, cryptlen); #endif } - free(c); - - return 1; -} - -static const EVP_CIPHER * -make_ctr_evp (size_t keylen, EVP_CIPHER **aes_ctr_cipher, int type) -{ -#ifdef HAVE_OPAQUE_STRUCTS - *aes_ctr_cipher = EVP_CIPHER_meth_new(type, 16, keylen); - if(*aes_ctr_cipher) { - EVP_CIPHER_meth_set_iv_length(*aes_ctr_cipher, 16); - EVP_CIPHER_meth_set_init(*aes_ctr_cipher, aes_ctr_init); - EVP_CIPHER_meth_set_do_cipher(*aes_ctr_cipher, aes_ctr_do_cipher); - EVP_CIPHER_meth_set_cleanup(*aes_ctr_cipher, aes_ctr_cleanup); - } -#else - (*aes_ctr_cipher)->nid = type; - (*aes_ctr_cipher)->block_size = 16; - (*aes_ctr_cipher)->key_len = keylen; - (*aes_ctr_cipher)->iv_len = 16; - (*aes_ctr_cipher)->init = aes_ctr_init; - (*aes_ctr_cipher)->do_cipher = aes_ctr_do_cipher; - (*aes_ctr_cipher)->cleanup = aes_ctr_cleanup; -#endif - - return *aes_ctr_cipher; -} - -const EVP_CIPHER * -_libssh2_EVP_aes_128_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - static EVP_CIPHER * aes_ctr_cipher; - return !aes_ctr_cipher ? - make_ctr_evp(16, &aes_ctr_cipher, NID_aes_128_ctr) : aes_ctr_cipher; +#if (defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3) || \ + defined(LIBSSH2_WOLFSSL) + if(ret != -1) #else - static EVP_CIPHER aes_ctr_cipher; - static EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher; - return !aes_ctr_cipher.key_len ? - make_ctr_evp(16, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher; + if(ret >= 1) #endif -} - -const EVP_CIPHER * -_libssh2_EVP_aes_192_ctr(void) -{ + { + rc = 0; + if(IS_LAST(firstlast)) { + /* This is the last block. + encrypt: compute tag, if applicable + decrypt: verify tag, if applicable + in!=NULL is equivalent to EVP_CipherUpdate + in==NULL is equivalent to EVP_CipherFinal */ #ifdef HAVE_OPAQUE_STRUCTS - static EVP_CIPHER * aes_ctr_cipher; - return !aes_ctr_cipher ? - make_ctr_evp(24, &aes_ctr_cipher, NID_aes_192_ctr) : aes_ctr_cipher; + ret = EVP_Cipher(*ctx, NULL, NULL, 0); /* final */ #else - static EVP_CIPHER aes_ctr_cipher; - static EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher; - return !aes_ctr_cipher.key_len ? - make_ctr_evp(24, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher; + ret = EVP_Cipher(ctx, NULL, NULL, 0); /* final */ #endif -} + if(ret < 0) { + ret = 0; + } + else { + ret = 1; +#if LIBSSH2_AES_GCM + if(is_aesgcm && encrypt) { + /* write the Authentication Tag a.k.a. MAC at the end + of the block */ + assert(authenticationtag == authlen); + ret = EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_GCM_GET_TAG, + authlen, block + blocksize - authenticationtag); + } +#endif /* LIBSSH2_AES_GCM */ + } + } + /* Copy en/decrypted data back to the caller. + The first aadlen should not be touched because they weren't + encrypted and are unmodified. */ + memcpy(block + aadlen, buf + aadlen, cryptlen); + rc = !ret; + } -const EVP_CIPHER * -_libssh2_EVP_aes_256_ctr(void) -{ -#ifdef HAVE_OPAQUE_STRUCTS - static EVP_CIPHER * aes_ctr_cipher; - return !aes_ctr_cipher ? - make_ctr_evp(32, &aes_ctr_cipher, NID_aes_256_ctr) : aes_ctr_cipher; -#else - static EVP_CIPHER aes_ctr_cipher; - static EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher; - return !aes_ctr_cipher.key_len ? - make_ctr_evp(32, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher; -#endif + /* TODO: the return code should distinguish between decryption errors and + invalid MACs */ + return rc; } -#endif /* LIBSSH2_AES_CTR */ - -#ifndef HAVE_EVP_AES_128_CTR -static EVP_CIPHER * aes_128_ctr_cipher = NULL; -static EVP_CIPHER * aes_192_ctr_cipher = NULL; -static EVP_CIPHER * aes_256_ctr_cipher = NULL; -#endif - void _libssh2_openssl_crypto_init(void) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ @@ -655,44 +632,22 @@ void _libssh2_openssl_crypto_init(void) ENGINE_register_all_complete(); #endif #endif -#ifndef HAVE_EVP_AES_128_CTR - aes_128_ctr_cipher = (EVP_CIPHER *)_libssh2_EVP_aes_128_ctr(); - aes_192_ctr_cipher = (EVP_CIPHER *)_libssh2_EVP_aes_192_ctr(); - aes_256_ctr_cipher = (EVP_CIPHER *)_libssh2_EVP_aes_256_ctr(); -#endif } void _libssh2_openssl_crypto_exit(void) { -#ifndef HAVE_EVP_AES_128_CTR -#ifdef HAVE_OPAQUE_STRUCTS - if(aes_128_ctr_cipher) { - EVP_CIPHER_meth_free(aes_128_ctr_cipher); - } - - if(aes_192_ctr_cipher) { - EVP_CIPHER_meth_free(aes_192_ctr_cipher); - } - - if(aes_256_ctr_cipher) { - EVP_CIPHER_meth_free(aes_256_ctr_cipher); - } -#endif - - aes_128_ctr_cipher = NULL; - aes_192_ctr_cipher = NULL; - aes_256_ctr_cipher = NULL; -#endif } +#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA || LIBSSH2_ED25519 /* TODO: Optionally call a passphrase callback specified by the * calling program */ static int passphrase_cb(char *buf, int size, int rwflag, char *passphrase) { - int passphrase_len = strlen(passphrase); - (void) rwflag; + int passphrase_len = (int) strlen(passphrase); + + (void)rwflag; if(passphrase_len > (size - 1)) { passphrase_len = size - 1; @@ -717,19 +672,24 @@ read_private_key_from_memory(void **key_ctx, *key_ctx = NULL; - bp = BIO_new_mem_buf((char *)filedata, filedata_len); +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL + bp = BIO_new_mem_buf(filedata, (int)filedata_len); +#else + bp = BIO_new_mem_buf((char *)filedata, (int)filedata_len); +#endif if(!bp) { return -1; } + *key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb, (void *) passphrase); BIO_free(bp); return (*key_ctx) ? 0 : -1; } +#endif - - +#if LIBSSH2_RSA || LIBSSH2_DSA || LIBSSH2_ECDSA static int read_private_key_from_file(void **key_ctx, pem_read_bio_func read_private_key, @@ -751,7 +711,9 @@ read_private_key_from_file(void **key_ctx, BIO_free(bp); return (*key_ctx) ? 0 : -1; } +#endif +#if LIBSSH2_RSA int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, LIBSSH2_SESSION * session, @@ -762,7 +724,6 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, pem_read_bio_func read_rsa = (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; - (void) session; _libssh2_init_if_needed(); @@ -774,7 +735,7 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, "ssh-rsa", filedata, filedata_len, passphrase); } -return rc; + return rc; } static unsigned char * @@ -800,7 +761,7 @@ gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; key = LIBSSH2_ALLOC(session, len); - if(key == NULL) { + if(!key) { return NULL; } @@ -832,23 +793,23 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, unsigned char *method_buf = NULL; size_t key_len; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing public key from RSA private key envelop"); + "Computing public key from RSA private key envelope")); rsa = EVP_PKEY_get1_RSA(pk); - if(rsa == NULL) { + if(!rsa) { /* Assume memory allocation error... what else could it be ? */ goto __alloc_error; } method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */ - if(method_buf == NULL) { + if(!method_buf) { goto __alloc_error; } key = gen_publickey_from_rsa(session, rsa, &key_len); - if(key == NULL) { + if(!key) { goto __alloc_error; } RSA_free(rsa); @@ -860,11 +821,11 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, *pubkeydata_len = key_len; return 0; - __alloc_error: - if(rsa != NULL) { +__alloc_error: + if(rsa) { RSA_free(rsa); } - if(method_buf != NULL) { + if(method_buf) { LIBSSH2_FREE(session, method_buf); } @@ -894,23 +855,23 @@ static int _libssh2_rsa_new_additional_parameters(RSA *rsa) #endif ctx = BN_CTX_new(); - if(ctx == NULL) + if(!ctx) return -1; aux = BN_new(); - if(aux == NULL) { + if(!aux) { rc = -1; goto out; } dmp1 = BN_new(); - if(dmp1 == NULL) { + if(!dmp1) { rc = -1; goto out; } dmq1 = BN_new(); - if(dmq1 == NULL) { + if(!dmq1) { rc = -1; goto out; } @@ -935,7 +896,7 @@ out: BN_clear_free(aux); BN_CTX_free(ctx); - if(rc != 0) { + if(rc) { if(dmp1) BN_clear_free(dmp1); if(dmq1) @@ -959,9 +920,9 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, unsigned char *n, *e, *d, *p, *q, *coeff, *comment; RSA *rsa = NULL; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing RSA keys from private key data"); + "Computing RSA keys from private key data")); /* public key data */ if(_libssh2_get_bignum_bytes(decrypted, &n, &nlen)) { @@ -1007,19 +968,25 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, return -1; } - if((rc = _libssh2_rsa_new(&rsa, e, elen, n, nlen, d, dlen, p, plen, - q, qlen, NULL, 0, NULL, 0, - coeff, coefflen)) != 0) { - _libssh2_debug(session, + rc = _libssh2_rsa_new(&rsa, + e, (unsigned long)elen, + n, (unsigned long)nlen, + d, (unsigned long)dlen, + p, (unsigned long)plen, + q, (unsigned long)qlen, + NULL, 0, NULL, 0, + coeff, (unsigned long)coefflen); + if(rc) { + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Could not create RSA private key"); + "Could not create RSA private key")); goto fail; } - if(rsa != NULL) + if(rsa) rc = _libssh2_rsa_new_additional_parameters(rsa); - if(rsa != NULL && pubkeydata != NULL && method != NULL) { + if(rsa && pubkeydata && method) { EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pk, rsa); @@ -1031,7 +998,7 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, EVP_PKEY_free(pk); } - if(rsa_ctx != NULL) + if(rsa_ctx) *rsa_ctx = rsa; else RSA_free(rsa); @@ -1040,7 +1007,7 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, fail: - if(rsa != NULL) + if(rsa) RSA_free(rsa); return _libssh2_error(session, @@ -1059,7 +1026,7 @@ _libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa, unsigned char *buf = NULL; struct string_buf *decrypted = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -1083,7 +1050,7 @@ _libssh2_rsa_new_openssh_private(libssh2_rsa_ctx ** rsa, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -1113,7 +1080,6 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, pem_read_bio_func read_rsa = (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; - (void) session; _libssh2_init_if_needed(); @@ -1127,6 +1093,7 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, return rc; } +#endif #if LIBSSH2_DSA int @@ -1139,16 +1106,18 @@ _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, pem_read_bio_func read_dsa = (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; - (void) session; _libssh2_init_if_needed(); rc = read_private_key_from_memory((void **)dsa, read_dsa, - filedata, filedata_len, passphrase); + filedata, filedata_len, + passphrase); if(rc) { rc = read_openssh_private_key_from_memory((void **)dsa, session, - "ssh-dsa", filedata, filedata_len, passphrase); + "ssh-dsa", + filedata, filedata_len, + passphrase); } return rc; @@ -1189,7 +1158,7 @@ gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes; key = LIBSSH2_ALLOC(session, len); - if(key == NULL) { + if(!key) { return NULL; } @@ -1223,23 +1192,23 @@ gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session, unsigned char *method_buf = NULL; size_t key_len; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing public key from DSA private key envelop"); + "Computing public key from DSA private key envelope")); dsa = EVP_PKEY_get1_DSA(pk); - if(dsa == NULL) { + if(!dsa) { /* Assume memory allocation error... what else could it be ? */ goto __alloc_error; } method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */ - if(method_buf == NULL) { + if(!method_buf) { goto __alloc_error; } key = gen_publickey_from_dsa(session, dsa, &key_len); - if(key == NULL) { + if(!key) { goto __alloc_error; } DSA_free(dsa); @@ -1251,11 +1220,11 @@ gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session, *pubkeydata_len = key_len; return 0; - __alloc_error: - if(dsa != NULL) { +__alloc_error: + if(dsa) { DSA_free(dsa); } - if(method_buf != NULL) { + if(method_buf) { LIBSSH2_FREE(session, method_buf); } @@ -1278,9 +1247,9 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, unsigned char *p, *q, *g, *pub_key, *priv_key; DSA *dsa = NULL; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing DSA keys from private key data"); + "Computing DSA keys from private key data")); if(_libssh2_get_bignum_bytes(decrypted, &p, &plen)) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, @@ -1312,16 +1281,20 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, return -1; } - rc = _libssh2_dsa_new(&dsa, p, plen, q, qlen, g, glen, pub_key, pub_len, - priv_key, priv_len); - if(rc != 0) { - _libssh2_debug(session, + rc = _libssh2_dsa_new(&dsa, + p, (unsigned long)plen, + q, (unsigned long)qlen, + g, (unsigned long)glen, + pub_key, (unsigned long)pub_len, + priv_key, (unsigned long)priv_len); + if(rc) { + _libssh2_debug((session, LIBSSH2_ERROR_PROTO, - "Could not create DSA private key"); + "Could not create DSA private key")); goto fail; } - if(dsa != NULL && pubkeydata != NULL && method != NULL) { + if(dsa && pubkeydata && method) { EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_DSA(pk, dsa); @@ -1333,7 +1306,7 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, EVP_PKEY_free(pk); } - if(dsa_ctx != NULL) + if(dsa_ctx) *dsa_ctx = dsa; else DSA_free(dsa); @@ -1342,7 +1315,7 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, fail: - if(dsa != NULL) + if(dsa) DSA_free(dsa); return _libssh2_error(session, @@ -1361,7 +1334,7 @@ _libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa, unsigned char *buf = NULL; struct string_buf *decrypted = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -1385,7 +1358,7 @@ _libssh2_dsa_new_openssh_private(libssh2_dsa_ctx ** dsa, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -1415,7 +1388,6 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, pem_read_bio_func read_dsa = (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; - (void) session; _libssh2_init_if_needed(); @@ -1429,147 +1401,204 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, return rc; } - #endif /* LIBSSH_DSA */ #if LIBSSH2_ECDSA int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, - LIBSSH2_SESSION * session, - const char *filedata, size_t filedata_len, - unsigned const char *passphrase) + LIBSSH2_SESSION * session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) { int rc; pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; - (void) session; _libssh2_init_if_needed(); rc = read_private_key_from_memory((void **) ec_ctx, read_ec, - filedata, filedata_len, passphrase); + filedata, filedata_len, + passphrase); if(rc) { rc = read_openssh_private_key_from_memory((void **)ec_ctx, session, - "ssh-ecdsa", filedata, - filedata_len, passphrase); + "ssh-ecdsa", + filedata, filedata_len, + passphrase); } return rc; } +int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) +{ + int algorithm; + return _libssh2_sk_pub_openssh_keyfilememory(session, + (void **)ec_ctx, + "sk-ecdsa-sha2-nistp256@openssh.com", + NULL, + NULL, + NULL, + NULL, + &algorithm, + flags, + application, + key_handle, + handle_len, + filedata, + filedata_len, + passphrase); +} + #endif /* LIBSSH2_ECDSA */ #if LIBSSH2_ED25519 int -_libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx, +_libssh2_curve25519_new(LIBSSH2_SESSION *session, unsigned char **out_public_key, unsigned char **out_private_key) { EVP_PKEY *key = NULL; EVP_PKEY_CTX *pctx = NULL; - PKCS8_PRIV_KEY_INFO *info = NULL; - ASN1_OCTET_STRING *oct = NULL; - X509_PUBKEY *pubkey = NULL; - libssh2_ed25519_ctx *ctx = NULL; - const unsigned char *pkcs, *priv, *pub; - int privLen, pubLen, pkcsLen; + unsigned char *priv = NULL, *pub = NULL; + size_t privLen, pubLen; int rc = -1; pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); - if(pctx == NULL) + if(!pctx) return -1; - EVP_PKEY_keygen_init(pctx); - EVP_PKEY_keygen(pctx, &key); - info = EVP_PKEY2PKCS8(key); - - if(info == NULL || !PKCS8_pkey_get0(NULL, &pkcs, &pkcsLen, NULL, info)) - goto cleanExit; - - oct = d2i_ASN1_OCTET_STRING(NULL, &pkcs, pkcsLen); - if(oct == NULL) { - goto cleanExit; + if(EVP_PKEY_keygen_init(pctx) != 1 || + EVP_PKEY_keygen(pctx, &key) != 1) { + goto clean_exit; } - priv = ASN1_STRING_get0_data(oct); - privLen = ASN1_STRING_length(oct); - - if(privLen != LIBSSH2_ED25519_KEY_LEN) - goto cleanExit; - - pubkey = X509_PUBKEY_new(); - if(pubkey == NULL || !X509_PUBKEY_set(&pubkey, key)) - goto cleanExit; - - if(!X509_PUBKEY_get0_param(NULL, &pub, &pubLen, NULL, pubkey)) - goto cleanExit; - - if(pubLen != LIBSSH2_ED25519_KEY_LEN) - goto cleanExit; - - if(out_private_key != NULL) { - *out_private_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN); - if(*out_private_key == NULL) - goto cleanExit; - - memcpy(*out_private_key, priv, LIBSSH2_ED25519_KEY_LEN); - } + if(out_private_key) { + privLen = LIBSSH2_ED25519_KEY_LEN; + priv = LIBSSH2_ALLOC(session, privLen); + if(!priv) + goto clean_exit; - if(out_public_key != NULL) { - *out_public_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN); - if(*out_public_key == NULL) - goto cleanExit; + if(EVP_PKEY_get_raw_private_key(key, priv, &privLen) != 1 || + privLen != LIBSSH2_ED25519_KEY_LEN) { + goto clean_exit; + } - memcpy(*out_public_key, pub, LIBSSH2_ED25519_KEY_LEN); + *out_private_key = priv; + priv = NULL; } - if(out_ctx != NULL) { - ctx = malloc(sizeof(libssh2_x25519_ctx)); - if(ctx == NULL) - goto cleanExit; - - ctx->private_key = - EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, - (const unsigned char *)priv, - LIBSSH2_ED25519_KEY_LEN); - - ctx->public_key = - EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, - (const unsigned char *)pub, - LIBSSH2_ED25519_KEY_LEN); + if(out_public_key) { + pubLen = LIBSSH2_ED25519_KEY_LEN; + pub = LIBSSH2_ALLOC(session, pubLen); + if(!pub) + goto clean_exit; - if(ctx->public_key == NULL || ctx->private_key == NULL) { - _libssh2_x25519_free(ctx); - goto cleanExit; + if(EVP_PKEY_get_raw_public_key(key, pub, &pubLen) != 1 || + pubLen != LIBSSH2_ED25519_KEY_LEN) { + goto clean_exit; } - *out_ctx = ctx; + *out_public_key = pub; + pub = NULL; } /* success */ rc = 0; -cleanExit: +clean_exit: - if(info) - PKCS8_PRIV_KEY_INFO_free(info); if(pctx) EVP_PKEY_CTX_free(pctx); - if(oct) - ASN1_OCTET_STRING_free(oct); - if(pubkey) - X509_PUBKEY_free(pubkey); if(key) EVP_PKEY_free(key); + if(priv) + LIBSSH2_FREE(session, priv); + if(pub) + LIBSSH2_FREE(session, pub); return rc; } + +static int +gen_publickey_from_ed_evp(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + EVP_PKEY *pk) +{ + const char methodName[] = "ssh-ed25519"; + unsigned char *methodBuf = NULL; + size_t rawKeyLen = 0; + unsigned char *keyBuf = NULL; + size_t bufLen = 0; + unsigned char *bufPos = NULL; + + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Computing public key from ED private key envelope")); + + methodBuf = LIBSSH2_ALLOC(session, sizeof(methodName) - 1); + if(!methodBuf) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for private key data"); + goto fail; + } + memcpy(methodBuf, methodName, sizeof(methodName) - 1); + + if(EVP_PKEY_get_raw_public_key(pk, NULL, &rawKeyLen) != 1) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "EVP_PKEY_get_raw_public_key failed"); + goto fail; + } + + /* Key form is: type_len(4) + type(11) + pub_key_len(4) + pub_key(32). */ + bufLen = 4 + sizeof(methodName) - 1 + 4 + rawKeyLen; + bufPos = keyBuf = LIBSSH2_ALLOC(session, bufLen); + if(!keyBuf) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for private key data"); + goto fail; + } + + _libssh2_store_str(&bufPos, methodName, sizeof(methodName) - 1); + _libssh2_store_u32(&bufPos, (uint32_t) rawKeyLen); + + if(EVP_PKEY_get_raw_public_key(pk, bufPos, &rawKeyLen) != 1) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "EVP_PKEY_get_raw_public_key failed"); + goto fail; + } + + *method = methodBuf; + *method_len = sizeof(methodName) - 1; + *pubkeydata = keyBuf; + *pubkeydata_len = bufLen; + return 0; + +fail: + if(methodBuf) + LIBSSH2_FREE(session, methodBuf); + if(keyBuf) + LIBSSH2_FREE(session, keyBuf); + return -1; +} + + static int gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, struct string_buf *decrypted, @@ -1587,9 +1616,9 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, size_t key_len = 0, tmp_len = 0; unsigned char *p; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing ED25519 keys from private key data"); + "Computing ED25519 keys from private key data")); if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) || tmp_len != LIBSSH2_ED25519_KEY_LEN) { @@ -1606,25 +1635,11 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, goto clean_exit; } - ctx = _libssh2_ed25519_new_ctx(); - if(ctx == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for ed25519 key"); - ret = -1; - goto clean_exit; - } - /* first 32 bytes of priv_key is the private key, the last 32 bytes are the public key */ - ctx->private_key = - EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, - (const unsigned char *)priv_key, - LIBSSH2_ED25519_KEY_LEN); - - ctx->public_key = - EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, - (const unsigned char *)pub_key, - LIBSSH2_ED25519_KEY_LEN); + ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, + (const unsigned char *)priv_key, + LIBSSH2_ED25519_KEY_LEN); /* comment */ if(_libssh2_get_string(decrypted, &buf, &tmp_len)) { @@ -1636,12 +1651,12 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, if(tmp_len > 0) { unsigned char *comment = LIBSSH2_CALLOC(session, tmp_len + 1); - if(comment != NULL) { + if(comment) { memcpy(comment, buf, tmp_len); memcpy(comment + tmp_len, "\0", 1); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Key comment: %s", - comment); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Key comment: %s", + comment)); LIBSSH2_FREE(session, comment); } @@ -1661,13 +1676,15 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, } if(ret == 0) { - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Computing public key from ED25519 " - "private key envelop"); + "private key envelope")); method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */ - if(method_buf == NULL) { + if(!method_buf) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); goto clean_exit; } @@ -1675,7 +1692,9 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, pub_key(32). */ key_len = LIBSSH2_ED25519_KEY_LEN + 19; key = LIBSSH2_CALLOC(session, key_len); - if(key == NULL) { + if(!key) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); goto clean_exit; } @@ -1686,25 +1705,168 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, memcpy(method_buf, "ssh-ed25519", 11); - if(method != NULL) + if(method) *method = method_buf; else LIBSSH2_FREE(session, method_buf); - if(method_len != NULL) + if(method_len) *method_len = 11; - if(pubkeydata != NULL) + if(pubkeydata) *pubkeydata = key; else LIBSSH2_FREE(session, key); - if(pubkeydata_len != NULL) + if(pubkeydata_len) + *pubkeydata_len = key_len; + + if(out_ctx) + *out_ctx = ctx; + else if(ctx) + _libssh2_ed25519_free(ctx); + + return 0; + } + +clean_exit: + + if(ctx) + _libssh2_ed25519_free(ctx); + + if(method_buf) + LIBSSH2_FREE(session, method_buf); + + if(key) + LIBSSH2_FREE(session, key); + + return -1; +} + +static int +gen_publickey_from_sk_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, + struct string_buf *decrypted, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + libssh2_ed25519_ctx **out_ctx) +{ + const char *key_type = "sk-ssh-ed25519@openssh.com"; + + libssh2_ed25519_ctx *ctx = NULL; + unsigned char *method_buf = NULL; + unsigned char *key = NULL; + int ret = 0; + unsigned char *pub_key, *app; + size_t key_len = 0, app_len = 0, tmp_len = 0; + unsigned char *p; + + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing sk-ED25519 keys from private key data")); + + if(_libssh2_get_string(decrypted, &pub_key, &tmp_len) || + tmp_len != LIBSSH2_ED25519_KEY_LEN) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Wrong public key length"); + return -1; + } + + if(_libssh2_get_string(decrypted, &app, &app_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK application."); + return -1; + } + + if(flags && _libssh2_get_byte(decrypted, flags)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK flags."); + return -1; + } + + if(key_handle && handle_len) { + unsigned char *handle = NULL; + if(_libssh2_get_string(decrypted, &handle, handle_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK key_handle."); + return -1; + } + + if(*handle_len > 0) { + *key_handle = LIBSSH2_ALLOC(session, *handle_len); + + if(key_handle) { + memcpy((void *)*key_handle, handle, *handle_len); + } + } + } + + ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, + (const unsigned char *)pub_key, + LIBSSH2_ED25519_KEY_LEN); + + if(ret == 0) { + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing public key from ED25519 " + "private key envelope")); + + /* sk-ssh-ed25519@openssh.com. */ + method_buf = LIBSSH2_ALLOC(session, strlen(key_type)); + if(!method_buf) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); + goto clean_exit; + } + + /* Key form is: type_len(4) + type(26) + pub_key_len(4) + + pub_key(32) + application_len(4) + application(X). */ + key_len = LIBSSH2_ED25519_KEY_LEN + 38 + app_len; + key = LIBSSH2_CALLOC(session, key_len); + if(!key) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); + goto clean_exit; + } + + p = key; + + _libssh2_store_str(&p, key_type, strlen(key_type)); + _libssh2_store_str(&p, (const char *)pub_key, LIBSSH2_ED25519_KEY_LEN); + _libssh2_store_str(&p, (const char *)app, app_len); + + if(application && app_len > 0) { + *application = (const char *)LIBSSH2_ALLOC(session, app_len + 1); + _libssh2_explicit_zero((void *)*application, app_len + 1); + memcpy((void *)*application, app, app_len); + } + + memcpy(method_buf, key_type, strlen(key_type)); + + if(method) + *method = method_buf; + else + LIBSSH2_FREE(session, method_buf); + + if(method_len) + *method_len = strlen(key_type); + + if(pubkeydata) + *pubkeydata = key; + else if(key) + LIBSSH2_FREE(session, key); + + if(pubkeydata_len) *pubkeydata_len = key_len; - if(out_ctx != NULL) + if(out_ctx) *out_ctx = ctx; - else if(ctx != NULL) + else if(ctx) _libssh2_ed25519_free(ctx); return 0; @@ -1721,9 +1883,20 @@ clean_exit: if(key) LIBSSH2_FREE(session, key); + if(application && *application) { + LIBSSH2_FREE(session, (void *)application); + *application = NULL; + } + + if(key_handle && *key_handle) { + LIBSSH2_FREE(session, (void *)key_handle); + *key_handle = NULL; + } + return -1; } + int _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, LIBSSH2_SESSION * session, @@ -1735,7 +1908,7 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, struct string_buf *decrypted = NULL; libssh2_ed25519_ctx *ctx = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -1759,7 +1932,7 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -1782,9 +1955,85 @@ _libssh2_ed25519_new_private(libssh2_ed25519_ctx ** ed_ctx, _libssh2_string_buf_free(session, decrypted); if(rc == 0) { - if(ed_ctx != NULL) + if(ed_ctx) + *ed_ctx = ctx; + else if(ctx) + _libssh2_ed25519_free(ctx); + } + + return rc; +} + +int +_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filename, + const uint8_t *passphrase) +{ + int rc; + FILE *fp; + unsigned char *buf; + struct string_buf *decrypted = NULL; + libssh2_ed25519_ctx *ctx = NULL; + + if(!session) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Session is required"); + return -1; + } + + _libssh2_init_if_needed(); + + fp = fopen(filename, "r"); + if(!fp) { + _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to open ED25519 SK private key file"); + return -1; + } + + rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); + fclose(fp); + if(rc) { + return rc; + } + + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); + + if(rc || !buf) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted key data not found"); + return -1; + } + + if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) { + rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session, + decrypted, + NULL, + NULL, + NULL, + NULL, + flags, + application, + key_handle, + handle_len, + &ctx); + } + else { + rc = -1; + } + + if(decrypted) + _libssh2_string_buf_free(session, decrypted); + + if(rc == 0) { + if(ed_ctx) *ed_ctx = ctx; - else if(ctx != NULL) + else if(ctx) _libssh2_ed25519_free(ctx); } @@ -1798,6 +2047,25 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx, size_t filedata_len, unsigned const char *passphrase) { + libssh2_ed25519_ctx *ctx = NULL; + + _libssh2_init_if_needed(); + + if(read_private_key_from_memory((void **)&ctx, + (pem_read_bio_func) + &PEM_read_bio_PrivateKey, + filedata, filedata_len, + passphrase) == 0) { + if(EVP_PKEY_id(ctx) != EVP_PKEY_ED25519) { + _libssh2_ed25519_free(ctx); + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Private key is not an ED25519 key"); + } + + *ed_ctx = ctx; + return 0; + } + return read_openssh_private_key_from_memory((void **)ed_ctx, session, "ssh-ed25519", filedata, filedata_len, @@ -1805,46 +2073,64 @@ _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx ** ed_ctx, } int +_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase) +{ + int algorithm; + return _libssh2_sk_pub_openssh_keyfilememory(session, + (void **)ed_ctx, + "sk-ssh-ed25519@openssh.com", + NULL, + NULL, + NULL, + NULL, + &algorithm, + flags, + application, + key_handle, + handle_len, + filedata, + filedata_len, + passphrase); +} + +int _libssh2_ed25519_new_public(libssh2_ed25519_ctx ** ed_ctx, LIBSSH2_SESSION * session, const unsigned char *raw_pub_key, - const uint8_t key_len) + const size_t key_len) { libssh2_ed25519_ctx *ctx = NULL; - EVP_PKEY *public_key = NULL; - if(ed_ctx == NULL) + if(!ed_ctx) return -1; - public_key = - EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, - (const unsigned char *)raw_pub_key, - key_len); - if(public_key == NULL) { + ctx = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, + raw_pub_key, key_len); + if(!ctx) return _libssh2_error(session, LIBSSH2_ERROR_PROTO, "could not create ED25519 public key"); - } - - ctx = _libssh2_ed25519_new_ctx(); - if(ctx == NULL) { - return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "could not alloc public/private key"); - } - - ctx->public_key = public_key; - if(ed_ctx != NULL) + if(ed_ctx) *ed_ctx = ctx; - else if(ctx != NULL) + else if(ctx) _libssh2_ed25519_free(ctx); return 0; } - #endif /* LIBSSH2_ED25519 */ + +#if LIBSSH2_RSA int -_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, +_libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session, libssh2_rsa_ctx * rsactx, const unsigned char *hash, size_t hash_len, @@ -1861,7 +2147,20 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, return -1; } - ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx); + if(hash_len == SHA_DIGEST_LENGTH) + ret = RSA_sign(NID_sha1, + hash, (unsigned int) hash_len, sig, &sig_len, rsactx); + else if(hash_len == SHA256_DIGEST_LENGTH) + ret = RSA_sign(NID_sha256, + hash, (unsigned int) hash_len, sig, &sig_len, rsactx); + else if(hash_len == SHA512_DIGEST_LENGTH) + ret = RSA_sign(NID_sha512, + hash, (unsigned int) hash_len, sig, &sig_len, rsactx); + else { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unsupported hash digest length"); + ret = -1; + } if(!ret) { LIBSSH2_FREE(session, sig); @@ -1874,17 +2173,32 @@ _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, return 0; } +#if LIBSSH2_RSA_SHA1 +int +_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, + libssh2_rsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, size_t *signature_len) +{ + return _libssh2_rsa_sha2_sign(session, rsactx, hash, hash_len, + signature, signature_len); +} +#endif +#endif + #if LIBSSH2_DSA int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, - unsigned long hash_len, unsigned char *signature) + size_t hash_len, unsigned char *signature) { DSA_SIG *sig; const BIGNUM * r; const BIGNUM * s; int r_len, s_len; - (void) hash_len; + + (void)hash_len; sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); if(!sig) { @@ -1923,8 +2237,8 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, int _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, - const unsigned char *hash, unsigned long hash_len, - unsigned char **signature, size_t *signature_len) + const unsigned char *hash, size_t hash_len, + unsigned char **signature, size_t *signature_len) { int r_len, s_len; int rc = 0; @@ -1934,8 +2248,8 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, unsigned char *temp_buffer = NULL; unsigned char *out_buffer = NULL; - ECDSA_SIG *sig = ECDSA_do_sign(hash, hash_len, ec_ctx); - if(sig == NULL) + ECDSA_SIG *sig = ECDSA_do_sign(hash, (int) hash_len, ec_ctx); + if(!sig) return -1; #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG_get0(sig, &pr, &ps); @@ -1948,7 +2262,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, s_len = BN_num_bytes(ps) + 1; temp_buffer = malloc(r_len + s_len + 8); - if(temp_buffer == NULL) { + if(!temp_buffer) { rc = -1; goto clean_exit; } @@ -1960,7 +2274,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, out_buffer_len = (size_t)(sp - temp_buffer); out_buffer = LIBSSH2_CALLOC(session, out_buffer_len); - if(out_buffer == NULL) { + if(!out_buffer) { rc = -1; goto clean_exit; } @@ -1972,7 +2286,7 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, clean_exit: - if(temp_buffer != NULL) + if(temp_buffer) free(temp_buffer); if(sig) @@ -1988,7 +2302,7 @@ _libssh2_sha1_init(libssh2_sha1_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha1"))) @@ -2005,13 +2319,13 @@ _libssh2_sha1_init(libssh2_sha1_ctx *ctx) } int -_libssh2_sha1(const unsigned char *message, unsigned long len, +_libssh2_sha1(const unsigned char *message, size_t len, unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha1"))) { @@ -2040,7 +2354,7 @@ _libssh2_sha256_init(libssh2_sha256_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha256"))) @@ -2057,13 +2371,13 @@ _libssh2_sha256_init(libssh2_sha256_ctx *ctx) } int -_libssh2_sha256(const unsigned char *message, unsigned long len, +_libssh2_sha256(const unsigned char *message, size_t len, unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha256"))) { @@ -2092,7 +2406,7 @@ _libssh2_sha384_init(libssh2_sha384_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha384"))) @@ -2109,13 +2423,13 @@ _libssh2_sha384_init(libssh2_sha384_ctx *ctx) } int -_libssh2_sha384(const unsigned char *message, unsigned long len, - unsigned char *out) +_libssh2_sha384(const unsigned char *message, size_t len, + unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha384"))) { @@ -2144,7 +2458,7 @@ _libssh2_sha512_init(libssh2_sha512_ctx *ctx) #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("sha512"))) @@ -2161,13 +2475,13 @@ _libssh2_sha512_init(libssh2_sha512_ctx *ctx) } int -_libssh2_sha512(const unsigned char *message, unsigned long len, - unsigned char *out) +_libssh2_sha512(const unsigned char *message, size_t len, + unsigned char *out) { #ifdef HAVE_OPAQUE_STRUCTS EVP_MD_CTX * ctx = EVP_MD_CTX_new(); - if(ctx == NULL) + if(!ctx) return 1; /* error */ if(EVP_DigestInit(ctx, EVP_get_digestbyname("sha512"))) { @@ -2193,10 +2507,24 @@ _libssh2_sha512(const unsigned char *message, unsigned long len, int _libssh2_md5_init(libssh2_md5_ctx *ctx) { + /* MD5 digest is not supported in OpenSSL FIPS mode + * Trying to init it will result in a latent OpenSSL error: + * "digital envelope routines:FIPS_DIGESTINIT:disabled for fips" + * So, just return 0 in FIPS mode + */ +#if OPENSSL_VERSION_NUMBER >= 0x000907000L && \ + defined(OPENSSL_VERSION_MAJOR) && \ + OPENSSL_VERSION_MAJOR < 3 && \ + !defined(LIBRESSL_VERSION_NUMBER) + + if(FIPS_mode()) + return 0; +#endif + #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); - if(*ctx == NULL) + if(!*ctx) return 0; if(EVP_DigestInit(*ctx, EVP_get_digestbyname("md5"))) @@ -2220,6 +2548,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, size_t *method_len, unsigned char **pubkeydata, size_t *pubkeydata_len, + int is_sk, EVP_PKEY *pk) { int rc = 0; @@ -2235,40 +2564,47 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, BN_CTX *bn_ctx; libssh2_curve_type type; - _libssh2_debug(session, - LIBSSH2_TRACE_AUTH, - "Computing public key from EC private key envelop"); + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing public key from EC private key envelope")); bn_ctx = BN_CTX_new(); - if(bn_ctx == NULL) + if(!bn_ctx) return -1; ec = EVP_PKEY_get1_EC_KEY(pk); - if(ec == NULL) { + if(!ec) { rc = -1; goto clean_exit; } public_key = EC_KEY_get0_public_key(ec); group = EC_KEY_get0_group(ec); - type = _libssh2_ecdsa_key_get_curve_type(ec); + type = _libssh2_ecdsa_get_curve_type(ec); + + if(is_sk) + *method_len = 34; + else + *method_len = 19; - method_buf = LIBSSH2_ALLOC(session, 19); - if(method_buf == NULL) { + method_buf = LIBSSH2_ALLOC(session, *method_len); + if(!method_buf) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "out of memory"); + "out of memory"); } - if(type == LIBSSH2_EC_CURVE_NISTP256) - memcpy(method_buf, "ecdsa-sha2-nistp256", 19); + if(is_sk) + memcpy(method_buf, "sk-ecdsa-sha2-nistp256@openssh.com", *method_len); + else if(type == LIBSSH2_EC_CURVE_NISTP256) + memcpy(method_buf, "ecdsa-sha2-nistp256", *method_len); else if(type == LIBSSH2_EC_CURVE_NISTP384) - memcpy(method_buf, "ecdsa-sha2-nistp384", 19); + memcpy(method_buf, "ecdsa-sha2-nistp384", *method_len); else if(type == LIBSSH2_EC_CURVE_NISTP521) - memcpy(method_buf, "ecdsa-sha2-nistp521", 19); + memcpy(method_buf, "ecdsa-sha2-nistp521", *method_len); else { - _libssh2_debug(session, - LIBSSH2_TRACE_ERROR, - "Unsupported EC private key type"); + _libssh2_debug((session, + LIBSSH2_TRACE_ERROR, + "Unsupported EC private key type")); rc = -1; goto clean_exit; } @@ -2283,7 +2619,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, } octal_value = malloc(octal_len); - if(octal_value == NULL) { + if(!octal_value) { rc = -1; goto clean_exit; } @@ -2291,52 +2627,56 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, /* convert to octal */ if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, octal_value, octal_len, bn_ctx) != octal_len) { - rc = -1; - goto clean_exit; + rc = -1; + goto clean_exit; } - /* Key form is: type_len(4) + type(19) + domain_len(4) + domain(8) + - pub_key_len(4) + pub_key(~65). */ - key_len = 4 + 19 + 4 + 8 + 4 + octal_len; + /* Key form is: type_len(4) + type(method_len) + domain_len(4) + domain(8) + + pub_key_len(4) + pub_key(~65). */ + key_len = 4 + *method_len + 4 + 8 + 4 + octal_len; key = LIBSSH2_ALLOC(session, key_len); - if(key == NULL) { + if(!key) { rc = -1; - goto clean_exit; + goto clean_exit; } /* Process key encoding. */ p = key; /* Key type */ - _libssh2_store_str(&p, (const char *)method_buf, 19); + _libssh2_store_str(&p, (const char *)method_buf, *method_len); /* Name domain */ - _libssh2_store_str(&p, (const char *)method_buf + 11, 8); + if(is_sk) { + _libssh2_store_str(&p, "nistp256", 8); + } + else { + _libssh2_store_str(&p, (const char *)method_buf + 11, 8); + } /* Public key */ _libssh2_store_str(&p, (const char *)octal_value, octal_len); *method = method_buf; - *method_len = 19; *pubkeydata = key; *pubkeydata_len = key_len; clean_exit: - if(ec != NULL) + if(ec) EC_KEY_free(ec); - if(bn_ctx != NULL) { + if(bn_ctx) { BN_CTX_free(bn_ctx); } - if(octal_value != NULL) + if(octal_value) free(octal_value); if(rc == 0) return 0; - if(method_buf != NULL) + if(method_buf) LIBSSH2_FREE(session, method_buf); return -1; @@ -2358,9 +2698,9 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, EC_KEY *ec_key = NULL; BIGNUM *bn_exponent; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing ECDSA keys from private key data"); + "Computing ECDSA keys from private key data")); if(_libssh2_get_string(decrypted, &curve, &curvelen) || curvelen == 0) { @@ -2381,35 +2721,40 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, return -1; } - if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf, - pointlen, curve_type)) != 0) { + rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, + point_buf, pointlen, + curve_type); + if(rc) { + rc = -1; _libssh2_error(session, LIBSSH2_ERROR_PROTO, "ECDSA could not create key"); goto fail; } bn_exponent = BN_new(); - if(bn_exponent == NULL) { + if(!bn_exponent) { rc = -1; + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for private key data"); goto fail; } - BN_bin2bn(exponent, exponentlen, bn_exponent); + BN_bin2bn(exponent, (int) exponentlen, bn_exponent); rc = (EC_KEY_set_private_key(ec_key, bn_exponent) != 1); - if(rc == 0 && ec_key != NULL && pubkeydata != NULL && method != NULL) { + if(rc == 0 && ec_key && pubkeydata && method) { EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(pk, ec_key); rc = gen_publickey_from_ec_evp(session, method, method_len, pubkeydata, pubkeydata_len, - pk); + 0, pk); if(pk) EVP_PKEY_free(pk); } - if(ec_ctx != NULL) + if(ec_ctx) *ec_ctx = ec_key; else EC_KEY_free(ec_key); @@ -2417,17 +2762,152 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, return rc; fail: + if(ec_key) + EC_KEY_free(ec_key); + + return rc; +} + +static int +gen_publickey_from_sk_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, + struct string_buf *decrypted, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + uint8_t *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + libssh2_ecdsa_ctx **ec_ctx) +{ + int rc = 0; + size_t curvelen, pointlen, key_len, app_len; + unsigned char *curve, *point_buf, *p, *key, *app; + EC_KEY *ec_key = NULL; + + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Extracting ECDSA-SK public key")); + + if(_libssh2_get_string(decrypted, &curve, &curvelen) || + curvelen == 0) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "ECDSA no curve"); + return -1; + } + + if(_libssh2_get_string(decrypted, &point_buf, &pointlen)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "ECDSA no point"); + return -1; + } + + rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, + point_buf, pointlen, + LIBSSH2_EC_CURVE_NISTP256); + if(rc) { + rc = -1; + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "ECDSA could not create key"); + goto fail; + } + + if(_libssh2_get_string(decrypted, &app, &app_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK application."); + goto fail; + } + + if(flags && _libssh2_get_byte(decrypted, flags)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK flags."); + goto fail; + } + + if(key_handle && handle_len) { + unsigned char *handle = NULL; + if(_libssh2_get_string(decrypted, &handle, handle_len)) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "No SK key_handle."); + goto fail; + } + + if(*handle_len > 0) { + *key_handle = LIBSSH2_ALLOC(session, *handle_len); + + if(*key_handle) { + memcpy((void *)*key_handle, handle, *handle_len); + } + } + } + + if(rc == 0 && ec_key && pubkeydata && method) { + EVP_PKEY *pk = EVP_PKEY_new(); + EVP_PKEY_set1_EC_KEY(pk, ec_key); + + rc = gen_publickey_from_ec_evp(session, method, method_len, + pubkeydata, pubkeydata_len, + 1, pk); + + if(pk) + EVP_PKEY_free(pk); + } + + if(rc == 0 && pubkeydata) { + key_len = *pubkeydata_len + app_len + 4; + key = LIBSSH2_ALLOC(session, key_len); + + if(!key) { + rc = -1; + goto fail; + } + + p = key + *pubkeydata_len; + + memcpy(key, *pubkeydata, *pubkeydata_len); + _libssh2_store_str(&p, (const char *)app, app_len); - if(ec_key != NULL) + if(application && app_len > 0) { + *application = (const char *)LIBSSH2_ALLOC(session, app_len + 1); + _libssh2_explicit_zero((void *)*application, app_len + 1); + memcpy((void *)*application, app, app_len); + } + + LIBSSH2_FREE(session, *pubkeydata); + *pubkeydata_len = key_len; + + if(pubkeydata) + *pubkeydata = key; + else if(key) + LIBSSH2_FREE(session, key); + } + + if(ec_ctx) + *ec_ctx = ec_key; + else EC_KEY_free(ec_key); - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); + return rc; + +fail: + if(ec_key) + EC_KEY_free(ec_key); + if(application && *application) { + LIBSSH2_FREE(session, (void *)application); + *application = NULL; + } + if(key_handle && *key_handle) { + LIBSSH2_FREE(session, (void *)key_handle); + *key_handle = NULL; + } + + return rc; } + static int _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, LIBSSH2_SESSION * session, @@ -2440,9 +2920,9 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, libssh2_curve_type type; struct string_buf *decrypted = NULL; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); + "Session is required"); return -1; } @@ -2464,7 +2944,7 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -2487,6 +2967,72 @@ _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx ** ec_ctx, return rc; } +static int +_libssh2_ecdsa_new_openssh_private_sk(libssh2_ecdsa_ctx ** ec_ctx, + uint8_t *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase) +{ + FILE *fp; + int rc; + unsigned char *buf = NULL; + struct string_buf *decrypted = NULL; + + if(!session) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Session is required"); + return -1; + } + + _libssh2_init_if_needed(); + + fp = fopen(filename, "r"); + if(!fp) { + _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to open OpenSSH ECDSA private key file"); + return -1; + } + + rc = _libssh2_openssh_pem_parse(session, passphrase, fp, &decrypted); + fclose(fp); + if(rc) { + return rc; + } + + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); + + if(rc || !buf) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted key data not found"); + return -1; + } + + if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) { + rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, + decrypted, + NULL, 0, + NULL, 0, + flags, + application, + key_handle, + handle_len, + ec_ctx); + } + else { + rc = -1; + } + + if(decrypted) + _libssh2_string_buf_free(session, decrypted); + + return rc; +} + int _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, LIBSSH2_SESSION * session, @@ -2495,7 +3041,6 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, int rc; pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; - (void) session; _libssh2_init_if_needed(); @@ -2510,6 +3055,40 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, return rc; } +int +_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase) +{ + int rc; + + pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; + + _libssh2_init_if_needed(); + + rc = read_private_key_from_file((void **) ec_ctx, read_ec, + filename, passphrase); + + if(rc) { + return _libssh2_ecdsa_new_openssh_private_sk(ec_ctx, + flags, + application, + key_handle, + handle_len, + session, + filename, + passphrase); + } + + return rc; +} + + /* * _libssh2_ecdsa_create_key * @@ -2555,16 +3134,16 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, /* convert to octal */ if(EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, octal_value, octal_len, bn_ctx) != octal_len) { - ret = -1; - goto clean_exit; + ret = -1; + goto clean_exit; } - if(out_private_key != NULL) + if(out_private_key) *out_private_key = private_key; if(out_public_key_octal) { *out_public_key_octal = LIBSSH2_ALLOC(session, octal_len); - if(*out_public_key_octal == NULL) { + if(!*out_public_key_octal) { ret = -1; goto clean_exit; } @@ -2572,7 +3151,7 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, memcpy(*out_public_key_octal, octal_value, octal_len); } - if(out_public_key_octal_len != NULL) + if(out_public_key_octal_len) *out_public_key_octal_len = octal_len; clean_exit: @@ -2605,13 +3184,13 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, if(!bn_ctx) return -1; - if(k == NULL) + if(!k) return -1; private_key_group = EC_KEY_get0_group(private_key); server_public_key_point = EC_POINT_new(private_key_group); - if(server_public_key_point == NULL) + if(!server_public_key_point) return -1; rc = EC_POINT_oct2point(private_key_group, server_public_key_point, @@ -2636,17 +3215,17 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, goto clean_exit; } - BN_bin2bn(secret, secret_len, *k); + BN_bin2bn(secret, (int) secret_len, *k); clean_exit: - if(server_public_key_point != NULL) + if(server_public_key_point) EC_POINT_free(server_public_key_point); - if(bn_ctx != NULL) + if(bn_ctx) BN_CTX_free(bn_ctx); - if(secret != NULL) + if(secret) free(secret); return ret; @@ -2667,8 +3246,8 @@ _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, size_t sig_len = 0; unsigned char *sig = NULL; - if(md_ctx != NULL) { - if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx->private_key) != 1) + if(md_ctx) { + if(EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, ctx) != 1) goto clean_exit; if(EVP_DigestSign(md_ctx, NULL, &sig_len, message, message_len) != 1) goto clean_exit; @@ -2677,7 +3256,7 @@ _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, goto clean_exit; sig = LIBSSH2_CALLOC(session, sig_len); - if(sig == NULL) + if(!sig) goto clean_exit; rc = EVP_DigestSign(md_ctx, sig, &sig_len, message, message_len); @@ -2698,7 +3277,7 @@ clean_exit: if(md_ctx) EVP_MD_CTX_free(md_ctx); - return (rc == 1 ? 0 : -1); + return (rc == 1) ? 0 : -1; } int @@ -2713,11 +3292,11 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k, BN_CTX *bn_ctx = NULL; size_t out_len = 0; - if(k == NULL || *k == NULL) + if(!k || !*k) return -1; bn_ctx = BN_CTX_new(); - if(bn_ctx == NULL) + if(!bn_ctx) return -1; peer_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, @@ -2728,27 +3307,33 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k, private_key, LIBSSH2_ED25519_KEY_LEN); - if(peer_key == NULL || server_key == NULL) { - goto cleanExit; + if(!peer_key || !server_key) { + goto clean_exit; } server_key_ctx = EVP_PKEY_CTX_new(server_key, NULL); - if(server_key_ctx == NULL) { - goto cleanExit; + if(!server_key_ctx) { + goto clean_exit; } rc = EVP_PKEY_derive_init(server_key_ctx); - if(rc <= 0) goto cleanExit; + if(rc <= 0) { + goto clean_exit; + } rc = EVP_PKEY_derive_set_peer(server_key_ctx, peer_key); - if(rc <= 0) goto cleanExit; + if(rc <= 0) { + goto clean_exit; + } rc = EVP_PKEY_derive(server_key_ctx, NULL, &out_len); - if(rc <= 0) goto cleanExit; + if(rc <= 0) { + goto clean_exit; + } if(out_len != LIBSSH2_ED25519_KEY_LEN) { rc = -1; - goto cleanExit; + goto clean_exit; } rc = EVP_PKEY_derive(server_key_ctx, out_shared_key, &out_len); @@ -2760,7 +3345,7 @@ _libssh2_curve25519_gen_k(_libssh2_bn **k, rc = -1; } -cleanExit: +clean_exit: if(server_key_ctx) EVP_PKEY_CTX_free(server_key_ctx); @@ -2768,7 +3353,7 @@ cleanExit: EVP_PKEY_free(peer_key); if(server_key) EVP_PKEY_free(server_key); - if(bn_ctx != NULL) + if(bn_ctx) BN_CTX_free(bn_ctx); return (rc == 1) ? 0 : -1; @@ -2782,16 +3367,16 @@ _libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s, int ret = -1; EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); - if(NULL == md_ctx) + if(!md_ctx) return -1; - ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx->public_key); + ret = EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, ctx); if(ret != 1) goto clean_exit; ret = EVP_DigestVerify(md_ctx, s, s_len, m, m_len); - clean_exit: +clean_exit: EVP_MD_CTX_free(md_ctx); @@ -2814,7 +3399,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, struct string_buf *decrypted = NULL; int rc = 0; - if(session == NULL) { + if(!session) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Session is required"); return -1; @@ -2841,7 +3426,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, /* We have a new key file, now try and parse it using supported types */ rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { + if(rc || !buf) { _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Public key type in decrypted key data not found"); return -1; @@ -2849,6 +3434,12 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, rc = -1; + /* Avoid unused variable warnings when all branches below are disabled */ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + #if LIBSSH2_ED25519 if(strcmp("ssh-ed25519", (const char *)buf) == 0) { rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted, @@ -2895,7 +3486,7 @@ _libssh2_pub_priv_openssh_keyfile(LIBSSH2_SESSION *session, if(decrypted) _libssh2_string_buf_free(session, decrypted); - if(rc != 0) { + if(rc) { _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unsupported OpenSSH key type"); } @@ -2918,13 +3509,13 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, int pktype; int rc; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Computing public key from private key file: %s", - privatekey); + privatekey)); bp = BIO_new_file(privatekey, "r"); - if(bp == NULL) { + if(!bp) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key from private key " @@ -2935,7 +3526,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); BIO_free(bp); - if(pk == NULL) { + if(!pk) { /* Try OpenSSH format */ rc = _libssh2_pub_priv_openssh_keyfile(session, @@ -2943,7 +3534,7 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, method_len, pubkeydata, pubkeydata_len, privatekey, passphrase); - if(rc != 0) { + if(rc) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key " @@ -2962,26 +3553,31 @@ _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, #endif switch(pktype) { - case EVP_PKEY_RSA : +#if LIBSSH2_ED25519 + case EVP_PKEY_ED25519: + st = gen_publickey_from_ed_evp( + session, method, method_len, pubkeydata, pubkeydata_len, pk); + break; +#endif /* LIBSSH2_ED25519 */ +#if LIBSSH2_RSA + case EVP_PKEY_RSA: st = gen_publickey_from_rsa_evp( session, method, method_len, pubkeydata, pubkeydata_len, pk); break; - +#endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA - case EVP_PKEY_DSA : + case EVP_PKEY_DSA: st = gen_publickey_from_dsa_evp( session, method, method_len, pubkeydata, pubkeydata_len, pk); break; -#endif /* LIBSSH_DSA */ - +#endif /* LIBSSH2_DSA */ #if LIBSSH2_ECDSA - case EVP_PKEY_EC : + case EVP_PKEY_EC: st = gen_publickey_from_ec_evp( - session, method, method_len, pubkeydata, pubkeydata_len, pk); + session, method, method_len, pubkeydata, pubkeydata_len, 0, pk); break; -#endif - - default : +#endif /* LIBSSH2_ECDSA */ + default: st = _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key " @@ -3010,20 +3606,16 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, unsigned char *buf = NULL; struct string_buf *decrypted = NULL; - if(key_ctx != NULL) + if(key_ctx) *key_ctx = NULL; - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } + if(!session) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Session is required"); - if(key_type != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7)) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "type is invalid"); - return -1; - } + if(key_type && (strlen(key_type) > 11 || strlen(key_type) < 7)) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "type is invalid"); _libssh2_init_if_needed(); @@ -3031,24 +3623,28 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, privatekeydata, privatekeydata_len, &decrypted); - if(rc) { + if(rc) return rc; - } - /* We have a new key file, now try and parse it using supported types */ - rc = _libssh2_get_string(decrypted, &buf, NULL); + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } + if(rc || !buf) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted " + "key data not found"); + + rc = LIBSSH2_ERROR_FILE; - rc = -1; + /* Avoid unused variable warnings when all branches below are disabled */ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; #if LIBSSH2_ED25519 if(strcmp("ssh-ed25519", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-ed25519", key_type) == 0) { + if(!key_type || strcmp("ssh-ed25519", key_type) == 0) { rc = gen_publickey_from_ed25519_openssh_priv_data(session, decrypted, method, @@ -3057,47 +3653,187 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, pubkeydata_len, (libssh2_ed25519_ctx**)key_ctx); } - } + } + + if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) { + if(!key_type || + strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) { + rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session, + decrypted, + method, + method_len, + pubkeydata, + pubkeydata_len, + NULL, + NULL, + NULL, + NULL, + (libssh2_ed25519_ctx**)key_ctx); + } + } #endif #if LIBSSH2_RSA if(strcmp("ssh-rsa", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-rsa", key_type) == 0) { + if(!key_type || strcmp("ssh-rsa", key_type) == 0) { rc = gen_publickey_from_rsa_openssh_priv_data(session, decrypted, method, method_len, pubkeydata, pubkeydata_len, - (libssh2_rsa_ctx**)key_ctx); + (libssh2_rsa_ctx**)key_ctx); } - } + } #endif #if LIBSSH2_DSA if(strcmp("ssh-dss", (const char *)buf) == 0) { - if(key_type == NULL || strcmp("ssh-dss", key_type) == 0) { + if(!key_type || strcmp("ssh-dss", key_type) == 0) { rc = gen_publickey_from_dsa_openssh_priv_data(session, decrypted, - method, method_len, + method, method_len, pubkeydata, pubkeydata_len, - (libssh2_dsa_ctx**)key_ctx); + (libssh2_dsa_ctx**)key_ctx); } - } + } #endif #if LIBSSH2_ECDSA { libssh2_curve_type type; - if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type) == 0) { - if(key_type == NULL || strcmp("ssh-ecdsa", key_type) == 0) { - rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, - decrypted, + if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) { + rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted, method, method_len, pubkeydata, pubkeydata_len, - (libssh2_ecdsa_ctx**)key_ctx); + NULL, + NULL, NULL, + NULL, + (libssh2_ecdsa_ctx**)key_ctx); + } + else if(_libssh2_ecdsa_curve_type_from_name((const char *)buf, &type) + == 0) { + if(!key_type || strcmp("ssh-ecdsa", key_type) == 0) { + rc = gen_publickey_from_ecdsa_openssh_priv_data(session, type, + decrypted, + method, method_len, + pubkeydata, + pubkeydata_len, + (libssh2_ecdsa_ctx**)key_ctx); } } } #endif + if(rc == LIBSSH2_ERROR_FILE) + rc = _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key from private key file: " + "invalid/unrecognized private key file format"); + + if(decrypted) + _libssh2_string_buf_free(session, decrypted); + + return rc; +} + +static int +_libssh2_sk_pub_openssh_keyfilememory(LIBSSH2_SESSION *session, + void **key_ctx, + const char *key_type, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + unsigned const char *passphrase) +{ + int rc; + unsigned char *buf = NULL; + struct string_buf *decrypted = NULL; + + if(key_ctx) + *key_ctx = NULL; + + if(!session) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Session is required"); + + if(key_type && strlen(key_type) < 7) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "type is invalid"); + + _libssh2_init_if_needed(); + + rc = _libssh2_openssh_pem_parse_memory(session, passphrase, + privatekeydata, + privatekeydata_len, &decrypted); + + if(rc) + return rc; + + /* We have a new key file, now try and parse it using supported types */ + rc = _libssh2_get_string(decrypted, &buf, NULL); + + if(rc || !buf) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted " + "key data not found"); + + rc = LIBSSH2_ERROR_FILE; + + /* Avoid unused variable warnings when all branches below are disabled */ + (void)method; + (void)method_len; + (void)pubkeydata; + (void)pubkeydata_len; + (void)algorithm; + (void)flags; + (void)application; + (void)key_handle; + (void)handle_len; + +#if LIBSSH2_ED25519 + if(strcmp("sk-ssh-ed25519@openssh.com", (const char *)buf) == 0) { + *algorithm = LIBSSH2_HOSTKEY_TYPE_ED25519; + if(!key_type || + strcmp("sk-ssh-ed25519@openssh.com", key_type) == 0) { + rc = gen_publickey_from_sk_ed25519_openssh_priv_data(session, + decrypted, + method, + method_len, + pubkeydata, + pubkeydata_len, + flags, + application, + key_handle, + handle_len, + (libssh2_ed25519_ctx**)key_ctx); + } + } +#endif +#if LIBSSH2_ECDSA + if(strcmp("sk-ecdsa-sha2-nistp256@openssh.com", (const char *)buf) == 0) { + *algorithm = LIBSSH2_HOSTKEY_TYPE_ECDSA_256; + rc = gen_publickey_from_sk_ecdsa_openssh_priv_data(session, decrypted, + method, method_len, + pubkeydata, + pubkeydata_len, + flags, + application, + key_handle, + handle_len, + (libssh2_ecdsa_ctx**)key_ctx); + } +#endif + + if(rc == LIBSSH2_ERROR_FILE) + rc = _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key from private key file: " + "invalid/unrecognized private key file format"); + if(decrypted) _libssh2_string_buf_free(session, decrypted); @@ -3117,6 +3853,10 @@ read_openssh_private_key_from_memory(void **key_ctx, LIBSSH2_SESSION *session, passphrase); } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define HAVE_SSLERROR_BAD_DECRYPT +#endif + int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, unsigned char **method, @@ -3131,21 +3871,31 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, BIO* bp; EVP_PKEY* pk; int pktype; +#ifdef HAVE_SSLERROR_BAD_DECRYPT + unsigned long sslError; +#endif - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, - "Computing public key from private key."); - - bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len); - if(!bp) { - return -1; - } + "Computing public key from private key.")); +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL + bp = BIO_new_mem_buf(privatekeydata, (int)privatekeydata_len); +#else + bp = BIO_new_mem_buf((char *)privatekeydata, (int)privatekeydata_len); +#endif + if(!bp) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory when" + "computing public key"); BIO_reset(bp); pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); +#ifdef HAVE_SSLERROR_BAD_DECRYPT + sslError = ERR_get_error(); +#endif BIO_free(bp); - if(pk == NULL) { + if(!pk) { /* Try OpenSSH format */ st = _libssh2_pub_priv_openssh_keyfilememory(session, NULL, NULL, method, @@ -3154,17 +3904,23 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, pubkeydata_len, privatekeydata, privatekeydata_len, - (unsigned const char *)passphrase); - if(st != 0) { - return _libssh2_error(session, - LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key file: " - "Wrong passphrase or invalid/unrecognized " - "private key file format"); - } - - return 0; + (unsigned const char *)passphrase); + if(st == 0) + return 0; + +#ifdef HAVE_SSLERROR_BAD_DECRYPT + if((ERR_GET_LIB(sslError) == ERR_LIB_PEM && + ERR_GET_REASON(sslError) == PEM_R_BAD_DECRYPT) || + (ERR_GET_LIB(sslError) == ERR_LIB_PROV && + ERR_GET_REASON(sslError) == EVP_R_BAD_DECRYPT)) + return _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED, + "Wrong passphrase for private key"); +#endif + return _libssh2_error(session, + LIBSSH2_ERROR_FILE, + "Unable to extract public key " + "from private key file: " + "Unsupported private key file format"); } #ifdef HAVE_OPAQUE_STRUCTS @@ -3174,23 +3930,32 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, #endif switch(pktype) { - case EVP_PKEY_RSA : +#if LIBSSH2_ED25519 + case EVP_PKEY_ED25519: + st = gen_publickey_from_ed_evp( + session, method, method_len, pubkeydata, pubkeydata_len, pk); + break; +#endif /* LIBSSH2_ED25519 */ +#if LIBSSH2_RSA + case EVP_PKEY_RSA: st = gen_publickey_from_rsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); break; +#endif /* LIBSSH2_RSA */ #if LIBSSH2_DSA - case EVP_PKEY_DSA : + case EVP_PKEY_DSA: st = gen_publickey_from_dsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); break; -#endif /* LIBSSH_DSA */ +#endif /* LIBSSH2_DSA */ #if LIBSSH2_ECDSA - case EVP_PKEY_EC : + case EVP_PKEY_EC: st = gen_publickey_from_ec_evp(session, method, method_len, - pubkeydata, pubkeydata_len, pk); + pubkeydata, pubkeydata_len, + 0, pk); break; #endif /* LIBSSH2_ECDSA */ - default : + default: st = _libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to extract public key " @@ -3203,6 +3968,62 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, return st; } +int +_libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + int *algorithm, + unsigned char *flags, + const char **application, + const unsigned char **key_handle, + size_t *handle_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase) +{ + int st = -1; + BIO* bp; + EVP_PKEY* pk; + + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing public key from private key.")); + +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL + bp = BIO_new_mem_buf(privatekeydata, (int)privatekeydata_len); +#else + bp = BIO_new_mem_buf((char *)privatekeydata, (int)privatekeydata_len); +#endif + if(!bp) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory when" + "computing public key"); + BIO_reset(bp); + pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void *)passphrase); + BIO_free(bp); + + if(!pk) { + /* Try OpenSSH format */ + st = _libssh2_sk_pub_openssh_keyfilememory(session, NULL, NULL, + method, + method_len, + pubkeydata, + pubkeydata_len, + algorithm, + flags, + application, + key_handle, + handle_len, + privatekeydata, + privatekeydata_len, + (unsigned const char *)passphrase); + } + + return st; +} + void _libssh2_dh_init(_libssh2_dh_ctx *dhctx) { @@ -3237,4 +4058,27 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) *dhctx = NULL; } -#endif /* LIBSSH2_OPENSSL */ +/* _libssh2_supported_key_sign_algorithms + * + * Return supported key hash algo upgrades, see crypto.h + * + */ + +const char * +_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session, + unsigned char *key_method, + size_t key_method_len) +{ + (void)session; + +#if LIBSSH2_RSA_SHA2 + if(key_method_len == 7 && + memcmp(key_method, "ssh-rsa", key_method_len) == 0) { + return "rsa-sha2-512,rsa-sha2-256,ssh-rsa"; + } +#endif + + return NULL; +} + +#endif /* LIBSSH2_CRYPTO_C */ diff --git a/libs/libssh2/src/openssl.h b/libs/libssh2/src/openssl.h index 15518e0a66..ad256a18c3 100644 --- a/libs/libssh2/src/openssl.h +++ b/libs/libssh2/src/openssl.h @@ -1,7 +1,8 @@ -/* Copyright (C) 2009, 2010 Simon Josefsson - * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * - * Author: Simon Josefsson +#ifndef __LIBSSH2_OPENSSL_H +#define __LIBSSH2_OPENSSL_H +/* Copyright (C) Simon Josefsson + * Copyright (C) The Written Word, Inc. + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -35,8 +36,48 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ +#define LIBSSH2_CRYPTO_ENGINE libssh2_openssl + +/* disable deprecated warnings in OpenSSL 3 */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#ifdef LIBSSH2_WOLFSSL + +#include <wolfssl/options.h> +#include <openssl/ecdh.h> + +#if defined(NO_DSA) || defined(HAVE_FIPS) +#define OPENSSL_NO_DSA +#endif + +#if defined(NO_MD5) || defined(HAVE_FIPS) +#define OPENSSL_NO_MD5 +#endif + +#if !defined(WOLFSSL_RIPEMD) || defined(HAVE_FIPS) +#define OPENSSL_NO_RIPEMD +#endif + +#if defined(NO_RC4) || defined(HAVE_FIPS) +#define OPENSSL_NO_RC4 +#endif + +#ifdef NO_DES3 +#define OPENSSL_NO_DES +#endif + +/* wolfSSL doesn't support Blowfish or CAST. */ +#define OPENSSL_NO_BF +#define OPENSSL_NO_CAST +/* wolfSSL has no engine framework. */ +#define OPENSSL_NO_ENGINE + +#endif /* LIBSSH2_WOLFSSL */ + #include <openssl/opensslconf.h> #include <openssl/sha.h> #include <openssl/rsa.h> @@ -49,21 +90,29 @@ #ifndef OPENSSL_NO_MD5 #include <openssl/md5.h> #endif +#include <openssl/err.h> #include <openssl/evp.h> #include <openssl/hmac.h> #include <openssl/bn.h> #include <openssl/pem.h> #include <openssl/rand.h> -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(LIBRESSL_VERSION_NUMBER)) || defined(LIBSSH2_WOLFSSL) || \ + LIBRESSL_VERSION_NUMBER >= 0x3050000fL +/* For wolfSSL, whether the structs are truly opaque or not, it's best to not + * rely on their internal data members being exposed publicly. */ # define HAVE_OPAQUE_STRUCTS 1 #endif #ifdef OPENSSL_NO_RSA # define LIBSSH2_RSA 0 +# define LIBSSH2_RSA_SHA1 0 +# define LIBSSH2_RSA_SHA2 0 #else # define LIBSSH2_RSA 1 +# define LIBSSH2_RSA_SHA1 1 +# define LIBSSH2_RSA_SHA2 1 #endif #ifdef OPENSSL_NO_DSA @@ -72,14 +121,16 @@ # define LIBSSH2_DSA 1 #endif -#ifdef OPENSSL_NO_ECDSA +#if defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_EC) # define LIBSSH2_ECDSA 0 #else # define LIBSSH2_ECDSA 1 #endif -#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ -!defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER)) || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER >= 0x3070000fL) # define LIBSSH2_ED25519 1 #else # define LIBSSH2_ED25519 0 @@ -92,7 +143,7 @@ # define LIBSSH2_MD5 1 #endif -#ifdef OPENSSL_NO_RIPEMD +#if defined(OPENSSL_NO_RIPEMD) || defined(OPENSSL_NO_RMD160) # define LIBSSH2_HMAC_RIPEMD 0 #else # define LIBSSH2_HMAC_RIPEMD 1 @@ -101,12 +152,21 @@ #define LIBSSH2_HMAC_SHA256 1 #define LIBSSH2_HMAC_SHA512 1 -#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) +#if (OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)) || \ + (defined(LIBSSH2_WOLFSSL) && defined(WOLFSSL_AES_COUNTER)) # define LIBSSH2_AES_CTR 1 -# define LIBSSH2_AES 1 +# define LIBSSH2_AES_CBC 1 #else # define LIBSSH2_AES_CTR 0 -# define LIBSSH2_AES 0 +# define LIBSSH2_AES_CBC 0 +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x01010100fL && !defined(OPENSSL_NO_AES)) || \ + (defined(LIBSSH2_WOLFSSL) && \ + defined(HAVE_AESGCM) && defined(WOLFSSL_AESGCM_STREAM)) +# define LIBSSH2_AES_GCM 1 +#else +# define LIBSSH2_AES_GCM 0 #endif #ifdef OPENSSL_NO_BF @@ -135,7 +195,8 @@ #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) -#define _libssh2_random(buf, len) RAND_bytes ((buf), (len)) +#define _libssh2_random(buf, len) \ + _libssh2_openssl_random((buf), (len)) #define libssh2_prepare_iovec(vec, len) /* Empty. */ @@ -158,7 +219,7 @@ int _libssh2_sha1_init(libssh2_sha1_ctx *ctx); #define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) #define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) #endif -int _libssh2_sha1(const unsigned char *message, unsigned long len, +int _libssh2_sha1(const unsigned char *message, size_t len, unsigned char *out); #define libssh2_sha1(x,y,z) _libssh2_sha1(x,y,z) @@ -182,8 +243,8 @@ int _libssh2_sha256_init(libssh2_sha256_ctx *ctx); EVP_DigestUpdate(&(ctx), data, len) #define libssh2_sha256_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) #endif -int _libssh2_sha256(const unsigned char *message, unsigned long len, - unsigned char *out); +int _libssh2_sha256(const unsigned char *message, size_t len, + unsigned char *out); #define libssh2_sha256(x,y,z) _libssh2_sha256(x,y,z) #ifdef HAVE_OPAQUE_STRUCTS @@ -206,7 +267,7 @@ int _libssh2_sha384_init(libssh2_sha384_ctx *ctx); EVP_DigestUpdate(&(ctx), data, len) #define libssh2_sha384_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) #endif -int _libssh2_sha384(const unsigned char *message, unsigned long len, +int _libssh2_sha384(const unsigned char *message, size_t len, unsigned char *out); #define libssh2_sha384(x,y,z) _libssh2_sha384(x,y,z) @@ -230,7 +291,7 @@ int _libssh2_sha512_init(libssh2_sha512_ctx *ctx); EVP_DigestUpdate(&(ctx), data, len) #define libssh2_sha512_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) #endif -int _libssh2_sha512(const unsigned char *message, unsigned long len, +int _libssh2_sha512(const unsigned char *message, size_t len, unsigned char *out); #define libssh2_sha512(x,y,z) _libssh2_sha512(x,y,z) @@ -258,37 +319,43 @@ int _libssh2_md5_init(libssh2_md5_ctx *ctx); #define libssh2_hmac_ctx HMAC_CTX * #define libssh2_hmac_ctx_init(ctx) ctx = HMAC_CTX_new() #define libssh2_hmac_sha1_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha1(), NULL) + HMAC_Init_ex(*(ctx), key, (int)keylen, EVP_sha1(), NULL) #define libssh2_hmac_md5_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_md5(), NULL) + HMAC_Init_ex(*(ctx), key, (int)keylen, EVP_md5(), NULL) #define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_ripemd160(), NULL) + HMAC_Init_ex(*(ctx), key, (int)keylen, EVP_ripemd160(), NULL) #define libssh2_hmac_sha256_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha256(), NULL) + HMAC_Init_ex(*(ctx), key, (int)keylen, EVP_sha256(), NULL) #define libssh2_hmac_sha512_init(ctx, key, keylen) \ - HMAC_Init_ex(*(ctx), key, keylen, EVP_sha512(), NULL) + HMAC_Init_ex(*(ctx), key, (int)keylen, EVP_sha512(), NULL) +#ifdef LIBSSH2_WOLFSSL +/* FIXME: upstream bug as of v5.6.0: datalen is int instead of size_t */ +#define libssh2_hmac_update(ctx, data, datalen) \ + HMAC_Update(ctx, data, (int)datalen) +#else #define libssh2_hmac_update(ctx, data, datalen) \ - HMAC_Update(ctx, data, datalen) + HMAC_Update(ctx, data, datalen) +#endif /* LIBSSH2_WOLFSSL */ #define libssh2_hmac_final(ctx, data) HMAC_Final(ctx, data, NULL) #define libssh2_hmac_cleanup(ctx) HMAC_CTX_free(*(ctx)) #else #define libssh2_hmac_ctx HMAC_CTX #define libssh2_hmac_ctx_init(ctx) \ - HMAC_CTX_init(&ctx) + HMAC_CTX_init(&ctx) #define libssh2_hmac_sha1_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha1(), NULL) + HMAC_Init_ex(ctx, key, (int)keylen, EVP_sha1(), NULL) #define libssh2_hmac_md5_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL) + HMAC_Init_ex(ctx, key, (int)keylen, EVP_md5(), NULL) #define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_ripemd160(), NULL) + HMAC_Init_ex(ctx, key, (int)keylen, EVP_ripemd160(), NULL) #define libssh2_hmac_sha256_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL) + HMAC_Init_ex(ctx, key, (int)keylen, EVP_sha256(), NULL) #define libssh2_hmac_sha512_init(ctx, key, keylen) \ - HMAC_Init_ex(ctx, key, keylen, EVP_sha512(), NULL) + HMAC_Init_ex(ctx, key, (int)keylen, EVP_sha512(), NULL) #define libssh2_hmac_update(ctx, data, datalen) \ - HMAC_Update(&(ctx), data, datalen) + HMAC_Update(&(ctx), data, datalen) #define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL) #define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx) #endif @@ -298,15 +365,19 @@ extern void _libssh2_openssl_crypto_exit(void); #define libssh2_crypto_init() _libssh2_openssl_crypto_init() #define libssh2_crypto_exit() _libssh2_openssl_crypto_exit() +#if LIBSSH2_RSA #define libssh2_rsa_ctx RSA #define _libssh2_rsa_free(rsactx) RSA_free(rsactx) +#endif +#if LIBSSH2_DSA #define libssh2_dsa_ctx DSA #define _libssh2_dsa_free(dsactx) DSA_free(dsactx) +#endif -#ifdef LIBSSH2_ECDSA +#if LIBSSH2_ECDSA #define libssh2_ecdsa_ctx EC_KEY #define _libssh2_ecdsa_free(ecdsactx) EC_KEY_free(ecdsactx) #define _libssh2_ec_key EC_KEY @@ -321,27 +392,10 @@ libssh2_curve_type; #define _libssh2_ec_key void #endif /* LIBSSH2_ECDSA */ -#ifdef LIBSSH2_ED25519 - -typedef struct { - EVP_PKEY *public_key; - EVP_PKEY *private_key; -} libssh2_curve25519_keys; - -#define libssh2_ed25519_ctx libssh2_curve25519_keys -#define libssh2_x25519_ctx libssh2_curve25519_keys - -#define _libssh2_ed25519_new_ctx() calloc(1, sizeof(libssh2_ed25519_ctx)) -#define _libssh2_ed25519_free(ctx) do { \ - if(ctx) { \ - if(ctx->public_key) EVP_PKEY_free(ctx->public_key); \ - if(ctx->private_key) EVP_PKEY_free(ctx->private_key); \ - free(ctx); \ - } \ -} while(0) - -#define _libssh2_x25519_free(ctx) _libssh2_ed25519_free(ctx) +#if LIBSSH2_ED25519 +#define libssh2_ed25519_ctx EVP_PKEY +#define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx) #endif /* ED25519 */ #define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void) @@ -351,18 +405,15 @@ typedef struct { #define _libssh2_cipher_ctx EVP_CIPHER_CTX #endif +#define _libssh2_cipher_aes256gcm EVP_aes_256_gcm +#define _libssh2_cipher_aes128gcm EVP_aes_128_gcm + #define _libssh2_cipher_aes256 EVP_aes_256_cbc #define _libssh2_cipher_aes192 EVP_aes_192_cbc #define _libssh2_cipher_aes128 EVP_aes_128_cbc -#ifdef HAVE_EVP_AES_128_CTR #define _libssh2_cipher_aes128ctr EVP_aes_128_ctr #define _libssh2_cipher_aes192ctr EVP_aes_192_ctr #define _libssh2_cipher_aes256ctr EVP_aes_256_ctr -#else -#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr -#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr -#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr -#endif #define _libssh2_cipher_blowfish EVP_bf_cbc #define _libssh2_cipher_arcfour EVP_rc4 #define _libssh2_cipher_cast5 EVP_cast5_cbc @@ -381,18 +432,26 @@ typedef struct { #define _libssh2_bn_init() BN_new() #define _libssh2_bn_init_from_bin() _libssh2_bn_init() #define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val) -#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn) +#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, (int)len, bn) #define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val) #define _libssh2_bn_bytes(bn) BN_num_bytes(bn) #define _libssh2_bn_bits(bn) BN_num_bits(bn) #define _libssh2_bn_free(bn) BN_clear_free(bn) +/* Default generate and safe prime sizes for + diffie-hellman-group-exchange-sha1 */ +#define LIBSSH2_DH_GEX_MINGROUP 2048 +#define LIBSSH2_DH_GEX_OPTGROUP 4096 +#define LIBSSH2_DH_GEX_MAXGROUP 8192 + +#define LIBSSH2_DH_MAX_MODULUS_BITS 16384 + #define _libssh2_dh_ctx BIGNUM * #define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) #define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) + _libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) #define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p, bnctx) + _libssh2_dh_secret(dhctx, secret, f, p, bnctx) #define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, @@ -404,6 +463,10 @@ extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, _libssh2_bn_ctx *bnctx); extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); +extern int _libssh2_openssl_random(void *buf, size_t len); + const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void); const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void); const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void); + +#endif /* __LIBSSH2_OPENSSL_H */ diff --git a/libs/libssh2/src/packet.c b/libs/libssh2/src/packet.c index 38ab62944a..e3ccf814d4 100644 --- a/libs/libssh2/src/packet.c +++ b/libs/libssh2/src/packet.c @@ -1,7 +1,7 @@ -/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2005,2006 Mikhail Gusarov - * Copyright (c) 2009-2014 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Mikhail Gusarov + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,31 +36,23 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include <errno.h> -#include <fcntl.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif - /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H #include <sys/uio.h> #endif -#include <sys/types.h> - #include "transport.h" #include "channel.h" #include "packet.h" @@ -72,48 +64,71 @@ */ static inline int packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, + size_t datalen, packet_queue_listener_state_t *listen_state) { /* * Look for a matching listener */ /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1); + size_t packet_len = 17 + (sizeof(FwdNotReq) - 1); unsigned char *p; LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners); char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; int rc; - (void) datalen; - if(listen_state->state == libssh2_NB_state_idle) { - unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5; - listen_state->sender_channel = _libssh2_ntohu32(s); - s += 4; + size_t offset = (sizeof("forwarded-tcpip") - 1) + 5; + size_t temp_len = 0; + struct string_buf buf; + buf.data = data; + buf.dataptr = buf.data; + buf.len = datalen; + + if(datalen < offset) { + return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Unexpected packet size"); + } - listen_state->initial_window_size = _libssh2_ntohu32(s); - s += 4; - listen_state->packet_size = _libssh2_ntohu32(s); - s += 4; + buf.dataptr += offset; - listen_state->host_len = _libssh2_ntohu32(s); - s += 4; - listen_state->host = s; - s += listen_state->host_len; - listen_state->port = _libssh2_ntohu32(s); - s += 4; + if(_libssh2_get_u32(&buf, &(listen_state->sender_channel))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting channel"); + } + if(_libssh2_get_u32(&buf, &(listen_state->initial_window_size))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting window size"); + } + if(_libssh2_get_u32(&buf, &(listen_state->packet_size))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting packet"); + } + if(_libssh2_get_string(&buf, &(listen_state->host), &temp_len)) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting host"); + } + listen_state->host_len = (uint32_t)temp_len; - listen_state->shost_len = _libssh2_ntohu32(s); - s += 4; - listen_state->shost = s; - s += listen_state->shost_len; - listen_state->sport = _libssh2_ntohu32(s); + if(_libssh2_get_u32(&buf, &(listen_state->port))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting port"); + } + if(_libssh2_get_string(&buf, &(listen_state->shost), &temp_len)) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting shost"); + } + listen_state->shost_len = (uint32_t)temp_len; + + if(_libssh2_get_u32(&buf, &(listen_state->sport))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting sport"); + } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Remote received connection from %s:%ld to %s:%ld", listen_state->shost, listen_state->sport, - listen_state->host, listen_state->port); + listen_state->host, listen_state->port)); listen_state->state = libssh2_NB_state_allocated; } @@ -133,8 +148,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, (listn->queue_maxsize <= listn->queue_size)) { /* Queue is full */ failure_code = SSH_OPEN_RESOURCE_SHORTAGE; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Listener queue full, ignoring"); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Listener queue full, ignoring")); listen_state->state = libssh2_NB_state_sent; break; } @@ -183,14 +198,14 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, listen_state->initial_window_size; channel->local.packet_size = listen_state->packet_size; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Connection queued: channel %lu/%lu " "win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, - channel->remote.packet_size); + channel->remote.packet_size)); p = listen_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; @@ -262,36 +277,71 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, */ static inline int packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, - unsigned long datalen, + size_t datalen, packet_x11_open_state_t *x11open_state) { int failure_code = SSH_OPEN_CONNECT_FAILED; /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); + size_t packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); unsigned char *p; LIBSSH2_CHANNEL *channel = x11open_state->channel; int rc; - (void) datalen; - if(x11open_state->state == libssh2_NB_state_idle) { - unsigned char *s = data + (sizeof("x11") - 1) + 5; - x11open_state->sender_channel = _libssh2_ntohu32(s); - s += 4; - x11open_state->initial_window_size = _libssh2_ntohu32(s); - s += 4; - x11open_state->packet_size = _libssh2_ntohu32(s); - s += 4; - x11open_state->shost_len = _libssh2_ntohu32(s); - s += 4; - x11open_state->shost = s; - s += x11open_state->shost_len; - x11open_state->sport = _libssh2_ntohu32(s); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + size_t offset = (sizeof("x11") - 1) + 5; + size_t temp_len = 0; + struct string_buf buf; + buf.data = data; + buf.dataptr = buf.data; + buf.len = datalen; + + if(datalen < offset) { + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "unexpected data length"); + failure_code = SSH_OPEN_CONNECT_FAILED; + goto x11_exit; + } + + buf.dataptr += offset; + + if(_libssh2_get_u32(&buf, &(x11open_state->sender_channel))) { + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "unexpected sender channel size"); + failure_code = SSH_OPEN_CONNECT_FAILED; + goto x11_exit; + } + if(_libssh2_get_u32(&buf, &(x11open_state->initial_window_size))) { + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "unexpected window size"); + failure_code = SSH_OPEN_CONNECT_FAILED; + goto x11_exit; + } + if(_libssh2_get_u32(&buf, &(x11open_state->packet_size))) { + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "unexpected window size"); + failure_code = SSH_OPEN_CONNECT_FAILED; + goto x11_exit; + } + if(_libssh2_get_string(&buf, &(x11open_state->shost), &temp_len)) { + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "unexpected host size"); + failure_code = SSH_OPEN_CONNECT_FAILED; + goto x11_exit; + } + x11open_state->shost_len = (uint32_t)temp_len; + + if(_libssh2_get_u32(&buf, &(x11open_state->sport))) { + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "unexpected port size"); + failure_code = SSH_OPEN_CONNECT_FAILED; + goto x11_exit; + } + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "X11 Connection Received from %s:%ld on channel %lu", x11open_state->shost, x11open_state->sport, - x11open_state->sender_channel); + x11open_state->sender_channel)); x11open_state->state = libssh2_NB_state_allocated; } @@ -333,14 +383,14 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, channel->local.window_size = x11open_state->initial_window_size; channel->local.packet_size = x11open_state->packet_size; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "X11 Connection established: channel %lu/%lu " "win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, - channel->remote.packet_size); + channel->remote.packet_size)); p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; _libssh2_store_u32(&p, channel->remote.id); @@ -381,7 +431,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, else failure_code = SSH_OPEN_RESOURCE_SHORTAGE; /* fall-trough */ - x11_exit: +x11_exit: p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, x11open_state->sender_channel); @@ -403,6 +453,154 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, } /* + * packet_authagent_open + * + * Open a connection to authentication agent + */ +static inline int +packet_authagent_open(LIBSSH2_SESSION * session, + unsigned char *data, size_t datalen, + packet_authagent_state_t *authagent_state) +{ + int failure_code = SSH_OPEN_CONNECT_FAILED; + /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ + size_t packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); + unsigned char *p; + LIBSSH2_CHANNEL *channel = authagent_state->channel; + int rc; + + (void)datalen; + + if(authagent_state->state == libssh2_NB_state_idle) { + unsigned char *s = data + (sizeof("auth-agent@openssh.org") - 1) + 5; + authagent_state->sender_channel = _libssh2_ntohu32(s); + s += 4; + authagent_state->initial_window_size = _libssh2_ntohu32(s); + s += 4; + authagent_state->packet_size = _libssh2_ntohu32(s); + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Auth Agent Connection Received on channel %lu", + authagent_state->sender_channel)); + + authagent_state->state = libssh2_NB_state_allocated; + } + + if(session->authagent) { + if(authagent_state->state == libssh2_NB_state_allocated) { + channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); + authagent_state->channel = channel; + + if(!channel) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "allocate a channel for new connection"); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + goto authagent_exit; + } + memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); + + channel->session = session; + channel->channel_type_len = sizeof("auth agent") - 1; + channel->channel_type = LIBSSH2_ALLOC(session, + channel->channel_type_len + + 1); + if(!channel->channel_type) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "allocate a channel for new connection"); + LIBSSH2_FREE(session, channel); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + goto authagent_exit; + } + memcpy(channel->channel_type, "auth agent", + channel->channel_type_len + 1); + + channel->remote.id = authagent_state->sender_channel; + channel->remote.window_size_initial = + LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT; + + channel->local.id = _libssh2_channel_nextid(session); + channel->local.window_size_initial = + authagent_state->initial_window_size; + channel->local.window_size = authagent_state->initial_window_size; + channel->local.packet_size = authagent_state->packet_size; + + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Auth Agent Connection established: channel " + "%lu/%lu win %lu/%lu packet %lu/%lu", + channel->local.id, channel->remote.id, + channel->local.window_size, + channel->remote.window_size, + channel->local.packet_size, + channel->remote.packet_size)); + + p = authagent_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; + _libssh2_store_u32(&p, channel->remote.id); + _libssh2_store_u32(&p, channel->local.id); + _libssh2_store_u32(&p, channel->remote.window_size_initial); + _libssh2_store_u32(&p, channel->remote.packet_size); + + authagent_state->state = libssh2_NB_state_created; + } + + if(authagent_state->state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, authagent_state->packet, 17, + NULL, 0); + if(rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if(rc) { + authagent_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send channel open " + "confirmation"); + } + + /* Link the channel into the session */ + _libssh2_list_add(&session->channels, &channel->node); + + /* mess with stuff so we don't keep reading the same packet + over and over */ + session->packet.total_num = 0; + session->fullpacket_state = libssh2_NB_state_idle; + + /* Pass control to the callback, they may turn right around and + and free the channel, or actually use it */ + + LIBSSH2_AUTHAGENT(channel); + + authagent_state->state = libssh2_NB_state_idle; + return 0; + } + } + else + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + + /* fall-through */ +authagent_exit: + p = authagent_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; + _libssh2_store_u32(&p, authagent_state->sender_channel); + _libssh2_store_u32(&p, failure_code); + _libssh2_store_str(&p, AuthAgentUnavail, sizeof(AuthAgentUnavail) - 1); + _libssh2_htonu32(p, 0); + + rc = _libssh2_transport_send(session, authagent_state->packet, packet_len, + NULL, 0); + if(rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if(rc) { + authagent_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, "Unable to send open failure"); + } + authagent_state->state = libssh2_NB_state_idle; + return 0; +} + +/* * _libssh2_packet_add * * Create a new packet and attach it to the brigade. Called from the transport @@ -419,8 +617,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, size_t datalen, int macstate) { int rc = 0; - char *message = NULL; - char *language = NULL; + unsigned char *message = NULL; + unsigned char *language = NULL; size_t message_len = 0; size_t language_len = 0; LIBSSH2_CHANNEL *channelp = NULL; @@ -429,9 +627,9 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, switch(session->packAdd_state) { case libssh2_NB_state_idle: - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Packet type %d received, length=%d", - (int) msg, (int) datalen); + (int) msg, (int) datalen)); if((macstate == LIBSSH2_MAC_INVALID) && (!session->macerror || @@ -455,6 +653,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, goto libssh2_packet_add_jump_point4; case libssh2_NB_state_jump5: goto libssh2_packet_add_jump_point5; + case libssh2_NB_state_jumpauthagent: + goto libssh2_packet_add_jump_authagent; default: /* nothing to do */ break; } @@ -472,36 +672,26 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, case SSH_MSG_DISCONNECT: if(datalen >= 5) { - size_t reason = _libssh2_ntohu32(data + 1); - - if(datalen >= 9) { - message_len = _libssh2_ntohu32(data + 5); + uint32_t reason = 0; + struct string_buf buf; + buf.data = (unsigned char *)data; + buf.dataptr = buf.data; + buf.len = datalen; + buf.dataptr++; /* advance past type */ - if(message_len < datalen-13) { - /* 9 = packet_type(1) + reason(4) + message_len(4) */ - message = (char *) data + 9; + _libssh2_get_u32(&buf, &reason); + _libssh2_get_string(&buf, &message, &message_len); + _libssh2_get_string(&buf, &language, &language_len); - language_len = - _libssh2_ntohu32(data + 9 + message_len); - language = (char *) data + 9 + message_len + 4; - - if(language_len > (datalen-13-message_len)) { - /* bad input, clear info */ - language = message = NULL; - language_len = message_len = 0; - } - } - else - /* bad size, clear it */ - message_len = 0; - } if(session->ssh_msg_disconnect) { - LIBSSH2_DISCONNECT(session, reason, message, - message_len, language, language_len); + LIBSSH2_DISCONNECT(session, reason, (const char *)message, + message_len, (const char *)language, + language_len); } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Disconnect(%d): %s(%s)", reason, - message, language); + message, language)); } LIBSSH2_FREE(session, data); @@ -539,35 +729,104 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, int always_display = data[1]; if(datalen >= 6) { - message_len = _libssh2_ntohu32(data + 2); - - if(message_len <= (datalen - 10)) { - /* 6 = packet_type(1) + display(1) + message_len(4) */ - message = (char *) data + 6; - language_len = _libssh2_ntohu32(data + 6 + - message_len); - - if(language_len <= (datalen - 10 - message_len)) - language = (char *) data + 10 + message_len; - } + struct string_buf buf; + buf.data = (unsigned char *)data; + buf.dataptr = buf.data; + buf.len = datalen; + buf.dataptr += 2; /* advance past type & always display */ + + _libssh2_get_string(&buf, &message, &message_len); + _libssh2_get_string(&buf, &language, &language_len); } if(session->ssh_msg_debug) { - LIBSSH2_DEBUG(session, always_display, message, - message_len, language, language_len); + LIBSSH2_DEBUG(session, always_display, + (const char *)message, + message_len, (const char *)language, + language_len); } } + /* - * _libssh2_debug will actually truncate this for us so + * _libssh2_debug() will actually truncate this for us so * that it's not an inordinate about of data */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Debug Packet: %s", message); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Debug Packet: %s", message)); LIBSSH2_FREE(session, data); session->packAdd_state = libssh2_NB_state_idle; return 0; /* + byte SSH_MSG_EXT_INFO + uint32 nr-extensions + [repeat "nr-extensions" times] + string extension-name [RFC8308] + string extension-value (binary) + */ + + case SSH_MSG_EXT_INFO: + if(datalen >= 5) { + uint32_t nr_extensions = 0; + struct string_buf buf; + buf.data = (unsigned char *)data; + buf.dataptr = buf.data; + buf.len = datalen; + buf.dataptr += 1; /* advance past type */ + + if(_libssh2_get_u32(&buf, &nr_extensions) != 0) { + rc = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid extension info received"); + } + + while(rc == 0 && nr_extensions > 0) { + + size_t name_len = 0; + size_t value_len = 0; + unsigned char *name = NULL; + unsigned char *value = NULL; + + nr_extensions -= 1; + + _libssh2_get_string(&buf, &name, &name_len); + _libssh2_get_string(&buf, &value, &value_len); + + if(name && value) { + _libssh2_debug((session, + LIBSSH2_TRACE_KEX, + "Server to Client extension %.*s: %.*s", + name_len, name, value_len, value)); + } + + if(name_len == 15 && + memcmp(name, "server-sig-algs", 15) == 0) { + if(session->server_sign_algorithms) { + LIBSSH2_FREE(session, + session->server_sign_algorithms); + } + + session->server_sign_algorithms = + LIBSSH2_ALLOC(session, + value_len + 1); + + if(session->server_sign_algorithms) { + memcpy(session->server_sign_algorithms, + value, value_len); + session->server_sign_algorithms[value_len] = '\0'; + } + else { + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "memory for server sign algo"); + } + } + } + } + + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return rc; + + /* byte SSH_MSG_GLOBAL_REQUEST string request name in US-ASCII only boolean want reply @@ -579,19 +838,19 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, uint32_t len = 0; unsigned char want_reply = 0; len = _libssh2_ntohu32(data + 1); - if(datalen >= (6 + len)) { + if((len <= (UINT_MAX - 6)) && (datalen >= (6 + len))) { want_reply = data[5 + len]; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Received global request type %.*s (wr %X)", - len, data + 5, want_reply); + len, data + 5, want_reply)); } if(want_reply) { static const unsigned char packet = SSH_MSG_REQUEST_FAILURE; - libssh2_packet_add_jump_point5: +libssh2_packet_add_jump_point5: session->packAdd_state = libssh2_NB_state_jump5; rc = _libssh2_transport_send(session, &packet, 1, NULL, 0); if(rc == LIBSSH2_ERROR_EAGAIN) @@ -643,12 +902,12 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(msg == SSH_MSG_CHANNEL_EXTENDED_DATA) stream_id = _libssh2_ntohu32(data + 5); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "%d bytes packet_add() for %lu/%lu/%lu", (int) (datalen - data_head), channelp->local.id, channelp->remote.id, - stream_id); + stream_id)); } #endif if((channelp->remote.extended_data_ignore_mode == @@ -657,30 +916,31 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, /* Pretend we didn't receive this */ LIBSSH2_FREE(session, data); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Ignoring extended data and refunding %d bytes", - (int) (datalen - 13)); + (int) (datalen - 13))); if(channelp->read_avail + datalen - data_head >= channelp->remote.window_size) datalen = channelp->remote.window_size - channelp->read_avail + data_head; - channelp->remote.window_size -= datalen - data_head; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + channelp->remote.window_size -= (uint32_t)(datalen - + data_head); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "shrinking window size by %lu bytes to %lu, " "read_avail %lu", datalen - data_head, channelp->remote.window_size, - channelp->read_avail); + channelp->read_avail)); session->packAdd_channelp = channelp; /* Adjust the window based on the block we just freed */ - libssh2_packet_add_jump_point1: +libssh2_packet_add_jump_point1: session->packAdd_state = libssh2_NB_state_jump1; rc = _libssh2_channel_receive_window_adjust(session-> packAdd_channelp, - datalen - 13, + (uint32_t)(datalen - 13), 1, NULL); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -698,8 +958,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * Spec says we MAY ignore bytes sent beyond * packet_size */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "Packet contains more data than we offered" " to receive, truncating"); datalen = channelp->remote.packet_size + data_head; @@ -709,8 +968,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * Spec says we MAY ignore bytes sent beyond * window_size */ - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "The current receive window is full," " data ignored"); LIBSSH2_FREE(session, data); @@ -722,8 +980,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(channelp->read_avail + datalen - data_head > channelp->remote.window_size) { - _libssh2_error(session, - LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current " "window allows, truncating"); datalen = channelp->remote.window_size - @@ -735,11 +992,11 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * from an upper layer */ channelp->read_avail += datalen - data_head; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "increasing read_avail by %lu bytes to %lu/%lu", (long)(datalen - data_head), (long)channelp->read_avail, - (long)channelp->remote.window_size); + (long)channelp->remote.window_size)); break; @@ -757,11 +1014,11 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, /* We may have freed already, just quietly ignore this... */ ; else { - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "EOF received for channel %lu/%lu", channelp->local.id, - channelp->remote.id); + channelp->remote.id)); channelp->remote.eof = 1; } LIBSSH2_FREE(session, data); @@ -785,10 +1042,10 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if((len + 9) < datalen) want_reply = data[len + 9]; - _libssh2_debug(session, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Channel %d received request type %.*s (wr %X)", - channel, len, data + 9, want_reply); + channel, len, data + 9, want_reply)); if(len == sizeof("exit-status") - 1 && (sizeof("exit-status") - 1 + 9) <= datalen @@ -803,12 +1060,12 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(channelp && (sizeof("exit-status") + 13) <= datalen) { channelp->exit_status = _libssh2_ntohu32(data + 9 + sizeof("exit-status")); - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Exit status %lu received for " "channel %lu/%lu", channelp->exit_status, channelp->local.id, - channelp->remote.id); + channelp->remote.id)); } } @@ -842,12 +1099,12 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, data + 13 + sizeof("exit-signal"), namelen); channelp->exit_signal[namelen] = '\0'; /* TODO: save error message and language tag */ - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Exit signal %s received for " "channel %lu/%lu", channelp->exit_signal, channelp->local.id, - channelp->remote.id); + channelp->remote.id)); } } } @@ -855,7 +1112,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(want_reply) { unsigned char packet[5]; - libssh2_packet_add_jump_point4: +libssh2_packet_add_jump_point4: session->packAdd_state = libssh2_NB_state_jump4; packet[0] = SSH_MSG_CHANNEL_FAILURE; memcpy(&packet[1], data + 1, 4); @@ -884,10 +1141,10 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, session->packAdd_state = libssh2_NB_state_idle; return 0; } - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Close received for channel %lu/%lu", channelp->local.id, - channelp->remote.id); + channelp->remote.id)); channelp->remote.close = 1; channelp->remote.eof = 1; @@ -918,7 +1175,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, memset(&session->packAdd_Qlstn_state, 0, sizeof(session->packAdd_Qlstn_state)); - libssh2_packet_add_jump_point2: +libssh2_packet_add_jump_point2: session->packAdd_state = libssh2_NB_state_jump2; rc = packet_queue_listener(session, data, datalen, &session->packAdd_Qlstn_state); @@ -931,11 +1188,26 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, memset(&session->packAdd_x11open_state, 0, sizeof(session->packAdd_x11open_state)); - libssh2_packet_add_jump_point3: +libssh2_packet_add_jump_point3: session->packAdd_state = libssh2_NB_state_jump3; rc = packet_x11_open(session, data, datalen, &session->packAdd_x11open_state); } + else if((datalen >= (sizeof("auth-agent@openssh.com") + 4)) && + ((sizeof("auth-agent@openssh.com") - 1) == + _libssh2_ntohu32(data + 1)) && + (memcmp(data + 5, "auth-agent@openssh.com", + sizeof("auth-agent@openssh.com") - 1) == 0)) { + + /* init the state struct */ + memset(&session->packAdd_authagent_state, 0, + sizeof(session->packAdd_authagent_state)); + +libssh2_packet_add_jump_authagent: + session->packAdd_state = libssh2_NB_state_jumpauthagent; + rc = packet_authagent_open(session, data, datalen, + &session->packAdd_authagent_state); + } if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -959,13 +1231,13 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, if(channelp) { channelp->local.window_size += bytestoadd; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, + _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Window adjust for channel %lu/%lu, " "adding %lu bytes, new window_size=%lu", channelp->local.id, channelp->remote.id, bytestoadd, - channelp->local.window_size); + channelp->local.window_size)); } } LIBSSH2_FREE(session, data); @@ -982,8 +1254,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, LIBSSH2_PACKET *packetp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET)); if(!packetp) { - _libssh2_debug(session, LIBSSH2_ERROR_ALLOC, - "memory for packet"); + _libssh2_debug((session, LIBSSH2_ERROR_ALLOC, + "memory for packet")); LIBSSH2_FREE(session, data); session->packAdd_state = libssh2_NB_state_idle; return LIBSSH2_ERROR_ALLOC; @@ -1006,7 +1278,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, * Well, it's already in the brigade, * let's just call back into ourselves */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Renegotiating Keys")); session->packAdd_state = libssh2_NB_state_sent2; } @@ -1051,8 +1324,8 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, { LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets); - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Looking for packet of type: %d", (int) packet_type); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Looking for packet of type: %d", (int) packet_type)); while(packet) { if(packet->data[0] == packet_type @@ -1089,12 +1362,12 @@ _libssh2_packet_askv(LIBSSH2_SESSION * session, const unsigned char *match_buf, size_t match_len) { - int i, packet_types_len = strlen((char *) packet_types); + size_t i, packet_types_len = strlen((const char *) packet_types); for(i = 0; i < packet_types_len; i++) { - if(0 == _libssh2_packet_ask(session, packet_types[i], data, - data_len, match_ofs, - match_buf, match_len)) { + if(_libssh2_packet_ask(session, packet_types[i], data, + data_len, match_ofs, + match_buf, match_len) == 0) { return 0; } } @@ -1121,8 +1394,8 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, { if(state->start == 0) { if(_libssh2_packet_ask(session, packet_type, data, data_len, - match_ofs, match_buf, - match_len) == 0) { + match_ofs, match_buf, + match_len) == 0) { /* A packet was available in the packet brigade */ return 0; } @@ -1148,8 +1421,8 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, } else if(ret == 0) { /* nothing available, wait until data arrives or we time out */ - long left = LIBSSH2_READ_TIMEOUT - (long)(time(NULL) - - state->start); + long left = session->packet_read_timeout - (long)(time(NULL) - + state->start); if(left <= 0) { state->start = 0; @@ -1186,15 +1459,15 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session, all_packets[254] = 0; if(_libssh2_packet_askv(session, all_packets, &data, &data_len, 0, - NULL, 0) == 0) { + NULL, 0) == 0) { i = data[0]; /* A packet was available in the packet brigade, burn it */ LIBSSH2_FREE(session, data); return i; } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Blocking until packet becomes available to burn"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Blocking until packet becomes available to burn")); *state = libssh2_NB_state_created; } @@ -1215,7 +1488,7 @@ _libssh2_packet_burn(LIBSSH2_SESSION * session, /* Be lazy, let packet_ask pull it out of the brigade */ if(0 == _libssh2_packet_ask(session, (unsigned char)ret, - &data, &data_len, 0, NULL, 0)) { + &data, &data_len, 0, NULL, 0)) { /* Smoke 'em if you got 'em */ LIBSSH2_FREE(session, data); *state = libssh2_NB_state_idle; @@ -1244,7 +1517,7 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, packet_requirev_state_t * state) { if(_libssh2_packet_askv(session, packet_types, data, data_len, match_ofs, - match_buf, match_len) == 0) { + match_buf, match_len) == 0) { /* One of the packets listed was available in the packet brigade */ state->start = 0; return 0; @@ -1261,7 +1534,7 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, return ret; } if(ret <= 0) { - long left = LIBSSH2_READ_TIMEOUT - + long left = session->packet_read_timeout - (long)(time(NULL) - state->start); if(left <= 0) { @@ -1275,9 +1548,11 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, if(strchr((char *) packet_types, ret)) { /* Be lazy, let packet_ask pull it out of the brigade */ - return _libssh2_packet_askv(session, packet_types, data, - data_len, match_ofs, match_buf, - match_len); + ret = _libssh2_packet_askv(session, packet_types, data, + data_len, match_ofs, match_buf, + match_len); + state->start = 0; + return ret; } } @@ -1285,4 +1560,3 @@ _libssh2_packet_requirev(LIBSSH2_SESSION *session, state->start = 0; return LIBSSH2_ERROR_SOCKET_DISCONNECT; } - diff --git a/libs/libssh2/src/packet.h b/libs/libssh2/src/packet.h index d66b15b50d..55428d0651 100644 --- a/libs/libssh2/src/packet.h +++ b/libs/libssh2/src/packet.h @@ -1,8 +1,8 @@ -#ifndef LIBSSH2_PACKET_H -#define LIBSSH2_PACKET_H +#ifndef __LIBSSH2_PACKET_H +#define __LIBSSH2_PACKET_H /* - * Copyright (C) 2010 by Daniel Stenberg - * Author: Daniel Stenberg <daniel@haxx.se> + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -37,6 +37,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ int _libssh2_packet_read(LIBSSH2_SESSION * session); @@ -73,4 +74,4 @@ int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data, int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, size_t datalen, int macstate); -#endif /* LIBSSH2_PACKET_H */ +#endif /* __LIBSSH2_PACKET_H */ diff --git a/libs/libssh2/src/pem.c b/libs/libssh2/src/pem.c index 53f58c2ef1..912498c5d3 100644 --- a/libs/libssh2/src/pem.c +++ b/libs/libssh2/src/pem.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2007 The Written Word, Inc. - * Copyright (C) 2008, Simon Josefsson +/* Copyright (C) The Written Word, Inc. + * Copyright (C) Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -100,20 +102,27 @@ static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED"; static unsigned char hex_decode(char digit) { - return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0'); + return (unsigned char) + ((digit >= 'A') ? (0xA + (digit - 'A')) : (digit - '0')); } +/* Hack to fix builds with crypto backends with MD5 support disabled. + FIXME: Honor our LIBSSH2_MD5 macro for MD5-dependent logic. */ +#ifdef OPENSSL_NO_MD5 +#define MD5_DIGEST_LENGTH 16 +#endif + int _libssh2_pem_parse(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const unsigned char *passphrase, - FILE * fp, unsigned char **data, unsigned int *datalen) + FILE * fp, unsigned char **data, size_t *datalen) { char line[LINE_SIZE]; unsigned char iv[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; int ret; const LIBSSH2_CRYPT_METHOD *method = NULL; @@ -141,7 +150,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, } all_methods = libssh2_crypt_methods(); - while((cur_method = *all_methods++)) { + /* !checksrc! disable EQUALSNULL 1 */ + while((cur_method = *all_methods++) != NULL) { if(*cur_method->pem_annotation && memcmp(line, cur_method->pem_annotation, strlen(cur_method->pem_annotation)) == 0) { @@ -152,12 +162,12 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, } /* None of the available crypt methods were able to decrypt the key */ - if(method == NULL) + if(!method) return -1; /* Decode IV from hex */ for(i = 0; i < method->iv_len; ++i) { - iv[i] = hex_decode(iv[2*i]) << 4; + iv[i] = (unsigned char)(hex_decode(iv[2*i]) << 4); iv[i] |= hex_decode(iv[2*i + 1]); } @@ -176,6 +186,8 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, linelen = strlen(line); tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); if(!tmp) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for PEM parsing"); ret = -1; goto out; } @@ -196,7 +208,7 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, return -1; } - if(libssh2_base64_decode(session, (char **) data, datalen, + if(_libssh2_base64_decode(session, (char **) data, datalen, b64data, b64datalen)) { ret = -1; goto out; @@ -256,7 +268,11 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, while(len_decrypted <= (int)*datalen - blocksize) { if(method->crypt(session, *data + len_decrypted, blocksize, - &abstract)) { + &abstract, + len_decrypted == 0 ? FIRST_BLOCK : + ((len_decrypted == (int)*datalen - blocksize) ? + LAST_BLOCK : MIDDLE_BLOCK) + )) { ret = LIBSSH2_ERROR_DECRYPT; _libssh2_explicit_zero((char *)secret, sizeof(secret)); method->dtor(session, &abstract); @@ -279,7 +295,7 @@ _libssh2_pem_parse(LIBSSH2_SESSION * session, } ret = 0; - out: +out: if(b64data) { _libssh2_explicit_zero(b64data, b64datalen); LIBSSH2_FREE(session, b64data); @@ -292,11 +308,11 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, const char *headerbegin, const char *headerend, const char *filedata, size_t filedata_len, - unsigned char **data, unsigned int *datalen) + unsigned char **data, size_t *datalen) { char line[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; size_t off = 0; int ret; @@ -319,6 +335,8 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, linelen = strlen(line); tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); if(!tmp) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for PEM parsing"); ret = -1; goto out; } @@ -339,14 +357,14 @@ _libssh2_pem_parse_memory(LIBSSH2_SESSION * session, return -1; } - if(libssh2_base64_decode(session, (char **) data, datalen, + if(_libssh2_base64_decode(session, (char **) data, datalen, b64data, b64datalen)) { ret = -1; goto out; } ret = 0; - out: +out: if(b64data) { _libssh2_explicit_zero(b64data, b64datalen); LIBSSH2_FREE(session, b64data); @@ -378,7 +396,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, unsigned char *key_part = NULL; unsigned char *iv_part = NULL; unsigned char *f = NULL; - unsigned int f_len = 0; + size_t f_len = 0; int ret = 0, keylen = 0, ivlen = 0, total_len = 0; size_t kdf_len = 0, tmp_len = 0, salt_len = 0; @@ -386,10 +404,10 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, *decrypted_buf = NULL; /* decode file */ - if(libssh2_base64_decode(session, (char **)&f, &f_len, - b64data, b64datalen)) { - ret = -1; - goto out; + if(_libssh2_base64_decode(session, (char **)&f, &f_len, + b64data, b64datalen)) { + ret = -1; + goto out; } /* Parse the file */ @@ -421,7 +439,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) || tmp_len == 0) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "kdfname is missing"); + "kdfname is missing"); goto out; } @@ -436,7 +454,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, kdf_buf.len = kdf_len; } - if((passphrase == NULL || strlen((const char *)passphrase) == 0) && + if((!passphrase || strlen((const char *)passphrase) == 0) && strcmp((const char *)ciphername, "none") != 0) { /* passphrase required */ ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; @@ -452,8 +470,8 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(!strcmp((const char *)kdfname, "none") && strcmp((const char *)ciphername, "none") != 0) { - ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO, - "invalid format"); + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "invalid format"); goto out; } @@ -474,7 +492,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Private key data not found"); + "Private key data not found"); goto out; } @@ -486,7 +504,8 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method; all_methods = libssh2_crypt_methods(); - while((cur_method = *all_methods++)) { + /* !checksrc! disable EQUALSNULL 1 */ + while((cur_method = *all_methods++) != NULL) { if(*cur_method->name && memcmp(ciphername, cur_method->name, strlen(cur_method->name)) == 0) { @@ -496,9 +515,9 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, /* None of the available crypt methods were able to decrypt the key */ - if(method == NULL) { + if(!method) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "No supported cipher found"); + "No supported cipher found"); goto out; } } @@ -513,16 +532,15 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, total_len = keylen + ivlen; key = LIBSSH2_CALLOC(session, total_len); - if(key == NULL) { + if(!key) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Could not alloc key"); + "Could not alloc key"); goto out; } - if(strcmp((const char *)kdfname, "bcrypt") == 0 && - passphrase != NULL) { + if(strcmp((const char *)kdfname, "bcrypt") == 0 && passphrase) { if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) || - (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) { + (_libssh2_get_u32(&kdf_buf, &rounds) != 0)) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "kdf contains unexpected values"); LIBSSH2_FREE(session, key); @@ -541,7 +559,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, } else { ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED, - "bcrypted without passphrase"); + "bcrypted without passphrase"); LIBSSH2_FREE(session, key); goto out; } @@ -550,14 +568,14 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, blocksize = method->blocksize; key_part = LIBSSH2_CALLOC(session, keylen); - if(key_part == NULL) { + if(!key_part) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Could not alloc key part"); goto out; } iv_part = LIBSSH2_CALLOC(session, ivlen); - if(iv_part == NULL) { + if(!iv_part) { ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Could not alloc iv part"); goto out; @@ -568,7 +586,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, /* Initialize the decryption */ if(method->init(session, method, iv_part, &free_iv, key_part, - &free_secret, 0, &abstract)) { + &free_secret, 0, &abstract)) { ret = LIBSSH2_ERROR_DECRYPT; goto out; } @@ -583,7 +601,11 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, while((size_t)len_decrypted <= decrypted.len - blocksize) { if(method->crypt(session, decrypted.data + len_decrypted, blocksize, - &abstract)) { + &abstract, + len_decrypted == 0 ? FIRST_BLOCK : ( + ((size_t)len_decrypted == decrypted.len - blocksize) ? + LAST_BLOCK : MIDDLE_BLOCK) + )) { ret = LIBSSH2_ERROR_DECRYPT; method->dtor(session, &abstract); goto out; @@ -602,13 +624,13 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, if(_libssh2_get_u32(&decrypted, &check1) != 0 || _libssh2_get_u32(&decrypted, &check2) != 0 || check1 != check2) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Private key unpack failed (correct password?)"); - ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; - goto out; + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Private key unpack failed (correct password?)"); + ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED; + goto out; } - if(decrypted_buf != NULL) { + if(decrypted_buf) { /* copy data to out-going buffer */ struct string_buf *out_buf = _libssh2_string_buf_new(session); if(!out_buf) { @@ -619,7 +641,7 @@ _libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session, } out_buf->data = LIBSSH2_CALLOC(session, decrypted.len); - if(out_buf->data == NULL) { + if(!out_buf->data) { ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for " "decrypted struct"); @@ -664,7 +686,7 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, { char line[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; int ret = 0; /* read file */ @@ -690,6 +712,8 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, linelen = strlen(line); tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); if(!tmp) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for PEM parsing"); ret = -1; goto out; } @@ -713,7 +737,7 @@ _libssh2_openssh_pem_parse(LIBSSH2_SESSION * session, ret = _libssh2_openssh_pem_parse_data(session, passphrase, (const char *)b64data, - (size_t)b64datalen, + b64datalen, decrypted_buf); if(b64data) { @@ -734,21 +758,22 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, { char line[LINE_SIZE]; char *b64data = NULL; - unsigned int b64datalen = 0; + size_t b64datalen = 0; size_t off = 0; int ret; - if(filedata == NULL || filedata_len <= 0) { - return -1; - } + if(!filedata || filedata_len <= 0) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Error parsing PEM: filedata missing"); do { *line = '\0'; - if(off >= filedata_len) { - return -1; - } + if(off >= filedata_len) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Error parsing PEM: " + "OpenSSH header not found"); if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { return -1; @@ -759,14 +784,16 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, *line = '\0'; do { - if (*line) { + if(*line) { char *tmp; size_t linelen; linelen = strlen(line); tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); if(!tmp) { - ret = -1; + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "PEM parsing"); goto out; } memcpy(tmp + b64datalen, line, linelen); @@ -777,7 +804,8 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, *line = '\0'; if(off >= filedata_len) { - ret = -1; + ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Error parsing PEM: offset out of bounds"); goto out; } @@ -787,9 +815,9 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, } } while(strcmp(line, OPENSSH_HEADER_END) != 0); - if(!b64data) { - return -1; - } + if(!b64data) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Error parsing PEM: base 64 data missing"); ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data, b64datalen, decrypted_buf); @@ -805,7 +833,7 @@ out: static int read_asn1_length(const unsigned char *data, - unsigned int datalen, unsigned int *len) + size_t datalen, size_t *len) { unsigned int lenlen; int nextpos; @@ -839,9 +867,9 @@ read_asn1_length(const unsigned char *data, } int -_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) +_libssh2_pem_decode_sequence(unsigned char **data, size_t *datalen) { - unsigned int len; + size_t len; int lenlen; if(*datalen < 1) { @@ -867,10 +895,10 @@ _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) } int -_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, +_libssh2_pem_decode_integer(unsigned char **data, size_t *datalen, unsigned char **i, unsigned int *ilen) { - unsigned int len; + size_t len; int lenlen; if(*datalen < 1) { @@ -893,7 +921,7 @@ _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, *datalen -= lenlen; *i = *data; - *ilen = len; + *ilen = (unsigned int)len; *data += len; *datalen -= len; diff --git a/libs/libssh2/src/publickey.c b/libs/libssh2/src/publickey.c index f26c6327dc..db45be99be 100644 --- a/libs/libssh2/src/publickey.c +++ b/libs/libssh2/src/publickey.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2010-2014 by Daniel Stenberg +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,6 +34,8 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" @@ -105,7 +107,7 @@ static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_status_codes[] = { */ static void publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, - LIBSSH2_SESSION *session, int status) + LIBSSH2_SESSION *session, unsigned long status) { const char *msg; @@ -114,7 +116,7 @@ publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, status = 7; } - if(status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) { + if(status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) { msg = "unknown"; } else { @@ -136,14 +138,14 @@ publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey, LIBSSH2_CHANNEL *channel = pkey->channel; LIBSSH2_SESSION *session = channel->session; unsigned char buffer[4]; - int rc; + ssize_t rc; *data = NULL; /* default to nothing returned */ *data_len = 0; if(pkey->receive_state == libssh2_NB_state_idle) { rc = _libssh2_channel_read(channel, 0, (char *) buffer, 4); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc != 4) { return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, @@ -166,9 +168,9 @@ publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey, rc = _libssh2_channel_read(channel, 0, (char *) pkey->receive_packet, pkey->receive_packet_len); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } - else if(rc != (int)pkey->receive_packet_len) { + else if(rc != (ssize_t)pkey->receive_packet_len) { LIBSSH2_FREE(session, pkey->receive_packet); pkey->receive_packet = NULL; pkey->receive_state = libssh2_NB_state_idle; @@ -234,7 +236,7 @@ publickey_response_success(LIBSSH2_PUBLICKEY * pkey) size_t data_len; int response; - while(1) { + for(;;) { int rc = publickey_packet_receive(pkey, &data, &data_len); if(rc == LIBSSH2_ERROR_EAGAIN) { return rc; @@ -272,7 +274,7 @@ publickey_response_success(LIBSSH2_PUBLICKEY * pkey) return 0; publickey_status_error(pkey, session, status); - return -1; + goto err_exit; } default: LIBSSH2_FREE(session, data); @@ -287,7 +289,7 @@ publickey_response_success(LIBSSH2_PUBLICKEY * pkey) data = NULL; } } - /* never reached, but include `return` to silence compiler warnings */ +err_exit: return -1; } @@ -310,8 +312,8 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) session->pkeyInit_pkey = NULL; session->pkeyInit_channel = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Initializing publickey subsystem"); + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, + "Initializing publickey subsystem")); session->pkeyInit_state = libssh2_NB_state_allocated; } @@ -387,28 +389,29 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) session->pkeyInit_buffer_sent = 0; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Sending publickey advertising version %d support", - (int) LIBSSH2_PUBLICKEY_VERSION); + (int) LIBSSH2_PUBLICKEY_VERSION)); session->pkeyInit_state = libssh2_NB_state_sent2; } if(session->pkeyInit_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->pkeyInit_channel, 0, - session->pkeyInit_buffer, - 19 - session->pkeyInit_buffer_sent); - if(rc == LIBSSH2_ERROR_EAGAIN) { + ssize_t nwritten; + nwritten = _libssh2_channel_write(session->pkeyInit_channel, 0, + session->pkeyInit_buffer, + 19 - session->pkeyInit_buffer_sent); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending publickey version packet"); return NULL; } - else if(rc < 0) { - _libssh2_error(session, rc, + else if(nwritten < 0) { + _libssh2_error(session, (int)nwritten, "Unable to send publickey version packet"); goto err_exit; } - session->pkeyInit_buffer_sent += rc; + session->pkeyInit_buffer_sent += nwritten; if(session->pkeyInit_buffer_sent < 19) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Need to be called again to complete this"); @@ -419,7 +422,7 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) } if(session->pkeyInit_state == libssh2_NB_state_sent3) { - while(1) { + for(;;) { unsigned char *s; rc = publickey_packet_receive(session->pkeyInit_pkey, &session->pkeyInit_data, @@ -511,16 +514,16 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) session->pkeyInit_pkey->version = _libssh2_ntohu32(s); if(session->pkeyInit_pkey->version > LIBSSH2_PUBLICKEY_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Truncate remote publickey version " "from %lu", - session->pkeyInit_pkey->version); + session->pkeyInit_pkey->version)); session->pkeyInit_pkey->version = LIBSSH2_PUBLICKEY_VERSION; } - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Enabling publickey subsystem version %lu", - session->pkeyInit_pkey->version); + session->pkeyInit_pkey->version)); LIBSSH2_FREE(session, session->pkeyInit_data); session->pkeyInit_data = NULL; session->pkeyInit_state = libssh2_NB_state_idle; @@ -538,7 +541,7 @@ static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) } /* Never reached except by direct goto */ - err_exit: +err_exit: session->pkeyInit_state = libssh2_NB_state_sent4; if(session->pkeyInit_channel) { rc = _libssh2_channel_close(session->pkeyInit_channel); @@ -607,8 +610,8 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, if(pkey->add_state == libssh2_NB_state_idle) { pkey->add_packet = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, "Adding %s publickey", - name); + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, + "Adding %s publickey", name)); if(pkey->version == 1) { for(i = 0; i < num_attrs; i++) { @@ -639,25 +642,25 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, } pkey->add_s = pkey->add_packet; - _libssh2_htonu32(pkey->add_s, packet_len - 4); + _libssh2_htonu32(pkey->add_s, (uint32_t)(packet_len - 4)); pkey->add_s += 4; _libssh2_htonu32(pkey->add_s, sizeof("add") - 1); pkey->add_s += 4; memcpy(pkey->add_s, "add", sizeof("add") - 1); pkey->add_s += sizeof("add") - 1; if(pkey->version == 1) { - _libssh2_htonu32(pkey->add_s, comment_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)comment_len); pkey->add_s += 4; if(comment) { memcpy(pkey->add_s, comment, comment_len); pkey->add_s += comment_len; } - _libssh2_htonu32(pkey->add_s, name_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)name_len); pkey->add_s += 4; memcpy(pkey->add_s, name, name_len); pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)blob_len); pkey->add_s += 4; memcpy(pkey->add_s, blob, blob_len); pkey->add_s += blob_len; @@ -665,23 +668,23 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, else { /* Version == 2 */ - _libssh2_htonu32(pkey->add_s, name_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)name_len); pkey->add_s += 4; memcpy(pkey->add_s, name, name_len); pkey->add_s += name_len; - _libssh2_htonu32(pkey->add_s, blob_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)blob_len); pkey->add_s += 4; memcpy(pkey->add_s, blob, blob_len); pkey->add_s += blob_len; *(pkey->add_s++) = overwrite ? 0x01 : 0; - _libssh2_htonu32(pkey->add_s, num_attrs); + _libssh2_htonu32(pkey->add_s, (uint32_t)num_attrs); pkey->add_s += 4; for(i = 0; i < num_attrs; i++) { - _libssh2_htonu32(pkey->add_s, attrs[i].name_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)attrs[i].name_len); pkey->add_s += 4; memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len); pkey->add_s += attrs[i].name_len; - _libssh2_htonu32(pkey->add_s, attrs[i].value_len); + _libssh2_htonu32(pkey->add_s, (uint32_t)attrs[i].value_len); pkey->add_s += 4; memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len); pkey->add_s += attrs[i].value_len; @@ -689,21 +692,22 @@ libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, } } - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Sending publickey \"add\" packet: " "type=%s blob_len=%ld num_attrs=%ld", - name, blob_len, num_attrs); + name, blob_len, num_attrs)); pkey->add_state = libssh2_NB_state_created; } if(pkey->add_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->add_packet, - (pkey->add_s - pkey->add_packet)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, pkey->add_packet, + (pkey->add_s - pkey->add_packet)); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((pkey->add_s - pkey->add_packet) != rc) { + else if((pkey->add_s - pkey->add_packet) != nwritten) { LIBSSH2_FREE(session, pkey->add_packet); pkey->add_packet = NULL; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, @@ -758,36 +762,37 @@ libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey, } pkey->remove_s = pkey->remove_packet; - _libssh2_htonu32(pkey->remove_s, packet_len - 4); + _libssh2_htonu32(pkey->remove_s, (uint32_t)(packet_len - 4)); pkey->remove_s += 4; _libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1); pkey->remove_s += 4; memcpy(pkey->remove_s, "remove", sizeof("remove") - 1); pkey->remove_s += sizeof("remove") - 1; - _libssh2_htonu32(pkey->remove_s, name_len); + _libssh2_htonu32(pkey->remove_s, (uint32_t)name_len); pkey->remove_s += 4; memcpy(pkey->remove_s, name, name_len); pkey->remove_s += name_len; - _libssh2_htonu32(pkey->remove_s, blob_len); + _libssh2_htonu32(pkey->remove_s, (uint32_t)blob_len); pkey->remove_s += 4; memcpy(pkey->remove_s, blob, blob_len); pkey->remove_s += blob_len; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, "Sending publickey \"remove\" packet: " "type=%s blob_len=%ld", - name, blob_len); + name, blob_len)); pkey->remove_state = libssh2_NB_state_created; } if(pkey->remove_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, pkey->remove_packet, - (pkey->remove_s - pkey->remove_packet)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, pkey->remove_packet, + (pkey->remove_s - pkey->remove_packet)); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((pkey->remove_s - pkey->remove_packet) != rc) { + else if((pkey->remove_s - pkey->remove_packet) != nwritten) { LIBSSH2_FREE(session, pkey->remove_packet); pkey->remove_packet = NULL; pkey->remove_state = libssh2_NB_state_idle; @@ -835,28 +840,29 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, pkey->listFetch_data = NULL; pkey->listFetch_s = pkey->listFetch_buffer; - _libssh2_htonu32(pkey->listFetch_s, buffer_len - 4); + _libssh2_htonu32(pkey->listFetch_s, (uint32_t)(buffer_len - 4)); pkey->listFetch_s += 4; _libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1); pkey->listFetch_s += 4; memcpy(pkey->listFetch_s, "list", sizeof("list") - 1); pkey->listFetch_s += sizeof("list") - 1; - _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, - "Sending publickey \"list\" packet"); + _libssh2_debug((session, LIBSSH2_TRACE_PUBLICKEY, + "Sending publickey \"list\" packet")); pkey->listFetch_state = libssh2_NB_state_created; } if(pkey->listFetch_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, - pkey->listFetch_buffer, - (pkey->listFetch_s - - pkey->listFetch_buffer)); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, + pkey->listFetch_buffer, + (pkey->listFetch_s - + pkey->listFetch_buffer)); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((pkey->listFetch_s - pkey->listFetch_buffer) != rc) { + else if((pkey->listFetch_s - pkey->listFetch_buffer) != nwritten) { pkey->listFetch_state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet"); @@ -865,7 +871,7 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, pkey->listFetch_state = libssh2_NB_state_sent; } - while(1) { + for(;;) { rc = publickey_packet_receive(pkey, &pkey->listFetch_data, &pkey->listFetch_data_len); if(rc == LIBSSH2_ERROR_EAGAIN) { @@ -1197,7 +1203,7 @@ libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, } /* Only reached via explicit goto */ - err_exit: +err_exit: if(pkey->listFetch_data) { LIBSSH2_FREE(session, pkey->listFetch_data); pkey->listFetch_data = NULL; diff --git a/libs/libssh2/src/scp.c b/libs/libssh2/src/scp.c index a9d2db5354..ff20a80ae5 100644 --- a/libs/libssh2/src/scp.c +++ b/libs/libssh2/src/scp.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2009-2019 by Daniel Stenberg - * Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org> +/* Copyright (C) Daniel Stenberg + * Copyright (C) Sara Golemon <sarag@libssh2.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,15 +34,24 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include <errno.h> -#include <stdlib.h> #include "channel.h" #include "session.h" +#include <stdlib.h> /* strtoll(), _strtoi64(), strtol() */ + +#if defined(HAVE_STRTOLL) +#define scpsize_strtol strtoll +#elif defined(HAVE_STRTOI64) +#define scpsize_strtol _strtoi64 +#else +#define scpsize_strtol strtol +#endif /* Max. length of a quoted string after libssh2_shell_quotearg() processing */ #define _libssh2_shell_quotedsize(s) (3 * strlen(s) + 2) @@ -65,13 +74,13 @@ current argument word, add the apostrophe in quotation marks "", and open a new argument word instead (_ indicate the input string characters): - _____ _ _ + _____ _ _ 'doesn' "'" 't' Sequences of apostrophes are combined in one pair of quotation marks: a'''b becomes - _ ___ _ + _ ___ _ 'a'"'''"'b' o If the string contains an exclamation mark (!), the C-Shell @@ -84,7 +93,7 @@ a!b become - _ _ _ + _ _ _ 'a'\!'b' The result buffer must be large enough for the expanded result. A @@ -112,7 +121,7 @@ References: o csh-compatible quotation (special handling for '!' etc.), see - http://www.grymoire.com/Unix/Csh.html#toc-uh-10 + https://www.grymoire.com/Unix/Csh.html#toc-uh-10 Return value: Length of the resulting string (not counting the terminating '\0'), @@ -122,9 +131,9 @@ until then it is kept static and in this source file. */ -static unsigned +static size_t shell_quotearg(const char *path, unsigned char *buf, - unsigned bufsize) + size_t bufsize) { const char *src; unsigned char *dst, *endp; @@ -270,7 +279,7 @@ shell_quotearg(const char *path, unsigned char *buf, static LIBSSH2_CHANNEL * scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) { - int cmd_len; + size_t cmd_len; int rc; int tmp_err_code; const char *tmp_err_msg; @@ -282,7 +291,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) session->scpRecv_atime = 0; session->scpRecv_command_len = - _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0); + _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb ? 1 : 0); session->scpRecv_command = LIBSSH2_ALLOC(session, session->scpRecv_command_len); @@ -296,18 +305,30 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) snprintf((char *)session->scpRecv_command, session->scpRecv_command_len, - "scp -%sf ", sb?"p":""); + "scp -%sf ", sb ? "p" : ""); cmd_len = strlen((char *)session->scpRecv_command); - cmd_len += shell_quotearg(path, - &session->scpRecv_command[cmd_len], - session->scpRecv_command_len - cmd_len); + + if(!session->flag.quote_paths) { + size_t path_len; + + path_len = strlen(path); + + /* no NUL-termination needed, so memcpy will do */ + memcpy(&session->scpRecv_command[cmd_len], path, path_len); + cmd_len += path_len; + } + else { + cmd_len += shell_quotearg(path, + &session->scpRecv_command[cmd_len], + session->scpRecv_command_len - cmd_len); + } /* the command to exec should _not_ be NUL-terminated */ session->scpRecv_command_len = cmd_len; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP receive"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP receive")); session->scpRecv_state = libssh2_NB_state_created; } @@ -356,7 +377,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) LIBSSH2_FREE(session, session->scpRecv_command); session->scpRecv_command = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sending initial wakeup")); /* SCP ACK */ session->scpRecv_response[0] = '\0'; @@ -364,8 +385,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent1) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending initial wakeup"); @@ -384,14 +405,15 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) if((session->scpRecv_state == libssh2_NB_state_sent2) || (session->scpRecv_state == libssh2_NB_state_sent3)) { while(sb && (session->scpRecv_response_len < - LIBSSH2_SCP_RESPONSE_BUFLEN)) { + LIBSSH2_SCP_RESPONSE_BUFLEN)) { unsigned char *s, *p; if(session->scpRecv_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); + rc = (int)_libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response"); @@ -435,9 +457,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) /* zero terminate the error */ err_msg[err_len] = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "got %02x %s", session->scpRecv_response[0], - err_msg); + err_msg)); _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Failed to recv file"); @@ -550,8 +572,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent3) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting to send SCP ACK"); @@ -561,9 +583,10 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) goto scp_recv_error; } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "mtime = %ld, atime = %ld", - session->scpRecv_mtime, session->scpRecv_atime); + session->scpRecv_mtime, + session->scpRecv_atime)); /* We *should* check that atime.usec is valid, but why let that stop use? */ @@ -586,17 +609,18 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) char *s, *p, *e = NULL; if(session->scpRecv_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); + rc = (int)_libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response"); return NULL; } else if(rc < 0) { - /* error, bail out*/ + /* error, bail out */ _libssh2_error(session, rc, "Failed reading SCP response"); goto scp_recv_error; } @@ -678,7 +702,6 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) *(p++) = '\0'; /* Make sure we don't get fooled by leftover values */ - session->scpRecv_mode = strtol(s, &e, 8); if(e && *e) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, @@ -713,8 +736,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent6) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending SCP ACK"); @@ -723,9 +746,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) else if(rc != 1) { goto scp_recv_error; } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "mode = 0%lo size = %ld", session->scpRecv_mode, - session->scpRecv_size); + session->scpRecv_size)); /* We *should* check that basename is valid, but why let that stop us? */ @@ -741,14 +764,14 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) sb->st_mtime = session->scpRecv_mtime; sb->st_atime = session->scpRecv_atime; - sb->st_size = session->scpRecv_size; + sb->st_size = (libssh2_struct_stat_size)session->scpRecv_size; sb->st_mode = (unsigned short)session->scpRecv_mode; } session->scpRecv_state = libssh2_NB_state_idle; return session->scpRecv_channel; - scp_recv_empty_channel: +scp_recv_empty_channel: /* the code only jumps here as a result of a zero read from channel_read() so we check EOF status to avoid getting stuck in a loop */ if(libssh2_channel_eof(session->scpRecv_channel)) @@ -757,7 +780,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) else return session->scpRecv_channel; /* fall-through */ - scp_recv_error: +scp_recv_error: tmp_err_code = session->err_code; tmp_err_msg = session->err_msg; while(libssh2_channel_free(session->scpRecv_channel) == @@ -780,7 +803,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) * */ LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) +libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb) { LIBSSH2_CHANNEL *ptr; @@ -823,7 +846,7 @@ libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, } /* - * scp_send() + * scp_send * * Send a file using SCP * @@ -832,7 +855,7 @@ static LIBSSH2_CHANNEL * scp_send(LIBSSH2_SESSION * session, const char *path, int mode, libssh2_int64_t size, time_t mtime, time_t atime) { - int cmd_len; + size_t cmd_len; int rc; int tmp_err_code; const char *tmp_err_msg; @@ -840,7 +863,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_idle) { session->scpSend_command_len = _libssh2_shell_quotedsize(path) + sizeof("scp -t ") + - ((mtime || atime)?1:0); + ((mtime || atime) ? 1 : 0); session->scpSend_command = LIBSSH2_ALLOC(session, session->scpSend_command_len); @@ -854,18 +877,31 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, snprintf((char *)session->scpSend_command, session->scpSend_command_len, - "scp -%st ", (mtime || atime)?"p":""); + "scp -%st ", (mtime || atime) ? "p" : ""); cmd_len = strlen((char *)session->scpSend_command); - cmd_len += shell_quotearg(path, - &session->scpSend_command[cmd_len], - session->scpSend_command_len - cmd_len); + + if(!session->flag.quote_paths) { + size_t path_len; + + path_len = strlen(path); + + /* no NUL-termination needed, so memcpy will do */ + memcpy(&session->scpSend_command[cmd_len], path, path_len); + cmd_len += path_len; + + } + else { + cmd_len += shell_quotearg(path, + &session->scpSend_command[cmd_len], + session->scpSend_command_len - cmd_len); + } /* the command to exec should _not_ be NUL-terminated */ session->scpSend_command_len = cmd_len; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP send"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP send")); /* Allocate a channel */ session->scpSend_state = libssh2_NB_state_created; @@ -922,8 +958,8 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent1) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response from remote"); @@ -936,7 +972,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(!rc) /* remain in the same state */ goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote"); goto scp_send_error; @@ -947,8 +983,8 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, snprintf((char *) session->scpSend_response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", (long)mtime, (long)atime); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response)); } session->scpSend_state = libssh2_NB_state_sent2; @@ -957,9 +993,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, /* Send mtime and atime to be used for file */ if(mtime || atime) { if(session->scpSend_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); + rc = (int)_libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending time data for SCP file"); @@ -976,8 +1012,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent3) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response"); @@ -990,7 +1027,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(!rc) /* remain in the same state */ goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid SCP ACK response"); goto scp_send_error; @@ -1018,16 +1055,16 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %" LIBSSH2_INT64_T_FORMAT " %s\n", mode, size, base); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response)); session->scpSend_state = libssh2_NB_state_sent5; } if(session->scpSend_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); + rc = (int)_libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block send core file data for SCP file"); @@ -1044,8 +1081,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent6) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response"); @@ -1059,7 +1097,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(rc == 0) goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { size_t err_len; char *err_msg; @@ -1073,13 +1111,13 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, } /* Read the remote error message */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - err_msg, err_len); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + err_msg, err_len); if(rc > 0) { err_msg[err_len] = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "got %02x %s", session->scpSend_response[0], - err_msg); + err_msg)); } LIBSSH2_FREE(session, err_msg); _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, @@ -1091,7 +1129,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, session->scpSend_state = libssh2_NB_state_idle; return session->scpSend_channel; - scp_send_empty_channel: +scp_send_empty_channel: /* the code only jumps here as a result of a zero read from channel_read() so we check EOF status to avoid getting stuck in a loop */ if(libssh2_channel_eof(session->scpSend_channel)) { @@ -1101,7 +1139,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else return session->scpSend_channel; /* fall-through */ - scp_send_error: +scp_send_error: tmp_err_code = session->err_code; tmp_err_msg = session->err_msg; while(libssh2_channel_free(session->scpSend_channel) == diff --git a/libs/libssh2/src/session.c b/libs/libssh2/src/session.c index e439acde57..4d9edc5c8c 100644 --- a/libs/libssh2/src/session.c +++ b/libs/libssh2/src/session.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2009-2015 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson <simon@josefsson.org> +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson <simon@josefsson.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,35 +35,45 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include <errno.h> + +#ifdef WIN32 +#include <ws2tcpip.h> /* for socklen_t */ +#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#include <stdlib.h> -#include <fcntl.h> - -#ifdef HAVE_GETTIMEOFDAY -#include <sys/time.h> -#endif #ifdef HAVE_ALLOCA_H #include <alloca.h> #endif +#include <errno.h> +#include <stdlib.h> +#include <fcntl.h> + #include "transport.h" #include "session.h" #include "channel.h" #include "mac.h" -#include "misc.h" + +#if defined(WIN32) +#define libssh2_usec_t long +#elif defined(__APPLE__) +#define libssh2_usec_t suseconds_t +#else +#undef libssh2_usec_t +#endif /* libssh2_default_alloc */ static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc) { - (void) abstract; + (void)abstract; return malloc(count); } @@ -72,7 +82,7 @@ LIBSSH2_ALLOC_FUNC(libssh2_default_alloc) static LIBSSH2_FREE_FUNC(libssh2_default_free) { - (void) abstract; + (void)abstract; free(ptr); } @@ -81,7 +91,7 @@ LIBSSH2_FREE_FUNC(libssh2_default_free) static LIBSSH2_REALLOC_FUNC(libssh2_default_realloc) { - (void) abstract; + (void)abstract; return realloc(ptr, count); } @@ -96,8 +106,8 @@ LIBSSH2_REALLOC_FUNC(libssh2_default_realloc) static int banner_receive(LIBSSH2_SESSION * session) { - int ret; - int banner_len; + ssize_t ret; + size_t banner_len; if(session->banner_TxRx_state == libssh2_NB_state_idle) { banner_len = 0; @@ -108,25 +118,25 @@ banner_receive(LIBSSH2_SESSION * session) banner_len = session->banner_TxRx_total_send; } - while((banner_len < (int) sizeof(session->banner_TxRx_banner)) && - ((banner_len == 0) - || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) { + while((banner_len < sizeof(session->banner_TxRx_banner)) && + ((banner_len == 0) + || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) { char c = '\0'; /* no incoming block yet! */ session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; ret = LIBSSH2_RECV(session, &c, 1, - LIBSSH2_SOCKET_RECV_FLAGS(session)); + LIBSSH2_SOCKET_RECV_FLAGS(session)); if(ret < 0) { if(session->api_block_mode || (ret != -EAGAIN)) /* ignore EAGAIN when non-blocking */ - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error recving %d bytes: %d", 1, -ret); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error recving %d bytes: %d", 1, (int)-ret)); } else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Recved %d bytes banner", ret); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Recved %d bytes banner", (int)ret)); if(ret < 0) { if(ret == -EAGAIN) { @@ -147,6 +157,10 @@ banner_receive(LIBSSH2_SESSION * session) return LIBSSH2_ERROR_SOCKET_DISCONNECT; } + if((c == '\r' || c == '\n') && banner_len == 0) { + continue; + } + if(c == '\0') { /* NULLs are not allowed in SSH banners */ session->banner_TxRx_state = libssh2_NB_state_idle; @@ -158,8 +172,8 @@ banner_receive(LIBSSH2_SESSION * session) } while(banner_len && - ((session->banner_TxRx_banner[banner_len - 1] == '\n') || - (session->banner_TxRx_banner[banner_len - 1] == '\r'))) { + ((session->banner_TxRx_banner[banner_len - 1] == '\n') || + (session->banner_TxRx_banner[banner_len - 1] == '\r'))) { banner_len--; } @@ -180,8 +194,8 @@ banner_receive(LIBSSH2_SESSION * session) } memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len); session->remote.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Received Banner: %s", - session->remote.banner); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Received Banner: %s", + session->remote.banner)); return LIBSSH2_ERROR_NONE; } @@ -199,11 +213,8 @@ static int banner_send(LIBSSH2_SESSION * session) { char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF; - int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1; + size_t banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1; ssize_t ret; -#ifdef LIBSSH2DEBUG - char banner_dup[256]; -#endif if(session->banner_TxRx_state == libssh2_NB_state_idle) { if(session->local.banner) { @@ -212,18 +223,22 @@ banner_send(LIBSSH2_SESSION * session) banner = (char *) session->local.banner; } #ifdef LIBSSH2DEBUG - /* Hack and slash to avoid sending CRLF in debug output */ - if(banner_len < 256) { - memcpy(banner_dup, banner, banner_len - 2); - banner_dup[banner_len - 2] = '\0'; - } - else { - memcpy(banner_dup, banner, 255); - banner[255] = '\0'; - } + { + char banner_dup[256]; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s", - banner_dup); + /* Hack and slash to avoid sending CRLF in debug output */ + if(banner_len < 256) { + memcpy(banner_dup, banner, banner_len - 2); + banner_dup[banner_len - 2] = '\0'; + } + else { + memcpy(banner_dup, banner, 255); + banner_dup[255] = '\0'; + } + + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Sending Banner: %s", banner_dup)); + } #endif session->banner_TxRx_state = libssh2_NB_state_created; @@ -233,20 +248,20 @@ banner_send(LIBSSH2_SESSION * session) session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; ret = LIBSSH2_SEND(session, - banner + session->banner_TxRx_total_send, - banner_len - session->banner_TxRx_total_send, - LIBSSH2_SOCKET_SEND_FLAGS(session)); + banner + session->banner_TxRx_total_send, + banner_len - session->banner_TxRx_total_send, + LIBSSH2_SOCKET_SEND_FLAGS(session)); if(ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, "Error sending %d bytes: %d", - banner_len - session->banner_TxRx_total_send, -ret); + banner_len - session->banner_TxRx_total_send, -ret)); else - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p+%d", ret, banner_len - session->banner_TxRx_total_send, - banner, session->banner_TxRx_total_send); + banner, session->banner_TxRx_total_send)); - if(ret != (banner_len - session->banner_TxRx_total_send)) { + if(ret != (ssize_t)(banner_len - session->banner_TxRx_total_send)) { if(ret >= 0 || ret == -EAGAIN) { /* the whole packet could not be sent, save the what was */ session->socket_block_directions = @@ -276,8 +291,6 @@ static int session_nonblock(libssh2_socket_t sockfd, /* operate on this */ int nonblock /* TRUE or FALSE */ ) { -#undef SETBLOCK -#define SETBLOCK 0 #ifdef HAVE_O_NONBLOCK /* most recent unix versions */ int flags; @@ -287,66 +300,39 @@ session_nonblock(libssh2_socket_t sockfd, /* operate on this */ return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); else return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); -#undef SETBLOCK -#define SETBLOCK 1 -#endif - -#if defined(HAVE_FIONBIO) && (SETBLOCK == 0) - /* older unix versions and VMS*/ +#elif defined(HAVE_FIONBIO) + /* older unix versions and VMS */ int flags; flags = nonblock; return ioctl(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 2 -#endif - -#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0) - /* Windows? */ - unsigned long flags; - flags = nonblock; - - return ioctlsocket(sockfd, FIONBIO, &flags); -#undef SETBLOCK -#define SETBLOCK 3 -#endif - -#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0) +#elif defined(HAVE_IOCTLSOCKET_CASE) /* presumably for Amiga */ return IoctlSocket(sockfd, FIONBIO, (long) nonblock); -#undef SETBLOCK -#define SETBLOCK 4 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0) +#elif defined(HAVE_SO_NONBLOCK) /* BeOS */ long b = nonblock ? 1 : 0; return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); -#undef SETBLOCK -#define SETBLOCK 5 -#endif +#elif defined(WIN32) + unsigned long flags; -#ifdef HAVE_DISABLED_NONBLOCKING + flags = nonblock; + return ioctlsocket(sockfd, FIONBIO, &flags); +#else + (void)sockfd; + (void)nonblock; return 0; /* returns success */ -#undef SETBLOCK -#define SETBLOCK 6 -#endif - -#if(SETBLOCK == 0) -#error "no non-blocking method was found/used/set" #endif } /* - * get_socket_nonblocking() + * get_socket_nonblocking * * gets the given blocking or non-blocking state of the socket. */ static int -get_socket_nonblocking(int sockfd) +get_socket_nonblocking(libssh2_socket_t sockfd) { /* operate on this */ -#undef GETBLOCK -#define GETBLOCK 0 #ifdef HAVE_O_NONBLOCK /* most recent unix versions */ int flags = fcntl(sockfd, F_GETFL, 0); @@ -356,26 +342,7 @@ get_socket_nonblocking(int sockfd) return 1; } return (flags & O_NONBLOCK); -#undef GETBLOCK -#define GETBLOCK 1 -#endif - -#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0) - /* Windows? */ - unsigned int option_value; - socklen_t option_len = sizeof(option_value); - - if(getsockopt - (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) { - /* Assume blocking on error */ - return 1; - } - return (int) option_value; -#undef GETBLOCK -#define GETBLOCK 2 -#endif - -#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0) +#elif defined(HAVE_SO_NONBLOCK) /* BeOS */ long b; if(getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) { @@ -383,12 +350,7 @@ get_socket_nonblocking(int sockfd) return 1; } return (int) b; -#undef GETBLOCK -#define GETBLOCK 5 -#endif - -#if defined(SO_STATE) && defined(__VMS) && (GETBLOCK == 0) - +#elif defined(SO_STATE) && defined(__VMS) /* VMS TCP/IP Services */ size_t sockstat = 0; @@ -396,23 +358,27 @@ get_socket_nonblocking(int sockfd) size_t size = sizeof(int); callstat = getsockopt(sockfd, SOL_SOCKET, SO_STATE, - (char *)&sockstat, &size); - if(callstat == -1) return 0; - if((sockstat&SS_NBIO) != 0) return 1; + (char *)&sockstat, &size); + if(callstat == -1) { + return 0; + } + if((sockstat&SS_NBIO) != 0) { + return 1; + } return 0; +#elif defined(WIN32) + unsigned int option_value; + socklen_t option_len = sizeof(option_value); -#undef GETBLOCK -#define GETBLOCK 6 -#endif - -#ifdef HAVE_DISABLED_NONBLOCKING + if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, + (void *) &option_value, &option_len)) { + /* Assume blocking on error */ + return 1; + } + return (int) option_value; +#else + (void)sockfd; return 1; /* returns blocking */ -#undef GETBLOCK -#define GETBLOCK 7 -#endif - -#if(GETBLOCK == 0) -#error "no non-blocking method was found/used/get" #endif } @@ -442,8 +408,8 @@ libssh2_session_banner_set(LIBSSH2_SESSION * session, const char *banner) /* first zero terminate like this so that the debug output is nice */ session->local.banner[banner_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s", - session->local.banner); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s", + session->local.banner)); session->local.banner[banner_len++] = '\r'; session->local.banner[banner_len++] = '\n'; session->local.banner[banner_len] = '\0'; @@ -500,8 +466,11 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), session->abstract = abstract; session->api_timeout = 0; /* timeout-free API by default */ session->api_block_mode = 1; /* blocking API by default */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "New session resource allocated"); + session->packet_read_timeout = LIBSSH2_DEFAULT_READ_TIMEOUT; + session->flag.quote_paths = 1; /* default behavior is to quote paths + for the scp subsystem */ + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "New session resource allocated")); _libssh2_init_if_needed(); } return session; @@ -516,8 +485,14 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), * ALERT: this function relies on that we can typecast function pointers * to void pointers, which isn't allowed in ISO C! */ +#ifdef _MSC_VER +#pragma warning(push) +/* nonstandard extension, function/data pointer conversion in expression */ +#pragma warning(disable:4152) +#else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" +#endif LIBSSH2_API void * libssh2_session_callback_set(LIBSSH2_SESSION * session, int cbtype, void *callback) @@ -559,16 +534,35 @@ libssh2_session_callback_set(LIBSSH2_SESSION * session, oldcb = session->recv; session->recv = callback; return oldcb; + + case LIBSSH2_CALLBACK_AUTHAGENT: + oldcb = session->authagent; + session->authagent = callback; + return oldcb; + + case LIBSSH2_CALLBACK_AUTHAGENT_IDENTITIES: + oldcb = session->addLocalIdentities; + session->addLocalIdentities = callback; + return oldcb; + + case LIBSSH2_CALLBACK_AUTHAGENT_SIGN: + oldcb = session->agentSignCallback; + session->agentSignCallback = callback; + return oldcb; } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", - cbtype); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", + cbtype)); return NULL; } +#ifdef _MSC_VER +#pragma warning(pop) +#else #pragma GCC diagnostic pop +#endif /* - * _libssh2_wait_socket() + * _libssh2_wait_socket * * Utility function that waits for action on the socket. Returns 0 when ready * to run again or error on timeout. @@ -589,7 +583,7 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) session->err_code = LIBSSH2_ERROR_NONE; rc = libssh2_keepalive_send(session, &seconds_to_next); - if(rc < 0) + if(rc) return rc; ms_to_next = seconds_to_next * 1000; @@ -598,8 +592,8 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) dir = libssh2_session_block_directions(session); if(!dir) { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Nothing to wait for in wait_socket"); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Nothing to wait for in wait_socket")); /* To avoid that we hang below just because there's nothing set to wait for, we timeout on 1 second to also avoid busy-looping during this condition */ @@ -638,7 +632,7 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) sockets[0].events |= POLLOUT; - rc = poll(sockets, 1, has_timeout?ms_to_next: -1); + rc = poll(sockets, 1, has_timeout ? (int)ms_to_next : -1); } #else { @@ -649,7 +643,11 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) struct timeval tv; tv.tv_sec = ms_to_next / 1000; +#ifdef libssh2_usec_t + tv.tv_usec = (libssh2_usec_t)((ms_to_next - tv.tv_sec*1000) * 1000); +#else tv.tv_usec = (ms_to_next - tv.tv_sec*1000) * 1000; +#endif if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) { FD_ZERO(&rfd); @@ -663,7 +661,7 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) writefd = &wfd; } - rc = select(session->socket_fd + 1, readfd, writefd, NULL, + rc = select((int)(session->socket_fd + 1), readfd, writefd, NULL, has_timeout ? &tv : NULL); } #endif @@ -685,8 +683,8 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) int rc; if(session->startup_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "session_startup for socket %d", sock); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "session_startup for socket %d", sock)); if(LIBSSH2_INVALID_SOCKET == sock) { /* Did we forget something? */ return _libssh2_error(session, LIBSSH2_ERROR_BAD_SOCKET, @@ -730,7 +728,7 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) else if(rc) return _libssh2_error(session, rc, "Failed getting banner"); - } while(strncmp("SSH-", (char *)session->remote.banner, 4)); + } while(strncmp("SSH-", (const char *)session->remote.banner, 4)); session->startup_state = libssh2_NB_state_sent1; } @@ -747,8 +745,8 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) } if(session->startup_state == libssh2_NB_state_sent2) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Requesting userauth service"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Requesting userauth service")); /* Request the userauth service */ session->startup_service[0] = SSH_MSG_SERVICE_REQUEST; @@ -780,7 +778,9 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) &session->startup_data_len, 0, NULL, 0, &session->startup_req_state); if(rc) - return rc; + return _libssh2_error(session, rc, + "Failed to get response to " + "ssh-userauth request"); if(session->startup_data_len < 5) { return _libssh2_error(session, LIBSSH2_ERROR_PROTO, @@ -792,7 +792,8 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) if((session->startup_service_length != (sizeof("ssh-userauth") - 1)) - || strncmp("ssh-userauth", (char *) session->startup_data + 5, + || strncmp("ssh-userauth", + (const char *) session->startup_data + 5, session->startup_service_length)) { LIBSSH2_FREE(session, session->startup_data); session->startup_data = NULL; @@ -812,7 +813,7 @@ session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) } /* - * libssh2_session_handshake() + * libssh2_session_handshake * * session: LIBSSH2_SESSION struct allocated and owned by the calling program * sock: *must* be populated with an opened and connected socket. @@ -824,13 +825,13 @@ libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t sock) { int rc; - BLOCK_ADJUST(rc, session, session_startup(session, sock) ); + BLOCK_ADJUST(rc, session, session_startup(session, sock)); return rc; } /* - * libssh2_session_startup() + * libssh2_session_startup * * DEPRECATED. Use libssh2_session_handshake() instead! This function is not * portable enough. @@ -847,7 +848,7 @@ libssh2_session_startup(LIBSSH2_SESSION *session, int sock) } /* - * libssh2_session_free + * session_free * * Frees the memory allocated to the session * Also closes and frees any channels attached to this session @@ -862,16 +863,16 @@ session_free(LIBSSH2_SESSION *session) int packets_left = 0; if(session->free_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Freeing session resource", - session->remote.banner); + session->remote.banner)); session->free_state = libssh2_NB_state_created; } if(session->free_state == libssh2_NB_state_created) { - while((ch = _libssh2_list_first(&session->channels))) { - + /* !checksrc! disable EQUALSNULL 1 */ + while((ch = _libssh2_list_first(&session->channels)) != NULL) { rc = _libssh2_channel_free(ch); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -881,7 +882,8 @@ session_free(LIBSSH2_SESSION *session) } if(session->free_state == libssh2_NB_state_sent) { - while((l = _libssh2_list_first(&session->listeners))) { + /* !checksrc! disable EQUALSNULL 1 */ + while((l = _libssh2_list_first(&session->listeners)) != NULL) { rc = _libssh2_channel_forward_cancel(l); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -981,6 +983,12 @@ session_free(LIBSSH2_SESSION *session) if(session->remote.lang_prefs) { LIBSSH2_FREE(session, session->remote.lang_prefs); } + if(session->server_sign_algorithms) { + LIBSSH2_FREE(session, session->server_sign_algorithms); + } + if(session->sign_algo_prefs) { + LIBSSH2_FREE(session, session->sign_algo_prefs); + } /* * Make sure all memory used in the state variables are free @@ -994,6 +1002,9 @@ session_free(LIBSSH2_SESSION *session) if(session->userauth_list_data) { LIBSSH2_FREE(session, session->userauth_list_data); } + if(session->userauth_banner) { + LIBSSH2_FREE(session, session->userauth_banner); + } if(session->userauth_pswd_data) { LIBSSH2_FREE(session, session->userauth_pswd_data); } @@ -1058,10 +1069,11 @@ session_free(LIBSSH2_SESSION *session) } /* Cleanup all remaining packets */ - while((pkg = _libssh2_list_first(&session->packets))) { + /* !checksrc! disable EQUALSNULL 1 */ + while((pkg = _libssh2_list_first(&session->packets)) != NULL) { packets_left++; - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "packet left with id %d", pkg->data[0]); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "packet left with id %d", pkg->data[0])); /* unlink the node */ _libssh2_list_remove(&pkg->node); @@ -1069,15 +1081,16 @@ session_free(LIBSSH2_SESSION *session) LIBSSH2_FREE(session, pkg->data); LIBSSH2_FREE(session, pkg); } - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "Extra packets left %d", packets_left); + (void)packets_left; + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "Extra packets left %d", packets_left)); if(session->socket_prev_blockstate) { /* if the socket was previously blocking, put it back so */ rc = session_nonblock(session->socket_fd, 0); if(rc) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, - "unable to reset socket's blocking state"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, + "unable to reset socket's blocking state")); } } @@ -1107,13 +1120,13 @@ libssh2_session_free(LIBSSH2_SESSION * session) { int rc; - BLOCK_ADJUST(rc, session, session_free(session) ); + BLOCK_ADJUST(rc, session, session_free(session)); return rc; } /* - * libssh2_session_disconnect_ex + * session_disconnect */ static int session_disconnect(LIBSSH2_SESSION *session, int reason, @@ -1121,13 +1134,13 @@ session_disconnect(LIBSSH2_SESSION *session, int reason, const char *lang) { unsigned char *s; - unsigned long descr_len = 0, lang_len = 0; + size_t descr_len = 0, lang_len = 0; int rc; if(session->disconnect_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, - description, lang); + description, lang)); if(description) descr_len = strlen(description); @@ -1138,6 +1151,10 @@ session_disconnect(LIBSSH2_SESSION *session, int reason, return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "too long description"); + if(lang_len > 256) + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "too long language string"); + /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */ session->disconnect_data_len = descr_len + lang_len + 13; @@ -1147,14 +1164,14 @@ session_disconnect(LIBSSH2_SESSION *session, int reason, _libssh2_store_u32(&s, reason); _libssh2_store_str(&s, description, descr_len); /* store length only, lang is sent separately */ - _libssh2_store_u32(&s, lang_len); + _libssh2_store_u32(&s, (uint32_t)lang_len); session->disconnect_state = libssh2_NB_state_created; } rc = _libssh2_transport_send(session, session->disconnect_data, session->disconnect_data_len, - (unsigned char *)lang, lang_len); + (const unsigned char *)lang, lang_len); if(rc == LIBSSH2_ERROR_EAGAIN) return rc; @@ -1303,7 +1320,7 @@ libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg, } if(errmsg_len) { - *errmsg_len = msglen; + *errmsg_len = (int)msglen; } return session->err_code; @@ -1336,7 +1353,7 @@ libssh2_session_set_last_error(LIBSSH2_SESSION* session, LIBSSH2_ERR_FLAG_DUP); } -/* Libssh2_session_flag +/* libssh2_session_flag * * Set/Get session flags * @@ -1352,6 +1369,9 @@ libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value) case LIBSSH2_FLAG_COMPRESS: session->flag.compress = value; break; + case LIBSSH2_FLAG_QUOTE_PATHS: + session->flag.quote_paths = value; + break; default: /* unknown flag */ return LIBSSH2_ERROR_INVAL; @@ -1370,8 +1390,8 @@ int _libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking) { int bl = session->api_block_mode; - _libssh2_debug(session, LIBSSH2_TRACE_CONN, - "Setting blocking mode %s", blocking?"ON":"OFF"); + _libssh2_debug((session, LIBSSH2_TRACE_CONN, + "Setting blocking mode %s", blocking ? "ON" : "OFF")); session->api_block_mode = blocking; return bl; @@ -1385,7 +1405,7 @@ _libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking) LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking) { - (void) _libssh2_session_set_blocking(session, blocking); + (void)_libssh2_session_set_blocking(session, blocking); } /* libssh2_session_get_blocking @@ -1420,6 +1440,30 @@ libssh2_session_get_timeout(LIBSSH2_SESSION * session) return session->api_timeout; } +/* libssh2_session_set_read_timeout + * + * Set a session's timeout (in sec) when reading packets, + * or 0 to use default of 60 seconds. + */ +LIBSSH2_API void +libssh2_session_set_read_timeout(LIBSSH2_SESSION * session, long timeout) +{ + if(timeout <= 0) { + timeout = LIBSSH2_DEFAULT_READ_TIMEOUT; + } + session->packet_read_timeout = timeout; +} + +/* libssh2_session_get_read_timeout + * + * Returns a session's timeout. Default is 60 seconds. + */ +LIBSSH2_API long +libssh2_session_get_read_timeout(LIBSSH2_SESSION * session) +{ + return session->packet_read_timeout; +} + /* * libssh2_poll_channel_read * @@ -1513,7 +1557,7 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) switch(fds[i].type) { case LIBSSH2_POLLFD_SOCKET: sockets[i].fd = fds[i].fd.socket; - sockets[i].events = fds[i].events; + sockets[i].events = (short)fds[i].events; sockets[i].revents = 0; break; @@ -1675,23 +1719,15 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) } #ifdef HAVE_POLL -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY { struct timeval tv_begin, tv_end; - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = poll(sockets, nfds, timeout_remaining); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); + gettimeofday(&tv_begin, NULL); + sysret = poll(sockets, nfds, (int)timeout_remaining); + gettimeofday(&tv_end, NULL); timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = poll(sockets, nfds, timeout_remaining); - timeout_remaining = 0; -#endif /* HAVE_GETTIMEOFDAY */ if(sysret > 0) { for(i = 0; i < nfds; i++) { @@ -1738,24 +1774,17 @@ libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) #elif defined(HAVE_SELECT) tv.tv_sec = timeout_remaining / 1000; tv.tv_usec = (timeout_remaining % 1000) * 1000; -#ifdef HAVE_LIBSSH2_GETTIMEOFDAY + { struct timeval tv_begin, tv_end; - _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); - sysret = select(maxfd + 1, &rfds, &wfds, NULL, &tv); - _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); + gettimeofday(&tv_begin, NULL); + sysret = select((int)(maxfd + 1), &rfds, &wfds, NULL, &tv); + gettimeofday(&tv_end, NULL); timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; } -#else - /* If the platform doesn't support gettimeofday, - * then just make the call non-blocking and walk away - */ - sysret = select(maxfd + 1, &rfds, &wfds, NULL, &tv); - timeout_remaining = 0; -#endif if(sysret > 0) { for(i = 0; i < nfds; i++) { @@ -1822,10 +1851,10 @@ LIBSSH2_API const char * libssh2_session_banner_get(LIBSSH2_SESSION *session) { /* to avoid a coredump when session is NULL */ - if(NULL == session) + if(!session) return NULL; - if(NULL == session->remote.banner) + if(!session->remote.banner) return NULL; return (const char *) session->remote.banner; diff --git a/libs/libssh2/src/session.h b/libs/libssh2/src/session.h index 7b6c291e27..bfc9b545b8 100644 --- a/libs/libssh2/src/session.h +++ b/libs/libssh2/src/session.h @@ -1,8 +1,8 @@ -#ifndef LIBSSH2_SESSION_H -#define LIBSSH2_SESSION_H -/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2009-2010 by Daniel Stenberg - * Copyright (c) 2010 Simon Josefsson <simon@josefsson.org> +#ifndef __LIBSSH2_SESSION_H +#define __LIBSSH2_SESSION_H +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg + * Copyright (C) Simon Josefsson <simon@josefsson.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -37,31 +37,32 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ /* Conveniance-macros to allow code like this; - int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) ); + int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock)); - int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) ); + int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock)); - The point of course being to make sure that while in non-blocking mode - these always return no matter what the return code is, but in blocking mode - it blocks if EAGAIN is the reason for the return from the underlying - function. + The point being to make sure that while in non-blocking mode these always + return no matter what the return code is, but in blocking mode it blocks + if EAGAIN is the reason for the return from the underlying function. */ #define BLOCK_ADJUST(rc, sess, x) \ do { \ - time_t entry_time = time(NULL); \ - do { \ - rc = x; \ - /* the order of the check below is important to properly deal with \ - the case when the 'sess' is freed */ \ - if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ - } while(!rc); \ + time_t entry_time = time(NULL); \ + do { \ + rc = x; \ + /* the order of the check below is important to properly \ + deal with the case when the 'sess' is freed */ \ + if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \ + break; \ + rc = _libssh2_wait_socket(sess, entry_time); \ + } while(!rc); \ } while(0) /* @@ -72,15 +73,15 @@ */ #define BLOCK_ADJUST_ERRNO(ptr, sess, x) \ do { \ - time_t entry_time = time(NULL); \ - int rc; \ - do { \ - ptr = x; \ - if(!sess->api_block_mode || \ - (ptr != NULL) || \ - (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN) ) \ - break; \ - rc = _libssh2_wait_socket(sess, entry_time); \ + time_t entry_time = time(NULL); \ + int rc; \ + do { \ + ptr = x; \ + if(!sess->api_block_mode || \ + (ptr != NULL) || \ + (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN)) \ + break; \ + rc = _libssh2_wait_socket(sess, entry_time); \ } while(!rc); \ } while(0) @@ -90,4 +91,4 @@ int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time); /* this is the lib-internal set blocking function */ int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking); -#endif /* LIBSSH2_SESSION_H */ +#endif /* __LIBSSH2_SESSION_H */ diff --git a/libs/libssh2/src/sftp.c b/libs/libssh2/src/sftp.c index ece590e51f..16ee7b8689 100644 --- a/libs/libssh2/src/sftp.c +++ b/libs/libssh2/src/sftp.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2007 Eli Fant <elifantu@mail.ru> - * Copyright (c) 2009-2019 by Daniel Stenberg +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Eli Fant <elifantu@mail.ru> + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,21 +35,25 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ -#include <assert.h> - #include "libssh2_priv.h" #include "libssh2_sftp.h" + #include "channel.h" #include "session.h" #include "sftp.h" -/* Note: Version 6 was documented at the time of writing - * However it was marked as "DO NOT IMPLEMENT" due to pending changes - * - * This release of libssh2 implements Version 5 with automatic downgrade +#include <assert.h> + +/* This release of libssh2 implements Version 5 with automatic downgrade * based on server's declaration + * https://www.ietf.org/archive/id/draft-ietf-secsh-filexfer-05.txt + * + * Version 6: + * https://www.ietf.org/archive/id/draft-ietf-secsh-filexfer-13.txt */ /* SFTP packet types */ @@ -98,19 +102,6 @@ static int sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, size_t *data_len); static void sftp_packet_flush(LIBSSH2_SFTP *sftp); -/* sftp_attrsize - * Size that attr with this flagset will occupy when turned into a bin struct - */ -static int sftp_attrsize(unsigned long flags) -{ - return (4 + /* flags(4) */ - ((flags & LIBSSH2_SFTP_ATTR_SIZE) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_UIDGID) ? 8 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) ? 4 : 0) + - ((flags & LIBSSH2_SFTP_ATTR_ACMODTIME) ? 8 : 0)); - /* atime + mtime as u32 */ -} - /* _libssh2_store_u64 */ static void _libssh2_store_u64(unsigned char **ptr, libssh2_uint64_t value) @@ -120,12 +111,12 @@ static void _libssh2_store_u64(unsigned char **ptr, libssh2_uint64_t value) buf[0] = (unsigned char)((msl >> 24) & 0xFF); buf[1] = (unsigned char)((msl >> 16) & 0xFF); - buf[2] = (unsigned char)((msl >> 8) & 0xFF); + buf[2] = (unsigned char)((msl >> 8) & 0xFF); buf[3] = (unsigned char)( msl & 0xFF); buf[4] = (unsigned char)((value >> 24) & 0xFF); buf[5] = (unsigned char)((value >> 16) & 0xFF); - buf[6] = (unsigned char)((value >> 8) & 0xFF); + buf[6] = (unsigned char)((value >> 8) & 0xFF); buf[7] = (unsigned char)( value & 0xFF); *ptr += 8; @@ -160,10 +151,10 @@ remove_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) struct sftp_zombie_requests *zombie = find_zombie_request(sftp, request_id); if(zombie) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Removing request ID %ld from the list of " "zombie requests", - request_id); + request_id)); _libssh2_list_remove(&zombie->node); LIBSSH2_FREE(session, zombie); @@ -177,8 +168,8 @@ add_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) struct sftp_zombie_requests *zombie; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Marking request ID %ld as a zombie request", request_id); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Marking request ID %ld as a zombie request", request_id)); zombie = LIBSSH2_ALLOC(sftp->channel->session, sizeof(struct sftp_zombie_requests)); @@ -192,9 +183,7 @@ add_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) } } -/* - * sftp_packet_add - * +/* sftp_packet_add * Add a packet to the SFTP packet brigade */ static int @@ -209,9 +198,9 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Received packet type %d (len %d)", - (int) data[0], data_len); + (int) data[0], data_len)); /* * Experience shows that if we mess up EAGAIN handling somewhere or @@ -250,14 +239,15 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, case SSH_FXP_EXTENDED_REPLY: break; default: + sftp->last_errno = LIBSSH2_FX_OK; return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Out of sync with the world"); } request_id = _libssh2_ntohu32(&data[1]); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Received packet id %d", - request_id); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Received packet id %d", + request_id)); /* Don't add the packet if it answers a request we've given up on. */ if((data[0] == SSH_FXP_STATUS || data[0] == SSH_FXP_DATA) @@ -287,9 +277,7 @@ sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, return LIBSSH2_ERROR_NONE; } -/* - * sftp_packet_read - * +/* sftp_packet_read * Frame an SFTP packet off the channel */ static int @@ -301,8 +289,9 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) ssize_t rc; unsigned long recv_window; int packet_type; + uint32_t request_id; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "recv packet"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "recv packet")); switch(sftp->packet_state) { case libssh2_NB_state_sent: /* EAGAIN from window adjusting */ @@ -316,11 +305,11 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) packet = sftp->partial_packet; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "partial read cont, len: %lu", sftp->partial_len); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "partial read cont, len: %lu", sftp->partial_len)); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "partial read cont, already recvd: %lu", - sftp->partial_received); + sftp->partial_received)); /* fall-through */ default: if(!packet) { @@ -329,49 +318,59 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) /* each packet starts with a 32 bit length field */ rc = _libssh2_channel_read(channel, 0, - (char *)&sftp->partial_size[ - sftp->partial_size_len], - 4 - sftp->partial_size_len); + (char *)&sftp->packet_header[ + sftp->packet_header_len], + sizeof(sftp->packet_header) - + sftp->packet_header_len); if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; else if(rc < 0) - return _libssh2_error(session, rc, "channel read"); + return _libssh2_error(session, (int)rc, "channel read"); - sftp->partial_size_len += rc; + sftp->packet_header_len += rc; - if(4 != sftp->partial_size_len) - /* we got a short read for the length part */ + if(sftp->packet_header_len != sizeof(sftp->packet_header)) + /* we got a short read for the header part */ return LIBSSH2_ERROR_EAGAIN; - sftp->partial_len = _libssh2_ntohu32(sftp->partial_size); + /* parse SFTP packet header */ + sftp->partial_len = _libssh2_ntohu32(sftp->packet_header); + packet_type = sftp->packet_header[4]; + request_id = _libssh2_ntohu32(sftp->packet_header + 5); + /* make sure we don't proceed if the packet size is unreasonably large */ - if(sftp->partial_len > LIBSSH2_SFTP_PACKET_MAXLEN) { + if(sftp->partial_len > LIBSSH2_SFTP_PACKET_MAXLEN && + /* exception: response to SSH_FXP_READDIR request */ + !(sftp->readdir_state != libssh2_NB_state_idle && + sftp->readdir_request_id == request_id && + packet_type == SSH_FXP_NAME)) { libssh2_channel_flush(channel); - sftp->partial_size_len = 0; + sftp->packet_header_len = 0; return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "SFTP packet too large"); } - if(sftp->partial_len == 0) + if(sftp->partial_len < 5) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate empty SFTP packet"); + "Invalid SFTP packet size"); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Data begin - Packet Length: %lu", - sftp->partial_len); + sftp->partial_len)); packet = LIBSSH2_ALLOC(session, sftp->partial_len); if(!packet) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate SFTP packet"); - sftp->partial_size_len = 0; - sftp->partial_received = 0; /* how much of the packet already - received */ + sftp->packet_header_len = 0; sftp->partial_packet = packet; + /* copy over packet type(4) and request id(1) */ + sftp->partial_received = 5; + memcpy(packet, sftp->packet_header + 4, 5); - window_adjust: +window_adjust: recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); if(sftp->partial_len > recv_window) { @@ -387,7 +386,7 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) libssh2_NB_state_idle; if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; } } @@ -405,12 +404,12 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) * knows how to continue on the next invoke. */ sftp->packet_state = libssh2_NB_state_sent1; - return rc; + return (int)rc; } else if(rc < 0) { LIBSSH2_FREE(session, packet); sftp->partial_packet = NULL; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for SFTP packet"); } sftp->partial_received += rc; @@ -424,7 +423,7 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) rc = sftp_packet_add(sftp, packet, sftp->partial_len); if(rc) { LIBSSH2_FREE(session, packet); - return rc; + return (int)rc; } else { return packet_type; @@ -432,8 +431,8 @@ sftp_packet_read(LIBSSH2_SFTP *sftp) } /* WON'T REACH */ } -/* - * sftp_packetlist_flush + +/* sftp_packetlist_flush * * Remove all pending packets in the packet_list and the corresponding one(s) * in the SFTP packet brigade. @@ -474,7 +473,7 @@ static void sftp_packetlist_flush(LIBSSH2_SFTP_HANDLE *handle) /* - * sftp_packet_ask() + * sftp_packet_ask * * Checks if there's a matching SFTP packet available. */ @@ -523,19 +522,19 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type, LIBSSH2_SESSION *session = sftp->channel->session; int rc; - if(data == NULL || data_len == NULL || required_size == 0) { + if(!data || !data_len || required_size == 0) { return LIBSSH2_ERROR_BAD_USE; } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld", - (int) packet_type, request_id); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld", + (int) packet_type, request_id)); if(sftp_packet_ask(sftp, packet_type, request_id, data, data_len) == 0) { /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Got %d", + (int) packet_type)); - if (*data_len < required_size) { + if(*data_len < required_size) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } @@ -550,10 +549,10 @@ sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type, /* data was read, check the queue again */ if(!sftp_packet_ask(sftp, packet_type, request_id, data, data_len)) { /* The right packet was available in the packet brigade */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", - (int) packet_type); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Got %d", + (int) packet_type)); - if (*data_len < required_size) { + if(*data_len < required_size) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } @@ -577,7 +576,7 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, int i; int rc; - if(data == NULL || data_len == NULL || required_size == 0) { + if(!data || !data_len || required_size == 0) { return LIBSSH2_ERROR_BAD_USE; } @@ -588,14 +587,14 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, while(sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) { for(i = 0; i < num_valid_responses; i++) { if(sftp_packet_ask(sftp, valid_responses[i], request_id, - data, data_len) == 0) { + data, data_len) == 0) { /* * Set to zero before all returns to say * the timeout is not active */ sftp->requirev_start = 0; - if (*data_len < required_size) { + if(*data_len < required_size) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } @@ -611,7 +610,7 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, else if(rc <= 0) { /* prevent busy-looping */ long left = - LIBSSH2_READ_TIMEOUT - + sftp->channel->session->packet_read_timeout - (long)(time(NULL) - sftp->requirev_start); if(left <= 0) { @@ -630,6 +629,19 @@ sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, return LIBSSH2_ERROR_SOCKET_DISCONNECT; } +/* sftp_attrsize + * Size that attr with this flagset will occupy when turned into a bin struct + */ +static int sftp_attrsize(unsigned long flags) +{ + return 4 + /* flags(4) */ + ((flags & LIBSSH2_SFTP_ATTR_SIZE) ? 8 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_UIDGID) ? 8 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) ? 4 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_ACMODTIME) ? 8 : 0); + /* atime + mtime as u32 */ +} + /* sftp_attr2bin * Populate attributes into an SFTP block */ @@ -638,8 +650,10 @@ sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs) { unsigned char *s = p; uint32_t flag_mask = - LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID | - LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME; + LIBSSH2_SFTP_ATTR_SIZE | + LIBSSH2_SFTP_ATTR_UIDGID | + LIBSSH2_SFTP_ATTR_PERMISSIONS | + LIBSSH2_SFTP_ATTR_ACMODTIME; /* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */ @@ -649,32 +663,32 @@ sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs) return 4; } - _libssh2_store_u32(&s, attrs->flags & flag_mask); + _libssh2_store_u32(&s, (uint32_t)(attrs->flags & flag_mask)); if(attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { _libssh2_store_u64(&s, attrs->filesize); } if(attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { - _libssh2_store_u32(&s, attrs->uid); - _libssh2_store_u32(&s, attrs->gid); + _libssh2_store_u32(&s, (uint32_t)attrs->uid); + _libssh2_store_u32(&s, (uint32_t)attrs->gid); } if(attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - _libssh2_store_u32(&s, attrs->permissions); + _libssh2_store_u32(&s, (uint32_t)attrs->permissions); } if(attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { - _libssh2_store_u32(&s, attrs->atime); - _libssh2_store_u32(&s, attrs->mtime); + _libssh2_store_u32(&s, (uint32_t)attrs->atime); + _libssh2_store_u32(&s, (uint32_t)attrs->mtime); } - return (s - p); + return s - p; } /* sftp_bin2attr */ -static int +static ssize_t sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, size_t data_len) { @@ -684,13 +698,13 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, buf.dataptr = buf.data; buf.len = data_len; - if(_libssh2_get_u32(&buf, &flags) != 0) { + if(_libssh2_get_u32(&buf, &flags)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->flags = flags; if(attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { - if(_libssh2_get_u64(&buf, &(attrs->filesize)) != 0) { + if(_libssh2_get_u64(&buf, &(attrs->filesize))) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } } @@ -698,8 +712,8 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, if(attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { uint32_t uid = 0; uint32_t gid = 0; - if(_libssh2_get_u32(&buf, &uid) != 0 || - _libssh2_get_u32(&buf, &gid) != 0) { + if(_libssh2_get_u32(&buf, &uid) || + _libssh2_get_u32(&buf, &gid)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->uid = uid; @@ -708,7 +722,7 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, if(attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { uint32_t permissions; - if(_libssh2_get_u32(&buf, &permissions) != 0) { + if(_libssh2_get_u32(&buf, &permissions)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->permissions = permissions; @@ -717,15 +731,36 @@ sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, const unsigned char *p, if(attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { uint32_t atime; uint32_t mtime; - if(_libssh2_get_u32(&buf, &atime) != 0 || - _libssh2_get_u32(&buf, &mtime) != 0) { + if(_libssh2_get_u32(&buf, &atime) || + _libssh2_get_u32(&buf, &mtime)) { return LIBSSH2_ERROR_BUFFER_TOO_SMALL; } attrs->atime = atime; attrs->mtime = mtime; } - return (buf.dataptr - buf.data); + /* Parse extended data, if present, to avoid stream parsing errors */ + if(attrs->flags & LIBSSH2_SFTP_ATTR_EXTENDED) { + uint32_t extended_count; + uint32_t i; + size_t etype_len; + unsigned char *etype; + size_t edata_len; + unsigned char *edata; + + if(_libssh2_get_u32(&buf, &extended_count)) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + + for(i = 0; i < extended_count; ++i) { + if(_libssh2_get_string(&buf, &etype, &etype_len) || + _libssh2_get_string(&buf, &edata, &edata_len)) { + return LIBSSH2_ERROR_BUFFER_TOO_SMALL; + } + } + } + + return buf.dataptr - buf.data; } /* ************ @@ -741,8 +776,8 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) { LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract); - (void) session_abstract; - (void) channel; + (void)session_abstract; + (void)channel; /* Free the partial packet storage for sftp_packet_read */ if(sftp->partial_packet) { @@ -757,23 +792,21 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) LIBSSH2_FREE(session, sftp); } -/* - * sftp_init - * +/* sftp_init * Startup an SFTP session */ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) { unsigned char *data; - size_t data_len; + size_t data_len = 0; ssize_t rc; LIBSSH2_SFTP *sftp_handle; struct string_buf buf; unsigned char *endp; if(session->sftpInit_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Initializing SFTP subsystem"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Initializing SFTP subsystem")); /* * The 'sftpInit_sftp' and 'sftpInit_channel' struct fields within the @@ -787,7 +820,7 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) * including *EAGAIN). */ - assert(session->sftpInit_sftp == NULL); + assert(!session->sftpInit_sftp); session->sftpInit_sftp = NULL; session->sftpInit_state = libssh2_NB_state_created; } @@ -860,10 +893,10 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) _libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION); session->sftpInit_sent = 0; /* nothing's sent yet */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Sending FXP_INIT packet advertising " "version %d support", - (int) LIBSSH2_SFTP_VERSION); + (int) LIBSSH2_SFTP_VERSION)); session->sftpInit_state = libssh2_NB_state_sent2; } @@ -896,6 +929,22 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) } } + if(session->sftpInit_state == libssh2_NB_state_error_closing) { + rc = _libssh2_channel_free(session->sftpInit_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block closing channel"); + return NULL; + } + session->sftpInit_channel = NULL; + if(session->sftpInit_sftp) { + LIBSSH2_FREE(session, session->sftpInit_sftp); + session->sftpInit_sftp = NULL; + } + session->sftpInit_state = libssh2_NB_state_idle; + return NULL; + } + rc = sftp_packet_require(sftp_handle, SSH_FXP_VERSION, 0, &data, &data_len, 5); if(rc == LIBSSH2_ERROR_EAGAIN) { @@ -912,7 +961,7 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) goto sftp_init_error; } else if(rc) { - _libssh2_error(session, rc, + _libssh2_error(session, (int)rc, "Timeout waiting for response from SFTP subsystem"); goto sftp_init_error; } @@ -922,21 +971,21 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) buf.len = data_len; endp = &buf.data[data_len]; - if(_libssh2_get_u32(&buf, &(sftp_handle->version)) != 0) { + if(_libssh2_get_u32(&buf, &(sftp_handle->version))) { LIBSSH2_FREE(session, data); rc = LIBSSH2_ERROR_BUFFER_TOO_SMALL; goto sftp_init_error; } if(sftp_handle->version > LIBSSH2_SFTP_VERSION) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Truncating remote SFTP version from %lu", - sftp_handle->version); + sftp_handle->version)); sftp_handle->version = LIBSSH2_SFTP_VERSION; } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Enabling SFTP version %lu compatibility", - sftp_handle->version); + sftp_handle->version)); while(buf.dataptr < endp) { unsigned char *extname, *extdata; @@ -971,21 +1020,12 @@ static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) return sftp_handle; - sftp_init_error: - while(_libssh2_channel_free(session->sftpInit_channel) == - LIBSSH2_ERROR_EAGAIN); - session->sftpInit_channel = NULL; - if(session->sftpInit_sftp) { - LIBSSH2_FREE(session, session->sftpInit_sftp); - session->sftpInit_sftp = NULL; - } - session->sftpInit_state = libssh2_NB_state_idle; +sftp_init_error: + session->sftpInit_state = libssh2_NB_state_error_closing; return NULL; } -/* - * libssh2_sftp_init - * +/* libssh2_sftp_init * Startup an SFTP session */ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session) @@ -1005,9 +1045,7 @@ LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session) return ptr; } -/* - * sftp_shutdown - * +/* sftp_shutdown * Shuts down the SFTP subsystem */ static int @@ -1103,7 +1141,7 @@ libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) static LIBSSH2_SFTP_HANDLE * sftp_open(LIBSSH2_SFTP *sftp, const char *filename, size_t filename_len, uint32_t flags, long mode, - int open_type) + int open_type, LIBSSH2_SFTP_ATTRIBUTES *attrs_in) { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; @@ -1113,14 +1151,19 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, }; unsigned char *s; ssize_t rc; - int open_file = (open_type == LIBSSH2_SFTP_OPENFILE)?1:0; + int open_file = (open_type == LIBSSH2_SFTP_OPENFILE) ? 1 : 0; if(sftp->open_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + + if(attrs_in) { + memcpy(&attrs, attrs_in, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); + } + /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + flags(4) */ - sftp->open_packet_len = filename_len + 13 + - (open_file? (4 + - sftp_attrsize(LIBSSH2_SFTP_ATTR_PERMISSIONS)) : 0); + sftp->open_packet_len = (uint32_t)(filename_len + 13 + + (open_file? (4 + sftp_attrsize(attrs.flags)) : 0)); /* surprise! this starts out with nothing sent */ sftp->open_packet_sent = 0; @@ -1147,8 +1190,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, s += sftp_attr2bin(s, &attrs); } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Sending %s open request", - open_file? "file" : "directory"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Sending %s open request", + open_file? "file" : "directory")); sftp->open_state = libssh2_NB_state_created; } @@ -1165,7 +1208,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, return NULL; } else if(rc < 0) { - _libssh2_error(session, rc, "Unable to send FXP_OPEN*"); + _libssh2_error(session, (int)rc, "Unable to send FXP_OPEN*"); LIBSSH2_FREE(session, sftp->open_packet); sftp->open_packet = NULL; sftp->open_state = libssh2_NB_state_idle; @@ -1185,7 +1228,7 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, } if(sftp->open_state == libssh2_NB_state_sent) { - size_t data_len; + size_t data_len = 0; unsigned char *data; static const unsigned char fopen_responses[2] = { SSH_FXP_HANDLE, SSH_FXP_STATUS }; @@ -1207,7 +1250,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, } sftp->open_state = libssh2_NB_state_idle; if(rc) { - _libssh2_error(session, rc, "Timeout waiting for status message"); + _libssh2_error(session, (int)rc, + "Timeout waiting for status message"); return NULL; } @@ -1228,8 +1272,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, sftp->last_errno = _libssh2_ntohu32(data + 5); if(LIBSSH2_FX_OK == sftp->last_errno) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "got HANDLE FXOK!"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "got HANDLE FXOK")); LIBSSH2_FREE(session, data); @@ -1258,9 +1302,9 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, if(badness) { _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Failed opening remote file"); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "got FXP_STATUS %d", - sftp->last_errno); + sftp->last_errno)); LIBSSH2_FREE(session, data); return NULL; } @@ -1304,7 +1348,8 @@ sftp_open(LIBSSH2_SFTP *sftp, const char *filename, fp->u.file.offset = 0; fp->u.file.offset_sent = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Open command successful"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Open command successful")); return fp; } return NULL; @@ -1323,16 +1368,31 @@ libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, return NULL; BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session, - sftp_open(sftp, filename, filename_len, flags, mode, - open_type)); + sftp_open(sftp, filename, filename_len, (uint32_t)flags, + mode, open_type, NULL)); return hnd; } -/* - * sftp_read - * +/* libssh2_sftp_open_ex_r + */ +LIBSSH2_API LIBSSH2_SFTP_HANDLE * +libssh2_sftp_open_ex_r(LIBSSH2_SFTP *sftp, const char *filename, + size_t filename_len, unsigned long flags, long mode, + int open_type, LIBSSH2_SFTP_ATTRIBUTES *attrs) +{ + LIBSSH2_SFTP_HANDLE *hnd; + + if(!sftp) + return NULL; + + BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session, + sftp_open(sftp, filename, filename_len, (uint32_t)flags, + mode, open_type, attrs)); + return hnd; +} + +/* sftp_read * Read from an SFTP file handle - * */ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, size_t buffer_size) @@ -1382,13 +1442,14 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, switch(sftp->read_state) { case libssh2_NB_state_idle: + sftp->last_errno = LIBSSH2_FX_OK; /* Some data may already have been read from the server in the previous call but didn't fit in the buffer at the time. If so, we return that now as we can't risk being interrupted later with data partially written to the buffer. */ if(filep->data_left) { - size_t copy = MIN(buffer_size, filep->data_left); + size_t copy = LIBSSH2_MIN(buffer_size, filep->data_left); memcpy(buffer, &filep->data[ filep->data_len - filep->data_left], copy); @@ -1428,7 +1489,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* 'count' is how much more data to ask for, and 'already' is how much data that already has been asked for but not yet returned. - Specificly, 'count' means how much data that have or will be + Specifically, 'count' means how much data that have or will be asked for by the nodes that are already added to the linked list. Some of those read requests may not actually have been sent off successfully yet. @@ -1452,8 +1513,8 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, allows, expand it! */ rc = _libssh2_channel_receive_window_adjust(sftp->channel, - max_read_ahead*8, - 1, NULL); + (uint32_t)(max_read_ahead * 8), + 1, NULL); /* if this returns EAGAIN, we will get back to this function at next call */ assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->data_left); @@ -1468,12 +1529,12 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */ - uint32_t packet_len = (uint32_t)handle->handle_len + 25; + uint32_t packet_len = (uint32_t)(handle->handle_len + 25); uint32_t request_id; - uint32_t size = count; + uint32_t size = (uint32_t)count; if(size < buffer_size) - size = buffer_size; + size = (uint32_t)buffer_size; if(size > MAX_SFTP_READ_SIZE) size = MAX_SFTP_READ_SIZE; @@ -1502,11 +1563,12 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* add this new entry LAST in the list */ _libssh2_list_add(&handle->packet_list, &chunk->node); - count -= MIN(size, count); /* deduct the size we used, as we might - * have to create more packets */ - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + /* deduct the size we used, as we might have to create + more packets */ + count -= LIBSSH2_MIN(size, count); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "read request id %d sent (offset: %d, size: %d)", - request_id, (int)chunk->offset, (int)chunk->len); + request_id, (int)chunk->offset, (int)chunk->len)); } /* FALL-THROUGH */ case libssh2_NB_state_sent: @@ -1561,7 +1623,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, while(chunk) { unsigned char *data; - size_t data_len; + size_t data_len = 0; uint32_t rc32; static const unsigned char read_responses[2] = { SSH_FXP_DATA, SSH_FXP_STATUS @@ -1582,7 +1644,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, rc = sftp_packet_requirev(sftp, 2, read_responses, chunk->request_id, &data, &data_len, 9); - if(rc == LIBSSH2_ERROR_EAGAIN && bytes_in_buffer != 0) { + if(rc == LIBSSH2_ERROR_EAGAIN && bytes_in_buffer) { /* do not return EAGAIN if we have already * written data into the buffer */ return bytes_in_buffer; @@ -1636,7 +1698,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, requested, which shouldn't happen for normal files. See: https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02 #section-6.4 - */ + */ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Read Packet At Unexpected Offset"); } @@ -1667,7 +1729,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, /* getting the full packet would overflow the buffer, so only get the correct amount and keep the remainder */ - rc32 = (uint32_t)buffer_size - bytes_in_buffer; + rc32 = (uint32_t)(buffer_size - bytes_in_buffer); /* store data to keep for next call */ filep->data = data; @@ -1717,7 +1779,7 @@ static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, break; default: - assert(!"State machine error; unrecognised read state"); + assert(0); /* State machine error; unrecognised read state */ } /* we should never reach this point */ @@ -1751,16 +1813,18 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; uint32_t num_names; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; + uint32_t packet_len = (uint32_t)(handle->handle_len + 13); unsigned char *s, *data; static const unsigned char read_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS }; ssize_t retcode; if(sftp->readdir_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + if(handle->u.dir.names_left) { /* * A prior request returned more than one directory entry, @@ -1772,7 +1836,7 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t filename_len; size_t longentry_len; size_t names_packet_len = handle->u.dir.names_packet_len; - int attr_len = 0; + ssize_t attr_len = 0; if(names_packet_len >= 4) { s = (unsigned char *) handle->u.dir.next_name; @@ -1813,7 +1877,7 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, goto end; } - if(longentry && (longentry_maxlen>1)) { + if(longentry && (longentry_maxlen > 1)) { longentry_len = real_longentry_len; if(longentry_len >= longentry_maxlen || @@ -1852,14 +1916,14 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, handle->u.dir.next_name = (char *) s; handle->u.dir.names_packet_len = names_packet_len; - end: if((--handle->u.dir.names_left) == 0) LIBSSH2_FREE(session, handle->u.dir.names_packet); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, +end: + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "libssh2_sftp_readdir_ex() return %d", - filename_len); + filename_len)); return (ssize_t)filename_len; } @@ -1881,8 +1945,8 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, } if(sftp->readdir_state == libssh2_NB_state_created) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Reading entries from directory handle"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Reading entries from directory handle")); retcode = _libssh2_channel_write(channel, 0, sftp->readdir_packet, packet_len); if(retcode == LIBSSH2_ERROR_EAGAIN) { @@ -1916,19 +1980,20 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, } else if(retcode) { sftp->readdir_state = libssh2_NB_state_idle; - return _libssh2_error(session, retcode, + return _libssh2_error(session, (int)retcode, "Timeout waiting for status message"); } if(data[0] == SSH_FXP_STATUS) { - retcode = _libssh2_ntohu32(data + 5); + unsigned int rerrno; + rerrno = _libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, data); - if(retcode == LIBSSH2_FX_EOF) { + if(rerrno == LIBSSH2_FX_EOF) { sftp->readdir_state = libssh2_NB_state_idle; return 0; } else { - sftp->last_errno = retcode; + sftp->last_errno = rerrno; sftp->readdir_state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error"); @@ -1938,8 +2003,8 @@ static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, sftp->readdir_state = libssh2_NB_state_idle; num_names = _libssh2_ntohu32(data + 5); - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%lu entries returned", - num_names); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "%lu entries returned", + num_names)); if(!num_names) { LIBSSH2_FREE(session, data); return 0; @@ -1964,17 +2029,16 @@ libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, size_t longentry_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs) { - int rc; + ssize_t rc; if(!hnd) return LIBSSH2_ERROR_BAD_USE; BLOCK_ADJUST(rc, hnd->sftp->channel->session, sftp_readdir(hnd, buffer, buffer_maxlen, longentry, longentry_maxlen, attrs)); - return rc; + return (int)rc; /* FIXME: -> ssize_t */ } -/* - * sftp_write +/* sftp_write * * Write data to an SFTP handle. Returns the number of bytes written, or * a negative error code. @@ -2017,10 +2081,10 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; uint32_t retcode; uint32_t packet_len; - unsigned char *s, *data; + unsigned char *s, *data = NULL; ssize_t rc; struct sftp_pipeline_chunk *chunk; struct sftp_pipeline_chunk *next; @@ -2031,6 +2095,7 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, switch(sftp->write_state) { default: case libssh2_NB_state_idle: + sftp->last_errno = LIBSSH2_FX_OK; /* Number of bytes sent off that haven't been acked and therefore we will get passed in here again. @@ -2039,8 +2104,8 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, acked but we haven't been able to return as such yet, so we will get that data as well passed in here again. */ - already = (size_t) (handle->u.file.offset_sent - - handle->u.file.offset)+ + already = (size_t)(handle->u.file.offset_sent - + handle->u.file.offset)+ handle->u.file.acked; if(count >= already) { @@ -2056,12 +2121,13 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, while(count) { /* TODO: Possibly this should have some logic to prevent a very very small fraction to be left but lets ignore that for now */ - uint32_t size = MIN(MAX_SFTP_OUTGOING_SIZE, count); + uint32_t size = + (uint32_t)(LIBSSH2_MIN(MAX_SFTP_OUTGOING_SIZE, count)); uint32_t request_id; /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */ - packet_len = handle->handle_len + size + 25; + packet_len = (uint32_t)(handle->handle_len + size + 25); chunk = LIBSSH2_ALLOC(session, packet_len + sizeof(struct sftp_pipeline_chunk)); @@ -2206,7 +2272,7 @@ static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, acked += handle->u.file.acked; if(acked) { - ssize_t ret = MIN(acked, org_count); + ssize_t ret = LIBSSH2_MIN(acked, org_count); /* we got data acked so return that amount, but no more than what was asked to get sent! */ @@ -2244,15 +2310,17 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) LIBSSH2_SESSION *session = channel->session; /* 34 = packet_len(4) + packet_type(1) + request_id(4) + string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 34; - size_t data_len; - unsigned char *packet, *s, *data; + uint32_t packet_len = (uint32_t)(handle->handle_len + 34); + size_t data_len = 0; + unsigned char *packet, *s, *data = NULL; ssize_t rc; uint32_t retcode; if(sftp->fsync_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Issuing fsync command"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Issuing fsync command")); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -2295,7 +2363,7 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) rc = sftp_packet_require(sftp, SSH_FXP_STATUS, sftp->fsync_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -2306,7 +2374,7 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) } else if(rc) { sftp->fsync_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP EXTENDED REPLY"); } @@ -2339,9 +2407,7 @@ libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd) } -/* - * sftp_fstat - * +/* sftp_fstat * Get or Set stat on a file */ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, @@ -2350,18 +2416,20 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = - handle->handle_len + 13 + (setstat ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; + uint32_t packet_len = (uint32_t)(handle->handle_len + 13 + + (setstat ? sftp_attrsize(attrs->flags) : 0)); + unsigned char *s, *data = NULL; static const unsigned char fstat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS }; ssize_t rc; if(sftp->fstat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Issuing %s command", - setstat ? "set-stat" : "stat"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Issuing %s command", + setstat ? "set-stat" : "stat")); s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->fstat_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -2386,7 +2454,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, rc = _libssh2_channel_write(channel, 0, sftp->fstat_packet, packet_len); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if((ssize_t)packet_len != rc) { LIBSSH2_FREE(session, sftp->fstat_packet); @@ -2406,7 +2474,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, sftp->fstat_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { LIBSSH2_FREE(session, data); @@ -2416,7 +2484,7 @@ static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, } else if(rc) { sftp->fstat_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Timeout waiting for status message"); } @@ -2575,14 +2643,16 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ - uint32_t packet_len = handle->handle_len + 13; + uint32_t packet_len = (uint32_t)(handle->handle_len + 13); unsigned char *s, *data = NULL; int rc = 0; if(handle->close_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Closing handle"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Closing handle")); s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len); if(!handle->close_packet) { handle->close_state = libssh2_NB_state_idle; @@ -2602,12 +2672,13 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) } if(handle->close_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, handle->close_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, handle->close_packet, + packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((ssize_t)packet_len != rc) { + else if((ssize_t)packet_len != nwritten) { handle->close_state = libssh2_NB_state_idle; rc = _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_CLOSE command"); @@ -2649,7 +2720,7 @@ sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) } else { - int retcode = _libssh2_ntohu32(data + 5); + uint32_t retcode = _libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, data); if(retcode != LIBSSH2_FX_OK) { @@ -2705,15 +2776,18 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; + size_t data_len = 0; + uint32_t retcode; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */ - uint32_t packet_len = filename_len + 13; - unsigned char *s, *data; + uint32_t packet_len = (uint32_t)(filename_len + 13); + unsigned char *s, *data = NULL; int rc; if(sftp->unlink_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Unlinking %s", filename); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Unlinking %s", filename)); s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->unlink_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -2730,12 +2804,13 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, } if(sftp->unlink_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->unlink_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, sftp->unlink_packet, + packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if((ssize_t)packet_len != rc) { + else if((ssize_t)packet_len != nwritten) { LIBSSH2_FREE(session, sftp->unlink_packet); sftp->unlink_packet = NULL; sftp->unlink_state = libssh2_NB_state_idle; @@ -2797,9 +2872,7 @@ libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, return rc; } -/* - * sftp_rename - * +/* sftp_rename * Rename a file on the remote server */ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, @@ -2809,24 +2882,26 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; int retcode; uint32_t packet_len = - source_filename_len + dest_filename_len + 17 + (sftp->version >= - 5 ? 4 : 0); + source_filename_len + dest_filename_len + 17 + + (sftp->version >= 5 ? 4 : 0); /* packet_len(4) + packet_type(1) + request_id(4) + source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */ - unsigned char *data; + unsigned char *data = NULL; ssize_t rc; - if(sftp->version < 2) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support RENAME"); - } - if(sftp->rename_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s", - source_filename, dest_filename); + sftp->last_errno = LIBSSH2_FX_OK; + + if(sftp->version < 2) { + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Server does not support RENAME"); + } + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s", + source_filename, dest_filename)); sftp->rename_s = sftp->rename_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->rename_packet) { @@ -2844,7 +2919,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, _libssh2_store_str(&sftp->rename_s, dest_filename, dest_filename_len); if(sftp->version >= 5) - _libssh2_store_u32(&sftp->rename_s, flags); + _libssh2_store_u32(&sftp->rename_s, (uint32_t)flags); sftp->rename_state = libssh2_NB_state_created; } @@ -2853,7 +2928,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, rc = _libssh2_channel_write(channel, 0, sftp->rename_packet, sftp->rename_s - sftp->rename_packet); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if((ssize_t)packet_len != rc) { LIBSSH2_FREE(session, sftp->rename_packet); @@ -2872,7 +2947,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, sftp->rename_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -2883,7 +2958,7 @@ static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, } else if(rc) { sftp->rename_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP STATUS"); } @@ -2939,9 +3014,7 @@ libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, return rc; } -/* - * sftp_fstatvfs - * +/* sftp_fstatvfs * Get file system statistics */ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) @@ -2949,20 +3022,22 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) + handle_len (4) */ /* 20 = strlen ("fstatvfs@openssh.com") */ - uint32_t packet_len = handle->handle_len + 20 + 17; - unsigned char *packet, *s, *data; + uint32_t packet_len = (uint32_t)(handle->handle_len + 20 + 17); + unsigned char *packet, *s, *data = NULL; ssize_t rc; unsigned int flag; static const unsigned char responses[2] = { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; if(sftp->fstatvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics"); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Getting file system statistics")); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3006,7 +3081,7 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -3017,12 +3092,12 @@ static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) } else if(rc) { sftp->fstatvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP EXTENDED REPLY"); } if(data[0] == SSH_FXP_STATUS) { - int retcode = _libssh2_ntohu32(data + 5); + uint32_t retcode = _libssh2_ntohu32(data + 5); sftp->fstatvfs_state = libssh2_NB_state_idle; LIBSSH2_FREE(session, data); sftp->last_errno = retcode; @@ -3075,9 +3150,7 @@ libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) return rc; } -/* - * sftp_statvfs - * +/* sftp_statvfs * Get file system statistics */ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, @@ -3085,20 +3158,22 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) + path_len (4) */ /* 19 = strlen ("statvfs@openssh.com") */ uint32_t packet_len = path_len + 19 + 17; - unsigned char *packet, *s, *data; + unsigned char *packet, *s, *data = NULL; ssize_t rc; unsigned int flag; static const unsigned char responses[2] = { SSH_FXP_EXTENDED_REPLY, SSH_FXP_STATUS }; if(sftp->statvfs_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Getting file system statistics of %s", path); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Getting file system statistics of %s", path)); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3141,7 +3216,7 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, rc = sftp_packet_requirev(sftp, 2, responses, sftp->statvfs_request_id, &data, &data_len, 9); if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + return (int)rc; } else if(rc == LIBSSH2_ERROR_BUFFER_TOO_SMALL) { if(data_len > 0) { @@ -3152,12 +3227,12 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, } else if(rc) { sftp->statvfs_state = libssh2_NB_state_idle; - return _libssh2_error(session, rc, + return _libssh2_error(session, (int)rc, "Error waiting for FXP EXTENDED REPLY"); } if(data[0] == SSH_FXP_STATUS) { - int retcode = _libssh2_ntohu32(data + 5); + uint32_t retcode = _libssh2_ntohu32(data + 5); sftp->statvfs_state = libssh2_NB_state_idle; LIBSSH2_FREE(session, data); sftp->last_errno = retcode; @@ -3206,15 +3281,13 @@ libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, int rc; if(!sftp || !st) return LIBSSH2_ERROR_BAD_USE; - BLOCK_ADJUST(rc, sftp->channel->session, sftp_statvfs(sftp, path, path_len, - st)); + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_statvfs(sftp, path, (unsigned int)path_len, st)); return rc; } -/* - * sftp_mkdir - * +/* sftp_mkdir * Create an SFTP directory */ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, @@ -3225,10 +3298,10 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES attrs = { 0, 0, 0, 0, 0, 0, 0 }; - size_t data_len; - int retcode; + size_t data_len = 0; + uint32_t retcode; ssize_t packet_len; - unsigned char *packet, *s, *data; + unsigned char *packet, *s, *data = NULL; int rc; if(mode != LIBSSH2_SFTP_DEFAULT_MODE) { @@ -3241,8 +3314,10 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, packet_len = path_len + 13 + sftp_attrsize(attrs.flags); if(sftp->mkdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, - "Creating directory %s with mode 0%lo", path, mode); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, + "Creating directory %s with mode 0%lo", path, mode)); s = packet = LIBSSH2_ALLOC(session, packet_len); if(!packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3250,7 +3325,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, "packet"); } - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); *(s++) = SSH_FXP_MKDIR; sftp->mkdir_request_id = sftp->request_id++; _libssh2_store_u32(&s, sftp->mkdir_request_id); @@ -3265,12 +3340,13 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, } if(sftp->mkdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, packet, packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { sftp->mkdir_packet = packet; - return rc; + return (int)nwritten; } - if(packet_len != rc) { + if(packet_len != nwritten) { LIBSSH2_FREE(session, packet); sftp->mkdir_state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, @@ -3305,7 +3381,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_FREE(session, data); if(retcode == LIBSSH2_FX_OK) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "OK!"); + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "OK")); return 0; } else { @@ -3315,9 +3391,7 @@ static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, } } -/* - * libssh2_sftp_mkdir_ex - * +/* libssh2_sftp_mkdir_ex * Create an SFTP directory */ LIBSSH2_API int @@ -3340,16 +3414,18 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; - int retcode; + size_t data_len = 0; + uint32_t retcode; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ ssize_t packet_len = path_len + 13; - unsigned char *s, *data; + unsigned char *s, *data = NULL; int rc; if(sftp->rmdir_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Removing directory: %s", - path); + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "Removing directory: %s", + path)); s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->rmdir_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3357,7 +3433,7 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, "packet"); } - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); *(s++) = SSH_FXP_RMDIR; sftp->rmdir_request_id = sftp->request_id++; _libssh2_store_u32(&s, sftp->rmdir_request_id); @@ -3367,12 +3443,13 @@ static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, } if(sftp->rmdir_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->rmdir_packet, - packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, sftp->rmdir_packet, + packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if(packet_len != rc) { + else if(packet_len != nwritten) { LIBSSH2_FREE(session, sftp->rmdir_packet); sftp->rmdir_packet = NULL; sftp->rmdir_state = libssh2_NB_state_idle; @@ -3442,22 +3519,24 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ ssize_t packet_len = path_len + 13 + ((stat_type == LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0); - unsigned char *s, *data; + unsigned char *s, *data = NULL; static const unsigned char stat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS }; int rc; if(sftp->stat_state == libssh2_NB_state_idle) { - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s", + sftp->last_errno = LIBSSH2_FX_OK; + + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "%s %s", (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : (stat_type == - LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path); + LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path)); s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->stat_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3465,7 +3544,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, "packet"); } - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); switch(stat_type) { case LIBSSH2_SFTP_SETSTAT: @@ -3491,11 +3570,13 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, } if(sftp->stat_state == libssh2_NB_state_created) { - rc = _libssh2_channel_write(channel, 0, sftp->stat_packet, packet_len); - if(rc == LIBSSH2_ERROR_EAGAIN) { - return rc; + ssize_t nwritten; + nwritten = _libssh2_channel_write(channel, 0, + sftp->stat_packet, packet_len); + if(nwritten == LIBSSH2_ERROR_EAGAIN) { + return (int)nwritten; } - else if(packet_len != rc) { + else if(packet_len != nwritten) { LIBSSH2_FREE(session, sftp->stat_packet); sftp->stat_packet = NULL; sftp->stat_state = libssh2_NB_state_idle; @@ -3528,7 +3609,7 @@ static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, sftp->stat_state = libssh2_NB_state_idle; if(data[0] == SSH_FXP_STATUS) { - int retcode; + uint32_t retcode; retcode = _libssh2_ntohu32(data + 5); LIBSSH2_FREE(session, data); @@ -3580,22 +3661,25 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len, link_len; + size_t data_len = 0, link_len; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ ssize_t packet_len = path_len + 13 + ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0); - unsigned char *s, *data; + unsigned char *s, *data = NULL; static const unsigned char link_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS }; int retcode; - if((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) { - return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, - "Server does not support SYMLINK or READLINK"); - } - if(sftp->symlink_state == libssh2_NB_state_idle) { + sftp->last_errno = LIBSSH2_FX_OK; + + if((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) { + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Server does not support SYMLINK or" + " READLINK"); + } + s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len); if(!sftp->symlink_packet) { return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -3603,13 +3687,14 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, "SYMLINK/READLINK/REALPATH packet"); } - _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s on %s", + _libssh2_debug((session, LIBSSH2_TRACE_SFTP, "%s %s on %s", (link_type == LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading", (link_type == - LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path); + LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", + path)); - _libssh2_store_u32(&s, packet_len - 4); + _libssh2_store_u32(&s, (uint32_t)(packet_len - 4)); switch(link_type) { case LIBSSH2_SFTP_REALPATH: @@ -3638,7 +3723,7 @@ static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, ssize_t rc = _libssh2_channel_write(channel, 0, sftp->symlink_packet, packet_len); if(rc == LIBSSH2_ERROR_EAGAIN) - return rc; + return (int)rc; else if(packet_len != rc) { LIBSSH2_FREE(session, sftp->symlink_packet); sftp->symlink_packet = NULL; diff --git a/libs/libssh2/src/sftp.h b/libs/libssh2/src/sftp.h index ae4162f10f..647ddbc007 100644 --- a/libs/libssh2/src/sftp.h +++ b/libs/libssh2/src/sftp.h @@ -1,8 +1,8 @@ -#ifndef _LIBSSH2_SFTP_H -#define _LIBSSH2_SFTP_H +#ifndef __LIBSSH2_SFTP_H +#define __LIBSSH2_SFTP_H /* - * Copyright (C) 2010 - 2012 by Daniel Stenberg - * Author: Daniel Stenberg <daniel@haxx.se> + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -37,6 +37,7 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ /* @@ -67,10 +68,6 @@ struct sftp_zombie_requests { uint32_t request_id; }; -#ifndef MIN -#define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - struct _LIBSSH2_SFTP_PACKET { struct list_node node; /* linked list header */ @@ -153,9 +150,10 @@ struct _LIBSSH2_SFTP uint32_t last_errno; /* Holder for partial packet, use in libssh2_sftp_packet_read() */ - unsigned char partial_size[4]; /* buffer for size field */ - size_t partial_size_len; /* size field length */ - unsigned char *partial_packet; /* The data */ + unsigned char packet_header[9]; + /* packet size (4) packet type (1) request id (4) */ + size_t packet_header_len; /* packet_header length */ + unsigned char *partial_packet; /* The data, with header */ uint32_t partial_len; /* Desired number of bytes */ size_t partial_received; /* Bytes received so far */ @@ -235,4 +233,4 @@ struct _LIBSSH2_SFTP uint32_t symlink_request_id; }; -#endif +#endif /* __LIBSSH2_SFTP_H */ diff --git a/libs/libssh2/src/transport.c b/libs/libssh2/src/transport.c index 45e445c743..c73b859e4d 100644 --- a/libs/libssh2/src/transport.c +++ b/libs/libssh2/src/transport.c @@ -1,6 +1,6 @@ -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg <daniel@haxx.se> +/* Copyright (C) The Written Word, Inc. + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -35,17 +35,17 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* * This file handles reading and writing to the SECSH transport layer. RFC4253. */ #include "libssh2_priv.h" + #include <errno.h> -#include <fcntl.h> #include <ctype.h> -#ifdef LIBSSH2DEBUG -#include <stdio.h> -#endif - #include <assert.h> #include "transport.h" @@ -118,29 +118,50 @@ debugdump(LIBSSH2_SESSION * session, } } #else -#define debugdump(a,x,y,z) +#define debugdump(a,x,y,z) do {} while(0) #endif -/* decrypt() decrypts 'len' bytes from 'source' to 'dest'. +/* decrypt() decrypts 'len' bytes from 'source' to 'dest' in units of + * blocksize. * * returns 0 on success and negative on failure */ static int decrypt(LIBSSH2_SESSION * session, unsigned char *source, - unsigned char *dest, int len) + unsigned char *dest, ssize_t len, int firstlast) { struct transportpacket *p = &session->packet; int blocksize = session->remote.crypt->blocksize; /* if we get called with a len that isn't an even number of blocksizes - we risk losing those extra bytes */ - assert((len % blocksize) == 0); + we risk losing those extra bytes. AAD is an exception, since those first + few bytes aren't encrypted so it throws off the rest of the count. */ + if(!CRYPT_FLAG_L(session, PKTLEN_AAD)) + assert((len % blocksize) == 0); + + while(len > 0) { + /* normally decrypt up to blocksize bytes at a time */ + ssize_t decryptlen = LIBSSH2_MIN(blocksize, len); + /* The first block is special (since it needs to be decoded to get the + length of the remainder of the block) and takes priority. When the + length finally gets to the last blocksize bytes, and there's no + more data to come, it's the end. */ + int lowerfirstlast = IS_FIRST(firstlast) ? FIRST_BLOCK : + ((len <= blocksize) ? firstlast : MIDDLE_BLOCK); + /* If the last block would be less than a whole blocksize, combine it + with the previous block to make it larger. This ensures that the + whole MAC is included in a single decrypt call. */ + if(CRYPT_FLAG_L(session, PKTLEN_AAD) && IS_LAST(firstlast) + && (len < blocksize*2)) { + decryptlen = len; + lowerfirstlast = LAST_BLOCK; + } - while(len >= blocksize) { - if(session->remote.crypt->crypt(session, source, blocksize, - &session->remote.crypt_abstract)) { + if(session->remote.crypt->crypt(session, source, decryptlen, + &session->remote.crypt_abstract, + lowerfirstlast)) { LIBSSH2_FREE(session, p->payload); return LIBSSH2_ERROR_DECRYPT; } @@ -148,11 +169,11 @@ decrypt(LIBSSH2_SESSION * session, unsigned char *source, /* if the crypt() function would write to a given address it wouldn't have to memcpy() and we could avoid this memcpy() too */ - memcpy(dest, source, blocksize); + memcpy(dest, source, decryptlen); - len -= blocksize; /* less bytes left */ - dest += blocksize; /* advance write pointer */ - source += blocksize; /* advance read pointer */ + len -= decryptlen; /* less bytes left */ + dest += decryptlen; /* advance write pointer */ + source += decryptlen; /* advance read pointer */ } return LIBSSH2_ERROR_NONE; /* all is fine */ } @@ -173,24 +194,84 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED; session->fullpacket_payload_len = p->packet_length - 1; - if(encrypted) { + if(encrypted && !CRYPT_FLAG_L(session, INTEGRATED_MAC)) { /* Calculate MAC hash */ - session->remote.mac->hash(session, macbuf, /* store hash here */ - session->remote.seqno, - p->init, 5, - p->payload, - session->fullpacket_payload_len, - &session->remote.mac_abstract); + int etm = session->remote.mac->etm; + size_t mac_len = session->remote.mac->mac_len; + if(etm) { + /* store hash here */ + session->remote.mac->hash(session, macbuf, + session->remote.seqno, + p->payload, p->total_num - mac_len, + NULL, 0, + &session->remote.mac_abstract); + } + else { + /* store hash here */ + session->remote.mac->hash(session, macbuf, + session->remote.seqno, + p->init, 5, + p->payload, + session->fullpacket_payload_len, + &session->remote.mac_abstract); + } /* Compare the calculated hash with the MAC we just read from * the network. The read one is at the very end of the payload * buffer. Note that 'payload_len' here is the packet_length * field which includes the padding but not the MAC. */ - if(memcmp(macbuf, p->payload + session->fullpacket_payload_len, - session->remote.mac->mac_len)) { + if(memcmp(macbuf, p->payload + p->total_num - mac_len, mac_len)) { + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Failed MAC check")); session->fullpacket_macstate = LIBSSH2_MAC_INVALID; + + } + else if(etm) { + /* MAC was ok and we start by decrypting the first block that + contains padding length since this allows us to decrypt + all other blocks to the right location in memory + avoiding moving a larger block of memory one byte. */ + unsigned char first_block[MAX_BLOCKSIZE]; + ssize_t decrypt_size; + unsigned char *decrypt_buffer; + int blocksize = session->remote.crypt->blocksize; + + rc = decrypt(session, p->payload + 4, + first_block, blocksize, FIRST_BLOCK); + if(rc) { + return rc; + } + + /* we need buffer for decrypt */ + decrypt_size = p->total_num - mac_len - 4; + decrypt_buffer = LIBSSH2_ALLOC(session, decrypt_size); + if(!decrypt_buffer) { + return LIBSSH2_ERROR_ALLOC; + } + + /* grab padding length and copy anything else + into target buffer */ + p->padding_length = first_block[0]; + if(blocksize > 1) { + memcpy(decrypt_buffer, first_block + 1, blocksize - 1); + } + + /* decrypt all other blocks packet */ + if(blocksize < decrypt_size) { + rc = decrypt(session, p->payload + blocksize + 4, + decrypt_buffer + blocksize - 1, + decrypt_size - blocksize, LAST_BLOCK); + if(rc) { + LIBSSH2_FREE(session, decrypt_buffer); + return rc; + } + } + + /* replace encrypted payload with plain text payload */ + LIBSSH2_FREE(session, p->payload); + p->payload = decrypt_buffer; } } @@ -200,11 +281,10 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) session->fullpacket_payload_len -= p->padding_length; /* Check for and deal with decompression */ - compressed = - session->local.comp != NULL && - session->local.comp->compress && - ((session->state & LIBSSH2_STATE_AUTHENTICATED) || - session->local.comp->use_in_auth); + compressed = session->local.comp && + session->local.comp->compress && + ((session->state & LIBSSH2_STATE_AUTHENTICATED) || + session->local.comp->use_in_auth); if(compressed && session->remote.comp_abstract) { /* @@ -274,13 +354,19 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) { int rc; struct transportpacket *p = &session->packet; - int remainbuf; - int remainpack; - int numbytes; - int numdecrypt; - unsigned char block[MAX_BLOCKSIZE]; - int blocksize; - int encrypted = 1; + ssize_t remainpack; /* how much there is left to add to the current payload + package */ + ssize_t remainbuf; /* how much data there is remaining in the buffer to + deal with before we should read more from the + network */ + ssize_t numbytes; /* how much data to deal with from the buffer on this + iteration through the loop */ + ssize_t numdecrypt; /* number of bytes to decrypt this iteration */ + unsigned char block[MAX_BLOCKSIZE]; /* working block buffer */ + int blocksize; /* minimum number of bytes we need before we can + use them */ + int encrypted = 1; /* whether the packet is encrypted or not */ + int firstlast = FIRST_BLOCK; /* if the first or last block to decrypt */ /* default clear the bit */ session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; @@ -303,8 +389,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) /* Whoever wants a packet won't get anything until the key re-exchange * is done! */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_read"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Redirecting into the" + " key re-exchange from _libssh2_transport_read")); rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); if(rc) return rc; @@ -322,8 +408,9 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) } do { + int etm; if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) { - return LIBSSH2_ERROR_NONE; + return LIBSSH2_ERROR_SOCKET_DISCONNECT; } if(session->state & LIBSSH2_STATE_NEWKEYS) { @@ -335,6 +422,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) make the checks below work fine still */ } + etm = encrypted && session->local.mac ? session->local.mac->etm : 0; + /* read/use a whole big chunk into a temporary area stored in the LIBSSH2_SESSION struct. We will decrypt data from that buffer into the packet buffer so this temp one doesn't have @@ -366,10 +455,9 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) } /* now read a big chunk from the network into the temp buffer */ - nread = - LIBSSH2_RECV(session, &p->buf[remainbuf], - PACKETBUFSIZE - remainbuf, - LIBSSH2_SOCKET_RECV_FLAGS(session)); + nread = LIBSSH2_RECV(session, &p->buf[remainbuf], + PACKETBUFSIZE - remainbuf, + LIBSSH2_SOCKET_RECV_FLAGS(session)); if(nread <= 0) { /* check if this is due to EAGAIN and return the special return code if so, error out normally otherwise */ @@ -378,14 +466,14 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) LIBSSH2_SESSION_BLOCK_INBOUND; return LIBSSH2_ERROR_EAGAIN; } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, "Error recving %d bytes (got %d)", - PACKETBUFSIZE - remainbuf, -nread); + PACKETBUFSIZE - remainbuf, -nread)); return LIBSSH2_ERROR_SOCKET_RECV; } - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, "Recved %d/%d bytes to %p+%d", nread, - PACKETBUFSIZE - remainbuf, p->buf, remainbuf); + PACKETBUFSIZE - remainbuf, p->buf, remainbuf)); debugdump(session, "libssh2_transport_read() raw", &p->buf[remainbuf], nread); @@ -400,13 +488,19 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) numbytes = remainbuf; if(!p->total_num) { - size_t total_num; + size_t total_num; /* the number of bytes following the initial + (5 bytes) packet length and padding length + fields */ + + /* packet length is not encrypted in encode-then-mac mode + and we donøt need to decrypt first block */ + ssize_t required_size = etm ? 4 : blocksize; /* No payload package area allocated yet. To know the - size of this payload, we need to decrypt the first + size of this payload, we need enough to decrypt the first blocksize data. */ - if(numbytes < blocksize) { + if(numbytes < required_size) { /* we can't act on anything less than blocksize, but this check is only done for the initial block since once we have got the start of a block we can in fact deal with fractions @@ -416,28 +510,37 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) return LIBSSH2_ERROR_EAGAIN; } - if(encrypted) { - rc = decrypt(session, &p->buf[p->readidx], block, blocksize); - if(rc != LIBSSH2_ERROR_NONE) { - return rc; - } - /* save the first 5 bytes of the decrypted package, to be - used in the hash calculation later down. */ - memcpy(p->init, block, 5); + if(etm) { + p->packet_length = _libssh2_ntohu32(&p->buf[p->readidx]); } else { - /* the data is plain, just copy it verbatim to - the working block buffer */ - memcpy(block, &p->buf[p->readidx], blocksize); - } + if(encrypted) { + /* first decrypted block */ + rc = decrypt(session, &p->buf[p->readidx], + block, blocksize, FIRST_BLOCK); + if(rc != LIBSSH2_ERROR_NONE) { + return rc; + } + /* Save the first 5 bytes of the decrypted package, to be + used in the hash calculation later down. + This is ignored in the INTEGRATED_MAC case. */ + memcpy(p->init, block, 5); + } + else { + /* the data is plain, just copy it verbatim to + the working block buffer */ + memcpy(block, &p->buf[p->readidx], blocksize); + } - /* advance the read pointer */ - p->readidx += blocksize; + /* advance the read pointer */ + p->readidx += blocksize; + + /* we now have the initial blocksize bytes decrypted, + * and we can extract packet and padding length from it + */ + p->packet_length = _libssh2_ntohu32(block); + } - /* we now have the initial blocksize bytes decrypted, - * and we can extract packet and padding length from it - */ - p->packet_length = _libssh2_ntohu32(block); if(p->packet_length < 1) { return LIBSSH2_ERROR_DECRYPT; } @@ -445,17 +548,27 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } - p->padding_length = block[4]; - if(p->padding_length > p->packet_length - 1) { - return LIBSSH2_ERROR_DECRYPT; + if(etm) { + /* we collect entire undecrypted packet including the + packet length field that we run MAC over */ + total_num = 4 + p->packet_length + + session->remote.mac->mac_len; } + else { + /* padding_length has not been authenticated yet, but it won't + actually be used (except for the sanity check immediately + following) until after the entire packet is authenticated, + so this is safe. */ + p->padding_length = block[4]; + if(p->padding_length > p->packet_length - 1) { + return LIBSSH2_ERROR_DECRYPT; + } - - /* total_num is the number of bytes following the initial - (5 bytes) packet length and padding length fields */ - total_num = - p->packet_length - 1 + - (encrypted ? session->remote.mac->mac_len : 0); + /* total_num is the number of bytes following the initial + (5 bytes) packet length and padding length fields */ + total_num = p->packet_length - 1 + + (encrypted ? session->remote.mac->mac_len : 0); + } /* RFC4253 section 6.1 Maximum Packet Length says: * @@ -465,7 +578,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) * or less (including length, padding length, payload, * padding, and MAC.)." */ - if(total_num > LIBSSH2_PACKET_MAXPAYLOAD) { + if(total_num > LIBSSH2_PACKET_MAXPAYLOAD || total_num == 0) { return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } @@ -479,15 +592,21 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) /* init write pointer to start of payload buffer */ p->wptr = p->payload; - if(blocksize > 5) { + if(!etm && blocksize > 5) { /* copy the data from index 5 to the end of the blocksize from the temporary buffer to the start of the decrypted buffer */ if(blocksize - 5 <= (int) total_num) { memcpy(p->wptr, &block[5], blocksize - 5); p->wptr += blocksize - 5; /* advance write pointer */ + if(etm) { + /* advance past unencrypted packet length */ + p->wptr += 4; + } } else { + if(p->payload) + LIBSSH2_FREE(session, p->payload); return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } } @@ -497,7 +616,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) p->data_num = p->wptr - p->payload; /* we already dealt with a blocksize worth of data */ - numbytes -= blocksize; + if(!etm) + numbytes -= blocksize; } /* how much there is left to add to the current payload @@ -510,42 +630,60 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) numbytes = remainpack; } - if(encrypted) { + if(encrypted && !etm) { /* At the end of the incoming stream, there is a MAC, and we don't want to decrypt that since we need it "raw". We MUST however decrypt the padding data since it is used for the hash later on. */ int skip = session->remote.mac->mac_len; + if(CRYPT_FLAG_R(session, INTEGRATED_MAC)) + /* This crypto method DOES need the MAC to go through + decryption so it can be authenticated. */ + skip = 0; + /* if what we have plus numbytes is bigger than the total minus the skip margin, we should lower the amount to decrypt even more */ - if((p->data_num + numbytes) > (p->total_num - skip)) { - numdecrypt = (p->total_num - skip) - p->data_num; + if((p->data_num + numbytes) >= (p->total_num - skip)) { + /* decrypt the entire rest of the package */ + numdecrypt = LIBSSH2_MAX(0, + (int)(p->total_num - skip) - (int)p->data_num); + firstlast = LAST_BLOCK; } else { - int frac; + ssize_t frac; numdecrypt = numbytes; frac = numdecrypt % blocksize; if(frac) { - /* not an aligned amount of blocks, - align it */ + /* not an aligned amount of blocks, align it by reducing + the number of bytes processed this loop */ numdecrypt -= frac; /* and make it no unencrypted data after it */ numbytes = 0; } + if(CRYPT_FLAG_R(session, INTEGRATED_MAC)) { + /* Make sure that we save enough bytes to make the last + * block large enough to hold the entire integrated MAC */ + numdecrypt = LIBSSH2_MIN(numdecrypt, + (int)(p->total_num - skip - blocksize - p->data_num)); + numbytes = 0; + } + firstlast = MIDDLE_BLOCK; } } else { /* unencrypted data should not be decrypted at all */ numdecrypt = 0; } + assert(numdecrypt >= 0); /* if there are bytes to decrypt, do that */ if(numdecrypt > 0) { /* now decrypt the lot */ - rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt); + rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt, + firstlast); if(rc != LIBSSH2_ERROR_NONE) { p->total_num = 0; /* no packet buffer available */ return rc; @@ -562,14 +700,16 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) numbytes -= numdecrypt; } - /* if there are bytes to copy that aren't decrypted, simply + /* if there are bytes to copy that aren't decrypted, copy them as-is to the target buffer */ if(numbytes > 0) { - if(numbytes <= (int)(p->total_num - (p->wptr - p->payload))) { + if((size_t)numbytes <= (p->total_num - (p->wptr - p->payload))) { memcpy(p->wptr, &p->buf[p->readidx], numbytes); } else { + if(p->payload) + LIBSSH2_FREE(session, p->payload); return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } @@ -587,13 +727,13 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) if(!remainpack) { /* we have a full packet */ - libssh2_transport_read_point1: +libssh2_transport_read_point1: rc = fullpacket(session, encrypted); if(rc == LIBSSH2_ERROR_EAGAIN) { if(session->packAdd_state != libssh2_NB_state_idle) { /* fullpacket only returns LIBSSH2_ERROR_EAGAIN if - * libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If + * libssh2_packet_add() returns LIBSSH2_ERROR_EAGAIN. If * that returns LIBSSH2_ERROR_EAGAIN but the packAdd_state * is idle, then the packet has been added to the brigade, * but some immediate action that was taken based on the @@ -637,7 +777,8 @@ send_existing(LIBSSH2_SESSION *session, const unsigned char *data, we don't add this one up until the previous one has been sent. To make the caller really notice his/hers flaw, we return error for this case */ - return LIBSSH2_ERROR_BAD_USE; + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Address is different, but will resume nonetheless")); } *ret = 1; /* set to make our parent return */ @@ -646,14 +787,14 @@ send_existing(LIBSSH2_SESSION *session, const unsigned char *data, length = p->ototal_num - p->osent; rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); + LIBSSH2_SOCKET_SEND_FLAGS(session)); if(rc < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", length, -rc); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error sending %d bytes: %d", length, -rc)); else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p+%d", rc, length, p->outbuf, - p->osent); + p->osent)); debugdump(session, "libssh2_transport_write send()", &p->outbuf[p->osent], rc); } @@ -708,20 +849,22 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, int blocksize = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8; - int padding_length; + ssize_t padding_length; size_t packet_length; - int total_length; -#ifdef RANDOM_PADDING + ssize_t total_length; +#ifdef LIBSSH2_RANDOM_PADDING int rand_max; int seed = data[0]; /* FIXME: make this random */ #endif struct transportpacket *p = &session->packet; int encrypted; int compressed; + int etm; ssize_t ret; int rc; const unsigned char *orgdata = data; size_t orgdata_len = data_len; + size_t crypt_offset, etm_crypt_offset; /* * If the last read operation was interrupted in the middle of a key @@ -734,8 +877,8 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { /* Don't write any new packets if we're still in the middle of a key * exchange. */ - _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" - " key re-exchange from _libssh2_transport_send"); + _libssh2_debug((session, LIBSSH2_TRACE_TRANS, "Redirecting into the" + " key re-exchange from _libssh2_transport_send")); rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); if(rc) return rc; @@ -746,7 +889,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, debugdump(session, "libssh2_transport_write plain2", data2, data2_len); /* FIRST, check if we have a pending write to complete. send_existing - only sanity-check data and data_len and not data2 and data2_len!! */ + only sanity-check data and data_len and not data2 and data2_len! */ rc = send_existing(session, data, data_len, &ret); if(rc) return rc; @@ -759,13 +902,14 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0; - compressed = - session->local.comp != NULL && - session->local.comp->compress && - ((session->state & LIBSSH2_STATE_AUTHENTICATED) || - session->local.comp->use_in_auth); + etm = encrypted && session->local.mac ? session->local.mac->etm : 0; - if(encrypted && compressed) { + compressed = session->local.comp && + session->local.comp->compress && + ((session->state & LIBSSH2_STATE_AUTHENTICATED) || + session->local.comp->use_in_auth); + + if(encrypted && compressed && session->local.comp_abstract) { /* the idea here is that these function must fail if the output gets larger than what fits in the assigned buffer so thus they don't check the input size as we don't know how much it compresses */ @@ -821,12 +965,17 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, packet_length = data_len + 1 + 4; /* 1 is for padding_length field 4 for the packet_length field */ + /* subtract 4 bytes of the packet_length field when padding AES-GCM + or with ETM */ + crypt_offset = (etm || (encrypted && CRYPT_FLAG_R(session, PKTLEN_AAD))) + ? 4 : 0; + etm_crypt_offset = etm ? 4 : 0; /* at this point we have it all except the padding */ /* first figure out our minimum padding amount to make it an even block size */ - padding_length = blocksize - (packet_length % blocksize); + padding_length = blocksize - ((packet_length - crypt_offset) % blocksize); /* if the padding becomes too small we add another blocksize worth of it (taken from the original libssh2 where it didn't have any @@ -834,7 +983,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, if(padding_length < 4) { padding_length += blocksize; } -#ifdef RANDOM_PADDING +#ifdef LIBSSH2_RANDOM_PADDING /* FIXME: we can add padding here, but that also makes the packets bigger etc */ @@ -853,12 +1002,15 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, /* store packet_length, which is the size of the whole packet except the MAC and the packet_length field itself */ - _libssh2_htonu32(p->outbuf, packet_length - 4); + _libssh2_htonu32(p->outbuf, (uint32_t)(packet_length - 4)); /* store padding_length */ p->outbuf[4] = (unsigned char)padding_length; /* fill the padding area with random junk */ - _libssh2_random(p->outbuf + 5 + data_len, padding_length); + if(_libssh2_random(p->outbuf + 5 + data_len, padding_length)) { + return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN, + "Unable to get random bytes for packet padding"); + } if(encrypted) { size_t i; @@ -866,33 +1018,90 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, /* Calculate MAC hash. Put the output at index packet_length, since that size includes the whole packet. The MAC is calculated on the entire unencrypted packet, including all - fields except the MAC field itself. */ - session->local.mac->hash(session, p->outbuf + packet_length, - session->local.seqno, p->outbuf, - packet_length, NULL, 0, - &session->local.mac_abstract); + fields except the MAC field itself. This is skipped in the + INTEGRATED_MAC case, where the crypto algorithm also does its + own hash. */ + if(!etm && !CRYPT_FLAG_R(session, INTEGRATED_MAC)) { + session->local.mac->hash(session, p->outbuf + packet_length, + session->local.seqno, p->outbuf, + packet_length, NULL, 0, + &session->local.mac_abstract); + } /* Encrypt the whole packet data, one block size at a time. - The MAC field is not encrypted. */ - for(i = 0; i < packet_length; i += session->local.crypt->blocksize) { + The MAC field is not encrypted unless INTEGRATED_MAC. */ + /* Some crypto back-ends could handle a single crypt() call for + encryption, but (presumably) others cannot, so break it up + into blocksize-sized chunks to satisfy them all. */ + for(i = etm_crypt_offset; i < packet_length; + i += session->local.crypt->blocksize) { unsigned char *ptr = &p->outbuf[i]; + size_t bsize = LIBSSH2_MIN(session->local.crypt->blocksize, + (int)(packet_length-i)); + /* The INTEGRATED_MAC case always has an extra call below, so it + will never be LAST_BLOCK up here. */ + int firstlast = i == 0 ? FIRST_BLOCK : + (!CRYPT_FLAG_L(session, INTEGRATED_MAC) + && (i == packet_length - session->local.crypt->blocksize) + ? LAST_BLOCK: MIDDLE_BLOCK); + /* In the AAD case, the last block would be only 4 bytes because + everything is offset by 4 since the initial packet_length isn't + encrypted. In this case, combine that last short packet with the + previous one since AES-GCM crypt() assumes that the entire MAC + is available in that packet so it can set that to the + authentication tag. */ + if(!CRYPT_FLAG_L(session, INTEGRATED_MAC)) + if(i > packet_length - 2*bsize) { + /* increase the final block size */ + bsize = packet_length - i; + /* advance the loop counter by the extra amount */ + i += bsize - session->local.crypt->blocksize; + } + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "crypting bytes %d-%d", i, + i + session->local.crypt->blocksize - 1)); if(session->local.crypt->crypt(session, ptr, - session->local.crypt->blocksize, - &session->local.crypt_abstract)) + bsize, + &session->local.crypt_abstract, + firstlast)) + return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ + } + /* Call crypt() one last time so it can be filled in with the MAC */ + if(CRYPT_FLAG_L(session, INTEGRATED_MAC)) { + int authlen = session->local.mac->mac_len; + assert((size_t)total_length <= + packet_length + session->local.crypt->blocksize); + if(session->local.crypt->crypt(session, &p->outbuf[packet_length], + authlen, + &session->local.crypt_abstract, + LAST_BLOCK)) return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ } + + if(etm) { + /* Calculate MAC hash. Put the output at index packet_length, + since that size includes the whole packet. The MAC is + calculated on the entire packet (length plain the rest + encrypted), including all fields except the MAC field + itself. */ + session->local.mac->hash(session, p->outbuf + packet_length, + session->local.seqno, p->outbuf, + packet_length, NULL, 0, + &session->local.mac_abstract); + } } session->local.seqno++; ret = LIBSSH2_SEND(session, p->outbuf, total_length, - LIBSSH2_SOCKET_SEND_FLAGS(session)); + LIBSSH2_SOCKET_SEND_FLAGS(session)); if(ret < 0) - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, - "Error sending %d bytes: %d", total_length, -ret); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Error sending %d bytes: %d", total_length, -ret)); else { - _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p", - ret, total_length, p->outbuf); + _libssh2_debug((session, LIBSSH2_TRACE_SOCKET, + "Sent %d/%d bytes at %p", + ret, total_length, p->outbuf)); debugdump(session, "libssh2_transport_write send()", p->outbuf, ret); } diff --git a/libs/libssh2/src/transport.h b/libs/libssh2/src/transport.h index 89982a67f0..64482290ee 100644 --- a/libs/libssh2/src/transport.h +++ b/libs/libssh2/src/transport.h @@ -1,9 +1,8 @@ #ifndef __LIBSSH2_TRANSPORT_H #define __LIBSSH2_TRANSPORT_H - -/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009-2010 by Daniel Stenberg - * Author: Daniel Stenberg <daniel@haxx.se> +/* Copyright (C) The Written Word, Inc. + * Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -39,12 +38,13 @@ * OF SUCH DAMAGE. * * This file handles reading and writing to the SECSH transport layer. RFC4253. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include "packet.h" - /* * libssh2_transport_send * diff --git a/libs/libssh2/src/userauth.c b/libs/libssh2/src/userauth.c index 949dc1c660..e7578759f3 100644 --- a/libs/libssh2/src/userauth.c +++ b/libs/libssh2/src/userauth.c @@ -1,6 +1,6 @@ -/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net> - * Copyright (c) 2009-2014 by Daniel Stenberg +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Mikhail Gusarov <dottedmag@dottedmag.net> + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -35,14 +35,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" #include <ctype.h> -#include <stdio.h> - -#include <assert.h> /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H @@ -52,8 +51,9 @@ #include "transport.h" #include "session.h" #include "userauth.h" +#include "userauth_kbd_packet.h" -/* libssh2_userauth_list +/* userauth_list * * List authentication methods * Will yield successful login if "none" happens to be allowable for this user @@ -63,11 +63,13 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len) { - static const unsigned char reply_codes[3] = - { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; + unsigned char reply_codes[4] = + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, + SSH_MSG_USERAUTH_BANNER, 0 }; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" + method_len(4) = 27 */ unsigned long methods_len; + unsigned int banner_len; unsigned char *s; int rc; @@ -134,6 +136,57 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, return NULL; } + if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_BANNER) { + if(session->userauth_list_data_len < 5) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unexpected packet size"); + return NULL; + } + banner_len = _libssh2_ntohu32(session->userauth_list_data + 1); + if(banner_len > session->userauth_list_data_len - 5) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Unexpected userauth banner size"); + return NULL; + } + session->userauth_banner = LIBSSH2_ALLOC(session, banner_len + 1); + if(!session->userauth_banner) { + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for userauth_banner"); + return NULL; + } + memcpy(session->userauth_banner, session->userauth_list_data + 5, + banner_len); + session->userauth_banner[banner_len] = '\0'; + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Banner: %s", + session->userauth_banner)); + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + /* SSH_MSG_USERAUTH_BANNER has been handled */ + reply_codes[2] = 0; + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_list_data, + &session->userauth_list_data_len, 0, + NULL, 0, + &session->userauth_list_packet_requirev_state); + if(rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting userauth list"); + return NULL; + } + else if(rc || (session->userauth_list_data_len < 1)) { + _libssh2_error(session, rc, "Failed getting response"); + session->userauth_list_state = libssh2_NB_state_idle; + return NULL; + } + } + if(session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) { /* Wow, who'dve thought... */ _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error"); @@ -163,13 +216,13 @@ static char *userauth_list(LIBSSH2_SESSION *session, const char *username, memmove(session->userauth_list_data, session->userauth_list_data + 5, methods_len); session->userauth_list_data[methods_len] = '\0'; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Permitted auth methods: %s", - session->userauth_list_data); + session->userauth_list_data)); } session->userauth_list_state = libssh2_NB_state_idle; - return (char *) session->userauth_list_data; + return (char *)session->userauth_list_data; } /* libssh2_userauth_list @@ -189,6 +242,30 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, return ptr; } +/* libssh2_userauth_banner + * + * Retrieve banner message from server, if available. + * When no such message is sent by server or if no authentication attempt has + * been made, this function returns LIBSSH2_ERROR_MISSING_AUTH_BANNER. + */ +LIBSSH2_API int +libssh2_userauth_banner(LIBSSH2_SESSION *session, char **banner) +{ + if(!session) + return LIBSSH2_ERROR_MISSING_USERAUTH_BANNER; + + if(!session->userauth_banner) { + return _libssh2_error(session, + LIBSSH2_ERROR_MISSING_USERAUTH_BANNER, + "Missing userauth banner"); + } + + if(banner) + *banner = session->userauth_banner; + + return LIBSSH2_ERROR_NONE; +} + /* * libssh2_userauth_authenticated * @@ -198,7 +275,7 @@ libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION * session) { - return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0; + return (session->state & LIBSSH2_STATE_AUTHENTICATED) ? 1 : 0; } @@ -251,8 +328,8 @@ userauth_password(LIBSSH2_SESSION *session, _libssh2_store_u32(&s, password_len); /* 'password' is sent separately */ - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting to login using password authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting to login using password authentication")); session->userauth_pswd_state = libssh2_NB_state_created; } @@ -279,7 +356,7 @@ userauth_password(LIBSSH2_SESSION *session, session->userauth_pswd_state = libssh2_NB_state_sent; } - password_response: +password_response: if((session->userauth_pswd_state == libssh2_NB_state_sent) || (session->userauth_pswd_state == libssh2_NB_state_sent1) @@ -306,8 +383,8 @@ userauth_password(LIBSSH2_SESSION *session, } if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password authentication successful")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; session->state |= LIBSSH2_STATE_AUTHENTICATED; @@ -316,8 +393,8 @@ userauth_password(LIBSSH2_SESSION *session, } else if(session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password authentication failed"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password authentication failed")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; session->userauth_pswd_state = libssh2_NB_state_idle; @@ -348,8 +425,8 @@ userauth_password(LIBSSH2_SESSION *session, if((session->userauth_pswd_state == libssh2_NB_state_sent1) || (session->userauth_pswd_state == libssh2_NB_state_sent2)) { if(session->userauth_pswd_state == libssh2_NB_state_sent1) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Password change required"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Password change required")); LIBSSH2_FREE(session, session->userauth_pswd_data); session->userauth_pswd_data = NULL; } @@ -490,7 +567,7 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, { unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; size_t pubkey_len = pubkeyfiledata_len; - unsigned int tmp_len; + size_t tmp_len; if(pubkeyfiledata_len <= 1) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, @@ -518,7 +595,7 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, } sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { + if(!sp1) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data"); @@ -527,16 +604,17 @@ memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, sp1++; sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey)); - if(sp2 == NULL) { + if(!sp2) { /* Assume that the id string is missing, but that it's okay */ sp2 = pubkey + pubkey_len; } - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { + if(_libssh2_base64_decode(session, (char **)&tmp, &tmp_len, + (const char *)sp1, + sp2 - sp1)) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Invalid key data, not base64 encoded"); + "Invalid key data, not base64 encoded"); } /* Wasting some bytes here (okay, more than some), but since it's likely @@ -573,10 +651,10 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, char c; unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; size_t pubkey_len = 0, sp_len; - unsigned int tmp_len; + size_t tmp_len; - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", - pubkeyfile); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", + pubkeyfile)); /* Read Public Key */ fd = fopen(pubkeyfile, FOPEN_READTEXT); if(!fd) { @@ -621,7 +699,7 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, } sp1 = memchr(pubkey, ' ', pubkey_len); - if(sp1 == NULL) { + if(!sp1) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data"); @@ -629,15 +707,16 @@ file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, sp1++; - sp_len = sp1 > pubkey ? (sp1 - pubkey) - 1 : 0; + sp_len = sp1 > pubkey ? (sp1 - pubkey) : 0; sp2 = memchr(sp1, ' ', pubkey_len - sp_len); - if(sp2 == NULL) { + if(!sp2) { /* Assume that the id string is missing, but that it's okay */ sp2 = pubkey + pubkey_len; } - if(libssh2_base64_decode(session, (char **) &tmp, &tmp_len, - (char *) sp1, sp2 - sp1)) { + if(_libssh2_base64_decode(session, (char **)&tmp, &tmp_len, + (const char *)sp1, + sp2 - sp1)) { LIBSSH2_FREE(session, pubkey); return _libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid key data, not base64 encoded"); @@ -659,7 +738,7 @@ static int memory_read_privatekey(LIBSSH2_SESSION * session, const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, void **hostkey_abstract, - const unsigned char *method, int method_len, + const unsigned char *method, size_t method_len, const char *privkeyfiledata, size_t privkeyfiledata_len, const char *passphrase) { @@ -687,7 +766,7 @@ memory_read_privatekey(LIBSSH2_SESSION * session, (unsigned char *) passphrase, hostkey_abstract)) { return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to initialize private key from file"); + "Unable to initialize private key from memory"); } return 0; @@ -700,14 +779,14 @@ static int file_read_privatekey(LIBSSH2_SESSION * session, const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, void **hostkey_abstract, - const unsigned char *method, int method_len, + const unsigned char *method, size_t method_len, const char *privkeyfile, const char *passphrase) { const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods(); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s", - privkeyfile); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Loading private key file: %s", privkeyfile)); *hostkey_method = NULL; *hostkey_abstract = NULL; while(*hostkey_methods_avail && (*hostkey_methods_avail)->name) { @@ -763,7 +842,7 @@ sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, datavec.iov_len = data_len; if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { + &hostkey_abstract)) { if(privkeyobj->dtor) { privkeyobj->dtor(session, &hostkey_abstract); } @@ -799,7 +878,7 @@ sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, datavec.iov_len = data_len; if(privkeyobj->signv(session, sig, sig_len, 1, &datavec, - &hostkey_abstract)) { + &hostkey_abstract)) { if(privkeyobj->dtor) { privkeyobj->dtor(session, &hostkey_abstract); } @@ -812,7 +891,106 @@ sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, return 0; } +int +libssh2_sign_sk(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, + const unsigned char *data, size_t data_len, void **abstract) +{ + int rc = LIBSSH2_ERROR_DECRYPT; + LIBSSH2_PRIVKEY_SK *sk_info = (LIBSSH2_PRIVKEY_SK *) (*abstract); + LIBSSH2_SK_SIG_INFO sig_info = { 0 }; + if(sk_info->handle_len <= 0) { + return LIBSSH2_ERROR_DECRYPT; + } + + rc = sk_info->sign_callback(session, + &sig_info, + data, + data_len, + sk_info->algorithm, + sk_info->flags, + sk_info->application, + sk_info->key_handle, + sk_info->handle_len, + sk_info->orig_abstract); + + if(rc == 0 && sig_info.sig_r_len > 0 && sig_info.sig_r) { + unsigned char *p = NULL; + + if(sig_info.sig_s_len > 0 && sig_info.sig_s) { + /* sig length, sig_r, sig_s, flags, counter, plus 4 bytes for each + component's length, and up to 1 extra byte for each component */ + *sig_len = 4 + 5 + sig_info.sig_r_len + 5 + sig_info.sig_s_len + 5; + *sig = LIBSSH2_ALLOC(session, *sig_len); + + if(*sig) { + unsigned char *x = *sig; + p = *sig; + + _libssh2_store_u32(&p, 0); + + _libssh2_store_bignum2_bytes(&p, + sig_info.sig_r, + sig_info.sig_r_len); + + _libssh2_store_bignum2_bytes(&p, + sig_info.sig_s, + sig_info.sig_s_len); + + *sig_len = p - *sig; + + _libssh2_store_u32(&x, (uint32_t)(*sig_len - 4)); + } + else { + _libssh2_debug((session, + LIBSSH2_ERROR_ALLOC, + "Unable to allocate ecdsa-sk signature.")); + rc = LIBSSH2_ERROR_ALLOC; + } + } + else { + /* sig, flags, counter, plus 4 bytes for sig length. */ + *sig_len = 4 + sig_info.sig_r_len + 1 + 4; + *sig = LIBSSH2_ALLOC(session, *sig_len); + + if(*sig) { + p = *sig; + + _libssh2_store_str(&p, + (const char *)sig_info.sig_r, + sig_info.sig_r_len); + } + else { + _libssh2_debug((session, + LIBSSH2_ERROR_ALLOC, + "Unable to allocate ed25519-sk signature.")); + rc = LIBSSH2_ERROR_ALLOC; + } + } + + if(p) { + *p = sig_info.flags; + ++p; + _libssh2_store_u32(&p, sig_info.counter); + + *sig_len = p - *sig; + } + + LIBSSH2_FREE(session, sig_info.sig_r); + + if(sig_info.sig_s) { + LIBSSH2_FREE(session, sig_info.sig_s); + } + } + else { + _libssh2_debug((session, + LIBSSH2_ERROR_DECRYPT, + "sign_callback failed or returned invalid signature.")); + *sig_len = 0; + } + + return rc; +} /* userauth_hostbased_fromfile * Authenticate using a keypair found in the named files @@ -828,11 +1006,6 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, { int rc; -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - if(session->userauth_host_state == libssh2_NB_state_idle) { const LIBSSH2_HOSTKEY_METHOD *privkeyobj; unsigned char *pubkeydata = NULL; @@ -863,7 +1036,7 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, &pubkeydata, &pubkeydata_len, privatekey, passphrase); if(rc) - /* libssh2_pub_priv_keyfile calls _libssh2_error() */ + /* libssh2_pub_priv_keyfile() calls _libssh2_error() */ return rc; } @@ -932,8 +1105,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, datavec[2].iov_len = session->userauth_host_packet_len; if(privkeyobj && privkeyobj->signv && - privkeyobj->signv(session, &sig, &sig_len, 3, - datavec, &abstract)) { + privkeyobj->signv(session, &sig, &sig_len, 3, + datavec, &abstract)) { LIBSSH2_FREE(session, session->userauth_host_method); session->userauth_host_method = NULL; LIBSSH2_FREE(session, session->userauth_host_packet); @@ -972,8 +1145,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, session->userauth_host_packet + session->userauth_host_packet_len; _libssh2_store_u32(&session->userauth_host_s, - 4 + session->userauth_host_method_len + - 4 + sig_len); + (uint32_t)(4 + session->userauth_host_method_len + + 4 + sig_len)); _libssh2_store_str(&session->userauth_host_s, (const char *)session->userauth_host_method, session->userauth_host_method_len); @@ -984,8 +1157,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, sig_len); LIBSSH2_FREE(session, sig); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting hostbased authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting hostbased authentication")); session->userauth_host_state = libssh2_NB_state_created; } @@ -1033,8 +1206,8 @@ userauth_hostbased_fromfile(LIBSSH2_SESSION *session, } if(session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Hostbased authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Hostbased authentication successful")); /* We are us and we've proved it. */ LIBSSH2_FREE(session, session->userauth_host_data); session->userauth_host_data = NULL; @@ -1075,14 +1248,196 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, return rc; } +size_t plain_method(char *method, size_t method_len) +{ + if(!strncmp("ssh-rsa-cert-v01@openssh.com", + method, + method_len)) { + return 7; + } + + if(!strncmp("ecdsa-sha2-nistp256-cert-v01@openssh.com", + method, + method_len) || + !strncmp("ecdsa-sha2-nistp384-cert-v01@openssh.com", + method, + method_len) || + !strncmp("ecdsa-sha2-nistp521-cert-v01@openssh.com", + method, + method_len)) { + return 19; + } + + if(!strncmp("ssh-ed25519-cert-v01@openssh.com", + method, + method_len)) { + return 11; + } + + if(!strncmp("sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", + method, + method_len)) { + const char *new_method = "sk-ecdsa-sha2-nistp256@openssh.com"; + memcpy(method, new_method, strlen(new_method)); + return strlen(new_method); + } + + if(!strncmp("sk-ssh-ed25519-cert-v01@openssh.com", + method, + method_len)) { + const char *new_method = "sk-ssh-ed25519@openssh.com"; + memcpy(method, new_method, strlen(new_method)); + return strlen(new_method); + } + + return method_len; +} + +/** + * @function _libssh2_key_sign_algorithm + * @abstract Upgrades the algorithm used for public key signing RFC 8332 + * @discussion Based on the incoming key_method value, this function + * will upgrade the key method input based on user preferences, + * server support algos and crypto backend support + * @related _libssh2_supported_key_sign_algorithms() + * @param key_method current key method, usually the default key sig method + * @param key_method_len length of the key method buffer + * @result error code or zero on success + */ + +static int +_libssh2_key_sign_algorithm(LIBSSH2_SESSION *session, + unsigned char **key_method, + size_t *key_method_len) +{ + const char *s = NULL; + const char *a = NULL; + const char *match = NULL; + const char *p = NULL; + const char *f = NULL; + char *i = NULL; + size_t p_len = 0; + size_t f_len = 0; + int rc = 0; + size_t match_len = 0; + char *filtered_algs = NULL; + + const char *supported_algs = + _libssh2_supported_key_sign_algorithms(session, + *key_method, + *key_method_len); + + if(!supported_algs || !session->server_sign_algorithms) { + /* no upgrading key algorithm supported, do nothing */ + return LIBSSH2_ERROR_NONE; + } + + filtered_algs = LIBSSH2_ALLOC(session, strlen(supported_algs) + 1); + if(!filtered_algs) { + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate filtered algs"); + return rc; + } + + s = session->server_sign_algorithms; + i = filtered_algs; + + /* this walks the server algo list and the supported algo list and creates + a filtered list that includes matches */ + + while(s && *s) { + p = strchr(s, ','); + p_len = (p ? (size_t)(p - s) : strlen(s)); + a = supported_algs; + + while(a && *a) { + f = strchr(a, ','); + f_len = (f ? (size_t)(f - a) : strlen(a)); + + if(f_len == p_len && memcmp(a, s, p_len) == 0) { + + if(i != filtered_algs) { + memcpy(i, ",", 1); + i += 1; + } + + memcpy(i, s, p_len); + i += p_len; + } + + a = f ? (f + 1) : NULL; + } + + s = p ? (p + 1) : NULL; + } + + filtered_algs[i - filtered_algs] = '\0'; + if(session->sign_algo_prefs) { + s = session->sign_algo_prefs; + } + else { + s = supported_algs; + } + + /* now that we have the possible supported algos, match based on the prefs + or what is supported by the crypto backend, look for a match */ + + while(s && *s && !match) { + p = strchr(s, ','); + p_len = (p ? (size_t)(p - s) : strlen(s)); + a = filtered_algs; + + while(a && *a && !match) { + f = strchr(a, ','); + f_len = (f ? (size_t)(f - a) : strlen(a)); + + if(f_len == p_len && memcmp(a, s, p_len) == 0) { + /* found a match, upgrade key method */ + match = s; + match_len = p_len; + } + else { + a = f ? (f + 1) : NULL; + } + } + + s = p ? (p + 1) : NULL; + } + + if(match) { + if(*key_method) + LIBSSH2_FREE(session, *key_method); + + *key_method = LIBSSH2_ALLOC(session, match_len); + if(key_method) { + memcpy(*key_method, match, match_len); + *key_method_len = match_len; + } + else { + *key_method_len = 0; + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate key method upgrade"); + } + } + else { + /* no match was found */ + rc = _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, + "No signing signature matched"); + } + + if(filtered_algs) + LIBSSH2_FREE(session, filtered_algs); + + return rc; +} int _libssh2_userauth_publickey(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len, + size_t username_len, const unsigned char *pubkeydata, - unsigned long pubkeydata_len, + size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC ((*sign_callback)), void *abstract) @@ -1093,6 +1448,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, }; int rc; unsigned char *s; + int auth_attempts = 0; + +retry_auth: + auth_attempts++; if(session->userauth_pblc_state == libssh2_NB_state_idle) { @@ -1118,9 +1477,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata); if(session->userauth_pblc_method_len > pubkeydata_len - 4) - /* the method length simply cannot be longer than the entire - passed in data, so we use this to detect crazy input - data */ + /* the method length cannot be longer than the entire passed + in data, so we use this to detect crazy input data */ return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid public key"); @@ -1135,15 +1493,27 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, memcpy(session->userauth_pblc_method, pubkeydata + 4, session->userauth_pblc_method_len); } - /* - * The length of the method name read from plaintext prefix in the - * file must match length embedded in the key. - * TODO: The data should match too but we don't check that. Should we? - */ - else if(session->userauth_pblc_method_len != - _libssh2_ntohu32(pubkeydata)) - return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, - "Invalid public key"); + + /* upgrade key signing algo if it is supported and + * it is our first auth attempt, otherwise fallback to + * the key default algo */ + if(auth_attempts == 1) { + rc = _libssh2_key_sign_algorithm(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len); + + if(rc) + return rc; + } + + if(session->userauth_pblc_method_len && + session->userauth_pblc_method) { + _libssh2_debug((session, + LIBSSH2_TRACE_KEX, + "Signing using %.*s", + session->userauth_pblc_method_len, + session->userauth_pblc_method)); + } /* * 45 = packet_type(1) + username_len(4) + servicename_len(4) + @@ -1189,8 +1559,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, session->userauth_pblc_method_len); _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication")); session->userauth_pblc_state = libssh2_NB_state_created; } @@ -1237,8 +1607,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, } if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Pubkey authentication prematurely successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Pubkey authentication prematurely successful")); /* * God help any SSH server that allows an UNVERIFIED * public key to validate the user @@ -1301,6 +1671,17 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); } + else if(rc == LIBSSH2_ERROR_ALGO_UNSUPPORTED && auth_attempts == 1) { + /* try again with the default key algo */ + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + + rc = LIBSSH2_ERROR_NONE; + goto retry_auth; + } else if(rc) { LIBSSH2_FREE(session, session->userauth_pblc_method); session->userauth_pblc_method = NULL; @@ -1340,20 +1721,40 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, s = session->userauth_pblc_packet + session->userauth_pblc_packet_len; session->userauth_pblc_b = NULL; - _libssh2_store_u32(&s, - 4 + session->userauth_pblc_method_len + 4 + - sig_len); - _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, - session->userauth_pblc_method_len); + session->userauth_pblc_method_len = + plain_method((char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + + if(strncmp((const char *)session->userauth_pblc_method, + "sk-ecdsa-sha2-nistp256@openssh.com", + session->userauth_pblc_method_len) == 0 || + strncmp((const char *)session->userauth_pblc_method, + "sk-ssh-ed25519@openssh.com", + session->userauth_pblc_method_len) == 0) { + _libssh2_store_u32(&s, + (uint32_t)(4 + session->userauth_pblc_method_len + + sig_len)); + _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + memcpy(s, sig, sig_len); + s += sig_len; + } + else { + _libssh2_store_u32(&s, + (uint32_t)(4 + session->userauth_pblc_method_len + + 4 + sig_len)); + _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + _libssh2_store_str(&s, (const char *)sig, sig_len); + } LIBSSH2_FREE(session, session->userauth_pblc_method); session->userauth_pblc_method = NULL; - _libssh2_store_str(&s, (const char *)sig, sig_len); LIBSSH2_FREE(session, sig); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting publickey authentication -- phase 2"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication -- phase 2")); session->userauth_pblc_s = s; session->userauth_pblc_state = libssh2_NB_state_sent2; @@ -1399,8 +1800,8 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, } if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Publickey authentication successful"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Publickey authentication successful")); /* We are us and we've proved it. */ LIBSSH2_FREE(session, session->userauth_pblc_data); session->userauth_pblc_data = NULL; @@ -1418,10 +1819,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, "username/public key combination"); } - /* - * userauth_publickey_frommemory - * Authenticate using a keypair from memory - */ +/* + * userauth_publickey_frommemory + * Authenticate using a keypair from memory + */ static int userauth_publickey_frommemory(LIBSSH2_SESSION *session, const char *username, @@ -1438,11 +1839,6 @@ userauth_publickey_frommemory(LIBSSH2_SESSION *session, void *abstract = &privkey_file; int rc; -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - privkey_file.filename = privatekeydata; privkey_file.passphrase = passphrase; @@ -1457,15 +1853,14 @@ userauth_publickey_frommemory(LIBSSH2_SESSION *session, } else if(privatekeydata_len && privatekeydata) { /* Compute public key from private key. */ - if(_libssh2_pub_priv_keyfilememory(session, + rc = _libssh2_pub_priv_keyfilememory(session, &session->userauth_pblc_method, &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len, privatekeydata, privatekeydata_len, - passphrase)) - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to extract public key " - "from private key."); + passphrase); + if(rc) + return rc; } else { return _libssh2_error(session, LIBSSH2_ERROR_FILE, @@ -1500,11 +1895,6 @@ userauth_publickey_fromfile(LIBSSH2_SESSION *session, void *abstract = &privkey_file; int rc; -#if !LIBSSH2_RSA - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "RSA is not supported by crypto backend"); -#endif - privkey_file.filename = privatekey; privkey_file.passphrase = passphrase; @@ -1554,7 +1944,7 @@ libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, { int rc; - if(NULL == passphrase) + if(!passphrase) /* if given a NULL pointer, make it point to a zero-length string to save us from having to check this all over */ passphrase = ""; @@ -1582,7 +1972,7 @@ libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, { int rc; - if(NULL == passphrase) + if(!passphrase) /* if given a NULL pointer, make it point to a zero-length string to save us from having to check this all over */ passphrase = ""; @@ -1603,7 +1993,7 @@ libssh2_userauth_publickey(LIBSSH2_SESSION *session, const unsigned char *pubkeydata, size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), + ((*sign_callback)), void **abstract) { int rc; @@ -1630,16 +2020,16 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, const char *username, unsigned int username_len, LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) + ((*response_callback))) { unsigned char *s; + int rc; static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 }; - unsigned int language_tag_len; unsigned int i; if(session->userauth_kybd_state == libssh2_NB_state_idle) { @@ -1690,8 +2080,8 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, /* submethods */ _libssh2_store_u32(&s, 0); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Attempting keyboard-interactive authentication"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Attempting keyboard-interactive authentication")); session->userauth_kybd_state = libssh2_NB_state_created; } @@ -1739,9 +2129,9 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Keyboard-interactive " - "authentication successful"); + "authentication successful")); LIBSSH2_FREE(session, session->userauth_kybd_data); session->userauth_kybd_data = NULL; session->state |= LIBSSH2_STATE_AUTHENTICATED; @@ -1750,8 +2140,8 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) { - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, - "Keyboard-interactive authentication failed"); + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, + "Keyboard-interactive authentication failed")); LIBSSH2_FREE(session, session->userauth_kybd_data); session->userauth_kybd_data = NULL; session->userauth_kybd_state = libssh2_NB_state_idle; @@ -1762,230 +2152,34 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, } /* server requested PAM-like conversation */ - s = session->userauth_kybd_data + 1; - - if(session->userauth_kybd_data_len >= 5) { - /* string name (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "to get length"); + if(userauth_keyboard_interactive_decode_info_request(session) + < 0) { goto cleanup; } - if(session->userauth_kybd_auth_name_len) { - session->userauth_kybd_auth_name = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_name_len); - if(!session->userauth_kybd_auth_name) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'name' " - "request field"); - goto cleanup; - } - if(s + session->userauth_list_data_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_name, s, - session->userauth_kybd_auth_name_len); - s += session->userauth_kybd_auth_name_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth name"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string instruction (ISO-10646 UTF-8) */ - session->userauth_kybd_auth_instruction_len = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction length"); - goto cleanup; - } - - if(session->userauth_kybd_auth_instruction_len) { - session->userauth_kybd_auth_instruction = - LIBSSH2_ALLOC(session, - session->userauth_kybd_auth_instruction_len); - if(!session->userauth_kybd_auth_instruction) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive 'instruction' " - "request field"); - goto cleanup; - } - if(s + session->userauth_kybd_auth_instruction_len <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_auth_instruction, s, - session->userauth_kybd_auth_instruction_len); - s += session->userauth_kybd_auth_instruction_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth instruction"); - goto cleanup; - } - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string language tag (as defined in [RFC-3066]) */ - language_tag_len = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag length"); - goto cleanup; - } - - if(s + language_tag_len <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* ignoring this field as deprecated */ - s += language_tag_len; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth language tag"); - goto cleanup; - } - - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* int num-prompts */ - session->userauth_kybd_num_prompts = _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too small" - "for auth num keyboard prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts > 100) { - _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, - "Too many replies for " - "keyboard-interactive prompts"); - goto cleanup; - } - - if(session->userauth_kybd_num_prompts) { - session->userauth_kybd_prompts = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_prompts) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompts array"); - goto cleanup; - } - - session->userauth_kybd_responses = - LIBSSH2_CALLOC(session, - sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * - session->userauth_kybd_num_prompts); - if(!session->userauth_kybd_responses) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive responses array"); - goto cleanup; - } - - for(i = 0; i < session->userauth_kybd_num_prompts; i++) { - if(s + 4 <= session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* string prompt[1] (ISO-10646 UTF-8) */ - session->userauth_kybd_prompts[i].length = - _libssh2_ntohu32(s); - s += 4; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard " - "prompt length"); - goto cleanup; - } - - session->userauth_kybd_prompts[i].text = - LIBSSH2_CALLOC(session, - session->userauth_kybd_prompts[i]. - length); - if(!session->userauth_kybd_prompts[i].text) { - _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for " - "keyboard-interactive prompt message"); - goto cleanup; - } - - if(s + session->userauth_kybd_prompts[i].length <= - session->userauth_kybd_data + - session->userauth_kybd_data_len) { - memcpy(session->userauth_kybd_prompts[i].text, s, - session->userauth_kybd_prompts[i].length); - s += session->userauth_kybd_prompts[i].length; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt"); - goto cleanup; - } - if(s < session->userauth_kybd_data + - session->userauth_kybd_data_len) { - /* boolean echo[1] */ - session->userauth_kybd_prompts[i].echo = *s++; - } - else { - _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, - "userauth keyboard data buffer too " - "small for auth keyboard prompt echo"); - goto cleanup; - } - } - } - - response_callback(session->userauth_kybd_auth_name, - session->userauth_kybd_auth_name_len, + response_callback((const char *)session->userauth_kybd_auth_name, + (int)session->userauth_kybd_auth_name_len, + (const char *) session->userauth_kybd_auth_instruction, - session->userauth_kybd_auth_instruction_len, + (int)session->userauth_kybd_auth_instruction_len, session->userauth_kybd_num_prompts, session->userauth_kybd_prompts, session->userauth_kybd_responses, &session->abstract); - _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + _libssh2_debug((session, LIBSSH2_TRACE_AUTH, "Keyboard-interactive response callback function" - " invoked"); + " invoked")); session->userauth_kybd_packet_len = - 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ - + 4 /* int num-responses */ + 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ + + 4 /* int num-responses */ ; for(i = 0; i < session->userauth_kybd_num_prompts; i++) { /* string response[1] (ISO-10646 UTF-8) */ if(session->userauth_kybd_responses[i].length <= - (SIZE_MAX - 4 - session->userauth_kybd_packet_len) ) { + (SIZE_MAX - 4 - session->userauth_kybd_packet_len)) { session->userauth_kybd_packet_len += 4 + session->userauth_kybd_responses[i].length; } @@ -2040,7 +2234,7 @@ userauth_keyboard_interactive(LIBSSH2_SESSION * session, session->userauth_kybd_auth_failure = 0; } - cleanup: +cleanup: /* * It's safe to clean all the data here, because unallocated pointers * are filled by zeroes @@ -2100,7 +2294,7 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *user, unsigned int user_len, LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC - ((*response_callback))) + ((*response_callback))) { int rc; BLOCK_ADJUST(rc, session, @@ -2108,3 +2302,124 @@ libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, response_callback)); return rc; } + +/* + * libssh2_userauth_publickey_sk + * + * Authenticate using an external callback function + */ +LIBSSH2_API int +libssh2_userauth_publickey_sk(LIBSSH2_SESSION *session, + const char *username, + size_t username_len, + const unsigned char *publickeydata, + size_t publickeydata_len, + const char *privatekeydata, + size_t privatekeydata_len, + const char *passphrase, + LIBSSH2_USERAUTH_SK_SIGN_FUNC + ((*sign_callback)), + void **abstract) +{ + int rc = LIBSSH2_ERROR_NONE; + + unsigned char *tmp_method = NULL; + size_t tmp_method_len = 0; + + unsigned char *tmp_publickeydata = NULL; + size_t tmp_publickeydata_len = 0; + + unsigned char *pubkeydata = NULL; + size_t pubkeydata_len = 0; + + LIBSSH2_PRIVKEY_SK sk_info = { 0 }; + void *sign_abstract = &sk_info; + + sk_info.sign_callback = sign_callback; + sk_info.orig_abstract = abstract; + + if(privatekeydata_len && privatekeydata) { + + if(_libssh2_sk_pub_keyfilememory(session, + &tmp_method, + &tmp_method_len, + &tmp_publickeydata, + &tmp_publickeydata_len, + &(sk_info.algorithm), + &(sk_info.flags), + &(sk_info.application), + &(sk_info.key_handle), + &(sk_info.handle_len), + privatekeydata, privatekeydata_len, + passphrase)) { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key " + "from private key."); + } + else if(publickeydata_len == 0 || !publickeydata) { + session->userauth_pblc_method = tmp_method; + session->userauth_pblc_method_len = tmp_method_len; + + pubkeydata_len = tmp_publickeydata_len; + pubkeydata = tmp_publickeydata; + } + else { + const char *ecdsa = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"; + const char *ed25519 = "sk-ssh-ed25519-cert-v01@openssh.com"; + + if(tmp_method) { + LIBSSH2_FREE(session, tmp_method); + } + + if(!strncmp((char *)publickeydata, ecdsa, strlen(ecdsa))) { + session->userauth_pblc_method_len = strlen(ecdsa); + session->userauth_pblc_method = + LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); + + memcpy(session->userauth_pblc_method, ecdsa, + session->userauth_pblc_method_len); + } + else if(!strncmp((char *)publickeydata, ed25519, + strlen(ed25519))) { + session->userauth_pblc_method_len = strlen(ed25519); + session->userauth_pblc_method = + LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); + + memcpy(session->userauth_pblc_method, ed25519, + session->userauth_pblc_method_len); + } + + rc = memory_read_publickey(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len, + &pubkeydata, &pubkeydata_len, + (char *)publickeydata, + publickeydata_len); + } + } + else { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Invalid data in public and private key."); + } + + if(rc == LIBSSH2_ERROR_NONE) { + rc = _libssh2_userauth_publickey(session, username, username_len, + pubkeydata, pubkeydata_len, + libssh2_sign_sk, &sign_abstract); + + while(rc == LIBSSH2_ERROR_EAGAIN) { + rc = _libssh2_userauth_publickey(session, username, username_len, + pubkeydata, pubkeydata_len, + libssh2_sign_sk, &sign_abstract); + } + } + + if(tmp_publickeydata) + LIBSSH2_FREE(session, tmp_publickeydata); + + if(sk_info.application) { + LIBSSH2_FREE(session, (void *)sk_info.application); + } + + return rc; +} diff --git a/libs/libssh2/src/userauth.h b/libs/libssh2/src/userauth.h index a7b0a9846e..24f8037ec2 100644 --- a/libs/libssh2/src/userauth.h +++ b/libs/libssh2/src/userauth.h @@ -1,7 +1,7 @@ -#ifndef LIBSSH2_USERAUTH_H -#define LIBSSH2_USERAUTH_H -/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> - * Copyright (c) 2009-2010 by Daniel Stenberg +#ifndef __LIBSSH2_USERAUTH_H +#define __LIBSSH2_USERAUTH_H +/* Copyright (C) Sara Golemon <sarag@libssh2.org> + * Copyright (C) Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, @@ -36,16 +36,18 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ int _libssh2_userauth_publickey(LIBSSH2_SESSION *session, const char *username, - unsigned int username_len, + size_t username_len, const unsigned char *pubkeydata, - unsigned long pubkeydata_len, + size_t pubkeydata_len, LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC - ((*sign_callback)), + ((*sign_callback)), void *abstract); -#endif /* LIBSSH2_USERAUTH_H */ +#endif /* __LIBSSH2_USERAUTH_H */ diff --git a/libs/libssh2/src/userauth_kbd_packet.c b/libs/libssh2/src/userauth_kbd_packet.c new file mode 100644 index 0000000000..216048e2ea --- /dev/null +++ b/libs/libssh2/src/userauth_kbd_packet.c @@ -0,0 +1,166 @@ +/* Copyright (C) Xaver Loppenstedt <xaver@loppenstedt.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "libssh2_priv.h" +#include "userauth_kbd_packet.h" + +int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *session) +{ + unsigned char *language_tag; + size_t language_tag_len; + unsigned int i; + unsigned char packet_type; + uint32_t tmp_u32; + + struct string_buf decoded; + + decoded.data = session->userauth_kybd_data; + decoded.dataptr = session->userauth_kybd_data; + decoded.len = session->userauth_kybd_data_len; + + if(session->userauth_kybd_data_len < 17) { + _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "userauth keyboard data buffer too small " + "to get length"); + return -1; + } + + /* byte SSH_MSG_USERAUTH_INFO_REQUEST */ + _libssh2_get_byte(&decoded, &packet_type); + + /* string name (ISO-10646 UTF-8) */ + if(_libssh2_copy_string(session, &decoded, + &session->userauth_kybd_auth_name, + &session->userauth_kybd_auth_name_len) == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive 'name' " + "request field"); + return -1; + } + + /* string instruction (ISO-10646 UTF-8) */ + if(_libssh2_copy_string(session, &decoded, + &session->userauth_kybd_auth_instruction, + &session->userauth_kybd_auth_instruction_len) + == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive 'instruction' " + "request field"); + return -1; + } + + /* string language tag (as defined in [RFC-3066]) */ + if(_libssh2_get_string(&decoded, &language_tag, + &language_tag_len) == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive 'language tag' " + "request field"); + return -1; + } + + /* int num-prompts */ + if(_libssh2_get_u32(&decoded, &tmp_u32) == -1 || + (session->userauth_kybd_num_prompts = tmp_u32) != tmp_u32) { + _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Unable to decode " + "keyboard-interactive number of keyboard prompts"); + return -1; + } + + if(session->userauth_kybd_num_prompts > 100) { + _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Too many replies for " + "keyboard-interactive prompts"); + return -1; + } + + if(session->userauth_kybd_num_prompts == 0) { + return 0; + } + + session->userauth_kybd_prompts = + LIBSSH2_CALLOC(session, + sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * + session->userauth_kybd_num_prompts); + if(!session->userauth_kybd_prompts) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive prompts array"); + return -1; + } + + session->userauth_kybd_responses = + LIBSSH2_CALLOC(session, + sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * + session->userauth_kybd_num_prompts); + if(!session->userauth_kybd_responses) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive responses array"); + return -1; + } + + for(i = 0; i < session->userauth_kybd_num_prompts; i++) { + /* string prompt[1] (ISO-10646 UTF-8) */ + if(_libssh2_copy_string(session, &decoded, + &session->userauth_kybd_prompts[i].text, + &session->userauth_kybd_prompts[i].length) + == -1) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to decode " + "keyboard-interactive prompt message"); + return -1; + } + + /* boolean echo[1] */ + if(_libssh2_get_boolean(&decoded, + &session->userauth_kybd_prompts[i].echo) + == -1) { + _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Unable to decode " + "user auth keyboard prompt echo"); + return -1; + } + } + + return 0; +} diff --git a/libs/libssh2/src/userauth_kbd_packet.h b/libs/libssh2/src/userauth_kbd_packet.h new file mode 100644 index 0000000000..bee34495e1 --- /dev/null +++ b/libs/libssh2/src/userauth_kbd_packet.h @@ -0,0 +1,45 @@ +/* Copyright (C) Xaver Loppenstedt <xaver@loppenstedt.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __LIBSSH2_USERAUTH_KBD_PARSE_H +#define __LIBSSH2_USERAUTH_KBD_PARSE_H + +int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *); + +#endif /* __LIBSSH2_USERAUTH_KBD_PARSE_H */ diff --git a/libs/libssh2/src/version.c b/libs/libssh2/src/version.c index 408f83a398..d32ae64ae0 100644 --- a/libs/libssh2/src/version.c +++ b/libs/libssh2/src/version.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2009 Daniel Stenberg. All rights reserved. +/* Copyright (C) Daniel Stenberg + * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -33,18 +34,11 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -/* - libssh2_version() can be used like this: - - if (!libssh2_version(LIBSSH2_VERSION_NUM)) { - fprintf (stderr, "Runtime libssh2 version too old!\n"); - exit(1); - } -*/ LIBSSH2_API const char *libssh2_version(int req_version_num) { @@ -52,3 +46,9 @@ const char *libssh2_version(int req_version_num) return LIBSSH2_VERSION; return NULL; /* this is not a suitable library! */ } + +LIBSSH2_API +libssh2_crypto_engine_t libssh2_crypto_engine(void) +{ + return LIBSSH2_CRYPTO_ENGINE; +} diff --git a/libs/libssh2/src/wincng.c b/libs/libssh2/src/wincng.c deleted file mode 100644 index 4bebc6407a..0000000000 --- a/libs/libssh2/src/wincng.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* - * Copyright (C) 2013-2015 Marc Hoersken <info@marc-hoersken.de> - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -#include "libssh2_priv.h" - -#ifdef LIBSSH2_WINCNG /* compile only if we build with wincng */ - -/* required for cross-compilation against the w64 mingw-runtime package */ -#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#undef _WIN32_WINNT -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif - -/* specify the required libraries for dependencies using MSVC */ -#ifdef _MSC_VER -#pragma comment(lib, "bcrypt.lib") -#ifdef HAVE_LIBCRYPT32 -#pragma comment(lib, "crypt32.lib") -#endif -#endif - -#include <windows.h> -#include <bcrypt.h> -#include <math.h> -#include "misc.h" - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_LIBCRYPT32 -#include <wincrypt.h> -#endif - -#define PEM_RSA_HEADER "-----BEGIN RSA PRIVATE KEY-----" -#define PEM_RSA_FOOTER "-----END RSA PRIVATE KEY-----" -#define PEM_DSA_HEADER "-----BEGIN DSA PRIVATE KEY-----" -#define PEM_DSA_FOOTER "-----END DSA PRIVATE KEY-----" - - -/*******************************************************************/ -/* - * Windows CNG backend: Missing definitions (for MinGW[-w64]) - */ -#ifndef BCRYPT_SUCCESS -#define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -#endif - -#ifndef BCRYPT_RNG_ALGORITHM -#define BCRYPT_RNG_ALGORITHM L"RNG" -#endif - -#ifndef BCRYPT_MD5_ALGORITHM -#define BCRYPT_MD5_ALGORITHM L"MD5" -#endif - -#ifndef BCRYPT_SHA1_ALGORITHM -#define BCRYPT_SHA1_ALGORITHM L"SHA1" -#endif - -#ifndef BCRYPT_SHA256_ALGORITHM -#define BCRYPT_SHA256_ALGORITHM L"SHA256" -#endif - -#ifndef BCRYPT_SHA512_ALGORITHM -#define BCRYPT_SHA512_ALGORITHM L"SHA512" -#endif - -#ifndef BCRYPT_RSA_ALGORITHM -#define BCRYPT_RSA_ALGORITHM L"RSA" -#endif - -#ifndef BCRYPT_DSA_ALGORITHM -#define BCRYPT_DSA_ALGORITHM L"DSA" -#endif - -#ifndef BCRYPT_AES_ALGORITHM -#define BCRYPT_AES_ALGORITHM L"AES" -#endif - -#ifndef BCRYPT_RC4_ALGORITHM -#define BCRYPT_RC4_ALGORITHM L"RC4" -#endif - -#ifndef BCRYPT_3DES_ALGORITHM -#define BCRYPT_3DES_ALGORITHM L"3DES" -#endif - -#ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG -#define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008 -#endif - -#ifndef BCRYPT_DSA_PUBLIC_BLOB -#define BCRYPT_DSA_PUBLIC_BLOB L"DSAPUBLICBLOB" -#endif - -#ifndef BCRYPT_DSA_PUBLIC_MAGIC -#define BCRYPT_DSA_PUBLIC_MAGIC 0x42505344 /* DSPB */ -#endif - -#ifndef BCRYPT_DSA_PRIVATE_BLOB -#define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB" -#endif - -#ifndef BCRYPT_DSA_PRIVATE_MAGIC -#define BCRYPT_DSA_PRIVATE_MAGIC 0x56505344 /* DSPV */ -#endif - -#ifndef BCRYPT_RSAPUBLIC_BLOB -#define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB" -#endif - -#ifndef BCRYPT_RSAPUBLIC_MAGIC -#define BCRYPT_RSAPUBLIC_MAGIC 0x31415352 /* RSA1 */ -#endif - -#ifndef BCRYPT_RSAFULLPRIVATE_BLOB -#define BCRYPT_RSAFULLPRIVATE_BLOB L"RSAFULLPRIVATEBLOB" -#endif - -#ifndef BCRYPT_RSAFULLPRIVATE_MAGIC -#define BCRYPT_RSAFULLPRIVATE_MAGIC 0x33415352 /* RSA3 */ -#endif - -#ifndef BCRYPT_KEY_DATA_BLOB -#define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob" -#endif - -#ifndef BCRYPT_MESSAGE_BLOCK_LENGTH -#define BCRYPT_MESSAGE_BLOCK_LENGTH L"MessageBlockLength" -#endif - -#ifndef BCRYPT_NO_KEY_VALIDATION -#define BCRYPT_NO_KEY_VALIDATION 0x00000008 -#endif - -#ifndef BCRYPT_BLOCK_PADDING -#define BCRYPT_BLOCK_PADDING 0x00000001 -#endif - -#ifndef BCRYPT_PAD_NONE -#define BCRYPT_PAD_NONE 0x00000001 -#endif - -#ifndef BCRYPT_PAD_PKCS1 -#define BCRYPT_PAD_PKCS1 0x00000002 -#endif - -#ifndef BCRYPT_PAD_OAEP -#define BCRYPT_PAD_OAEP 0x00000004 -#endif - -#ifndef BCRYPT_PAD_PSS -#define BCRYPT_PAD_PSS 0x00000008 -#endif - -#ifndef CRYPT_STRING_ANY -#define CRYPT_STRING_ANY 0x00000007 -#endif - -#ifndef LEGACY_RSAPRIVATE_BLOB -#define LEGACY_RSAPRIVATE_BLOB L"CAPIPRIVATEBLOB" -#endif - -#ifndef PKCS_RSA_PRIVATE_KEY -#define PKCS_RSA_PRIVATE_KEY (LPCSTR)43 -#endif - - -/*******************************************************************/ -/* - * Windows CNG backend: Generic functions - */ - -void -_libssh2_wincng_init(void) -{ - int ret; - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG, - BCRYPT_RNG_ALGORITHM, NULL, 0); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5, - BCRYPT_MD5_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1, - BCRYPT_SHA1_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256, - BCRYPT_SHA256_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512, - BCRYPT_SHA512_ALGORITHM, NULL, 0); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5, - BCRYPT_MD5_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1, - BCRYPT_SHA1_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256, - BCRYPT_SHA256_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512, - BCRYPT_SHA512_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA, - BCRYPT_RSA_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA, - BCRYPT_DSA_ALGORITHM, NULL, 0); - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC, - BCRYPT_AES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_CBC, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_CBC, - sizeof(BCRYPT_CHAIN_MODE_CBC), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_ECB, - BCRYPT_AES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_ECB, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_ECB, - sizeof(BCRYPT_CHAIN_MODE_ECB), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRC4_NA, - BCRYPT_RC4_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgRC4_NA, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_NA, - sizeof(BCRYPT_CHAIN_MODE_NA), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlg3DES_CBC, - BCRYPT_3DES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlg3DES_CBC, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_CBC, - sizeof(BCRYPT_CHAIN_MODE_CBC), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, - 0); - } - } -} - -void -_libssh2_wincng_free(void) -{ - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0); - - memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); -} - -int -_libssh2_wincng_random(void *buf, int len) -{ - int ret; - - ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, len, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -static void -_libssh2_wincng_safe_free(void *buf, int len) -{ -#ifndef LIBSSH2_CLEAR_MEMORY - (void)len; -#endif - - if(!buf) - return; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(len > 0) - SecureZeroMemory(buf, len); -#endif - - free(buf); -} - - -/*******************************************************************/ -/* - * Windows CNG backend: Hash functions - */ - -int -_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, - BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen, - unsigned char *key, unsigned long keylen) -{ - BCRYPT_HASH_HANDLE hHash; - unsigned char *pbHashObject; - unsigned long dwHashObject, dwHash, cbData; - int ret; - - ret = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, - (unsigned char *)&dwHash, - sizeof(dwHash), - &cbData, 0); - if((!BCRYPT_SUCCESS(ret)) || dwHash != hashlen) { - return -1; - } - - ret = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, - (unsigned char *)&dwHashObject, - sizeof(dwHashObject), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - pbHashObject = malloc(dwHashObject); - if(!pbHashObject) { - return -1; - } - - - ret = BCryptCreateHash(hAlg, &hHash, - pbHashObject, dwHashObject, - key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbHashObject, dwHashObject); - return -1; - } - - - ctx->hHash = hHash; - ctx->pbHashObject = pbHashObject; - ctx->dwHashObject = dwHashObject; - ctx->cbHash = dwHash; - - return 0; -} - -int -_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx, - const unsigned char *data, unsigned long datalen) -{ - int ret; - - ret = BCryptHashData(ctx->hHash, (unsigned char *)data, datalen, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash) -{ - int ret; - - ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); - - BCryptDestroyHash(ctx->hHash); - ctx->hHash = NULL; - - _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject); - ctx->pbHashObject = NULL; - ctx->dwHashObject = 0; - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_hash(unsigned char *data, unsigned long datalen, - BCRYPT_ALG_HANDLE hAlg, - unsigned char *hash, unsigned long hashlen) -{ - _libssh2_wincng_hash_ctx ctx; - int ret; - - ret = _libssh2_wincng_hash_init(&ctx, hAlg, hashlen, NULL, 0); - if(!ret) { - ret = _libssh2_wincng_hash_update(&ctx, data, datalen); - ret |= _libssh2_wincng_hash_final(&ctx, hash); - } - - return ret; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: HMAC functions - */ - -int -_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash) -{ - int ret; - - ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx) -{ - BCryptDestroyHash(ctx->hHash); - ctx->hHash = NULL; - - _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject); - ctx->pbHashObject = NULL; - ctx->dwHashObject = 0; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: Key functions - */ - -int -_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len, - unsigned long flags) -{ - BCRYPT_PKCS1_PADDING_INFO paddingInfoPKCS1; - void *pPaddingInfo; - unsigned char *data, *hash; - unsigned long datalen, hashlen; - int ret; - - datalen = m_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - hashlen = SHA_DIGEST_LENGTH; - hash = malloc(hashlen); - if(!hash) { - free(data); - return -1; - } - - memcpy(data, m, datalen); - - ret = _libssh2_wincng_hash(data, datalen, - _libssh2_wincng.hAlgHashSHA1, - hash, hashlen); - - _libssh2_wincng_safe_free(data, datalen); - - if(ret) { - _libssh2_wincng_safe_free(hash, hashlen); - return -1; - } - - datalen = sig_len; - data = malloc(datalen); - if(!data) { - _libssh2_wincng_safe_free(hash, hashlen); - return -1; - } - - if(flags & BCRYPT_PAD_PKCS1) { - paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM; - pPaddingInfo = &paddingInfoPKCS1; - } - else - pPaddingInfo = NULL; - - memcpy(data, sig, datalen); - - ret = BCryptVerifySignature(ctx->hKey, pPaddingInfo, - hash, hashlen, data, datalen, flags); - - _libssh2_wincng_safe_free(hash, hashlen); - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_load_pem(LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase, - const char *headerbegin, - const char *headerend, - unsigned char **data, - unsigned int *datalen) -{ - FILE *fp; - int ret; - - fp = fopen(filename, FOPEN_READTEXT); - if(!fp) { - return -1; - } - - ret = _libssh2_pem_parse(session, headerbegin, headerend, - passphrase, - fp, data, datalen); - - fclose(fp); - - return ret; -} - -static int -_libssh2_wincng_load_private(LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase, - unsigned char **ppbEncoded, - unsigned long *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) -{ - unsigned char *data = NULL; - unsigned int datalen = 0; - int ret = -1; - - if(ret && tryLoadRSA) { - ret = _libssh2_wincng_load_pem(session, filename, passphrase, - PEM_RSA_HEADER, PEM_RSA_FOOTER, - &data, &datalen); - } - - if(ret && tryLoadDSA) { - ret = _libssh2_wincng_load_pem(session, filename, passphrase, - PEM_DSA_HEADER, PEM_DSA_FOOTER, - &data, &datalen); - } - - if(!ret) { - *ppbEncoded = data; - *pcbEncoded = datalen; - } - - return ret; -} - -static int -_libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase, - unsigned char **ppbEncoded, - unsigned long *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) -{ - unsigned char *data = NULL; - unsigned int datalen = 0; - int ret = -1; - - (void)passphrase; - - if(ret && tryLoadRSA) { - ret = _libssh2_pem_parse_memory(session, - PEM_RSA_HEADER, PEM_RSA_FOOTER, - privatekeydata, privatekeydata_len, - &data, &datalen); - } - - if(ret && tryLoadDSA) { - ret = _libssh2_pem_parse_memory(session, - PEM_DSA_HEADER, PEM_DSA_FOOTER, - privatekeydata, privatekeydata_len, - &data, &datalen); - } - - if(!ret) { - *ppbEncoded = data; - *pcbEncoded = datalen; - } - - return ret; -} - -static int -_libssh2_wincng_asn_decode(unsigned char *pbEncoded, - unsigned long cbEncoded, - LPCSTR lpszStructType, - unsigned char **ppbDecoded, - unsigned long *pcbDecoded) -{ - unsigned char *pbDecoded = NULL; - unsigned long cbDecoded = 0; - int ret; - - ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - lpszStructType, - pbEncoded, cbEncoded, 0, NULL, - NULL, &cbDecoded); - if(!ret) { - return -1; - } - - pbDecoded = malloc(cbDecoded); - if(!pbDecoded) { - return -1; - } - - ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - lpszStructType, - pbEncoded, cbEncoded, 0, NULL, - pbDecoded, &cbDecoded); - if(!ret) { - _libssh2_wincng_safe_free(pbDecoded, cbDecoded); - return -1; - } - - - *ppbDecoded = pbDecoded; - *pcbDecoded = cbDecoded; - - return 0; -} - -static int -_libssh2_wincng_bn_ltob(unsigned char *pbInput, - unsigned long cbInput, - unsigned char **ppbOutput, - unsigned long *pcbOutput) -{ - unsigned char *pbOutput; - unsigned long cbOutput, index, offset, length; - - if(cbInput < 1) { - return 0; - } - - offset = 0; - length = cbInput - 1; - cbOutput = cbInput; - if(pbInput[length] & (1 << 7)) { - offset++; - cbOutput += offset; - } - - pbOutput = (unsigned char *)malloc(cbOutput); - if(!pbOutput) { - return -1; - } - - pbOutput[0] = 0; - for(index = 0; ((index + offset) < cbOutput) - && (index < cbInput); index++) { - pbOutput[index + offset] = pbInput[length - index]; - } - - - *ppbOutput = pbOutput; - *pcbOutput = cbOutput; - - return 0; -} - -static int -_libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded, - unsigned long cbEncoded, - unsigned char **ppbDecoded, - unsigned long *pcbDecoded) -{ - unsigned char *pbDecoded = NULL, *pbInteger; - unsigned long cbDecoded = 0, cbInteger; - int ret; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - X509_MULTI_BYTE_UINT, - &pbInteger, &cbInteger); - if(!ret) { - ret = _libssh2_wincng_bn_ltob(((PCRYPT_DATA_BLOB)pbInteger)->pbData, - ((PCRYPT_DATA_BLOB)pbInteger)->cbData, - &pbDecoded, &cbDecoded); - if(!ret) { - *ppbDecoded = pbDecoded; - *pcbDecoded = cbDecoded; - } - _libssh2_wincng_safe_free(pbInteger, cbInteger); - } - - return ret; -} - -static int -_libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded, - unsigned long cbEncoded, - unsigned char ***prpbDecoded, - unsigned long **prcbDecoded, - unsigned long *pcbCount) -{ - PCRYPT_DER_BLOB pBlob; - unsigned char *pbDecoded, **rpbDecoded; - unsigned long cbDecoded, *rcbDecoded, index, length; - int ret; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - X509_SEQUENCE_OF_ANY, - &pbDecoded, &cbDecoded); - if(!ret) { - length = ((PCRYPT_DATA_BLOB)pbDecoded)->cbData; - - rpbDecoded = malloc(sizeof(PBYTE) * length); - if(rpbDecoded) { - rcbDecoded = malloc(sizeof(DWORD) * length); - if(rcbDecoded) { - for(index = 0; index < length; index++) { - pBlob = &((PCRYPT_DER_BLOB) - ((PCRYPT_DATA_BLOB)pbDecoded)->pbData)[index]; - ret = _libssh2_wincng_asn_decode_bn(pBlob->pbData, - pBlob->cbData, - &rpbDecoded[index], - &rcbDecoded[index]); - if(ret) - break; - } - - if(!ret) { - *prpbDecoded = rpbDecoded; - *prcbDecoded = rcbDecoded; - *pcbCount = length; - } - else { - for(length = 0; length < index; length++) { - _libssh2_wincng_safe_free(rpbDecoded[length], - rcbDecoded[length]); - rpbDecoded[length] = NULL; - rcbDecoded[length] = 0; - } - free(rpbDecoded); - free(rcbDecoded); - } - } - else { - free(rpbDecoded); - ret = -1; - } - } - else { - ret = -1; - } - - _libssh2_wincng_safe_free(pbDecoded, cbDecoded); - } - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -static unsigned long -_libssh2_wincng_bn_size(const unsigned char *bignum, - unsigned long length) -{ - unsigned long offset; - - if(!bignum) - return 0; - - length--; - - offset = 0; - while(!(*(bignum + offset)) && (offset < length)) - offset++; - - length++; - - return length - offset; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: RSA functions - */ - -int -_libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_RSAKEY_BLOB *rsakey; - LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, mlen, p1len = 0, p2len = 0; - int ret; - - mlen = max(_libssh2_wincng_bn_size(ndata, nlen), - _libssh2_wincng_bn_size(ddata, dlen)); - offset = sizeof(BCRYPT_RSAKEY_BLOB); - keylen = offset + elen + mlen; - if(ddata && dlen > 0) { - p1len = max(_libssh2_wincng_bn_size(pdata, plen), - _libssh2_wincng_bn_size(e1data, e1len)); - p2len = max(_libssh2_wincng_bn_size(qdata, qlen), - _libssh2_wincng_bn_size(e2data, e2len)); - keylen += p1len * 3 + p2len * 2 + mlen; - } - - key = malloc(keylen); - if(!key) { - return -1; - } - - memset(key, 0, keylen); - - - /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; - rsakey->BitLength = mlen * 8; - rsakey->cbPublicExp = elen; - rsakey->cbModulus = mlen; - - memcpy(key + offset, edata, elen); - offset += elen; - - if(nlen < mlen) - memcpy(key + offset + mlen - nlen, ndata, nlen); - else - memcpy(key + offset, ndata + nlen - mlen, mlen); - - if(ddata && dlen > 0) { - offset += mlen; - - if(plen < p1len) - memcpy(key + offset + p1len - plen, pdata, plen); - else - memcpy(key + offset, pdata + plen - p1len, p1len); - offset += p1len; - - if(qlen < p2len) - memcpy(key + offset + p2len - qlen, qdata, qlen); - else - memcpy(key + offset, qdata + qlen - p2len, p2len); - offset += p2len; - - if(e1len < p1len) - memcpy(key + offset + p1len - e1len, e1data, e1len); - else - memcpy(key + offset, e1data + e1len - p1len, p1len); - offset += p1len; - - if(e2len < p2len) - memcpy(key + offset + p2len - e2len, e2data, e2len); - else - memcpy(key + offset, e2data + e2len - p2len, p2len); - offset += p2len; - - if(coefflen < p1len) - memcpy(key + offset + p1len - coefflen, coeffdata, coefflen); - else - memcpy(key + offset, coeffdata + coefflen - p1len, p1len); - offset += p1len; - - if(dlen < mlen) - memcpy(key + offset + mlen - dlen, ddata, dlen); - else - memcpy(key + offset, ddata + dlen - mlen, mlen); - - lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB; - rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC; - rsakey->cbPrime1 = p1len; - rsakey->cbPrime2 = p2len; - } - else { - lpszBlobType = BCRYPT_RSAPUBLIC_BLOB; - rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; - rsakey->cbPrime1 = 0; - rsakey->cbPrime2 = 0; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - - *rsa = malloc(sizeof(libssh2_rsa_ctx)); - if(!(*rsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - (*rsa)->hKey = hKey; - (*rsa)->pbKeyObject = key; - (*rsa)->cbKeyObject = keylen; - - return 0; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - BCRYPT_KEY_HANDLE hKey; - unsigned char *pbStructInfo; - unsigned long cbStructInfo; - int ret; - - (void)session; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - PKCS_RSA_PRIVATE_KEY, - &pbStructInfo, &cbStructInfo); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - LEGACY_RSAPRIVATE_BLOB, &hKey, - pbStructInfo, cbStructInfo, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo); - return -1; - } - - - *rsa = malloc(sizeof(libssh2_rsa_ctx)); - if(!(*rsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo); - return -1; - } - - (*rsa)->hKey = hKey; - (*rsa)->pbKeyObject = pbStructInfo; - (*rsa)->cbKeyObject = cbStructInfo; - - return 0; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - (void)session; - - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) { - return -1; - } - - return _libssh2_wincng_rsa_new_private_parse(rsa, session, - pbEncoded, cbEncoded); -#else - (void)rsa; - (void)filename; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load RSA key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - (void)session; - - ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) { - return -1; - } - - return _libssh2_wincng_rsa_new_private_parse(rsa, session, - pbEncoded, cbEncoded); -#else - (void)rsa; - (void)filedata; - (void)filedata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len) -{ - return _libssh2_wincng_key_sha1_verify(rsa, sig, sig_len, m, m_len, - BCRYPT_PAD_PKCS1); -} - -int -_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len) -{ - BCRYPT_PKCS1_PADDING_INFO paddingInfo; - unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; - - datalen = (unsigned long)hash_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; - - memcpy(data, hash, datalen); - - ret = BCryptSignHash(rsa->hKey, &paddingInfo, - data, datalen, NULL, 0, - &cbData, BCRYPT_PAD_PKCS1); - if(BCRYPT_SUCCESS(ret)) { - siglen = cbData; - sig = LIBSSH2_ALLOC(session, siglen); - if(sig) { - ret = BCryptSignHash(rsa->hKey, &paddingInfo, - data, datalen, sig, siglen, - &cbData, BCRYPT_PAD_PKCS1); - if(BCRYPT_SUCCESS(ret)) { - *signature_len = siglen; - *signature = sig; - } - else { - LIBSSH2_FREE(session, sig); - } - } - else - ret = STATUS_NO_MEMORY; - } - - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa) -{ - if(!rsa) - return; - - BCryptDestroyKey(rsa->hKey); - rsa->hKey = NULL; - - _libssh2_wincng_safe_free(rsa->pbKeyObject, rsa->cbKeyObject); - _libssh2_wincng_safe_free(rsa, sizeof(libssh2_rsa_ctx)); -} - - -/*******************************************************************/ -/* - * Windows CNG backend: DSA functions - */ - -#if LIBSSH2_DSA -int -_libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *xdata, - unsigned long xlen) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_DSA_KEY_BLOB *dsakey; - LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, length; - int ret; - - length = max(max(_libssh2_wincng_bn_size(pdata, plen), - _libssh2_wincng_bn_size(gdata, glen)), - _libssh2_wincng_bn_size(ydata, ylen)); - offset = sizeof(BCRYPT_DSA_KEY_BLOB); - keylen = offset + length * 3; - if(xdata && xlen > 0) - keylen += 20; - - key = malloc(keylen); - if(!key) { - return -1; - } - - memset(key, 0, keylen); - - - /* https://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */ - dsakey = (BCRYPT_DSA_KEY_BLOB *)key; - dsakey->cbKey = length; - - memset(dsakey->Count, -1, sizeof(dsakey->Count)); - memset(dsakey->Seed, -1, sizeof(dsakey->Seed)); - - if(qlen < 20) - memcpy(dsakey->q + 20 - qlen, qdata, qlen); - else - memcpy(dsakey->q, qdata + qlen - 20, 20); - - if(plen < length) - memcpy(key + offset + length - plen, pdata, plen); - else - memcpy(key + offset, pdata + plen - length, length); - offset += length; - - if(glen < length) - memcpy(key + offset + length - glen, gdata, glen); - else - memcpy(key + offset, gdata + glen - length, length); - offset += length; - - if(ylen < length) - memcpy(key + offset + length - ylen, ydata, ylen); - else - memcpy(key + offset, ydata + ylen - length, length); - - if(xdata && xlen > 0) { - offset += length; - - if(xlen < 20) - memcpy(key + offset + 20 - xlen, xdata, xlen); - else - memcpy(key + offset, xdata + xlen - 20, 20); - - lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB; - dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC; - } - else { - lpszBlobType = BCRYPT_DSA_PUBLIC_BLOB; - dsakey->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - - *dsa = malloc(sizeof(libssh2_dsa_ctx)); - if(!(*dsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - (*dsa)->hKey = hKey; - (*dsa)->pbKeyObject = key; - (*dsa)->cbKeyObject = keylen; - - return 0; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - unsigned char **rpbDecoded; - unsigned long *rcbDecoded, index, length; - int ret; - - (void)session; - - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, - &rpbDecoded, &rcbDecoded, &length); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - if(length == 6) { - ret = _libssh2_wincng_dsa_new(dsa, - rpbDecoded[1], rcbDecoded[1], - rpbDecoded[2], rcbDecoded[2], - rpbDecoded[3], rcbDecoded[3], - rpbDecoded[4], rcbDecoded[4], - rpbDecoded[5], rcbDecoded[5]); - } - else { - ret = -1; - } - - for(index = 0; index < length; index++) { - _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]); - rpbDecoded[index] = NULL; - rcbDecoded[index] = 0; - } - - free(rpbDecoded); - free(rcbDecoded); - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_dsa_new_private_parse(dsa, session, - pbEncoded, cbEncoded); -#else - (void)dsa; - (void)filename; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load DSA key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_dsa_new_private_parse(dsa, session, - pbEncoded, cbEncoded); -#else - (void)dsa; - (void)filedata; - (void)filedata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa, - const unsigned char *sig_fixed, - const unsigned char *m, - unsigned long m_len) -{ - return _libssh2_wincng_key_sha1_verify(dsa, sig_fixed, 40, m, m_len, 0); -} - -int -_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, - const unsigned char *hash, - unsigned long hash_len, - unsigned char *sig_fixed) -{ - unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; - - datalen = hash_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - memcpy(data, hash, datalen); - - ret = BCryptSignHash(dsa->hKey, NULL, data, datalen, - NULL, 0, &cbData, 0); - if(BCRYPT_SUCCESS(ret)) { - siglen = cbData; - if(siglen == 40) { - sig = malloc(siglen); - if(sig) { - ret = BCryptSignHash(dsa->hKey, NULL, data, datalen, - sig, siglen, &cbData, 0); - if(BCRYPT_SUCCESS(ret)) { - memcpy(sig_fixed, sig, siglen); - } - - _libssh2_wincng_safe_free(sig, siglen); - } - else - ret = STATUS_NO_MEMORY; - } - else - ret = STATUS_NO_MEMORY; - } - - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa) -{ - if(!dsa) - return; - - BCryptDestroyKey(dsa->hKey); - dsa->hKey = NULL; - - _libssh2_wincng_safe_free(dsa->pbKeyObject, dsa->cbKeyObject); - _libssh2_wincng_safe_free(dsa, sizeof(libssh2_dsa_ctx)); -} -#endif - - -/*******************************************************************/ -/* - * Windows CNG backend: Key functions - */ - -#ifdef HAVE_LIBCRYPT32 -static unsigned long -_libssh2_wincng_pub_priv_write(unsigned char *key, - unsigned long offset, - const unsigned char *bignum, - const unsigned long length) -{ - _libssh2_htonu32(key + offset, length); - offset += 4; - - memcpy(key + offset, bignum, length); - offset += length; - - return offset; -} - -static int -_libssh2_wincng_pub_priv_keyfile_parse(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - unsigned char **rpbDecoded; - unsigned long *rcbDecoded; - unsigned char *key = NULL, *mth = NULL; - unsigned long keylen = 0, mthlen = 0; - unsigned long index, offset, length; - int ret; - - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, - &rpbDecoded, &rcbDecoded, &length); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - if(length == 9) { /* private RSA key */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-rsa", mthlen); - } - else { - ret = -1; - } - - - keylen = 4 + mthlen + 4 + rcbDecoded[2] + 4 + rcbDecoded[1]; - key = LIBSSH2_ALLOC(session, keylen); - if(key) { - offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[2], - rcbDecoded[2]); - - _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[1], - rcbDecoded[1]); - } - else { - ret = -1; - } - - } - else if(length == 6) { /* private DSA key */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-dss", mthlen); - } - else { - ret = -1; - } - - keylen = 4 + mthlen + 4 + rcbDecoded[1] + 4 + rcbDecoded[2] - + 4 + rcbDecoded[3] + 4 + rcbDecoded[4]; - key = LIBSSH2_ALLOC(session, keylen); - if(key) { - offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[1], - rcbDecoded[1]); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[2], - rcbDecoded[2]); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[3], - rcbDecoded[3]); - - _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[4], - rcbDecoded[4]); - } - else { - ret = -1; - } - - } - else { - ret = -1; - } - - - for(index = 0; index < length; index++) { - _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]); - rpbDecoded[index] = NULL; - rcbDecoded[index] = 0; - } - - free(rpbDecoded); - free(rcbDecoded); - - - if(ret) { - if(mth) - LIBSSH2_FREE(session, mth); - if(key) - LIBSSH2_FREE(session, key); - } - else { - *method = mth; - *method_len = mthlen; - *pubkeydata = key; - *pubkeydata_len = keylen; - } - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private(session, privatekey, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len, - pubkeydata, pubkeydata_len, - pbEncoded, cbEncoded); -#else - (void)method; - (void)method_len; - (void)pubkeydata; - (void)pubkeydata_len; - (void)privatekey; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load public key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private_memory(session, privatekeydata, - privatekeydata_len, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len, - pubkeydata, pubkeydata_len, - pbEncoded, cbEncoded); -#else - (void)method; - (void)method_len; - (void)pubkeydata_len; - (void)pubkeydata; - (void)privatekeydata; - (void)privatekeydata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract public key from private key in memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -/*******************************************************************/ -/* - * Windows CNG backend: Cipher functions - */ - -int -_libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_KEY_DATA_BLOB_HEADER *header; - unsigned char *pbKeyObject, *pbIV, *key, *pbCtr, *pbIVCopy; - unsigned long dwKeyObject, dwIV, dwCtrLength, dwBlockLength, - cbData, keylen; - int ret; - - (void)encrypt; - - ret = BCryptGetProperty(*type.phAlg, BCRYPT_OBJECT_LENGTH, - (unsigned char *)&dwKeyObject, - sizeof(dwKeyObject), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - ret = BCryptGetProperty(*type.phAlg, BCRYPT_BLOCK_LENGTH, - (unsigned char *)&dwBlockLength, - sizeof(dwBlockLength), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - pbKeyObject = malloc(dwKeyObject); - if(!pbKeyObject) { - return -1; - } - - - keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength; - key = malloc(keylen); - if(!key) { - free(pbKeyObject); - return -1; - } - - - header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key; - header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; - header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; - header->cbKeyData = type.dwKeyLength; - - memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), - secret, type.dwKeyLength); - - ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey, - pbKeyObject, dwKeyObject, key, keylen, 0); - - _libssh2_wincng_safe_free(key, keylen); - - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject); - return -1; - } - - pbIV = NULL; - pbCtr = NULL; - dwIV = 0; - dwCtrLength = 0; - - if(type.useIV || type.ctrMode) { - pbIVCopy = malloc(dwBlockLength); - if(!pbIVCopy) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject); - return -1; - } - memcpy(pbIVCopy, iv, dwBlockLength); - - if(type.ctrMode) { - pbCtr = pbIVCopy; - dwCtrLength = dwBlockLength; - } - else if(type.useIV) { - pbIV = pbIVCopy; - dwIV = dwBlockLength; - } - } - - ctx->hKey = hKey; - ctx->pbKeyObject = pbKeyObject; - ctx->pbIV = pbIV; - ctx->pbCtr = pbCtr; - ctx->dwKeyObject = dwKeyObject; - ctx->dwIV = dwIV; - ctx->dwBlockLength = dwBlockLength; - ctx->dwCtrLength = dwCtrLength; - - return 0; -} -int -_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen) -{ - unsigned char *pbOutput, *pbInput; - unsigned long cbOutput, cbInput; - int ret; - - (void)type; - - cbInput = (unsigned long)blocklen; - - if(type.ctrMode) { - pbInput = ctx->pbCtr; - } - else { - pbInput = block; - } - - if(encrypt || type.ctrMode) { - ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0); - } - else { - ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0); - } - if(BCRYPT_SUCCESS(ret)) { - pbOutput = malloc(cbOutput); - if(pbOutput) { - if(encrypt || type.ctrMode) { - ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, - pbOutput, cbOutput, &cbOutput, 0); - } - else { - ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, - pbOutput, cbOutput, &cbOutput, 0); - } - if(BCRYPT_SUCCESS(ret)) { - if(type.ctrMode) { - _libssh2_xor_data(block, block, pbOutput, blocklen); - _libssh2_aes_ctr_increment(ctx->pbCtr, ctx->dwCtrLength); - } - else { - memcpy(block, pbOutput, cbOutput); - } - } - - _libssh2_wincng_safe_free(pbOutput, cbOutput); - } - else - ret = STATUS_NO_MEMORY; - } - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx) -{ - BCryptDestroyKey(ctx->hKey); - ctx->hKey = NULL; - - _libssh2_wincng_safe_free(ctx->pbKeyObject, ctx->dwKeyObject); - ctx->pbKeyObject = NULL; - ctx->dwKeyObject = 0; - - _libssh2_wincng_safe_free(ctx->pbIV, ctx->dwBlockLength); - ctx->pbIV = NULL; - ctx->dwBlockLength = 0; - - _libssh2_wincng_safe_free(ctx->pbCtr, ctx->dwCtrLength); - ctx->pbCtr = NULL; - ctx->dwCtrLength = 0; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: BigNumber functions - */ - -_libssh2_bn * -_libssh2_wincng_bignum_init(void) -{ - _libssh2_bn *bignum; - - bignum = (_libssh2_bn *)malloc(sizeof(_libssh2_bn)); - if(bignum) { - bignum->bignum = NULL; - bignum->length = 0; - } - - return bignum; -} - -static int -_libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length) -{ - unsigned char *bignum; - - if(!bn) - return -1; - - if(length == bn->length) - return 0; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(bn->bignum && bn->length > 0 && length < bn->length) { - SecureZeroMemory(bn->bignum + length, bn->length - length); - } -#endif - - bignum = realloc(bn->bignum, length); - if(!bignum) - return -1; - - bn->bignum = bignum; - bn->length = length; - - return 0; -} - -static int -_libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) -{ - unsigned char *bignum; - unsigned long length; - - if(!rnd) - return -1; - - length = (unsigned long)(ceil((float)bits / 8) * sizeof(unsigned char)); - if(_libssh2_wincng_bignum_resize(rnd, length)) - return -1; - - bignum = rnd->bignum; - - if(_libssh2_wincng_random(bignum, length)) - return -1; - - /* calculate significant bits in most significant byte */ - bits %= 8; - - /* fill most significant byte with zero padding */ - bignum[0] &= (1 << (8 - bits)) - 1; - - /* set some special last bits in most significant byte */ - if(top == 0) - bignum[0] |= (1 << (7 - bits)); - else if(top == 1) - bignum[0] |= (3 << (6 - bits)); - - /* make odd by setting first bit in least significant byte */ - if(bottom) - bignum[length - 1] |= 1; - - return 0; -} - -static int -_libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, - _libssh2_bn *a, - _libssh2_bn *p, - _libssh2_bn *m) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_RSAKEY_BLOB *rsakey; - unsigned char *key, *bignum; - unsigned long keylen, offset, length; - int ret; - - if(!r || !a || !p || !m) - return -1; - - offset = sizeof(BCRYPT_RSAKEY_BLOB); - keylen = offset + p->length + m->length; - - key = malloc(keylen); - if(!key) - return -1; - - - /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; - rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; - rsakey->BitLength = m->length * 8; - rsakey->cbPublicExp = p->length; - rsakey->cbModulus = m->length; - rsakey->cbPrime1 = 0; - rsakey->cbPrime2 = 0; - - memcpy(key + offset, p->bignum, p->length); - offset += p->length; - - memcpy(key + offset, m->bignum, m->length); - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, - BCRYPT_NO_KEY_VALIDATION); - - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0, - NULL, 0, &length, BCRYPT_PAD_NONE); - if(BCRYPT_SUCCESS(ret)) { - if(!_libssh2_wincng_bignum_resize(r, length)) { - length = max(a->length, length); - bignum = malloc(length); - if(bignum) { - offset = length - a->length; - memset(bignum, 0, offset); - memcpy(bignum + offset, a->bignum, a->length); - - ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0, - r->bignum, r->length, &offset, - BCRYPT_PAD_NONE); - - _libssh2_wincng_safe_free(bignum, length); - - if(BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_bignum_resize(r, offset); - } - } - else - ret = STATUS_NO_MEMORY; - } - else - ret = STATUS_NO_MEMORY; - } - - BCryptDestroyKey(hKey); - } - - _libssh2_wincng_safe_free(key, keylen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word) -{ - unsigned long offset, number, bits, length; - - if(!bn) - return -1; - - bits = 0; - number = word; - while(number >>= 1) - bits++; - - length = (unsigned long) (ceil(((double)(bits + 1)) / 8.0) * - sizeof(unsigned char)); - if(_libssh2_wincng_bignum_resize(bn, length)) - return -1; - - for(offset = 0; offset < length; offset++) - bn->bignum[offset] = (word >> (offset * 8)) & 0xff; - - return 0; -} - -unsigned long -_libssh2_wincng_bignum_bits(const _libssh2_bn *bn) -{ - unsigned char number; - unsigned long offset, length, bits; - - if(!bn) - return 0; - - length = bn->length - 1; - - offset = 0; - while(!(*(bn->bignum + offset)) && (offset < length)) - offset++; - - bits = (length - offset) * 8; - number = bn->bignum[offset]; - - while(number >>= 1) - bits++; - - bits++; - - return bits; -} - -void -_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, - const unsigned char *bin) -{ - unsigned char *bignum; - unsigned long offset, length, bits; - - if(!bn || !bin || !len) - return; - - if(_libssh2_wincng_bignum_resize(bn, len)) - return; - - memcpy(bn->bignum, bin, len); - - bits = _libssh2_wincng_bignum_bits(bn); - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); - - offset = bn->length - length; - if(offset > 0) { - memmove(bn->bignum, bn->bignum + offset, length); - -#ifdef LIBSSH2_CLEAR_MEMORY - SecureZeroMemory(bn->bignum + length, offset); -#endif - - bignum = realloc(bn->bignum, length); - if(bignum) { - bn->bignum = bignum; - bn->length = length; - } - } -} - -void -_libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin) -{ - if(bin && bn && bn->bignum && bn->length > 0) { - memcpy(bin, bn->bignum, bn->length); - } -} - -void -_libssh2_wincng_bignum_free(_libssh2_bn *bn) -{ - if(bn) { - if(bn->bignum) { - _libssh2_wincng_safe_free(bn->bignum, bn->length); - bn->bignum = NULL; - } - bn->length = 0; - _libssh2_wincng_safe_free(bn, sizeof(_libssh2_bn)); - } -} - - -/* - * Windows CNG backend: Diffie-Hellman support. - */ - -void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx) -{ - *dhctx = _libssh2_wincng_bignum_init(); /* Random from client */ -} - -int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order) -{ - /* Generate x and e */ - if(_libssh2_wincng_bignum_rand(*dhctx, group_order * 8 - 1, 0, -1)) - return -1; - if(_libssh2_wincng_bignum_mod_exp(public, g, *dhctx, p)) - return -1; - return 0; -} - -int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p) -{ - /* Compute the shared secret */ - _libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p); - return 0; -} - -void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - _libssh2_wincng_bignum_free(*dhctx); - *dhctx = NULL; -} - -#endif /* LIBSSH2_WINCNG */ diff --git a/libs/libssh2/src/wincng.h b/libs/libssh2/src/wincng.h deleted file mode 100644 index f5838d0e64..0000000000 --- a/libs/libssh2/src/wincng.h +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Copyright (C) 2013-2015 Marc Hoersken <info@marc-hoersken.de> - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the copyright holder nor the names - * of any other contributors may be used to endorse or - * promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - */ - -/* required for cross-compilation against the w64 mingw-runtime package */ -#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#undef _WIN32_WINNT -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif - -#include <windows.h> -#include <bcrypt.h> - - -#define LIBSSH2_MD5 1 - -#define LIBSSH2_HMAC_RIPEMD 0 -#define LIBSSH2_HMAC_SHA256 1 -#define LIBSSH2_HMAC_SHA512 1 - -#define LIBSSH2_AES 1 -#define LIBSSH2_AES_CTR 1 -#define LIBSSH2_BLOWFISH 0 -#define LIBSSH2_RC4 1 -#define LIBSSH2_CAST 0 -#define LIBSSH2_3DES 1 - -#define LIBSSH2_RSA 1 -#define LIBSSH2_DSA 1 -#define LIBSSH2_ECDSA 0 -#define LIBSSH2_ED25519 0 - -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 -#define SHA256_DIGEST_LENGTH 32 -#define SHA512_DIGEST_LENGTH 64 - -#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) - -#if LIBSSH2_ECDSA -#else -#define _libssh2_ec_key void -#endif - -/*******************************************************************/ -/* - * Windows CNG backend: Global context handles - */ - -struct _libssh2_wincng_ctx { - BCRYPT_ALG_HANDLE hAlgRNG; - BCRYPT_ALG_HANDLE hAlgHashMD5; - BCRYPT_ALG_HANDLE hAlgHashSHA1; - BCRYPT_ALG_HANDLE hAlgHashSHA256; - BCRYPT_ALG_HANDLE hAlgHashSHA512; - BCRYPT_ALG_HANDLE hAlgHmacMD5; - BCRYPT_ALG_HANDLE hAlgHmacSHA1; - BCRYPT_ALG_HANDLE hAlgHmacSHA256; - BCRYPT_ALG_HANDLE hAlgHmacSHA512; - BCRYPT_ALG_HANDLE hAlgRSA; - BCRYPT_ALG_HANDLE hAlgDSA; - BCRYPT_ALG_HANDLE hAlgAES_CBC; - BCRYPT_ALG_HANDLE hAlgAES_ECB; - BCRYPT_ALG_HANDLE hAlgRC4_NA; - BCRYPT_ALG_HANDLE hAlg3DES_CBC; -}; - -struct _libssh2_wincng_ctx _libssh2_wincng; - - -/*******************************************************************/ -/* - * Windows CNG backend: Generic functions - */ - -void _libssh2_wincng_init(void); -void _libssh2_wincng_free(void); - -#define libssh2_crypto_init() \ - _libssh2_wincng_init() -#define libssh2_crypto_exit() \ - _libssh2_wincng_free() - -#define _libssh2_random(buf, len) \ - _libssh2_wincng_random(buf, len) - -#define libssh2_prepare_iovec(vec, len) /* Empty. */ - - -/*******************************************************************/ -/* - * Windows CNG backend: Hash structure - */ - -typedef struct __libssh2_wincng_hash_ctx { - BCRYPT_HASH_HANDLE hHash; - unsigned char *pbHashObject; - unsigned long dwHashObject; - unsigned long cbHash; -} _libssh2_wincng_hash_ctx; - -/* - * Windows CNG backend: Hash functions - */ - -#define libssh2_sha1_ctx _libssh2_wincng_hash_ctx -#define libssh2_sha1_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA1, \ - SHA_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_sha1_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha1_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_sha1(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA1, \ - hash, SHA_DIGEST_LENGTH) - -#define libssh2_sha256_ctx _libssh2_wincng_hash_ctx -#define libssh2_sha256_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA256, \ - SHA256_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_sha256_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha256_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_sha256(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA256, \ - hash, SHA256_DIGEST_LENGTH) - -#define libssh2_sha512_ctx _libssh2_wincng_hash_ctx -#define libssh2_sha512_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA512, \ - SHA512_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_sha512_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_sha512_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_sha512(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA512, \ - hash, SHA512_DIGEST_LENGTH) - -#define libssh2_md5_ctx _libssh2_wincng_hash_ctx -#define libssh2_md5_init(ctx) \ - (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashMD5, \ - MD5_DIGEST_LENGTH, NULL, 0) == 0) -#define libssh2_md5_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_md5_final(ctx, hash) \ - _libssh2_wincng_hash_final(&ctx, hash) -#define libssh2_md5(data, datalen, hash) \ - _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashMD5, \ - hash, MD5_DIGEST_LENGTH) - -/* - * Windows CNG backend: HMAC functions - */ - -#define libssh2_hmac_ctx _libssh2_wincng_hash_ctx -#define libssh2_hmac_ctx_init(ctx) -#define libssh2_hmac_sha1_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA1, \ - SHA_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_md5_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacMD5, \ - MD5_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_ripemd160_init(ctx, key, keylen) - /* not implemented */ -#define libssh2_hmac_sha256_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA256, \ - SHA256_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_sha512_init(ctx, key, keylen) \ - _libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHmacSHA512, \ - SHA512_DIGEST_LENGTH, key, keylen) -#define libssh2_hmac_update(ctx, data, datalen) \ - _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) -#define libssh2_hmac_final(ctx, hash) \ - _libssh2_wincng_hmac_final(&ctx, hash) -#define libssh2_hmac_cleanup(ctx) \ - _libssh2_wincng_hmac_cleanup(ctx) - - -/*******************************************************************/ -/* - * Windows CNG backend: Key Context structure - */ - -typedef struct __libssh2_wincng_key_ctx { - BCRYPT_KEY_HANDLE hKey; - unsigned char *pbKeyObject; - unsigned long cbKeyObject; -} _libssh2_wincng_key_ctx; - - -/* - * Windows CNG backend: RSA functions - */ - -#define libssh2_rsa_ctx _libssh2_wincng_key_ctx -#define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) \ - _libssh2_wincng_rsa_new(rsactx, e, e_len, n, n_len, \ - d, d_len, p, p_len, q, q_len, \ - e1, e1_len, e2, e2_len, c, c_len) -#define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \ - _libssh2_wincng_rsa_new_private(rsactx, s, filename, passphrase) -#define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) \ - _libssh2_wincng_rsa_new_private_frommemory(rsactx, s, filedata, \ - filedata_len, passphrase) -#define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \ - _libssh2_wincng_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) -#define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \ - _libssh2_wincng_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) -#define _libssh2_rsa_free(rsactx) \ - _libssh2_wincng_rsa_free(rsactx) - -/* - * Windows CNG backend: DSA functions - */ - -#define libssh2_dsa_ctx _libssh2_wincng_key_ctx -#define _libssh2_dsa_new(dsactx, p, p_len, q, q_len, \ - g, g_len, y, y_len, x, x_len) \ - _libssh2_wincng_dsa_new(dsactx, p, p_len, q, q_len, \ - g, g_len, y, y_len, x, x_len) -#define _libssh2_dsa_new_private(dsactx, s, filename, passphrase) \ - _libssh2_wincng_dsa_new_private(dsactx, s, filename, passphrase) -#define _libssh2_dsa_new_private_frommemory(dsactx, s, filedata, \ - filedata_len, passphrase) \ - _libssh2_wincng_dsa_new_private_frommemory(dsactx, s, filedata, \ - filedata_len, passphrase) -#define _libssh2_dsa_sha1_sign(dsactx, hash, hash_len, sig) \ - _libssh2_wincng_dsa_sha1_sign(dsactx, hash, hash_len, sig) -#define _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len) \ - _libssh2_wincng_dsa_sha1_verify(dsactx, sig, m, m_len) -#define _libssh2_dsa_free(dsactx) \ - _libssh2_wincng_dsa_free(dsactx) - -/* - * Windows CNG backend: Key functions - */ - -#define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \ - _libssh2_wincng_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) -#define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) \ - _libssh2_wincng_pub_priv_keyfilememory(s, m, m_len, p, p_len, \ - pk, pk_len, pw) - - -/*******************************************************************/ -/* - * Windows CNG backend: Cipher Context structure - */ - -struct _libssh2_wincng_cipher_ctx { - BCRYPT_KEY_HANDLE hKey; - unsigned char *pbKeyObject; - unsigned char *pbIV; - unsigned char *pbCtr; - unsigned long dwKeyObject; - unsigned long dwIV; - unsigned long dwBlockLength; - unsigned long dwCtrLength; -}; - -#define _libssh2_cipher_ctx struct _libssh2_wincng_cipher_ctx - -/* - * Windows CNG backend: Cipher Type structure - */ - -struct _libssh2_wincng_cipher_type { - BCRYPT_ALG_HANDLE *phAlg; - unsigned long dwKeyLength; - int useIV; /* TODO: Convert to bool when a C89 compatible bool type - is defined */ - int ctrMode; -}; - -#define _libssh2_cipher_type(type) struct _libssh2_wincng_cipher_type type - -#define _libssh2_cipher_aes256ctr { &_libssh2_wincng.hAlgAES_ECB, 32, 0, 1 } -#define _libssh2_cipher_aes192ctr { &_libssh2_wincng.hAlgAES_ECB, 24, 0, 1 } -#define _libssh2_cipher_aes128ctr { &_libssh2_wincng.hAlgAES_ECB, 16, 0, 1 } -#define _libssh2_cipher_aes256 { &_libssh2_wincng.hAlgAES_CBC, 32, 1, 0 } -#define _libssh2_cipher_aes192 { &_libssh2_wincng.hAlgAES_CBC, 24, 1, 0 } -#define _libssh2_cipher_aes128 { &_libssh2_wincng.hAlgAES_CBC, 16, 1, 0 } -#define _libssh2_cipher_arcfour { &_libssh2_wincng.hAlgRC4_NA, 16, 0, 0 } -#define _libssh2_cipher_3des { &_libssh2_wincng.hAlg3DES_CBC, 24, 1, 0 } - -/* - * Windows CNG backend: Cipher functions - */ - -#define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \ - _libssh2_wincng_cipher_init(ctx, type, iv, secret, encrypt) -#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \ - _libssh2_wincng_cipher_crypt(ctx, type, encrypt, block, blocklen) -#define _libssh2_cipher_dtor(ctx) \ - _libssh2_wincng_cipher_dtor(ctx) - -/*******************************************************************/ -/* - * Windows CNG backend: BigNumber Context - */ - -#define _libssh2_bn_ctx int /* not used */ -#define _libssh2_bn_ctx_new() 0 /* not used */ -#define _libssh2_bn_ctx_free(bnctx) ((void)0) /* not used */ - - -/*******************************************************************/ -/* - * Windows CNG backend: BigNumber structure - */ - -struct _libssh2_wincng_bignum { - unsigned char *bignum; - unsigned long length; -}; - -#define _libssh2_bn struct _libssh2_wincng_bignum - -/* - * Windows CNG backend: BigNumber functions - */ - -_libssh2_bn *_libssh2_wincng_bignum_init(void); - -#define _libssh2_bn_init() \ - _libssh2_wincng_bignum_init() -#define _libssh2_bn_init_from_bin() \ - _libssh2_bn_init() -#define _libssh2_bn_set_word(bn, word) \ - _libssh2_wincng_bignum_set_word(bn, word) -#define _libssh2_bn_from_bin(bn, len, bin) \ - _libssh2_wincng_bignum_from_bin(bn, len, bin) -#define _libssh2_bn_to_bin(bn, bin) \ - _libssh2_wincng_bignum_to_bin(bn, bin) -#define _libssh2_bn_bytes(bn) bn->length -#define _libssh2_bn_bits(bn) \ - _libssh2_wincng_bignum_bits(bn) -#define _libssh2_bn_free(bn) \ - _libssh2_wincng_bignum_free(bn) - -/* - * Windows CNG backend: Diffie-Hellman support - */ - -#define _libssh2_dh_ctx struct _libssh2_wincng_bignum * -#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx) -#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \ - _libssh2_dh_key_pair(dhctx, public, g, p, group_order) -#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \ - _libssh2_dh_secret(dhctx, secret, f, p) -#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx) - -/*******************************************************************/ -/* - * Windows CNG backend: forward declarations - */ -void _libssh2_wincng_init(void); -void _libssh2_wincng_free(void); -int _libssh2_wincng_random(void *buf, int len); - -int -_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, - BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen, - unsigned char *key, unsigned long keylen); -int -_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx, - const unsigned char *data, unsigned long datalen); -int -_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash); -int -_libssh2_wincng_hash(unsigned char *data, unsigned long datalen, - BCRYPT_ALG_HANDLE hAlg, - unsigned char *hash, unsigned long hashlen); - -int -_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash); -void -_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx); - -int -_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len, - unsigned long flags); - -int -_libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, - const unsigned char *edata, - unsigned long elen, - const unsigned char *ndata, - unsigned long nlen, - const unsigned char *ddata, - unsigned long dlen, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *e1data, - unsigned long e1len, - const unsigned char *e2data, - unsigned long e2len, - const unsigned char *coeffdata, - unsigned long coefflen); -int -_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); -int -_libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len); -void -_libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa); - -#if LIBSSH2_DSA -int -_libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *xdata, - unsigned long xlen); -int -_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase); -int -_libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase); -int -_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa, - const unsigned char *sig_fixed, - const unsigned char *m, - unsigned long m_len); -int -_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, - const unsigned char *hash, - unsigned long hash_len, - unsigned char *sig_fixed); -void -_libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa); -#endif - -int -_libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekey, - const char *passphrase); -int -_libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase); - -int -_libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt); -int -_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen); -void -_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx); - -_libssh2_bn * -_libssh2_wincng_bignum_init(void); -int -_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word); -unsigned long -_libssh2_wincng_bignum_bits(const _libssh2_bn *bn); -void -_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, - const unsigned char *bin); -void -_libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin); -void -_libssh2_wincng_bignum_free(_libssh2_bn *bn); -extern void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx); -extern int -_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, - _libssh2_bn *g, _libssh2_bn *p, int group_order); -extern int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p); -extern void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); |