From 35da19fe25c0b038c4f58298d28f181e639cc04b Mon Sep 17 00:00:00 2001 From: Wallace Souza Date: Mon, 3 Feb 2020 17:06:02 -0300 Subject: [PATCH 001/102] Rename INSTALL_CMAKE to INTALL_CMAKE.md (#429) Adding Markdown file extension in order to Github render the instructions properly --- docs/{INSTALL_CMAKE => INSTALL_CMAKE.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{INSTALL_CMAKE => INSTALL_CMAKE.md} (100%) diff --git a/docs/INSTALL_CMAKE b/docs/INSTALL_CMAKE.md similarity index 100% rename from docs/INSTALL_CMAKE rename to docs/INSTALL_CMAKE.md From 92e5e01505a77103ad9b0081016d31646cdcc2a2 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Mon, 3 Feb 2020 14:30:26 -0800 Subject: [PATCH 002/102] Update INSTALL_CMAKE filename to INSTALL_CMAKE.md (#445) Fixing for #429 --- docs/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile.am b/docs/Makefile.am index 6df03371..3d7ca821 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -1,6 +1,6 @@ # $Id: Makefile.am,v 1.37 2009/03/26 15:41:15 bagder Exp $ -EXTRA_DIST = template.3 BINDINGS INSTALL_AUTOTOOLS INSTALL_CMAKE HACKING TODO \ +EXTRA_DIST = template.3 BINDINGS INSTALL_AUTOTOOLS INSTALL_CMAKE.md HACKING TODO \ AUTHORS CMakeLists.txt HACKING.CRYPTO SECURITY.md dist_man_MANS = \ From 14a7db0eaacfcdcfccd61e4e04dc955f71513c7e Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Mon, 3 Feb 2020 15:02:40 -0800 Subject: [PATCH 003/102] Update INSTALL_MAKE path to INSTALL_MAKE.md (#446) Included for #429 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0f6c25a..a4c741f6 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,5 @@ the revised BSD license. [Web site source code](https://github.com/libssh2/www) Installation instructions: - - [for CMake](docs/INSTALL_CMAKE) + - [for CMake](docs/INSTALL_CMAKE.md) - [for autotools](docs/INSTALL_AUTOTOOLS) From 03c7c4a351712492969bcc6ca40ca421c8dfe8bc Mon Sep 17 00:00:00 2001 From: Zenju Date: Thu, 6 Feb 2020 00:02:56 +0100 Subject: [PATCH 004/102] transport.c: Fix crash with delayed compression (#443) Files: transport.c Notes: Fixes crash with delayed compression option using Bitvise server. Contributor: Zenju --- src/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transport.c b/src/transport.c index 45e445c7..96fca6b8 100644 --- a/src/transport.c +++ b/src/transport.c @@ -765,7 +765,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, ((session->state & LIBSSH2_STATE_AUTHENTICATED) || session->local.comp->use_in_auth); - if(encrypted && compressed) { + 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 */ From ff9f228389aea13190a2252beebdaa38e3ca0d8a Mon Sep 17 00:00:00 2001 From: "Romain Geissler @ Amadeus" Date: Tue, 18 Feb 2020 20:59:00 +0100 Subject: [PATCH 005/102] Session.c: Fix undefined warning when mixing with LTO-enabled libcurl. (#449) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit File: Session.c Notes: With gcc 9, libssh2, libcurl and LTO enabled for all binaries I see this warning (error with -Werror): vssh/libssh2.c: In function ‘ssh_statemach_act’: /data/mwrep/rgeissler/ospack/ssh2/BUILD/libssh2-libssh2-03c7c4a/src/session.c:579:9: error: ‘seconds_to_next’ is used uninitialized in this function [-Werror=uninitialized] 579 | int seconds_to_next; | ^ lto1: all warnings being treated as errors Gcc normally issues -Wuninitialized when it is sure there is a problem, and -Wmaybe-uninitialized when it's not sure, but it's possible. Here the compiler seems to have find a real case where this could happen. I looked in your code and overall it seems you always check if the return code is non null, not often that it's below zero. I think we should do the same here. With this patch, gcc is fine. Credit: Romain-Geissler-1A --- src/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/session.c b/src/session.c index e439acde..256eb999 100644 --- a/src/session.c +++ b/src/session.c @@ -589,7 +589,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; From 508203da9bf31b71e60d0899ac008903298f3a58 Mon Sep 17 00:00:00 2001 From: Hans Meier Date: Wed, 26 Feb 2020 20:06:12 +0100 Subject: [PATCH 006/102] openssl.c: Fix use-after-free crash in openssl backend without memory leak (#439) Files: openssl.c Notes: Fixes memory leaks and use after free AES EVP_CIPHER contexts when using OpenSSL 1.0.x. Credit: Hans Meier --- src/openssl.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index d4cf401d..d5ad7026 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -433,6 +433,12 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, return ret == 1 ? 0 : 1; } +#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 + #if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) #include @@ -589,12 +595,14 @@ const EVP_CIPHER * _libssh2_EVP_aes_128_ctr(void) { #ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER * aes_ctr_cipher; - return make_ctr_evp(16, &aes_ctr_cipher, NID_aes_128_ctr); + return !aes_128_ctr_cipher ? + make_ctr_evp(16, &aes_128_ctr_cipher, NID_aes_128_ctr) : + aes_128_ctr_cipher; #else static EVP_CIPHER aes_ctr_cipher; - EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher; - return make_ctr_evp(16, &aes_ctr_cipher_ptr, 0); + 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; #endif } @@ -602,12 +610,14 @@ const EVP_CIPHER * _libssh2_EVP_aes_192_ctr(void) { #ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER * aes_ctr_cipher; - return make_ctr_evp(24, &aes_ctr_cipher, NID_aes_192_ctr); + return !aes_192_ctr_cipher ? + make_ctr_evp(24, &aes_192_ctr_cipher, NID_aes_192_ctr) : + aes_192_ctr_cipher; #else static EVP_CIPHER aes_ctr_cipher; - EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher; - return make_ctr_evp(24, &aes_ctr_cipher_ptr, 0); + 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; #endif } @@ -615,23 +625,19 @@ const EVP_CIPHER * _libssh2_EVP_aes_256_ctr(void) { #ifdef HAVE_OPAQUE_STRUCTS - EVP_CIPHER * aes_ctr_cipher; - return make_ctr_evp(32, &aes_ctr_cipher, NID_aes_256_ctr); + return !aes_256_ctr_cipher ? + make_ctr_evp(32, &aes_256_ctr_cipher, NID_aes_256_ctr) : + aes_256_ctr_cipher; #else static EVP_CIPHER aes_ctr_cipher; - EVP_CIPHER * aes_ctr_cipher_ptr = &aes_ctr_cipher; - return make_ctr_evp(32, &aes_ctr_cipher_ptr, 0); + 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 } #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 && \ @@ -650,11 +656,8 @@ void _libssh2_openssl_crypto_init(void) #endif #endif #ifndef HAVE_EVP_AES_128_CTR - if(!aes_128_ctr_cipher) aes_128_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_128_ctr(); - if(!aes_192_ctr_cipher) aes_192_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_192_ctr(); - if(!aes_256_ctr_cipher) aes_256_ctr_cipher = (EVP_CIPHER *) _libssh2_EVP_aes_256_ctr(); #endif } From 0effd5d4157719e6be9183489931ffb82070ad66 Mon Sep 17 00:00:00 2001 From: Zenju Date: Wed, 26 Feb 2020 20:35:33 +0100 Subject: [PATCH 007/102] agent.c: Fix Unicode builds on Windows (#417) File: agent.c Notes: Fixes unicode builds for Windows in Visual Studio 16.3.2. Credit: Zenju --- src/agent.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/agent.c b/src/agent.c index 07400fb8..c9efe304 100644 --- a/src/agent.c +++ b/src/agent.c @@ -274,7 +274,7 @@ static int agent_connect_pageant(LIBSSH2_AGENT *agent) { HWND hwnd; - hwnd = FindWindow("Pageant", "Pageant"); + hwnd = FindWindowA("Pageant", "Pageant"); if(!hwnd) return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "failed connecting agent"); @@ -297,15 +297,15 @@ agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL, "illegal input"); - hwnd = FindWindow("Pageant", "Pageant"); + hwnd = FindWindowA("Pageant", "Pageant"); if(!hwnd) return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, "found no pageant"); snprintf(mapname, sizeof(mapname), "PageantRequest%08x%c", (unsigned)GetCurrentThreadId(), '\0'); - filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, PAGEANT_MAX_MSGLEN, mapname); + filemap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, PAGEANT_MAX_MSGLEN, mapname); if(filemap == NULL || filemap == INVALID_HANDLE_VALUE) return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, From b3b45813d61c66d0e95b36665ff8d7f0dd662a9d Mon Sep 17 00:00:00 2001 From: Hans Meier Date: Thu, 27 Feb 2020 18:35:35 +0100 Subject: [PATCH 008/102] openssl.c: Fix for use of uninitialized aes_ctr_cipher.key_len (#453) File: Openssl.c Notes: * Fix for use of uninitialized aes_ctr_cipher.key_len when using HAVE_OPAQUE_STRUCTS, regression from #439 Credit: Hans Meirer, Tseng Jun --- src/openssl.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index d5ad7026..2802217d 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -600,9 +600,11 @@ _libssh2_EVP_aes_128_ctr(void) aes_128_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(16, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher; + if(!aes_128_ctr_cipher) { + aes_128_ctr_cipher = &aes_ctr_cipher; + make_ctr_evp(16, &aes_128_ctr_cipher, 0); + } + return aes_128_ctr_cipher; #endif } @@ -615,9 +617,11 @@ _libssh2_EVP_aes_192_ctr(void) aes_192_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(24, &aes_ctr_cipher_ptr, 0) : &aes_ctr_cipher; + if(!aes_192_ctr_cipher) { + aes_192_ctr_cipher = &aes_ctr_cipher; + make_ctr_evp(24, &aes_192_ctr_cipher, 0); + } + return aes_192_ctr_cipher; #endif } @@ -630,9 +634,11 @@ _libssh2_EVP_aes_256_ctr(void) aes_256_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; + if(!aes_256_ctr_cipher) { + aes_256_ctr_cipher = &aes_ctr_cipher; + make_ctr_evp(32, &aes_256_ctr_cipher, 0); + } + return aes_256_ctr_cipher; #endif } From ee3abe04089cc0e253ab6cdffbf450e191b2bf41 Mon Sep 17 00:00:00 2001 From: Tseng Jun <6501202@qq.com> Date: Wed, 4 Mar 2020 03:57:21 +0800 Subject: [PATCH 009/102] openssl.c: minor changes of coding style (#454) File: openssl.c Notes: minor changes of coding style and align preprocessor conditional for #439 Credit: Tseng Jun --- src/openssl.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 2802217d..9d3b8c7e 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -433,12 +433,6 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, return ret == 1 ? 0 : 1; } -#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 - #if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) #include @@ -451,6 +445,10 @@ typedef struct unsigned char ctr[AES_BLOCK_SIZE]; } aes_ctr_ctx; +static EVP_CIPHER * aes_128_ctr_cipher = NULL; +static EVP_CIPHER * aes_192_ctr_cipher = NULL; +static EVP_CIPHER * aes_256_ctr_cipher = NULL; + static int aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc) /* init key */ @@ -642,7 +640,7 @@ _libssh2_EVP_aes_256_ctr(void) #endif } -#endif /* LIBSSH2_AES_CTR */ +#endif /* LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) */ void _libssh2_openssl_crypto_init(void) { @@ -661,16 +659,16 @@ 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(); +#if LIBSSH2_AES_CTR && !defined(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 +#if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) #ifdef HAVE_OPAQUE_STRUCTS if(aes_128_ctr_cipher) { EVP_CIPHER_meth_free(aes_128_ctr_cipher); From 159d4c813809238ed96c65e1ea01e7d0c0b375a5 Mon Sep 17 00:00:00 2001 From: Thomas Klausner Date: Fri, 20 Mar 2020 19:37:16 +0100 Subject: [PATCH 010/102] Makefile.am: Fix unportable test(1) operator. (#459) file: Makefile.am Notes: The POSIX comparison operator for test(1) is =; bash supports == but not even test from GNU coreutils does. Credit: Thomas Klausner --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6411e8a0..5889e55f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,7 +119,7 @@ $(DSP): win32/msvcproj.head win32/msvcproj.foot Makefile.am for file in $$sorted_hdrs; do \ echo "# Begin Source File"; \ echo ""; \ - if [ "$$file" == "libssh2_config.h" ]; \ + if [ "$$file" = "libssh2_config.h" ]; \ then \ echo "SOURCE=.\\"$$file; \ else \ From bfcac7ccdac320938d140ce21fd09eabd6a61312 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Mon, 6 Apr 2020 10:13:54 -0700 Subject: [PATCH 011/102] hostkey.c: Fix 'unsigned int'/'uint32_t' mismatch (#461) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit File: hostkey.c Notes: These types are the same size so most compilers are fine with it, but CodeWarrior (on classic MacOS) throws an ‘illegal implicit conversion’ error Credit: Brendan Shanks --- src/hostkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hostkey.c b/src/hostkey.c index 5255e689..1631aae6 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -647,7 +647,7 @@ 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); From 1e57d61b01fc415b57a7348ed6aa6e32760f0758 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Fri, 17 Apr 2020 15:28:20 -0700 Subject: [PATCH 012/102] os400qc3.h: define EC types to fix building #426 (#462) File: os400qc3.h Notes: define missing EC types which prevents building Credit: hjindra --- src/os400qc3.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/os400qc3.h b/src/os400qc3.h index 79bbb96e..83864297 100644 --- a/src/os400qc3.h +++ b/src/os400qc3.h @@ -176,12 +176,20 @@ #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 SHA512_DIGEST_LENGTH 64 +#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) + +#if LIBSSH2_ECDSA +#else +#define _libssh2_ec_key void +#endif /******************************************************************* * From e238df7353b55d071cf16de97ca2ddd424f6d9e0 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Thu, 30 Apr 2020 11:27:41 -0700 Subject: [PATCH 013/102] os400qc3.h: define sha512 macros (#465) file: os400qc3.h notes: fixes for building libssh2 1.9.x --- src/os400qc3.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/os400qc3.h b/src/os400qc3.h index 83864297..10b1c5c1 100644 --- a/src/os400qc3.h +++ b/src/os400qc3.h @@ -233,6 +233,7 @@ typedef struct { /* Diffie-Hellman context. */ #define libssh2_sha1_ctx Qc3_Format_ALGD0100_T #define libssh2_sha256_ctx Qc3_Format_ALGD0100_T +#define libssh2_sha512_ctx Qc3_Format_ALGD0100_T #define libssh2_md5_ctx Qc3_Format_ALGD0100_T #define libssh2_hmac_ctx _libssh2_os400qc3_crypto_ctx #define _libssh2_cipher_ctx _libssh2_os400qc3_crypto_ctx @@ -247,9 +248,17 @@ typedef struct { /* Diffie-Hellman context. */ libssh2_os400qc3_hash_update(&(ctx), data, len) #define libssh2_sha256_final(ctx, out) \ libssh2_os400qc3_hash_final(&(ctx), out) -#define libssh2_sha256(message, len, out) \ +#define libssh2_sha256(message, len, out) \ libssh2_os400qc3_hash(message, len, out, \ Qc3_SHA256) +#define libssh2_sha512_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA512) +#define libssh2_sha512_update(ctx, data, len) \ + libssh2_os400qc3_hash_update(&(ctx), data, len) +#define libssh2_sha512_final(ctx, out) \ + libssh2_os400qc3_hash_final(&(ctx), out) +#define libssh2_sha512(message, len, out) \ + libssh2_os400qc3_hash(message, len, out, \ + Qc3_SHA512) #define libssh2_md5_init(x) libssh2_os400qc3_hash_init(x, Qc3_MD5) #define libssh2_md5_update(ctx, data, len) \ libssh2_os400qc3_hash_update(&(ctx), data, len) From 1a082247a797f6d48f1cdb9c4209e165cb00ac24 Mon Sep 17 00:00:00 2001 From: Harry Sintonen Date: Fri, 1 May 2020 20:26:20 +0300 Subject: [PATCH 014/102] kex.c: Add diffie-hellman-group14-sha256 Key Exchange Method (#464) File: kex.c Notes: Added diffie-hellman-group14-sha256 kex Credit: Harry Sintonen --- src/kex.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/src/kex.c b/src/kex.c index 7b111fea..b225a2f0 100644 --- a/src/kex.c +++ b/src/kex.c @@ -1560,13 +1560,24 @@ 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, + unsigned char, + unsigned char, + unsigned char *, + unsigned long, + 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, + diffie_hellman_hash_func_t + hashfunc) { static const unsigned char p_value[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -1619,9 +1630,9 @@ kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, 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 = hashfunc(session, key_state->g, key_state->p, + 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, + NULL, 0, &key_state->exchange_state); if(ret == LIBSSH2_ERROR_EAGAIN) { return ret; } @@ -1637,6 +1648,34 @@ kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, +/* 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) +{ + return kex_method_diffie_hellman_group14_key_exchange(session, key_state, + diffie_hellman_sha1); +} + + + +/* 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) +{ + return kex_method_diffie_hellman_group14_key_exchange(session, key_state, + diffie_hellman_sha256); +} + + + /* kex_method_diffie_hellman_group_exchange_sha1_key_exchange * Diffie-Hellman Group Exchange Key Exchange using SHA1 * Negotiates random(ish) group for secret derivation @@ -3263,6 +3302,12 @@ 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_group_exchange_sha1 = { "diffie-hellman-group-exchange-sha1", @@ -3325,6 +3370,7 @@ static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = { &kex_method_ssh_curve25519_sha256, &kex_method_ssh_curve25519_sha256_libssh, #endif + &kex_method_diffie_helman_group14_sha256, &kex_method_diffie_helman_group_exchange_sha256, &kex_method_diffie_helman_group_exchange_sha1, &kex_method_diffie_helman_group14_sha1, From 6e0f17f6728aa67e671e399a905ffe98a3db07e6 Mon Sep 17 00:00:00 2001 From: monnerat Date: Thu, 7 May 2020 01:54:11 +0200 Subject: [PATCH 015/102] HACKING.CRYPTO: keep up to date with new crypto definitions from code. (#466) File: HACKING.CRYPTO Notes: This commit updates the HACKING.CRYPTO documentation file in an attempt to make it in sync with current code. New documented features are: SHA384 SHA512 ECDSA ED25519 Credit: monnerat --- docs/HACKING.CRYPTO | 276 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 269 insertions(+), 7 deletions(-) diff --git a/docs/HACKING.CRYPTO b/docs/HACKING.CRYPTO index e1c4f38d..b78a0148 100644 --- a/docs/HACKING.CRYPTO +++ b/docs/HACKING.CRYPTO @@ -165,21 +165,86 @@ void libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, Setup the HMAC computation context ctx for an HMAC-256 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). -3.3) SHA-512 -LIBSSH2_HMAC_SHA512 -#define as 1 if the crypto library supports HMAC-SHA-512, else 0. -If defined as 0, the rest of this section can be omitted. +3.3) SHA-384 +Mandatory if ECDSA is implemented. Can be omitted otherwise. + +SHA384_DIGEST_LENGTH +#define to 48, the SHA-384 digest length. + +libssh2_sha384_ctx +Type of an SHA-384 computation context. Generally a struct. + +int libssh2_sha384_init(libssh2_sha384_ctx *x); +Initializes the SHA-384 computation context at x. +Returns 1 for success and 0 for failure + +void libssh2_sha384_update(libssh2_sha384_ctx ctx, + const unsigned char *data, + size_t len); +Continue computation of SHA-384 on len bytes at data using context ctx. +Note: if the ctx parameter is modified by the underlying code, +this procedure must be implemented as a macro to map ctx --> &ctx. + +void libssh2_sha384_final(libssh2_sha384_ctx ctx, + unsigned char output[SHA384_DIGEST_LENGTH]); +Gets the computed SHA-384 signature from context ctx into the output buffer. +Release the context. +Note: if the ctx parameter is modified by the underlying code, +this procedure must be implemented as a macro to map ctx --> &ctx. + +int libssh2_sha384(const unsigned char *message, + unsigned long len, + unsigned char output[SHA384_DIGEST_LENGTH]); +Computes the SHA-384 signature over the given message of length len and +store the result into the output buffer. +Return 1 if error, else 0. + +3.4) SHA-512 +Must always be implemented. SHA512_DIGEST_LENGTH #define to 64, the SHA-512 digest length. +libssh2_sha512_ctx +Type of an SHA-512 computation context. Generally a struct. + +int libssh2_sha512_init(libssh2_sha512_ctx *x); +Initializes the SHA-512 computation context at x. +Returns 1 for success and 0 for failure + +void libssh2_sha512_update(libssh2_sha512_ctx ctx, + const unsigned char *data, + size_t len); +Continue computation of SHA-512 on len bytes at data using context ctx. +Note: if the ctx parameter is modified by the underlying code, +this procedure must be implemented as a macro to map ctx --> &ctx. + +void libssh2_sha512_final(libssh2_sha512_ctx ctx, + unsigned char output[SHA512_DIGEST_LENGTH]); +Gets the computed SHA-512 signature from context ctx into the output buffer. +Release the context. +Note: if the ctx parameter is modified by the underlying code, +this procedure must be implemented as a macro to map ctx --> &ctx. + +int libssh2_sha512(const unsigned char *message, + unsigned long len, + unsigned char output[SHA512_DIGEST_LENGTH]); +Computes the SHA-512 signature over the given message of length len and +store the result into the output buffer. +Return 1 if error, else 0. +Note: Seems unused in current code, but defined in each crypto library backend. + +LIBSSH2_HMAC_SHA512 +#define as 1 if the crypto library supports HMAC-SHA-512, else 0. +If defined as 0, the rest of this section can be omitted. + void libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, const void *key, int keylen); Setup the HMAC computation context ctx for an HMAC-512 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). -3.4) MD5 +3.5) MD5 LIBSSH2_MD5 #define to 1 if the crypto library supports MD5, else 0. If defined as 0, the rest of this section can be omitted. @@ -215,7 +280,7 @@ void libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, Setup the HMAC computation context ctx for an HMAC-MD5 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). -3.5) RIPEMD-160 +3.6) RIPEMD-160 LIBSSH2_HMAC_RIPEMD #define as 1 if the crypto library supports HMAC-RIPEMD-160, else 0. If defined as 0, the rest of this section can be omitted. @@ -438,6 +503,17 @@ d) g, MSB first, with high order bit = 0. e) pub_key, MSB first, with high order bit = 0. Each item is preceded by its 32-bit byte length, MSB first. +Format of an ECDSA public key: +a) "ecdsa-sha2-nistp256" or "ecdsa-sha2-nistp384" or "ecdsa-sha2-nistp521". +b) domain: "nistp256", "nistp384" or "nistp521" matching a). +c) raw public key ("octal"). +Each item is preceded by its 32-bit byte length, MSB first. + +Format of an ED25519 public key: +a) "ssh-ed25519". +b) raw key (32 bytes). +Each item is preceded by its 32-bit byte length, MSB first. + int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, unsigned char **method, size_t *method_len, @@ -467,6 +543,7 @@ Both buffers have to be allocated using LIBSSH2_ALLOC(). Returns 0 if OK, else -1. This procedure is already prototyped in crypto.h. + 7.1) RSA LIBSSH2_RSA #define as 1 if the crypto library supports RSA, else 0. @@ -529,7 +606,7 @@ 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); -Verify (sig, siglen) signature of (m, m_len) using an SHA-1 hash and the +Verify (sig, sig_len) signature of (m, m_len) using an SHA-1 hash and the RSA context. Return 0 if OK, else -1. This procedure is already prototyped in crypto.h. @@ -627,6 +704,191 @@ void _libssh2_dsa_free(libssh2_dsa_ctx *dsactx); Releases the DSA computation context at dsactx. +7.3) ECDSA +LIBSSH2_ECDSA +#define as 1 if the crypto library supports ECDSA, else 0. +If defined as 0, _libssh2_ec_key should be defined as void and the rest of +this section can be omitted. + +EC_MAX_POINT_LEN +Maximum point length. Usually defined as ((528 * 2 / 8) + 1) (= 133). + +libssh2_ecdsa_ctx +Type of an ECDSA computation context. Generally a struct. + +_libssh2_ec_key +Type of an elliptic curve key. + +libssh2_curve_type +An enum type defining curve types. Current supported identifiers are: + LIBSSH2_EC_CURVE_NISTP256 + LIBSSH2_EC_CURVE_NISTP384 + LIBSSH2_EC_CURVE_NISTP521 + +int _libssh2_ecdsa_create_key(_libssh2_ec_key **out_private_key, + unsigned char **out_public_key_octal, + size_t *out_public_key_octal_len, + libssh2_curve_type curve_type); +Create a new ECDSA private key of type curve_type and return it at +out_private_key. If out_public_key_octal is not NULL, store an allocated +pointer to the associated public key in "octal" form in it and its length +at out_public_key_octal_len. +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx **ec_ctx, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase); +Reads an ECDSA private key from PEM file filename into a new ECDSA context. +Must call _libssh2_init_if_needed(). +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +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); +Builds an ECDSA private key from PEM data at filedata of length filedata_len +into a new ECDSA context stored at ec_ctx. +Must call _libssh2_init_if_needed(). +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ecdsactx, + const unsigned char *k, + size_t k_len, + libssh2_curve_type type); +Stores at ecdsactx a new ECDSA context associated with the given curve type +and with "octal" form public key (k, k_len). +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ecdsa_new_openssh_private(libssh2_ecdsa_ctx **ec_ctx, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase); +Reads a PEM-encoded ECDSA private key from file filename encrypted with +passphrase and stores at ec_ctx a new ECDSA context for it. +Return 0 if OK, else -1. +Currently used only from openssl backend (ought to be private). +This procedure is already prototyped in crypto.h. + +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); +ECDSA signs the (hash, hashlen) hash bytes and stores the allocated +signature at (signature, signature_len). Hash algorithm used should be +SHA-256, SHA-384 or SHA-512 depending on type stored in ECDSA context at ec_ctx. +Signature buffer must be allocated from the given session. +Returns 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +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); +Verify the ECDSA signature made of (r, r_len) and (s, s_len) of (m, m_len) +using the hash algorithm configured in the ECDSA context ctx. +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +libssh2_curve_type _libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ecdsactx); +Returns the curve type associated with given context. +This procedure is already prototyped in crypto.h. + +int _libssh2_ecdsa_curve_type_from_name(const char *name, + libssh2_curve_type *out_type); +Stores in out_type the curve type matching string name of the form +"ecdsa-sha2-nistpxxx". +Return 0 if OK, else -1. +Currently used only from openssl backend (ought to be private). +This procedure is already prototyped in crypto.h. + +void _libssh2_ecdsa_free(libssh2_ecdsa_ctx *ecdsactx); +Releases the ECDSA computation context at ecdsactx. + + +7.4) ED25519 +LIBSSH2_ED25519 +#define as 1 if the crypto library supports ED25519, else 0. +If defined as 0, the rest of this section can be omitted. + + +libssh2_ed25519_ctx +Type of an ED25519 computation context. Generally a struct. + +int _libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_ed25519_ctx **ctx, + uint8_t **out_public_key, + uint8_t **out_private_key); +Generates an ED25519 key pair, stores a pointer to them at out_private_key +and out_public_key respectively and stores at ctx a new ED25519 context for +this key. +Argument ctx, out_private_key and out_public key may be NULL to disable storing +the corresponding value. +Length of each key is LIBSSH2_ED25519_KEY_LEN (32 bytes). +Key buffers are allocated and should be released by caller after use. +Returns 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx, + LIBSSH2_SESSION *session, + const char *filename, + const uint8_t *passphrase); +Reads an ED25519 private key from PEM file filename into a new ED25519 context. +Must call _libssh2_init_if_needed(). +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx, + LIBSSH2_SESSION *session, + const unsigned char *raw_pub_key, + const uint8_t key_len); +Stores at ed_ctx a new ED25519 key context for raw public key (raw_pub_key, +key_len). +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx, + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + unsigned const char *passphrase); +Builds an ED25519 private key from PEM data at filedata of length filedata_len +into a new ED25519 context stored at ed_ctx. +Must call _libssh2_init_if_needed(). +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session, + uint8_t **out_sig, size_t *out_sig_len, + const uint8_t *message, size_t message_len); +ED25519 signs the (message, message_len) bytes and stores the allocated +signature at (sig, sig_len). +Signature buffer is allocated from the given session. +Returns 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s, + size_t s_len, const uint8_t *m, size_t m_len); +Verify (s, s_len) signature of (m, m_len) using the given ED25519 context. +Return 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +int _libssh2_curve25519_gen_k(_libssh2_bn **k, + uint8_t private_key[LIBSSH2_ED25519_KEY_LEN], + uint8_t srvr_public_key[LIBSSH2_ED25519_KEY_LEN]); +Computes a shared ED25519 secret key from the given raw server public key and +raw client public key and stores it as a big number in *k. Big number should +have been initialized before calling this function. +Returns 0 if OK, else -1. +This procedure is already prototyped in crypto.h. + +void _libssh2_ed25519_free(libssh2_ed25519_ctx *ed25519ctx); +Releases the ED25519 computation context at ed25519ctx. + + 8) Miscellaneous void libssh2_prepare_iovec(struct iovec *vector, unsigned int len); From 4e75a59e294b7170428f028267460b1026c2634e Mon Sep 17 00:00:00 2001 From: monnerat Date: Fri, 15 May 2020 19:26:52 +0200 Subject: [PATCH 016/102] os400qc3.c: constify libssh2_os400qc3_hash_update() data parameter. (#469) Files: os400qc3.c, os400qc3.h Notes: Fixes building on OS400. #426 Credit: Reported-by: hjindra on github, dev by Monnerat --- src/os400qc3.c | 8 ++++---- src/os400qc3.h | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/os400qc3.c b/src/os400qc3.c index de602c82..bf5acdaf 100644 --- a/src/os400qc3.c +++ b/src/os400qc3.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015-2016 Patrick Monnerat, D+H + * Copyright (C) 2020 Patrick Monnerat . * All rights reserved. * * Redistribution and use in source and binary forms, @@ -965,7 +966,7 @@ libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, unsigned int algorithm) void libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx, - unsigned char *data, int len) + const unsigned char *data, int len) { char dummy[64]; @@ -995,7 +996,7 @@ libssh2_os400qc3_hash(const unsigned char *message, unsigned long len, if(!libssh2_os400qc3_hash_init(&ctx, algo)) return 1; - libssh2_os400qc3_hash_update(&ctx, (unsigned char *) message, len); + libssh2_os400qc3_hash_update(&ctx, message, len); libssh2_os400qc3_hash_final(&ctx, out); return 0; } @@ -1390,8 +1391,7 @@ pbkdf1(LIBSSH2_SESSION *session, char **dk, const unsigned char *passphrase, /* Initial hash. */ libssh2_os400qc3_hash_init(&hctx, pkcs5->hash); - libssh2_os400qc3_hash_update(&hctx, (unsigned char *) passphrase, - strlen(passphrase)); + libssh2_os400qc3_hash_update(&hctx, passphrase, strlen(passphrase)); hctx.Final_Op_Flag = Qc3_Final; Qc3CalculateHash((char *) pkcs5->salt, &len, Qc3_Data, (char *) &hctx, Qc3_Alg_Token, anycsp, NULL, *dk, (char *) &ecnull); diff --git a/src/os400qc3.h b/src/os400qc3.h index 10b1c5c1..0557cabb 100644 --- a/src/os400qc3.h +++ b/src/os400qc3.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2015-2016 Patrick Monnerat, D+H + * Copyright (C) 2020 Patrick Monnerat . * All rights reserved. * * Redistribution and use in source and binary forms, @@ -355,7 +356,8 @@ extern void _libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x); extern int libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, unsigned int algo); extern void libssh2_os400qc3_hash_update(Qc3_Format_ALGD0100_T *ctx, - unsigned char *data, int len); + const unsigned char *data, + int len); extern void libssh2_os400qc3_hash_final(Qc3_Format_ALGD0100_T *ctx, unsigned char *out); extern int libssh2_os400qc3_hash(const unsigned char *message, From 1105af5651b4bb0d2d959f1112d15437ffea45c4 Mon Sep 17 00:00:00 2001 From: "Dr. Koutheir Attouchi" Date: Tue, 26 May 2020 13:28:12 -0400 Subject: [PATCH 017/102] libssh2_sftp.h: Changed type of LIBSSH2_FX_* constants to unsigned long, fixes #474 File: libssh2_sftp.h Notes: Error constants `LIBSSH2_FX_*` are only returned by `libssh2_sftp_last_error()` which returns `unsigned long`. Therefore these constants should be defined as unsigned long literals, instead of int literals. Credit: Dr. Koutheir Attouchi --- include/libssh2_sftp.h | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/include/libssh2_sftp.h b/include/libssh2_sftp.h index b9932216..476ea870 100644 --- a/include/libssh2_sftp.h +++ b/include/libssh2_sftp.h @@ -189,30 +189,30 @@ 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 +#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 From 642eec48ff3adfdb7a9e562b6d7fc865d1733f45 Mon Sep 17 00:00:00 2001 From: lutianxiong Date: Fri, 29 May 2020 01:25:40 +0800 Subject: [PATCH 018/102] transport.c: fix use-of-uninitialized-value (#476) file:transport.c notes: return error if malloc(0) credit: lutianxiong --- src/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transport.c b/src/transport.c index 96fca6b8..adf96c24 100644 --- a/src/transport.c +++ b/src/transport.c @@ -472,7 +472,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) /* Get a packet handle put data into. We get one to hold all data, including padding and MAC. */ p->payload = LIBSSH2_ALLOC(session, total_num); - if(!p->payload) { + if(total_num == 0 || !p->payload) { return LIBSSH2_ERROR_ALLOC; } p->total_num = total_num; From 0b44e558f311671f6e6d14c559bc1c9bda59b8df Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Thu, 28 May 2020 14:20:08 -0700 Subject: [PATCH 019/102] transport.c: moving total_num check from #476 (#478) file: transport.c notes: moving total_num zero length check from #476 up to the prior bounds check which already includes a total_num check. Makes it slightly more readable. credit: Will Cosgrove --- src/transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/transport.c b/src/transport.c index adf96c24..11e56142 100644 --- a/src/transport.c +++ b/src/transport.c @@ -465,14 +465,14 @@ 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; } /* Get a packet handle put data into. We get one to hold all data, including padding and MAC. */ p->payload = LIBSSH2_ALLOC(session, total_num); - if(total_num == 0 || !p->payload) { + if(!p->payload) { return LIBSSH2_ERROR_ALLOC; } p->total_num = total_num; From ba149e804ef653cc05ed9803dfc94519ce9328f7 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 31 May 2020 21:24:58 +0200 Subject: [PATCH 020/102] wincng: fix multiple definition of `_libssh2_wincng' (#479) Add missing include guard and move global state from header to source file by using extern. --- src/wincng.c | 2 ++ src/wincng.h | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index 4bebc640..dffd2ed3 100755 --- a/src/wincng.c +++ b/src/wincng.c @@ -208,6 +208,8 @@ * Windows CNG backend: Generic functions */ +struct _libssh2_wincng_ctx _libssh2_wincng; + void _libssh2_wincng_init(void) { diff --git a/src/wincng.h b/src/wincng.h index f5838d0e..c817f090 100755 --- a/src/wincng.h +++ b/src/wincng.h @@ -1,5 +1,7 @@ +#ifndef __LIBSSH2_WINCNG_H +#define __LIBSSH2_WINCNG_H /* - * Copyright (C) 2013-2015 Marc Hoersken + * Copyright (C) 2013-2020 Marc Hoersken * All rights reserved. * * Redistribution and use in source and binary forms, @@ -101,7 +103,7 @@ struct _libssh2_wincng_ctx { BCRYPT_ALG_HANDLE hAlg3DES_CBC; }; -struct _libssh2_wincng_ctx _libssh2_wincng; +extern struct _libssh2_wincng_ctx _libssh2_wincng; /*******************************************************************/ @@ -569,3 +571,5 @@ _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_WINCNG_H */ From ffab6960b5f5293d62d07772a7e570396e070aac Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 31 May 2020 21:39:22 +0200 Subject: [PATCH 021/102] src: add new and align include guards in header files (#480) Make sure all include guards exist and follow the same format. --- src/blf.h | 7 +++---- src/comp.h | 1 - src/crypto.h | 6 +++--- src/libgcrypt.h | 3 +++ src/libssh2_priv.h | 7 +++---- src/mac.h | 1 - src/mbedtls.h | 4 ++++ src/openssl.h | 4 ++++ src/os400qc3.h | 7 +++---- src/packet.h | 6 +++--- src/session.h | 6 +++--- src/sftp.h | 6 +++--- src/transport.h | 1 - src/userauth.h | 6 +++--- 14 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/blf.h b/src/blf.h index 1a85e6ee..5b7c8aae 100644 --- a/src/blf.h +++ b/src/blf.h @@ -1,3 +1,5 @@ +#ifndef __LIBSSH2_BLF_H +#define __LIBSSH2_BLF_H /* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */ /* * Blowfish - a fast block cipher designed by Bruce Schneier @@ -31,9 +33,6 @@ * 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. @@ -87,4 +86,4 @@ int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, uint8_t *key, size_t keylen, unsigned int rounds); #endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */ -#endif /* _BLF_H */ +#endif /* __LIBSSH2_BLF_H */ diff --git a/src/comp.h b/src/comp.h index 8edc1502..82ac2dc9 100644 --- a/src/comp.h +++ b/src/comp.h @@ -1,6 +1,5 @@ #ifndef __LIBSSH2_COMP_H #define __LIBSSH2_COMP_H - /* Copyright (C) 2009-2010 by Daniel Stenberg * * Redistribution and use in source and binary forms, diff --git a/src/crypto.h b/src/crypto.h index deb9581c..c36dde10 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -1,3 +1,5 @@ +#ifndef __LIBSSH2_CRYPTO_H +#define __LIBSSH2_CRYPTO_H /* Copyright (C) 2009, 2010 Simon Josefsson * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. * Copyright (C) 2010-2019 Daniel Stenberg @@ -35,8 +37,6 @@ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ -#ifndef LIBSSH2_CRYPTO_H -#define LIBSSH2_CRYPTO_H #ifdef LIBSSH2_OPENSSL #include "openssl.h" @@ -245,4 +245,4 @@ int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, size_t privatekeydata_len, const char *passphrase); -#endif +#endif /* __LIBSSH2_CRYPTO_H */ diff --git a/src/libgcrypt.h b/src/libgcrypt.h index ec88aded..92b48b88 100644 --- a/src/libgcrypt.h +++ b/src/libgcrypt.h @@ -1,3 +1,5 @@ +#ifndef __LIBSSH2_LIBGCRYPT_H +#define __LIBSSH2_LIBGCRYPT_H /* * Copyright (C) 2008, 2009, 2010 Simon Josefsson * Copyright (C) 2006, 2007, The Written Word, Inc. @@ -232,3 +234,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/src/libssh2_priv.h b/src/libssh2_priv.h index baff0fa8..474698e1 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -1,3 +1,5 @@ +#ifndef __LIBSSH2_PRIV_H +#define __LIBSSH2_PRIV_H /* Copyright (c) 2004-2008, 2010, Sara Golemon * Copyright (c) 2009-2014 by Daniel Stenberg * Copyright (c) 2010 Simon Josefsson @@ -37,9 +39,6 @@ * OF SUCH DAMAGE. */ -#ifndef LIBSSH2_PRIV_H -#define LIBSSH2_PRIV_H 1 - #define LIBSSH2_LIBRARY #include "libssh2_config.h" @@ -1147,4 +1146,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/src/mac.h b/src/mac.h index 66d3e610..46fce542 100644 --- a/src/mac.h +++ b/src/mac.h @@ -1,6 +1,5 @@ #ifndef __LIBSSH2_MAC_H #define __LIBSSH2_MAC_H - /* Copyright (C) 2009-2010 by Daniel Stenberg * * Redistribution and use in source and binary forms, diff --git a/src/mbedtls.h b/src/mbedtls.h index 88b0e54d..7832c450 100644 --- a/src/mbedtls.h +++ b/src/mbedtls.h @@ -1,3 +1,5 @@ +#ifndef __LIBSSH2_MBEDTLS_H +#define __LIBSSH2_MBEDTLS_H /* Copyright (c) 2016, Art * All rights reserved. * @@ -445,3 +447,5 @@ _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_MBEDTLS_H */ diff --git a/src/openssl.h b/src/openssl.h index a65d710e..f65192d2 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -1,3 +1,5 @@ +#ifndef __LIBSSH2_OPENSSL_H +#define __LIBSSH2_OPENSSL_H /* Copyright (C) 2009, 2010 Simon Josefsson * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. * @@ -392,3 +394,5 @@ extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx); 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/src/os400qc3.h b/src/os400qc3.h index 0557cabb..d915dc2c 100644 --- a/src/os400qc3.h +++ b/src/os400qc3.h @@ -1,3 +1,5 @@ +#ifndef __LIBSSH2_OS400QC3_H +#define __LIBSSH2_OS400QC3_H /* * Copyright (C) 2015-2016 Patrick Monnerat, D+H * Copyright (C) 2020 Patrick Monnerat . @@ -37,9 +39,6 @@ * OF SUCH DAMAGE. */ -#ifndef LIBSSH2_OS400QC3_H -#define LIBSSH2_OS400QC3_H - #include #include @@ -387,6 +386,6 @@ extern int _libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *f, _libssh2_bn *p); extern void _libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx); -#endif +#endif /* __LIBSSH2_OS400QC3_H */ /* vim: set expandtab ts=4 sw=4: */ diff --git a/src/packet.h b/src/packet.h index d66b15b5..79018bcf 100644 --- a/src/packet.h +++ b/src/packet.h @@ -1,5 +1,5 @@ -#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 @@ -73,4 +73,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/src/session.h b/src/session.h index 7b6c291e..9f8f2c70 100644 --- a/src/session.h +++ b/src/session.h @@ -1,5 +1,5 @@ -#ifndef LIBSSH2_SESSION_H -#define LIBSSH2_SESSION_H +#ifndef __LIBSSH2_SESSION_H +#define __LIBSSH2_SESSION_H /* Copyright (c) 2004-2007 Sara Golemon * Copyright (c) 2009-2010 by Daniel Stenberg * Copyright (c) 2010 Simon Josefsson @@ -90,4 +90,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/src/sftp.h b/src/sftp.h index ae4162f1..129b8f08 100644 --- a/src/sftp.h +++ b/src/sftp.h @@ -1,5 +1,5 @@ -#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 @@ -235,4 +235,4 @@ struct _LIBSSH2_SFTP uint32_t symlink_request_id; }; -#endif +#endif /* __LIBSSH2_SFTP_H */ diff --git a/src/transport.h b/src/transport.h index 89982a67..7d395d0e 100644 --- a/src/transport.h +++ b/src/transport.h @@ -1,6 +1,5 @@ #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 diff --git a/src/userauth.h b/src/userauth.h index a7b0a984..6b402ddb 100644 --- a/src/userauth.h +++ b/src/userauth.h @@ -1,5 +1,5 @@ -#ifndef LIBSSH2_USERAUTH_H -#define LIBSSH2_USERAUTH_H +#ifndef __LIBSSH2_USERAUTH_H +#define __LIBSSH2_USERAUTH_H /* Copyright (c) 2004-2007, Sara Golemon * Copyright (c) 2009-2010 by Daniel Stenberg * All rights reserved. @@ -48,4 +48,4 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, ((*sign_callback)), void *abstract); -#endif /* LIBSSH2_USERAUTH_H */ +#endif /* __LIBSSH2_USERAUTH_H */ From 07fc1532b6224fa47e5d836d9913d4eaa07188ef Mon Sep 17 00:00:00 2001 From: suryakalpo Date: Mon, 1 Jun 2020 19:26:09 -0400 Subject: [PATCH 022/102] INSTALL_CMAKE.md: Update formatting (#481) File: INSTALL_CMAKE.md Notes: Although the original text would be immediately clear to seasoned users of CMAKE and/or Unix shell, the lack of newlines may cause some confusion for newcomers. Hence, wrapping the texts in a md code-block such that the newlines appear as intended. credit: suryakalpo --- docs/INSTALL_CMAKE.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/INSTALL_CMAKE.md b/docs/INSTALL_CMAKE.md index b9261b34..9ad9f8d2 100644 --- a/docs/INSTALL_CMAKE.md +++ b/docs/INSTALL_CMAKE.md @@ -20,10 +20,12 @@ Getting started If you are happy with the default options, make a new build directory, change to it, configure the build environment and build the project: +``` mkdir bin cd bin cmake .. cmake --build . +``` libssh2 will be built as a static library and will use any cryptography library available. The library binary will be put in @@ -119,20 +121,27 @@ Tests To test the build, run the appropriate test target for your build system. For example: +``` cmake --build . --target test +``` or +``` cmake --build . --target RUN_TESTS +``` How do I use libssh2 in my project if my project doesn't use CMake? ------------------------------------------------------------------- If you are not using CMake for your own project, install libssh2 - +``` cmake cmake --build . cmake --build . --target install +``` or +``` cmake --build . --target INSTALL +``` and then specify the install location to your project in the normal way for your build environment. If you don't like the default install From 9b5407f91b7b88d3fb5fc63cbc950ac13d325f84 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Mon, 8 Jun 2020 21:14:47 +0200 Subject: [PATCH 023/102] appveyor: build and run tests for WinCNG crypto backend --- appveyor.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 8b9b9728..08e60c1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,15 +29,35 @@ environment: matrix: - GENERATOR: "Visual Studio 14 2015" BUILD_SHARED_LIBS: ON + CRYPTO_BACKEND: "OpenSSL" - GENERATOR: "Visual Studio 14 2015" BUILD_SHARED_LIBS: OFF + CRYPTO_BACKEND: "OpenSSL" - GENERATOR: "Visual Studio 12 2013" BUILD_SHARED_LIBS: ON + CRYPTO_BACKEND: "OpenSSL" - GENERATOR: "Visual Studio 12 2013" BUILD_SHARED_LIBS: OFF + CRYPTO_BACKEND: "OpenSSL" + + - GENERATOR: "Visual Studio 14 2015" + BUILD_SHARED_LIBS: ON + CRYPTO_BACKEND: "WinCNG" + + - GENERATOR: "Visual Studio 14 2015" + BUILD_SHARED_LIBS: OFF + CRYPTO_BACKEND: "WinCNG" + + - GENERATOR: "Visual Studio 12 2013" + BUILD_SHARED_LIBS: ON + CRYPTO_BACKEND: "WinCNG" + + - GENERATOR: "Visual Studio 12 2013" + BUILD_SHARED_LIBS: OFF + CRYPTO_BACKEND: "WinCNG" digitalocean_access_token: secure: 8qRitvrj69Xhf0Tmu27xnz5drmL2YhmOJLGpXIkYyTCC0JNtBoXW6fMcF3u4Uj1+pIQ+TjegQOwYimlz0oivKTro3v3EXro+osAMNJG6NKc= @@ -62,7 +82,7 @@ install: build_script: - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } - - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -H. -B_builds + - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -DCRYPTO_BACKEND=%CRYPTO_BACKEND% -H. -B_builds - cmake --build _builds --config "%CONFIGURATION%" before_test: From 93206a7acd242d96d97d431e7de152d5ebc305e6 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 14 Jun 2020 19:32:49 +0200 Subject: [PATCH 024/102] wincng: fix return value in _libssh2_dh_secret Do not ignore return value of modular exponentiation. --- src/wincng.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index dffd2ed3..4af9a58b 100755 --- a/src/wincng.c +++ b/src/wincng.c @@ -2156,8 +2156,7 @@ _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; + return _libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p); } void From cc00ece962b691bf56a13ddafb2a6edd4414c11c Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 14 Jun 2020 19:34:18 +0200 Subject: [PATCH 025/102] wincng: do not disable key validation that can be enabled The modular exponentiation also works with key validation enabled. --- src/wincng.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index 4af9a58b..079fbbca 100755 --- a/src/wincng.c +++ b/src/wincng.c @@ -1982,9 +1982,7 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, memcpy(key + offset, m->bignum, m->length); ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, - BCRYPT_NO_KEY_VALIDATION); - + BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, 0); if(BCRYPT_SUCCESS(ret)) { ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0, NULL, 0, &length, BCRYPT_PAD_NONE); From e7d5439119b3465e67a560df04258c128617e8c5 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 14 Jun 2020 19:35:21 +0200 Subject: [PATCH 026/102] wincng: align bits to bytes calculation in all functions --- src/wincng.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index 079fbbca..1779a8df 100755 --- a/src/wincng.c +++ b/src/wincng.c @@ -1916,7 +1916,8 @@ _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) if(!rnd) return -1; - length = (unsigned long)(ceil((float)bits / 8) * sizeof(unsigned char)); + length = (unsigned long) (ceil(((double)bits) / 8.0) * + sizeof(unsigned char)); if(_libssh2_wincng_bignum_resize(rnd, length)) return -1; @@ -2032,8 +2033,9 @@ _libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word) number = word; while(number >>= 1) bits++; + bits++; - length = (unsigned long) (ceil(((double)(bits + 1)) / 8.0) * + length = (unsigned long) (ceil(((double)bits) / 8.0) * sizeof(unsigned char)); if(_libssh2_wincng_bignum_resize(bn, length)) return -1; From 6c99a185775a836148e7f6bb7a689477c77b3986 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 14 Jun 2020 19:36:32 +0200 Subject: [PATCH 027/102] wincng: add and improve checks in bit counting function --- src/wincng.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index 1779a8df..04a4f81a 100755 --- a/src/wincng.c +++ b/src/wincng.c @@ -2052,21 +2052,18 @@ _libssh2_wincng_bignum_bits(const _libssh2_bn *bn) unsigned char number; unsigned long offset, length, bits; - if(!bn) + if(!bn || !bn->bignum || !bn->length) return 0; - length = bn->length - 1; - offset = 0; - while(!(*(bn->bignum + offset)) && (offset < length)) + length = bn->length - 1; + while(!bn->bignum[offset] && offset < length) offset++; bits = (length - offset) * 8; number = bn->bignum[offset]; - while(number >>= 1) bits++; - bits++; return bits; From 0f6d3b68db8ca0c9dbee9808779fff6554c8865e Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sat, 20 Jun 2020 18:42:24 +0200 Subject: [PATCH 028/102] tests: fix mix of declarations and code failing C89 compliance --- tests/test_hostkey_hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_hostkey_hash.c b/tests/test_hostkey_hash.c index 0576120b..f3840e89 100644 --- a/tests/test_hostkey_hash.c +++ b/tests/test_hostkey_hash.c @@ -51,6 +51,7 @@ int test(LIBSSH2_SESSION *session) { char buf[BUFSIZ]; + const char *hostkey; const char *md5_hash; const char *sha1_hash; const char *sha256_hash; @@ -61,7 +62,7 @@ int test(LIBSSH2_SESSION *session) (void)EXPECTED_RSA_HOSTKEY; (void)EXPECTED_ECDSA_HOSTKEY; - const char *hostkey = libssh2_session_hostkey(session, &len, &type); + hostkey = libssh2_session_hostkey(session, &len, &type); if(hostkey == NULL) { print_last_session_error("libssh2_session_hostkey"); return 1; From b78e57a2d7e1871a55ab72758a99e34cf7596e26 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sat, 20 Jun 2020 18:44:30 +0200 Subject: [PATCH 029/102] tests: restore retry behaviour for docker-machine ip command --- tests/openssh_fixture.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 093f31e0..e2c6f8b3 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -167,9 +167,11 @@ static int ip_address_from_container(char *container_id, char **ip_address_out) int attempt_no = 0; int wait_time = 500; for(;;) { - return run_command(ip_address_out, "docker-machine ip %s", active_docker_machine); - - if(attempt_no > 5) { + int ret = run_command(ip_address_out, "docker-machine ip %s", active_docker_machine); + if(ret == 0) { + return 0; + } + else if(attempt_no > 5) { fprintf( stderr, "Unable to get IP from docker-machine after %d attempts\n", From ec53d55cc0fd84706f479c910f82c125be7274ae Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sat, 20 Jun 2020 18:47:49 +0200 Subject: [PATCH 030/102] tests: add support for ports published via Docker for Windows --- tests/openssh_fixture.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index e2c6f8b3..4c421328 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -231,6 +231,14 @@ static int open_socket_to_container(char *container_id) ret = -1; } + /* 0.0.0.0 is returned by Docker for Windows, because the container + is reachable from anywhere. But we cannot connect to 0.0.0.0, + instead we assume localhost and try to connect to 127.0.0.1. */ + if(ip_address && strcmp(ip_address, "0.0.0.0") == 0) { + free(ip_address); + ip_address = strdup("127.0.0.1"); + } + hostaddr = inet_addr(ip_address); if(hostaddr == (unsigned long)(-1)) { fprintf(stderr, "Failed to convert %s host address\n", ip_address); From 2764bc8e06d51876b6796d6080c6ac51e20f3332 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sat, 20 Jun 2020 20:47:56 +0200 Subject: [PATCH 031/102] tests: satisfy checksrc with whitespace only fixes checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT -AFOPENMODE tests/*.[ch] --- tests/test_agent_forward_succeeds.c | 10 +++++----- ...ucceeds_with_correct_ed25519_key_from_mem.c | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/test_agent_forward_succeeds.c b/tests/test_agent_forward_succeeds.c index 2d7a389e..3de40b82 100644 --- a/tests/test_agent_forward_succeeds.c +++ b/tests/test_agent_forward_succeeds.c @@ -15,12 +15,12 @@ int test(LIBSSH2_SESSION *session) const char *userauth_list = libssh2_userauth_list(session, USERNAME, strlen(USERNAME)); - if (userauth_list == NULL) { + if(userauth_list == NULL) { print_last_session_error("libssh2_userauth_list"); return 1; } - if (strstr(userauth_list, "publickey") == NULL) { + if(strstr(userauth_list, "publickey") == NULL) { fprintf(stderr, "'publickey' was expected in userauth list: %s\n", userauth_list); return 1; @@ -29,19 +29,19 @@ int test(LIBSSH2_SESSION *session) rc = libssh2_userauth_publickey_fromfile_ex( session, USERNAME, strlen(USERNAME), KEY_FILE_PUBLIC, KEY_FILE_PRIVATE, NULL); - if (rc != 0) { + if(rc != 0) { print_last_session_error("libssh2_userauth_publickey_fromfile_ex"); return 1; } channel = libssh2_channel_open_session(session); - /* if (channel == NULL) { */ + /* if(channel == NULL) { */ /* printf("Error opening channel\n"); */ /* return 1; */ /* } */ rc = libssh2_channel_request_auth_agent(channel); - if (rc != 0) { + if(rc != 0) { fprintf(stderr, "Auth agent request for agent forwarding failed, error code %d\n", rc); return 1; diff --git a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c index 82eb0823..06aab1e6 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c +++ b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c @@ -66,8 +66,8 @@ int read_file(const char *path, char **out_buffer, size_t *out_len) fp = fopen(path, "r"); if(!fp) { - fprintf(stderr, "File could not be read."); - return 1; + fprintf(stderr, "File could not be read."); + return 1; } fseek(fp, 0L, SEEK_END); @@ -76,16 +76,16 @@ int read_file(const char *path, char **out_buffer, size_t *out_len) buffer = calloc(1, len + 1); if(!buffer) { - fclose(fp); - fprintf(stderr, "Could not alloc memory."); - return 1; + fclose(fp); + fprintf(stderr, "Could not alloc memory."); + return 1; } if(1 != fread(buffer, len, 1, fp)) { - fclose(fp); - free(buffer); - fprintf(stderr, "Could not read file into memory."); - return 1; + fclose(fp); + free(buffer); + fprintf(stderr, "Could not read file into memory."); + return 1; } fclose(fp); From 36d87a17a8987025543338ef8fe346829aae9bf2 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sat, 20 Jun 2020 21:48:30 +0200 Subject: [PATCH 032/102] tests: satisfy checksrc regarding max line length of 79 chars Follow up to 2764bc8e06d51876b6796d6080c6ac51e20f3332 --- tests/openssh_fixture.c | 18 ++++---- tests/ssh2.c | 12 ++++-- tests/test_agent_forward_succeeds.c | 8 ++-- tests/test_hostkey.c | 8 ++-- tests/test_hostkey_hash.c | 42 +++++++++++-------- ...teractive_auth_fails_with_wrong_response.c | 6 +-- ...tive_auth_succeeds_with_correct_response.c | 8 ++-- ..._password_auth_fails_with_wrong_password.c | 2 +- ..._password_auth_fails_with_wrong_username.c | 2 +- ...d_auth_succeeds_with_correct_credentials.c | 4 +- ...est_public_key_auth_fails_with_wrong_key.c | 2 +- ...c_key_auth_succeeds_with_correct_dsa_key.c | 4 +- ...y_auth_succeeds_with_correct_ed25519_key.c | 4 +- ...cceeds_with_correct_ed25519_key_from_mem.c | 5 ++- ...ceeds_with_correct_encrypted_ed25519_key.c | 5 ++- ..._succeeds_with_correct_encrypted_rsa_key.c | 5 ++- ...c_key_auth_succeeds_with_correct_rsa_key.c | 4 +- ...th_succeeds_with_correct_rsa_openssh_key.c | 5 ++- 18 files changed, 82 insertions(+), 62 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 4c421328..62719cd7 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -136,14 +136,14 @@ static int run_command(char **output, const char *command, ...) static int build_openssh_server_docker_image() { - return run_command(NULL, "docker build -t libssh2/openssh_server openssh_server"); + return run_command(NULL, "docker build -t libssh2/openssh_server " + "openssh_server"); } static int start_openssh_server(char **container_id_out) { return run_command(container_id_out, - "docker run --detach -P libssh2/openssh_server" - ); + "docker run --detach -P libssh2/openssh_server"); } static int stop_openssh_server(char *container_id) @@ -167,7 +167,8 @@ static int ip_address_from_container(char *container_id, char **ip_address_out) int attempt_no = 0; int wait_time = 500; for(;;) { - int ret = run_command(ip_address_out, "docker-machine ip %s", active_docker_machine); + int ret = run_command(ip_address_out, "docker-machine ip %s", + active_docker_machine); if(ret == 0) { return 0; } @@ -220,14 +221,16 @@ static int open_socket_to_container(char *container_id) int ret = ip_address_from_container(container_id, &ip_address); if(ret != 0) { - fprintf(stderr, "Failed to get IP address for container %s\n", container_id); + fprintf(stderr, "Failed to get IP address for container %s\n", + container_id); ret = -1; goto cleanup; } ret = port_from_container(container_id, &port_string); if(ret != 0) { - fprintf(stderr, "Failed to get port for container %s\n", container_id); + fprintf(stderr, "Failed to get port for container %s\n", + container_id); ret = -1; } @@ -259,7 +262,8 @@ static int open_socket_to_container(char *container_id) if(connect(sock, (struct sockaddr *)(&sin), sizeof(struct sockaddr_in)) != 0) { - fprintf(stderr, "Failed to connect to %s:%s\n", ip_address, port_string); + fprintf(stderr, "Failed to connect to %s:%s\n", + ip_address, port_string); ret = -1; goto cleanup; } diff --git a/tests/ssh2.c b/tests/ssh2.c index 7ef9f379..f903e075 100644 --- a/tests/ssh2.c +++ b/tests/ssh2.c @@ -84,7 +84,8 @@ int main(int argc, char *argv[]) } /* Create a session instance and start it up - * This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers + * This will trade welcome banners, exchange keys, + * and setup crypto, compression, and MAC layers */ session = libssh2_session_init(); if(libssh2_session_startup(session, sock)) { @@ -93,8 +94,10 @@ int main(int argc, char *argv[]) } /* At this point we haven't authenticated, - * The first thing to do is check the hostkey's fingerprint against our known hosts - * Your app may have it hard coded, may go to a file, may present it to the user, that's your call + * The first thing to do is check the hostkey's + * fingerprint against our known hosts + * Your app may have it hard coded, may go to a file, + * may present it to the user, that's your call */ fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); printf("Fingerprint: "); @@ -118,7 +121,8 @@ int main(int argc, char *argv[]) if(auth_pw & 4) { /* Authenticate by public key */ - if(libssh2_userauth_publickey_fromfile(session, username, pubkeyfile, privkeyfile, password)) { + if(libssh2_userauth_publickey_fromfile(session, username, pubkeyfile, + privkeyfile, password)) { printf("\tAuthentication by public key failed!\n"); goto shutdown; } diff --git a/tests/test_agent_forward_succeeds.c b/tests/test_agent_forward_succeeds.c index 3de40b82..a3117395 100644 --- a/tests/test_agent_forward_succeeds.c +++ b/tests/test_agent_forward_succeeds.c @@ -4,9 +4,9 @@ #include -const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +const char *USERNAME = "libssh2"; /* set in Dockerfile */ const char *KEY_FILE_PRIVATE = "key_rsa"; -const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* configured in Dockerfile */ +const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { @@ -42,8 +42,8 @@ int test(LIBSSH2_SESSION *session) rc = libssh2_channel_request_auth_agent(channel); if(rc != 0) { - fprintf(stderr, "Auth agent request for agent forwarding failed, error code %d\n", - rc); + fprintf(stderr, "Auth agent request for agent forwarding failed, " + "error code %d\n", rc); return 1; } diff --git a/tests/test_hostkey.c b/tests/test_hostkey.c index e09a7674..e33f68f9 100644 --- a/tests/test_hostkey.c +++ b/tests/test_hostkey.c @@ -32,11 +32,13 @@ int test(LIBSSH2_SESSION *session) if(type == LIBSSH2_HOSTKEY_TYPE_ECDSA_256) { rc = libssh2_base64_decode(session, &expected_hostkey, &expected_len, - EXPECTED_ECDSA_HOSTKEY, strlen(EXPECTED_ECDSA_HOSTKEY)); + EXPECTED_ECDSA_HOSTKEY, + strlen(EXPECTED_ECDSA_HOSTKEY)); } else if(type == LIBSSH2_HOSTKEY_TYPE_RSA) { rc = libssh2_base64_decode(session, &expected_hostkey, &expected_len, - EXPECTED_RSA_HOSTKEY, strlen(EXPECTED_RSA_HOSTKEY)); + EXPECTED_RSA_HOSTKEY, + strlen(EXPECTED_RSA_HOSTKEY)); } else { fprintf(stderr, "Unexpected type of hostkey: %i\n", type); @@ -49,7 +51,7 @@ int test(LIBSSH2_SESSION *session) } if(len != expected_len) { - fprintf(stderr, "Hostkey does not have the expected length %ld != %d\n", + fprintf(stderr, "Hostkey does not have the expected length %ld!=%d\n", (unsigned long)len, expected_len); return 1; } diff --git a/tests/test_hostkey_hash.c b/tests/test_hostkey_hash.c index f3840e89..620d6370 100644 --- a/tests/test_hostkey_hash.c +++ b/tests/test_hostkey_hash.c @@ -17,19 +17,23 @@ static const char *EXPECTED_ECDSA_HOSTKEY = "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC+/syyeKJD9dC2ZH" "9Q7iJGReR4YM3rUCMsSynkyXojdfSClGCMY7JvWlt30ESjYvxoTfSRGx6WvaqYK/vPoYQ4="; -static const char *EXPECTED_RSA_MD5_HASH_DIGEST = "0C0ED1A5BB10275F76924CE187CE5C5E"; +static const char *EXPECTED_RSA_MD5_HASH_DIGEST = + "0C0ED1A5BB10275F76924CE187CE5C5E"; static const char *EXPECTED_RSA_SHA1_HASH_DIGEST = "F3CD59E2913F4422B80F7B0A82B2B89EAE449387"; -static const char *EXPECTED_RSA_SHA256_HASH_DIGEST = "92E3DA49DF3C7F99A828F505ED8239397A5D1F62914459760F878F7510F563A3"; +static const char *EXPECTED_RSA_SHA256_HASH_DIGEST = + "92E3DA49DF3C7F99A828F505ED8239397A5D1F62914459760F878F7510F563A3"; -static const char *EXPECTED_ECDSA_MD5_HASH_DIGEST = "0402E4D897580BBC911379CBD88BCD3D"; +static const char *EXPECTED_ECDSA_MD5_HASH_DIGEST = + "0402E4D897580BBC911379CBD88BCD3D"; static const char *EXPECTED_ECDSA_SHA1_HASH_DIGEST = "12FDAD1E3B31B10BABB00F2A8D1B9A62C326BD2F"; -static const char *EXPECTED_ECDSA_SHA256_HASH_DIGEST = "56FCD975B166C3F0342D0036E44C311A86C0EAE40713B53FC776369BAE7F5264"; +static const char *EXPECTED_ECDSA_SHA256_HASH_DIGEST = + "56FCD975B166C3F0342D0036E44C311A86C0EAE40713B53FC776369BAE7F5264"; static const int MD5_HASH_SIZE = 16; static const int SHA1_HASH_SIZE = 20; @@ -80,8 +84,8 @@ int test(LIBSSH2_SESSION *session) calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_ECDSA_MD5_HASH_DIGEST) != 0) { - fprintf(stderr, "ECDSA MD5 hash not as expected - digest %s != %s\n", buf, - EXPECTED_ECDSA_MD5_HASH_DIGEST); + fprintf(stderr, "ECDSA MD5 hash not as expected, digest " + "%s != %s\n", buf, EXPECTED_ECDSA_MD5_HASH_DIGEST); return 1; } @@ -95,12 +99,13 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST) != 0) { - fprintf(stderr, "ECDSA SHA1 hash not as expected - digest %s != %s\n", buf, - EXPECTED_ECDSA_SHA1_HASH_DIGEST); + fprintf(stderr, "ECDSA SHA1 hash not as expected, digest " + "%s != %s\n", buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST); return 1; } - sha256_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256); + sha256_hash = libssh2_hostkey_hash(session, + LIBSSH2_HOSTKEY_HASH_SHA256); if(sha256_hash == NULL) { print_last_session_error( "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA256)"); @@ -110,8 +115,8 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST) != 0) { - fprintf(stderr, "ECDSA SHA256 hash not as expected - digest %s != %s\n", buf, - EXPECTED_ECDSA_SHA256_HASH_DIGEST); + fprintf(stderr, "ECDSA SHA256 hash not as expected, digest " + "%s != %s\n", buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST); return 1; } @@ -128,8 +133,8 @@ int test(LIBSSH2_SESSION *session) calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_RSA_MD5_HASH_DIGEST) != 0) { - fprintf(stderr, "MD5 hash not as expected - digest %s != %s\n", buf, - EXPECTED_RSA_MD5_HASH_DIGEST); + fprintf(stderr, "MD5 hash not as expected, digest " + "%s != %s\n", buf, EXPECTED_RSA_MD5_HASH_DIGEST); return 1; } @@ -143,12 +148,13 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_RSA_SHA1_HASH_DIGEST) != 0) { - fprintf(stderr, "SHA1 hash not as expected - digest %s != %s\n", buf, - EXPECTED_RSA_SHA1_HASH_DIGEST); + fprintf(stderr, "SHA1 hash not as expected, digest " + "%s != %s\n", buf, EXPECTED_RSA_SHA1_HASH_DIGEST); return 1; } - sha256_hash = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256); + sha256_hash = libssh2_hostkey_hash(session, + LIBSSH2_HOSTKEY_HASH_SHA256); if(sha256_hash == NULL) { print_last_session_error( "libssh2_hostkey_hash(LIBSSH2_HOSTKEY_HASH_SHA256)"); @@ -158,8 +164,8 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_RSA_SHA256_HASH_DIGEST) != 0) { - fprintf(stderr, "SHA256 hash not as expected - digest %s != %s\n", buf, - EXPECTED_RSA_SHA256_HASH_DIGEST); + fprintf(stderr, "SHA256 hash not as expected, digest " + "%s != %s\n", buf, EXPECTED_RSA_SHA256_HASH_DIGEST); return 1; } } diff --git a/tests/test_keyboard_interactive_auth_fails_with_wrong_response.c b/tests/test_keyboard_interactive_auth_fails_with_wrong_response.c index 995d9f1d..56b1ba54 100644 --- a/tests/test_keyboard_interactive_auth_fails_with_wrong_response.c +++ b/tests/test_keyboard_interactive_auth_fails_with_wrong_response.c @@ -4,11 +4,11 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *WRONG_PASSWORD = "i'm not the password"; static void kbd_callback(const char *name, int name_len, - const char *instruction, int instruction_len, + const char *instruct, int instruct_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, @@ -17,7 +17,7 @@ static void kbd_callback(const char *name, int name_len, int i; (void)abstract; fprintf(stdout, "Kb-int name: %.*s\n", name_len, name); - fprintf(stdout, "Kb-int instruction: %.*s\n", instruction_len, instruction); + fprintf(stdout, "Kb-int instruction: %.*s\n", instruct_len, instruct); for(i = 0; i < num_prompts; ++i) { fprintf(stdout, "Kb-int prompt %d: %.*s\n", i, prompts[i].length, prompts[i].text); diff --git a/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c b/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c index 06b9e68c..e9902449 100644 --- a/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c +++ b/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c @@ -4,11 +4,11 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ -static const char *PASSWORD = "my test password"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +static const char *PASSWORD = "my test password"; /* set in Dockerfile */ static void kbd_callback(const char *name, int name_len, - const char *instruction, int instruction_len, + const char *instruct, int instruct_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, @@ -18,7 +18,7 @@ static void kbd_callback(const char *name, int name_len, (void)abstract; fprintf(stdout, "Kb-int name: %.*s\n", name_len, name); - fprintf(stdout, "Kb-int instruction: %.*s\n", instruction_len, instruction); + fprintf(stdout, "Kb-int instruction: %.*s\n", instruct_len, instruct); for(i = 0; i < num_prompts; ++i) { fprintf(stdout, "Kb-int prompt %d: %.*s\n", i, prompts[i].length, prompts[i].text); diff --git a/tests/test_password_auth_fails_with_wrong_password.c b/tests/test_password_auth_fails_with_wrong_password.c index af906df4..2b895d08 100644 --- a/tests/test_password_auth_fails_with_wrong_password.c +++ b/tests/test_password_auth_fails_with_wrong_password.c @@ -4,7 +4,7 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *WRONG_PASSWORD = "i'm not the password"; int test(LIBSSH2_SESSION *session) diff --git a/tests/test_password_auth_fails_with_wrong_username.c b/tests/test_password_auth_fails_with_wrong_username.c index 81df36f3..f6e7a068 100644 --- a/tests/test_password_auth_fails_with_wrong_username.c +++ b/tests/test_password_auth_fails_with_wrong_username.c @@ -4,7 +4,7 @@ #include -static const char *PASSWORD = "my test password"; /* configured in Dockerfile */ +static const char *PASSWORD = "my test password"; /* set in Dockerfile */ static const char *WRONG_USERNAME = "i dont exist"; int test(LIBSSH2_SESSION *session) diff --git a/tests/test_password_auth_succeeds_with_correct_credentials.c b/tests/test_password_auth_succeeds_with_correct_credentials.c index f39e6d6a..a26e5220 100644 --- a/tests/test_password_auth_succeeds_with_correct_credentials.c +++ b/tests/test_password_auth_succeeds_with_correct_credentials.c @@ -4,8 +4,8 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ -static const char *PASSWORD = "my test password"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +static const char *PASSWORD = "my test password"; /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_fails_with_wrong_key.c b/tests/test_public_key_auth_fails_with_wrong_key.c index 4da7068b..dd2d254f 100644 --- a/tests/test_public_key_auth_fails_with_wrong_key.c +++ b/tests/test_public_key_auth_fails_with_wrong_key.c @@ -4,7 +4,7 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *KEY_FILE_PRIVATE = "key_dsa_wrong"; static const char *KEY_FILE_PUBLIC = "key_dsa_wrong.pub"; diff --git a/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c index 46bcc26a..cbaefc13 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c @@ -4,9 +4,9 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *KEY_FILE_PRIVATE = "key_dsa"; -static const char *KEY_FILE_PUBLIC = "key_dsa.pub"; /* configured in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_dsa.pub"; /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c index 99e41f7e..8acb073f 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c @@ -4,9 +4,9 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *KEY_FILE_PRIVATE = "key_ed25519"; -static const char *KEY_FILE_PUBLIC = "key_ed25519.pub"; /* configured in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_ed25519.pub"; /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c index 06aab1e6..a0b25a04 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c +++ b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c @@ -5,7 +5,7 @@ #include #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *KEY_FILE_ED25519_PRIVATE = "key_ed25519"; int read_file(const char *path, char **buf, size_t *len); @@ -35,7 +35,8 @@ int test(LIBSSH2_SESSION *session) return 1; } - rc = libssh2_userauth_publickey_frommemory(session, USERNAME, strlen(USERNAME), + rc = libssh2_userauth_publickey_frommemory(session, USERNAME, + strlen(USERNAME), NULL, 0, buffer, len, NULL); free(buffer); diff --git a/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c b/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c index 42616223..f3162236 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c @@ -4,10 +4,11 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *PASSWORD = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_ed25519_encrypted"; -static const char *KEY_FILE_PUBLIC = "key_ed25519_encrypted.pub"; /* configured in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_ed25519_encrypted.pub"; + /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c index 6b945135..80026ed2 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c @@ -4,10 +4,11 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *PASSWORD = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_rsa_encrypted"; -static const char *KEY_FILE_PUBLIC = "key_rsa_encrypted.pub"; /* configured in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_rsa_encrypted.pub"; + /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c index d9e87c61..3806c26b 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c @@ -4,9 +4,9 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *KEY_FILE_PRIVATE = "key_rsa"; -static const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* configured in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c b/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c index e7fd7373..5560ad00 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c @@ -4,9 +4,10 @@ #include -static const char *USERNAME = "libssh2"; /* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; /* set in Dockerfile */ static const char *KEY_FILE_PRIVATE = "key_rsa_openssh"; -static const char *KEY_FILE_PUBLIC = "key_rsa_openssh.pub"; /* configured in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_rsa_openssh.pub"; + /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { From ac13b70a89a16490ff69e0d92bffa818a59e3ed5 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Mon, 22 Jun 2020 08:21:26 +0200 Subject: [PATCH 033/102] tests: avoid use of banned function strncat (#489) --- tests/openssh_fixture.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 62719cd7..7112903f 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -62,10 +62,12 @@ static int run_command_varg(char **output, const char *command, va_list args) { FILE *pipe; + char redirect_stderr[] = "%s 2>&1"; char command_buf[BUFSIZ]; char buf[BUFSIZ]; char *p; int ret; + if(output) { *output = NULL; } @@ -78,18 +80,22 @@ static int run_command_varg(char **output, const char *command, va_list args) } /* Rewrite the command to redirect stderr to stdout to we can output it */ - if(strlen(command_buf) + 6 >= sizeof(command_buf)) { + if(strlen(command_buf) + strlen(redirect_stderr) >= sizeof(buf)) { fprintf(stderr, "Unable to rewrite command (%s)\n", command); return -1; } - strncat(command_buf, " 2>&1", 6); + ret = snprintf(buf, sizeof(buf), redirect_stderr, command_buf); + if(ret < 0 || ret >= BUFSIZ) { + fprintf(stderr, "Unable to rewrite command (%s)\n", command); + return -1; + } fprintf(stdout, "Command: %s\n", command); #ifdef WIN32 - pipe = _popen(command_buf, "r"); + pipe = _popen(buf, "r"); #else - pipe = popen(command_buf, "r"); + pipe = popen(buf, "r"); #endif if(!pipe) { fprintf(stderr, "Unable to execute command '%s'\n", command); From 984d008106b2d950a6f16ce84a5c0a0ef96d3f93 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Mon, 22 Jun 2020 08:22:36 +0200 Subject: [PATCH 034/102] tests: avoid use of deprecated function _sleep (#490) --- tests/openssh_fixture.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 7112903f..248a561d 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -187,10 +187,7 @@ static int ip_address_from_container(char *container_id, char **ip_address_out) } else { #ifdef WIN32 -#pragma warning(push) -#pragma warning(disable : 4996) - _sleep(wait_time); -#pragma warning(pop) + Sleep(wait_time); #else sleep(wait_time); #endif From 87c5883a421cd3a37567795935346071759e6c56 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Mon, 22 Jun 2020 21:24:05 +0200 Subject: [PATCH 035/102] Makefile: also run checksrc on test source files --- Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 5889e55f..70549995 100644 --- a/Makefile.am +++ b/Makefile.am @@ -149,4 +149,6 @@ $(VCPROJ): win32/vc8proj.head win32/vc8proj.foot Makefile.am awk '{printf("%s\r\n", gensub("\r", "", "g"))}' > $@ ) checksrc: - perl src/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT -AFOPENMODE -Wsrc/libssh2_config.h src/*.[ch] include/*.h example/*.c + perl src/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT \ + -AFOPENMODE -Wsrc/libssh2_config.h src/*.[ch] include/*.h example/*.c \ + tests/*.[ch] From 92d756045adb04caac1027ae05960a0ab60687cf Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Mon, 22 Jun 2020 21:24:44 +0200 Subject: [PATCH 036/102] travis: use existing Makefile target to run checksrc --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e5e1b328..58bc19ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -101,7 +101,9 @@ install: script: - | if [ "$B" = "style" ]; then - perl src/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT -AFOPENMODE -Wsrc/libssh2_config.h src/*.[ch] include/*.h example/*.c + ./buildconf + ./configure + make checksrc fi - | if [ "$B" = "configure" ]; then From 1c3a03ebc3166cf69735111aba2b8cee57cdba51 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 1 Jul 2020 11:37:20 -0700 Subject: [PATCH 037/102] libssh2.h: Update Diffie Hellman group values (#493) File: libssh2.h Notes: Update the min, preferred and max DH group values based on RFC 8270. Credit: Will Cosgrove, noted from email list by Mitchell Holland --- include/libssh2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index 386bcc89..d7e87b1f 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -235,9 +235,9 @@ typedef off_t libssh2_struct_stat_size; /* 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 +#define LIBSSH2_DH_GEX_MINGROUP 2048 +#define LIBSSH2_DH_GEX_OPTGROUP 4096 +#define LIBSSH2_DH_GEX_MAXGROUP 8192 /* Defaults for pty requests */ #define LIBSSH2_TERM_WIDTH 80 From fc5d77881eb6bb179f831e626d15f4f29179aad5 Mon Sep 17 00:00:00 2001 From: yann-morin-1998 Date: Wed, 1 Jul 2020 20:44:08 +0200 Subject: [PATCH 038/102] buildsystem: drop custom buildconf script, rely on autoreconf (#224) Notes: The buildconf script is currently required, because we need to copy a header around, because it is used both from the library and the examples sources. However, having a custom 'buildconf'-like script is not needed if we can ensure that the header exists by the time it is needed. For that, we can just append the src/ directory to the headers search path for the examples. And then it means we no longer need to generate the same header twice, so we remove the second one from configure.ac. Now, we can just call "autoreconf -fi" to generate the autotools files, instead of relying on the canned sequence in "buildconf", since autoreconf has now long known what to do at the correct moment (future versions of autotools, automake, autopoint, autoheader etc... may require an other ordering, or other intermediate steps, etc...). Eventually, get rid of buildconf now it is no longer needed. In fact, we really keep it for legacy, but have it just call autoreconf (and print a nice user-friendly warning). Don't include it in the release tarballs, though. Update doc, gitignore, and travis-CI jobs accordingly. Credit: Signed-off-by: "Yann E. MORIN" Cc: Sam Voss --- .gitignore | 2 ++ .travis.yml | 2 +- Makefile.am | 2 +- buildconf | 24 +++++------------------- configure.ac | 2 +- docs/INSTALL_AUTOTOOLS | 4 ++-- example/.gitignore | 2 -- example/Makefile.am | 2 +- 8 files changed, 13 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 997e51e1..b6d6b5cb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ Makefile Makefile.in aclocal.m4 autom4te.cache +compile +test-driver config.guess config.log config.status diff --git a/.travis.yml b/.travis.yml index 58bc19ff..d543a334 100644 --- a/.travis.yml +++ b/.travis.yml @@ -107,7 +107,7 @@ script: fi - | if [ "$B" = "configure" ]; then - ./buildconf + autoreconf -fi ./configure --enable-debug --enable-werror make make check diff --git a/Makefile.am b/Makefile.am index 70549995..986441bd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,7 +43,7 @@ os400/libssh2rpg/libssh2_publickey.rpgle \ os400/libssh2rpg/libssh2_sftp.rpgle \ Makefile.os400qc3.inc -EXTRA_DIST = $(WIN32FILES) buildconf $(NETWAREFILES) get_ver.awk \ +EXTRA_DIST = $(WIN32FILES) $(NETWAREFILES) get_ver.awk \ maketgz NMakefile RELEASE-NOTES libssh2.pc.in $(VMSFILES) config.rpath \ CMakeLists.txt cmake $(OS400FILES) diff --git a/buildconf b/buildconf index 558dcb66..728b3397 100755 --- a/buildconf +++ b/buildconf @@ -1,22 +1,8 @@ #!/bin/sh -LIBTOOLIZE="libtoolize" +echo "***" >&2 +echo "*** Do not use buildconf. Instead, just use: autoreconf -fi" >&2 +echo "*** Doing it for you now, but buildconf may disapear in the future." >&2 +echo "***" >&2 -if [ "x`which $LIBTOOLIZE`" = "x" ]; then - LIBTOOLIZE="glibtoolize" -fi - -if [ "x`which $LIBTOOLIZE`" = "x" ]; then - echo "Neither libtoolize nor glibtoolize could be found!" - exit 1 -fi - -${LIBTOOLIZE} --copy --automake --force -${ACLOCAL:-aclocal} -I m4 $ACLOCAL_FLAGS -${AUTOHEADER:-autoheader} -# copy the private libssh2_config.h.in to the examples dir so that -# it can be included without pointing the include path to the private -# source dir -cp src/libssh2_config.h.in example/libssh2_config.h.in -${AUTOCONF:-autoconf} -${AUTOMAKE:-automake} --add-missing --copy +${AUTORECONF:-autoreconf} -fi "${@}" diff --git a/configure.ac b/configure.ac index fe5054a0..1f60c144 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_INIT(libssh2, [-], libssh2-devel@cool.haxx.se) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src]) -AC_CONFIG_HEADERS([src/libssh2_config.h example/libssh2_config.h]) +AC_CONFIG_HEADERS([src/libssh2_config.h]) AM_MAINTAINER_MODE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/docs/INSTALL_AUTOTOOLS b/docs/INSTALL_AUTOTOOLS index 515001e3..a75b5181 100644 --- a/docs/INSTALL_AUTOTOOLS +++ b/docs/INSTALL_AUTOTOOLS @@ -14,9 +14,9 @@ If you want to build directly from the git repository, you must first generate the configure script and Makefile using autotools. There is a convenience script that calls all tools in the correct order. Make sure that autoconf, automake and libtool are installed on your system, -then execute the following script: +then execute: - ./buildconf + autoreconf -fi After executing this script, you can build the project as usual: diff --git a/example/.gitignore b/example/.gitignore index e3c63371..a1549e2f 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -21,8 +21,6 @@ config.h.in ssh2_exec ssh2_agent ssh2_agent_forwarding -libssh2_config.h -libssh2_config.h.in stamp-h2 sftp_append sftp_write_sliding diff --git a/example/Makefile.am b/example/Makefile.am index c238148b..ec542cd1 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -13,5 +13,5 @@ if HAVE_SYS_UN_H noinst_PROGRAMS += x11 endif -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/example +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/example -I../src LDADD = $(top_builddir)/src/libssh2.la From 0222603df5b0e557e429a761a9c3ce0a6f43fd13 Mon Sep 17 00:00:00 2001 From: Zenju Date: Wed, 1 Jul 2020 20:55:29 +0200 Subject: [PATCH 039/102] comp.c: Fix name clash with ZLIB macro "compress" (#418) File: comp.c Notes: * Fix name clash with ZLIB macro "compress". Credit: Zenju --- src/comp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/comp.c b/src/comp.c index fec82a74..90ab30c8 100644 --- a/src/comp.c +++ b/src/comp.c @@ -38,7 +38,8 @@ #include "libssh2_priv.h" #ifdef LIBSSH2_HAVE_ZLIB -# include +#include +#undef compress /* dodge name clash with ZLIB macro */ #endif #include "comp.h" From 7a26697ede3e8e8696501bc51ca230ad5f2262d9 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Wed, 31 Jul 2019 09:54:44 -0700 Subject: [PATCH 040/102] wincng: use newer DH API for Windows 8.1+ Since Windows 1903 the approach used to perform DH kex with the CNG API has been failing. This commit switches to using the `DH` algorithm provider to perform generation of the key pair and derivation of the shared secret. It uses a feature of CNG that is not yet documented. The sources of information that I've found on this are: * https://stackoverflow.com/a/56378698/149111 * https://github.com/wbenny/mini-tor/blob/5d39011e632be8e2b6b1819ee7295e8bd9b7a769/mini/crypto/cng/dh.inl#L355 With this change I am able to successfully connect from Windows 10 to my ubuntu system. Refs: https://github.com/alexcrichton/ssh2-rs/issues/122 Fixes: https://github.com/libssh2/libssh2/issues/388 Closes: https://github.com/libssh2/libssh2/pull/397 --- src/wincng.c | 326 +++++++++++++++++++++++++++++++++++++++++++++++---- src/wincng.h | 21 +++- 2 files changed, 323 insertions(+), 24 deletions(-) mode change 100755 => 100644 src/wincng.c diff --git a/src/wincng.c b/src/wincng.c old mode 100755 new mode 100644 index 04a4f81a..c37d1f0e --- a/src/wincng.c +++ b/src/wincng.c @@ -293,6 +293,11 @@ _libssh2_wincng_init(void) 0); } } + +#if LIBSSH2_USE_BCRYPT_DH + (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDH, + BCRYPT_DH_ALGORITHM, NULL, 0); +#endif } void @@ -312,6 +317,9 @@ _libssh2_wincng_free(void) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0); +#if LIBSSH2_USE_BCRYPT_DH + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDH, 0); +#endif memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); } @@ -2125,6 +2133,25 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn) } } +#if LIBSSH2_USE_BCRYPT_DH +/* We provide our own prototype for this function as the availability + * of the header that is documented to provide it is patchy across + * the various environments that the libssh2 CI builds on, and + * because the stdcall convention is important for the linker to + * be able to resolve the function in 32-bit MSVC compiler + * environments. */ +extern NTSTATUS __stdcall RtlGetVersion(OSVERSIONINFOW*); + +static int is_windows_10_or_later(void) +{ + OSVERSIONINFOW vers; + vers.dwOSVersionInfoSize = sizeof(vers); + if(RtlGetVersion(&vers) != 0) { + return 0; + } + return vers.dwMajorVersion >= 10; +} +#endif /* * Windows CNG backend: Diffie-Hellman support. @@ -2133,34 +2160,287 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn) 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 */ - return _libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p); +#if LIBSSH2_USE_BCRYPT_DH + if(is_windows_10_or_later()) { + dhctx->dh_handle = NULL; + dhctx->dh_params = NULL; + return; + } +#endif + /* Random from client */ + dhctx->bn = _libssh2_wincng_bignum_init(); } void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) { - _libssh2_wincng_bignum_free(*dhctx); - *dhctx = NULL; +#if LIBSSH2_USE_BCRYPT_DH + if(is_windows_10_or_later()) { + if(dhctx->dh_handle) { + BCryptDestroyKey(dhctx->dh_handle); + dhctx->dh_handle = NULL; + } + if(dhctx->dh_params) { + /* Since dh_params were shared in clear text, we don't need + * to securely zero them out here */ + free(dhctx->dh_params); + dhctx->dh_params = NULL; + } + return; + } +#endif + if(dhctx->bn) { + _libssh2_wincng_bignum_free(dhctx->bn); + dhctx->bn = NULL; + } +} + +/* Copy a big endian set of bits from src to dest. + * if the size of src is smaller than dest then pad the "left" (MSB) + * end with zeroes and copy the bits into the "right" (LSB) end. */ +static void +memcpy_with_be_padding(unsigned char *dest, unsigned long dest_len, + unsigned char *src, unsigned long src_len) +{ + if(dest_len > src_len) { + memset(dest, 0, dest_len - src_len); + } + memcpy(dest + dest_len - src_len, src, src_len); +} + +static int +round_down(int number, int multiple) +{ + return (number / multiple) * multiple; +} + +/* Generates a Diffie-Hellman key pair using base `g', prime `p' and the given + * `group_order'. Can use the given big number context `bnctx' if needed. The + * private key is stored as opaque in the Diffie-Hellman context `*dhctx' and + * the public key is returned in `public'. 0 is returned upon success, else + * -1. */ +int +_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, + _libssh2_bn *g, _libssh2_bn *p, int group_order) +{ +#if LIBSSH2_USE_BCRYPT_DH + if(is_windows_10_or_later()) { + BCRYPT_DH_PARAMETER_HEADER *dh_params = NULL; + unsigned long dh_params_len; + unsigned char *blob = NULL; + int status; + DWORD public_key_len_bytes = 0; + /* Note that the DH provider requires that keys be multiples of 64 bits + * in length. At the time of writing a practical observed group_order + * value is 257, so we need to round down to 8 bytes of length (64/8) + * in order for kex to succeed */ + DWORD key_length_bytes = max(round_down(group_order, 8), + max(g->length, p->length)); + unsigned char *public_blob = NULL; + BCRYPT_DH_KEY_BLOB *dh_key_blob; + + /* Prepare a key pair; pass the in the bit length of the key, + * but the key is not ready for consumption until it is finalized. */ + status = BCryptGenerateKeyPair(_libssh2_wincng.hAlgDH, + &dhctx->dh_handle, + key_length_bytes * 8, 0); + if(!BCRYPT_SUCCESS(status)) { + return -1; + } + + dh_params_len = sizeof(*dh_params) + 2 * key_length_bytes; + blob = malloc(dh_params_len); + if(!blob) { + return -1; + } + + /* Populate DH parameters blob; after the header follows the `p` + * value and the `g` value. */ + dh_params = (BCRYPT_DH_PARAMETER_HEADER*)blob; + dh_params->cbLength = dh_params_len; + dh_params->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; + dh_params->cbKeyLength = key_length_bytes; + memcpy_with_be_padding(blob + sizeof(*dh_params), key_length_bytes, + p->bignum, p->length); + memcpy_with_be_padding(blob + sizeof(*dh_params) + key_length_bytes, + key_length_bytes, g->bignum, g->length); + + status = BCryptSetProperty(dhctx->dh_handle, BCRYPT_DH_PARAMETERS, + blob, dh_params_len, 0); + /* Pass ownership to dhctx; these parameters will be freed when + * the context is destroyed. We need to keep the parameters more + * easily available so that we have access to the `g` value when + * _libssh2_dh_secret is called later. */ + dhctx->dh_params = dh_params; + blob = NULL; + + if(!BCRYPT_SUCCESS(status)) { + return -1; + } + + status = BCryptFinalizeKeyPair(dhctx->dh_handle, 0); + if(!BCRYPT_SUCCESS(status)) { + return -1; + } + + /* Now we need to extract the public portion of the key so that we + * set it in the `public` bignum to satisfy our caller. + * First measure up the size of the required buffer. */ + status = BCryptExportKey(dhctx->dh_handle, NULL, BCRYPT_DH_PUBLIC_BLOB, + NULL, 0, &public_key_len_bytes, 0); + if(!BCRYPT_SUCCESS(status)) { + return -1; + } + + public_blob = malloc(public_key_len_bytes); + + status = BCryptExportKey(dhctx->dh_handle, NULL, BCRYPT_DH_PUBLIC_BLOB, + public_blob, public_key_len_bytes, + &public_key_len_bytes, 0); + if(!BCRYPT_SUCCESS(status)) { + return -1; + } + + /* BCRYPT_DH_PUBLIC_BLOB corresponds to a BCRYPT_DH_KEY_BLOB header + * followed by the Modulus, Generator and Public data. Those components + * each have equal size, specified by dh_key_blob->cbKey. */ + dh_key_blob = (BCRYPT_DH_KEY_BLOB*)public_blob; + if(_libssh2_wincng_bignum_resize(public, dh_key_blob->cbKey)) { + return -1; + } + + /* Copy the public key data into the bignum data buffer */ + memcpy(public->bignum, + public_blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey, + dh_key_blob->cbKey); + + return 0; + } +#endif + /* Generate x and e */ + if(_libssh2_wincng_bignum_rand(dhctx->bn, group_order * 8 - 1, 0, -1)) + return -1; + if(_libssh2_wincng_bignum_mod_exp(public, g, dhctx->bn, p)) + return -1; + return 0; +} + +/* Computes the Diffie-Hellman secret from the previously created context + * `*dhctx', the public key `f' from the other party and the same prime `p' + * used at context creation. The result is stored in `secret'. 0 is returned + * upon success, else -1. */ +int +_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, + _libssh2_bn *f, _libssh2_bn *p) +{ +#if LIBSSH2_USE_BCRYPT_DH + if(is_windows_10_or_later()) { + BCRYPT_KEY_HANDLE peer_public = NULL; + BCRYPT_SECRET_HANDLE agreement = NULL; + ULONG secret_len_bytes = 0; + unsigned char *blob; + int status; + unsigned char *start, *end; + BCRYPT_DH_KEY_BLOB *public_blob = NULL; + DWORD key_length_bytes = max(f->length, dhctx->dh_params->cbKeyLength); + DWORD public_blob_len = sizeof(*public_blob) + 3 * key_length_bytes; + + { + /* Populate a BCRYPT_DH_KEY_BLOB; after the header follows the + * Modulus, Generator and Public data. Those components must have + * equal size in this representation. */ + unsigned char *dest; + unsigned char *src; + + blob = malloc(public_blob_len); + if(!blob) { + return -1; + } + public_blob = (BCRYPT_DH_KEY_BLOB*)blob; + public_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC; + public_blob->cbKey = key_length_bytes; + + dest = (unsigned char *)(public_blob + 1); + src = (unsigned char *)(dhctx->dh_params + 1); + + /* Modulus (the p-value from the first call) */ + memcpy_with_be_padding(dest, key_length_bytes, src, + dhctx->dh_params->cbKeyLength); + /* Generator (the g-value from the first call) */ + memcpy_with_be_padding(dest + key_length_bytes, key_length_bytes, + src + dhctx->dh_params->cbKeyLength, + dhctx->dh_params->cbKeyLength); + /* Public from the peer */ + memcpy_with_be_padding(dest + 2*key_length_bytes, key_length_bytes, + f->bignum, f->length); + } + + /* Import the peer public key information */ + status = BCryptImportKeyPair(_libssh2_wincng.hAlgDH, NULL, + BCRYPT_DH_PUBLIC_BLOB, &peer_public, blob, + public_blob_len, 0); + if(!BCRYPT_SUCCESS(status)) { + goto out; + } + + /* Set up a handle that we can use to establish the shared secret + * between ourselves (our saved dh_handle) and the peer. */ + status = BCryptSecretAgreement(dhctx->dh_handle, peer_public, + &agreement, 0); + if(!BCRYPT_SUCCESS(status)) { + goto out; + } + + /* Compute the size of the buffer that is needed to hold the derived + * shared secret. */ + status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL, NULL, + 0, &secret_len_bytes, 0); + if(!BCRYPT_SUCCESS(status)) { + goto out; + } + + /* Expand the secret bignum to be ready to receive the derived secret + * */ + if(_libssh2_wincng_bignum_resize(secret, secret_len_bytes)) { + status = STATUS_NO_MEMORY; + goto out; + } + + /* And populate the secret bignum */ + status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL, + secret->bignum, secret_len_bytes, + &secret_len_bytes, 0); + if(!BCRYPT_SUCCESS(status)) { + goto out; + } + + /* Counter to all the other data in the BCrypt APIs, the raw secret is + * returned to us in host byte order, so we need to swap it to big + * endian order. */ + start = secret->bignum; + end = secret->bignum + secret->length - 1; + while(start < end) { + unsigned char tmp = *end; + *end = *start; + *start = tmp; + start++; + end--; + } + + status = 0; + +out: + if(peer_public) { + BCryptDestroyKey(peer_public); + } + if(agreement) { + BCryptDestroySecret(agreement); + } + return BCRYPT_SUCCESS(status) ? 0 : -1; + } +#endif + /* Compute the shared secret */ + return _libssh2_wincng_bignum_mod_exp(secret, f, dhctx->bn, p); } #endif /* LIBSSH2_WINCNG */ diff --git a/src/wincng.h b/src/wincng.h index c817f090..de966191 100755 --- a/src/wincng.h +++ b/src/wincng.h @@ -49,6 +49,12 @@ #include #include +#if defined(BCRYPT_KDF_RAW_SECRET) && defined(BCRYPT_DH_ALGORITHM) +/* BCRYPT_KDF_RAW_SECRET is available from Windows 8.1 and onwards */ +#define LIBSSH2_USE_BCRYPT_DH 1 +#else +#define LIBSSH2_USE_BCRYPT_DH 0 +#endif #define LIBSSH2_MD5 1 @@ -101,6 +107,9 @@ struct _libssh2_wincng_ctx { BCRYPT_ALG_HANDLE hAlgAES_ECB; BCRYPT_ALG_HANDLE hAlgRC4_NA; BCRYPT_ALG_HANDLE hAlg3DES_CBC; +#if LIBSSH2_USE_BCRYPT_DH + BCRYPT_ALG_HANDLE hAlgDH; +#endif }; extern struct _libssh2_wincng_ctx _libssh2_wincng; @@ -387,7 +396,17 @@ _libssh2_bn *_libssh2_wincng_bignum_init(void); * Windows CNG backend: Diffie-Hellman support */ -#define _libssh2_dh_ctx struct _libssh2_wincng_bignum * +typedef struct { +#if LIBSSH2_USE_BCRYPT_DH + /* holds our private+public key components */ + BCRYPT_KEY_HANDLE dh_handle; + /* records the parsed out modulus and generator parameters that are shared + * with the peer */ + BCRYPT_DH_PARAMETER_HEADER *dh_params; +#endif + /* fallback if the newer DH api doesn't work on this system */ + struct _libssh2_wincng_bignum *bn; +} _libssh2_dh_ctx; #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) From 8e6ae2855bdd2d2413da6eec561d347d264f8e55 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 14 Jun 2020 18:49:48 +0200 Subject: [PATCH 041/102] wincng: fix indentation of function arguments and comments Follow up to #397 --- src/wincng.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index c37d1f0e..de9b9e76 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -2235,12 +2235,12 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, * value is 257, so we need to round down to 8 bytes of length (64/8) * in order for kex to succeed */ DWORD key_length_bytes = max(round_down(group_order, 8), - max(g->length, p->length)); + max(g->length, p->length)); unsigned char *public_blob = NULL; BCRYPT_DH_KEY_BLOB *dh_key_blob; /* Prepare a key pair; pass the in the bit length of the key, - * but the key is not ready for consumption until it is finalized. */ + * but the key is not ready for consumption until it is finalized. */ status = BCryptGenerateKeyPair(_libssh2_wincng.hAlgDH, &dhctx->dh_handle, key_length_bytes * 8, 0); @@ -2255,18 +2255,18 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, } /* Populate DH parameters blob; after the header follows the `p` - * value and the `g` value. */ + * value and the `g` value. */ dh_params = (BCRYPT_DH_PARAMETER_HEADER*)blob; dh_params->cbLength = dh_params_len; dh_params->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; dh_params->cbKeyLength = key_length_bytes; memcpy_with_be_padding(blob + sizeof(*dh_params), key_length_bytes, - p->bignum, p->length); + p->bignum, p->length); memcpy_with_be_padding(blob + sizeof(*dh_params) + key_length_bytes, - key_length_bytes, g->bignum, g->length); + key_length_bytes, g->bignum, g->length); status = BCryptSetProperty(dhctx->dh_handle, BCRYPT_DH_PARAMETERS, - blob, dh_params_len, 0); + blob, dh_params_len, 0); /* Pass ownership to dhctx; these parameters will be freed when * the context is destroyed. We need to keep the parameters more * easily available so that we have access to the `g` value when @@ -2295,8 +2295,8 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, public_blob = malloc(public_key_len_bytes); status = BCryptExportKey(dhctx->dh_handle, NULL, BCRYPT_DH_PUBLIC_BLOB, - public_blob, public_key_len_bytes, - &public_key_len_bytes, 0); + public_blob, public_key_len_bytes, + &public_key_len_bytes, 0); if(!BCRYPT_SUCCESS(status)) { return -1; } @@ -2309,10 +2309,10 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, return -1; } - /* Copy the public key data into the bignum data buffer */ + /* Copy the public key data into the public bignum data buffer */ memcpy(public->bignum, - public_blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey, - dh_key_blob->cbKey); + public_blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey, + dh_key_blob->cbKey); return 0; } @@ -2365,20 +2365,20 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, /* Modulus (the p-value from the first call) */ memcpy_with_be_padding(dest, key_length_bytes, src, - dhctx->dh_params->cbKeyLength); + dhctx->dh_params->cbKeyLength); /* Generator (the g-value from the first call) */ memcpy_with_be_padding(dest + key_length_bytes, key_length_bytes, - src + dhctx->dh_params->cbKeyLength, - dhctx->dh_params->cbKeyLength); + src + dhctx->dh_params->cbKeyLength, + dhctx->dh_params->cbKeyLength); /* Public from the peer */ memcpy_with_be_padding(dest + 2*key_length_bytes, key_length_bytes, - f->bignum, f->length); + f->bignum, f->length); } /* Import the peer public key information */ status = BCryptImportKeyPair(_libssh2_wincng.hAlgDH, NULL, - BCRYPT_DH_PUBLIC_BLOB, &peer_public, blob, - public_blob_len, 0); + BCRYPT_DH_PUBLIC_BLOB, &peer_public, blob, + public_blob_len, 0); if(!BCRYPT_SUCCESS(status)) { goto out; } @@ -2386,7 +2386,7 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, /* Set up a handle that we can use to establish the shared secret * between ourselves (our saved dh_handle) and the peer. */ status = BCryptSecretAgreement(dhctx->dh_handle, peer_public, - &agreement, 0); + &agreement, 0); if(!BCRYPT_SUCCESS(status)) { goto out; } @@ -2408,8 +2408,8 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, /* And populate the secret bignum */ status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL, - secret->bignum, secret_len_bytes, - &secret_len_bytes, 0); + secret->bignum, secret_len_bytes, + &secret_len_bytes, 0); if(!BCRYPT_SUCCESS(status)) { goto out; } From 3baa367136fa3afa2150a7154d708eda4e296ce9 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 14 Jun 2020 19:28:29 +0200 Subject: [PATCH 042/102] wincng: try newer DH API first, fallback to legacy RSA API Avoid the use of RtlGetVersion or similar Win32 functions, since these depend on version information from manifests. This commit makes the WinCNG backend first try to use the new DH algorithm API with the raw secret derivation feature. In case this feature is not available the WinCNG backend will fallback to the classic approach of using RSA-encrypt to perform the required modular exponentiation of BigNums. The feature availability test is done during the first handshake and the result is stored in the crypto backends global state. Follow up to #397 Closes #484 --- src/wincng.c | 212 +++++++++++++++++++++++++++++++++------------------ src/wincng.h | 22 ++---- 2 files changed, 145 insertions(+), 89 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index de9b9e76..627d0aa9 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Marc Hoersken + * Copyright (C) 2013-2020 Marc Hoersken * All rights reserved. * * Redistribution and use in source and binary forms, @@ -58,6 +58,7 @@ #include #include +#include #include #include "misc.h" @@ -122,6 +123,15 @@ #define BCRYPT_3DES_ALGORITHM L"3DES" #endif +#ifndef BCRYPT_DH_ALGORITHM +#define BCRYPT_DH_ALGORITHM L"DH" +#endif + +/* BCRYPT_KDF_RAW_SECRET is available from Windows 8.1 and onwards */ +#ifndef BCRYPT_KDF_RAW_SECRET +#define BCRYPT_KDF_RAW_SECRET L"TRUNCATE" +#endif + #ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG #define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008 #endif @@ -294,10 +304,11 @@ _libssh2_wincng_init(void) } } -#if LIBSSH2_USE_BCRYPT_DH - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDH, + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDH, BCRYPT_DH_ALGORITHM, NULL, 0); -#endif + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgDH = NULL; + } } void @@ -317,9 +328,7 @@ _libssh2_wincng_free(void) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0); -#if LIBSSH2_USE_BCRYPT_DH (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDH, 0); -#endif memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); } @@ -2133,26 +2142,7 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn) } } -#if LIBSSH2_USE_BCRYPT_DH -/* We provide our own prototype for this function as the availability - * of the header that is documented to provide it is patchy across - * the various environments that the libssh2 CI builds on, and - * because the stdcall convention is important for the linker to - * be able to resolve the function in 32-bit MSVC compiler - * environments. */ -extern NTSTATUS __stdcall RtlGetVersion(OSVERSIONINFOW*); - -static int is_windows_10_or_later(void) -{ - OSVERSIONINFOW vers; - vers.dwOSVersionInfoSize = sizeof(vers); - if(RtlGetVersion(&vers) != 0) { - return 0; - } - return vers.dwMajorVersion >= 10; -} -#endif - +/*******************************************************************/ /* * Windows CNG backend: Diffie-Hellman support. */ @@ -2160,35 +2150,25 @@ static int is_windows_10_or_later(void) void _libssh2_dh_init(_libssh2_dh_ctx *dhctx) { -#if LIBSSH2_USE_BCRYPT_DH - if(is_windows_10_or_later()) { - dhctx->dh_handle = NULL; - dhctx->dh_params = NULL; - return; - } -#endif /* Random from client */ - dhctx->bn = _libssh2_wincng_bignum_init(); + dhctx->bn = NULL; + dhctx->dh_handle = NULL; + dhctx->dh_params = NULL; } void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) { -#if LIBSSH2_USE_BCRYPT_DH - if(is_windows_10_or_later()) { - if(dhctx->dh_handle) { - BCryptDestroyKey(dhctx->dh_handle); - dhctx->dh_handle = NULL; - } - if(dhctx->dh_params) { - /* Since dh_params were shared in clear text, we don't need - * to securely zero them out here */ - free(dhctx->dh_params); - dhctx->dh_params = NULL; - } - return; + if(dhctx->dh_handle) { + BCryptDestroyKey(dhctx->dh_handle); + dhctx->dh_handle = NULL; + } + if(dhctx->dh_params) { + /* Since public dh_params are shared in clear text, + * we don't need to securely zero them out here */ + free(dhctx->dh_params); + dhctx->dh_params = NULL; } -#endif if(dhctx->bn) { _libssh2_wincng_bignum_free(dhctx->bn); dhctx->bn = NULL; @@ -2223,21 +2203,20 @@ int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, _libssh2_bn *g, _libssh2_bn *p, int group_order) { -#if LIBSSH2_USE_BCRYPT_DH - if(is_windows_10_or_later()) { + const int hasAlgDHwithKDF = _libssh2_wincng.hasAlgDHwithKDF; + while(_libssh2_wincng.hAlgDH && hasAlgDHwithKDF != -1) { BCRYPT_DH_PARAMETER_HEADER *dh_params = NULL; unsigned long dh_params_len; unsigned char *blob = NULL; int status; - DWORD public_key_len_bytes = 0; /* Note that the DH provider requires that keys be multiples of 64 bits * in length. At the time of writing a practical observed group_order * value is 257, so we need to round down to 8 bytes of length (64/8) * in order for kex to succeed */ DWORD key_length_bytes = max(round_down(group_order, 8), max(g->length, p->length)); - unsigned char *public_blob = NULL; BCRYPT_DH_KEY_BLOB *dh_key_blob; + LPCWSTR key_type; /* Prepare a key pair; pass the in the bit length of the key, * but the key is not ready for consumption until it is finalized. */ @@ -2267,11 +2246,18 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, status = BCryptSetProperty(dhctx->dh_handle, BCRYPT_DH_PARAMETERS, blob, dh_params_len, 0); - /* Pass ownership to dhctx; these parameters will be freed when - * the context is destroyed. We need to keep the parameters more - * easily available so that we have access to the `g` value when - * _libssh2_dh_secret is called later. */ - dhctx->dh_params = dh_params; + if(hasAlgDHwithKDF == -1) { + /* We know that the raw KDF is not supported, so discard this. */ + free(blob); + } + else { + /* Pass ownership to dhctx; these parameters will be freed when + * the context is destroyed. We need to keep the parameters more + * easily available so that we have access to the `g` value when + * _libssh2_dh_secret is called later. */ + dhctx->dh_params = dh_params; + } + dh_params = NULL; blob = NULL; if(!BCRYPT_SUCCESS(status)) { @@ -2283,45 +2269,111 @@ _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public, return -1; } - /* Now we need to extract the public portion of the key so that we - * set it in the `public` bignum to satisfy our caller. - * First measure up the size of the required buffer. */ - status = BCryptExportKey(dhctx->dh_handle, NULL, BCRYPT_DH_PUBLIC_BLOB, - NULL, 0, &public_key_len_bytes, 0); + key_length_bytes = 0; + if(hasAlgDHwithKDF == 1) { + /* Now we need to extract the public portion of the key so that we + * set it in the `public` bignum to satisfy our caller. + * First measure up the size of the required buffer. */ + key_type = BCRYPT_DH_PUBLIC_BLOB; + } + else { + /* We also need to extract the private portion of the key to + * set it in the `*dhctx' bignum if the raw KDF is not supported. + * First measure up the size of the required buffer. */ + key_type = BCRYPT_DH_PRIVATE_BLOB; + } + status = BCryptExportKey(dhctx->dh_handle, NULL, key_type, + NULL, 0, &key_length_bytes, 0); if(!BCRYPT_SUCCESS(status)) { return -1; } - public_blob = malloc(public_key_len_bytes); - - status = BCryptExportKey(dhctx->dh_handle, NULL, BCRYPT_DH_PUBLIC_BLOB, - public_blob, public_key_len_bytes, - &public_key_len_bytes, 0); - if(!BCRYPT_SUCCESS(status)) { + blob = malloc(key_length_bytes); + if(!blob) { return -1; } + status = BCryptExportKey(dhctx->dh_handle, NULL, key_type, + blob, key_length_bytes, + &key_length_bytes, 0); + if(!BCRYPT_SUCCESS(status)) { + if(hasAlgDHwithKDF == 1) { + /* We have no private data, because raw KDF is supported */ + free(blob); + } + else { /* we may have potentially private data, use secure free */ + _libssh2_wincng_safe_free(blob, key_length_bytes); + } + return -1; + } + + if(hasAlgDHwithKDF == -1) { + /* We know that the raw KDF is not supported, so discard this */ + BCryptDestroyKey(dhctx->dh_handle); + dhctx->dh_handle = NULL; + } + /* BCRYPT_DH_PUBLIC_BLOB corresponds to a BCRYPT_DH_KEY_BLOB header * followed by the Modulus, Generator and Public data. Those components * each have equal size, specified by dh_key_blob->cbKey. */ - dh_key_blob = (BCRYPT_DH_KEY_BLOB*)public_blob; + dh_key_blob = (BCRYPT_DH_KEY_BLOB*)blob; if(_libssh2_wincng_bignum_resize(public, dh_key_blob->cbKey)) { + if(hasAlgDHwithKDF == 1) { + /* We have no private data, because raw KDF is supported */ + free(blob); + } + else { /* we may have potentially private data, use secure free */ + _libssh2_wincng_safe_free(blob, key_length_bytes); + } return -1; } /* Copy the public key data into the public bignum data buffer */ memcpy(public->bignum, - public_blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey, + blob + sizeof(*dh_key_blob) + 2 * dh_key_blob->cbKey, dh_key_blob->cbKey); + if(dh_key_blob->dwMagic == BCRYPT_DH_PRIVATE_MAGIC) { + /* BCRYPT_DH_PRIVATE_BLOB additionally contains the Private data */ + dhctx->bn = _libssh2_wincng_bignum_init(); + if(!dhctx->bn) { + _libssh2_wincng_safe_free(blob, key_length_bytes); + return -1; + } + if(_libssh2_wincng_bignum_resize(dhctx->bn, dh_key_blob->cbKey)) { + _libssh2_wincng_safe_free(blob, key_length_bytes); + return -1; + } + + /* Copy the private key data into the dhctx bignum data buffer */ + memcpy(dhctx->bn->bignum, + blob + sizeof(*dh_key_blob) + 3 * dh_key_blob->cbKey, + dh_key_blob->cbKey); + + /* Make sure the private key is an odd number, because only + * odd primes can be used with the RSA-based fallback while + * DH itself does not seem to care about it being odd or not. */ + if(!(dhctx->bn->bignum[dhctx->bn->length-1] % 2)) { + _libssh2_wincng_safe_free(blob, key_length_bytes); + /* discard everything first, then try again */ + _libssh2_dh_dtor(dhctx); + _libssh2_dh_init(dhctx); + continue; + } + } + return 0; } -#endif + /* Generate x and e */ + dhctx->bn = _libssh2_wincng_bignum_init(); + if(!dhctx->bn) + return -1; if(_libssh2_wincng_bignum_rand(dhctx->bn, group_order * 8 - 1, 0, -1)) return -1; if(_libssh2_wincng_bignum_mod_exp(public, g, dhctx->bn, p)) return -1; + return 0; } @@ -2333,8 +2385,8 @@ int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, _libssh2_bn *f, _libssh2_bn *p) { -#if LIBSSH2_USE_BCRYPT_DH - if(is_windows_10_or_later()) { + if(_libssh2_wincng.hAlgDH && _libssh2_wincng.hasAlgDHwithKDF != -1 && + dhctx->dh_handle && dhctx->dh_params && f) { BCRYPT_KEY_HANDLE peer_public = NULL; BCRYPT_SECRET_HANDLE agreement = NULL; ULONG secret_len_bytes = 0; @@ -2396,6 +2448,9 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, status = BCryptDeriveKey(agreement, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &secret_len_bytes, 0); if(!BCRYPT_SUCCESS(status)) { + if(status == STATUS_NOT_SUPPORTED) { + _libssh2_wincng.hasAlgDHwithKDF = -1; + } goto out; } @@ -2411,6 +2466,9 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, secret->bignum, secret_len_bytes, &secret_len_bytes, 0); if(!BCRYPT_SUCCESS(status)) { + if(status == STATUS_NOT_SUPPORTED) { + _libssh2_wincng.hasAlgDHwithKDF = -1; + } goto out; } @@ -2428,6 +2486,7 @@ _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, } status = 0; + _libssh2_wincng.hasAlgDHwithKDF = 1; out: if(peer_public) { @@ -2436,9 +2495,14 @@ out: if(agreement) { BCryptDestroySecret(agreement); } + if(status == STATUS_NOT_SUPPORTED && + _libssh2_wincng.hasAlgDHwithKDF == -1) { + goto fb; /* fallback to RSA-based implementation */ + } return BCRYPT_SUCCESS(status) ? 0 : -1; } -#endif + +fb: /* Compute the shared secret */ return _libssh2_wincng_bignum_mod_exp(secret, f, dhctx->bn, p); } diff --git a/src/wincng.h b/src/wincng.h index de966191..43ee974f 100755 --- a/src/wincng.h +++ b/src/wincng.h @@ -49,13 +49,6 @@ #include #include -#if defined(BCRYPT_KDF_RAW_SECRET) && defined(BCRYPT_DH_ALGORITHM) -/* BCRYPT_KDF_RAW_SECRET is available from Windows 8.1 and onwards */ -#define LIBSSH2_USE_BCRYPT_DH 1 -#else -#define LIBSSH2_USE_BCRYPT_DH 0 -#endif - #define LIBSSH2_MD5 1 #define LIBSSH2_HMAC_RIPEMD 0 @@ -107,9 +100,8 @@ struct _libssh2_wincng_ctx { BCRYPT_ALG_HANDLE hAlgAES_ECB; BCRYPT_ALG_HANDLE hAlgRC4_NA; BCRYPT_ALG_HANDLE hAlg3DES_CBC; -#if LIBSSH2_USE_BCRYPT_DH BCRYPT_ALG_HANDLE hAlgDH; -#endif + volatile int hasAlgDHwithKDF; /* -1=no, 0=maybe, 1=yes */ }; extern struct _libssh2_wincng_ctx _libssh2_wincng; @@ -397,16 +389,16 @@ _libssh2_bn *_libssh2_wincng_bignum_init(void); */ typedef struct { -#if LIBSSH2_USE_BCRYPT_DH - /* holds our private+public key components */ + /* holds our private and public key components */ BCRYPT_KEY_HANDLE dh_handle; - /* records the parsed out modulus and generator parameters that are shared - * with the peer */ + /* records the parsed out modulus and generator + * parameters that are shared with the peer */ BCRYPT_DH_PARAMETER_HEADER *dh_params; -#endif - /* fallback if the newer DH api doesn't work on this system */ + /* records the parsed out private key component for + * fallback if the DH API raw KDF is not supported */ struct _libssh2_wincng_bignum *bn; } _libssh2_dh_ctx; + #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) From 6b5fdf796b73d48da0bf36612f73ccfb4c2ad49d Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 8 Jul 2020 13:48:59 -0700 Subject: [PATCH 043/102] stale.yml Increasing stale values. --- .github/stale.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index 4423ec86..159f419b 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Number of days of inactivity before an issue becomes stale -daysUntilStale: 90 +daysUntilStale: 120 # Number of days of inactivity before a stale issue is closed -daysUntilClose: 21 +daysUntilClose: 30 # Issues with these labels will never be considered stale exemptLabels: - pinned From ca9bb089081d0458bff098436e54b81f9e1e3779 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Fri, 10 Jul 2020 10:45:47 -0700 Subject: [PATCH 044/102] transport.c: socket is disconnected, return error (#500) File: transport.c Notes: This is to fix #102, instead of continuing to attempt to read a disconnected socket, it will now error out. Credit: TDi-jonesds --- src/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transport.c b/src/transport.c index 11e56142..0723b77b 100644 --- a/src/transport.c +++ b/src/transport.c @@ -323,7 +323,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) do { if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) { - return LIBSSH2_ERROR_NONE; + return LIBSSH2_ERROR_SOCKET_DISCONNECT; } if(session->state & LIBSSH2_STATE_NEWKEYS) { From 1a61d0c3ca09de527e474becd6c3a14c8a3abe18 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 10 Jul 2020 13:47:48 -0400 Subject: [PATCH 045/102] openssl.c: clean up curve25519 code (#499) File: openssl.c, openssl.h, crypto.h, kex.c Notes: This cleans up a few things in the curve25519 implementation: - There is no need to create X509_PUBKEYs or PKCS8_PRIV_KEY_INFOs to extract key material. EVP_PKEY_get_raw_private_key and EVP_PKEY_get_raw_public_key work fine. - libssh2_x25519_ctx was never used (and occasionally mis-typedefed to libssh2_ed25519_ctx). Remove it. The _libssh2_curve25519_new and _libssh2_curve25519_gen_k interfaces use the bytes. Note, if it needs to be added back, there is no need to roundtrip through EVP_PKEY_new_raw_private_key. EVP_PKEY_keygen already generated an EVP_PKEY. - Add some missing error checks. Credit: David Benjamin --- src/crypto.h | 4 +-- src/kex.c | 2 +- src/openssl.c | 78 ++++++++++++++++++--------------------------------- src/openssl.h | 2 -- 4 files changed, 30 insertions(+), 56 deletions(-) diff --git a/src/crypto.h b/src/crypto.h index c36dde10..f512d603 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -181,8 +181,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, diff --git a/src/kex.c b/src/kex.c index b225a2f0..2122c7b5 100644 --- a/src/kex.c +++ b/src/kex.c @@ -3195,7 +3195,7 @@ kex_method_curve25519_key_exchange goto clean_exit; } - rc = _libssh2_curve25519_new(session, NULL, + rc = _libssh2_curve25519_new(session, &key_state->curve25519_public_key, &key_state->curve25519_private_key); diff --git a/src/openssl.c b/src/openssl.c index 9d3b8c7e..65a6c173 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -1465,75 +1465,53 @@ _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, #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) 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) { + if(EVP_PKEY_keygen_init(pctx) != 1 || + EVP_PKEY_keygen(pctx, &key) != 1) { goto cleanExit; } - 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) + privLen = LIBSSH2_ED25519_KEY_LEN; + priv = LIBSSH2_ALLOC(session, privLen); + if(priv == NULL) goto cleanExit; - memcpy(*out_private_key, priv, LIBSSH2_ED25519_KEY_LEN); + if(EVP_PKEY_get_raw_private_key(key, priv, &privLen) != 1 || + privLen != LIBSSH2_ED25519_KEY_LEN) { + goto cleanExit; + } + + *out_private_key = priv; + priv = NULL; } if(out_public_key != NULL) { - *out_public_key = LIBSSH2_ALLOC(session, LIBSSH2_ED25519_KEY_LEN); - if(*out_public_key == NULL) + pubLen = LIBSSH2_ED25519_KEY_LEN; + pub = LIBSSH2_ALLOC(session, pubLen); + if(pub == NULL) goto cleanExit; - memcpy(*out_public_key, pub, LIBSSH2_ED25519_KEY_LEN); - } - - if(out_ctx != NULL) { - ctx = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, priv, - LIBSSH2_ED25519_KEY_LEN); - if(!ctx) + if(EVP_PKEY_get_raw_public_key(key, pub, &pubLen) != 1 || + pubLen != LIBSSH2_ED25519_KEY_LEN) { goto cleanExit; + } - *out_ctx = ctx; + *out_public_key = pub; + pub = NULL; } /* success */ @@ -1541,16 +1519,14 @@ _libssh2_curve25519_new(LIBSSH2_SESSION *session, libssh2_x25519_ctx **out_ctx, cleanExit: - 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; } diff --git a/src/openssl.h b/src/openssl.h index f65192d2..66ff1b26 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -325,10 +325,8 @@ libssh2_curve_type; #if LIBSSH2_ED25519 #define libssh2_ed25519_ctx EVP_PKEY -#define libssh2_x25519_ctx EVP_PKEY #define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx) -#define _libssh2_x25519_free(ctx) EVP_PKEY_free(ctx) #endif /* ED25519 */ #define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void) From 1894b30b5c20340065015f2065594d89bb9c1127 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Mon, 6 Jul 2020 21:22:20 +0200 Subject: [PATCH 046/102] wincng: make sure algorithm providers are closed once (#496) --- src/wincng.c | 122 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 92 insertions(+), 30 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index 627d0aa9..69bacb92 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -225,35 +225,70 @@ _libssh2_wincng_init(void) { int ret; - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG, + memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); + + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG, BCRYPT_RNG_ALGORITHM, NULL, 0); + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgRNG = NULL; + } - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5, + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5, BCRYPT_MD5_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1, + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHashMD5 = NULL; + } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1, BCRYPT_SHA1_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256, + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHashSHA1 = NULL; + } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256, BCRYPT_SHA256_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512, + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHashSHA256 = NULL; + } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512, BCRYPT_SHA512_ALGORITHM, NULL, 0); + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHashSHA512 = NULL; + } - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5, + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5, BCRYPT_MD5_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1, + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHmacMD5 = NULL; + } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256, + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHmacSHA1 = NULL; + } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512, + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHmacSHA256 = NULL; + } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512, BCRYPT_SHA512_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHmacSHA512 = NULL; + } - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA, + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA, BCRYPT_RSA_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA, + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgRSA = NULL; + } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA, BCRYPT_DSA_ALGORITHM, NULL, 0); + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgDSA = NULL; + } ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC, BCRYPT_AES_ALGORITHM, NULL, 0); @@ -263,7 +298,10 @@ _libssh2_wincng_init(void) (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); + ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); + if(BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgAES_CBC = NULL; + } } } @@ -275,7 +313,10 @@ _libssh2_wincng_init(void) (PBYTE)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0); if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0); + ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0); + if(BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgAES_ECB = NULL; + } } } @@ -287,7 +328,10 @@ _libssh2_wincng_init(void) (PBYTE)BCRYPT_CHAIN_MODE_NA, sizeof(BCRYPT_CHAIN_MODE_NA), 0); if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); + ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); + if(BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgRC4_NA = NULL; + } } } @@ -299,8 +343,11 @@ _libssh2_wincng_init(void) (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0); if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, + ret = BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0); + if(BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlg3DES_CBC = NULL; + } } } @@ -314,21 +361,36 @@ _libssh2_wincng_init(void) 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); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDH, 0); + if(_libssh2_wincng.hAlgRNG) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0); + if(_libssh2_wincng.hAlgHashMD5) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0); + if(_libssh2_wincng.hAlgHashSHA1) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0); + if(_libssh2_wincng.hAlgHashSHA256) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0); + if(_libssh2_wincng.hAlgHashSHA512) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0); + if(_libssh2_wincng.hAlgHmacMD5) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0); + if(_libssh2_wincng.hAlgHmacSHA1) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0); + if(_libssh2_wincng.hAlgHmacSHA256) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0); + if(_libssh2_wincng.hAlgHmacSHA512) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0); + if(_libssh2_wincng.hAlgRSA) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0); + if(_libssh2_wincng.hAlgDSA) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0); + if(_libssh2_wincng.hAlgAES_CBC) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); + if(_libssh2_wincng.hAlgRC4_NA) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); + if(_libssh2_wincng.hAlg3DES_CBC) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0); + if(_libssh2_wincng.hAlgDH) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDH, 0); memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); } From 5eaa7aa1c042e06cd4826a79af6af73ea5bf8370 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Mon, 6 Jul 2020 21:43:03 +0200 Subject: [PATCH 047/102] wincng: make more use of new helper functions (#496) --- src/wincng.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index 69bacb92..88c82ca2 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -423,6 +423,24 @@ _libssh2_wincng_safe_free(void *buf, int len) free(buf); } +/* Copy a big endian set of bits from src to dest. + * if the size of src is smaller than dest then pad the "left" (MSB) + * end with zeroes and copy the bits into the "right" (LSB) end. */ +static void +memcpy_with_be_padding(unsigned char *dest, unsigned long dest_len, + unsigned char *src, unsigned long src_len) +{ + if(dest_len > src_len) { + memset(dest, 0, dest_len - src_len); + } + memcpy((dest + dest_len) - src_len, src, src_len); +} + +static int +round_down(int number, int multiple) +{ + return (number / multiple) * multiple; +} /*******************************************************************/ /* @@ -2060,6 +2078,7 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, offset += p->length; memcpy(key + offset, m->bignum, m->length); + offset = 0; ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, 0); @@ -2071,9 +2090,8 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, 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); + memcpy_with_be_padding(bignum, length, + a->bignum, a->length); ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0, r->bignum, r->length, &offset, @@ -2204,6 +2222,7 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn) } } + /*******************************************************************/ /* * Windows CNG backend: Diffie-Hellman support. @@ -2237,25 +2256,6 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) } } -/* Copy a big endian set of bits from src to dest. - * if the size of src is smaller than dest then pad the "left" (MSB) - * end with zeroes and copy the bits into the "right" (LSB) end. */ -static void -memcpy_with_be_padding(unsigned char *dest, unsigned long dest_len, - unsigned char *src, unsigned long src_len) -{ - if(dest_len > src_len) { - memset(dest, 0, dest_len - src_len); - } - memcpy(dest + dest_len - src_len, src, src_len); -} - -static int -round_down(int number, int multiple) -{ - return (number / multiple) * multiple; -} - /* Generates a Diffie-Hellman key pair using base `g', prime `p' and the given * `group_order'. Can use the given big number context `bnctx' if needed. The * private key is stored as opaque in the Diffie-Hellman context `*dhctx' and From 5964268dc79c4b2556d1f21c83c2c079fb59c610 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 23 Aug 2020 20:53:48 +0200 Subject: [PATCH 048/102] scp.c: fix indentation in shell_quotearg documentation --- src/scp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scp.c b/src/scp.c index a9d2db53..8cb3d65c 100644 --- a/src/scp.c +++ b/src/scp.c @@ -65,13 +65,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 +84,7 @@ a!b become - _ _ _ + _ _ _ 'a'\!'b' The result buffer must be large enough for the expanded result. A From 93862bf6c1337da49c075a013a9a9a812905b41a Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sat, 29 Aug 2020 21:52:42 +0200 Subject: [PATCH 049/102] buildconf: exec autoreconf to avoid additional process (#512) Also make buildconf exit with the return code of autoreconf. Follow up to #224 --- buildconf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildconf b/buildconf index 728b3397..80971930 100755 --- a/buildconf +++ b/buildconf @@ -5,4 +5,4 @@ echo "*** Do not use buildconf. Instead, just use: autoreconf -fi" >&2 echo "*** Doing it for you now, but buildconf may disapear in the future." >&2 echo "***" >&2 -${AUTORECONF:-autoreconf} -fi "${@}" +exec ${AUTORECONF:-autoreconf} -fi "${@}" From 5528f3da02eba1de425535481de049b21c48e9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Katzer?= Date: Tue, 1 Sep 2020 23:18:09 +0200 Subject: [PATCH 050/102] mbedtls.c: ECDSA support for mbed TLS (#385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files: mbedtls.c, mbedtls.h, .travis.yml Notes: This PR adds support for ECDSA for both key exchange and host key algorithms. The following elliptic curves are supported: 256-bit curve defined by FIPS 186-4 and SEC1 384-bit curve defined by FIPS 186-4 and SEC1 521-bit curve defined by FIPS 186-4 and SEC1 Credit: Sebastián Katzer --- .travis.yml | 2 +- src/mbedtls.c | 520 +++++++++++++++++++++++++++++++++++++++++++++++++- src/mbedtls.h | 149 ++++++++++++++- 3 files changed, 662 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index d543a334..b13ac4af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -86,7 +86,7 @@ before_install: - if [ $ADDRESS_SIZE = '64' ]; then sudo apt-get install -y libgcrypt11-dev; fi - if [ $ADDRESS_SIZE = '32' ]; then export TOOLCHAIN_OPTION="-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-Linux-32.cmake"; fi - if [ $CRYPTO_BACKEND = 'mbedTLS' ]; then - MBEDTLSVER=mbedtls-2.4.0; + MBEDTLSVER=mbedtls-2.7.0; curl -L https://github.com/ARMmbed/mbedtls/archive/$MBEDTLSVER.tar.gz | tar -xzf -; cd mbedtls-$MBEDTLSVER; cmake $TOOLCHAIN_OPTION -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DCMAKE_INSTALL_PREFIX:PATH=../usr .; diff --git a/src/mbedtls.c b/src/mbedtls.c index 128eee4b..4629ce4a 100644 --- a/src/mbedtls.c +++ b/src/mbedtls.c @@ -94,7 +94,7 @@ _libssh2_mbedtls_safe_free(void *buf, int len) #ifdef LIBSSH2_CLEAR_MEMORY if(len > 0) - memset(buf, 0, len); + _libssh2_explicit_zero(buf, len); #endif mbedtls_free(buf); @@ -730,4 +730,522 @@ _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) *dhctx = NULL; } +#if LIBSSH2_ECDSA + +/*******************************************************************/ +/* + * mbedTLS backend: ECDSA functions + */ + +/* + * _libssh2_ecdsa_create_key + * + * Creates a local private key based on input curve + * and returns octal value and octal length + * + */ + +int +_libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session, + _libssh2_ec_key **privkey, + unsigned char **pubkey_oct, + size_t *pubkey_oct_len, + libssh2_curve_type curve) +{ + size_t plen = 0; + + *privkey = LIBSSH2_ALLOC(session, sizeof(mbedtls_ecp_keypair)); + + if(*privkey == NULL) + goto failed; + + mbedtls_ecdsa_init(*privkey); + + if(mbedtls_ecdsa_genkey(*privkey, (mbedtls_ecp_group_id)curve, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg) != 0) + goto failed; + + plen = 2 * mbedtls_mpi_size(&(*privkey)->grp.P) + 1; + *pubkey_oct = LIBSSH2_ALLOC(session, plen); + + if(*pubkey_oct == NULL) + goto failed; + + if(mbedtls_ecp_point_write_binary(&(*privkey)->grp, &(*privkey)->Q, + MBEDTLS_ECP_PF_UNCOMPRESSED, + pubkey_oct_len, *pubkey_oct, plen) == 0) + return 0; + +failed: + + _libssh2_mbedtls_ecdsa_free(*privkey); + _libssh2_mbedtls_safe_free(*pubkey_oct, plen); + *privkey = NULL; + + return -1; +} + +/* _libssh2_ecdsa_curve_name_with_octal_new + * + * Creates a new public key given an octal string, length and type + * + */ + +int +_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx, + const unsigned char *k, + size_t k_len, + libssh2_curve_type curve) +{ + *ctx = mbedtls_calloc(1, sizeof(mbedtls_ecp_keypair)); + + if(*ctx == NULL) + goto failed; + + mbedtls_ecdsa_init(*ctx); + + if(mbedtls_ecp_group_load(&(*ctx)->grp, (mbedtls_ecp_group_id)curve) != 0) + goto failed; + + if(mbedtls_ecp_point_read_binary(&(*ctx)->grp, &(*ctx)->Q, k, k_len) != 0) + goto failed; + + if(mbedtls_ecp_check_pubkey(&(*ctx)->grp, &(*ctx)->Q) == 0) + return 0; + +failed: + + _libssh2_mbedtls_ecdsa_free(*ctx); + *ctx = NULL; + + return -1; +} + +/* _libssh2_ecdh_gen_k + * + * Computes the shared secret K given a local private key, + * remote public key and length + */ + +int +_libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k, + _libssh2_ec_key *privkey, + const unsigned char *server_pubkey, + size_t server_pubkey_len) +{ + mbedtls_ecp_point pubkey; + int rc = 0; + + if(*k == NULL) + return -1; + + mbedtls_ecp_point_init(&pubkey); + + if(mbedtls_ecp_point_read_binary(&privkey->grp, &pubkey, + server_pubkey, server_pubkey_len) != 0) { + rc = -1; + goto cleanup; + } + + if(mbedtls_ecdh_compute_shared(&privkey->grp, *k, + &pubkey, &privkey->d, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg) != 0) { + rc = -1; + goto cleanup; + } + + if(mbedtls_ecp_check_privkey(&privkey->grp, *k) != 0) + rc = -1; + +cleanup: + + mbedtls_ecp_point_free(&pubkey); + + return rc; +} + +#define LIBSSH2_MBEDTLS_ECDSA_VERIFY(digest_type) \ +{ \ + unsigned char hsh[SHA##digest_type##_DIGEST_LENGTH]; \ + \ + if(libssh2_sha##digest_type(m, m_len, hsh) == 0) { \ + rc = mbedtls_ecdsa_verify(&ctx->grp, hsh, \ + SHA##digest_type##_DIGEST_LENGTH, \ + &ctx->Q, &pr, &ps); \ + } \ + \ +} + +/* _libssh2_ecdsa_sign + * + * Verifies the ECDSA signature of a hashed message + * + */ + +int +_libssh2_mbedtls_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) +{ + mbedtls_mpi pr, ps; + int rc = -1; + + mbedtls_mpi_init(&pr); + mbedtls_mpi_init(&ps); + + if(mbedtls_mpi_read_binary(&pr, r, r_len) != 0) + goto cleanup; + + if(mbedtls_mpi_read_binary(&ps, s, s_len) != 0) + goto cleanup; + + switch(_libssh2_ecdsa_get_curve_type(ctx)) { + case LIBSSH2_EC_CURVE_NISTP256: + LIBSSH2_MBEDTLS_ECDSA_VERIFY(256); + break; + case LIBSSH2_EC_CURVE_NISTP384: + LIBSSH2_MBEDTLS_ECDSA_VERIFY(384); + break; + case LIBSSH2_EC_CURVE_NISTP521: + LIBSSH2_MBEDTLS_ECDSA_VERIFY(512); + break; + default: + rc = -1; + } + +cleanup: + + mbedtls_mpi_free(&pr); + mbedtls_mpi_free(&ps); + + return (rc == 0) ? 0 : -1; +} + +static int +_libssh2_mbedtls_parse_eckey(libssh2_ecdsa_ctx **ctx, + mbedtls_pk_context *pkey, + LIBSSH2_SESSION *session, + const unsigned char *data, + size_t data_len, + const unsigned char *pwd) +{ + size_t pwd_len; + + pwd_len = pwd ? strlen((const char *) pwd) : 0; + + if(mbedtls_pk_parse_key(pkey, data, data_len, pwd, pwd_len) != 0) + goto failed; + + if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_ECKEY) + goto failed; + + *ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx)); + + if(*ctx == NULL) + goto failed; + + mbedtls_ecdsa_init(*ctx); + + if(mbedtls_ecdsa_from_keypair(*ctx, mbedtls_pk_ec(*pkey)) == 0) + return 0; + +failed: + + _libssh2_mbedtls_ecdsa_free(*ctx); + *ctx = NULL; + + return -1; +} + +static int +_libssh2_mbedtls_parse_openssh_key(libssh2_ecdsa_ctx **ctx, + LIBSSH2_SESSION *session, + const unsigned char *data, + size_t data_len, + const unsigned char *pwd) +{ + libssh2_curve_type type; + unsigned char *name = NULL; + struct string_buf *decrypted = NULL; + size_t curvelen, exponentlen, pointlen; + unsigned char *curve, *exponent, *point_buf; + + if(_libssh2_openssh_pem_parse_memory(session, pwd, + (const char *)data, data_len, + &decrypted) != 0) + goto failed; + + if(_libssh2_get_string(decrypted, &name, NULL) != 0) + goto failed; + + if(_libssh2_mbedtls_ecdsa_curve_type_from_name((const char *)name, + &type) != 0) + goto failed; + + if(_libssh2_get_string(decrypted, &curve, &curvelen) != 0) + goto failed; + + if(_libssh2_get_string(decrypted, &point_buf, &pointlen) != 0) + goto failed; + + if(_libssh2_get_bignum_bytes(decrypted, &exponent, &exponentlen) != 0) + goto failed; + + *ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx)); + + if(*ctx == NULL) + goto failed; + + mbedtls_ecdsa_init(*ctx); + + if(mbedtls_ecp_group_load(&(*ctx)->grp, (mbedtls_ecp_group_id)type) != 0) + goto failed; + + if(mbedtls_mpi_read_binary(&(*ctx)->d, exponent, exponentlen) != 0) + goto failed; + + if(mbedtls_ecp_mul(&(*ctx)->grp, &(*ctx)->Q, + &(*ctx)->d, &(*ctx)->grp.G, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg) != 0) + goto failed; + + if(mbedtls_ecp_check_privkey(&(*ctx)->grp, &(*ctx)->d) == 0) + goto cleanup; + +failed: + + _libssh2_mbedtls_ecdsa_free(*ctx); + *ctx = NULL; + +cleanup: + + if(decrypted) { + _libssh2_string_buf_free(session, decrypted); + } + + return (*ctx == NULL) ? -1 : 0; +} + +/* _libssh2_ecdsa_new_private + * + * Creates a new private key given a file path and password + * + */ + +int +_libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx, + LIBSSH2_SESSION *session, + const char *filename, + const unsigned char *pwd) +{ + mbedtls_pk_context pkey; + unsigned char *data; + size_t data_len; + + if(mbedtls_pk_load_file(filename, &data, &data_len) != 0) + goto cleanup; + + mbedtls_pk_init(&pkey); + + if(_libssh2_mbedtls_parse_eckey(ctx, &pkey, session, + data, data_len, pwd) == 0) + goto cleanup; + + _libssh2_mbedtls_parse_openssh_key(ctx, session, data, data_len, pwd); + +cleanup: + + mbedtls_pk_free(&pkey); + + _libssh2_mbedtls_safe_free(data, data_len); + + return (*ctx == NULL) ? -1 : 0; +} + +/* _libssh2_ecdsa_new_private + * + * Creates a new private key given a file data and password + * + */ + +int +_libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx, + LIBSSH2_SESSION *session, + const char *data, + size_t data_len, + const unsigned char *pwd) +{ + unsigned char *ntdata; + mbedtls_pk_context pkey; + + mbedtls_pk_init(&pkey); + + ntdata = LIBSSH2_ALLOC(session, data_len + 1); + + if(ntdata == NULL) + goto cleanup; + + memcpy(ntdata, data, data_len); + + if(_libssh2_mbedtls_parse_eckey(ctx, &pkey, session, + ntdata, data_len + 1, pwd) == 0) + goto cleanup; + + _libssh2_mbedtls_parse_openssh_key(ctx, session, + ntdata, data_len + 1, pwd); + +cleanup: + + mbedtls_pk_free(&pkey); + + _libssh2_mbedtls_safe_free(ntdata, data_len); + + return (*ctx == NULL) ? -1 : 0; +} + +static unsigned char * +_libssh2_mbedtls_mpi_write_binary(unsigned char *buf, + const mbedtls_mpi *mpi, + size_t bytes) +{ + unsigned char *p = buf; + + if(sizeof(&p) / sizeof(p[0]) < 4) { + goto done; + } + + p += 4; + *p = 0; + + if(bytes > 0) { + mbedtls_mpi_write_binary(mpi, p + 1, bytes - 1); + } + + if(bytes > 0 && !(*(p + 1) & 0x80)) { + memmove(p, p + 1, --bytes); + } + + _libssh2_htonu32(p - 4, bytes); + +done: + + return p + bytes; +} + +/* _libssh2_ecdsa_sign + * + * Computes the ECDSA signature of a previously-hashed message + * + */ + +int +_libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session, + libssh2_ecdsa_ctx *ctx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char **sign, + size_t *sign_len) +{ + size_t r_len, s_len, tmp_sign_len = 0; + unsigned char *sp, *tmp_sign = NULL; + mbedtls_mpi pr, ps; + + mbedtls_mpi_init(&pr); + mbedtls_mpi_init(&ps); + + if(mbedtls_ecdsa_sign(&ctx->grp, &pr, &ps, &ctx->d, + hash, hash_len, + mbedtls_ctr_drbg_random, + &_libssh2_mbedtls_ctr_drbg) != 0) + goto cleanup; + + r_len = mbedtls_mpi_size(&pr) + 1; + s_len = mbedtls_mpi_size(&ps) + 1; + tmp_sign_len = r_len + s_len + 8; + + tmp_sign = LIBSSH2_CALLOC(session, tmp_sign_len); + + if(tmp_sign == NULL) + goto cleanup; + + sp = tmp_sign; + sp = _libssh2_mbedtls_mpi_write_binary(sp, &pr, r_len); + sp = _libssh2_mbedtls_mpi_write_binary(sp, &ps, s_len); + + *sign_len = (size_t)(sp - tmp_sign); + + *sign = LIBSSH2_CALLOC(session, *sign_len); + + if(*sign == NULL) + goto cleanup; + + memcpy(*sign, tmp_sign, *sign_len); + +cleanup: + + mbedtls_mpi_free(&pr); + mbedtls_mpi_free(&ps); + + _libssh2_mbedtls_safe_free(tmp_sign, tmp_sign_len); + + return (*sign == NULL) ? -1 : 0; +} + +/* _libssh2_ecdsa_get_curve_type + * + * returns key curve type that maps to libssh2_curve_type + * + */ + +libssh2_curve_type +_libssh2_mbedtls_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ctx) +{ + return (libssh2_curve_type) ctx->grp.id; +} + +/* _libssh2_ecdsa_curve_type_from_name + * + * returns 0 for success, key curve type that maps to libssh2_curve_type + * + */ + +int +_libssh2_mbedtls_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) + return -1; + + if(strcmp(name, "ecdsa-sha2-nistp256") == 0) + type = LIBSSH2_EC_CURVE_NISTP256; + else if(strcmp(name, "ecdsa-sha2-nistp384") == 0) + type = LIBSSH2_EC_CURVE_NISTP384; + else if(strcmp(name, "ecdsa-sha2-nistp521") == 0) + type = LIBSSH2_EC_CURVE_NISTP521; + else { + ret = -1; + } + + if(ret == 0 && out_type) { + *out_type = type; + } + + return ret; +} + +void +_libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx) +{ + mbedtls_ecdsa_free(ctx); + mbedtls_free(ctx); +} + +#endif /* LIBSSH2_ECDSA */ #endif /* LIBSSH2_MBEDTLS */ diff --git a/src/mbedtls.h b/src/mbedtls.h index 7832c450..671932c5 100644 --- a/src/mbedtls.h +++ b/src/mbedtls.h @@ -45,6 +45,12 @@ #include #include #include +#ifdef MBEDTLS_ECDH_C +# include +#endif +#ifdef MBEDTLS_ECDSA_C +# include +#endif #include #include #include @@ -66,7 +72,11 @@ #define LIBSSH2_RSA 1 #define LIBSSH2_DSA 0 -#define LIBSSH2_ECDSA 0 +#ifdef MBEDTLS_ECDSA_C +# define LIBSSH2_ECDSA 1 +#else +# define LIBSSH2_ECDSA 0 +#endif #define LIBSSH2_ED25519 0 #define MD5_DIGEST_LENGTH 16 @@ -77,10 +87,6 @@ #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) -#if LIBSSH2_ECDSA -#else -#define _libssh2_ec_key void -#endif /*******************************************************************/ /* @@ -210,9 +216,10 @@ #define libssh2_md5(data, datalen, hash) \ _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_MD5, hash) + /*******************************************************************/ /* - * mbedTLS backend: RSA structure + * mbedTLS backend: RSA functions */ #define libssh2_rsa_ctx mbedtls_rsa_context @@ -241,6 +248,82 @@ #define _libssh2_rsa_free(rsactx) \ _libssh2_mbedtls_rsa_free(rsactx) + +/*******************************************************************/ +/* + * mbedTLS backend: ECDSA structures + */ + +#if LIBSSH2_ECDSA + +typedef enum { +#ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED + LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_SECP256R1, +#else + LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_NONE, +#endif +#ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED + LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_SECP384R1, +#else + LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_NONE, +#endif +#ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED + LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_SECP521R1 +#else + LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_NONE, +#endif +} libssh2_curve_type; + +# define _libssh2_ec_key mbedtls_ecp_keypair +#else +# define _libssh2_ec_key void +#endif /* LIBSSH2_ECDSA */ + + +/*******************************************************************/ +/* + * mbedTLS backend: ECDSA functions + */ + +#if LIBSSH2_ECDSA + +#define libssh2_ecdsa_ctx mbedtls_ecdsa_context + +#define _libssh2_ecdsa_create_key(session, privkey, pubkey_octal, \ + pubkey_octal_len, curve) \ + _libssh2_mbedtls_ecdsa_create_key(session, privkey, pubkey_octal, \ + pubkey_octal_len, curve) + +#define _libssh2_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve) \ + _libssh2_mbedtls_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve) + +#define _libssh2_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len) \ + _libssh2_mbedtls_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len) + +#define _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len) \ + _libssh2_mbedtls_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len) + +#define _libssh2_ecdsa_new_private(ctx, session, filename, passphrase) \ + _libssh2_mbedtls_ecdsa_new_private(ctx, session, filename, passphrase) + +#define _libssh2_ecdsa_new_private_frommemory(ctx, session, filedata, \ + filedata_len, passphrase) \ + _libssh2_mbedtls_ecdsa_new_private_frommemory(ctx, session, filedata, \ + filedata_len, passphrase) + +#define _libssh2_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len) \ + _libssh2_mbedtls_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len) + +#define _libssh2_ecdsa_get_curve_type(ctx) \ + _libssh2_mbedtls_ecdsa_get_curve_type(ctx) + +#define _libssh2_ecdsa_free(ctx) \ + _libssh2_mbedtls_ecdsa_free(ctx) + +#endif /* LIBSSH2_ECDSA */ + + +/*******************************************************************/ /* * mbedTLS backend: Key functions */ @@ -253,10 +336,11 @@ 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 @@ -272,6 +356,8 @@ #define _libssh2_cipher_cast5 MBEDTLS_CIPHER_NULL #define _libssh2_cipher_3des MBEDTLS_CIPHER_DES_EDE3_CBC + +/*******************************************************************/ /* * mbedTLS backend: Cipher functions */ @@ -331,6 +417,7 @@ /* * mbedTLS backend: forward declarations */ + void _libssh2_mbedtls_init(void); @@ -436,6 +523,54 @@ _libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session, const char *privatekeydata, size_t privatekeydata_len, const char *passphrase); +#if LIBSSH2_ECDSA +int +_libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session, + _libssh2_ec_key **privkey, + unsigned char **pubkey_octal, + size_t *pubkey_octal_len, + libssh2_curve_type curve); +int +_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx, + const unsigned char *k, + size_t k_len, + libssh2_curve_type curve); +int +_libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k, + _libssh2_ec_key *privkey, + const unsigned char *server_pubkey, + size_t server_pubkey_len); +int +_libssh2_mbedtls_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); +int +_libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx, + LIBSSH2_SESSION *session, + const char *filename, + const unsigned char *passphrase); +int +_libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx, + LIBSSH2_SESSION *session, + const char *filedata, + size_t filedata_len, + const unsigned char *passphrase); +int +_libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session, + libssh2_ecdsa_ctx *ctx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char **signature, + size_t *signature_len); +libssh2_curve_type +_libssh2_mbedtls_ecdsa_key_get_curve_type(libssh2_ecdsa_ctx *ctx); +int +_libssh2_mbedtls_ecdsa_curve_type_from_name(const char *name, + libssh2_curve_type *type); +void +_libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx); +#endif /* LIBSSH2_ECDSA */ extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx); From 7a4b051ba4ccae560c388c3ad08e734c076237ed Mon Sep 17 00:00:00 2001 From: Max Dymond Date: Tue, 1 Sep 2020 22:20:52 +0100 Subject: [PATCH 051/102] Add support for an OSS Fuzzer fuzzing target (#392) Files: .travis.yml, configure.ac, ossfuzz Notes: This adds support for an OSS-Fuzz fuzzing target in ssh2_client_fuzzer, which is a cut down example of ssh2.c. Future enhancements can improve coverage. Credit: Max Dymond --- .travis.yml | 5 ++ configure.ac | 17 ++++++ tests/Makefile.am | 2 + tests/ossfuzz/.gitignore | 2 + tests/ossfuzz/Makefile.am | 32 +++++++++++ tests/ossfuzz/ossfuzz.sh | 30 ++++++++++ tests/ossfuzz/ssh2_client_fuzzer.cc | 87 +++++++++++++++++++++++++++++ tests/ossfuzz/standaloneengine.cc | 74 ++++++++++++++++++++++++ tests/ossfuzz/testinput.h | 3 + tests/ossfuzz/travisoss.sh | 26 +++++++++ 10 files changed, 278 insertions(+) create mode 100644 tests/ossfuzz/.gitignore create mode 100644 tests/ossfuzz/Makefile.am create mode 100755 tests/ossfuzz/ossfuzz.sh create mode 100644 tests/ossfuzz/ssh2_client_fuzzer.cc create mode 100644 tests/ossfuzz/standaloneengine.cc create mode 100644 tests/ossfuzz/testinput.h create mode 100755 tests/ossfuzz/travisoss.sh diff --git a/.travis.yml b/.travis.yml index b13ac4af..64a3c403 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,6 +75,7 @@ env: - ADDRESS_SIZE=32 CRYPTO_BACKEND=mbedTLS BUILD_SHARED_LIBS=ON ENABLE_ZLIB_COMPRESSION=OFF B=cmake - ADDRESS_SIZE=32 CRYPTO_BACKEND=mbedTLS BUILD_SHARED_LIBS=OFF ENABLE_ZLIB_COMPRESSION=ON B=cmake - ADDRESS_SIZE=32 CRYPTO_BACKEND=mbedTLS BUILD_SHARED_LIBS=ON ENABLE_ZLIB_COMPRESSION=ON B=cmake + - B=fuzzer before_install: - if [ $ADDRESS_SIZE = '32' ]; then sudo dpkg --add-architecture i386; fi @@ -118,6 +119,10 @@ script: cd bin cmake $TOOLCHAIN_OPTION -DCRYPTO_BACKEND=$CRYPTO_BACKEND -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DENABLE_ZLIB_COMPRESSION=$ENABLE_ZLIB_COMPRESSION .. && cmake --build . && CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test && cmake --build . --target package fi + - | + if [ "$B" = "fuzzer" ]; then + ./tests/ossfuzz/travisoss.sh + fi # whitelist branches to avoid testing feature branches twice (as branch and as pull request) branches: diff --git a/configure.ac b/configure.ac index 1f60c144..c9696ecc 100644 --- a/configure.ac +++ b/configure.ac @@ -69,6 +69,7 @@ AC_SEARCH_LIBS(inet_addr, nsl) AC_SUBST(LIBS) AC_PROG_CC +AC_PROG_CXX AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET @@ -284,6 +285,21 @@ esac], [build_examples='yes']) AC_MSG_RESULT($build_examples) AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"]) + +# Build OSS fuzzing targets? +AC_ARG_ENABLE([ossfuzzers], + [AS_HELP_STRING([--enable-ossfuzzers], + [Whether to generate the fuzzers for OSS-Fuzz])], + [have_ossfuzzers=yes], [have_ossfuzzers=no]) +AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$have_ossfuzzers" = "xyes"]) + + +# Set the correct flags for the given fuzzing engine. +AC_SUBST([LIB_FUZZING_ENGINE]) +AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"]) +AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "$LIB_FUZZING_ENGINE"]) + + # Checks for header files. # AC_HEADER_STDC AC_CHECK_HEADERS([errno.h fcntl.h stdio.h stdlib.h unistd.h sys/uio.h]) @@ -373,6 +389,7 @@ LIBSSH2_CHECK_OPTION_WERROR AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile + tests/ossfuzz/Makefile example/Makefile docs/Makefile libssh2.pc]) diff --git a/tests/Makefile.am b/tests/Makefile.am index dc0922f2..3272a985 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = ossfuzz + AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include -I$(top_builddir)/src LDADD = ../src/libssh2.la diff --git a/tests/ossfuzz/.gitignore b/tests/ossfuzz/.gitignore new file mode 100644 index 00000000..cf4f8c0b --- /dev/null +++ b/tests/ossfuzz/.gitignore @@ -0,0 +1,2 @@ +*.a +ssh2_client_fuzzer diff --git a/tests/ossfuzz/Makefile.am b/tests/ossfuzz/Makefile.am new file mode 100644 index 00000000..a7e95825 --- /dev/null +++ b/tests/ossfuzz/Makefile.am @@ -0,0 +1,32 @@ +AM_CPPFLAGS = -I$(top_builddir)/include +LDADD = $(top_builddir)/src/libssh2.la + +if USE_OSSFUZZ_FLAG +FUZZ_FLAG = $(LIB_FUZZING_ENGINE) +else +if USE_OSSFUZZ_STATIC +LDADD += $(LIB_FUZZING_ENGINE) +FUZZ_FLAG = +else +LDADD += libstandaloneengine.a +FUZZ_FLAG = +endif +endif + +noinst_PROGRAMS = +noinst_LIBRARIES = + +if USE_OSSFUZZERS +noinst_PROGRAMS += \ + ssh2_client_fuzzer + +noinst_LIBRARIES += \ + libstandaloneengine.a +endif + +ssh2_client_fuzzer_SOURCES = ssh2_client_fuzzer.cc testinput.h +ssh2_client_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG) +ssh2_client_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static + +libstandaloneengine_a_SOURCES = standaloneengine.cc +libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS) diff --git a/tests/ossfuzz/ossfuzz.sh b/tests/ossfuzz/ossfuzz.sh new file mode 100755 index 00000000..4ea60a2a --- /dev/null +++ b/tests/ossfuzz/ossfuzz.sh @@ -0,0 +1,30 @@ +#!/bin/bash -eu + +# This script is called by the oss-fuzz main project when compiling the fuzz +# targets. This script is regression tested by travisoss.sh. + +# Save off the current folder as the build root. +export BUILD_ROOT=$PWD + +echo "CC: $CC" +echo "CXX: $CXX" +echo "LIB_FUZZING_ENGINE: $LIB_FUZZING_ENGINE" +echo "CFLAGS: $CFLAGS" +echo "CXXFLAGS: $CXXFLAGS" +echo "OUT: $OUT" + +export MAKEFLAGS+="-j$(nproc)" + +# Install dependencies +apt-get -y install automake libtool libssl-dev zlib1g-dev + +# Compile the fuzzer. +./buildconf +./configure --disable-shared \ + --enable-ossfuzzers \ + --disable-examples-build \ + --enable-debug +make V=1 + +# Copy the fuzzer to the output directory. +cp -v tests/ossfuzz/ssh2_client_fuzzer $OUT/ diff --git a/tests/ossfuzz/ssh2_client_fuzzer.cc b/tests/ossfuzz/ssh2_client_fuzzer.cc new file mode 100644 index 00000000..1988878e --- /dev/null +++ b/tests/ossfuzz/ssh2_client_fuzzer.cc @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "testinput.h" + +#define FUZZ_ASSERT(COND) \ + if(!(COND)) \ + { \ + fprintf(stderr, "Assertion failed: " #COND "\n%s", \ + strerror(errno)); \ + assert((COND)); \ + } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + int socket_fds[2] = {-1, -1}; + ssize_t written; + int rc; + LIBSSH2_SESSION *session = NULL; + int handshake_completed = 0; + + rc = libssh2_init(0); + + if(rc != 0) { + fprintf(stderr, "libssh2 initialization failed (%d)\n", rc); + goto EXIT_LABEL; + } + + // Create a socket pair so data can be sent in. + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds); + FUZZ_ASSERT(rc == 0); + + written = send(socket_fds[1], data, size, 0); + + if (written != size) + { + // Handle whatever error case we're in. + fprintf(stderr, "send() of %zu bytes returned %zu (%d)\n", + size, + written, + errno); + goto EXIT_LABEL; + } + + rc = shutdown(socket_fds[1], SHUT_WR); + if (rc != 0) + { + fprintf(stderr, "socket shutdown failed (%d)\n", rc); + goto EXIT_LABEL; + } + + // Create a session and start the handshake using the fuzz data passed in. + session = libssh2_session_init(); + + if(libssh2_session_handshake(session, socket_fds[0])) { + goto EXIT_LABEL; + } + + // If we get here the handshake actually completed. + handshake_completed = 1; + +EXIT_LABEL: + + if (session != NULL) + { + if (handshake_completed) + { + libssh2_session_disconnect(session, + "Normal Shutdown, Thank you for playing"); + } + + libssh2_session_free(session); + } + + libssh2_exit(); + + close(socket_fds[0]); + close(socket_fds[1]); + + return 0; +} \ No newline at end of file diff --git a/tests/ossfuzz/standaloneengine.cc b/tests/ossfuzz/standaloneengine.cc new file mode 100644 index 00000000..175360e4 --- /dev/null +++ b/tests/ossfuzz/standaloneengine.cc @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "testinput.h" + +/** + * Main procedure for standalone fuzzing engine. + * + * Reads filenames from the argument array. For each filename, read the file + * into memory and then call the fuzzing interface with the data. + */ +int main(int argc, char **argv) +{ + int ii; + for(ii = 1; ii < argc; ii++) + { + FILE *infile; + printf("[%s] ", argv[ii]); + + /* Try and open the file. */ + infile = fopen(argv[ii], "rb"); + if(infile) + { + uint8_t *buffer = NULL; + size_t buffer_len; + + printf("Opened.. "); + + /* Get the length of the file. */ + fseek(infile, 0L, SEEK_END); + buffer_len = ftell(infile); + + /* Reset the file indicator to the beginning of the file. */ + fseek(infile, 0L, SEEK_SET); + + /* Allocate a buffer for the file contents. */ + buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t)); + if(buffer) + { + /* Read all the text from the file into the buffer. */ + fread(buffer, sizeof(uint8_t), buffer_len, infile); + printf("Read %zu bytes, fuzzing.. ", buffer_len); + + /* Call the fuzzer with the data. */ + LLVMFuzzerTestOneInput(buffer, buffer_len); + + printf("complete !!"); + + /* Free the buffer as it's no longer needed. */ + free(buffer); + buffer = NULL; + } + else + { + fprintf(stderr, + "[%s] Failed to allocate %zu bytes \n", + argv[ii], + buffer_len); + } + + /* Close the file as it's no longer needed. */ + fclose(infile); + infile = NULL; + } + else + { + /* Failed to open the file. Maybe wrong name or wrong permissions? */ + fprintf(stderr, "[%s] Open failed. \n", argv[ii]); + } + + printf("\n"); + } +} diff --git a/tests/ossfuzz/testinput.h b/tests/ossfuzz/testinput.h new file mode 100644 index 00000000..6ab9b515 --- /dev/null +++ b/tests/ossfuzz/testinput.h @@ -0,0 +1,3 @@ +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); diff --git a/tests/ossfuzz/travisoss.sh b/tests/ossfuzz/travisoss.sh new file mode 100755 index 00000000..486cd6fd --- /dev/null +++ b/tests/ossfuzz/travisoss.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -ex + +PROJECT_NAME=libssh2 + +# Clone the oss-fuzz repository +git clone https://github.com/google/oss-fuzz.git /tmp/ossfuzz + +if [[ ! -d /tmp/ossfuzz/projects/${PROJECT_NAME} ]] +then + echo "Could not find the ${PROJECT_NAME} project in ossfuzz" + + # Exit with a success code while the libssh2 project is not expected to exist + # on oss-fuzz. + exit 0 +fi + +# Modify the oss-fuzz Dockerfile so that we're checking out the current branch on travis. +sed -i "s@https://github.com/libssh2/libssh2.git@-b $TRAVIS_BRANCH https://github.com/libssh2/libssh2.git@" /tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile + +# Try and build the fuzzers +pushd /tmp/ossfuzz +python infra/helper.py build_image --pull ${PROJECT_NAME} +python infra/helper.py build_fuzzers ${PROJECT_NAME} +popd From ecd6a74e44562797a1e92186ad4a402c5641720e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 2 Sep 2020 01:40:48 +0200 Subject: [PATCH 052/102] Makefile.am: include all test files in the dist #379 File: Makefile.am Notes: No longer conditionally include OpenSSL specific test files, they aren't run if we're not building against OpenSSL 1.1.x anyway. Credit: Daniel Stenberg --- tests/Makefile.am | 65 ++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 3272a985..d210ad63 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -18,26 +18,45 @@ check_PROGRAMS = $(ctests) TESTS_ENVIRONMENT = SSHD=$(SSHD) EXEEXT=$(EXEEXT) TESTS_ENVIRONMENT += srcdir=$(top_srcdir)/tests builddir=$(top_builddir)/tests -EXTRA_DIST = ssh2.sh mansyntax.sh -EXTRA_DIST += etc/host etc/host.pub etc/user etc/user.pub -EXTRA_DIST += CMakeLists.txt libssh2_config_cmake.h.in sshd_fixture.sh.in -EXTRA_DIST += key_dsa key_dsa.pub key_dsa_wrong key_dsa_wrong.pub key_rsa key_rsa.pub -EXTRA_DIST += openssh_server/authorized_keys openssh_server/Dockerfile openssh_server/ssh_host_rsa_key -EXTRA_DIST += openssh_fixture.c openssh_fixture.h runner.c session_fixture.c session_fixture.h -EXTRA_DIST += test_hostkey.c test_hostkey_hash.c -EXTRA_DIST += test_keyboard_interactive_auth_fails_with_wrong_response.c -EXTRA_DIST += test_keyboard_interactive_auth_succeeds_with_correct_response.c -EXTRA_DIST += test_password_auth_fails_with_wrong_password.c -EXTRA_DIST += test_password_auth_fails_with_wrong_username.c -EXTRA_DIST += test_password_auth_succeeds_with_correct_credentials.c -EXTRA_DIST += test_public_key_auth_fails_with_wrong_key.c -EXTRA_DIST += test_public_key_auth_succeeds_with_correct_dsa_key.c -EXTRA_DIST += test_public_key_auth_succeeds_with_correct_rsa_key.c -EXTRA_DIST += test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c -if OPENSSL -# TODO: need to add a test for specific openssl version some how -# EXTRA_DIST += test_public_key_auth_succeeds_with_correct_ed25519_key.c -# EXTRA_DIST += test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c -# EXTRA_DIST += test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c -EXTRA_DIST += test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c -endif \ No newline at end of file +EXTRA_DIST = \ + CMakeLists.txt \ + etc/host \ + etc/host.pub \ + etc/user \ + etc/user.pub \ + key_dsa \ + key_dsa.pub \ + key_dsa_wrong \ + key_dsa_wrong.pub \ + key_rsa \ + key_rsa.pub \ + libssh2_config_cmake.h.in \ + mansyntax.sh \ + openssh_fixture.c \ + openssh_fixture.h \ + openssh_server/authorized_keys \ + openssh_server/Dockerfile \ + openssh_server/ssh_host_rsa_key \ + runner.c \ + session_fixture.c \ + session_fixture.h \ + simple.c \ + ssh2.c \ + ssh2.sh \ + sshd_fixture.sh.in \ + test_agent_forward_succeeds.c \ + test_hostkey.c \ + test_hostkey_hash.c \ + test_keyboard_interactive_auth_fails_with_wrong_response.c \ + test_keyboard_interactive_auth_succeeds_with_correct_response.c \ + test_password_auth_fails_with_wrong_password.c \ + test_password_auth_fails_with_wrong_username.c \ + test_password_auth_succeeds_with_correct_credentials.c \ + test_public_key_auth_fails_with_wrong_key.c \ + test_public_key_auth_succeeds_with_correct_dsa_key.c \ + test_public_key_auth_succeeds_with_correct_ed25519_key.c \ + test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c \ + test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c \ + test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c \ + test_public_key_auth_succeeds_with_correct_rsa_key.c \ + test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c From 9ae9ff30cbefd84f20c9dc47ac476d32b31a717d Mon Sep 17 00:00:00 2001 From: Igor Klevanets <8238332+cerevra@users.noreply.github.com> Date: Wed, 23 Sep 2020 23:15:01 +0300 Subject: [PATCH 053/102] agent.c: Recv and send all bytes via network in agent_transact_unix() (#510) Files: agent.c Notes: Handle sending/receiving partial packet replies in agent.c API. Credit: Klevanets Igor --- src/agent.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/agent.c b/src/agent.c index c9efe304..7ce39707 100644 --- a/src/agent.c +++ b/src/agent.c @@ -175,6 +175,40 @@ agent_connect_unix(LIBSSH2_AGENT *agent) return LIBSSH2_ERROR_NONE; } +#define RECV_SEND_ALL(func, socket, buffer, length, flags, abstract) \ + int rc; \ + size_t finished; \ + \ + finished = 0; \ + \ + while(finished < length) { \ + rc = func(socket, \ + (char *)buffer + finished, length - finished, \ + flags, abstract); \ + if(rc < 0) \ + return rc; \ + \ + finished += rc; \ + } \ + \ + return finished; + +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) { @@ -184,7 +218,8 @@ 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); + rc = _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 +230,8 @@ 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 = _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 +242,8 @@ 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 = _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 +261,8 @@ 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 = _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; From f553dcc95ddd9683ac572dd8aa66ba877f6be39d Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 23 Sep 2020 13:20:00 -0700 Subject: [PATCH 054/102] kex.c: group16-sha512 and group18-sha512 support #457 (#468) Files: kex.c Notes: Added key exchange group16-sha512 and group18-sha512. As a result did the following: Abstracted diffie_hellman_sha256() to diffie_hellman_sha_algo() which is now algorithm agnostic and takes the algorithm as a parameter since we needed sha512 support. Unfortunately it required some helper functions but they are simple. Deleted diffie_hellman_sha1() Deleted diffie_hellman_sha1 specific macro Cleaned up some formatting Defined sha384 in os400 and wincng backends Defined LIBSSH2_DH_MAX_MODULUS_BITS to abort the connection if we receive too large of p from the server doing sha1 key exchange. Reorder the default key exchange list to match OpenSSH and improve security Credit: Will Cosgrove --- include/libssh2.h | 2 + src/kex.c | 1391 +++++++++++++++++---------------------------- src/os400qc3.h | 10 + src/wincng.c | 19 + src/wincng.h | 15 +- 5 files changed, 575 insertions(+), 862 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index d7e87b1f..4931a2af 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -239,6 +239,8 @@ typedef off_t libssh2_struct_stat_size; #define LIBSSH2_DH_GEX_OPTGROUP 4096 #define LIBSSH2_DH_GEX_MAXGROUP 8192 +#define LIBSSH2_DH_MAX_MODULUS_BITS 16384 + /* Defaults for pty requests */ #define LIBSSH2_TERM_WIDTH 80 #define LIBSSH2_TERM_HEIGHT 24 diff --git a/src/kex.c b/src/kex.c index 2122c7b5..cc871e75 100644 --- a/src/kex.c +++ b/src/kex.c @@ -42,792 +42,202 @@ #include "comp.h" #include "mac.h" +#include + +/* 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) \ + { \ + 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, \ +#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, \ 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; \ - } \ + } \ + libssh2_sha##digest_type##_final(hash, (value) + len); \ + len += SHA##digest_type##_DIGEST_LENGTH; \ + } \ } - -/* - * diffie_hellman_sha1 - * - * Diffie Hellman Key Exchange, Group Agnostic +/*! + * @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) + +static void _libssh2_sha_algo_ctx_init(int sha_algo, void *ctx) { - 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; + if(sha_algo == 512) { + 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) { + 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) { + libssh2_sha256_init((libssh2_sha256_ctx*)ctx); } + else if(sha_algo == 1) { + 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; - } - } -#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; - - 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; - } - } -#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); +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 { +#if LIBSSH2DEBUG + 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_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); } - - 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_sha384_ctx *_ctx = (libssh2_sha384_ctx*)ctx; + libssh2_sha384_final(*_ctx, hash); } - - 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_sha256_ctx *_ctx = (libssh2_sha256_ctx*)ctx; + libssh2_sha256_final(*_ctx, hash); } - - if(exchange_state->s_packet) { - LIBSSH2_FREE(session, exchange_state->s_packet); - exchange_state->s_packet = NULL; + else if(sha_algo == 1) { + libssh2_sha1_ctx *_ctx = (libssh2_sha1_ctx*)ctx; + libssh2_sha1_final(*_ctx, hash); } - - if(exchange_state->k_value) { - LIBSSH2_FREE(session, exchange_state->k_value); - exchange_state->k_value = NULL; + else { +#if LIBSSH2DEBUG + assert(0); +#endif } +} - exchange_state->state = libssh2_NB_state_idle; - - return ret; +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); + } + else if(sha_algo == 384) { + LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(384, *data, data_len, version); + } + else if(sha_algo == 256) { + LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(256, *data, data_len, version); + } + else if(sha_algo == 1) { + LIBSSH2_KEX_METHOD_SHA_VALUE_HASH(1, *data, data_len, version); + } + else { +#if LIBSSH2DEBUG + assert(0); +#endif + } } -/* - * 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, + unsigned long 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,6 +256,12 @@ 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) @@ -1059,6 +475,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, } #endif /* LIBSSH2DEBUG */ + if(session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, &session->server_hostkey_abstract)) { @@ -1110,59 +527,59 @@ 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); + _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)); + _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); + _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); + _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 */ @@ -1173,52 +590,49 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, 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); + _libssh2_sha_algo_ctx_update(sha_algo_value, 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); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->h_sig_comp, 4); #endif } 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_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_sha256_update(exchange_hash_ctx, - exchange_state->k_value, - exchange_state->k_value_len); + _libssh2_sha_algo_ctx_update(sha_algo_value, exchange_hash_ctx, + exchange_state->k_value, + exchange_state->k_value_len); - libssh2_sha256_final(exchange_hash_ctx, - exchange_state->h_sig_comp); + _libssh2_sha_algo_ctx_final(sha_algo_value, 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)) { + digest_len, &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; @@ -1261,7 +675,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session, 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,8 +683,8 @@ 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; + digest_len); + session->session_id_len = digest_len; _libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated"); } @@ -1286,18 +700,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; @@ -1336,18 +752,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; @@ -1384,10 +800,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; @@ -1411,10 +827,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; @@ -1526,6 +942,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 */ @@ -1542,9 +959,11 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, 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,7 +978,6 @@ kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, } - /* kex_method_diffie_hellman_group14_key_exchange * Diffie-Hellman Group14 Key Exchange with hash function callback */ @@ -1567,6 +985,8 @@ typedef int (*diffie_hellman_hash_func_t)(LIBSSH2_SESSION *, _libssh2_bn *, _libssh2_bn *, int, + int, + void *, unsigned char, unsigned char, unsigned char *, @@ -1576,6 +996,8 @@ static int 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) { @@ -1631,8 +1053,8 @@ kex_method_diffie_hellman_group14_key_exchange(LIBSSH2_SESSION *session, key_state->state = libssh2_NB_state_created; } ret = hashfunc(session, key_state->g, key_state->p, - 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, - NULL, 0, &key_state->exchange_state); + 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; } @@ -1656,8 +1078,11 @@ kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, key_exchange_state_low_t * key_state) { - return kex_method_diffie_hellman_group14_key_exchange(session, key_state, - diffie_hellman_sha1); + libssh2_sha1_ctx ctx; + return kex_method_diffie_hellman_group14_key_exchange(session, + key_state, 1, + &ctx, + diffie_hellman_sha_algo); } @@ -1670,11 +1095,235 @@ kex_method_diffie_hellman_group14_sha256_key_exchange(LIBSSH2_SESSION *session, key_exchange_state_low_t * key_state) { - return kex_method_diffie_hellman_group14_key_exchange(session, key_state, - diffie_hellman_sha256); + 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_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; + } + + 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_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 @@ -1747,6 +1396,7 @@ 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, @@ -1775,12 +1425,14 @@ kex_method_diffie_hellman_group_exchange_sha1_key_exchange _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, + 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; } @@ -1872,6 +1524,7 @@ 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, @@ -1900,12 +1553,14 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange _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, + 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; } @@ -3308,6 +2963,18 @@ static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha256 = { 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", @@ -3361,21 +3028,23 @@ kex_method_ssh_curve25519_sha256 = { #endif 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_group14_sha256, &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, - NULL + &kex_method_diffie_helman_group_exchange_sha1, + NULL }; typedef struct _LIBSSH2_COMMON_METHOD diff --git a/src/os400qc3.h b/src/os400qc3.h index d915dc2c..f0d2ea50 100644 --- a/src/os400qc3.h +++ b/src/os400qc3.h @@ -182,6 +182,7 @@ #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) @@ -233,6 +234,7 @@ typedef struct { /* Diffie-Hellman context. */ #define libssh2_sha1_ctx Qc3_Format_ALGD0100_T #define libssh2_sha256_ctx Qc3_Format_ALGD0100_T +#define libssh2_sha384_ctx Qc3_Format_ALGD0100_T #define libssh2_sha512_ctx Qc3_Format_ALGD0100_T #define libssh2_md5_ctx Qc3_Format_ALGD0100_T #define libssh2_hmac_ctx _libssh2_os400qc3_crypto_ctx @@ -251,6 +253,14 @@ typedef struct { /* Diffie-Hellman context. */ #define libssh2_sha256(message, len, out) \ libssh2_os400qc3_hash(message, len, out, \ Qc3_SHA256) +#define libssh2_sha384_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA384) +#define libssh2_sha384_update(ctx, data, len) \ + libssh2_os400qc3_hash_update(&(ctx), data, len) +#define libssh2_sha384_final(ctx, out) \ + libssh2_os400qc3_hash_final(&(ctx), out) +#define libssh2_sha384(message, len, out) \ + libssh2_os400qc3_hash(message, len, out, \ + Qc3_SHA384) #define libssh2_sha512_init(x) libssh2_os400qc3_hash_init(x, Qc3_SHA512) #define libssh2_sha512_update(ctx, data, len) \ libssh2_os400qc3_hash_update(&(ctx), data, len) diff --git a/src/wincng.c b/src/wincng.c index 88c82ca2..7cd7f03b 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -99,6 +99,10 @@ #define BCRYPT_SHA256_ALGORITHM L"SHA256" #endif +#ifndef BCRYPT_SHA384_ALGORITHM +#define BCRYPT_SHA384_ALGORITHM L"SHA384" +#endif + #ifndef BCRYPT_SHA512_ALGORITHM #define BCRYPT_SHA512_ALGORITHM L"SHA512" #endif @@ -248,6 +252,11 @@ _libssh2_wincng_init(void) if(!BCRYPT_SUCCESS(ret)) { _libssh2_wincng.hAlgHashSHA256 = NULL; } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA384, + BCRYPT_SHA384_ALGORITHM, NULL, 0); + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHashSHA384 = NULL; + } ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512, BCRYPT_SHA512_ALGORITHM, NULL, 0); if(!BCRYPT_SUCCESS(ret)) { @@ -272,6 +281,12 @@ _libssh2_wincng_init(void) if(!BCRYPT_SUCCESS(ret)) { _libssh2_wincng.hAlgHmacSHA256 = NULL; } + ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA384, + BCRYPT_SHA384_ALGORITHM, NULL, + BCRYPT_ALG_HANDLE_HMAC_FLAG); + if(!BCRYPT_SUCCESS(ret)) { + _libssh2_wincng.hAlgHmacSHA384 = NULL; + } ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512, BCRYPT_SHA512_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG); @@ -369,6 +384,8 @@ _libssh2_wincng_free(void) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0); if(_libssh2_wincng.hAlgHashSHA256) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0); + if(_libssh2_wincng.hAlgHashSHA384) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA384, 0); if(_libssh2_wincng.hAlgHashSHA512) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0); if(_libssh2_wincng.hAlgHmacMD5) @@ -377,6 +394,8 @@ _libssh2_wincng_free(void) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0); if(_libssh2_wincng.hAlgHmacSHA256) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0); + if(_libssh2_wincng.hAlgHmacSHA384) + (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA384, 0); if(_libssh2_wincng.hAlgHmacSHA512) (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0); if(_libssh2_wincng.hAlgRSA) diff --git a/src/wincng.h b/src/wincng.h index 43ee974f..eaf6f905 100755 --- a/src/wincng.h +++ b/src/wincng.h @@ -70,6 +70,7 @@ #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) @@ -89,10 +90,12 @@ struct _libssh2_wincng_ctx { BCRYPT_ALG_HANDLE hAlgHashMD5; BCRYPT_ALG_HANDLE hAlgHashSHA1; BCRYPT_ALG_HANDLE hAlgHashSHA256; + BCRYPT_ALG_HANDLE hAlgHashSHA384; BCRYPT_ALG_HANDLE hAlgHashSHA512; BCRYPT_ALG_HANDLE hAlgHmacMD5; BCRYPT_ALG_HANDLE hAlgHmacSHA1; BCRYPT_ALG_HANDLE hAlgHmacSHA256; + BCRYPT_ALG_HANDLE hAlgHmacSHA384; BCRYPT_ALG_HANDLE hAlgHmacSHA512; BCRYPT_ALG_HANDLE hAlgRSA; BCRYPT_ALG_HANDLE hAlgDSA; @@ -165,7 +168,17 @@ typedef struct __libssh2_wincng_hash_ctx { #define libssh2_sha256(data, datalen, hash) \ _libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA256, \ hash, SHA256_DIGEST_LENGTH) - +#define libssh2_sha384_ctx _libssh2_wincng_hash_ctx +#define libssh2_sha384_init(ctx) \ + (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA384, \ + SHA384_DIGEST_LENGTH, NULL, 0) == 0) +#define libssh2_sha384_update(ctx, data, datalen) \ + _libssh2_wincng_hash_update(&ctx, (unsigned char *) data, datalen) +#define libssh2_sha384_final(ctx, hash) \ + _libssh2_wincng_hash_final(&ctx, hash) +#define libssh2_sha384(data, datalen, hash) \ +_libssh2_wincng_hash(data, datalen, _libssh2_wincng.hAlgHashSHA384, \ + hash, SHA384_DIGEST_LENGTH) #define libssh2_sha512_ctx _libssh2_wincng_hash_ctx #define libssh2_sha512_init(ctx) \ (_libssh2_wincng_hash_init(ctx, _libssh2_wincng.hAlgHashSHA512, \ From a1975c5b594a25b4c6c8ddf37330b693ef5e109c Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 23 Sep 2020 13:21:11 -0700 Subject: [PATCH 055/102] CMakeLists.txt: respect install lib dir #405 (#515) Files: CMakeLists.txt Notes: Use CMAKE_INSTALL_LIBDIR directory Credit: Arfrever --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 74b04233..fa0812be 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -397,7 +397,7 @@ 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 @@ -429,4 +429,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) From 00d5b0c385c42f5f46f8d3012a18a6b222fb2670 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 23 Sep 2020 13:41:34 -0700 Subject: [PATCH 056/102] agent.c: formatting Improved formatting of RECV_SEND_ALL macro. --- src/agent.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/agent.c b/src/agent.c index 7ce39707..3fbf310d 100644 --- a/src/agent.c +++ b/src/agent.c @@ -176,21 +176,19 @@ agent_connect_unix(LIBSSH2_AGENT *agent) } #define RECV_SEND_ALL(func, socket, buffer, length, flags, abstract) \ - int rc; \ - size_t finished; \ - \ - finished = 0; \ - \ - while(finished < length) { \ - rc = func(socket, \ - (char *)buffer + finished, length - finished, \ - flags, abstract); \ - if(rc < 0) \ - return rc; \ - \ - finished += rc; \ - } \ - \ + int rc; \ + size_t finished = 0; \ + \ + while(finished < length) { \ + rc = func(socket, \ + (char *)buffer + finished, length - finished, \ + flags, abstract); \ + if(rc < 0) \ + return rc; \ + \ + finished += rc; \ + } \ + \ return finished; static ssize_t _send_all(LIBSSH2_SEND_FUNC(func), libssh2_socket_t socket, From 4afcb8cd9bc883e527d7d07f45cb12ea83186461 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 28 Sep 2020 15:53:29 +0200 Subject: [PATCH 057/102] libssh2_session_callback_set.3: explain the recv/send callbacks Describe how to actually use these callbacks. Closes #518 --- docs/libssh2_session_callback_set.3 | 40 ++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/libssh2_session_callback_set.3 b/docs/libssh2_session_callback_set.3 index 3901f884..6a075cbf 100644 --- a/docs/libssh2_session_callback_set.3 +++ b/docs/libssh2_session_callback_set.3 @@ -32,11 +32,43 @@ function returns 0, the packet will be accepted nonetheless. .IP LIBSSH2_CALLBACK_X11 Called when an X11 connection has been accepted .IP LIBSSH2_CALLBACK_SEND -Called when libssh2 wants to send some data on the connection. -Can be set to a custom function to handle I/O your own way. +Called when libssh2 wants to send data on the connection. Can be set to a +custom function to handle I/O your own way. + +The prototype of the callback: + +.nf +ssize_t sendcb(libssh2_socket_t sockfd, const void *buffer, + size_t length, int flags, void **abstract); +.fi + +\fBsockfd\fP is the socket to write to, \fBbuffer\fP points to the data to +send, \fBlength\fP is the size of the data, \fBflags\fP is the flags that +would've been used to a \fIsend()\fP call and \fBabstract\fP is a pointer to +the abstract pointer set in the \fIlibssh2_session_init_ex(3)\fP call. + +The callback returns the number of bytes sent, or -1 for error. The special +return code \fB-EAGAIN\fP can be returned to signal that the send was aborted +to prevent getting blocked and it needs to be called again. .IP LIBSSH2_CALLBACK_RECV -Called when libssh2 wants to receive some data from the connection. -Can be set to a custom function to handle I/O your own way. +Called when libssh2 wants to read data from the connection. Can be set to a +custom function to handle I/O your own way. + +The prototype of the callback: + +.nf +ssize_t recvcb(libssh2_socket_t sockfd, void *buffer, + size_t length, int flags, void **abstract); +.fi + +\fBsockfd\fP is the socket to read from, \fBbuffer\fP where to store received +data into, \fBlength\fP is the size of the buffer, \fBflags\fP is the flags +that would've been used to a \fIrecv()\fP call and \fBabstract\fP is a pointer +to the abstract pointer set in the \fIlibssh2_session_init_ex(3)\fP call. + +The callback returns the number of bytes read, or -1 for error. The special +return code \fB-EAGAIN\fP can be returned to signal that the read was aborted +to prevent getting blocked and it needs to be called again. .SH RETURN VALUE Pointer to previous callback handler. Returns NULL if no prior callback handler was set or the callback type was unknown. From 6c7769dcc422250d14af1b06fce378b6ee009440 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Sun, 14 Jun 2020 20:12:47 +0200 Subject: [PATCH 058/102] wincng: fix random big number generation to match openssl The old function would set the least significant bits in the most significant byte instead of the most significant bits. The old function would also zero pad too much bits in the most significant byte. This lead to a reduction of key space in the most significant byte according to the following listing: - 8 bits reduced to 0 bits => eg. 2048 bits to 2040 bits DH key - 7 bits reduced to 1 bits => eg. 2047 bits to 2041 bits DH key - 6 bits reduced to 2 bits => eg. 2046 bits to 2042 bits DH key - 5 bits reduced to 3 bits => eg. 2045 bits to 2043 bits DH key No change would occur for the case of 4 significant bits. For 1 to 3 significant bits in the most significant byte the DH key would actually be expanded instead of reduced: - 3 bits expanded to 5 bits => eg. 2043 bits to 2045 bits DH key - 2 bits expanded to 6 bits => eg. 2042 bits to 2046 bits DH key - 1 bits expanded to 7 bits => eg. 2041 bits to 2047 bits DH key There is no case of 0 significant bits in the most significant byte since this would be a case of 8 significant bits in the next byte. At the moment only the following case applies due to a fixed DH key size value currently being used in libssh2: The DH group_order is fixed to 256 (bytes) which leads to a 2047 bits DH key size by calculating (256 * 8) - 1. This means the DH keyspace was previously reduced from 2047 bits to 2041 bits (while the top and bottom bits are always set), so the keyspace is actually always reduced from 2045 bits to 2039 bits. All of this is only relevant for Windows versions supporting the WinCNG backend (Vista or newer) before Windows 10 version 1903. Closes #521 --- src/wincng.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wincng.c b/src/wincng.c index 7cd7f03b..cbb2b61c 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -2044,15 +2044,17 @@ _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) /* calculate significant bits in most significant byte */ bits %= 8; + if(bits == 0) + bits = 8; /* fill most significant byte with zero padding */ - bignum[0] &= (1 << (8 - bits)) - 1; + bignum[0] &= ((1 << bits) - 1); - /* set some special last bits in most significant byte */ + /* set most significant bits in most significant byte */ if(top == 0) - bignum[0] |= (1 << (7 - bits)); + bignum[0] |= (1 << (bits - 1)); else if(top == 1) - bignum[0] |= (3 << (6 - bits)); + bignum[0] |= (3 << (bits - 2)); /* make odd by setting first bit in least significant byte */ if(bottom) From cfe0bf64985fd6a5db3b45ffc31a2fe3b8fd9948 Mon Sep 17 00:00:00 2001 From: Tseng Jun <6501202@qq.com> Date: Thu, 12 Nov 2020 03:18:36 +0800 Subject: [PATCH 059/102] session.c: Correct a typo which may lead to stack overflow (#533) File: session.c Notes: Seems the author intend to terminate banner_dup buffer, later, print it to the debug console. Author: Tseng Jun --- src/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/session.c b/src/session.c index 256eb999..212560b8 100644 --- a/src/session.c +++ b/src/session.c @@ -219,7 +219,7 @@ banner_send(LIBSSH2_SESSION * session) } else { memcpy(banner_dup, banner, 255); - banner[255] = '\0'; + banner_dup[255] = '\0'; } _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s", From 720998f322f4bffffe531d5ec6a240c8c18459b2 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Sat, 19 Dec 2020 04:58:29 +1100 Subject: [PATCH 060/102] kex.c: fix simple typo, niumber -> number (#545) File: kex.c Notes: There is a small typo in src/kex.c. Should read `number` rather than `niumber`. Credit: Tim Gates --- src/kex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kex.c b/src/kex.c index cc871e75..99a4a947 100644 --- a/src/kex.c +++ b/src/kex.c @@ -4069,7 +4069,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 From 1f76151c92e1b52e9c24ebf06adc77fbd6c062bc Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Tue, 26 Jan 2021 11:41:21 -0800 Subject: [PATCH 061/102] kex.c: move EC macro outside of if check #549 (#550) File: kex.c Notes: Moved the macro LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY outside of the LIBSSH2_ECDSA since it's also now used by the ED25519 code. Sha 256, 384 and 512 need to be defined for all backends now even if they aren't used directly. I believe this is already the case, but just a heads up. Credit: Stefan-Ghinea --- src/kex.c | 66 +++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/kex.c b/src/kex.c index 99a4a947..2b29f7ec 100644 --- a/src/kex.c +++ b/src/kex.c @@ -1579,39 +1579,6 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange } -#if LIBSSH2_ECDSA - -/* kex_session_ecdh_curve_type - * returns the EC curve type by name used in 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) - return -1; - - if(strcmp(name, "ecdh-sha2-nistp256") == 0) - type = LIBSSH2_EC_CURVE_NISTP256; - else if(strcmp(name, "ecdh-sha2-nistp384") == 0) - type = LIBSSH2_EC_CURVE_NISTP384; - else if(strcmp(name, "ecdh-sha2-nistp521") == 0) - type = LIBSSH2_EC_CURVE_NISTP521; - else { - ret = -1; - } - - if(ret == 0 && out_type) { - *out_type = type; - } - - return ret; -} - - /* LIBSSH2_KEX_METHOD_EC_SHA_HASH_CREATE_VERIFY * * Macro that create and verifies EC SHA hash with a given digest bytes @@ -1721,6 +1688,39 @@ kex_session_ecdh_curve_type(const char *name, libssh2_curve_type *out_type) } \ +#if LIBSSH2_ECDSA + +/* kex_session_ecdh_curve_type + * returns the EC curve type by name used in 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) + return -1; + + if(strcmp(name, "ecdh-sha2-nistp256") == 0) + type = LIBSSH2_EC_CURVE_NISTP256; + else if(strcmp(name, "ecdh-sha2-nistp384") == 0) + type = LIBSSH2_EC_CURVE_NISTP384; + else if(strcmp(name, "ecdh-sha2-nistp521") == 0) + type = LIBSSH2_EC_CURVE_NISTP521; + else { + ret = -1; + } + + if(ret == 0 && out_type) { + *out_type = type; + } + + return ret; +} + + /* ecdh_sha2_nistp * Elliptic Curve Diffie Hellman Key Exchange */ From c69f1f27dc003d445b85fe6cbcff644b11ee6a67 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Sat, 30 Jan 2021 19:32:14 -0800 Subject: [PATCH 062/102] kex.c: use string_buf in ecdh_sha2_nistp (#551) * kex.c: use string_buf in ecdh_sha2_nistp file: kex.c notes: use string_buf in ecdh_sha2_nistp() to avoid attempting to parse malformed data --- src/kex.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/kex.c b/src/kex.c index 2b29f7ec..2e86b656 100644 --- a/src/kex.c +++ b/src/kex.c @@ -1752,26 +1752,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) { - ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for a copy " - "of the host key"); + 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"); 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 { @@ -1870,19 +1868,20 @@ static int ecdh_sha2_nistp(LIBSSH2_SESSION *session, libssh2_curve_type type, } /* 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"); + 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, From cde13f6201c56cc571489a7d7164b7205d688cf9 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Tue, 2 Feb 2021 10:11:14 -0800 Subject: [PATCH 063/102] kex.c: kex_agree_instr() improve string reading (#552) * kex.c: kex_agree_instr() improve string reading file: kex.c notes: if haystack isn't null terminated we should use memchr() not strchar(). We should also make sure we don't walk off the end of the buffer. credit: Will Cosgrove, reviewed by Michael Buckley --- src/kex.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/kex.c b/src/kex.c index 2e86b656..ed00c6a3 100644 --- a/src/kex.c +++ b/src/kex.c @@ -3286,24 +3286,40 @@ kex_agree_instr(unsigned char *haystack, unsigned long haystack_len, const unsigned char *needle, unsigned long needle_len) { unsigned char *s; + unsigned char *end_haystack; + unsigned long left; - /* Haystack too short to bother trying */ - if(haystack_len < needle_len) { + if(haystack == NULL || needle == NULL) { return NULL; } + /* Haystack too short to bother trying */ + 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++; + while((s = (unsigned char *) memchr((char *) s, ',', left))) { + /* 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 From 1adb24fd079152148c819adda574d23ab4047a3e Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Tue, 2 Feb 2021 19:28:28 +0100 Subject: [PATCH 064/102] Add a LINT option to CMake (#372) * ci: make style-checking available locally * cmake: add a linting target * tests: check test suite syntax with checksrc.pl --- .travis.yml | 12 +++----- CMakeLists.txt | 8 +++++ {src => ci}/checksrc.pl | 0 ci/checksrc.sh | 8 +++++ docs/INSTALL_CMAKE.md | 5 ++++ tests/openssh_fixture.c | 10 +++---- tests/test_agent_forward_succeeds.c | 2 +- tests/test_hostkey_hash.c | 30 +++++++++++-------- ...tive_auth_succeeds_with_correct_response.c | 5 ++-- ..._password_auth_fails_with_wrong_username.c | 3 +- ...d_auth_succeeds_with_correct_credentials.c | 5 ++-- ...c_key_auth_succeeds_with_correct_dsa_key.c | 5 ++-- ...y_auth_succeeds_with_correct_ed25519_key.c | 5 ++-- ...cceeds_with_correct_ed25519_key_from_mem.c | 8 +++-- ...ceeds_with_correct_encrypted_ed25519_key.c | 4 +-- ..._succeeds_with_correct_encrypted_rsa_key.c | 4 +-- ...c_key_auth_succeeds_with_correct_rsa_key.c | 5 ++-- ...th_succeeds_with_correct_rsa_openssh_key.c | 4 +-- 18 files changed, 77 insertions(+), 46 deletions(-) rename {src => ci}/checksrc.pl (100%) create mode 100755 ci/checksrc.sh diff --git a/.travis.yml b/.travis.yml index 64a3c403..e79ce8b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,10 +46,12 @@ compiler: addons: chrome: stable +matrix: + include: + - name: "Check style" + script: ./ci/checksrc.sh env: - matrix: - - B=style - ADDRESS_SIZE=64 CRYPTO_BACKEND=OpenSSL BUILD_SHARED_LIBS=OFF ENABLE_ZLIB_COMPRESSION=OFF B=configure - ADDRESS_SIZE=64 CRYPTO_BACKEND=OpenSSL BUILD_SHARED_LIBS=OFF ENABLE_ZLIB_COMPRESSION=OFF B=cmake - ADDRESS_SIZE=64 CRYPTO_BACKEND=OpenSSL BUILD_SHARED_LIBS=ON ENABLE_ZLIB_COMPRESSION=OFF B=cmake @@ -100,12 +102,6 @@ before_install: install: script: - - | - if [ "$B" = "style" ]; then - ./buildconf - ./configure - make checksrc - fi - | if [ "$B" = "configure" ]; then autoreconf -fi diff --git a/CMakeLists.txt b/CMakeLists.txt index ae559428..e6c95c88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,14 @@ if(BUILD_TESTING) add_subdirectory(tests) endif() +option(LINT "Check style while building" OFF) +if(LINT) + add_custom_target(lint ALL + ./ci/checksrc.sh + WORKING_DIRECTORY ${libssh2_SOURCE_DIR}) + add_dependencies(libssh2 lint) +endif() + add_subdirectory(docs) feature_summary(WHAT ALL) diff --git a/src/checksrc.pl b/ci/checksrc.pl similarity index 100% rename from src/checksrc.pl rename to ci/checksrc.pl diff --git a/ci/checksrc.sh b/ci/checksrc.sh new file mode 100755 index 00000000..3890815b --- /dev/null +++ b/ci/checksrc.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +FILES="src/*.[ch] include/*.h example/*.c tests/*.[ch]" +WHITELIST="-Wsrc/libssh2_config.h" + +perl ./ci/checksrc.pl -i4 -m79 -ASIZEOFNOPAREN -ASNPRINTF -ACOPYRIGHT -AFOPENMODE $WHITELIST $FILES diff --git a/docs/INSTALL_CMAKE.md b/docs/INSTALL_CMAKE.md index 9ad9f8d2..c136fdce 100644 --- a/docs/INSTALL_CMAKE.md +++ b/docs/INSTALL_CMAKE.md @@ -42,6 +42,11 @@ pass the options to CMake on the command line: The following options are available: + * `LINT=ON` + + Enables running the source code linter when building. Can be `ON` or `OFF`. + + * `BUILD_SHARED_LIBS=OFF` Determines whether libssh2 is built as a static library or as a diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 248a561d..f9d26e37 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -118,9 +118,9 @@ static int run_command_varg(char **output, const char *command, va_list args) if(output) { /* command output may contain a trailing newline, so we trim * whitespace here */ - size_t end = strlen(buf) - 1; - while(end > 0 && isspace(buf[end])) { - buf[end] = '\0'; + size_t end = strlen(buf); + while(end > 0 && isspace(buf[end - 1])) { + buf[end - 1] = '\0'; } *output = strdup(buf); @@ -140,7 +140,7 @@ static int run_command(char **output, const char *command, ...) return ret; } -static int build_openssh_server_docker_image() +static int build_openssh_server_docker_image(void) { return run_command(NULL, "docker build -t libssh2/openssh_server " "openssh_server"); @@ -157,7 +157,7 @@ static int stop_openssh_server(char *container_id) return run_command(NULL, "docker stop %s", container_id); } -static const char *docker_machine_name() +static const char *docker_machine_name(void) { return getenv("DOCKER_MACHINE_NAME"); } diff --git a/tests/test_agent_forward_succeeds.c b/tests/test_agent_forward_succeeds.c index a3117395..daf7bd5a 100644 --- a/tests/test_agent_forward_succeeds.c +++ b/tests/test_agent_forward_succeeds.c @@ -43,7 +43,7 @@ int test(LIBSSH2_SESSION *session) rc = libssh2_channel_request_auth_agent(channel); if(rc != 0) { fprintf(stderr, "Auth agent request for agent forwarding failed, " - "error code %d\n", rc); + "error code %d\n", rc); return 1; } diff --git a/tests/test_hostkey_hash.c b/tests/test_hostkey_hash.c index 620d6370..112b491f 100644 --- a/tests/test_hostkey_hash.c +++ b/tests/test_hostkey_hash.c @@ -84,8 +84,9 @@ int test(LIBSSH2_SESSION *session) calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_ECDSA_MD5_HASH_DIGEST) != 0) { - fprintf(stderr, "ECDSA MD5 hash not as expected, digest " - "%s != %s\n", buf, EXPECTED_ECDSA_MD5_HASH_DIGEST); + fprintf(stderr, + "ECDSA MD5 hash not as expected - digest %s != %s\n", + buf, EXPECTED_ECDSA_MD5_HASH_DIGEST); return 1; } @@ -99,8 +100,9 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST) != 0) { - fprintf(stderr, "ECDSA SHA1 hash not as expected, digest " - "%s != %s\n", buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST); + fprintf(stderr, + "ECDSA SHA1 hash not as expected - digest %s != %s\n", + buf, EXPECTED_ECDSA_SHA1_HASH_DIGEST); return 1; } @@ -115,8 +117,9 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST) != 0) { - fprintf(stderr, "ECDSA SHA256 hash not as expected, digest " - "%s != %s\n", buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST); + fprintf(stderr, + "ECDSA SHA256 hash not as expected - digest %s != %s\n", + buf, EXPECTED_ECDSA_SHA256_HASH_DIGEST); return 1; } @@ -133,8 +136,9 @@ int test(LIBSSH2_SESSION *session) calculate_digest(md5_hash, MD5_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_RSA_MD5_HASH_DIGEST) != 0) { - fprintf(stderr, "MD5 hash not as expected, digest " - "%s != %s\n", buf, EXPECTED_RSA_MD5_HASH_DIGEST); + fprintf(stderr, + "MD5 hash not as expected - digest %s != %s\n", + buf, EXPECTED_RSA_MD5_HASH_DIGEST); return 1; } @@ -148,8 +152,9 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha1_hash, SHA1_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_RSA_SHA1_HASH_DIGEST) != 0) { - fprintf(stderr, "SHA1 hash not as expected, digest " - "%s != %s\n", buf, EXPECTED_RSA_SHA1_HASH_DIGEST); + fprintf(stderr, + "SHA1 hash not as expected - digest %s != %s\n", + buf, EXPECTED_RSA_SHA1_HASH_DIGEST); return 1; } @@ -164,8 +169,9 @@ int test(LIBSSH2_SESSION *session) calculate_digest(sha256_hash, SHA256_HASH_SIZE, buf, BUFSIZ); if(strcmp(buf, EXPECTED_RSA_SHA256_HASH_DIGEST) != 0) { - fprintf(stderr, "SHA256 hash not as expected, digest " - "%s != %s\n", buf, EXPECTED_RSA_SHA256_HASH_DIGEST); + fprintf(stderr, + "SHA256 hash not as expected - digest %s != %s\n", + buf, EXPECTED_RSA_SHA256_HASH_DIGEST); return 1; } } diff --git a/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c b/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c index e9902449..0ccf5dd9 100644 --- a/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c +++ b/tests/test_keyboard_interactive_auth_succeeds_with_correct_response.c @@ -4,8 +4,9 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ -static const char *PASSWORD = "my test password"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; +static const char *PASSWORD = "my test password"; static void kbd_callback(const char *name, int name_len, const char *instruct, int instruct_len, diff --git a/tests/test_password_auth_fails_with_wrong_username.c b/tests/test_password_auth_fails_with_wrong_username.c index f6e7a068..b78617a4 100644 --- a/tests/test_password_auth_fails_with_wrong_username.c +++ b/tests/test_password_auth_fails_with_wrong_username.c @@ -4,7 +4,8 @@ #include -static const char *PASSWORD = "my test password"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *PASSWORD = "my test password"; static const char *WRONG_USERNAME = "i dont exist"; int test(LIBSSH2_SESSION *session) diff --git a/tests/test_password_auth_succeeds_with_correct_credentials.c b/tests/test_password_auth_succeeds_with_correct_credentials.c index a26e5220..94b86b87 100644 --- a/tests/test_password_auth_succeeds_with_correct_credentials.c +++ b/tests/test_password_auth_succeeds_with_correct_credentials.c @@ -4,8 +4,9 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ -static const char *PASSWORD = "my test password"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; +static const char *PASSWORD = "my test password"; int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c index cbaefc13..187c1313 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_dsa_key.c @@ -4,9 +4,10 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_dsa"; -static const char *KEY_FILE_PUBLIC = "key_dsa.pub"; /* set in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_dsa.pub"; int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c index 8acb073f..c52830d9 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key.c @@ -4,9 +4,10 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_ed25519"; -static const char *KEY_FILE_PUBLIC = "key_ed25519.pub"; /* set in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_ed25519.pub"; int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c index a0b25a04..4ecf168f 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c +++ b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c @@ -35,9 +35,11 @@ int test(LIBSSH2_SESSION *session) return 1; } - rc = libssh2_userauth_publickey_frommemory(session, USERNAME, - strlen(USERNAME), - NULL, 0, buffer, len, NULL); + rc = libssh2_userauth_publickey_frommemory(session, + USERNAME, strlen(USERNAME), + NULL, 0, + buffer, len, + NULL); free(buffer); diff --git a/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c b/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c index f3162236..553023a9 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c @@ -4,11 +4,11 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; static const char *PASSWORD = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_ed25519_encrypted"; static const char *KEY_FILE_PUBLIC = "key_ed25519_encrypted.pub"; - /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c index 80026ed2..ba98ac7c 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c @@ -4,11 +4,11 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; static const char *PASSWORD = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_rsa_encrypted"; static const char *KEY_FILE_PUBLIC = "key_rsa_encrypted.pub"; - /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c index 3806c26b..0cf2a633 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_rsa_key.c @@ -4,9 +4,10 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_rsa"; -static const char *KEY_FILE_PUBLIC = "key_rsa.pub"; /* set in Dockerfile */ +static const char *KEY_FILE_PUBLIC = "key_rsa.pub"; int test(LIBSSH2_SESSION *session) { diff --git a/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c b/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c index 5560ad00..a067d729 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c +++ b/tests/test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c @@ -4,10 +4,10 @@ #include -static const char *USERNAME = "libssh2"; /* set in Dockerfile */ +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; static const char *KEY_FILE_PRIVATE = "key_rsa_openssh"; static const char *KEY_FILE_PUBLIC = "key_rsa_openssh.pub"; - /* set in Dockerfile */ int test(LIBSSH2_SESSION *session) { From 384a50e0e4767b894b568220a0a26d492b305c5a Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Thu, 4 Feb 2021 09:56:16 -0800 Subject: [PATCH 065/102] ssh_client_fuzzer.cc: set blocking mode on (#553) file: ssh_client_fuzzer.cc notes: the session needs blocking mode turned on to avoid EAGAIN being returned from libssh2_session_handshake() credit: Will Cosgrove, reviewed by Michael Buckley --- tests/ossfuzz/ssh2_client_fuzzer.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ossfuzz/ssh2_client_fuzzer.cc b/tests/ossfuzz/ssh2_client_fuzzer.cc index 1988878e..84a9934c 100644 --- a/tests/ossfuzz/ssh2_client_fuzzer.cc +++ b/tests/ossfuzz/ssh2_client_fuzzer.cc @@ -57,6 +57,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) // Create a session and start the handshake using the fuzz data passed in. session = libssh2_session_init(); + if(session) { + libssh2_session_set_blocking(session, 1); + } if(libssh2_session_handshake(session, socket_fds[0])) { goto EXIT_LABEL; @@ -84,4 +87,5 @@ EXIT_LABEL: close(socket_fds[1]); return 0; -} \ No newline at end of file + + "Normal Shutdown, Thank you for playing") From 8ae21cad83dbae454fe6d86d748834cd58f9a8d8 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Fri, 5 Feb 2021 10:05:52 -0800 Subject: [PATCH 066/102] ssh2_client_fuzzer.cc: fixed building The GitHub web editor did some funky things --- tests/ossfuzz/ssh2_client_fuzzer.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ossfuzz/ssh2_client_fuzzer.cc b/tests/ossfuzz/ssh2_client_fuzzer.cc index 84a9934c..d9f5ab51 100644 --- a/tests/ossfuzz/ssh2_client_fuzzer.cc +++ b/tests/ossfuzz/ssh2_client_fuzzer.cc @@ -87,5 +87,4 @@ EXIT_LABEL: close(socket_fds[1]); return 0; - - "Normal Shutdown, Thank you for playing") +} From ae26886671848cbab60250790cc81568de957416 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Thu, 11 Feb 2021 09:18:16 -0800 Subject: [PATCH 067/102] transport.c: release payload on error (#554) file: transport.c notes: If the payload is invalid and there is an early return, we could leak the payload credit: Will Cosgrove --- src/transport.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/transport.c b/src/transport.c index 0723b77b..1a997279 100644 --- a/src/transport.c +++ b/src/transport.c @@ -488,6 +488,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) p->wptr += blocksize - 5; /* advance write pointer */ } else { + if(p->payload) + LIBSSH2_FREE(session, p->payload); return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } } @@ -570,6 +572,8 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) memcpy(p->wptr, &p->buf[p->readidx], numbytes); } else { + if(p->payload) + LIBSSH2_FREE(session, p->payload); return LIBSSH2_ERROR_OUT_OF_BOUNDARY; } From 4bb166a2a83efc62e94cac7e687a9e6f7586833c Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 4 Mar 2021 22:10:07 +0100 Subject: [PATCH 068/102] bcrypt_pbkdf.c: fix clang10 false positive warning (#563) File: bcrypt_pbkdf.c Notes: blf_enc() takes a number of 64-bit blocks to encrypt, but using sizeof(uint64_t) in the calculation triggers a warning with clang 10 because the actual data type is uint32_t. Pass BCRYPT_BLOCKS / 2 for the number of blocks like libc bcrypt(3) does. Ref: https://github.com/openbsd/src/commit/04a2240bd8f465bcae6b595d912af3e2965856de Fixes #562 Credit: Viktor Szakats --- src/bcrypt_pbkdf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bcrypt_pbkdf.c b/src/bcrypt_pbkdf.c index f9a97580..f782bcac 100644 --- a/src/bcrypt_pbkdf.c +++ b/src/bcrypt_pbkdf.c @@ -81,7 +81,7 @@ 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++) { From 5627b82be66135dbda6423ae10bcad1c9ac86f9d Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Thu, 4 Mar 2021 23:17:00 +0100 Subject: [PATCH 069/102] Tests: Fix unused variables warning (#561) file: test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c notes: fixed unused vars credit: Laurent Stacul --- ...public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c index 4ecf168f..a79d1b51 100644 --- a/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c +++ b/tests/test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c @@ -13,7 +13,6 @@ int read_file(const char *path, char **buf, size_t *len); int test(LIBSSH2_SESSION *session) { int rc; - FILE *fp = NULL; char *buffer = NULL; size_t len = 0; const char *userauth_list = NULL; @@ -53,7 +52,6 @@ int test(LIBSSH2_SESSION *session) int read_file(const char *path, char **out_buffer, size_t *out_len) { - int rc; FILE *fp = NULL; char *buffer = NULL; size_t len = 0; From 91393d66310f1a732e941c74cfc78292127adeca Mon Sep 17 00:00:00 2001 From: Mary Date: Thu, 22 Apr 2021 16:20:43 -0400 Subject: [PATCH 070/102] libssh2_priv.h: add iovec on 3ds (#575) file: libssh2_priv.h note: include iovec for 3DS credit: Mary Mstrodl --- src/libssh2_priv.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 474698e1..da488b74 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -109,14 +109,19 @@ #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; }; +#endif + +/* Provide iovec / writev on WIN32 platform. */ +#ifdef WIN32 + static inline int writev(int sock, struct iovec *iov, int nvecs) { DWORD ret; From ee199144fe27627cb12cb3b66a403e813327a94b Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Fri, 30 Apr 2021 19:10:52 -0400 Subject: [PATCH 071/102] ci: Swap from Travis to Github Actions (#581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files: ci files Notes: Move Linux CI using Github Actions Credit: Gabriel Smith, Marc Hörsken --- .github/workflows/ci.yml | 102 ++++++++++++++++++++ .travis.yml | 2 +- tests/ossfuzz/travisoss.sh => ci/ossfuzz.sh | 7 +- tests/ossfuzz/ossfuzz.sh | 2 +- 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/ci.yml rename tests/ossfuzz/travisoss.sh => ci/ossfuzz.sh (70%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..4fea3eac --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,102 @@ +name: CI + +on: + push: + branches: [ $default-branch ] + pull_request: + branches: [ $default-branch ] + +jobs: + style-check: + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@v2 + - name: Check Style + run: ./ci/checksrc.sh + build: + runs-on: ubuntu-16.04 + strategy: + fail-fast: false + matrix: + compiler: [gcc, clang] + address_size: [32, 64] + crypto_backend: [OpenSSL, Libgcrypt, mbedTLS] + build_shared_libs: [OFF, ON] + enable_zlib_compression: [OFF, ON] + b: [cmake] + include: + - compiler: gcc + address_size: 64 + crypto_backend: OpenSSL + build_shared_libs: OFF + enable_zlib_compression: OFF + b: configure + - compiler: clang + address_size: 64 + crypto_backend: OpenSSL + build_shared_libs: OFF + enable_zlib_compression: OFF + b: configure + env: + CC: ${{ matrix.compiler }} + CC_FOR_BUILD: ${{ matrix.compiler }} + CRYPTO_BACKEND: ${{ matrix.crypto_backend }} + BUILD_SHARED_LIBS: ${{ matrix.build_shared_libs }} + ENABLE_ZLIB_COMPRESSION: ${{ matrix.enable_zlib_compression }} + steps: + - uses: actions/checkout@v2 + - name: Install 32 Bit Dependencies + if: ${{ matrix.address_size == 32 }} + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update -qq + sudo apt-get install -y gcc-multilib + sudo apt-get install -y libssl-dev:i386 libgcrypt20-dev:i386 zlib1g-dev:i386 build-essential gcc-multilib + sudo dpkg --purge --force-depends gcc-multilib + sudo dpkg --purge --force-depends libssl-dev + echo "TOOLCHAIN_OPTION=-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-Linux-32.cmake" >> $GITHUB_ENV + - name: Install 64 Bit Dependencies + if: ${{ matrix.address_size == 64 }} + run: | + sudo apt-get install -y libssl-dev + sudo apt-get install -y libgcrypt11-dev + - name: Install mbedTLS Dependencies + if: ${{ matrix.crypto_backend == 'mbedTLS' }} + run: | + MBEDTLSVER=mbedtls-2.7.0 + curl -L https://github.com/ARMmbed/mbedtls/archive/$MBEDTLSVER.tar.gz | tar -xzf - + cd mbedtls-$MBEDTLSVER + cmake $TOOLCHAIN_OPTION -DUSE_SHARED_MBEDTLS_LIBRARY=ON -DCMAKE_INSTALL_PREFIX:PATH=../usr . + make -j3 install + cd .. + echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/usr/lib" >> $GITHUB_ENV + echo "TOOLCHAIN_OPTION=$TOOLCHAIN_OPTION -DCMAKE_PREFIX_PATH=$PWD/usr" >> $GITHUB_ENV + - name: Build with Configure + if: ${{ matrix.b == 'configure' }} + run: | + autoreconf -fi + ./configure --enable-debug --enable-werror + make + make check + - name: Build with CMake + if: ${{ matrix.b == 'cmake' }} + run: | + mkdir bin + cd bin + cmake $TOOLCHAIN_OPTION -DCRYPTO_BACKEND=$CRYPTO_BACKEND -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DENABLE_ZLIB_COMPRESSION=$ENABLE_ZLIB_COMPRESSION .. + cmake --build . + CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test + cmake --build . --target package + fuzzer: + runs-on: ubuntu-16.04 + strategy: + fail-fast: false + matrix: + compiler: [gcc, clang] + env: + CC: ${{ matrix.compiler }} + CC_FOR_BUILD: ${{ matrix.compiler }} + steps: + - uses: actions/checkout@v2 + - name: Run Fuzzer + run: GIT_REF=$GITHUB_REF ./ci/ossfuzz.sh diff --git a/.travis.yml b/.travis.yml index e79ce8b8..8b100675 100644 --- a/.travis.yml +++ b/.travis.yml @@ -117,7 +117,7 @@ script: fi - | if [ "$B" = "fuzzer" ]; then - ./tests/ossfuzz/travisoss.sh + GIT_REF=$TRAVIS_COMMIT ./ci/ossfuzz.sh fi # whitelist branches to avoid testing feature branches twice (as branch and as pull request) diff --git a/tests/ossfuzz/travisoss.sh b/ci/ossfuzz.sh similarity index 70% rename from tests/ossfuzz/travisoss.sh rename to ci/ossfuzz.sh index 486cd6fd..9ca9c165 100755 --- a/tests/ossfuzz/travisoss.sh +++ b/ci/ossfuzz.sh @@ -16,8 +16,11 @@ then exit 0 fi -# Modify the oss-fuzz Dockerfile so that we're checking out the current branch on travis. -sed -i "s@https://github.com/libssh2/libssh2.git@-b $TRAVIS_BRANCH https://github.com/libssh2/libssh2.git@" /tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile +# Modify the oss-fuzz Dockerfile so that we're checking out the current branch in the CI system. +sed -i \ + -e "s@--depth 1@--no-checkout@" \ + -e "s@/src/libssh2@/src/libssh2 ; git -C /src/libssh2 fetch origin $GIT_REF:ci; git -C /src/libssh2 checkout ci@" \ + /tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile # Try and build the fuzzers pushd /tmp/ossfuzz diff --git a/tests/ossfuzz/ossfuzz.sh b/tests/ossfuzz/ossfuzz.sh index 4ea60a2a..36c1f787 100755 --- a/tests/ossfuzz/ossfuzz.sh +++ b/tests/ossfuzz/ossfuzz.sh @@ -1,7 +1,7 @@ #!/bin/bash -eu # This script is called by the oss-fuzz main project when compiling the fuzz -# targets. This script is regression tested by travisoss.sh. +# targets. This script is regression tested by ci/ossfuzz.sh. # Save off the current folder as the build root. export BUILD_ROOT=$PWD From fb375d6fe26012ce4206f8758a7458cd2d424c4d Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Sun, 2 May 2021 20:32:48 -0400 Subject: [PATCH 072/102] ci: explicitly state the default branch (#585) Notes: It looks like the $default-branch macro only works in templates, not workflows. This is not explicitly stated anywhere except the linked PR comment. https://github.com/actions/starter-workflows/pull/590#issuecomment-672360634 credit: Gabriel Smith --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4fea3eac..52a3cd7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ $default-branch ] + branches: [ master ] pull_request: - branches: [ $default-branch ] + branches: [ master ] jobs: style-check: From b5c071d180d2591358ad0a84ab90ac5f37ff926a Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Mon, 3 May 2021 17:41:25 -0400 Subject: [PATCH 073/102] openssh_fixture.c: Fix potential overwrite of buffer when reading stdout of command (#580) File: openssh_fixture.c Notes: If reading the full output from the executed command took multiple passes (such as when reading multiple lines) the old code would read into the buffer starting at the some position (the start) every time. The old code only works if fgets updated p or had an offset parameter, both of which are not true. Credit: Gabriel Smith --- tests/openssh_fixture.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index f9d26e37..f5ee5ef0 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -65,8 +65,8 @@ static int run_command_varg(char **output, const char *command, va_list args) char redirect_stderr[] = "%s 2>&1"; char command_buf[BUFSIZ]; char buf[BUFSIZ]; - char *p; int ret; + size_t buf_len; if(output) { *output = NULL; @@ -101,9 +101,12 @@ static int run_command_varg(char **output, const char *command, va_list args) fprintf(stderr, "Unable to execute command '%s'\n", command); return -1; } - p = buf; - while(fgets(p, sizeof(buf) - (p - buf), pipe) != NULL) - ; + buf[0] = 0; + buf_len = 0; + while(buf_len < (sizeof(buf) - 1) && + fgets(&buf[buf_len], sizeof(buf) - buf_len, pipe) != NULL) { + buf_len = strlen(buf); + } #ifdef WIN32 ret = _pclose(pipe); From 35695772d0b93a50a1de79ced596be39062a48f1 Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Mon, 3 May 2021 23:47:06 +0200 Subject: [PATCH 074/102] openssl.c: Fix EVP_Cipher interface change in openssl 3 #463 File: openssl.c Notes: Fixes building with OpenSSL 3, #463. The change is described there: https://github.com/openssl/openssl/commit/f7397f0d58ce7ddf4c5366cd1846f16b341fbe43 Credit: Laurent Stacul, reported by Sergei --- src/openssl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/openssl.c b/src/openssl.c index 65a6c173..c286bc61 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -427,10 +427,19 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, #else ret = EVP_Cipher(ctx, buf, block, blocksize); #endif +#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 + if(ret != -1) { +#else if(ret == 1) { +#endif memcpy(block, buf, blocksize); } + +#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 + return ret != -1 ? 0 : 1; +#else return ret == 1 ? 0 : 1; +#endif } #if LIBSSH2_AES_CTR && !defined(HAVE_EVP_AES_128_CTR) From b853d7a86e1648c00386790e91cefcfd701bd17b Mon Sep 17 00:00:00 2001 From: Marc <34656315+MarcT512@users.noreply.github.com> Date: Mon, 3 May 2021 22:49:02 +0100 Subject: [PATCH 075/102] openssl.c: Avoid OpenSSL latent error in FIPS mode (#528) File: openssl.c Notes: Avoid initing MD5 digest, which is not permitted in OpenSSL FIPS certified cryptography mode. Credit: Marc --- src/openssl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/openssl.c b/src/openssl.c index c286bc61..4d0f53cf 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -2221,6 +2221,13 @@ _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(FIPS_mode() != 0) + return 0; #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); From 7118582a7cad8ca8235eadbae564fe768311246a Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Mon, 3 May 2021 14:49:53 -0700 Subject: [PATCH 076/102] userauth.c: don't error if using keys without RSA (#555) file: userauth.c notes: libssh2 now supports many other key types besides RSA, if the library is built without RSA support and a user attempts RSA auth it shouldn't be an automatic error credit: Will Cosgrove --- src/userauth.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/userauth.c b/src/userauth.c index d5dbaa48..df7663fe 100644 --- a/src/userauth.c +++ b/src/userauth.c @@ -828,11 +828,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; @@ -1438,11 +1433,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; @@ -1500,11 +1490,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; From 92366cdb79b4be7ec61bebbb7ba446001d2eca8d Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Tue, 4 May 2021 12:16:54 -0400 Subject: [PATCH 077/102] ci: Speed up docker builds for tests (#587) Notes: The OpenSSH server docker image used for tests is pre-built to prevent wasting time building it during a test, and unneeded rebuilds are prevented by caching the image layers. Credit: Gabriel Smith --- .github/workflows/ci.yml | 4 ++++ .travis.yml | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52a3cd7e..b3296b46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,7 @@ jobs: ENABLE_ZLIB_COMPRESSION: ${{ matrix.enable_zlib_compression }} steps: - uses: actions/checkout@v2 + - uses: satackey/action-docker-layer-caching@v0.0.11 - name: Install 32 Bit Dependencies if: ${{ matrix.address_size == 32 }} run: | @@ -85,6 +86,9 @@ jobs: cd bin cmake $TOOLCHAIN_OPTION -DCRYPTO_BACKEND=$CRYPTO_BACKEND -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DENABLE_ZLIB_COMPRESSION=$ENABLE_ZLIB_COMPRESSION .. cmake --build . + pushd ../tests + docker build -t libssh2/openssh_server openssh_server + popd CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test cmake --build . --target package fuzzer: diff --git a/.travis.yml b/.travis.yml index 8b100675..ec290126 100644 --- a/.travis.yml +++ b/.travis.yml @@ -112,7 +112,9 @@ script: - | if [ "$B" = "cmake" ]; then mkdir bin - cd bin + cd tests + docker build -t libssh2/openssh_server openssh_server + cd ../bin cmake $TOOLCHAIN_OPTION -DCRYPTO_BACKEND=$CRYPTO_BACKEND -DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS -DENABLE_ZLIB_COMPRESSION=$ENABLE_ZLIB_COMPRESSION .. && cmake --build . && CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test && cmake --build . --target package fi - | From 1270fdfe4bf31514a4a0ae4f5a543001d7c82232 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Tue, 11 May 2021 16:44:12 -0400 Subject: [PATCH 078/102] ci: Remove caching of docker image layers (#589) Notes: continued ci reliability work. Credit: Gabriel Smith --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3296b46..3333d9c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,6 @@ jobs: ENABLE_ZLIB_COMPRESSION: ${{ matrix.enable_zlib_compression }} steps: - uses: actions/checkout@v2 - - uses: satackey/action-docker-layer-caching@v0.0.11 - name: Install 32 Bit Dependencies if: ${{ matrix.address_size == 32 }} run: | From b3a8a6d27cd9c5c8039db14489f03e4a438a63d2 Mon Sep 17 00:00:00 2001 From: Paul Capron Date: Tue, 11 May 2021 23:06:18 +0200 Subject: [PATCH 079/102] Fix _libssh2_random() silently discarding errors (#520) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notes: * Make _libssh2_random return code consistent Previously, _libssh2_random was advertized in HACKING.CRYPTO as returning `void` (and was implemented that way in os400qc3.c), but that was in other crypto backends a lie; _libssh2_random is (a macro expanding) to an int-value expression or function. Moreover, that returned code was: — 0 or success, -1 on error for the MbedTLS & WinCNG crypto backends But also: — 1 on success, -1 or 0 on error for the OpenSSL backend! – 1 on success, error cannot happen for libgcrypt! This commit makes explicit that _libssh2_random can fail (because most of the underlying crypto functions can indeed fail!), and it makes its result code consistent: 0 on success, -1 on error. This is related to issue #519 https://github.com/libssh2/libssh2/issues/519 It fixes the first half of it. * Don't silent errors of _libssh2_random Make sure to check the returned code of _libssh2_random(), and propagates any failure. A new LIBSSH_ERROR_RANDGEN constant is added to libssh2.h None of the existing error constants seemed fit. This commit is related to d74285b68450c0e9ea6d5f8070450837fb1e74a7 and to https://github.com/libssh2/libssh2/issues/519 (see the issue for more info.) It closes #519. Credit: Paul Capron --- docs/HACKING.CRYPTO | 3 ++- include/libssh2.h | 1 + src/channel.c | 6 +++++- src/kex.c | 6 +++++- src/libgcrypt.h | 2 +- src/openssl.h | 2 +- src/os400qc3.c | 5 ++++- src/os400qc3.h | 2 +- src/transport.c | 5 ++++- 9 files changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/HACKING.CRYPTO b/docs/HACKING.CRYPTO index b78a0148..ea2530bb 100644 --- a/docs/HACKING.CRYPTO +++ b/docs/HACKING.CRYPTO @@ -897,5 +897,6 @@ In example, this is needed to preset unused structure slacks on platforms requiring it. If this is not needed, it should be defined as an empty macro. -void _libssh2_random(unsigned char *buf, int len); +int _libssh2_random(unsigned char *buf, int len); Store len random bytes at buf. +Returns 0 if OK, else -1. diff --git a/include/libssh2.h b/include/libssh2.h index 4931a2af..f17b502e 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -505,6 +505,7 @@ 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 /* this is a define to provide the old (<= 1.2.7) name */ #define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV diff --git a/src/channel.c b/src/channel.c index 55a16e9f..78ed40e8 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1338,7 +1338,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]); } diff --git a/src/kex.c b/src/kex.c index ed00c6a3..9f3ef799 100644 --- a/src/kex.c +++ b/src/kex.c @@ -3176,7 +3176,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?) diff --git a/src/libgcrypt.h b/src/libgcrypt.h index 92b48b88..298c65ed 100644 --- a/src/libgcrypt.h +++ b/src/libgcrypt.h @@ -68,7 +68,7 @@ #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) #define _libssh2_random(buf, len) \ - (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1) + (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 0) #define libssh2_prepare_iovec(vec, len) /* Empty. */ diff --git a/src/openssl.h b/src/openssl.h index 66ff1b26..658b040d 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -137,7 +137,7 @@ #define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1) -#define _libssh2_random(buf, len) RAND_bytes ((buf), (len)) +#define _libssh2_random(buf, len) (RAND_bytes((buf), (len)) == 1 ? 0 : -1) #define libssh2_prepare_iovec(vec, len) /* Empty. */ diff --git a/src/os400qc3.c b/src/os400qc3.c index bf5acdaf..f05bfabf 100644 --- a/src/os400qc3.c +++ b/src/os400qc3.c @@ -884,11 +884,14 @@ _libssh2_bn_from_bn(_libssh2_bn *to, _libssh2_bn *from) return 0; } -void +int _libssh2_random(unsigned char *buf, int len) { Qc3GenPRNs(buf, len, Qc3PRN_TYPE_NORMAL, Qc3PRN_NO_PARITY, (char *) &ecnull); + /* FIXME: any error is silently discarded! But Qc3GenPRNs could fail, + including if "The system seed digest is not ready" dixit IBM doc. */ + return 0; } diff --git a/src/os400qc3.h b/src/os400qc3.h index f0d2ea50..e3602d9f 100644 --- a/src/os400qc3.h +++ b/src/os400qc3.h @@ -360,7 +360,7 @@ extern int _libssh2_bn_from_bin(_libssh2_bn *bn, int len, const unsigned char *v); extern int _libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val); extern int _libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val); -extern void _libssh2_random(unsigned char *buf, int len); +extern int _libssh2_random(unsigned char *buf, int len); extern void _libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x); extern int libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x, unsigned int algo); diff --git a/src/transport.c b/src/transport.c index 1a997279..17af3e4d 100644 --- a/src/transport.c +++ b/src/transport.c @@ -862,7 +862,10 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, 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; From 58ae048c92753e869ea7638bf3d30f4f4cd0ca3f Mon Sep 17 00:00:00 2001 From: Zenju Date: Tue, 11 May 2021 23:09:57 +0200 Subject: [PATCH 080/102] Fix detailed _libssh2_error being overwritten (#473) Files: openssl.c, pem.c, userauth.c Notes: * Fix detailed _libssh2_error being overwritten by generic errors * Unified error handling Credit: Zenju --- src/openssl.c | 68 +++++++++++++++++++++++--------------------------- src/pem.c | 31 +++++++++++++++-------- src/userauth.c | 9 +++---- 3 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/openssl.c b/src/openssl.c index 4d0f53cf..2ea9e1ba 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -1690,6 +1690,8 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, method_buf = LIBSSH2_ALLOC(session, 11); /* ssh-ed25519. */ if(method_buf == NULL) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); goto clean_exit; } @@ -1698,6 +1700,8 @@ gen_publickey_from_ed25519_openssh_priv_data(LIBSSH2_SESSION *session, key_len = LIBSSH2_ED25519_KEY_LEN + 19; key = LIBSSH2_CALLOC(session, key_len); if(key == NULL) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for ED25519 key"); goto clean_exit; } @@ -2418,6 +2422,7 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, if((rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf, pointlen, curve_type)) != 0) { + rc = -1; _libssh2_error(session, LIBSSH2_ERROR_PROTO, "ECDSA could not create key"); goto fail; @@ -2426,6 +2431,8 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, bn_exponent = BN_new(); if(bn_exponent == NULL) { rc = -1; + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for private key data"); goto fail; } @@ -2452,15 +2459,10 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, return rc; fail: - if(ec_key != NULL) EC_KEY_free(ec_key); - return _libssh2_error(session, - LIBSSH2_ERROR_ALLOC, - "Unable to allocate memory for private key data"); - - + return rc; } static int @@ -3053,17 +3055,13 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, if(key_ctx != NULL) *key_ctx = NULL; - if(session == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Session is required"); - return -1; - } + if(session == NULL) + 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 != NULL && (strlen(key_type) > 11 || strlen(key_type) < 7)) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "type is invalid"); _libssh2_init_if_needed(); @@ -3071,20 +3069,18 @@ _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); - if(rc != 0 || buf == NULL) { - _libssh2_error(session, LIBSSH2_ERROR_PROTO, - "Public key type in decrypted key data not found"); - return -1; - } + if(rc != 0 || buf == NULL) + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Public key type in decrypted " + "key data not found"); - rc = -1; + rc = LIBSSH2_ERROR_FILE; #if LIBSSH2_ED25519 if(strcmp("ssh-ed25519", (const char *)buf) == 0) { @@ -3138,6 +3134,11 @@ _libssh2_pub_priv_openssh_keyfilememory(LIBSSH2_SESSION *session, } #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); @@ -3177,10 +3178,10 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, "Computing public key from private key."); bp = BIO_new_mem_buf((char *)privatekeydata, privatekeydata_len); - if(!bp) { - return -1; - } - + 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); @@ -3195,15 +3196,8 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session, 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"); - } - + if(st != 0) + return st; return 0; } diff --git a/src/pem.c b/src/pem.c index 53f58c2e..3416bd52 100644 --- a/src/pem.c +++ b/src/pem.c @@ -176,6 +176,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; } @@ -319,6 +321,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; } @@ -690,6 +694,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; } @@ -738,17 +744,17 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, size_t off = 0; int ret; - if(filedata == NULL || filedata_len <= 0) { - return -1; - } + if(filedata == NULL || 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: offset out of bounds"); if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) { return -1; @@ -766,7 +772,9 @@ _libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session, 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 +785,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 +796,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); diff --git a/src/userauth.c b/src/userauth.c index df7663fe..5f669594 100644 --- a/src/userauth.c +++ b/src/userauth.c @@ -1447,15 +1447,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, From c998f79384116e9f6633cb69c2731c60d3a442bb Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Tue, 11 May 2021 17:13:37 -0400 Subject: [PATCH 081/102] agent.c: Add support for Windows OpenSSH agent (#517) Files: agent.c, agent.h, agent_win.c Notes: * agent: Add support for Windows OpenSSH agent The implementation was partially taken and modified from that found in the Portable OpenSSH port to Win32 by the PowerShell team, but mostly based on the existing Unix OpenSSH agent support. https://github.com/PowerShell/openssh-portable Regarding the partial transfer support implementation: partial transfers are easy to deal with, but you need to track additional state when non-blocking IO enters the picture. A tracker of how many bytes have been transfered has been placed in the transfer context struct as that's where it makes most sense. This tracker isn't placed behind a WIN32 #ifdef as it will probably be useful for other agent implementations. * agent: win32 openssh: Disable overlapped IO Non-blocking IO is not currently supported by the surrounding agent code, despite a lot of the code having everything set up to handle it. Credit: Co-authored-by: Gabriel Smith --- COPYING | 2 + Makefile.inc | 2 +- src/CMakeLists.txt | 1 + src/agent.c | 65 ++------ src/agent.h | 112 ++++++++++++++ src/agent_win.c | 361 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 490 insertions(+), 53 deletions(-) create mode 100644 src/agent.h create mode 100644 src/agent_win.c diff --git a/COPYING b/COPYING index 68c8d369..4852a889 100644 --- a/COPYING +++ b/COPYING @@ -4,6 +4,8 @@ * Copyright (c) 2007 Eli Fant * Copyright (c) 2009-2019 Daniel Stenberg * Copyright (C) 2008, 2009 Simon Josefsson + * Copyright (c) 2000 Markus Friedl + * Copyright (c) 2015 Microsoft Corp. * All rights reserved. * * Redistribution and use in source and binary forms, diff --git a/Makefile.inc b/Makefile.inc index ff8e6efa..87d26bbd 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -1,7 +1,7 @@ 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 + blowfish.c bcrypt_pbkdf.c agent_win.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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fa0812be..eee1a80d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -176,6 +176,7 @@ include(GNUInstallDirs) set(SOURCES ${CRYPTO_SOURCES} agent.c + agent_win.c blf.h bcrypt_pbkdf.c blowfish.c diff --git a/src/agent.c b/src/agent.c index 3fbf310d..85c3e34a 100644 --- a/src/agent.c +++ b/src/agent.c @@ -38,6 +38,7 @@ */ #include "libssh2_priv.h" +#include "agent.h" #include "misc.h" #include #ifdef HAVE_SYS_UN_H @@ -50,6 +51,9 @@ #endif #include "userauth.h" #include "session.h" +#ifdef WIN32 +#include +#endif /* Requests from client to agent for protocol 1 key operations */ #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 @@ -90,58 +94,6 @@ #define SSH_AGENT_CONSTRAIN_LIFETIME 1 #define SSH_AGENT_CONSTRAIN_CONFIRM 2 -/* non-blocking mode on agent connection is not yet implemented, but - for future use. */ -typedef enum { - agent_NB_state_init = 0, - agent_NB_state_request_created, - agent_NB_state_request_length_sent, - agent_NB_state_request_sent, - agent_NB_state_response_length_received, - agent_NB_state_response_received -} agent_nonblocking_states; - -typedef struct agent_transaction_ctx { - unsigned char *request; - size_t request_len; - unsigned char *response; - size_t response_len; - agent_nonblocking_states state; -} *agent_transaction_ctx_t; - -typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent); -typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent, - agent_transaction_ctx_t transctx); -typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent); - -struct agent_publickey { - struct list_node node; - - /* this is the struct we expose externally */ - struct libssh2_agent_publickey external; -}; - -struct agent_ops { - agent_connect_func connect; - agent_transact_func transact; - agent_disconnect_func disconnect; -}; - -struct _LIBSSH2_AGENT -{ - LIBSSH2_SESSION *session; /* the session this "belongs to" */ - - libssh2_socket_t fd; - - struct agent_ops *ops; - - struct agent_transaction_ctx transctx; - struct agent_publickey *identity; - struct list_head head; /* list of public keys */ - - char *identity_agent_path; /* Path to a custom identity agent socket */ -}; - #ifdef PF_UNIX static int agent_connect_unix(LIBSSH2_AGENT *agent) @@ -404,6 +356,7 @@ static struct { } supported_backends[] = { #ifdef WIN32 {"Pageant", &agent_ops_pageant}, + {"OpenSSH", &agent_ops_openssh}, #endif /* WIN32 */ #ifdef PF_UNIX {"Unix", &agent_ops_unix}, @@ -441,6 +394,7 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, _libssh2_store_u32(&s, 0); transctx->request_len = s - transctx->request; + transctx->send_recv_total = 0; transctx->state = agent_NB_state_request_created; } @@ -541,6 +495,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; } @@ -717,6 +672,12 @@ libssh2_agent_init(LIBSSH2_SESSION *session) agent->identity_agent_path = NULL; _libssh2_list_init(&agent->head); +#ifdef WIN32 + agent->pipe = INVALID_HANDLE_VALUE; + memset(&agent->overlapped, 0, sizeof(OVERLAPPED)); + agent->pending_io = FALSE; +#endif + return agent; } diff --git a/src/agent.h b/src/agent.h new file mode 100644 index 00000000..dfac0715 --- /dev/null +++ b/src/agent.h @@ -0,0 +1,112 @@ +#ifndef __LIBSSH2_AGENT_H +#define __LIBSSH2_AGENT_H +/* + * Copyright (c) 2009 by Daiki Ueno + * Copyright (C) 2010-2014 by 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. + */ + +#include "libssh2_priv.h" +#include "misc.h" +#include "session.h" +#ifdef WIN32 +#include +#endif + +/* non-blocking mode on agent connection is not yet implemented, but + for future use. */ +typedef enum { + agent_NB_state_init = 0, + agent_NB_state_request_created, + agent_NB_state_request_length_sent, + agent_NB_state_request_sent, + agent_NB_state_response_length_received, + agent_NB_state_response_received +} agent_nonblocking_states; + +typedef struct agent_transaction_ctx { + unsigned char *request; + size_t request_len; + 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); +typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent, + agent_transaction_ctx_t transctx); +typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent); + +struct agent_publickey { + struct list_node node; + + /* this is the struct we expose externally */ + struct libssh2_agent_publickey external; +}; + +struct agent_ops { + agent_connect_func connect; + agent_transact_func transact; + agent_disconnect_func disconnect; +}; + +struct _LIBSSH2_AGENT +{ + LIBSSH2_SESSION *session; /* the session this "belongs to" */ + + libssh2_socket_t fd; + + struct agent_ops *ops; + + struct agent_transaction_ctx transctx; + struct agent_publickey *identity; + struct list_head head; /* list of public keys */ + + char *identity_agent_path; /* Path to a custom identity agent socket */ + +#ifdef WIN32 + OVERLAPPED overlapped; + HANDLE pipe; + BOOL pending_io; +#endif +}; + +#ifdef WIN32 +extern struct agent_ops agent_ops_openssh; +#endif + +#endif /* __LIBSSH2_AGENT_H */ diff --git a/src/agent_win.c b/src/agent_win.c new file mode 100644 index 00000000..a1605a95 --- /dev/null +++ b/src/agent_win.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2009 by Daiki Ueno + * Copyright (C) 2010-2014 by 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. + */ + +#include "libssh2_priv.h" +#include "agent.h" +#include "misc.h" +#include +#ifdef HAVE_SYS_UN_H +#include +#else +/* Use the existence of sys/un.h as a test if Unix domain socket is + supported. winsock*.h define PF_UNIX/AF_UNIX but do not actually + support them. */ +#undef PF_UNIX +#endif +#include "userauth.h" +#include "session.h" +#ifdef WIN32 +#include +#endif + +#ifdef WIN32 +/* 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, + * specificaly 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 + * Copyright (c) 1995 Tatu Ylonen , 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 == NULL) { + 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 != NULL) + 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; +} + +struct agent_ops agent_ops_openssh = { + agent_connect_openssh, + agent_transact_openssh, + agent_disconnect_openssh +}; +#endif /* WIN32 */ From 3f9d505353d687db14d1486530abf9147bf08033 Mon Sep 17 00:00:00 2001 From: kkoenig Date: Wed, 12 May 2021 09:13:19 -0700 Subject: [PATCH 082/102] Support ECDSA certificate authentication (#570) Files: hostkey.c, userauth.c, test_public_key_auth_succeeds_with_correct_ecdsa_key.c Notes: Support ECDSA certificate authentication Add a test for: - Existing ecdsa basic public key authentication - ecdsa public key authentication with a signed public key Credit: kkoenig --- src/hostkey.c | 39 +++++++++++++++++++ src/userauth.c | 20 +++++++++- tests/CMakeLists.txt | 4 +- tests/Makefile.am | 2 + tests/key_ecdsa | 10 +++++ tests/key_ecdsa.pub | 1 + tests/openssh_server/Dockerfile | 9 +++++ tests/openssh_server/authorized_keys | 1 + tests/openssh_server/ca_ecdsa | 12 ++++++ tests/openssh_server/ca_ecdsa.pub | 1 + tests/signed_key_ecdsa | 10 +++++ tests/signed_key_ecdsa-cert.pub | 1 + tests/signed_key_ecdsa.pub | 1 + ...key_auth_succeeds_with_correct_ecdsa_key.c | 38 ++++++++++++++++++ ...h_succeeds_with_correct_signed_ecdsa_key.c | 38 ++++++++++++++++++ 15 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 tests/key_ecdsa create mode 100644 tests/key_ecdsa.pub create mode 100644 tests/openssh_server/ca_ecdsa create mode 100644 tests/openssh_server/ca_ecdsa.pub create mode 100644 tests/signed_key_ecdsa create mode 100644 tests/signed_key_ecdsa-cert.pub create mode 100644 tests/signed_key_ecdsa.pub create mode 100644 tests/test_public_key_auth_succeeds_with_correct_ecdsa_key.c create mode 100644 tests/test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c diff --git a/src/hostkey.c b/src/hostkey.c index 1631aae6..d87a4c74 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -783,6 +783,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 @@ -999,6 +1035,9 @@ 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, diff --git a/src/userauth.c b/src/userauth.c index 5f669594..40ef9153 100644 --- a/src/userauth.c +++ b/src/userauth.c @@ -1070,7 +1070,21 @@ libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, return rc; } - +static int plain_method_len(const char *method, size_t method_len) +{ + 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; + } + return method_len; +} int _libssh2_userauth_publickey(LIBSSH2_SESSION *session, @@ -1335,6 +1349,10 @@ _libssh2_userauth_publickey(LIBSSH2_SESSION *session, s = session->userauth_pblc_packet + session->userauth_pblc_packet_len; session->userauth_pblc_b = NULL; + session->userauth_pblc_method_len = + plain_method_len((const char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + _libssh2_store_u32(&s, 4 + session->userauth_pblc_method_len + 4 + sig_len); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 99a8b8b5..cf4b3f76 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -130,7 +130,9 @@ if(CRYPTO_BACKEND STREQUAL "OpenSSL") public_key_auth_succeeds_with_correct_ed25519_key public_key_auth_succeeds_with_correct_encrypted_ed25519_key public_key_auth_succeeds_with_correct_ed25519_key_from_mem - ) + public_key_auth_succeeds_with_correct_ecdsa_key + public_key_auth_succeeds_with_correct_signed_ecdsa_key + ) endif() endif() diff --git a/tests/Makefile.am b/tests/Makefile.am index d210ad63..bf79c145 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -56,6 +56,8 @@ EXTRA_DIST = \ test_public_key_auth_succeeds_with_correct_dsa_key.c \ test_public_key_auth_succeeds_with_correct_ed25519_key.c \ test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c \ + test_public_key_auth_succeeds_with_correct_ecdsa_key.c \ + test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c \ test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c \ test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c \ test_public_key_auth_succeeds_with_correct_rsa_key.c \ diff --git a/tests/key_ecdsa b/tests/key_ecdsa new file mode 100644 index 00000000..6ed60773 --- /dev/null +++ b/tests/key_ecdsa @@ -0,0 +1,10 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS +1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQTosiScH/oRSazpIpPSEFcY4YVZyNby +peARi49N3qy78OE118KGc5T8eifd+n1PSb7z8PnfDwOL4jBHxW5nWx0RCocIt7tb2a349J +gfEl8PegHGcF/DwC+eesIKJvv0MfkAAADIKLgw6yi4MOsAAAATZWNkc2Etc2hhMi1uaXN0 +cDM4NAAAAAhuaXN0cDM4NAAAAGEE6LIknB/6EUms6SKT0hBXGOGFWcjW8qXgEYuPTd6su/ +DhNdfChnOU/Hon3fp9T0m+8/D53w8Di+IwR8VuZ1sdEQqHCLe7W9mt+PSYHxJfD3oBxnBf +w8AvnnrCCib79DH5AAAAMGYdHu+u2/L8zC/0S9bao9y6vKiLSuTEfZpCIsyE5jWj/vrS0n +r1lzv9kKj+5A86aQAAAAA= +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/key_ecdsa.pub b/tests/key_ecdsa.pub new file mode 100644 index 00000000..597f63fc --- /dev/null +++ b/tests/key_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOiyJJwf+hFJrOkik9IQVxjhhVnI1vKl4BGLj03erLvw4TXXwoZzlPx6J936fU9JvvPw+d8PA4viMEfFbmdbHREKhwi3u1vZrfj0mB8SXw96AcZwX8PAL556wgom+/Qx+Q== diff --git a/tests/openssh_server/Dockerfile b/tests/openssh_server/Dockerfile index 72e24bfe..c5ce2224 100644 --- a/tests/openssh_server/Dockerfile +++ b/tests/openssh_server/Dockerfile @@ -58,10 +58,19 @@ COPY ssh_host_ed25519_key /tmp/etc/ssh/ssh_host_ed25519_key RUN mv /tmp/etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_ed25519_key RUN chmod 600 /etc/ssh/ssh_host_ed25519_key +COPY ca_ecdsa.pub /tmp/etc/ssh/ca_ecdsa.pub +RUN mv /tmp/etc/ssh/ca_ecdsa.pub /etc/ssh/ca_ecdsa.pub +RUN chmod 600 /etc/ssh/ca_ecdsa.pub + +COPY ca_ecdsa /tmp/etc/ssh/ca_ecdsa +RUN mv /tmp/etc/ssh/ca_ecdsa /etc/ssh/ca_ecdsa +RUN chmod 600 /etc/ssh/ca_ecdsa + RUN adduser --disabled-password --gecos 'Test user for libssh2 integration tests' libssh2 RUN echo 'libssh2:my test password' | chpasswd RUN sed -i 's/ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config +RUN echo "TrustedUserCAKeys /etc/ssh/ca_ecdsa.pub" >> /etc/ssh/sshd_config # SSH login fix. Otherwise user is kicked off after login RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd diff --git a/tests/openssh_server/authorized_keys b/tests/openssh_server/authorized_keys index 870f9a2f..cdd6eef5 100644 --- a/tests/openssh_server/authorized_keys +++ b/tests/openssh_server/authorized_keys @@ -4,3 +4,4 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC92YlGoc4PJy6DzX916JJZhxkvmkWBLGJdWOL7R9B6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDTe1lN2L/yet0Ma1JzXkQf3t1f+pauALec2FsGZy87KRJW1AOxcTTiePjlFwP1yfSK1lWXQ+uf0b61gkKqqR52FDky24HJWuYlfXlEQMn2d/PNDNVDDbO4TXKyNxxUHFJ6qYMNd4kWjOH+6rmYoWKsWV+3mDRbHagbVPEYL8wep8OTqKOqruVLVPzZyYZkBtn4XOFi6UE8WKiSVdK1Am1O5UxvlD95t32eYch6wQ9azgMqja6spe/L5UJgP83QZFknVC3wPZWkjqomVFql0FpaQclENwyY/OZMxr0cT/f7bCL6s4A/1XpbsGmC0xak4/THHbOn+0LdIej2nGV8JFoR ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxtdyg2ZRXE70UwyPVUH3UyfDBV8GX5cPF636P6hjom ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICHxEyUTOVHXvdMFARedFQ+H9DW/n8Zy3daKKRqnTDMq +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOiyJJwf+hFJrOkik9IQVxjhhVnI1vKl4BGLj03erLvw4TXXwoZzlPx6J936fU9JvvPw+d8PA4viMEfFbmdbHREKhwi3u1vZrfj0mB8SXw96AcZwX8PAL556wgom+/Qx+Q== diff --git a/tests/openssh_server/ca_ecdsa b/tests/openssh_server/ca_ecdsa new file mode 100644 index 00000000..d6b670c5 --- /dev/null +++ b/tests/openssh_server/ca_ecdsa @@ -0,0 +1,12 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS +1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAfv15s+G2xg56J+audKAM4G9qOTFr +bZRo0CTwvkb/oHrf9/2RSWqYsx/0m5mYCZVlecnZqwRHAOolXbc/Yb4cGjsALUj3UDirsn +YR7Ve+SwnunkpvW/H3a98sA3sS+HCpd5RbpfWClSBOI9JEAlPtS1CrEQ7EmO7hmlFOH2cL +0qfHCyYAAAEA763VSe+t1UkAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ +AAAIUEAH79ebPhtsYOeifmrnSgDOBvajkxa22UaNAk8L5G/6B63/f9kUlqmLMf9JuZmAmV +ZXnJ2asERwDqJV23P2G+HBo7AC1I91A4q7J2Ee1XvksJ7p5Kb1vx92vfLAN7EvhwqXeUW6 +X1gpUgTiPSRAJT7UtQqxEOxJju4ZpRTh9nC9KnxwsmAAAAQgD8VJwi9RHYN13CAfhvdmjW +xVjH55J5jDjPlENU2Z+cnm01SQ+9mPFEY4wDSvfiovD1VstNJX/P97WbHw+e5XL+HwAAAA +JDQQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/openssh_server/ca_ecdsa.pub b/tests/openssh_server/ca_ecdsa.pub new file mode 100644 index 00000000..5086eabe --- /dev/null +++ b/tests/openssh_server/ca_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAB+/Xmz4bbGDnon5q50oAzgb2o5MWttlGjQJPC+Rv+get/3/ZFJapizH/SbmZgJlWV5ydmrBEcA6iVdtz9hvhwaOwAtSPdQOKuydhHtV75LCe6eSm9b8fdr3ywDexL4cKl3lFul9YKVIE4j0kQCU+1LUKsRDsSY7uGaUU4fZwvSp8cLJg== CA diff --git a/tests/signed_key_ecdsa b/tests/signed_key_ecdsa new file mode 100644 index 00000000..1e08cfd7 --- /dev/null +++ b/tests/signed_key_ecdsa @@ -0,0 +1,10 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS +1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRv1/fnN1SuIkg222jYnySqIJ88J5M3 +bB6JGeloKhIvnZdPOSVFuFBjuF7NPrGrsm87QstQFbDiLhIlcDNHIq0VhS5itHNMjtC6Ym +RRx7mlQSXPbRRF5MclxvDJCMyAIagAAADQekojnXpKI50AAAATZWNkc2Etc2hhMi1uaXN0 +cDM4NAAAAAhuaXN0cDM4NAAAAGEEb9f35zdUriJINtto2J8kqiCfPCeTN2weiRnpaCoSL5 +2XTzklRbhQY7hezT6xq7JvO0LLUBWw4i4SJXAzRyKtFYUuYrRzTI7QumJkUce5pUElz20U +ReTHJcbwyQjMgCGoAAAAMQDmng9vaqXjHAhRssuBHeQylRKRwzOYOaToF8f+O0NmpmfLnc +/c2wOcXf2f9GBAQdYAAAAAAQIDBAUGBw== +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/signed_key_ecdsa-cert.pub b/tests/signed_key_ecdsa-cert.pub new file mode 100644 index 00000000..ee32719b --- /dev/null +++ b/tests/signed_key_ecdsa-cert.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAzODQtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgQCXc1JaqZ4XzkudbzP/pgEUbkioo7pl9aB09h6sg7KYAAAAIbmlzdHAzODQAAABhBG/X9+c3VK4iSDbbaNifJKognzwnkzdsHokZ6WgqEi+dl085JUW4UGO4Xs0+sauybztCy1AVsOIuEiVwM0cirRWFLmK0c0yO0LpiZFHHuaVBJc9tFEXkxyXG8MkIzIAhqAAAAAAAAAABAAAAAQAAAAhpZGVudGl0eQAAAAsAAAAHbGlic3NoMgAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAArAAAABNlY2RzYS1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAfv15s+G2xg56J+audKAM4G9qOTFrbZRo0CTwvkb/oHrf9/2RSWqYsx/0m5mYCZVlecnZqwRHAOolXbc/Yb4cGjsALUj3UDirsnYR7Ve+SwnunkpvW/H3a98sA3sS+HCpd5RbpfWClSBOI9JEAlPtS1CrEQ7EmO7hmlFOH2cL0qfHCyYAAACnAAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAACMAAAAQgGxnhh8z8LNk5pMw0D9InyEtVRm8OJi23XEhqj/ieT/BsLZXbu65UAcMjrUn6DPdERxF9Dwe9pdIAWOLLjLHYEFBQAAAEIAlxz+XjUKa9Q2vpH0y8IgJMm0H1hTBUM1DQEoL8No1BVtgtIO20mac2fE3I35JxNDmmXoW+FuzmJnyrY9rxY+YXM= ./signed_key_ecdsa.pub diff --git a/tests/signed_key_ecdsa.pub b/tests/signed_key_ecdsa.pub new file mode 100644 index 00000000..3b208f8a --- /dev/null +++ b/tests/signed_key_ecdsa.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBG/X9+c3VK4iSDbbaNifJKognzwnkzdsHokZ6WgqEi+dl085JUW4UGO4Xs0+sauybztCy1AVsOIuEiVwM0cirRWFLmK0c0yO0LpiZFHHuaVBJc9tFEXkxyXG8MkIzIAhqA== diff --git a/tests/test_public_key_auth_succeeds_with_correct_ecdsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_ecdsa_key.c new file mode 100644 index 00000000..2ea3a369 --- /dev/null +++ b/tests/test_public_key_auth_succeeds_with_correct_ecdsa_key.c @@ -0,0 +1,38 @@ +#include "session_fixture.h" + +#include + +#include + +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; +static const char *KEY_FILE_PRIVATE = "key_ecdsa"; +static const char *KEY_FILE_PUBLIC = "key_ecdsa.pub"; + +int test(LIBSSH2_SESSION *session) +{ + int rc; + const char *userauth_list = NULL; + + userauth_list = libssh2_userauth_list(session, USERNAME, strlen(USERNAME)); + if(userauth_list == NULL) { + print_last_session_error("libssh2_userauth_list"); + return 1; + } + + if(strstr(userauth_list, "publickey") == NULL) { + fprintf(stderr, "'publickey' was expected in userauth list: %s\n", + userauth_list); + return 1; + } + + rc = libssh2_userauth_publickey_fromfile_ex( + session, USERNAME, strlen(USERNAME), KEY_FILE_PUBLIC, KEY_FILE_PRIVATE, + NULL); + if(rc != 0) { + print_last_session_error("libssh2_userauth_publickey_fromfile_ex"); + return 1; + } + + return 0; +} diff --git a/tests/test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c b/tests/test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c new file mode 100644 index 00000000..10b33cbb --- /dev/null +++ b/tests/test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c @@ -0,0 +1,38 @@ +#include "session_fixture.h" + +#include + +#include + +/* configured in Dockerfile */ +static const char *USERNAME = "libssh2"; +static const char *KEY_FILE_PRIVATE = "signed_key_ecdsa"; +static const char *KEY_FILE_PUBLIC = "signed_key_ecdsa-cert.pub"; + +int test(LIBSSH2_SESSION *session) +{ + int rc; + const char *userauth_list = NULL; + + userauth_list = libssh2_userauth_list(session, USERNAME, strlen(USERNAME)); + if(userauth_list == NULL) { + print_last_session_error("libssh2_userauth_list"); + return 1; + } + + if(strstr(userauth_list, "publickey") == NULL) { + fprintf(stderr, "'publickey' was expected in userauth list: %s\n", + userauth_list); + return 1; + } + + rc = libssh2_userauth_publickey_fromfile_ex( + session, USERNAME, strlen(USERNAME), KEY_FILE_PUBLIC, KEY_FILE_PRIVATE, + NULL); + if(rc != 0) { + print_last_session_error("libssh2_userauth_publickey_fromfile_ex"); + return 1; + } + + return 0; +} From 36fcd543d939b51595bd614a02e207da0300d46f Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 12 May 2021 09:14:09 -0700 Subject: [PATCH 083/102] packet.c: Reset read timeout after received a packet (#576) (#586) File: packet.c Notes: Attempt keyboard interactive login (Azure AD 2FA login) and use more than 60 seconds to complete the login, the connection fails. The _libssh2_packet_require function does almost the same as _libssh2_packet_requirev but this function sets state->start = 0 before returning. Credit: teottin, Co-authored-by: Tor Erik Ottinsen --- src/packet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/packet.c b/src/packet.c index 9897f777..04937d62 100644 --- a/src/packet.c +++ b/src/packet.c @@ -1323,9 +1323,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, + int ret = _libssh2_packet_askv(session, packet_types, data, data_len, match_ofs, match_buf, match_len); + state->start = 0; + return ret; } } From 8adbab3f6c0af207e9e88e0f8f220dfebde915d0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 15 May 2021 17:57:03 +0200 Subject: [PATCH 084/102] dist: add src/agent.h Fixes #597 Closes #599 --- Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.inc b/Makefile.inc index 87d26bbd..20d2ebee 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -4,4 +4,4 @@ CSOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c misc.c \ blowfish.c bcrypt_pbkdf.c agent_win.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 + mac.h misc.h packet.h userauth.h session.h sftp.h crypto.h blf.h agent.h From 62bc25c987ffe6062d7f63e19de72a33bd0739f7 Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Mon, 17 May 2021 18:11:10 +0200 Subject: [PATCH 085/102] Makefile.am: Add missing test keys in the distribution tarball (#601) Notes: Fix tests missing key to build the OCI image Credit: Laurent Stacul --- tests/Makefile.am | 90 +++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index bf79c145..6cd7934d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -18,47 +18,51 @@ check_PROGRAMS = $(ctests) TESTS_ENVIRONMENT = SSHD=$(SSHD) EXEEXT=$(EXEEXT) TESTS_ENVIRONMENT += srcdir=$(top_srcdir)/tests builddir=$(top_builddir)/tests -EXTRA_DIST = \ - CMakeLists.txt \ - etc/host \ - etc/host.pub \ - etc/user \ - etc/user.pub \ - key_dsa \ - key_dsa.pub \ - key_dsa_wrong \ - key_dsa_wrong.pub \ - key_rsa \ - key_rsa.pub \ - libssh2_config_cmake.h.in \ - mansyntax.sh \ - openssh_fixture.c \ - openssh_fixture.h \ - openssh_server/authorized_keys \ - openssh_server/Dockerfile \ - openssh_server/ssh_host_rsa_key \ - runner.c \ - session_fixture.c \ - session_fixture.h \ - simple.c \ - ssh2.c \ - ssh2.sh \ - sshd_fixture.sh.in \ - test_agent_forward_succeeds.c \ - test_hostkey.c \ - test_hostkey_hash.c \ - test_keyboard_interactive_auth_fails_with_wrong_response.c \ - test_keyboard_interactive_auth_succeeds_with_correct_response.c \ - test_password_auth_fails_with_wrong_password.c \ - test_password_auth_fails_with_wrong_username.c \ - test_password_auth_succeeds_with_correct_credentials.c \ - test_public_key_auth_fails_with_wrong_key.c \ - test_public_key_auth_succeeds_with_correct_dsa_key.c \ - test_public_key_auth_succeeds_with_correct_ed25519_key.c \ - test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c \ - test_public_key_auth_succeeds_with_correct_ecdsa_key.c \ - test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c \ - test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c \ - test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c \ - test_public_key_auth_succeeds_with_correct_rsa_key.c \ +EXTRA_DIST = \ + CMakeLists.txt \ + etc/host \ + etc/host.pub \ + etc/user \ + etc/user.pub \ + key_dsa \ + key_dsa.pub \ + key_dsa_wrong \ + key_dsa_wrong.pub \ + key_rsa \ + key_rsa.pub \ + libssh2_config_cmake.h.in \ + mansyntax.sh \ + openssh_fixture.c \ + openssh_fixture.h \ + openssh_server/Dockerfile \ + openssh_server/authorized_keys \ + openssh_server/ca_ecdsa \ + openssh_server/ca_ecdsa.pub \ + openssh_server/ssh_host_ecdsa_key \ + openssh_server/ssh_host_ed25519_key \ + openssh_server/ssh_host_rsa_key \ + runner.c \ + session_fixture.c \ + session_fixture.h \ + simple.c \ + ssh2.c \ + ssh2.sh \ + sshd_fixture.sh.in \ + test_agent_forward_succeeds.c \ + test_hostkey.c \ + test_hostkey_hash.c \ + test_keyboard_interactive_auth_fails_with_wrong_response.c \ + test_keyboard_interactive_auth_succeeds_with_correct_response.c \ + test_password_auth_fails_with_wrong_password.c \ + test_password_auth_fails_with_wrong_username.c \ + test_password_auth_succeeds_with_correct_credentials.c \ + test_public_key_auth_fails_with_wrong_key.c \ + test_public_key_auth_succeeds_with_correct_dsa_key.c \ + test_public_key_auth_succeeds_with_correct_ed25519_key.c \ + test_public_key_auth_succeeds_with_correct_ed25519_key_from_mem.c \ + test_public_key_auth_succeeds_with_correct_ecdsa_key.c \ + test_public_key_auth_succeeds_with_correct_signed_ecdsa_key.c \ + test_public_key_auth_succeeds_with_correct_encrypted_ed25519_key.c \ + test_public_key_auth_succeeds_with_correct_encrypted_rsa_key.c \ + test_public_key_auth_succeeds_with_correct_rsa_key.c \ test_public_key_auth_succeeds_with_correct_rsa_openssh_key.c From f1f47ef79bb1b028ed46a4435be74291d7fd4afb Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Tue, 18 May 2021 17:18:06 +0200 Subject: [PATCH 086/102] tests: Makefile.am: Add missing tests client keys in distribution tarball (#604) Notes: Added missing test keys. Credit: Laurent Stacul --- tests/Makefile.am | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 6cd7934d..27ddc2df 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -28,8 +28,18 @@ EXTRA_DIST = \ key_dsa.pub \ key_dsa_wrong \ key_dsa_wrong.pub \ + key_ecdsa \ + key_ecdsa.pub \ + key_ed25519 \ + key_ed25519.pub \ + key_ed25519_encrypted \ + key_ed25519_encrypted.pub \ key_rsa \ key_rsa.pub \ + key_rsa_encrypted \ + key_rsa_encrypted.pub \ + key_rsa_openssh \ + key_rsa_openssh.pub \ libssh2_config_cmake.h.in \ mansyntax.sh \ openssh_fixture.c \ From 35ac220a4436df4ce50e990a02721369c9779ea9 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 26 May 2021 16:42:38 -0700 Subject: [PATCH 087/102] configure.ac: don't undefine scoped variable (#594) * configure.ac: don't undefine scoped variable To get this script to run with Autoconf 2.71 on macOS I had to remove the undefine of the backend for loop variable. It seems scoped to the for loop and also isn't referenced later in the script so it seems OK to remove it. * configure.ac: remove cygwin specific CFLAGS #598 Notes: Remove cygwin specific Win32 CFLAGS and treat the build like a posix build Credit: Will Cosgrove, Brian Inglis --- configure.ac | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index c9696ecc..c4fc3e4e 100644 --- a/configure.ac +++ b/configure.ac @@ -36,12 +36,9 @@ case "$host" in CFLAGS="$CFLAGS -DLIBSSH2_WIN32" LIBS="$LIBS -lws2_32" ;; - *-cygwin) - CFLAGS="$CFLAGS -DLIBSSH2_WIN32" + *darwin*) + CFLAGS="$CFLAGS -DLIBSSH2_DARWIN" ;; - *darwin*) - CFLAGS="$CFLAGS -DLIBSSH2_DARWIN" - ;; *hpux*) ;; *osf*) @@ -128,8 +125,6 @@ fi m4_set_foreach([crypto_backends], [backend], [AM_CONDITIONAL(m4_toupper(backend), test "$found_crypto" = "backend")] ) -m4_undefine([backend]) - # libz From 6f68e8d0647aa8971d163a031e3679ae5b858df9 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 26 May 2021 16:43:32 -0700 Subject: [PATCH 088/102] openssl.c: guards around calling FIPS_mode() #596 (#603) Notes: FIPS_mode() is not implemented in LibreSSL and this API is removed in OpenSSL 3.0 and was introduced in 0.9.7. Added guards around making this call. Credit: Will Cosgrove --- src/openssl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openssl.c b/src/openssl.c index 2ea9e1ba..7a6810f1 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -2230,8 +2230,14 @@ _libssh2_md5_init(libssh2_md5_ctx *ctx) * "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() != 0) return 0; +#endif + #ifdef HAVE_OPAQUE_STRUCTS *ctx = EVP_MD_CTX_new(); From fee3125b3b7472fd0ffeebccd9d3b402b532bc61 Mon Sep 17 00:00:00 2001 From: Marc Hoersken Date: Wed, 19 May 2021 20:50:46 +0200 Subject: [PATCH 089/102] CI/appveyor: run SSH server for tests on GitHub Actions (#607) No longer rely on DigitalOcean to host the Docker container. Unfortunately we require a small dispatcher script that has access to a GitHub access token with scope repo in order to trigger the daemon workflow on GitHub Actions also for PRs. This script is hosted by myself for the time being until GitHub provides a tighter scope to trigger the workflow_dispatch event. --- .github/workflows/appveyor.yml | 67 ++++++++++++++++++++++++++++++++++ appveyor.yml | 41 ++++++++++++++------- ci/appveyor/docker-bridge.bat | 10 +++++ ci/appveyor/docker-bridge.ps1 | 22 +++++++++++ tests/openssh_fixture.c | 17 ++++++++- 5 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/appveyor.yml create mode 100644 ci/appveyor/docker-bridge.bat create mode 100644 ci/appveyor/docker-bridge.ps1 diff --git a/.github/workflows/appveyor.yml b/.github/workflows/appveyor.yml new file mode 100644 index 00000000..f0fa0eaf --- /dev/null +++ b/.github/workflows/appveyor.yml @@ -0,0 +1,67 @@ +# Copyright (c) 2021 Marc Hoersken +# 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. +# +# 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 HOLDER 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. + +name: AppVeyor Docker Bridge + +on: + workflow_dispatch: + inputs: + ssh_host: + required: true + ssh_port: + required: true + ssh_user: + required: true + ssh_forward: + required: true + ssh_hostkey: + required: true + ssh_privkey: + required: true + +jobs: + daemon: + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - name: Setup SSH client configuration + run: | + cd ~ + mkdir .ssh + chmod 0700 .ssh + echo "ServerAliveInterval 45" > .ssh/config + echo "Host ${{ github.event.inputs.ssh_host }}" >> .ssh/config + echo "${{ github.event.inputs.ssh_forward }}" | sed 's/,/\n/g' | sed 's/^/\tRemoteForward /g' >> .ssh/config + chmod 0600 .ssh/config + cat .ssh/config + echo "${{ github.event.inputs.ssh_host }} ${{ github.event.inputs.ssh_hostkey }}" | sed 's/,/\n${{ github.event.inputs.ssh_host }} /g' > .ssh/known_hosts + chmod 0600 .ssh/known_hosts + cat .ssh/known_hosts + echo "${{ github.event.inputs.ssh_privkey }}" | sed 's/,/\n/g' > .ssh/id_rsa + chmod 0600 .ssh/id_rsa + + # we sleep explicitly to allow the remote system to kill the sleep process + - name: Connect to AppVeyor and sleep + run: | + ssh -v -p ${{ github.event.inputs.ssh_port }} ${{ github.event.inputs.ssh_user }}@${{ github.event.inputs.ssh_host }} sleep 1h diff --git a/appveyor.yml b/appveyor.yml index 08e60c1b..c2731ca2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,6 @@ # Copyright (c) 2014, Ruslan Baratov # Copyright (c) 2014, 2016 Alexander Lamaison +# Copyright (c) 2020, 2021 Marc Hoersken # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -59,9 +60,6 @@ environment: BUILD_SHARED_LIBS: OFF CRYPTO_BACKEND: "WinCNG" - digitalocean_access_token: - secure: 8qRitvrj69Xhf0Tmu27xnz5drmL2YhmOJLGpXIkYyTCC0JNtBoXW6fMcF3u4Uj1+pIQ+TjegQOwYimlz0oivKTro3v3EXro+osAMNJG6NKc= - platform: - x86 - x64 @@ -77,8 +75,12 @@ matrix: platform: x64 install: - - choco install -y docker - - choco install -y docker-machine + # prepare local SSH server for reverse tunneling from GitHub Actions hosting our docker container + - ps: | + $env:OPENSSH_SERVER_PORT = Get-Random -Minimum 2000 -Maximum 2300 + [System.Environment]::SetEnvironmentVariable("OPENSSH_SERVER_PORT", $env:OPENSSH_SERVER_PORT) + - ps: .\ci\appveyor\docker-bridge.ps1 + - choco install -y docker-cli build_script: - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } @@ -86,23 +88,34 @@ build_script: - cmake --build _builds --config "%CONFIGURATION%" before_test: - - set DOCKER_MACHINE_NAME=appveyor-%APPVEYOR_PROJECT_SLUG%-%APPVEYOR_JOB_ID% - - ps: if($env:digitalocean_access_token) { echo "Using DigitalOcean for testing." } else { echo "DigitalOcean not available. Skipping testing." } - - ps: if($env:digitalocean_access_token) { docker-machine create --driver digitalocean --digitalocean-access-token $($env:digitalocean_access_token) $($env:DOCKER_MACHINE_NAME) } - - ps: if($env:digitalocean_access_token) { docker-machine env $($env:DOCKER_MACHINE_NAME) --shell powershell | Invoke-Expression } + - ps: | + Write-Host "Waiting for SSH connection from GitHub Actions" -NoNewline + while((Get-Process -Name "sshd" -ErrorAction SilentlyContinue).Count -eq 1) { + Write-Host "." -NoNewline + Start-Sleep -Seconds 1 + } + if((Get-Process -Name "sshd" -ErrorAction SilentlyContinue).Count -gt 1) { + $env:DOCKER_HOST = "tcp://127.0.0.1:2375" + [System.Environment]::SetEnvironmentVariable("DOCKER_HOST", $env:DOCKER_HOST) + Write-Host "... ready!" + } else { + Write-Host "... failed!" + } test_script: - ps: cd _builds - - ps: if($env:digitalocean_access_token) { ctest -VV -C $($env:CONFIGURATION) --output-on-failure } - -after_test: - - ps: if($env:digitalocean_access_token) { docker-machine rm -y $($env:DOCKER_MACHINE_NAME) } + - ps: ctest -VV -C $($env:CONFIGURATION) --output-on-failure on_failure: - - ps: if($env:digitalocean_access_token) { docker-machine rm -y $($env:DOCKER_MACHINE_NAME) } - ps: if(Test-Path _builds/CMakeFiles/CMakeOutput.log) { cat _builds/CMakeFiles/CMakeOutput.log } - ps: if(Test-Path _builds/CMakeFiles/CMakeError.log) { cat _builds/CMakeFiles/CMakeError.log } +on_finish: + - ps: | + Get-Process -Name "sleep" -ErrorAction SilentlyContinue | Stop-Process + Start-Sleep -Seconds 3 + Get-Process -Name "sshd" -ErrorAction SilentlyContinue | Stop-Process + # whitelist branches to avoid testing feature branches twice (as branch and as pull request) branches: only: diff --git a/ci/appveyor/docker-bridge.bat b/ci/appveyor/docker-bridge.bat new file mode 100644 index 00000000..e83b285d --- /dev/null +++ b/ci/appveyor/docker-bridge.bat @@ -0,0 +1,10 @@ +@echo off + +netsh interface portproxy add v4tov4 listenport=3389 listenaddress=%1 connectport=22 connectaddress=127.0.0.1 +netsh interface portproxy show all + +C:\msys64\usr\bin\sh -l -c "/usr/bin/ssh-keygen -b 2048 -t rsa -f auth -q -N '' && mkdir .ssh && mv auth.pub .ssh/authorized_keys" +C:\msys64\usr\bin\sh -l -c "/usr/bin/ssh-keygen -A" +C:\msys64\usr\bin\sh -l -c "/usr/bin/sshd" + +C:\msys64\usr\bin\sh -l -c '/usr/bin/curl -F "account=%APPVEYOR_ACCOUNT_NAME%" -F "project=%APPVEYOR_PROJECT_SLUG%" -F "buildid=%APPVEYOR_BUILD_VERSION%" -F "base=%APPVEYOR_REPO_BRANCH%" -F "hash=%APPVEYOR_REPO_COMMIT%" -F "repo=%APPVEYOR_REPO_NAME%" -F "ssh_host=%2" -F "ssh_port=%3" -F "ssh_user=`whoami`" -F "ssh_forward=127.0.0.1:%OPENSSH_SERVER_PORT% 127.0.0.1:%OPENSSH_SERVER_PORT%,127.0.0.1:2375 /var/run/docker.sock" -F "ssh_hostkey=`paste -d , /etc/ssh/ssh_host_*_key.pub`" -F "ssh_privkey=`paste -sd , auth`" -s "https://stuff.marc-hoersken.de/libssh2/dispatch.php"' diff --git a/ci/appveyor/docker-bridge.ps1 b/ci/appveyor/docker-bridge.ps1 new file mode 100644 index 00000000..03dbf7dd --- /dev/null +++ b/ci/appveyor/docker-bridge.ps1 @@ -0,0 +1,22 @@ +# Partially copied from https://github.com/appveyor/ci/blob/master/scripts/enable-rdp.ps1 + +# get current IP +$ip = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.InterfaceAlias -like 'ethernet*'}).IPAddress +$port = 3389 +if($ip.StartsWith('172.24.')) { + $port = 33800 + ($ip.split('.')[2] - 16) * 256 + $ip.split('.')[3] +} elseif ($ip.StartsWith('192.168.') -or $ip.StartsWith('10.240.')) { + # new environment - behind NAT + $port = 33800 + ($ip.split('.')[2] - 0) * 256 + $ip.split('.')[3] +} elseif ($ip.StartsWith('10.0.')) { + $port = 33800 + ($ip.split('.')[2] - 0) * 256 + $ip.split('.')[3] +} + +# get external IP +$extip = (New-Object Net.WebClient).DownloadString('https://www.appveyor.com/tools/my-ip.aspx').Trim() + +# allow inbound traffic +New-NetFirewallRule -DisplayName "SSH via RDP port" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 22,3389 + +# launch remote docker daemon with reverse SSH tunnel +& .\ci\appveyor\docker-bridge.bat $ip $extip $port diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index f5ee5ef0..631ed538 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -149,10 +149,23 @@ static int build_openssh_server_docker_image(void) "openssh_server"); } +static const char *openssh_server_port(void) +{ + return getenv("OPENSSH_SERVER_PORT"); +} + static int start_openssh_server(char **container_id_out) { - return run_command(container_id_out, - "docker run --detach -P libssh2/openssh_server"); + const char *container_host_port = openssh_server_port(); + if(container_host_port != NULL) { + return run_command(container_id_out, + "docker run -d -p %s:22 libssh2/openssh_server", + container_host_port); + } + else { + return run_command(container_id_out, + "docker run -d -p 22 libssh2/openssh_server"); + } } static int stop_openssh_server(char *container_id) From 718bcb03d267f974924f163eaf3adecb51b77ed0 Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Thu, 25 Feb 2021 13:55:51 +0000 Subject: [PATCH 090/102] Allow the tests to run inside a container The current tests suite starts SSH server as OCI container. This commit add the possibility to run the tests in a container provided that: * the docker client is installed builder container * the host docker daemon unix socket has been mounted in the builder container (with, if needed, the DOCKER_HOST environment variable accordingly set, and the permission to write on this socket) * the builder container is run on the default bridge network, or the host network. This PR does not handle the case where the builder container is on another network. --- tests/openssh_fixture.c | 64 ++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 631ed538..77fc3766 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -178,6 +178,34 @@ static const char *docker_machine_name(void) return getenv("DOCKER_MACHINE_NAME"); } +static int is_running_inside_a_container() +{ +#ifdef WIN32 + return 0; +#else + const char *cgroup_filename = "/proc/self/cgroup"; + FILE *f = NULL; + char *line = NULL; + size_t len = 0; + ssize_t read = 0; + int found = 0; + f = fopen(cgroup_filename, "r"); + if(f == NULL) { + /* Don't go further, we are not in a container */ + return 0; + } + while((read = getline(&line, &len, f)) != -1) { + if(strstr(line, "docker") != NULL) { + found = 1; + break; + } + } + fclose(f); + free(line); + return found; +#endif +} + static int ip_address_from_container(char *container_id, char **ip_address_out) { const char *active_docker_machine = docker_machine_name(); @@ -213,21 +241,37 @@ static int ip_address_from_container(char *container_id, char **ip_address_out) } } else { - return run_command(ip_address_out, - "docker inspect --format " - "\"{{ index (index (index .NetworkSettings.Ports " - "\\\"22/tcp\\\") 0) \\\"HostIp\\\" }}\" %s", - container_id); + if(is_running_inside_a_container()) { + return run_command(ip_address_out, + "docker inspect --format " + "\"{{ .NetworkSettings.IPAddress }}\"" + " %s", + container_id); + } + else { + return run_command(ip_address_out, + "docker inspect --format " + "\"{{ index (index (index " + ".NetworkSettings.Ports " + "\\\"22/tcp\\\") 0) \\\"HostIp\\\" }}\" %s", + container_id); + } } } static int port_from_container(char *container_id, char **port_out) { - return run_command(port_out, - "docker inspect --format " - "\"{{ index (index (index .NetworkSettings.Ports " - "\\\"22/tcp\\\") 0) \\\"HostPort\\\" }}\" %s", - container_id); + if(is_running_inside_a_container()) { + *port_out = strdup("22"); + return 0; + } + else { + return run_command(port_out, + "docker inspect --format " + "\"{{ index (index (index .NetworkSettings.Ports " + "\\\"22/tcp\\\") 0) \\\"HostPort\\\" }}\" %s", + container_id); + } } static int open_socket_to_container(char *container_id) From 3709037b2696350a87b41ddc05f2b88351ce7b72 Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Sun, 28 Feb 2021 06:50:33 +0000 Subject: [PATCH 091/102] Remove openssh_server container on test exit --- tests/openssh_fixture.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 77fc3766..2d6cb29a 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -159,12 +159,14 @@ static int start_openssh_server(char **container_id_out) const char *container_host_port = openssh_server_port(); if(container_host_port != NULL) { return run_command(container_id_out, - "docker run -d -p %s:22 libssh2/openssh_server", + "docker run --rm -d -p %s:22 " + "libssh2/openssh_server", container_host_port); } else { return run_command(container_id_out, - "docker run -d -p 22 libssh2/openssh_server"); + "docker run --rm -d -p 22 " + "libssh2/openssh_server"); } } From a88a727c2a1840f979b34f12bcce3d55dcd7ea6e Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Sat, 27 Feb 2021 10:06:20 +0000 Subject: [PATCH 092/102] [tests] Try several times to connect the ssh server Sometimes, as the OCI container is run in detached mode, it is possible the actual server is not ready yet to handle SSH traffic. The goal of this PR is to try several times (max 3). The mechanism is the same as for the connection to the docker machine. --- tests/openssh_fixture.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 2d6cb29a..0480c5d5 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -208,6 +208,15 @@ static int is_running_inside_a_container() #endif } +static unsigned int portable_sleep(unsigned int seconds) +{ +#ifdef WIN32 + Sleep(seconds); +#else + sleep(seconds); +#endif +} + static int ip_address_from_container(char *container_id, char **ip_address_out) { const char *active_docker_machine = docker_machine_name(); @@ -232,11 +241,7 @@ static int ip_address_from_container(char *container_id, char **ip_address_out) return -1; } else { -#ifdef WIN32 - Sleep(wait_time); -#else - sleep(wait_time); -#endif + portable_sleep(wait_time); ++attempt_no; wait_time *= 2; } @@ -283,6 +288,7 @@ static int open_socket_to_container(char *container_id) unsigned long hostaddr; int sock; struct sockaddr_in sin; + int counter = 0; int ret = ip_address_from_container(container_id, &ip_address); if(ret != 0) { @@ -325,16 +331,26 @@ static int open_socket_to_container(char *container_id) sin.sin_port = htons((short)strtol(port_string, NULL, 0)); sin.sin_addr.s_addr = hostaddr; - if(connect(sock, (struct sockaddr *)(&sin), - sizeof(struct sockaddr_in)) != 0) { + for(counter = 0; counter < 3; ++counter) { + if(connect(sock, (struct sockaddr *)(&sin), + sizeof(struct sockaddr_in)) != 0) { + ret = -1; + fprintf(stderr, + "Connection to %s:%s attempt #%d failed: retrying...\n", + ip_address, port_string, counter); + portable_sleep(1 + 2*counter); + } + else { + ret = sock; + break; + } + } + if(ret == -1) { fprintf(stderr, "Failed to connect to %s:%s\n", ip_address, port_string); - ret = -1; goto cleanup; } - ret = sock; - cleanup: free(ip_address); free(port_string); From 635caa90787220ac3773c1d5ba11f1236c22eae8 Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Wed, 12 May 2021 11:09:59 -0700 Subject: [PATCH 093/102] updated docs for 1.10.0 release --- COPYING | 2 +- RELEASE-NOTES | 94 ++++++++++++-------- docs/{HACKING.CRYPTO => HACKING-CRYPTO} | 112 ++++++++++++------------ docs/Makefile.am | 2 +- vms/libssh2_make_help.dcl | 24 ++--- 5 files changed, 126 insertions(+), 108 deletions(-) rename docs/{HACKING.CRYPTO => HACKING-CRYPTO} (92%) diff --git a/COPYING b/COPYING index 4852a889..937ed32e 100644 --- a/COPYING +++ b/COPYING @@ -2,7 +2,7 @@ * Copyright (c) 2005,2006 Mikhail Gusarov * Copyright (c) 2006-2007 The Written Word, Inc. * Copyright (c) 2007 Eli Fant - * Copyright (c) 2009-2019 Daniel Stenberg + * Copyright (c) 2009-2021 Daniel Stenberg * Copyright (C) 2008, 2009 Simon Josefsson * Copyright (c) 2000 Markus Friedl * Copyright (c) 2015 Microsoft Corp. diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 98cb8033..62064a9f 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,44 +1,62 @@ -libssh2 1.9.0 +libssh2 1.10 This release includes the following enhancements and bugfixes: - - o adds ECDSA keys and host key support when using OpenSSL - o adds ED25519 key and host key support when using OpenSSL 1.1.1 - o adds OpenSSH style key file reading - o adds AES CTR mode support when using WinCNG - o adds PEM passphrase protected file support for Libgcrypt and WinCNG - o adds SHA256 hostkey fingerprint - o adds libssh2_agent_get_identity_path() and libssh2_agent_set_identity_path() - o adds explicit zeroing of sensitive data in memory - o adds additional bounds checks to network buffer reads - o adds the ability to use the server default permissions when creating sftp directories - o adds support for building with OpenSSL no engine flag - o adds support for building with LibreSSL - o increased sftp packet size to 256k - o fixed oversized packet handling in sftp - o fixed building with OpenSSL 1.1 - o fixed a possible crash if sftp stat gets an unexpected response - o fixed incorrect parsing of the KEX preference string value - o fixed conditional RSA and AES-CTR support - o fixed a small memory leak during the key exchange process - o fixed a possible memory leak of the ssh banner string - o fixed various small memory leaks in the backends - o fixed possible out of bounds read when parsing public keys from the server - o fixed possible out of bounds read when parsing invalid PEM files - o no longer null terminates the scp remote exec command - o now handle errors when diffie hellman key pair generation fails - o fixed compiling on Windows with the flag STDCALL=ON - o improved building instructions + + o adds agent forwarding support + o adds OpenSSH Agent support on Windows + o adds ECDSA key support using the Mbed TLS backend + o adds ECDSA cert authentication + o adds diffie-hellman-group14-sha256, diffie-hellman-group16-sha512, + diffie-hellman-group18-sha512 key exchanges + o adds support for PKIX key reading when using ed25519 with OpenSSL + o adds support for EWOULDBLOCK on VMS systems + o adds support for building with OpenSSL 3 + o adds support for using FIPS mode in OpenSSL + o adds debug symbols when building with MSVC + o adds support for building on the 3DS + o adds unicode build support on Windows + o restores os400 building + o increases min, max and opt Diffie Hellman group values + o improves portiablity of the make file + o improves timeout behavior with 2FA keyboard auth + o various improvements to the Wincng backend + o fixes reading parital packet replies when using an agent + o fixes Diffie Hellman key exchange on Windows 1903+ builds + o fixes building tests with older versions of OpenSSL + o fixes possible multiple definition warnings + o fixes potential cast issues _libssh2_ecdsa_key_get_curve_type() + o fixes potential use after free if libssh2_init() is called twice + o improved linking when using Mbed TLS + o fixes call to libssh2_crypto_exit() if crypto hasn't been initialized + o fixes crash when loading public keys with no id + o fixes possible out of bounds read when exchanging keys + o fixes possible out of bounds read when reading packets + o fixes possible out of bounds read when opening an X11 connection + o fixes possible out of bounds read when ecdh host keys + o fixes possible hang when trying to read a disconnected socket + o fixes a crash when using the delayed compression option + o fixes read error with large known host entries + o fixes various warnings + o fixes various small memory leaks + o improved error handling, various detailed errors will now be reported + o builds are now using OSS-Fuzz + o builds now use autoreconf instead of a custom build script + o cmake now respects install directory + o improved CI backend + o updated HACKING-CRYPTO documentation + o use markdown file extensions o improved unit tests - + This release would not have looked like this without help, code, reports and advice from friends like these: - Peter Surge, Will Cosgrove, Daniel Stenberg, Alex Arslan, Alex Crichton, - Thomas Bleeker, Keno Fischer, Marc Hörsken, Marcel Raad, Viktor Szakats, - Kamil Dudka, Panos, Etienne Samson, Tseng Jun, Brendan Shanks, doublex, - Erik B, Jakob Egger, Thomas Lochmatter, alex-weaver, Adrian Moran, Zenju, - gartens, Matthew D. Fuller, Ryan Kelley, Zhen-Huan HWANG, Orivej Desh, - Alexander Curtiss - - (29 contributors) + katzer, Orgad Shaneh, mark-i-m, Zenju, axjowa, Thilo Schulz, + Etienne Samson, hlefebvre, seba30, Panos, jethrogb, Fabrice Fontaine, + Will Cosgrove, Daniel Stenberg, Michael Buckley, Wallace Souza Silva, + Romain-Geissler-1A, meierha, Tseng Jun, Thomas Klausner, Brendan Shanks, + Harry Sintonen, monnerat, Koutheir Attouchi, Marc Hörsken, yann-morin-1998, + Wez Furlong, TDi-jonesds, David Benjamin, Max Dymond, Igor Klevanets, + Viktor Szakats, Laurent Stacul, Mstrodl, Gabriel Smith, MarcT512, + Paul Capron, teottin, Tor Erik Ottinsen, Brian Inglis + + (40 contributors) diff --git a/docs/HACKING.CRYPTO b/docs/HACKING-CRYPTO similarity index 92% rename from docs/HACKING.CRYPTO rename to docs/HACKING-CRYPTO index ea2530bb..ca947728 100644 --- a/docs/HACKING.CRYPTO +++ b/docs/HACKING-CRYPTO @@ -1,4 +1,4 @@ - Definitions needed to implement a specific crypto library + Definitions needed to implement a specific crypto library This document offers some hints about implementing a new crypto library interface. @@ -67,14 +67,14 @@ Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_hmac_update(libssh2_hmac_ctx ctx, - const unsigned char *data, - int datalen); + const unsigned char *data, + int datalen); Continue computation of an HMAC on datalen bytes at data using context ctx. Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_hmac_final(libssh2_hmac_ctx ctx, - unsigned char output[]); + unsigned char output[]); Get the computed HMAC from context ctx into the output buffer. The minimum data buffer size depends on the HMAC hash algorithm. Note: if the ctx parameter is modified by the underlying code, @@ -100,8 +100,8 @@ Initializes the SHA-1 computation context at x. Returns 1 for success and 0 for failure void libssh2_sha1_update(libssh2_sha1_ctx ctx, - const unsigned char *data, - size_t len); + const unsigned char *data, + size_t len); Continue computation of SHA-1 on len bytes at data using context ctx. Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. @@ -115,8 +115,8 @@ Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx, - const void *key, - int keylen); + const void *key, + int keylen); Setup the HMAC computation context ctx for an HMAC-SHA-1 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). @@ -134,14 +134,14 @@ Initializes the SHA-256 computation context at x. Returns 1 for success and 0 for failure void libssh2_sha256_update(libssh2_sha256_ctx ctx, - const unsigned char *data, - size_t len); + const unsigned char *data, + size_t len); Continue computation of SHA-256 on len bytes at data using context ctx. Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_sha256_final(libssh2_sha256_ctx ctx, - unsigned char output[SHA256_DIGEST_LENGTH]); + unsigned char output[SHA256_DIGEST_LENGTH]); Gets the computed SHA-256 signature from context ctx into the output buffer. Release the context. Note: if the ctx parameter is modified by the underlying code, @@ -160,8 +160,8 @@ LIBSSH2_HMAC_SHA256 If defined as 0, the rest of this section can be omitted. void libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx, - const void *key, - int keylen); + const void *key, + int keylen); Setup the HMAC computation context ctx for an HMAC-256 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). @@ -179,14 +179,14 @@ Initializes the SHA-384 computation context at x. Returns 1 for success and 0 for failure void libssh2_sha384_update(libssh2_sha384_ctx ctx, - const unsigned char *data, - size_t len); + const unsigned char *data, + size_t len); Continue computation of SHA-384 on len bytes at data using context ctx. Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_sha384_final(libssh2_sha384_ctx ctx, - unsigned char output[SHA384_DIGEST_LENGTH]); + unsigned char output[SHA384_DIGEST_LENGTH]); Gets the computed SHA-384 signature from context ctx into the output buffer. Release the context. Note: if the ctx parameter is modified by the underlying code, @@ -213,14 +213,14 @@ Initializes the SHA-512 computation context at x. Returns 1 for success and 0 for failure void libssh2_sha512_update(libssh2_sha512_ctx ctx, - const unsigned char *data, - size_t len); + const unsigned char *data, + size_t len); Continue computation of SHA-512 on len bytes at data using context ctx. Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_sha512_final(libssh2_sha512_ctx ctx, - unsigned char output[SHA512_DIGEST_LENGTH]); + unsigned char output[SHA512_DIGEST_LENGTH]); Gets the computed SHA-512 signature from context ctx into the output buffer. Release the context. Note: if the ctx parameter is modified by the underlying code, @@ -239,8 +239,8 @@ LIBSSH2_HMAC_SHA512 If defined as 0, the rest of this section can be omitted. void libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx, - const void *key, - int keylen); + const void *key, + int keylen); Setup the HMAC computation context ctx for an HMAC-512 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). @@ -260,23 +260,23 @@ Initializes the MD5 computation context at x. Returns 1 for success and 0 for failure void libssh2_md5_update(libssh2_md5_ctx ctx, - const unsigned char *data, - size_t len); + const unsigned char *data, + size_t len); Continues computation of MD5 on len bytes at data using context ctx. Returns 1 for success and 0 for failure. Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_md5_final(libssh2_md5_ctx ctx, - unsigned char output[MD5_DIGEST_LENGTH]); + unsigned char output[MD5_DIGEST_LENGTH]); Gets the computed MD5 signature from context ctx into the output buffer. Release the context. Note: if the ctx parameter is modified by the underlying code, this procedure must be implemented as a macro to map ctx --> &ctx. void libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx, - const void *key, - int keylen); + const void *key, + int keylen); Setup the HMAC computation context ctx for an HMAC-MD5 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). @@ -286,8 +286,8 @@ LIBSSH2_HMAC_RIPEMD If defined as 0, the rest of this section can be omitted. void libssh2_hmac_ripemd160_init(libssh2_hmac_ctx *ctx, - const void *key, - int keylen); + const void *key, + int keylen); Setup the HMAC computation context ctx for an HMAC-RIPEMD-160 computation using the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init(). Returns 1 for success and 0 for failure. @@ -476,7 +476,7 @@ Sets the value of bn to val. Returns 1 on success, 0 otherwise. _libssh2_bn * _libssh2_bn_from_bin(_libssh2_bn *bn, int len, - const unsigned char *val); + const unsigned char *val); Converts the positive integer in big-endian form of length len at val into a _libssh2_bn and place it in bn. If bn is NULL, a new _libssh2_bn is created. @@ -569,14 +569,14 @@ int _libssh2_rsa_new(libssh2_rsa_ctx **rsa, unsigned long e2len, const unsigned char *coeffdata, unsigned long coefflen); Creates a new context for RSA computations from key source values: - pdata, plen Prime number p. Only used if private key known (ddata). - qdata, qlen Prime number q. Only used if private key known (ddata). - ndata, nlen Modulus n. - edata, elen Exponent e. - ddata, dlen e^-1 % phi(n) = private key. May be NULL if unknown. - e1data, e1len dp = d % (p-1). Only used if private key known (dtata). - e2data, e2len dq = d % (q-1). Only used if private key known (dtata). - coeffdata, coefflen q^-1 % p. Only used if private key known. + pdata, plen Prime number p. Only used if private key known (ddata). + qdata, qlen Prime number q. Only used if private key known (ddata). + ndata, nlen Modulus n. + edata, elen Exponent e. + ddata, dlen e^-1 % phi(n) = private key. May be NULL if unknown. + e1data, e1len dp = d % (p-1). Only used if private key known (dtata). + e2data, e2len dq = d % (q-1). Only used if private key known (dtata). + coeffdata, coefflen q^-1 % p. Only used if private key known. Returns 0 if OK. This procedure is already prototyped in crypto.h. Note: the current generic code only calls this function with e and n (public @@ -595,7 +595,7 @@ This procedure is already prototyped in crypto.h. int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, LIBSSH2_SESSION *session, const char *data, - size_t data_len, + size_t data_len, unsigned const char *passphrase); Gets an RSA private key from data into a new RSA context. Must call _libssh2_init_if_needed(). @@ -612,9 +612,9 @@ Return 0 if OK, else -1. This procedure is already prototyped in crypto.h. int _libssh2_rsa_sha1_signv(LIBSSH2_SESSION *session, - unsigned char **sig, size_t *siglen, - int count, const struct iovec vector[], - libssh2_rsa_ctx *ctx); + unsigned char **sig, size_t *siglen, + int count, const struct iovec vector[], + libssh2_rsa_ctx *ctx); RSA signs the SHA-1 hash computed over the count data chunks in vector. Signature is stored at (sig, siglen). Signature buffer must be allocated from the given session. @@ -658,11 +658,11 @@ int _libssh2_dsa_new(libssh2_dsa_ctx **dsa, unsigned long ylen, const unsigned char *x, unsigned long x_len); Creates a new context for DSA computations from source key values: - pdata, plen Prime number p. Only used if private key known (ddata). - qdata, qlen Prime number q. Only used if private key known (ddata). - gdata, glen G number. - ydata, ylen Public key. - xdata, xlen Private key. Only taken if xlen non-zero. + pdata, plen Prime number p. Only used if private key known (ddata). + qdata, qlen Prime number q. Only used if private key known (ddata). + gdata, glen G number. + ydata, ylen Public key. + xdata, xlen Private key. Only taken if xlen non-zero. Returns 0 if OK. This procedure is already prototyped in crypto.h. @@ -678,7 +678,7 @@ This procedure is already prototyped in crypto.h. int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, LIBSSH2_SESSION *session, const char *data, - size_t data_len, + size_t data_len, unsigned const char *passphrase); Gets a DSA private key from the data_len-bytes data into a new DSA context. Must call _libssh2_init_if_needed(). @@ -721,9 +721,9 @@ Type of an elliptic curve key. libssh2_curve_type An enum type defining curve types. Current supported identifiers are: - LIBSSH2_EC_CURVE_NISTP256 - LIBSSH2_EC_CURVE_NISTP384 - LIBSSH2_EC_CURVE_NISTP521 + LIBSSH2_EC_CURVE_NISTP256 + LIBSSH2_EC_CURVE_NISTP384 + LIBSSH2_EC_CURVE_NISTP521 int _libssh2_ecdsa_create_key(_libssh2_ec_key **out_private_key, unsigned char **out_public_key_octal, @@ -746,10 +746,10 @@ Return 0 if OK, else -1. This procedure is already prototyped in crypto.h. 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); Builds an ECDSA private key from PEM data at filedata of length filedata_len into a new ECDSA context stored at ec_ctx. Must call _libssh2_init_if_needed(). @@ -844,7 +844,7 @@ This procedure is already prototyped in crypto.h. 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 uint8_t key_len); Stores at ed_ctx a new ED25519 key context for raw public key (raw_pub_key, key_len). Return 0 if OK, else -1. @@ -879,7 +879,7 @@ This procedure is already prototyped in crypto.h. int _libssh2_curve25519_gen_k(_libssh2_bn **k, uint8_t private_key[LIBSSH2_ED25519_KEY_LEN], uint8_t srvr_public_key[LIBSSH2_ED25519_KEY_LEN]); -Computes a shared ED25519 secret key from the given raw server public key and +Computes a shared ED25519 secret key from the given raw server public key and raw client public key and stores it as a big number in *k. Big number should have been initialized before calling this function. Returns 0 if OK, else -1. diff --git a/docs/Makefile.am b/docs/Makefile.am index 3d7ca821..a8094312 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -1,7 +1,7 @@ # $Id: Makefile.am,v 1.37 2009/03/26 15:41:15 bagder Exp $ EXTRA_DIST = template.3 BINDINGS INSTALL_AUTOTOOLS INSTALL_CMAKE.md HACKING TODO \ - AUTHORS CMakeLists.txt HACKING.CRYPTO SECURITY.md + AUTHORS CMakeLists.txt HACKING-CRYPTO SECURITY.md dist_man_MANS = \ libssh2_agent_connect.3 \ diff --git a/vms/libssh2_make_help.dcl b/vms/libssh2_make_help.dcl index b36512ec..652671da 100644 --- a/vms/libssh2_make_help.dcl +++ b/vms/libssh2_make_help.dcl @@ -29,7 +29,7 @@ $ man2help -a [-.docs]AUTHORS.; libssh2.hlp -b 2 $ man2help -a [-.docs]BINDINGS.; libssh2.hlp -b 2 $ man2help -a [-.docs]HACKING.; libssh2.hlp -b 2 $ if f$search("[]HACKING_CRYPTO.") .nes. "" then delete []HACKING_CRYPTO.;* -$ copy [-.docs]HACKING.CRYPTO; []HACKING_CRYPTO. +$ copy [-.docs]HACKING-CRYPTO; []HACKING_CRYPTO. $ man2help -a []HACKING_CRYPTO.; libssh2.hlp -b 2 $ man2help -a [-.docs]TODO.; libssh2.hlp -b 2 $! @@ -56,18 +56,18 @@ $! $ thisdir = f$environment( "procedure" ) $ thisdir = f$parse(thisdir,,,"device") + f$parse(thisdir,,,"directory") $ set default 'thisdir' -$! +$! $ say = "write sys$output" $! -$ pipe search [-.include]*.h libssh2_version_major/nohead | (read sys$input l ; l = f$element(2," ",f$edit(l,"trim,compress")) ; - +$ pipe search [-.include]*.h libssh2_version_major/nohead | (read sys$input l ; l = f$element(2," ",f$edit(l,"trim,compress")) ; - define/job majorv &l ) -$ pipe search [-.include]*.h libssh2_version_minor/nohead | (read sys$input l ; l = f$element(2," ",f$edit(l,"trim,compress")) ; - +$ pipe search [-.include]*.h libssh2_version_minor/nohead | (read sys$input l ; l = f$element(2," ",f$edit(l,"trim,compress")) ; - define/job minorv &l ) -$ pipe search [-.include]*.h libssh2_version_patch/nohead | (read sys$input l ; l = f$element(2," ",f$edit(l,"trim,compress")) ; - +$ pipe search [-.include]*.h libssh2_version_patch/nohead | (read sys$input l ; l = f$element(2," ",f$edit(l,"trim,compress")) ; - define/job patchv &l ) $! $ majorv = f$trnlnm("majorv") -$ minorv = f$integer(f$trnlnm("minorv")) +$ minorv = f$integer(f$trnlnm("minorv")) $ patchv = f$integer( f$trnlnm("patchv")) $! $ helpversion = "This help library is based on build version ''majorv'.''minorv'.''patchv' of libssh2." @@ -81,15 +81,15 @@ $ then $ cc man2help $ link man2help $ endif -$! -$ man2help := $'thisdir'man2help.exe $! -$ if f$search("libssh2.hlp") .nes. "" -$ then +$ man2help := $'thisdir'man2help.exe +$! +$ if f$search("libssh2.hlp") .nes. "" +$ then $ delete libssh2.hlp;* $ endif -$ if f$search("libssh2.hlb") .nes. "" -$ then +$ if f$search("libssh2.hlb") .nes. "" +$ then $ delete libssh2.hlb;* $ endif $return From a4fc97bf0a3859cf1d38d4bc2d85262c8c3fa9b2 Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Mon, 30 Aug 2021 18:59:27 +0200 Subject: [PATCH 094/102] Makefile.am: Add missing key in case openssl > 1.1.0 (#617) File: Makefile.am Notes: fix missing test keys Credit: Laurent Stacul --- tests/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 27ddc2df..582c9141 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -30,6 +30,9 @@ EXTRA_DIST = \ key_dsa_wrong.pub \ key_ecdsa \ key_ecdsa.pub \ + signed_key_ecdsa \ + signed_key_ecdsa.pub \ + signed_key_ecdsa-cert.pub \ key_ed25519 \ key_ed25519.pub \ key_ed25519_encrypted \ From af4a4d3f35ffe54e1acca943ca4419d515320daa Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Tue, 31 Aug 2021 09:51:25 -0700 Subject: [PATCH 095/102] Update .gitignore Add .DS_Store files for macOS --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b6d6b5cb..d256f68b 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ tags libssh2.pc TAGS *~ +.DS_Store From d9b4222ef1c5ab9b9e499fe6234556e5cca7c4fe Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Thu, 2 Sep 2021 13:13:53 -0700 Subject: [PATCH 096/102] Update CI to use latest Ubuntu #624 (#625) File: ci.yml Notes: Update CI to use latest Ubuntu #624 Also removed 32 bit building in the matrix. Credit: Will Cosgrove --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3333d9c0..00846b1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,18 +8,18 @@ on: jobs: style-check: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Check Style run: ./ci/checksrc.sh build: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: compiler: [gcc, clang] - address_size: [32, 64] + address_size: [64] crypto_backend: [OpenSSL, Libgcrypt, mbedTLS] build_shared_libs: [OFF, ON] enable_zlib_compression: [OFF, ON] @@ -59,7 +59,7 @@ jobs: if: ${{ matrix.address_size == 64 }} run: | sudo apt-get install -y libssl-dev - sudo apt-get install -y libgcrypt11-dev + sudo apt-get install -y libgcrypt-dev - name: Install mbedTLS Dependencies if: ${{ matrix.crypto_backend == 'mbedTLS' }} run: | @@ -91,7 +91,7 @@ jobs: CTEST_OUTPUT_ON_FAILURE=1 cmake --build . --target test cmake --build . --target package fuzzer: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: From f0417cb1967331c8dcb38a96ab889ecdf71f6dcb Mon Sep 17 00:00:00 2001 From: Will Cosgrove Date: Thu, 2 Sep 2021 13:14:46 -0700 Subject: [PATCH 097/102] openssh_fixture.c: fix warning (#621) File: openssh_fixture.c Notes: Fix `portable_sleep` return type warning Credit: Will Cosgrove --- tests/openssh_fixture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 0480c5d5..97f154e9 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -208,7 +208,7 @@ static int is_running_inside_a_container() #endif } -static unsigned int portable_sleep(unsigned int seconds) +static void portable_sleep(unsigned int seconds) { #ifdef WIN32 Sleep(seconds); From 7daee037d110bbdb003ea75ca68d357ffa9d8fa8 Mon Sep 17 00:00:00 2001 From: Laurent Stacul Date: Thu, 2 Sep 2021 22:17:35 +0200 Subject: [PATCH 098/102] openssh_fixture.c: Fix openssh_server build not working (#616) (#620) File: openssh_fixture.c Notes: fixes too long of output lines building docker image Credit: Laurent Stacul --- tests/openssh_fixture.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/openssh_fixture.c b/tests/openssh_fixture.c index 97f154e9..474b20aa 100644 --- a/tests/openssh_fixture.c +++ b/tests/openssh_fixture.c @@ -145,7 +145,8 @@ static int run_command(char **output, const char *command, ...) static int build_openssh_server_docker_image(void) { - return run_command(NULL, "docker build -t libssh2/openssh_server " + return run_command(NULL, "docker build --quiet " + "-t libssh2/openssh_server " "openssh_server"); } From 6eb132f1594684276134616476225e1740f5dcf0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 3 Sep 2021 09:17:18 +0200 Subject: [PATCH 099/102] mailing list: moved to lists.haxx.se --- README | 2 +- README.md | 2 +- configure.ac | 2 +- os400/libssh2_config.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README b/README index 8a148568..89639ba7 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ the revised BSD license. Web site: https://www.libssh2.org/ -Mailing list: https://cool.haxx.se/mailman/listinfo/libssh2-devel +Mailing list: https://lists.haxx.se/listinfo/libssh2-devel License: see COPYING diff --git a/README.md b/README.md index a4c741f6..14153a3e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ the revised BSD license. [Web site](https://www.libssh2.org/) -[Mailing list](https://cool.haxx.se/mailman/listinfo/libssh2-devel) +[Mailing list](https://lists.haxx.se/listinfo/libssh2-devel) [BSD Licensed](https://libssh2.org/license.html) diff --git a/configure.ac b/configure.ac index c4fc3e4e..b51bb4b9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # AC_PREREQ(2.57) -AC_INIT(libssh2, [-], libssh2-devel@cool.haxx.se) +AC_INIT(libssh2, [-], libssh2-devel@lists.haxx.se) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src]) AC_CONFIG_HEADERS([src/libssh2_config.h]) diff --git a/os400/libssh2_config.h b/os400/libssh2_config.h index 2e34c4c3..c6ef1327 100644 --- a/os400/libssh2_config.h +++ b/os400/libssh2_config.h @@ -230,7 +230,7 @@ #define PACKAGE "libssh2" /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "libssh2-devel@cool.haxx.se" +#define PACKAGE_BUGREPORT "libssh2-devel@lists.haxx.se" /* Define to the full name of this package. */ #define PACKAGE_NAME "libssh2" From 4bcf8415a728d8a2148920a47ad7c5a589bb7abe Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 16 Sep 2021 12:56:20 +0200 Subject: [PATCH 100/102] libssh2.h: bump it to 1.10.1-dev --- include/libssh2.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index f17b502e..6af8cbaf 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2009, Sara Golemon - * Copyright (c) 2009-2015 Daniel Stenberg + * Copyright (c) 2009-2021 Daniel Stenberg * Copyright (c) 2010 Simon Josefsson * All rights reserved. * @@ -40,19 +40,19 @@ #ifndef LIBSSH2_H #define LIBSSH2_H 1 -#define LIBSSH2_COPYRIGHT "2004-2019 The libssh2 project and its contributors." +#define LIBSSH2_COPYRIGHT "2004-2021 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_DEV" +#define LIBSSH2_VERSION "1.10.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_MINOR 10 +#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 @@ -69,7 +69,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 0x010a01 /* * This is the date and time when the full source package was created. The From db34d2c4004fcd7282532221bf6648b925bd5a44 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 25 Sep 2021 16:21:33 +0200 Subject: [PATCH 101/102] README: use www.libssh2.org for the license link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 14153a3e..caa0b670 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ the revised BSD license. [Mailing list](https://lists.haxx.se/listinfo/libssh2-devel) -[BSD Licensed](https://libssh2.org/license.html) +[BSD Licensed](https://www.libssh2.org/license.html) [Web site source code](https://github.com/libssh2/www) From d39e9ccc5e08a6441075049f1f79ffcb2bbe5a52 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 1 Oct 2021 20:09:03 +0000 Subject: [PATCH 102/102] windows: fix clang and WinCNG warnings Fix these categories of warning: - in `wincng.c` disagreement in signed/unsigned char when passing around the passphrase string: `warning: pointer targets in passing argument [...] differ in signedness [-Wpointer-sign]` Fixed by using `const unsigned char *` in all static functions and applying/updating casts as necessary. - in each use of `libssh2_*_init()` macros where the result is not used: `warning: value computed is not used [-Wunused-value]` Fixed by using `(void)` casts. - `channel.c:1171:7: warning: 'rc' may be used uninitialized in this function [-Wmaybe-uninitialized]` Fixed by initializing this variable with `LIBSSH2_ERROR_CHANNEL_UNKNOWN`. While there I replaced a few 0 literals with `LIBSSH2_ERROR_NONE`. - in `sftp.c`, several of these two warnings: `warning: 'data' may be used uninitialized in this function [-Wmaybe-uninitialized]` `warning: 'data_len' may be used uninitialized in this function [-Wmaybe-uninitialized]` Fixed by initializing these variables with NULL and 0 respectively. - Also removed the exec attribute from `wincng.h`. Notes: - There are many pre-existing checksrc issues. - The `sftp.c` and `channel.c` warnings may apply to other platforms as well. Closes #628 --- src/bcrypt_pbkdf.c | 6 +++--- src/channel.c | 10 ++++++--- src/hostkey.c | 6 +++--- src/kex.c | 12 +++++------ src/sftp.c | 52 +++++++++++++++++++++++----------------------- src/wincng.c | 27 ++++++++++++------------ src/wincng.h | 0 7 files changed, 59 insertions(+), 54 deletions(-) mode change 100755 => 100644 src/wincng.h diff --git a/src/bcrypt_pbkdf.c b/src/bcrypt_pbkdf.c index f782bcac..50d54209 100644 --- a/src/bcrypt_pbkdf.c +++ b/src/bcrypt_pbkdf.c @@ -127,7 +127,7 @@ 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); @@ -139,7 +139,7 @@ bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt, 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); diff --git a/src/channel.c b/src/channel.c index 78ed40e8..59133f8a 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1140,6 +1140,8 @@ libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel) 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 @@ -1152,7 +1154,8 @@ libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel) /* If we failed (but not with EAGAIN), then we move onto * the next step to try another request type. */ - if(rc != 0 && rc != LIBSSH2_ERROR_EAGAIN) + if(rc != LIBSSH2_ERROR_NONE && + rc != LIBSSH2_ERROR_EAGAIN) channel->req_auth_agent_try_state = libssh2_NB_state_sent; } @@ -1163,12 +1166,13 @@ libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel) /* If we failed without an EAGAIN, then move on with this * state machine. */ - if(rc != 0 && rc != LIBSSH2_ERROR_EAGAIN) + 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 == 0) + if(rc == LIBSSH2_ERROR_NONE) channel->req_auth_agent_try_state = libssh2_NB_state_idle; return rc; diff --git a/src/hostkey.c b/src/hostkey.c index d87a4c74..d126b611 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -211,7 +211,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); } @@ -438,7 +438,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); } @@ -683,7 +683,7 @@ hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session, 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); \ diff --git a/src/kex.c b/src/kex.c index 9f3ef799..c300ecb7 100644 --- a/src/kex.c +++ b/src/kex.c @@ -78,7 +78,7 @@ } \ if(value) \ while(len < (unsigned long)reqlen) { \ - libssh2_sha##digest_type##_init(&hash); \ + (void)libssh2_sha##digest_type##_init(&hash); \ libssh2_sha##digest_type##_update(hash, \ exchange_state->k_value, \ exchange_state->k_value_len); \ @@ -108,16 +108,16 @@ static void _libssh2_sha_algo_ctx_init(int sha_algo, void *ctx) { if(sha_algo == 512) { - libssh2_sha512_init((libssh2_sha512_ctx*)ctx); + (void)libssh2_sha512_init((libssh2_sha512_ctx*)ctx); } else if(sha_algo == 384) { - libssh2_sha384_init((libssh2_sha384_ctx*)ctx); + (void)libssh2_sha384_init((libssh2_sha384_ctx*)ctx); } else if(sha_algo == 256) { - libssh2_sha256_init((libssh2_sha256_ctx*)ctx); + (void)libssh2_sha256_init((libssh2_sha256_ctx*)ctx); } else if(sha_algo == 1) { - libssh2_sha1_init((libssh2_sha1_ctx*)ctx); + (void)libssh2_sha1_init((libssh2_sha1_ctx*)ctx); } else { assert(0); @@ -1600,7 +1600,7 @@ kex_method_diffie_hellman_group_exchange_sha256_key_exchange { \ libssh2_sha##digest_type##_ctx ctx; \ exchange_state->exchange_hash = (void *)&ctx; \ - libssh2_sha##digest_type##_init(&ctx); \ + (void)libssh2_sha##digest_type##_init(&ctx); \ if(session->local.banner) { \ _libssh2_htonu32(exchange_state->h_sig_comp, \ strlen((char *) session->local.banner) - 2); \ diff --git a/src/sftp.c b/src/sftp.c index ac7ee016..b1a53527 100644 --- a/src/sftp.c +++ b/src/sftp.c @@ -765,7 +765,7 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) 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; @@ -1561,7 +1561,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 @@ -1751,7 +1751,7 @@ 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; @@ -2017,10 +2017,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; @@ -2245,8 +2245,8 @@ static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) /* 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; + size_t data_len = 0; + unsigned char *packet, *s, *data = NULL; ssize_t rc; uint32_t retcode; @@ -2350,11 +2350,11 @@ 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; + unsigned char *s, *data = NULL; static const unsigned char fstat_responses[2] = { SSH_FXP_ATTRS, SSH_FXP_STATUS }; ssize_t rc; @@ -2575,7 +2575,7 @@ 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; unsigned char *s, *data = NULL; @@ -2705,11 +2705,11 @@ static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, { LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; - size_t data_len; + size_t data_len = 0; int 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; + unsigned char *s, *data = NULL; int rc; if(sftp->unlink_state == libssh2_NB_state_idle) { @@ -2809,14 +2809,14 @@ 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); /* 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) { @@ -2949,12 +2949,12 @@ 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; + unsigned char *packet, *s, *data = NULL; ssize_t rc; unsigned int flag; static const unsigned char responses[2] = @@ -3085,12 +3085,12 @@ 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] = @@ -3225,10 +3225,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; + size_t data_len = 0; int retcode; ssize_t packet_len; - unsigned char *packet, *s, *data; + unsigned char *packet, *s, *data = NULL; int rc; if(mode != LIBSSH2_SFTP_DEFAULT_MODE) { @@ -3340,11 +3340,11 @@ static int sftp_rmdir(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; int 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) { @@ -3442,13 +3442,13 @@ 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; @@ -3580,12 +3580,12 @@ 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; diff --git a/src/wincng.c b/src/wincng.c index cbb2b61c..9ae8ddee 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -664,7 +664,7 @@ _libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, static int _libssh2_wincng_load_pem(LIBSSH2_SESSION *session, const char *filename, - const char *passphrase, + const unsigned char *passphrase, const char *headerbegin, const char *headerend, unsigned char **data, @@ -690,7 +690,7 @@ _libssh2_wincng_load_pem(LIBSSH2_SESSION *session, static int _libssh2_wincng_load_private(LIBSSH2_SESSION *session, const char *filename, - const char *passphrase, + const unsigned char *passphrase, unsigned char **ppbEncoded, unsigned long *pcbEncoded, int tryLoadRSA, int tryLoadDSA) @@ -723,7 +723,7 @@ static int _libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session, const char *privatekeydata, size_t privatekeydata_len, - const char *passphrase, + const unsigned char *passphrase, unsigned char **ppbEncoded, unsigned long *pcbEncoded, int tryLoadRSA, int tryLoadDSA) @@ -1148,8 +1148,7 @@ _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, (void)session; - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, + ret = _libssh2_wincng_load_private(session, filename, passphrase, &pbEncoded, &cbEncoded, 1, 0); if(ret) { return -1; @@ -1173,7 +1172,7 @@ _libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, LIBSSH2_SESSION *session, const char *filedata, size_t filedata_len, - unsigned const char *passphrase) + const unsigned char *passphrase) { #ifdef HAVE_LIBCRYPT32 unsigned char *pbEncoded; @@ -1183,7 +1182,7 @@ _libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, (void)session; ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, + passphrase, &pbEncoded, &cbEncoded, 1, 0); if(ret) { return -1; @@ -1447,8 +1446,7 @@ _libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, unsigned long cbEncoded; int ret; - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, + ret = _libssh2_wincng_load_private(session, filename, passphrase, &pbEncoded, &cbEncoded, 0, 1); if(ret) { return -1; @@ -1472,7 +1470,7 @@ _libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, LIBSSH2_SESSION *session, const char *filedata, size_t filedata_len, - unsigned const char *passphrase) + const unsigned char *passphrase) { #ifdef HAVE_LIBCRYPT32 unsigned char *pbEncoded; @@ -1480,7 +1478,7 @@ _libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, int ret; ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, + passphrase, &pbEncoded, &cbEncoded, 0, 1); if(ret) { return -1; @@ -1728,7 +1726,8 @@ _libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, unsigned long cbEncoded; int ret; - ret = _libssh2_wincng_load_private(session, privatekey, passphrase, + ret = _libssh2_wincng_load_private(session, privatekey, + (const unsigned char *)passphrase, &pbEncoded, &cbEncoded, 1, 1); if(ret) { return -1; @@ -1767,7 +1766,9 @@ _libssh2_wincng_pub_priv_keyfilememory(LIBSSH2_SESSION *session, int ret; ret = _libssh2_wincng_load_private_memory(session, privatekeydata, - privatekeydata_len, passphrase, + privatekeydata_len, + (const unsigned char *) + passphrase, &pbEncoded, &cbEncoded, 1, 1); if(ret) { return -1; diff --git a/src/wincng.h b/src/wincng.h old mode 100755 new mode 100644