diff --git a/libssh/CMakeLists.txt b/libssh/CMakeLists.txt index 2c5c7232..5998bc50 100644 --- a/libssh/CMakeLists.txt +++ b/libssh/CMakeLists.txt @@ -71,6 +71,13 @@ if (WITH_GSSAPI) find_package(GSSAPI) endif (WITH_GSSAPI) +if (WITH_NACL) + find_package(NaCl) + if (NOT NACL_FOUND) + set(WITH_NACL OFF) + endif (NOT NACL_FOUND) +endif (WITH_NACL) + # config.h checks include(ConfigureChecks.cmake) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) @@ -125,6 +132,7 @@ message(STATUS "********** ${PROJECT_NAME} build options : **********") message(STATUS "zlib support: ${WITH_ZLIB}") message(STATUS "libgcrypt support: ${WITH_GCRYPT}") +message(STATUS "libnacl support: ${WITH_NACL}") message(STATUS "SSH-1 support: ${WITH_SSH1}") message(STATUS "SFTP support: ${WITH_SFTP}") message(STATUS "Server support : ${WITH_SERVER}") diff --git a/libssh/ConfigureChecks.cmake b/libssh/ConfigureChecks.cmake index 1c89c4c7..472fe79e 100644 --- a/libssh/ConfigureChecks.cmake +++ b/libssh/ConfigureChecks.cmake @@ -50,6 +50,7 @@ check_include_file(argp.h HAVE_ARGP_H) check_include_file(pty.h HAVE_PTY_H) check_include_file(termios.h HAVE_TERMIOS_H) check_include_file(unistd.h HAVE_UNISTD_H) +check_include_file(util.h HAVE_UTIL_H) if (WIN32) check_include_files("winsock2.h;ws2tcpip.h;wspiapi.h" HAVE_WSPIAPI_H) @@ -93,6 +94,7 @@ endif (NOT WITH_GCRYPT) # FUNCTIONS +check_function_exists(isblank HAVE_ISBLANK) check_function_exists(strncpy HAVE_STRNCPY) check_function_exists(vsnprintf HAVE_VSNPRINTF) check_function_exists(snprintf HAVE_SNPRINTF) diff --git a/libssh/DefineOptions.cmake b/libssh/DefineOptions.cmake index 756b948a..ab7819a5 100644 --- a/libssh/DefineOptions.cmake +++ b/libssh/DefineOptions.cmake @@ -13,7 +13,7 @@ option(WITH_TESTING "Build with unit tests" OFF) option(WITH_CLIENT_TESTING "Build with client tests; requires a running sshd" OFF) option(WITH_BENCHMARKS "Build benchmarks tools" OFF) option(WITH_EXAMPLES "Build examples" ON) - +option(WITH_NACL "Build with libnacl (curve25519" ON) if (WITH_ZLIB) set(WITH_LIBZ ON) else (WITH_ZLIB) @@ -27,3 +27,7 @@ endif(WITH_BENCHMARKS) if (WITH_TESTING) set(WITH_STATIC_LIB ON) endif (WITH_TESTING) + +if (WITH_NACL) + set(WITH_NACL ON) +endif (WITH_NACL) \ No newline at end of file diff --git a/libssh/cmake/Modules/DefinePlatformDefaults.cmake b/libssh/cmake/Modules/DefinePlatformDefaults.cmake index 502d936b..77f8a461 100644 --- a/libssh/cmake/Modules/DefinePlatformDefaults.cmake +++ b/libssh/cmake/Modules/DefinePlatformDefaults.cmake @@ -26,3 +26,7 @@ endif (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") if (CMAKE_SYSTEM_NAME MATCHES "OS2") set(OS2 TRUE) endif (CMAKE_SYSTEM_NAME MATCHES "OS2") + +if (CMAKE_SYSTEM_NAME MATCHES "Darwin") + set (OSX TRUE) +endif (CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/libssh/config.h.cmake b/libssh/config.h.cmake index f7f8957f..7e8cb6a8 100644 --- a/libssh/config.h.cmake +++ b/libssh/config.h.cmake @@ -20,6 +20,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PTY_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UTIL_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TERMIOS_H 1 @@ -79,6 +82,9 @@ /* Define to 1 if you have the `_vsnprintf_s' function. */ #cmakedefine HAVE__VSNPRINTF_S 1 +/* Define to 1 if you have the `isblank' function. */ +#cmakedefine HAVE_ISBLANK 1 + /* Define to 1 if you have the `strncpy' function. */ #cmakedefine HAVE_STRNCPY 1 @@ -123,7 +129,6 @@ /* Define to 1 if you have the `pthread' library (-lpthread). */ #cmakedefine HAVE_PTHREAD 1 - /**************************** OPTIONS ****************************/ #cmakedefine HAVE_GCC_THREAD_LOCAL_STORAGE 1 @@ -155,6 +160,9 @@ /* Define to 1 if you want to enable calltrace debug output */ #cmakedefine DEBUG_CALLTRACE 1 +/* Define to 1 if you want to enable NaCl support */ +#cmakedefine WITH_NACL 1 + /*************************** ENDIAN *****************************/ /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most diff --git a/libssh/doc/doxy.config.in b/libssh/doc/doxy.config.in index 276a2611..4da9b2c9 100644 --- a/libssh/doc/doxy.config.in +++ b/libssh/doc/doxy.config.in @@ -1628,7 +1628,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = WITH_SERVER WITH_SFTP WITH_PCAP # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/libssh/doc/mainpage.dox b/libssh/doc/mainpage.dox index 5fb695a6..70f774ad 100644 --- a/libssh/doc/mainpage.dox +++ b/libssh/doc/mainpage.dox @@ -19,7 +19,7 @@ the interesting functions as you go. The libssh library provides: - - Key Exchange Methods: ecdh-sha2-nistp256, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1 + - Key Exchange Methods: curve25519-sha256@libssh.org, ecdh-sha2-nistp256, diffie-hellman-group1-sha1, diffie-hellman-group14-sha1 - Hostkey Types: ecdsa-sha2-nistp256, ssh-dss, ssh-rsa - Ciphers: aes256-ctr, aes192-ctr, aes128-ctr, aes256-cbc (rijndael-cbc@lysator.liu.se), aes192-cbc, aes128-cbc, 3des-cbc, des-cbc-ssh1, blowfish-cbc, none - Compression Schemes: zlib, zlib@openssh.com, none @@ -184,6 +184,8 @@ It was later modified and expanded by the following RFCs. Authentication and Key Exchange for the Secure Shell (SSH) Protocol - RFC 4716, The Secure Shell (SSH) Public Key File Format + - RFC 5647, + AES Galois Counter Mode for the Secure Shell Transport Layer Protocol - RFC 5656, Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer @@ -203,6 +205,12 @@ do the same in libssh. @subsection main-rfc-extensions Secure Shell Extensions +The libssh project has an extension to support Curve25519 which is also supported by +the OpenSSH project. + + - curve25519-sha256@libssh.org, + Curve25519-SHA256 for ECDH KEX + The OpenSSH project has defined some extensions to the protocol. We support some of them like the statvfs calls in SFTP or the ssh-agent. diff --git a/libssh/doc/sftp.dox b/libssh/doc/sftp.dox index 97f9afbb..8b7c7e1a 100644 --- a/libssh/doc/sftp.dox +++ b/libssh/doc/sftp.dox @@ -210,52 +210,63 @@ results to come. Synchronous read is done with sftp_read(). -The following example prints the contents of remote file "/etc/profile". For -each 1024 bytes of information read, it waits until the end of the read operation: +Files are normally transferred in chunks. A good chunk size is 16 KB. The following +example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we +request, sftp_read blocks till the data has been received: @code +// Good chunk size +#define MAX_XFER_BUF_SIZE 16384 + int sftp_read_sync(ssh_session session, sftp_session sftp) { int access_type; sftp_file file; - char buffer[1024]; - int nbytes, rc; + char buffer[MAX_XFER_BUF_SIZE]; + int nbytes, nwritten, rc; + int fd; access_type = O_RDONLY; file = sftp_open(sftp, "/etc/profile", access_type, 0); - if (file == NULL) - { - fprintf(stderr, "Can't open file for reading: %s\n", - ssh_get_error(session)); - return SSH_ERROR; - } - - nbytes = sftp_read(file, buffer, sizeof(buffer)); - while (nbytes > 0) - { - if (write(1, buffer, nbytes) != nbytes) - { - sftp_close(file); + if (file == NULL) { + fprintf(stderr, "Can't open file for reading: %s\n", + ssh_get_error(session)); return SSH_ERROR; - } - nbytes = sftp_read(file, buffer, sizeof(buffer)); } - if (nbytes < 0) - { - fprintf(stderr, "Error while reading file: %s\n", - ssh_get_error(session)); - sftp_close(file); - return SSH_ERROR; + fd = open("/path/to/profile", O_CREAT); + if (fd < 0) { + fprintf(stderr, "Can't open file for writing: %s\n", + strerror(errno)); + return SSH_ERROR; + } + + for (;;) { + nbytes = sftp_read(file, buffer, sizeof(buffer)); + if (nbytes == 0) { + break; // EOF + } else if (nbytes < 0) { + fprintf(stderr, "Error while reading file: %s\n", + ssh_get_error(session)); + sftp_close(file); + return SSH_ERROR; + } + + nwritten = write(fd, buf, nbytes); + if (nwritten != nbytes) { + fprintf(stderr, "Error writing: %s\n", + strerror(errno)); + sftp_close(file); + return SSH_ERROR; + } } rc = sftp_close(file); - if (rc != SSH_OK) - { - fprintf(stderr, "Can't close the read file: %s\n", - ssh_get_error(session)); - return rc; + if (rc != SSH_OK) { + fprintf(stderr, "Can't close the read file: %s\n", + ssh_get_error(session)); + return rc; } return SSH_OK; @@ -274,11 +285,14 @@ The example below reads a very big file in asynchronous, nonblocking, mode. Each time the data are not ready yet, a counter is incrementer. @code +// Good chunk size +#define MAX_XFER_BUF_SIZE 16384 + int sftp_read_async(ssh_session session, sftp_session sftp) { int access_type; sftp_file file; - char buffer[1024]; + char buffer[MAX_XFER_BUF_SIZE]; int async_request; int nbytes; long counter; @@ -287,8 +301,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp) access_type = O_RDONLY; file = sftp_open(sftp, "some_very_big_file", access_type, 0); - if (file == NULL) - { + if (file == NULL) { fprintf(stderr, "Can't open file for reading: %s\n", ssh_get_error(session)); return SSH_ERROR; @@ -298,27 +311,31 @@ int sftp_read_async(ssh_session session, sftp_session sftp) async_request = sftp_async_read_begin(file, sizeof(buffer)); counter = 0L; usleep(10000); - if (async_request >= 0) + if (async_request >= 0) { nbytes = sftp_async_read(file, buffer, sizeof(buffer), async_request); - else nbytes = -1; - while (nbytes > 0 || nbytes == SSH_AGAIN) - { - if (nbytes > 0) - { - write(1, buffer, nbytes); - async_request = sftp_async_read_begin(file, sizeof(buffer)); - } - else counter++; - usleep(10000); - if (async_request >= 0) - nbytes = sftp_async_read(file, buffer, sizeof(buffer), - async_request); - else nbytes = -1; + } else { + nbytes = -1; } - if (nbytes < 0) - { + while (nbytes > 0 || nbytes == SSH_AGAIN) { + if (nbytes > 0) { + write(1, buffer, nbytes); + async_request = sftp_async_read_begin(file, sizeof(buffer)); + } else { + counter++; + } + usleep(10000); + + if (async_request >= 0) { + nbytes = sftp_async_read(file, buffer, sizeof(buffer), + async_request); + } else { + nbytes = -1; + } + } + + if (nbytes < 0) { fprintf(stderr, "Error while reading file: %s\n", ssh_get_error(session)); sftp_close(file); @@ -328,8 +345,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp) printf("The counter has reached value: %ld\n", counter); rc = sftp_close(file); - if (rc != SSH_OK) - { + if (rc != SSH_OK) { fprintf(stderr, "Can't close the read file: %s\n", ssh_get_error(session)); return rc; diff --git a/libssh/examples/CMakeLists.txt b/libssh/examples/CMakeLists.txt index fc1c9341..c155e097 100644 --- a/libssh/examples/CMakeLists.txt +++ b/libssh/examples/CMakeLists.txt @@ -11,9 +11,9 @@ include_directories( ${CMAKE_BINARY_DIR} ) -if (BSD OR SOLARIS) +if (BSD OR SOLARIS OR OSX) find_package(Argp) -endif (BSD OR SOLARIS) +endif (BSD OR SOLARIS OR OSX) if (UNIX AND NOT WIN32) add_executable(libssh_scp libssh_scp.c ${examples_SRCS}) @@ -28,7 +28,7 @@ if (UNIX AND NOT WIN32) if (WITH_SERVER) if (HAVE_LIBUTIL) add_executable(samplesshd-tty samplesshd-tty.c) - target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} util) + target_link_libraries(samplesshd-tty ${LIBSSH_SHARED_LIBRARY} ${ARGP_LIBRARIES} util) endif (HAVE_LIBUTIL) endif (WITH_SERVER) diff --git a/libssh/examples/knownhosts.c b/libssh/examples/knownhosts.c index 37c0ba4e..5097cd93 100644 --- a/libssh/examples/knownhosts.c +++ b/libssh/examples/knownhosts.c @@ -34,14 +34,26 @@ int verify_knownhost(ssh_session session){ int state; char buf[10]; unsigned char *hash = NULL; - int hlen; + size_t hlen; + ssh_key srv_pubkey; + int rc; state=ssh_is_server_known(session); - hlen = ssh_get_pubkey_hash(session, &hash); - if (hlen < 0) { - return -1; + rc = ssh_get_publickey(session, &srv_pubkey); + if (rc < 0) { + return -1; } + + rc = ssh_get_publickey_hash(srv_pubkey, + SSH_PUBLICKEY_HASH_SHA1, + &hash, + &hlen); + ssh_key_free(srv_pubkey); + if (rc < 0) { + return -1; + } + switch(state){ case SSH_SERVER_KNOWN_OK: break; /* ok */ diff --git a/libssh/examples/samplesshd-tty.c b/libssh/examples/samplesshd-tty.c index 7ed70d3d..83b75648 100644 --- a/libssh/examples/samplesshd-tty.c +++ b/libssh/examples/samplesshd-tty.c @@ -25,8 +25,12 @@ clients must be made or how a client should react. #include #include #include +#ifdef HAVE_PTY_H #include - +#endif +#ifdef HAVE_UTIL_H +#include +#endif #define SSHD_USER "libssh" #define SSHD_PASSWORD "libssh" diff --git a/libssh/include/libssh/callbacks.h b/libssh/include/libssh/callbacks.h index 131e8229..a841f2e5 100644 --- a/libssh/include/libssh/callbacks.h +++ b/libssh/include/libssh/callbacks.h @@ -166,7 +166,7 @@ typedef struct ssh_callbacks_struct *ssh_callbacks; * @param user User that wants to authenticate * @param password Password used for authentication * @param userdata Userdata to be passed to the callback function. - * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_DENIED Authentication failed. */ @@ -179,7 +179,7 @@ typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user * @param session Current session handler * @param user User that wants to authenticate * @param userdata Userdata to be passed to the callback function. - * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_DENIED Authentication failed. */ @@ -191,7 +191,7 @@ typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, vo * @param user Username of the user (can be spoofed) * @param principal Authenticated principal of the user, including realm. * @param userdata Userdata to be passed to the callback function. - * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_DENIED Authentication failed. * @warning Implementations should verify that parameter user matches in some way the principal. @@ -209,7 +209,7 @@ typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *us * SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be * replied with a SSH_AUTH_DENIED. * @param userdata Userdata to be passed to the callback function. - * @returns SSH_AUTH_OK Authentication is accepted. + * @returns SSH_AUTH_SUCCESS Authentication is accepted. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_DENIED Authentication failed. */ diff --git a/libssh/include/libssh/curve25519.h b/libssh/include/libssh/curve25519.h index 004210cb..35e25be0 100644 --- a/libssh/include/libssh/curve25519.h +++ b/libssh/include/libssh/curve25519.h @@ -26,15 +26,23 @@ #ifdef WITH_NACL -#define HAVE_CURVE25519 #include #define CURVE25519_PUBKEY_SIZE crypto_scalarmult_curve25519_BYTES #define CURVE25519_PRIVKEY_SIZE crypto_scalarmult_curve25519_SCALARBYTES +#define crypto_scalarmult_base crypto_scalarmult_curve25519_base +#define crypto_scalarmult crypto_scalarmult_curve25519 +#else +#define CURVE25519_PUBKEY_SIZE 32 +#define CURVE25519_PRIVKEY_SIZE 32 +int crypto_scalarmult_base(unsigned char *q, const unsigned char *n); +int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p); +#endif /* WITH_NACL */ + +#define HAVE_CURVE25519 typedef unsigned char ssh_curve25519_pubkey[CURVE25519_PUBKEY_SIZE]; typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE]; -#endif /* WITH_NACL */ int ssh_client_curve25519_init(ssh_session session); int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet); diff --git a/libssh/include/libssh/libcrypto.h b/libssh/include/libssh/libcrypto.h index 54c78b16..5cf2da28 100644 --- a/libssh/include/libssh/libcrypto.h +++ b/libssh/include/libssh/libcrypto.h @@ -38,6 +38,11 @@ typedef SHA_CTX* SHACTX; typedef SHA256_CTX* SHA256CTX; typedef MD5_CTX* MD5CTX; typedef HMAC_CTX* HMACCTX; +#ifdef HAVE_ECC +typedef EVP_MD_CTX *EVPCTX; +#else +typedef void *EVPCTX; +#endif #define SHA_DIGEST_LEN SHA_DIGEST_LENGTH #ifdef MD5_DIGEST_LEN diff --git a/libssh/include/libssh/libgcrypt.h b/libssh/include/libssh/libgcrypt.h index 54982063..c1844a53 100644 --- a/libssh/include/libssh/libgcrypt.h +++ b/libssh/include/libssh/libgcrypt.h @@ -29,6 +29,7 @@ typedef gcry_md_hd_t SHACTX; typedef gcry_md_hd_t MD5CTX; typedef gcry_md_hd_t HMACCTX; +typedef void *EVPCTX; #define SHA_DIGEST_LENGTH 20 #define SHA_DIGEST_LEN SHA_DIGEST_LENGTH #define MD5_DIGEST_LEN 16 diff --git a/libssh/include/libssh/libssh.h b/libssh/include/libssh/libssh.h index a451620e..3833adcd 100644 --- a/libssh/include/libssh/libssh.h +++ b/libssh/include/libssh/libssh.h @@ -208,10 +208,14 @@ enum ssh_publickey_state_e { SSH_PUBLICKEY_STATE_WRONG=2 }; -/* status flags */ +/* Status flags */ +/** Socket is closed */ #define SSH_CLOSED 0x01 +/** Reading to socket won't block */ #define SSH_READ_PENDING 0x02 +/** Session was closed due to an error */ #define SSH_CLOSED_ERROR 0x04 +/** Output buffer not empty */ #define SSH_WRITE_PENDING 0x08 enum ssh_server_known_e { @@ -408,8 +412,20 @@ LIBSSH_API socket_t ssh_get_fd(ssh_session session); LIBSSH_API char *ssh_get_hexa(const unsigned char *what, size_t len); LIBSSH_API char *ssh_get_issue_banner(ssh_session session); LIBSSH_API int ssh_get_openssh_version(ssh_session session); + LIBSSH_API int ssh_get_publickey(ssh_session session, ssh_key *key); -LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash); + +enum ssh_publickey_hash_type { + SSH_PUBLICKEY_HASH_SHA1, + SSH_PUBLICKEY_HASH_MD5 +}; +LIBSSH_API int ssh_get_publickey_hash(const ssh_key key, + enum ssh_publickey_hash_type type, + unsigned char **hash, + size_t *hlen); + +SSH_DEPRECATED LIBSSH_API int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash); + LIBSSH_API int ssh_get_random(void *where,int len,int strong); LIBSSH_API int ssh_get_version(ssh_session session); LIBSSH_API int ssh_get_status(ssh_session session); diff --git a/libssh/include/libssh/pki.h b/libssh/include/libssh/pki.h index 96bacd52..89a0f982 100644 --- a/libssh/include/libssh/pki.h +++ b/libssh/include/libssh/pki.h @@ -60,6 +60,7 @@ struct ssh_key_struct { struct ssh_signature_struct { enum ssh_keytypes_e type; + const char *type_c; #ifdef HAVE_LIBGCRYPT gcry_sexp_t dsa_sig; gcry_sexp_t rsa_sig; diff --git a/libssh/include/libssh/priv.h b/libssh/include/libssh/priv.h index 43f749bb..d8176d90 100644 --- a/libssh/include/libssh/priv.h +++ b/libssh/include/libssh/priv.h @@ -67,7 +67,9 @@ # define strcasecmp _stricmp # define strncasecmp _strnicmp -# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r') +# if ! defined(HAVE_ISBLANK) +# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r') +# endif # define usleep(X) Sleep(((X)+1000)/1000) @@ -153,6 +155,16 @@ int gettimeofday(struct timeval *__p, void *__t); #include #endif +/* + * get rid of deprecacy warnings on OSX when using OpenSSL + */ +#if defined(__APPLE__) + #ifdef MAC_OS_X_VERSION_MIN_REQUIRED + #undef MAC_OS_X_VERSION_MIN_REQUIRED + #endif + #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6 +#endif + /* forward declarations */ struct ssh_common_struct; struct ssh_kex_struct; @@ -252,7 +264,7 @@ int match_hostname(const char *host, const char *pattern, unsigned int len); /** Overwrite the buffer with '\0' */ # define BURN_BUFFER(x, size) do { \ if ((x) != NULL) \ - memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \ + memset((x), '\0', (size)); __asm__ volatile("" : : "r"(&(x)) : "memory"); \ } while(0) #else /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */ /** Overwrite a string with '\0' */ @@ -263,7 +275,7 @@ int match_hostname(const char *host, const char *pattern, unsigned int len); /** Overwrite the buffer with '\0' */ # define BURN_BUFFER(x, size) do { \ if ((x) != NULL) \ - memset((x), '\0', (size))); __asm__ volatile("" : : "r"(&(x)) : "memory"); \ + memset((x), '\0', (size)); __asm__ volatile("" : : "r"(&(x)) : "memory"); \ } while(0) #endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */ diff --git a/libssh/include/libssh/wrapper.h b/libssh/include/libssh/wrapper.h index 90c268d9..7374a88a 100644 --- a/libssh/include/libssh/wrapper.h +++ b/libssh/include/libssh/wrapper.h @@ -53,6 +53,9 @@ void sha1(unsigned char *digest,int len,unsigned char *hash); void sha256(unsigned char *digest, int len, unsigned char *hash); void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen); +EVPCTX evp_init(int nid); +void evp_update(EVPCTX ctx, const void *data, unsigned long len); +void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen); ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type); void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len); diff --git a/libssh/src/CMakeLists.txt b/libssh/src/CMakeLists.txt index b4046805..83435d0c 100644 --- a/libssh/src/CMakeLists.txt +++ b/libssh/src/CMakeLists.txt @@ -115,6 +115,7 @@ set(libssh_SRCS client.c config.c connect.c + curve25519.c dh.c ecdh.c error.c @@ -204,12 +205,12 @@ if (WITH_GSSAPI AND GSSAPI_FOUND) ) endif (WITH_GSSAPI AND GSSAPI_FOUND) -if (WITH_NACL) +if (NOT WITH_NACL) set(libssh_SRCS ${libssh_SRCS} - curve25519.c + curve25519_ref.c ) -endif (WITH_NACL) +endif (NOT WITH_NACL) include_directories( ${LIBSSH_PUBLIC_INCLUDE_DIRS} diff --git a/libssh/src/auth.c b/libssh/src/auth.c index de7965d2..6664c203 100644 --- a/libssh/src/auth.c +++ b/libssh/src/auth.c @@ -355,7 +355,7 @@ int ssh_userauth_list(ssh_session session, const char *username) * later. * * @note Most server implementations do not permit changing the username during - * authentication. The username should only be set with ssh_optoins_set() only + * authentication. The username should only be set with ssh_options_set() only * before you connect to the server. */ int ssh_userauth_none(ssh_session session, const char *username) { @@ -478,7 +478,7 @@ fail: * later. * * @note Most server implementations do not permit changing the username during - * authentication. The username should only be set with ssh_optoins_set() only + * authentication. The username should only be set with ssh_options_set() only * before you connect to the server. */ int ssh_userauth_try_publickey(ssh_session session, @@ -640,7 +640,7 @@ fail: * later. * * @note Most server implementations do not permit changing the username during - * authentication. The username should only be set with ssh_optoins_set() only + * authentication. The username should only be set with ssh_options_set() only * before you connect to the server. */ int ssh_userauth_publickey(ssh_session session, @@ -961,7 +961,7 @@ struct ssh_agent_state_struct { * later. * * @note Most server implementations do not permit changing the username during - * authentication. The username should only be set with ssh_optoins_set() only + * authentication. The username should only be set with ssh_options_set() only * before you connect to the server. */ int ssh_userauth_agent(ssh_session session, @@ -1083,7 +1083,7 @@ struct ssh_auth_auto_state_struct { * later. * * @note Most server implementations do not permit changing the username during - * authentication. The username should only be set with ssh_optoins_set() only + * authentication. The username should only be set with ssh_options_set() only * before you connect to the server. */ int ssh_userauth_publickey_auto(ssh_session session, @@ -1297,7 +1297,7 @@ int ssh_userauth_publickey_auto(ssh_session session, * later. * * @note Most server implementations do not permit changing the username during - * authentication. The username should only be set with ssh_optoins_set() only + * authentication. The username should only be set with ssh_options_set() only * before you connect to the server. * * @see ssh_userauth_none() diff --git a/libssh/src/bind.c b/libssh/src/bind.c index e4c9327e..8132e3e9 100644 --- a/libssh/src/bind.c +++ b/libssh/src/bind.c @@ -454,8 +454,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) { #else close(fd); #endif - if (session->socket) - ssh_socket_close(session->socket); + ssh_socket_free(session->socket); } return rc; } diff --git a/libssh/src/channels.c b/libssh/src/channels.c index 81b2bdfb..f7bcded2 100644 --- a/libssh/src/channels.c +++ b/libssh/src/channels.c @@ -2089,7 +2089,7 @@ SSH_PACKET_CALLBACK(ssh_request_denied){ static int ssh_global_request_termination(void *s){ ssh_session session = (ssh_session) s; if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING || - session->session_state != SSH_SESSION_STATE_ERROR) + session->session_state == SSH_SESSION_STATE_ERROR) return 1; else return 0; @@ -2117,43 +2117,66 @@ static int ssh_global_request_termination(void *s){ static int global_request(ssh_session session, const char *request, ssh_buffer buffer, int reply) { ssh_string req = NULL; - int rc = SSH_ERROR; + int rc; - if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) + switch (session->global_req_state) { + case SSH_CHANNEL_REQ_STATE_NONE: + break; + default: goto pending; + } + + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST); + if (rc < 0) { + goto error; + } + req = ssh_string_from_char(request); if (req == NULL) { - ssh_set_error_oom(session); - goto error; + ssh_set_error_oom(session); + rc = SSH_ERROR; + goto error; } - if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, req) < 0 || - buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { - ssh_set_error_oom(session); - goto error; - } + rc = buffer_add_ssh_string(session->out_buffer, req); ssh_string_free(req); - req=NULL; + if (rc < 0) { + ssh_set_error_oom(session); + rc = SSH_ERROR; + goto error; + } + + rc = buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1); + if (rc < 0) { + ssh_set_error_oom(session); + rc = SSH_ERROR; + goto error; + } if (buffer != NULL) { - if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer), - buffer_get_rest_len(buffer)) < 0) { - ssh_set_error_oom(session); - goto error; - } + rc = buffer_add_data(session->out_buffer, + buffer_get_rest(buffer), + buffer_get_rest_len(buffer)); + if (rc < 0) { + ssh_set_error_oom(session); + rc = SSH_ERROR; + goto error; + } } + session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING; - if (packet_send(session) == SSH_ERROR) { - return rc; + rc = packet_send(session); + if (rc == SSH_ERROR) { + return rc; } SSH_LOG(SSH_LOG_PACKET, "Sent a SSH_MSG_GLOBAL_REQUEST %s", request); - if (reply == 0) { - session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE; - return SSH_OK; + if (reply == 0) { + session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE; + + return SSH_OK; } pending: rc = ssh_handle_packets_termination(session, @@ -2178,16 +2201,16 @@ pending: break; case SSH_CHANNEL_REQ_STATE_ERROR: case SSH_CHANNEL_REQ_STATE_NONE: - rc=SSH_ERROR; + rc = SSH_ERROR; break; case SSH_CHANNEL_REQ_STATE_PENDING: - rc=SSH_AGAIN; - break; + return SSH_AGAIN; } + session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE; return rc; error: - ssh_string_free(req); + buffer_reinit(session->out_buffer); return rc; } @@ -3325,17 +3348,18 @@ error: } /** - * @brief Send the exit status to the remote process (as described in RFC 4254, section 6.10). + * @brief Send the exit status to the remote process * - * Sends the exit status to the remote process. + * Sends the exit status to the remote process (as described in RFC 4254, + * section 6.10). * Only SSH-v2 is supported (I'm not sure about SSH-v1). * * @param[in] channel The channel to send exit status. * - * @param[in] sig The exit status to send + * @param[in] exit_status The exit status to send * - * @return SSH_OK on success, SSH_ERROR if an error occurred - * (including attempts to send exit status via SSH-v1 session). + * @return SSH_OK on success, SSH_ERROR if an error occurred. + * (including attempts to send exit status via SSH-v1 session). */ int ssh_channel_request_send_exit_status(ssh_channel channel, int exit_status) { ssh_buffer buffer = NULL; diff --git a/libssh/src/client.c b/libssh/src/client.c index dad988ed..1fb963d7 100644 --- a/libssh/src/client.c +++ b/libssh/src/client.c @@ -105,14 +105,18 @@ static int callback_receive_banner(const void *data, size_t len, void *user) { ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1); } #endif - if(buffer[i]=='\r') - buffer[i]='\0'; - if(buffer[i]=='\n'){ - buffer[i]='\0'; - str=strdup(buffer); - /* number of bytes read */ - ret=i+1; - session->serverbanner=str; + if(buffer[i]=='\r') { + buffer[i]='\0'; + } + if (buffer[i]=='\n') { + buffer[i] = '\0'; + str = strdup(buffer); + if (str == NULL) { + return SSH_ERROR; + } + /* number of bytes read */ + ret = i + 1; + session->serverbanner = str; session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED; SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str); session->ssh_connection_callback(session); @@ -529,7 +533,7 @@ pending: if (timeout == 0) { timeout = 10 * 1000; } - SSH_LOG(SSH_LOG_PACKET,"ssh_connect: Actual timeout : %d", timeout); + SSH_LOG(SSH_LOG_PACKET,"Actual timeout : %d", timeout); ret = ssh_handle_packets_termination(session, timeout, ssh_connect_termination, session); if (ret == SSH_ERROR || !ssh_connect_termination(session)) { ssh_set_error(session, SSH_FATAL, @@ -546,7 +550,7 @@ pending: session->session_state = SSH_SESSION_STATE_ERROR; } } - SSH_LOG(SSH_LOG_PACKET,"ssh_connect: Actual state : %d",session->session_state); + SSH_LOG(SSH_LOG_PACKET,"current state : %d",session->session_state); if(!ssh_is_blocking(session) && !ssh_connect_termination(session)){ return SSH_AGAIN; } diff --git a/libssh/src/connect.c b/libssh/src/connect.c index f7965cbe..b299d41e 100644 --- a/libssh/src/connect.c +++ b/libssh/src/connect.c @@ -436,6 +436,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){ */ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, fd_set *readfds, struct timeval *timeout) { + fd_set origfds; socket_t fd; int i,j; int rc; @@ -449,9 +450,11 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, ssh_event_add_session(event, channels[i]->session); } + FD_ZERO(&origfds); for (fd = 0; fd < maxfd ; fd++) { if (FD_ISSET(fd, readfds)) { ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds); + FD_SET(fd, &origfds); } } outchannels[0] = NULL; @@ -485,13 +488,17 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, /* since there's nothing, let's fire the polling */ rc = ssh_event_dopoll(event,tm); if (rc == SSH_ERROR){ - ssh_event_free(event); - return SSH_ERROR; + goto out; } tm = ssh_timeout_update(&ts, base_tm); firstround=0; } while (1); out: + for (fd = 0; fd < maxfd; fd++) { + if (FD_ISSET(fd, &origfds)) { + ssh_event_remove_fd(event, fd); + } + } ssh_event_free(event); return SSH_OK; } diff --git a/libssh/src/curve25519.c b/libssh/src/curve25519.c index 653beee0..153fbcd9 100644 --- a/libssh/src/curve25519.c +++ b/libssh/src/curve25519.c @@ -26,7 +26,10 @@ #include "libssh/curve25519.h" #ifdef HAVE_CURVE25519 +#ifdef WITH_NACL #include "nacl/crypto_scalarmult_curve25519.h" +#endif + #include "libssh/ssh2.h" #include "libssh/buffer.h" #include "libssh/priv.h" @@ -53,7 +56,7 @@ int ssh_client_curve25519_init(ssh_session session){ return SSH_ERROR; } - crypto_scalarmult_curve25519_base(session->next_crypto->curve25519_client_pubkey, + crypto_scalarmult_base(session->next_crypto->curve25519_client_pubkey, session->next_crypto->curve25519_privkey); client_pubkey = ssh_string_new(CURVE25519_PUBKEY_SIZE); if (client_pubkey == NULL) { @@ -81,10 +84,10 @@ static int ssh_curve25519_build_k(ssh_session session) { } if (session->server) - crypto_scalarmult_curve25519(k, session->next_crypto->curve25519_privkey, + crypto_scalarmult(k, session->next_crypto->curve25519_privkey, session->next_crypto->curve25519_client_pubkey); else - crypto_scalarmult_curve25519(k, session->next_crypto->curve25519_privkey, + crypto_scalarmult(k, session->next_crypto->curve25519_privkey, session->next_crypto->curve25519_server_pubkey); BN_bin2bn(k, CURVE25519_PUBKEY_SIZE, session->next_crypto->k); @@ -125,7 +128,7 @@ int ssh_client_curve25519_reply(ssh_session session, ssh_buffer packet){ } if (ssh_string_len(q_s_string) != CURVE25519_PUBKEY_SIZE){ ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d", - ssh_string_len(q_s_string)); + (int)ssh_string_len(q_s_string)); ssh_string_free(q_s_string); goto error; } @@ -179,7 +182,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){ } if (ssh_string_len(q_c_string) != CURVE25519_PUBKEY_SIZE){ ssh_set_error(session, SSH_FATAL, "Incorrect size for server Curve25519 public key: %d", - ssh_string_len(q_c_string)); + (int)ssh_string_len(q_c_string)); ssh_string_free(q_c_string); return SSH_ERROR; } @@ -195,7 +198,7 @@ int ssh_server_curve25519_init(ssh_session session, ssh_buffer packet){ return SSH_ERROR; } - crypto_scalarmult_curve25519_base(session->next_crypto->curve25519_server_pubkey, + crypto_scalarmult_base(session->next_crypto->curve25519_server_pubkey, session->next_crypto->curve25519_privkey); q_s_string = ssh_string_new(CURVE25519_PUBKEY_SIZE); diff --git a/libssh/src/dh.c b/libssh/src/dh.c index f96a94a3..5ebbc91e 100644 --- a/libssh/src/dh.c +++ b/libssh/src/dh.c @@ -239,63 +239,6 @@ void ssh_print_bignum(const char *which, bignum num) { SAFE_FREE(hex); } -/** - * @brief Convert a buffer into a colon separated hex string. - * The caller has to free the memory. - * - * @param what What should be converted to a hex string. - * - * @param len Length of the buffer to convert. - * - * @return The hex string or NULL on error. - * - * @see ssh_string_free_char() - */ -char *ssh_get_hexa(const unsigned char *what, size_t len) { - const char h[] = "0123456789abcdef"; - char *hexa; - size_t i; - size_t hlen = len * 3; - - if (len > (UINT_MAX - 1) / 3) { - return NULL; - } - - hexa = malloc(hlen + 1); - if (hexa == NULL) { - return NULL; - } - - for (i = 0; i < len; i++) { - hexa[i * 3] = h[(what[i] >> 4) & 0xF]; - hexa[i * 3 + 1] = h[what[i] & 0xF]; - hexa[i * 3 + 2] = ':'; - } - hexa[hlen - 1] = '\0'; - - return hexa; -} - -/** - * @brief Print a buffer as colon separated hex string. - * - * @param descr Description printed in front of the hex string. - * - * @param what What should be converted to a hex string. - * - * @param len Length of the buffer to convert. - */ -void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) { - char *hexa = ssh_get_hexa(what, len); - - if (hexa == NULL) { - return; - } - printf("%s: %s\n", descr, hexa); - - free(hexa); -} - int dh_generate_x(ssh_session session) { session->next_crypto->x = bignum_new(); if (session->next_crypto->x == NULL) { @@ -1047,25 +990,7 @@ error: */ /** - * @brief Allocates a buffer with the MD5 hash of the server public key. - * - * This function allows you to get a MD5 hash of the public key. You can then - * print this hash in a human-readable form to the user so that he is able to - * verify it. Use ssh_get_hexa() or ssh_print_hexa() to display it. - * - * @param[in] session The SSH session to use. - * - * @param[in] hash The buffer to allocate. - * - * @return The bytes allocated or < 0 on error. - * - * @warning It is very important that you verify at some moment that the hash - * matches a known server. If you don't do it, cryptography wont help - * you at making things secure - * - * @see ssh_is_server_known() - * @see ssh_get_hexa() - * @see ssh_print_hexa() + * @deprecated Use ssh_get_publickey_hash() */ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) { ssh_string pubkey; @@ -1142,6 +1067,164 @@ int ssh_get_publickey(ssh_session session, ssh_key *key) key); } +/** + * @brief Allocates a buffer with the hash of the public key. + * + * This function allows you to get a hash of the public key. You can then + * print this hash in a human-readable form to the user so that he is able to + * verify it. Use ssh_get_hexa() or ssh_print_hexa() to display it. + * + * @param[in] key The public key to create the hash for. + * + * @param[in] type The type of the hash you want. + * + * @param[in] hash A pointer to store the allocated buffer. It can be + * freed using ssh_clean_pubkey_hash(). + * + * @param[in] hlen The length of the hash. + * + * @return 0 on success, -1 if an error occured. + * + * @warning It is very important that you verify at some moment that the hash + * matches a known server. If you don't do it, cryptography wont help + * you at making things secure. + * OpenSSH uses SHA1 to print public key digests. + * + * @see ssh_is_server_known() + * @see ssh_get_hexa() + * @see ssh_print_hexa() + * @see ssh_clean_pubkey_hash() + */ +int ssh_get_publickey_hash(const ssh_key key, + enum ssh_publickey_hash_type type, + unsigned char **hash, + size_t *hlen) +{ + ssh_string blob; + unsigned char *h; + int rc; + + rc = ssh_pki_export_pubkey_blob(key, &blob); + if (rc < 0) { + return rc; + } + + switch (type) { + case SSH_PUBLICKEY_HASH_SHA1: + { + SHACTX ctx; + + h = malloc(SHA_DIGEST_LEN); + if (h == NULL) { + rc = -1; + goto out; + } + + ctx = sha1_init(); + if (ctx == NULL) { + free(h); + rc = -1; + goto out; + } + + sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); + sha1_final(h, ctx); + + *hlen = SHA_DIGEST_LEN; + } + break; + case SSH_PUBLICKEY_HASH_MD5: + { + MD5CTX ctx; + + h = malloc(MD5_DIGEST_LEN); + if (h == NULL) { + rc = -1; + goto out; + } + + ctx = md5_init(); + if (ctx == NULL) { + free(h); + rc = -1; + goto out; + } + + md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); + md5_final(h, ctx); + + *hlen = MD5_DIGEST_LEN; + } + break; + default: + rc = -1; + goto out; + } + + *hash = h; + rc = 0; +out: + ssh_string_free(blob); + return rc; +} + +/** + * @brief Convert a buffer into a colon separated hex string. + * The caller has to free the memory. + * + * @param what What should be converted to a hex string. + * + * @param len Length of the buffer to convert. + * + * @return The hex string or NULL on error. + * + * @see ssh_string_free_char() + */ +char *ssh_get_hexa(const unsigned char *what, size_t len) { + const char h[] = "0123456789abcdef"; + char *hexa; + size_t i; + size_t hlen = len * 3; + + if (len > (UINT_MAX - 1) / 3) { + return NULL; + } + + hexa = malloc(hlen + 1); + if (hexa == NULL) { + return NULL; + } + + for (i = 0; i < len; i++) { + hexa[i * 3] = h[(what[i] >> 4) & 0xF]; + hexa[i * 3 + 1] = h[what[i] & 0xF]; + hexa[i * 3 + 2] = ':'; + } + hexa[hlen - 1] = '\0'; + + return hexa; +} + +/** + * @brief Print a buffer as colon separated hex string. + * + * @param descr Description printed in front of the hex string. + * + * @param what What should be converted to a hex string. + * + * @param len Length of the buffer to convert. + */ +void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len) { + char *hexa = ssh_get_hexa(what, len); + + if (hexa == NULL) { + return; + } + printf("%s: %s\n", descr, hexa); + + free(hexa); +} + /** @} */ /* vim: set ts=4 sw=4 et cindent: */ diff --git a/libssh/src/libcrypto.c b/libssh/src/libcrypto.c index 44b0fb36..bb1d96ad 100644 --- a/libssh/src/libcrypto.c +++ b/libssh/src/libcrypto.c @@ -123,6 +123,30 @@ void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned EVP_DigestUpdate(&md, digest, len); EVP_DigestFinal(&md, hash, hlen); } + +EVPCTX evp_init(int nid) +{ + const EVP_MD *evp_md = nid_to_evpmd(nid); + + EVPCTX ctx = malloc(sizeof(EVP_MD_CTX)); + if (ctx == NULL) { + return NULL; + } + + EVP_DigestInit(ctx, evp_md); + + return ctx; +} + +void evp_update(EVPCTX ctx, const void *data, unsigned long len) +{ + EVP_DigestUpdate(ctx, data, len); +} + +void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen) +{ + EVP_DigestFinal(ctx, md, mdlen); +} #endif SHA256CTX sha256_init(void){ diff --git a/libssh/src/log.c b/libssh/src/log.c index fba5fdc4..4552b969 100644 --- a/libssh/src/log.c +++ b/libssh/src/log.c @@ -65,7 +65,7 @@ static int current_timestring(int hires, char *buf, size_t len) if (hires) { strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm); - snprintf(buf, len, "%s.%06ld", tbuf, tv.tv_usec); + snprintf(buf, len, "%s.%06ld", tbuf, (long)tv.tv_usec); } else { strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm); snprintf(buf, len, "%s", tbuf); diff --git a/libssh/src/messages.c b/libssh/src/messages.c index 73f39974..2c99311d 100644 --- a/libssh/src/messages.c +++ b/libssh/src/messages.c @@ -120,10 +120,18 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg) msg->auth_request.username, msg->auth_request.pubkey, msg->auth_request.signature_state, session->server_callbacks->userdata); - if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){ + if (msg->auth_request.signature_state != SSH_PUBLICKEY_STATE_NONE) { + if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) { ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL); - } else { + } else { ssh_message_reply_default(msg); + } + } else { + if (rc == SSH_AUTH_SUCCESS) { + ssh_message_auth_reply_pk_ok_simple(msg); + } else { + ssh_message_reply_default(msg); + } } return SSH_OK; @@ -301,10 +309,8 @@ static int ssh_execute_server_callbacks(ssh_session session, ssh_message msg){ if (session->server_callbacks != NULL){ rc = ssh_execute_server_request(session, msg); - } - - /* This one is in fact a client callback... */ - if (session->common.callbacks != NULL) { + } else if (session->common.callbacks != NULL) { + /* This one is in fact a client callback... */ rc = ssh_execute_client_request(session, msg); } diff --git a/libssh/src/options.c b/libssh/src/options.c index f8055780..e02ad4df 100644 --- a/libssh/src/options.c +++ b/libssh/src/options.c @@ -856,6 +856,11 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) { * It may include "%s" which will be replaced by the * user home directory. * + * - SSH_OPTIONS_PROXYCOMMAND: + * Get the proxycommand necessary to log into the + * remote host. When not explicitly set, it will be read + * from the ~/.ssh/config file. + * * @param value The value to get into. As a char**, space will be * allocated by the function for the value, it is * your responsibility to free the memory using @@ -894,6 +899,10 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value) src = ssh_iterator_value(char *, it); break; } + case SSH_OPTIONS_PROXYCOMMAND: { + src = session->opts.ProxyCommand; + break; + } default: ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); return SSH_ERROR; @@ -1245,7 +1254,7 @@ static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo, /** * @brief This function can set all possible ssh bind options. * - * @param session An allocated ssh option structure. + * @param sshbind An allocated ssh bind structure. * * @param type The option type to set. This could be one of the * following: diff --git a/libssh/src/pki.c b/libssh/src/pki.c index 770cfc72..ec5a6883 100644 --- a/libssh/src/pki.c +++ b/libssh/src/pki.c @@ -1118,7 +1118,7 @@ int ssh_pki_export_signature_blob(const ssh_signature sig, return SSH_ERROR; } - str = ssh_string_from_char(ssh_key_type_to_char(sig->type)); + str = ssh_string_from_char(sig->type_c); if (str == NULL) { ssh_buffer_free(buf); return SSH_ERROR; @@ -1271,11 +1271,9 @@ ssh_string ssh_pki_do_sign(ssh_session session, struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto : session->next_crypto; - unsigned char hash[SHA_DIGEST_LEN] = {0}; ssh_signature sig; ssh_string sig_blob; ssh_string session_id; - SHACTX ctx; int rc; if (privkey == NULL || !ssh_key_is_private(privkey)) { @@ -1287,24 +1285,46 @@ ssh_string ssh_pki_do_sign(ssh_session session, return NULL; } ssh_string_fill(session_id, crypto->session_id, crypto->digest_len); - /* TODO: change when supporting ECDSA keys */ - ctx = sha1_init(); - if (ctx == NULL) { - ssh_string_free(session_id); - return NULL; - } - sha1_update(ctx, session_id, ssh_string_len(session_id) + 4); - ssh_string_free(session_id); + if (privkey->type == SSH_KEYTYPE_ECDSA) { +#ifdef HAVE_ECC + unsigned char ehash[EVP_DIGEST_LEN] = {0}; + uint32_t elen; + EVPCTX ctx; - sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf)); - sha1_final(hash, ctx); + ctx = evp_init(privkey->ecdsa_nid); + if (ctx == NULL) { + ssh_string_free(session_id); + return NULL; + } + + evp_update(ctx, session_id, ssh_string_len(session_id) + 4); + evp_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf)); + evp_final(ctx, ehash, &elen); + + sig = pki_do_sign(privkey, ehash, elen); +#endif + } else { + unsigned char hash[SHA_DIGEST_LEN] = {0}; + SHACTX ctx; + + ctx = sha1_init(); + if (ctx == NULL) { + ssh_string_free(session_id); + return NULL; + } + + sha1_update(ctx, session_id, ssh_string_len(session_id) + 4); + sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf)); + sha1_final(hash, ctx); #ifdef DEBUG_CRYPTO - ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN); + ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN); #endif - sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN); + sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN); + } + ssh_string_free(session_id); if (sig == NULL) { return NULL; } diff --git a/libssh/src/pki_crypto.c b/libssh/src/pki_crypto.c index 92c37c85..e87d7ace 100644 --- a/libssh/src/pki_crypto.c +++ b/libssh/src/pki_crypto.c @@ -25,6 +25,8 @@ #ifndef _PKI_CRYPTO_H #define _PKI_CRYPTO_H +#include "libssh/priv.h" + #include #include #include @@ -37,8 +39,6 @@ #include #endif - -#include "libssh/priv.h" #include "libssh/libssh.h" #include "libssh/buffer.h" #include "libssh/session.h" @@ -1018,36 +1018,52 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) break; case SSH_KEYTYPE_ECDSA: #ifdef HAVE_OPENSSL_ECC + { + ssh_buffer b; + int rc; + + b = ssh_buffer_new(); + if (b == NULL) { + return NULL; + } + r = make_bignum_string(sig->ecdsa_sig->r); if (r == NULL) { + ssh_buffer_free(b); return NULL; } + rc = buffer_add_ssh_string(b, r); + ssh_string_free(r); + if (rc < 0) { + ssh_buffer_free(b); + return NULL; + } + s = make_bignum_string(sig->ecdsa_sig->s); if (s == NULL) { - ssh_string_free(r); + ssh_buffer_free(b); return NULL; } - - memcpy(buffer, - ((char *)ssh_string_data(r)) + ssh_string_len(r) - 20, - 20); - memcpy(buffer + 20, - ((char *)ssh_string_data(s)) + ssh_string_len(s) - 20, - 20); - - ssh_string_free(r); + rc = buffer_add_ssh_string(b, s); ssh_string_free(s); - - sig_blob = ssh_string_new(40); - if (sig_blob == NULL) { + if (rc < 0) { + ssh_buffer_free(b); return NULL; } - ssh_string_fill(sig_blob, buffer, 40); + sig_blob = ssh_string_new(buffer_get_rest_len(b)); + if (sig_blob == NULL) { + ssh_buffer_free(b); + return NULL; + } + + ssh_string_fill(sig_blob, buffer_get_rest(b), buffer_get_rest_len(b)); + ssh_buffer_free(b); break; + } #endif case SSH_KEYTYPE_UNKNOWN: - ssh_pki_log("Unknown signature key type: %d", sig->type); + ssh_pki_log("Unknown signature key type: %s", sig->type_c); return NULL; } @@ -1070,6 +1086,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, } sig->type = type; + sig->type_c = ssh_key_type_to_char(type); len = ssh_string_len(sig_blob); @@ -1309,6 +1326,7 @@ ssh_signature pki_do_sign(const ssh_key privkey, } sig->type = privkey->type; + sig->type_c = privkey->type_c; switch(privkey->type) { case SSH_KEYTYPE_DSS: @@ -1368,6 +1386,7 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key, return NULL; } sig->type = key->type; + sig->type_c = key->type_c; switch(key->type) { case SSH_KEYTYPE_DSS: diff --git a/libssh/src/poll.c b/libssh/src/poll.c index bde0198d..8e21e0d5 100644 --- a/libssh/src/poll.c +++ b/libssh/src/poll.c @@ -450,7 +450,11 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx) { if (ctx->polls_allocated > 0) { while (ctx->polls_used > 0){ ssh_poll_handle p = ctx->pollptrs[0]; - ssh_poll_ctx_remove(ctx, p); + /* + * The free function calls ssh_poll_ctx_remove() and decrements + * ctx->polls_used + */ + ssh_poll_free(p); } SAFE_FREE(ctx->pollptrs); diff --git a/libssh/src/scp.c b/libssh/src/scp.c index 6838a3cd..db07aed4 100644 --- a/libssh/src/scp.c +++ b/libssh/src/scp.c @@ -814,7 +814,7 @@ int ssh_scp_integer_mode(const char *mode){ */ char *ssh_scp_string_mode(int mode){ char buffer[16]; - snprintf(buffer,sizeof(buffer),"%.4o",mode); + snprintf(buffer,sizeof(buffer),"%.4d",mode); return strdup(buffer); } diff --git a/libssh/src/server.c b/libssh/src/server.c index b31371fe..8629c8ba 100644 --- a/libssh/src/server.c +++ b/libssh/src/server.c @@ -1221,38 +1221,45 @@ int ssh_execute_message_callbacks(ssh_session session){ return SSH_OK; } - int ssh_send_keepalive(ssh_session session) { - /* TODO check the reply and all that */ struct ssh_string_struct *req; - int reply = 1; - int rc = SSH_ERROR; + int rc; + + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST); + if (rc < 0) { + goto err; + } req = ssh_string_from_char("keepalive@openssh.com"); if (req == NULL) { - ssh_set_error_oom(session); - goto out; + goto err; } - if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 || - buffer_add_ssh_string(session->out_buffer, req) < 0 || - buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { - ssh_set_error_oom(session); - goto out; + rc = buffer_add_ssh_string(session->out_buffer, req); + ssh_string_free(req); + if (rc < 0) { + goto err; } - if (packet_send(session) == SSH_ERROR) - goto out; + rc = buffer_add_u8(session->out_buffer, 1); + if (rc < 0) { + goto err; + } + + if (packet_send(session) == SSH_ERROR) { + goto err; + } ssh_handle_packets(session, 0); SSH_LOG(SSH_LOG_PACKET, "Sent a keepalive"); - rc = SSH_OK; + return SSH_OK; -out: - ssh_string_free(req); - return rc; +err: + ssh_set_error_oom(session); + buffer_reinit(session->out_buffer); + return SSH_ERROR; } /** @} */ diff --git a/libssh/src/session.c b/libssh/src/session.c index fe11b416..d4b3643f 100644 --- a/libssh/src/session.c +++ b/libssh/src/session.c @@ -273,7 +273,7 @@ void ssh_free(ssh_session session) { } /* burn connection, it could hang sensitive datas */ - ZERO_STRUCTP(session); + BURN_BUFFER(session, sizeof(struct ssh_session_struct)); SAFE_FREE(session); } diff --git a/libssh/src/socket.c b/libssh/src/socket.c index 0dbbe2bc..c76ef5ae 100644 --- a/libssh/src/socket.c +++ b/libssh/src/socket.c @@ -695,11 +695,11 @@ int ssh_socket_buffered_write_bytes(ssh_socket s){ int ssh_socket_get_status(ssh_socket s) { int r = 0; - if (s->read_wontblock) { - r |= SSH_READ_PENDING; + if (buffer_get_len(s->in_buffer) > 0) { + r |= SSH_READ_PENDING; } - if (s->write_wontblock) { + if (buffer_get_len(s->out_buffer) > 0) { r |= SSH_WRITE_PENDING; } diff --git a/libssh/src/wrapper.c b/libssh/src/wrapper.c index 66593461..51688753 100644 --- a/libssh/src/wrapper.c +++ b/libssh/src/wrapper.c @@ -158,7 +158,7 @@ void crypto_free(struct ssh_crypto_struct *crypto){ SAFE_FREE(crypto->kex_methods[i]); } - memset(crypto,0,sizeof(*crypto)); + BURN_BUFFER(crypto, sizeof(struct ssh_crypto_struct)); SAFE_FREE(crypto); } @@ -317,8 +317,13 @@ int crypt_set_algorithms_server(ssh_session session){ session->next_crypto->do_compress_in=1; } if(strcmp(method,"zlib@openssh.com") == 0){ - SSH_LOG(SSH_LOG_PACKET,"enabling C->S compression"); - session->next_crypto->delayed_compress_in=1; + SSH_LOG(SSH_LOG_PACKET,"enabling C->S delayed compression"); + + if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) { + session->next_crypto->do_compress_in = 1; + } else { + session->next_crypto->delayed_compress_in = 1; + } } method = session->next_crypto->kex_methods[SSH_COMP_S_C]; @@ -328,7 +333,12 @@ int crypt_set_algorithms_server(ssh_session session){ } if(strcmp(method,"zlib@openssh.com") == 0){ SSH_LOG(SSH_LOG_PACKET,"enabling S->C delayed compression\n"); - session->next_crypto->delayed_compress_out=1; + + if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) { + session->next_crypto->do_compress_out = 1; + } else { + session->next_crypto->delayed_compress_out = 1; + } } method = session->next_crypto->kex_methods[SSH_HOSTKEYS]; diff --git a/libssh/tests/client/CMakeLists.txt b/libssh/tests/client/CMakeLists.txt index e3bb45d3..616060c3 100644 --- a/libssh/tests/client/CMakeLists.txt +++ b/libssh/tests/client/CMakeLists.txt @@ -6,7 +6,10 @@ add_cmocka_test(torture_connect torture_connect.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_knownhosts torture_knownhosts.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_session torture_session.c ${TORTURE_LIBRARY}) +add_cmocka_test(torture_forward torture_forward.c ${TORTURE_LIBRARY}) +add_cmocka_test(torture_request_env torture_request_env.c ${TORTURE_LIBRARY}) if (WITH_SFTP) add_cmocka_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY}) + add_cmocka_test(torture_sftp_read torture_sftp_read.c ${TORTURE_LIBRARY}) endif (WITH_SFTP) diff --git a/libssh/tests/unittests/CMakeLists.txt b/libssh/tests/unittests/CMakeLists.txt index d8a6125f..38203991 100644 --- a/libssh/tests/unittests/CMakeLists.txt +++ b/libssh/tests/unittests/CMakeLists.txt @@ -13,4 +13,6 @@ if (UNIX AND NOT WIN32) add_cmocka_test(torture_pki torture_pki.c ${TORTURE_LIBRARY}) # requires pthread add_cmocka_test(torture_rand torture_rand.c ${TORTURE_LIBRARY}) + # requires /dev/null + add_cmocka_test(torture_channel torture_channel.c ${TORTURE_LIBRARY}) endif (UNIX AND NOT WIN32)